aboutsummaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
authorSimon Glass2023-08-14 16:40:38 -0600
committerTom Rini2023-08-25 13:54:33 -0400
commitcfc402db3954d7c852c322b232ad6d8842af6bf1 (patch)
tree3e5eed7152cec2c46766d5b3dac2b9e2db9df27a /boot
parenteb6c71b56282d3054dbffb83793e7d2c6745578e (diff)
expo: cedit: Support reading settings from CMOS RAM
Add a command to read edit settings from CMOS RAM, using the cedit definition to indicate which registers and bits are used. Signed-off-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'boot')
-rw-r--r--boot/cedit.c99
-rw-r--r--boot/scene_internal.h12
-rw-r--r--boot/scene_menu.c16
3 files changed, 127 insertions, 0 deletions
diff --git a/boot/cedit.c b/boot/cedit.c
index 725745aba55..73645f70b6c 100644
--- a/boot/cedit.c
+++ b/boot/cedit.c
@@ -39,6 +39,7 @@ enum {
* @mask: Mask bits for the CMOS RAM. If a bit is set the byte containing it
* will be written
* @value: Value bits for CMOS RAM. This is the actual value written
+ * @dev: RTC device to write to
*/
struct cedit_iter_priv {
struct abuf *buf;
@@ -46,6 +47,7 @@ struct cedit_iter_priv {
bool verbose;
u8 *mask;
u8 *value;
+ struct udevice *dev;
};
int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id)
@@ -619,3 +621,100 @@ done:
free(priv.value);
return ret;
}
+
+static int h_read_settings_cmos(struct scene_obj *obj, void *vpriv)
+{
+ struct cedit_iter_priv *priv = vpriv;
+ const struct scene_menitem *mi;
+ struct scene_obj_menu *menu;
+ int val, ret;
+ uint i;
+
+ if (obj->type != SCENEOBJT_MENU)
+ return 0;
+
+ menu = (struct scene_obj_menu *)obj;
+
+ /* figure out where to place this item */
+ if (!obj->bit_length)
+ return log_msg_ret("len", -EINVAL);
+ if (obj->start_bit + obj->bit_length > CMOS_MAX_BITS)
+ return log_msg_ret("bit", -E2BIG);
+
+ val = 0;
+ for (i = 0; i < obj->bit_length; i++) {
+ uint bitnum = obj->start_bit + i;
+ uint offset = CMOS_BYTE(bitnum);
+
+ /* read the byte if not already read */
+ if (!priv->mask[offset]) {
+ ret = rtc_read8(priv->dev, offset);
+ if (ret < 0)
+ return log_msg_ret("rea", ret);
+ priv->value[offset] = ret;
+
+ /* mark it as read */
+ priv->mask[offset] = 0xff;
+ }
+
+ if (priv->value[offset] & BIT(CMOS_BIT(bitnum)))
+ val |= BIT(i);
+ log_debug("bit %x %x\n", bitnum, val);
+ }
+
+ /* update the current item */
+ mi = scene_menuitem_find_seq(menu, val);
+ if (!mi)
+ return log_msg_ret("seq", -ENOENT);
+
+ menu->cur_item_id = mi->id;
+ log_debug("Update menu %d cur_item_id %d\n", menu->obj.id, mi->id);
+
+ return 0;
+}
+
+int cedit_read_settings_cmos(struct expo *exp, struct udevice *dev,
+ bool verbose)
+{
+ struct cedit_iter_priv priv;
+ int ret, i, count, first, last;
+
+ /* read in the items */
+ priv.mask = calloc(1, CMOS_MAX_BYTES);
+ if (!priv.mask)
+ return log_msg_ret("mas", -ENOMEM);
+ priv.value = calloc(1, CMOS_MAX_BYTES);
+ if (!priv.value) {
+ free(priv.mask);
+ return log_msg_ret("val", -ENOMEM);
+ }
+ priv.dev = dev;
+
+ ret = expo_iter_scene_objs(exp, h_read_settings_cmos, &priv);
+ if (ret) {
+ log_debug("Failed to read CMOS (err=%d)\n", ret);
+ ret = log_msg_ret("set", ret);
+ goto done;
+ }
+
+ /* read the data to the RTC */
+ first = CMOS_MAX_BYTES;
+ last = -1;
+ for (i = 0, count = 0; i < CMOS_MAX_BYTES; i++) {
+ if (priv.mask[i]) {
+ log_debug("Read byte %x: %x\n", i, priv.value[i]);
+ count++;
+ first = min(first, i);
+ last = max(last, i);
+ }
+ }
+ if (verbose) {
+ printf("Read %d bytes from offset %x to %x\n", count, first,
+ last);
+ }
+
+done:
+ free(priv.mask);
+ free(priv.value);
+ return ret;
+}
diff --git a/boot/scene_internal.h b/boot/scene_internal.h
index 23e29cb349b..695a907dc6a 100644
--- a/boot/scene_internal.h
+++ b/boot/scene_internal.h
@@ -234,4 +234,16 @@ int expo_iter_scene_objs(struct expo *exp, expo_scene_obj_iterator iter,
struct scene_menitem *scene_menuitem_find(const struct scene_obj_menu *menu,
int id);
+/**
+ * scene_menuitem_find_seq() - Find the menu item at a sequential position
+ *
+ * This numbers the items from 0 and returns the seq'th one
+ *
+ * @menu: Menu to check
+ * @seq: Sequence number to look for
+ * Return: menu item if found, else NULL
+ */
+struct scene_menitem *scene_menuitem_find_seq(const struct scene_obj_menu *menu,
+ uint seq);
+
#endif /* __SCENE_INTERNAL_H */
diff --git a/boot/scene_menu.c b/boot/scene_menu.c
index 602fe24580a..e0dcd0a4e04 100644
--- a/boot/scene_menu.c
+++ b/boot/scene_menu.c
@@ -46,6 +46,22 @@ struct scene_menitem *scene_menuitem_find(const struct scene_obj_menu *menu,
return NULL;
}
+struct scene_menitem *scene_menuitem_find_seq(const struct scene_obj_menu *menu,
+ uint seq)
+{
+ struct scene_menitem *item;
+ uint i;
+
+ i = 0;
+ list_for_each_entry(item, &menu->item_head, sibling) {
+ if (i == seq)
+ return item;
+ i++;
+ }
+
+ return NULL;
+}
+
/**
* update_pointers() - Update the pointer object and handle highlights
*