blob: 067d437150f6ba1e3fcd82f0b3476aff40a70cab [file] [log] [blame]
Simon Glassbc3ec002024-08-07 16:47:31 -06001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * UPL handoff parsing
4 *
5 * Copyright 2024 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
7 */
8
9#define LOG_CATEGORY UCLASS_BOOTSTD
10
11#include <alist.h>
12#include <bloblist.h>
13#include <dm.h>
14#include <image.h>
15#include <mapmem.h>
16#include <serial.h>
17#include <spl.h>
18#include <upl.h>
19#include <video.h>
20#include <asm/global_data.h>
21#include <dm/read.h>
22#include <dm/uclass-internal.h>
23
24DECLARE_GLOBAL_DATA_PTR;
25
26struct upl s_upl;
27
28void upl_set_fit_addr(ulong fit)
29{
30 struct upl *upl = &s_upl;
31
32 upl->fit = fit;
33}
34
35void upl_set_fit_info(ulong fit, int conf_offset, ulong entry_addr)
36{
37 struct upl *upl = &s_upl;
38
39 upl->fit = fit;
40 upl->conf_offset = conf_offset;
41 log_debug("upl: add fit %lx conf %x\n", fit, conf_offset);
42}
43
44int _upl_add_image(int node, ulong load_addr, ulong size, const char *desc)
45{
46 struct upl *upl = &s_upl;
47 struct upl_image img;
48
49 img.load = load_addr;
50 img.size = size;
51 img.offset = node;
52 img.description = desc;
53 if (!alist_add(&upl->image, img))
54 return -ENOMEM;
55 log_debug("upl: add image %s at %lx size %lx\n", desc, load_addr, size);
56
57 return 0;
58}
59
60static int write_serial(struct upl_serial *ser)
61{
62 struct udevice *dev = gd->cur_serial_dev;
63 struct serial_device_info info;
64 struct memregion region;
65 int ret;
66
67 if (!dev)
68 return log_msg_ret("ser", -ENOENT);
69 ret = serial_getinfo(dev, &info);
70 if (ret)
71 return log_msg_ret("inf", ret);
72
73 ser->compatible = ofnode_read_string(dev_ofnode(dev), "compatible");
74 ser->clock_frequency = info.clock;
75 ser->current_speed = gd->baudrate;
76 region.base = info.addr;
77 region.size = info.size;
78 alist_init_struct(&ser->reg, struct memregion);
79 if (!alist_add(&ser->reg, region))
80 return -ENOMEM;
81 ser->reg_io_shift = info.reg_shift;
82 ser->reg_offset = info.reg_offset;
83 ser->reg_io_width = info.reg_width;
84 ser->virtual_reg = 0;
85 ser->access_type = info.addr_space;
86
87 return 0;
88}
89
90static int write_graphics(struct upl_graphics *gra)
91{
92 struct video_uc_plat *plat;
93 struct video_priv *priv;
94 struct memregion region;
95 struct udevice *dev;
96
97 alist_init_struct(&gra->reg, struct memregion);
98 uclass_find_first_device(UCLASS_VIDEO, &dev);
99 if (!dev || !device_active(dev))
100 return log_msg_ret("vid", -ENOENT);
101
102 plat = dev_get_uclass_plat(dev);
103 region.base = plat->base;
104 region.size = plat->size;
105 if (!alist_add(&gra->reg, region))
106 return log_msg_ret("reg", -ENOMEM);
107
108 priv = dev_get_uclass_priv(dev);
109 gra->width = priv->xsize;
110 gra->height = priv->ysize;
111 gra->stride = priv->line_length; /* private field */
112 switch (priv->format) {
113 case VIDEO_RGBA8888:
114 case VIDEO_X8R8G8B8:
115 gra->format = UPLGF_ARGB32;
116 break;
117 case VIDEO_X8B8G8R8:
118 gra->format = UPLGF_ABGR32;
119 break;
120 case VIDEO_X2R10G10B10:
121 log_debug("device '%s': VIDEO_X2R10G10B10 not supported\n",
122 dev->name);
123 return log_msg_ret("for", -EPROTO);
124 case VIDEO_UNKNOWN:
125 log_debug("device '%s': Unknown video format\n", dev->name);
126 return log_msg_ret("for", -EPROTO);
127 }
128
129 return 0;
130}
131
132int spl_write_upl_handoff(struct spl_image_info *spl_image)
133{
134 struct upl *upl = &s_upl;
135 struct abuf buf;
136 ofnode root;
137 void *ptr;
138 int ret;
139
140 log_debug("UPL: Writing handoff - image_count=%d\n", upl->image.count);
141 upl->addr_cells = IS_ENABLED(CONFIG_PHYS_64BIT) ? 2 : 1;
142 upl->size_cells = IS_ENABLED(CONFIG_PHYS_64BIT) ? 2 : 1;
143 upl->bootmode = UPLBM_DEFAULT;
144 ret = write_serial(&upl->serial);
145 if (ret)
146 return log_msg_ret("ser", ret);
147 ret = write_graphics(&upl->graphics);
148 if (ret && ret != -ENOENT)
149 return log_msg_ret("gra", ret);
150
151 root = ofnode_root();
152 ret = upl_write_handoff(upl, root, true);
153 if (ret)
154 return log_msg_ret("wr", ret);
155
156 ret = oftree_to_fdt(oftree_default(), &buf);
157 if (ret)
158 return log_msg_ret("fdt", ret);
159 log_debug("FDT size %zx\n", abuf_size(&buf));
160
161 ptr = bloblist_add(BLOBLISTT_CONTROL_FDT, abuf_size(&buf), 0);
162 if (!ptr)
163 return log_msg_ret("blo", -ENOENT);
164 memcpy(ptr, abuf_data(&buf), abuf_size(&buf));
165
166 return 0;
167}
168
169void spl_upl_init(void)
170{
171 upl_init(&s_upl);
172}