1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2021 Linaro Limited
4  *			Author: AKASHI Takahiro
5  */
6 
7 #include <malloc.h>
8 #include <asm/global_data.h>
9 #include <dm/root.h>
10 #include <dm/tag.h>
11 #include <linux/err.h>
12 #include <linux/list.h>
13 #include <linux/types.h>
14 
15 struct udevice;
16 
17 DECLARE_GLOBAL_DATA_PTR;
18 
19 static const char *const tag_name[] = {
20 	[DM_TAG_PLAT]		= "plat",
21 	[DM_TAG_PARENT_PLAT]	= "parent_plat",
22 	[DM_TAG_UC_PLAT]	= "uclass_plat",
23 
24 	[DM_TAG_PRIV]		= "priv",
25 	[DM_TAG_PARENT_PRIV]	= "parent_priv",
26 	[DM_TAG_UC_PRIV]	= "uclass_priv",
27 	[DM_TAG_DRIVER_DATA]	= "driver_data",
28 
29 	[DM_TAG_EFI]		= "efi",
30 };
31 
tag_get_name(enum dm_tag_t tag)32 const char *tag_get_name(enum dm_tag_t tag)
33 {
34 	return tag_name[tag];
35 }
36 
dev_tag_set_ptr(struct udevice * dev,enum dm_tag_t tag,void * ptr)37 int dev_tag_set_ptr(struct udevice *dev, enum dm_tag_t tag, void *ptr)
38 {
39 	struct dmtag_node *node;
40 
41 	if (!dev || tag >= DM_TAG_COUNT)
42 		return -EINVAL;
43 
44 	list_for_each_entry(node, &gd->dmtag_list, sibling) {
45 		if (node->dev == dev && node->tag == tag)
46 			return -EEXIST;
47 	}
48 
49 	node = calloc(sizeof(*node), 1);
50 	if (!node)
51 		return -ENOMEM;
52 
53 	node->dev = dev;
54 	node->tag = tag;
55 	node->ptr = ptr;
56 	list_add_tail(&node->sibling, (struct list_head *)&gd->dmtag_list);
57 
58 	return 0;
59 }
60 
dev_tag_set_val(struct udevice * dev,enum dm_tag_t tag,ulong val)61 int dev_tag_set_val(struct udevice *dev, enum dm_tag_t tag, ulong val)
62 {
63 	struct dmtag_node *node;
64 
65 	if (!dev || tag >= DM_TAG_COUNT)
66 		return -EINVAL;
67 
68 	list_for_each_entry(node, &gd->dmtag_list, sibling) {
69 		if (node->dev == dev && node->tag == tag)
70 			return -EEXIST;
71 	}
72 
73 	node = calloc(sizeof(*node), 1);
74 	if (!node)
75 		return -ENOMEM;
76 
77 	node->dev = dev;
78 	node->tag = tag;
79 	node->val = val;
80 	list_add_tail(&node->sibling, (struct list_head *)&gd->dmtag_list);
81 
82 	return 0;
83 }
84 
dev_tag_get_ptr(struct udevice * dev,enum dm_tag_t tag,void ** ptrp)85 int dev_tag_get_ptr(struct udevice *dev, enum dm_tag_t tag, void **ptrp)
86 {
87 	struct dmtag_node *node;
88 
89 	if (!dev || tag >= DM_TAG_COUNT)
90 		return -EINVAL;
91 
92 	list_for_each_entry(node, &gd->dmtag_list, sibling) {
93 		if (node->dev == dev && node->tag == tag) {
94 			*ptrp = node->ptr;
95 			return 0;
96 		}
97 	}
98 
99 	return -ENOENT;
100 }
101 
dev_tag_get_val(struct udevice * dev,enum dm_tag_t tag,ulong * valp)102 int dev_tag_get_val(struct udevice *dev, enum dm_tag_t tag, ulong *valp)
103 {
104 	struct dmtag_node *node;
105 
106 	if (!dev || tag >= DM_TAG_COUNT)
107 		return -EINVAL;
108 
109 	list_for_each_entry(node, &gd->dmtag_list, sibling) {
110 		if (node->dev == dev && node->tag == tag) {
111 			*valp = node->val;
112 			return 0;
113 		}
114 	}
115 
116 	return -ENOENT;
117 }
118 
dev_tag_del(struct udevice * dev,enum dm_tag_t tag)119 int dev_tag_del(struct udevice *dev, enum dm_tag_t tag)
120 {
121 	struct dmtag_node *node, *tmp;
122 
123 	if (!dev || tag >= DM_TAG_COUNT)
124 		return -EINVAL;
125 
126 	list_for_each_entry_safe(node, tmp, &gd->dmtag_list, sibling) {
127 		if (node->dev == dev && node->tag == tag) {
128 			list_del(&node->sibling);
129 			free(node);
130 
131 			return 0;
132 		}
133 	}
134 
135 	return -ENOENT;
136 }
137 
dev_tag_del_all(struct udevice * dev)138 int dev_tag_del_all(struct udevice *dev)
139 {
140 	struct dmtag_node *node, *tmp;
141 	bool found = false;
142 
143 	if (!dev)
144 		return -EINVAL;
145 
146 	list_for_each_entry_safe(node, tmp, &gd->dmtag_list, sibling) {
147 		if (node->dev == dev) {
148 			list_del(&node->sibling);
149 			free(node);
150 			found = true;
151 		}
152 	}
153 
154 	if (found)
155 		return 0;
156 
157 	return -ENOENT;
158 }
159 
dev_tag_collect_stats(struct dm_stats * stats)160 void dev_tag_collect_stats(struct dm_stats *stats)
161 {
162 	struct dmtag_node *node;
163 
164 	list_for_each_entry(node, &gd->dmtag_list, sibling) {
165 		stats->tag_count++;
166 		stats->tag_size += sizeof(struct dmtag_node);
167 	}
168 }
169