1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840 |
- /*
- * Copyright (c) 2006-2024, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2022-08-25 GuEe-GUI first version
- */
- #include <rthw.h>
- #include <rtthread.h>
- #include <drivers/ofw.h>
- #include <drivers/ofw_io.h>
- #include <drivers/ofw_fdt.h>
- #include <drivers/ofw_raw.h>
- #define DBG_TAG "rtdm.ofw"
- #define DBG_LVL DBG_INFO
- #include <rtdbg.h>
- #include "ofw_internal.h"
- struct rt_ofw_node *ofw_node_root = RT_NULL;
- struct rt_ofw_node *ofw_node_cpus = RT_NULL;
- struct rt_ofw_node *ofw_node_chosen = RT_NULL;
- struct rt_ofw_node *ofw_node_aliases = RT_NULL;
- struct rt_ofw_node *ofw_node_reserved_memory = RT_NULL;
- static rt_phandle _phandle_range[2] = { 1, 1 }, _phandle_next = 1;
- static struct rt_ofw_node **_phandle_hash = RT_NULL;
- static rt_list_t _aliases_nodes = RT_LIST_OBJECT_INIT(_aliases_nodes);
- rt_err_t ofw_phandle_hash_reset(rt_phandle min, rt_phandle max)
- {
- rt_err_t err = RT_EOK;
- rt_phandle next = max;
- struct rt_ofw_node **hash_ptr = RT_NULL;
- max = RT_ALIGN(max, OFW_NODE_MIN_HASH);
- if (max > _phandle_range[1])
- {
- rt_size_t size = sizeof(*_phandle_hash) * (max - min);
- if (!_phandle_hash)
- {
- hash_ptr = rt_calloc(1, size);
- }
- else
- {
- hash_ptr = rt_realloc(_phandle_hash, size);
- if (hash_ptr)
- {
- rt_size_t old_max = _phandle_range[1];
- rt_memset(&hash_ptr[old_max], 0, sizeof(_phandle_hash) * (max - old_max));
- }
- }
- }
- if (hash_ptr)
- {
- /* We always reset min value only once */
- if (min)
- {
- _phandle_range[0] = min;
- }
- _phandle_range[1] = max;
- _phandle_next = next + 1;
- _phandle_hash = hash_ptr;
- }
- else
- {
- err = -RT_ENOMEM;
- }
- return err;
- }
- static rt_phandle ofw_phandle_next(void)
- {
- rt_phandle next;
- static struct rt_spinlock op_lock = {};
- rt_hw_spin_lock(&op_lock.lock);
- RT_ASSERT(_phandle_next != OFW_PHANDLE_MAX);
- if (_phandle_next <= _phandle_range[1])
- {
- next = _phandle_next++;
- }
- else
- {
- rt_err_t err = ofw_phandle_hash_reset(_phandle_range[0], _phandle_next);
- if (!err)
- {
- next = _phandle_next++;
- }
- else
- {
- next = 0;
- LOG_E("Expanded phandle hash[%u, %u] fail error = %s",
- _phandle_range[0], _phandle_next + 1, rt_strerror(err));
- }
- }
- rt_hw_spin_unlock(&op_lock.lock);
- return next;
- }
- static void ofw_prop_destroy(struct rt_ofw_prop *prop)
- {
- struct rt_ofw_prop *next;
- while (prop)
- {
- next = prop->next;
- rt_free(prop);
- prop = next;
- }
- }
- static struct rt_ofw_node *ofw_get_next_node(struct rt_ofw_node *prev)
- {
- struct rt_ofw_node *np;
- /*
- * Walk:
- *
- * / { ------------------------ [0] (START) has child, goto child.
- *
- * node0 { ---------------- [1] has child, goto child.
- *
- * node0_0 { ---------- [2] no child, has sibling, goto sibling.
- * };
- *
- * node0_1 { ---------- [3] no sibling now.
- * upward while the parent has sibling.
- * };
- * };
- *
- * node1 { ---------------- [4] come from node0 who find the sibling:
- * node1, node1 has child, goto child.
- *
- * node1_0 { ---------- [5] has child, goto child.
- *
- * node1_0_0 { ---- [6] no sibling now.
- * upward while the parent has sibling.
- * (END) in the root.
- * };
- * };
- * };
- * };
- */
- if (!prev)
- {
- np = ofw_node_root;
- }
- else if (prev->child)
- {
- np = prev->child;
- }
- else
- {
- np = prev;
- while (np->parent && !np->sibling)
- {
- np = np->parent;
- }
- np = np->sibling;
- }
- return np;
- }
- static void ofw_node_destroy(struct rt_ofw_node *np)
- {
- struct rt_ofw_node *prev;
- if (np->parent)
- {
- /* Ask parent and prev sibling we are destroy. */
- prev = np->parent->child;
- if (prev == np)
- {
- np->parent->child = RT_NULL;
- }
- else
- {
- while (prev->sibling != np)
- {
- prev = prev->sibling;
- }
- prev->sibling = np->sibling;
- }
- }
- while (np)
- {
- if (rt_ofw_node_test_flag(np, RT_OFW_F_SYSTEM) == RT_FALSE)
- {
- LOG_E("%s is system node", np->full_name);
- RT_ASSERT(0);
- }
- prev = np;
- np = ofw_get_next_node(np);
- ofw_prop_destroy(prev->props);
- rt_free(prev);
- }
- }
- rt_err_t rt_ofw_node_destroy(struct rt_ofw_node *np)
- {
- rt_err_t err = RT_EOK;
- if (np)
- {
- if (rt_ref_read(&np->ref) <= 1)
- {
- ofw_node_destroy(np);
- }
- else
- {
- err = -RT_EBUSY;
- }
- }
- else
- {
- err = -RT_EINVAL;
- }
- return err;
- }
- struct rt_ofw_node *rt_ofw_node_get(struct rt_ofw_node *np)
- {
- if (np)
- {
- LOG_D("%s get ref = %d", np->full_name, rt_ref_read(&np->ref));
- rt_ref_get(&np->ref);
- }
- return np;
- }
- static void ofw_node_release(struct rt_ref *r)
- {
- struct rt_ofw_node *np = rt_container_of(r, struct rt_ofw_node, ref);
- LOG_E("%s is release", np->full_name);
- (void)np;
- RT_ASSERT(0);
- }
- void rt_ofw_node_put(struct rt_ofw_node *np)
- {
- if (np)
- {
- LOG_D("%s put ref = %d", np->full_name, rt_ref_read(&np->ref));
- rt_ref_put(&np->ref, &ofw_node_release);
- }
- }
- rt_bool_t rt_ofw_node_tag_equ(const struct rt_ofw_node *np, const char *tag)
- {
- rt_bool_t ret = RT_FALSE;
- if (np && tag)
- {
- const char *node_name = rt_fdt_node_name(np->full_name);
- rt_size_t tag_len = strchrnul(node_name, '@') - node_name;
- ret = (rt_strlen(tag) == tag_len && !rt_strncmp(node_name, tag, tag_len));
- }
- return ret;
- }
- rt_bool_t rt_ofw_node_tag_prefix(const struct rt_ofw_node *np, const char *prefix)
- {
- rt_bool_t ret = RT_FALSE;
- if (np && prefix)
- {
- ret = !rt_strncmp(rt_fdt_node_name(np->full_name), prefix, rt_strlen(prefix));
- }
- return ret;
- }
- static int ofw_prop_index_of_string(struct rt_ofw_prop *prop, const char *string,
- rt_int32_t (*cmp)(const char *cs, const char *ct))
- {
- int index = -1;
- rt_size_t len = prop->length, slen = 0;
- const char *value = prop->value;
- for (int idx = 0; len > 0; ++idx)
- {
- /* Add '\0' */
- slen = rt_strlen(value) + 1;
- if (!cmp(value, string))
- {
- index = idx;
- break;
- }
- len -= slen;
- value += slen;
- }
- return index;
- }
- static rt_int32_t ofw_strcasecmp(const char *cs, const char *ct)
- {
- extern rt_int32_t strcasecmp(const char *cs, const char *ct);
- return rt_strcasecmp(cs, ct);
- }
- static int ofw_prop_index_of_compatible(struct rt_ofw_prop *prop, const char *compatible)
- {
- return ofw_prop_index_of_string(prop, compatible, ofw_strcasecmp);
- }
- static int ofw_node_index_of_compatible(const struct rt_ofw_node *np, const char *compatible)
- {
- int idx = -1;
- struct rt_ofw_prop *prop = rt_ofw_get_prop(np, "compatible", RT_NULL);
- if (prop)
- {
- idx = ofw_prop_index_of_compatible(prop, compatible);
- }
- return idx;
- }
- rt_bool_t rt_ofw_machine_is_compatible(const char *compatible)
- {
- return ofw_node_index_of_compatible(ofw_node_root, compatible) >= 0;
- }
- /*
- * Property status:
- *
- * "okay" or "ok":
- * Indicates the device is operational.
- *
- * "disabled":
- * Indicates that the device is not presently operational, but it might
- * become operational in the future (for example, something is not
- * plugged in, or switched off).
- * Refer to the device binding for details on what disabled means for a
- * given device.
- *
- * "reserved":
- * Indicates that the device is operational, but should not be used.
- * Typically this is used for devices that are controlled by another
- * software component, such as platform firmware.
- *
- * "fail":
- * Indicates that the device is not operational. A serious error was
- * detected in the device, and it is unlikely to become operational
- * without repair.
- *
- * "fail-sss":
- * Indicates that the device is not operational. A serious error was
- * detected in the device and it is unlikely to become operational
- * without repair. The sss portion of the value is specific to the
- * device and indicates the error condition detected.
- */
- static rt_bool_t ofw_node_is_fail(const struct rt_ofw_node *np)
- {
- rt_bool_t res = RT_FALSE;
- const char *status = rt_ofw_prop_read_raw(np, "status", RT_NULL);
- if (status)
- {
- res = !rt_strcmp(status, "fail") || !rt_strncmp(status, "fail-", 5);
- }
- return res;
- }
- static rt_bool_t ofw_node_is_available(const struct rt_ofw_node *np)
- {
- rt_bool_t res = RT_TRUE;
- const char *status = rt_ofw_prop_read_raw(np, "status", RT_NULL);
- if (status)
- {
- res = !rt_strcmp(status, "okay") || !rt_strcmp(status, "ok");
- }
- return res;
- }
- rt_bool_t rt_ofw_node_is_available(const struct rt_ofw_node *np)
- {
- return np ? ofw_node_is_available(np) : RT_FALSE;
- }
- rt_bool_t rt_ofw_node_is_compatible(const struct rt_ofw_node *np, const char *compatible)
- {
- rt_bool_t res = RT_FALSE;
- if (np)
- {
- res = ofw_node_index_of_compatible(np, compatible) >= 0;
- }
- return res;
- }
- static struct rt_ofw_node_id *ofw_prop_match(struct rt_ofw_prop *prop, const struct rt_ofw_node_id *ids)
- {
- int best_index = RT_UINT32_MAX >> 1, index;
- struct rt_ofw_node_id *found_id = RT_NULL, *id;
- for (id = (struct rt_ofw_node_id *)ids; id->compatible[0]; ++id)
- {
- index = ofw_prop_index_of_compatible(prop, id->compatible);
- if (index >= 0 && index < best_index)
- {
- found_id = id;
- best_index = index;
- }
- }
- return found_id;
- }
- struct rt_ofw_node_id *rt_ofw_prop_match(struct rt_ofw_prop *prop, const struct rt_ofw_node_id *ids)
- {
- struct rt_ofw_node_id *id = RT_NULL;
- if (prop && ids && !rt_strcmp(prop->name, "compatible"))
- {
- id = ofw_prop_match(prop, ids);
- }
- return id;
- }
- struct rt_ofw_node_id *rt_ofw_node_match(struct rt_ofw_node *np, const struct rt_ofw_node_id *ids)
- {
- struct rt_ofw_prop *prop;
- struct rt_ofw_node_id *id = RT_NULL;
- if (np && ids && (prop = rt_ofw_get_prop(np, "compatible", RT_NULL)))
- {
- id = ofw_prop_match(prop, ids);
- }
- return id;
- }
- struct rt_ofw_node *rt_ofw_find_node_by_tag(struct rt_ofw_node *from, const char *tag)
- {
- struct rt_ofw_node *np = RT_NULL;
- if (tag)
- {
- rt_ofw_foreach_nodes(from, np)
- {
- if (rt_ofw_node_tag_equ(np, tag))
- {
- break;
- }
- }
- }
- return np;
- }
- struct rt_ofw_node *rt_ofw_find_node_by_prop_r(struct rt_ofw_node *from, const char *propname,
- const struct rt_ofw_prop **out_prop)
- {
- struct rt_ofw_node *np = RT_NULL;
- if (propname)
- {
- rt_ofw_foreach_nodes(from, np)
- {
- struct rt_ofw_prop *prop = rt_ofw_get_prop(np, propname, RT_NULL);
- if (prop)
- {
- if (out_prop)
- {
- *out_prop = prop;
- }
- break;
- }
- }
- }
- return np;
- }
- struct rt_ofw_node *rt_ofw_find_node_by_name(struct rt_ofw_node *from, const char *name)
- {
- struct rt_ofw_node *np = RT_NULL;
- if (name)
- {
- rt_ofw_foreach_nodes(from, np)
- {
- if (np->name && !rt_strcmp(np->name, name))
- {
- np = rt_ofw_node_get(np);
- break;
- }
- }
- }
- return np;
- }
- struct rt_ofw_node *rt_ofw_find_node_by_type(struct rt_ofw_node *from, const char *type)
- {
- struct rt_ofw_node *np = RT_NULL;
- if (type)
- {
- rt_ofw_foreach_nodes(from, np)
- {
- if (rt_ofw_node_is_type(np, type))
- {
- break;
- }
- }
- }
- return np;
- }
- struct rt_ofw_node *rt_ofw_find_node_by_compatible(struct rt_ofw_node *from, const char *compatible)
- {
- struct rt_ofw_node *np = RT_NULL;
- if (compatible)
- {
- rt_ofw_foreach_nodes(from, np)
- {
- if (ofw_node_index_of_compatible(np, compatible) >= 0)
- {
- break;
- }
- }
- }
- return np;
- }
- struct rt_ofw_node *rt_ofw_find_node_by_ids_r(struct rt_ofw_node *from, const struct rt_ofw_node_id *ids,
- const struct rt_ofw_node_id **out_id)
- {
- struct rt_ofw_node *np = RT_NULL;
- if (ids)
- {
- rt_ofw_foreach_nodes(from, np)
- {
- struct rt_ofw_node_id *id = rt_ofw_node_match(np, ids);
- if (id)
- {
- if (out_id)
- {
- *out_id = id;
- }
- break;
- }
- }
- }
- return np;
- }
- struct rt_ofw_node *rt_ofw_find_node_by_path(const char *path)
- {
- struct rt_ofw_node *np = RT_NULL, *parent, *tmp = RT_NULL;
- if (path)
- {
- if (!rt_strcmp(path, "/"))
- {
- np = ofw_node_root;
- }
- else
- {
- ++path;
- parent = rt_ofw_node_get(ofw_node_root);
- while (*path)
- {
- const char *next = strchrnul(path, '/');
- rt_size_t len = next - path;
- tmp = RT_NULL;
- rt_ofw_foreach_child_node(parent, np)
- {
- if (!rt_strncmp(np->full_name, path, len))
- {
- rt_ofw_node_put(parent);
- parent = np;
- tmp = np;
- break;
- }
- }
- if (!tmp)
- {
- rt_ofw_node_put(parent);
- break;
- }
- path += len + !!*next;
- }
- np = tmp;
- }
- rt_ofw_node_get(np);
- }
- return np;
- }
- struct rt_ofw_node *rt_ofw_find_node_by_phandle(rt_phandle phandle)
- {
- struct rt_ofw_node *np = RT_NULL;
- if (phandle >= OFW_PHANDLE_MIN && phandle <= OFW_PHANDLE_MAX)
- {
- /* rebase from zero */
- rt_phandle poff = phandle - _phandle_range[0];
- np = _phandle_hash[poff];
- if (!np)
- {
- rt_ofw_foreach_allnodes(np)
- {
- if (np->phandle == phandle)
- {
- _phandle_hash[poff] = np;
- break;
- }
- }
- }
- else
- {
- rt_ofw_node_get(np);
- }
- }
- return np;
- }
- struct rt_ofw_node *rt_ofw_get_parent(const struct rt_ofw_node *np)
- {
- if (np)
- {
- np = rt_ofw_node_get(np->parent);
- }
- return (struct rt_ofw_node *)np;
- }
- struct rt_ofw_node *rt_ofw_get_child_by_tag(const struct rt_ofw_node *parent, const char *tag)
- {
- struct rt_ofw_node *child = RT_NULL;
- if (parent && tag)
- {
- rt_ofw_foreach_child_node(parent, child)
- {
- if (rt_ofw_node_tag_equ(child, tag))
- {
- break;
- }
- }
- }
- return child;
- }
- struct rt_ofw_node *rt_ofw_get_child_by_compatible(const struct rt_ofw_node *parent, const char *compatible)
- {
- struct rt_ofw_node *child = RT_NULL;
- if (parent && compatible)
- {
- rt_ofw_foreach_child_node(parent, child)
- {
- if (ofw_node_index_of_compatible(child, compatible) >= 0)
- {
- break;
- }
- }
- }
- return child;
- }
- int rt_ofw_get_child_count(const struct rt_ofw_node *np)
- {
- int nr;
- if (np)
- {
- struct rt_ofw_node *child;
- nr = 0;
- rt_ofw_foreach_child_node(np, child)
- {
- ++nr;
- }
- }
- else
- {
- nr = -RT_EINVAL;
- }
- return nr;
- }
- int rt_ofw_get_available_child_count(const struct rt_ofw_node *np)
- {
- int nr;
- if (np)
- {
- struct rt_ofw_node *child;
- nr = 0;
- rt_ofw_foreach_available_child_node(np, child)
- {
- ++nr;
- }
- }
- else
- {
- nr = -RT_EINVAL;
- }
- return nr;
- }
- struct rt_ofw_node *rt_ofw_get_next_node(struct rt_ofw_node *prev)
- {
- struct rt_ofw_node *np;
- np = rt_ofw_node_get(ofw_get_next_node(prev));
- rt_ofw_node_put(prev);
- return np;
- }
- struct rt_ofw_node *rt_ofw_get_next_parent(struct rt_ofw_node *prev)
- {
- struct rt_ofw_node *next = RT_NULL;
- if (prev)
- {
- next = rt_ofw_node_get(prev->parent);
- rt_ofw_node_put(prev);
- }
- return next;
- }
- struct rt_ofw_node *rt_ofw_get_next_child(const struct rt_ofw_node *parent, struct rt_ofw_node *prev)
- {
- struct rt_ofw_node *next = RT_NULL;
- if (parent)
- {
- next = prev ? prev->sibling : parent->child;
- rt_ofw_node_put(prev);
- rt_ofw_node_get(next);
- }
- return next;
- }
- struct rt_ofw_node *rt_ofw_get_next_available_child(const struct rt_ofw_node *parent, struct rt_ofw_node *prev)
- {
- struct rt_ofw_node *next = RT_NULL;
- if (parent)
- {
- next = prev;
- do {
- next = rt_ofw_get_next_child(parent, next);
- } while (next && !ofw_node_is_available(next));
- }
- return next;
- }
- struct rt_ofw_node *rt_ofw_get_cpu_node(int cpu, int *thread, rt_bool_t (*match_cpu_hwid)(int cpu, rt_uint64_t hwid))
- {
- const char *propname = "reg";
- struct rt_ofw_node *cpu_np = RT_NULL;
- /*
- * "reg" (some of the obsolete arch may be other names):
- * The value of reg is a <prop-encoded-array> that defines a unique
- * CPU/thread id for the CPU/threads represented by the CPU node.
- *
- * If a CPU supports more than one thread (i.e. multiple streams of
- * execution) the reg property is an array with 1 element per thread. The
- * #address-cells on the /cpus node specifies how many cells each element
- * of the array takes. Software can determine the number of threads by
- * dividing the size of reg by the parent node’s #address-cells:
- *
- * thread-number = reg-cells / address-cells
- *
- * If a CPU/thread can be the target of an external interrupt the reg
- * property value must be a unique CPU/thread id that is addressable by the
- * interrupt controller.
- *
- * If a CPU/thread cannot be the target of an external interrupt, then reg
- * must be unique and out of bounds of the range addressed by the interrupt
- * controller
- *
- * If a CPU/thread’s PIR (pending interrupt register) is modifiable, a
- * client program should modify PIR to match the reg property value. If PIR
- * cannot be modified and the PIR value is distinct from the interrupt
- * controller number space, the CPUs binding may define a binding-specific
- * representation of PIR values if desired.
- */
- rt_ofw_foreach_cpu_node(cpu_np)
- {
- rt_ssize_t prop_len;
- rt_bool_t is_end = RT_FALSE;
- int tid, addr_cells = rt_ofw_io_addr_cells(cpu_np);
- const fdt32_t *cell = rt_ofw_prop_read_raw(cpu_np, propname, &prop_len);
- if (!cell && !addr_cells)
- {
- if (match_cpu_hwid && match_cpu_hwid(cpu, 0))
- {
- break;
- }
- continue;
- }
- if (!match_cpu_hwid)
- {
- continue;
- }
- prop_len /= sizeof(*cell) * addr_cells;
- for (tid = 0; tid < prop_len; ++tid)
- {
- rt_uint64_t hwid = rt_fdt_read_number(cell, addr_cells);
- if (match_cpu_hwid(cpu, hwid))
- {
- if (thread)
- {
- *thread = tid;
- }
- is_end = RT_TRUE;
- break;
- }
- cell += addr_cells;
- }
- if (is_end)
- {
- break;
- }
- }
- return cpu_np;
- }
- struct rt_ofw_node *rt_ofw_get_next_cpu_node(struct rt_ofw_node *prev)
- {
- struct rt_ofw_node *cpu_np;
- if (prev)
- {
- cpu_np = prev->sibling;
- rt_ofw_node_put(prev);
- }
- else
- {
- cpu_np = ofw_node_cpus->child;
- }
- for (; cpu_np; cpu_np = cpu_np->sibling)
- {
- if (ofw_node_is_fail(cpu_np))
- {
- continue;
- }
- if (!(rt_ofw_node_tag_equ(cpu_np, "cpu") || rt_ofw_node_is_type(cpu_np, "cpu")))
- {
- continue;
- }
- if (rt_ofw_node_get(cpu_np))
- {
- break;
- }
- }
- return cpu_np;
- }
- struct rt_ofw_node *rt_ofw_get_cpu_state_node(struct rt_ofw_node *cpu_np, int index)
- {
- struct rt_ofw_cell_args args;
- struct rt_ofw_node *np = RT_NULL, *state_np;
- rt_err_t err = rt_ofw_parse_phandle_cells(cpu_np, "power-domains", "#power-domain-cells", 0, &args);
- if (!err)
- {
- state_np = rt_ofw_parse_phandle(args.data, "domain-idle-states", index);
- rt_ofw_node_put(args.data);
- if (state_np)
- {
- np = state_np;
- }
- }
- if (!np)
- {
- int count = 0;
- rt_uint32_t phandle;
- const fdt32_t *cell;
- struct rt_ofw_prop *prop;
- rt_ofw_foreach_prop_u32(cpu_np, "cpu-idle-states", prop, cell, phandle)
- {
- if (count == index)
- {
- np = rt_ofw_find_node_by_phandle((rt_phandle)phandle);
- break;
- }
- ++count;
- }
- }
- return np;
- }
- rt_uint64_t rt_ofw_get_cpu_id(struct rt_ofw_node *cpu_np)
- {
- rt_uint64_t cpuid = ~0ULL;
- if (cpu_np)
- {
- rt_uint64_t idx = 0;
- struct rt_ofw_node *np = ofw_node_cpus->child;
- for (; np; np = np->sibling)
- {
- if (!(rt_ofw_node_tag_equ(cpu_np, "cpu") || rt_ofw_node_is_type(cpu_np, "cpu")))
- {
- continue;
- }
- if (cpu_np == np)
- {
- cpuid = idx;
- break;
- }
- ++idx;
- }
- if ((rt_int64_t)cpuid < 0 && !rt_ofw_prop_read_u64(cpu_np, "rt-thread,cpuid", &idx))
- {
- cpuid = idx;
- }
- }
- return cpuid;
- }
- rt_uint64_t rt_ofw_get_cpu_hwid(struct rt_ofw_node *cpu_np, unsigned int thread)
- {
- rt_uint64_t thread_id, hwid = ~0ULL;
- if (cpu_np && thread >= 0 && !rt_ofw_get_address(cpu_np, thread, &thread_id, RT_NULL))
- {
- hwid = thread_id;
- }
- return hwid;
- }
- rt_err_t ofw_alias_scan(void)
- {
- rt_err_t err = RT_EOK;
- struct rt_ofw_prop *prop;
- struct rt_ofw_node *np = ofw_node_aliases, *tmp;
- rt_ofw_foreach_prop(np, prop)
- {
- int id = 0, rate = 1;
- struct alias_info *info;
- const char *name = prop->name, *end;
- /* Maybe the bootloader will set the name, or other nodes reference the aliases */
- if (!rt_strcmp(name, "name") || !rt_strcmp(name, "phandle"))
- {
- continue;
- }
- if (!(tmp = rt_ofw_find_node_by_path(prop->value)))
- {
- continue;
- }
- end = name + rt_strlen(name) - 1;
- while (*end && !(*end >= '0' && *end <= '9') && end > name)
- {
- --end;
- }
- while (*end && (*end >= '0' && *end <= '9'))
- {
- id += (*end - '0') * rate;
- rate *= 10;
- ++end;
- }
- info = rt_malloc(sizeof(*info));
- if (!info)
- {
- err = -RT_ENOMEM;
- break;
- }
- rt_list_init(&info->list);
- info->id = id;
- info->tag = name;
- info->tag_len = end - name - 1;
- info->np = tmp;
- rt_list_insert_after(&_aliases_nodes, &info->list);
- }
- return err;
- }
- struct rt_ofw_node *rt_ofw_get_alias_node(const char *tag, int id)
- {
- struct alias_info *info;
- struct rt_ofw_node *np = RT_NULL;
- if (tag && id >= 0)
- {
- rt_list_for_each_entry(info, &_aliases_nodes, list)
- {
- if (rt_strncmp(info->tag, tag, info->tag_len))
- {
- continue;
- }
- if (info->id == id)
- {
- np = info->np;
- break;
- }
- }
- }
- return np;
- }
- int ofw_alias_node_id(struct rt_ofw_node *np)
- {
- int id;
- struct alias_info *info;
- if (np)
- {
- id = -1;
- rt_list_for_each_entry(info, &_aliases_nodes, list)
- {
- if (info->np == np)
- {
- id = info->id;
- break;
- }
- }
- }
- else
- {
- id = -RT_EINVAL;
- }
- return id;
- }
- int rt_ofw_get_alias_id(struct rt_ofw_node *np, const char *tag)
- {
- int id;
- struct alias_info *info;
- if (np && tag)
- {
- id = -1;
- rt_list_for_each_entry(info, &_aliases_nodes, list)
- {
- if (rt_strncmp(info->tag, tag, info->tag_len))
- {
- continue;
- }
- if (info->np == np)
- {
- id = info->id;
- break;
- }
- }
- }
- else
- {
- id = -RT_EINVAL;
- }
- return id;
- }
- int rt_ofw_get_alias_last_id(const char *tag)
- {
- int id;
- struct alias_info *info;
- if (tag)
- {
- id = -1;
- rt_list_for_each_entry(info, &_aliases_nodes, list)
- {
- if (rt_strncmp(info->tag, tag, info->tag_len))
- {
- continue;
- }
- if (info->id > id)
- {
- id = info->id;
- }
- }
- }
- else
- {
- id = -RT_EINVAL;
- }
- return id;
- }
- struct rt_ofw_node *rt_ofw_append_child(struct rt_ofw_node *parent, const char *full_name)
- {
- rt_phandle phandle;
- rt_err_t err = RT_EOK;
- fdt32_t *phandle_value;
- struct rt_ofw_node *np = RT_NULL, *child;
- if (full_name)
- {
- if ((phandle = ofw_phandle_next()))
- {
- np = rt_calloc(1, sizeof(*np) + sizeof(*phandle_value));
- }
- }
- if (np)
- {
- parent = parent ? : ofw_node_root;
- np->full_name = full_name;
- np->phandle = phandle;
- np->parent = parent;
- rt_ref_init(&np->ref);
- phandle_value = (void *)np + sizeof(*np);
- *phandle_value = cpu_to_fdt32(phandle);
- err = rt_ofw_append_prop(np, "phandle", sizeof(*phandle_value), phandle_value);
- if (!err)
- {
- if (parent->child)
- {
- rt_ofw_foreach_child_node(parent, child)
- {
- if (!child->sibling)
- {
- child->sibling = np;
- rt_ofw_node_put(child);
- break;
- }
- }
- }
- else
- {
- parent->child = np;
- }
- }
- else
- {
- rt_free(np);
- np = RT_NULL;
- }
- }
- return np;
- }
- rt_err_t rt_ofw_append_prop(struct rt_ofw_node *np, const char *name, int length, void *value)
- {
- rt_err_t err = RT_EOK;
- if (np && name && ((length && value) || (!length && !value)))
- {
- struct rt_ofw_prop *prop = rt_malloc(sizeof(*prop)), *last_prop;
- if (prop)
- {
- prop->name = name;
- prop->length = length;
- prop->value = value;
- prop->next = RT_NULL;
- if (np->props)
- {
- rt_ofw_foreach_prop(np, last_prop)
- {
- if (!last_prop->next)
- {
- last_prop->next = prop;
- break;
- }
- }
- }
- else
- {
- np->props = prop;
- }
- }
- else
- {
- err = -RT_ENOMEM;
- }
- }
- else
- {
- err = -RT_EINVAL;
- }
- return err;
- }
- struct rt_ofw_node *rt_ofw_parse_phandle(const struct rt_ofw_node *np, const char *phandle_name, int index)
- {
- struct rt_ofw_cell_args args;
- struct rt_ofw_node *ref_np = RT_NULL;
- if (!rt_ofw_parse_phandle_cells(np, phandle_name, RT_NULL, index, &args))
- {
- ref_np = args.data;
- }
- return ref_np;
- }
- static rt_err_t ofw_parse_phandle_cells(const struct rt_ofw_node *np, const char *list_name, const char *cells_name,
- int index, struct rt_ofw_cell_args *out_args)
- {
- rt_err_t err = -RT_EEMPTY;
- rt_uint32_t value;
- rt_size_t count = 0;
- const fdt32_t *cell;
- struct rt_ofw_prop *prop;
- /*
- * List:
- *
- * phandle1: node1 {
- * #list-cells = <2>;
- * };
- *
- * phandle2: node2 {
- * #list-cells = <1>;
- * };
- *
- * node3 {
- * list = <&phandle1 0xaa 0xbb>, <&phandle2 0xcc>;
- * };
- *
- * if call:
- * rt_ofw_parse_phandle_cells(node3, "list", "#list-cells", 0, &args):
- *
- * args.data = node1;
- * args.args_count = 2;
- * args.args[0] = 0xaa;
- * args.args[1] = 0xbb;
- *
- * rt_ofw_parse_phandle_cells(node3, "list", "#list-cells", 1, &args):
- *
- * args.data = node2;
- * args.args_count = 1;
- * args.args[0] = 0xcc;
- */
- rt_ofw_foreach_prop_u32(np, list_name, prop, cell, value)
- {
- rt_uint32_t cells_count = 0;
- struct rt_ofw_node *phandle_np = rt_ofw_find_node_by_phandle((rt_phandle)value);
- /* if phandle node is undefined, we assume that the cels_count is 0 */
- if (cells_name && phandle_np)
- {
- rt_ofw_prop_read_u32(phandle_np, cells_name, &cells_count);
- }
- if (count++ == index)
- {
- for (int idx = 0; idx < cells_count; ++idx)
- {
- cell = rt_ofw_prop_next_u32(prop, cell, &value);
- out_args->args[idx] = value;
- }
- out_args->args_count = cells_count;
- out_args->data = phandle_np;
- if (out_args->data)
- {
- err = RT_EOK;
- }
- break;
- }
- cell += cells_count;
- }
- return err;
- }
- rt_err_t rt_ofw_parse_phandle_cells(const struct rt_ofw_node *np, const char *list_name, const char *cells_name,
- int index, struct rt_ofw_cell_args *out_args)
- {
- rt_err_t err;
- if (np && list_name && index >= 0 && out_args)
- {
- err = ofw_parse_phandle_cells(np, list_name, cells_name, index, out_args);
- }
- else
- {
- err = -RT_EINVAL;
- }
- return err;
- }
- int rt_ofw_count_phandle_cells(const struct rt_ofw_node *np, const char *list_name, const char *cells_name)
- {
- int count;
- if (np && list_name)
- {
- count = -1;
- if (!cells_name)
- {
- rt_ssize_t length;
- if (rt_ofw_get_prop(np, list_name, &length))
- {
- count = length / sizeof(fdt32_t);
- }
- }
- else
- {
- int index = count = 0;
- struct rt_ofw_cell_args args;
- while (!ofw_parse_phandle_cells(np, list_name, cells_name, index, &args))
- {
- ++index;
- ++count;
- }
- }
- }
- else
- {
- count = -RT_EINVAL;
- }
- return count;
- }
- static const char *ofw_get_prop_fuzzy_name(const struct rt_ofw_node *np, const char *name)
- {
- char *sf, split_field[64];
- rt_size_t len = 0, max_ak = 0;
- const char *str, *result = RT_NULL;
- RT_DECLARE_BITMAP(ak, sizeof(split_field));
- struct rt_ofw_prop *prop;
- /*
- * List:
- *
- * node {
- * property;
- * front-prop-rear;
- * front-prop;
- * prop-rear;
- * };
- *
- * if call:
- * ofw_get_prop_fuzzy_name(node, name):
- * ["prop"] => property
- * ["-prop"] => front-prop-rear
- * ["prop-"] => front-prop-rear
- * ["-prop$"] => front-prop
- * ["^prop-"] => prop-rear
- * ["-prop-"] => front-prop-rear
- * ["front-*-rear"] => front-prop-rear
- */
- str = name;
- sf = split_field;
- if (str[0] != '^')
- {
- /* As '*' */
- *sf++ = '\0';
- rt_bitmap_set_bit(ak, len++);
- }
- else
- {
- ++str;
- }
- for (; *str && len < sizeof(split_field); ++str, ++sf, ++len)
- {
- if (*str != '*')
- {
- *sf = *str;
- rt_bitmap_clear_bit(ak, len);
- }
- else
- {
- max_ak = len;
- *sf = '\0';
- rt_bitmap_set_bit(ak, len);
- }
- }
- *sf = '\0';
- if (str[-1] != '$')
- {
- /* As '*' */
- max_ak = len;
- rt_bitmap_set_bit(ak, len++);
- }
- else
- {
- sf[-1] = '\0';
- --len;
- }
- sf = split_field;
- if (len >= sizeof(split_field))
- {
- LOG_W("%s fuzzy name = %s len is %d out of %d", np->full_name, name, rt_strlen(name), sizeof(split_field));
- }
- rt_ofw_foreach_prop(np, prop)
- {
- int prep_ak = 0, next_ak, field;
- rt_bool_t match = RT_TRUE;
- const char *propname = prop->name, *fuzzy_name = sf;
- if (!rt_bitmap_test_bit(ak, prep_ak))
- {
- next_ak = rt_bitmap_next_set_bit(ak, prep_ak + 1, max_ak) ? : len;
- field = next_ak - prep_ak;
- if (rt_strncmp(propname, fuzzy_name, field))
- {
- continue;
- }
- propname += field;
- fuzzy_name += field;
- prep_ak = next_ak;
- }
- rt_bitmap_for_each_set_bit_from(ak, prep_ak, next_ak, max_ak)
- {
- /* Skip the '*' */
- if (prep_ak == next_ak)
- {
- ++fuzzy_name;
- next_ak = rt_bitmap_next_set_bit(ak, prep_ak + 1, max_ak);
- }
- if (!(str = rt_strstr(propname, fuzzy_name)))
- {
- match = RT_FALSE;
- break;
- }
- field = next_ak - prep_ak;
- propname = str + field - 1;
- fuzzy_name += field;
- prep_ak = next_ak;
- }
- if (match)
- {
- if ((max_ak || !split_field[0]) && next_ak >= max_ak && len - max_ak > 1)
- {
- if (next_ak == max_ak)
- {
- /* Skip the last '*' */
- ++fuzzy_name;
- }
- if (!(propname = rt_strstr(propname, fuzzy_name)))
- {
- continue;
- }
- /* Check end flag */
- if (propname[len - max_ak - 1] != '\0')
- {
- continue;
- }
- }
- result = prop->name;
- break;
- }
- }
- return result;
- }
- const char *rt_ofw_get_prop_fuzzy_name(const struct rt_ofw_node *np, const char *name)
- {
- const char *propname = RT_NULL;
- if (np && name)
- {
- propname = ofw_get_prop_fuzzy_name(np, name);
- }
- return propname;
- }
- struct rt_ofw_prop *rt_ofw_get_prop(const struct rt_ofw_node *np, const char *name, rt_ssize_t *out_length)
- {
- struct rt_ofw_prop *prop = RT_NULL;
- if (np && name)
- {
- rt_ofw_foreach_prop(np, prop)
- {
- if (!rt_strcmp(prop->name, name))
- {
- if (out_length)
- {
- *out_length = prop->length;
- }
- break;
- }
- }
- }
- return prop;
- }
- #define OFW_PROP_READ_UXX_ARRAY_INDEX(bit) \
- int rt_ofw_prop_read_u##bit##_array_index( \
- const struct rt_ofw_node *np, const char *propname, \
- int index, int nr, rt_uint##bit##_t *out_values) \
- { \
- int res, max_nr; \
- if (np && propname && index >= 0 && nr >= 0 && out_values) \
- { \
- rt_ssize_t len; \
- const fdt##bit##_t *elm; \
- elm = rt_ofw_prop_read_raw(np, propname, &len); \
- max_nr = len / sizeof(*elm); \
- if (elm && index < max_nr) \
- { \
- elm += index; \
- max_nr -= index; \
- res = nr > max_nr ? max_nr : nr; \
- for (nr = 0; nr < res; ++nr) \
- { \
- *out_values++ = fdt##bit##_to_cpu(*elm++); \
- } \
- } \
- else \
- { \
- res = -RT_EEMPTY; \
- } \
- } \
- else \
- { \
- res = -RT_EINVAL; \
- } \
- return res; \
- }
- OFW_PROP_READ_UXX_ARRAY_INDEX(8)
- OFW_PROP_READ_UXX_ARRAY_INDEX(16)
- OFW_PROP_READ_UXX_ARRAY_INDEX(32)
- OFW_PROP_READ_UXX_ARRAY_INDEX(64)
- #undef OFW_PROP_READ_UXX_ARRAY_INDEX
- int rt_ofw_prop_read_string_array_index(const struct rt_ofw_node *np, const char *propname,
- int index, int nr, const char **out_strings)
- {
- int res = 0;
- if (np && propname && index >= 0 && nr >= 0 && out_strings)
- {
- rt_ssize_t len, slen = 0;
- const char *value = rt_ofw_prop_read_raw(np, propname, &len);
- if (value)
- {
- nr += index;
- for (int idx = 0; idx < nr && len > 0; ++idx)
- {
- /* Add '\0' */
- slen = rt_strlen(value) + 1;
- if (idx >= index)
- {
- *out_strings++ = value;
- ++res;
- }
- len -= slen;
- value += slen;
- }
- }
- else
- {
- res = -RT_EEMPTY;
- }
- }
- else
- {
- res = -RT_EINVAL;
- }
- return res;
- }
- int rt_ofw_prop_count_of_size(const struct rt_ofw_node *np, const char *propname, int size)
- {
- int count;
- if (np && propname && size > 0)
- {
- rt_ssize_t len;
- count = -RT_EEMPTY;
- if (rt_ofw_get_prop(np, propname, &len))
- {
- count = len / size;
- }
- }
- else
- {
- count = -RT_EINVAL;
- }
- return count;
- }
- static rt_int32_t ofw_strcmp(const char *cs, const char *ct)
- {
- return rt_strcmp(cs, ct);
- }
- int rt_ofw_prop_index_of_string(const struct rt_ofw_node *np, const char *propname, const char *string)
- {
- int idx;
- if (np && propname && string)
- {
- struct rt_ofw_prop *prop = rt_ofw_get_prop(np, propname, RT_NULL);
- idx = -1;
- if (prop)
- {
- idx = ofw_prop_index_of_string(prop, string, ofw_strcmp);
- }
- }
- else
- {
- idx = -RT_EINVAL;
- }
- return idx;
- }
- const fdt32_t *rt_ofw_prop_next_u32(struct rt_ofw_prop *prop, const fdt32_t *cur, rt_uint32_t *out_value)
- {
- if (prop && out_value)
- {
- if (cur)
- {
- ++cur;
- if ((void *)cur >= prop->value + prop->length)
- {
- cur = RT_NULL;
- }
- }
- else
- {
- cur = prop->value;
- }
- if (cur)
- {
- *out_value = fdt32_to_cpu(*cur);
- }
- }
- else
- {
- cur = RT_NULL;
- }
- return cur;
- }
- const char *rt_ofw_prop_next_string(struct rt_ofw_prop *prop, const char *cur)
- {
- if (prop)
- {
- if (cur)
- {
- cur += rt_strlen(cur) + 1;
- if ((void *)cur >= prop->value + prop->length)
- {
- cur = RT_NULL;
- }
- }
- else
- {
- cur = prop->value;
- }
- }
- else
- {
- cur = RT_NULL;
- }
- return cur;
- }
|