summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2024-11-25 17:23:49 -0600
committerTom Rini <[email protected]>2024-11-25 17:34:08 -0600
commit48380f9b2a12e3fc6339d6af5a154bded769d911 (patch)
tree4782d21bfc7ddf81f757a38a85bf47d18f20e69d /common
parentdc1859f8d2ac3faaa5e2e1d465ec4bd8980520a5 (diff)
parent3073246d1be682071d8b3d07d06c2484907aed60 (diff)
Merge tag 'v2025.01-rc3' into next
Prepare v2025.01-rc3
Diffstat (limited to 'common')
-rw-r--r--common/Makefile1
-rw-r--r--common/memtop.c171
-rw-r--r--common/usb_onboard_hub.c195
-rw-r--r--common/xyzModem.c1
4 files changed, 363 insertions, 5 deletions
diff --git a/common/Makefile b/common/Makefile
index 2ee5ef9cc6e..35991562a12 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -7,6 +7,7 @@
ifndef CONFIG_XPL_BUILD
obj-y += init/
obj-y += main.o
+obj-y += memtop.o
obj-y += exports.o
obj-y += cli_getch.o cli_simple.o cli_readline.o
obj-$(CONFIG_HUSH_OLD_PARSER) += cli_hush.o
diff --git a/common/memtop.c b/common/memtop.c
new file mode 100644
index 00000000000..841d89e0799
--- /dev/null
+++ b/common/memtop.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2024, Linaro Limited
+ */
+
+#include <fdt_support.h>
+#include <fdtdec.h>
+#include <memtop.h>
+
+#include <asm/types.h>
+
+#define MEM_RGN_COUNT 16
+
+struct region {
+ phys_addr_t base;
+ phys_size_t size;
+};
+
+struct mem_region {
+ struct region rgn[MEM_RGN_COUNT];
+ uint count;
+};
+
+static void add_mem_region(struct mem_region *mem_rgn, phys_addr_t base,
+ phys_size_t size)
+{
+ long i;
+
+ for (i = mem_rgn->count; i >= 0; i--) {
+ if (i && base < mem_rgn->rgn[i - 1].base) {
+ mem_rgn->rgn[i] = mem_rgn->rgn[i - 1];
+ } else {
+ mem_rgn->rgn[i].base = base;
+ mem_rgn->rgn[i].size = size;
+ break;
+ }
+ }
+
+ mem_rgn->count++;
+}
+
+static void mem_regions_init(struct mem_region *mem)
+{
+ uint i;
+
+ mem->count = 0;
+ for (i = 0; i < MEM_RGN_COUNT; i++) {
+ mem->rgn[i].base = 0;
+ mem->rgn[i].size = 0;
+ }
+}
+
+static int fdt_add_reserved_regions(struct mem_region *free_mem,
+ struct mem_region *reserved_mem,
+ void *fdt_blob)
+{
+ u64 addr, size;
+ int i, total, ret;
+ int nodeoffset, subnode;
+ struct fdt_resource res;
+
+ if (fdt_check_header(fdt_blob) != 0)
+ return -1;
+
+ /* process memreserve sections */
+ total = fdt_num_mem_rsv(fdt_blob);
+ assert_noisy(total < MEM_RGN_COUNT);
+ for (i = 0; i < total; i++) {
+ if (fdt_get_mem_rsv(fdt_blob, i, &addr, &size) != 0)
+ continue;
+ add_mem_region(reserved_mem, addr, size);
+ }
+
+ i = 0;
+ /* process reserved-memory */
+ nodeoffset = fdt_subnode_offset(fdt_blob, 0, "reserved-memory");
+ if (nodeoffset >= 0) {
+ subnode = fdt_first_subnode(fdt_blob, nodeoffset);
+ while (subnode >= 0) {
+ /* check if this subnode has a reg property */
+ ret = fdt_get_resource(fdt_blob, subnode, "reg", 0,
+ &res);
+ if (!ret && fdtdec_get_is_enabled(fdt_blob, subnode)) {
+ addr = res.start;
+ size = res.end - res.start + 1;
+ assert_noisy(i < MEM_RGN_COUNT);
+ add_mem_region(reserved_mem, addr, size);
+ }
+
+ subnode = fdt_next_subnode(fdt_blob, subnode);
+ ++i;
+ }
+ }
+
+ return 0;
+}
+
+static long addrs_overlap(phys_addr_t base1, phys_size_t size1,
+ phys_addr_t base2, phys_size_t size2)
+{
+ const phys_addr_t base1_end = base1 + size1 - 1;
+ const phys_addr_t base2_end = base2 + size2 - 1;
+
+ return ((base1 <= base2_end) && (base2 <= base1_end));
+}
+
+static long region_overlap_check(struct mem_region *mem_rgn, phys_addr_t base,
+ phys_size_t size)
+{
+ unsigned long i;
+ struct region *rgn = mem_rgn->rgn;
+
+ for (i = 0; i < mem_rgn->count; i++) {
+ phys_addr_t rgnbase = rgn[i].base;
+ phys_size_t rgnsize = rgn[i].size;
+
+ if (addrs_overlap(base, size, rgnbase, rgnsize))
+ break;
+ }
+
+ return (i < mem_rgn->count) ? i : -1;
+}
+
+static int find_ram_top(struct mem_region *free_mem,
+ struct mem_region *reserved_mem, phys_size_t size)
+{
+ long i, rgn;
+ phys_addr_t base = 0;
+ phys_addr_t res_base;
+
+ for (i = free_mem->count - 1; i >= 0; i--) {
+ phys_addr_t rgnbase = free_mem->rgn[i].base;
+ phys_size_t rgnsize = free_mem->rgn[i].size;
+
+ if (rgnsize < size)
+ continue;
+
+ base = rgnbase + rgnsize - size;
+ while (base && rgnbase <= base) {
+ rgn = region_overlap_check(reserved_mem, base, size);
+ if (rgn < 0)
+ return base;
+
+ res_base = reserved_mem->rgn[rgn].base;
+ if (res_base < size)
+ break;
+ base = res_base - size;
+ }
+ }
+
+ return 0;
+}
+
+phys_addr_t get_mem_top(phys_addr_t ram_start, phys_size_t ram_size,
+ phys_size_t size, void *fdt)
+{
+ int i;
+ struct mem_region free_mem;
+ struct mem_region reserved_mem;
+
+ mem_regions_init(&free_mem);
+ mem_regions_init(&reserved_mem);
+
+ add_mem_region(&free_mem, ram_start, ram_size);
+
+ i = fdt_add_reserved_regions(&free_mem, &reserved_mem, fdt);
+ if (i < 0)
+ return 0;
+
+ return find_ram_top(&free_mem, &reserved_mem, size);
+}
diff --git a/common/usb_onboard_hub.c b/common/usb_onboard_hub.c
index 68a04ac0412..6f28036e095 100644
--- a/common/usb_onboard_hub.c
+++ b/common/usb_onboard_hub.c
@@ -7,37 +7,203 @@
* Mostly inspired by Linux kernel v6.1 onboard_usb_hub driver
*/
+#include <asm/gpio.h>
#include <dm.h>
#include <dm/device_compat.h>
+#include <i2c.h>
+#include <linux/delay.h>
#include <power/regulator.h>
+#define USB5744_COMMAND_ATTACH 0x0056
+#define USB5744_COMMAND_ATTACH_LSB 0xAA
+#define USB5744_CONFIG_REG_ACCESS 0x0037
+#define USB5744_CONFIG_REG_ACCESS_LSB 0x99
+
struct onboard_hub {
struct udevice *vdd;
+ struct gpio_desc *reset_gpio;
+};
+
+struct onboard_hub_data {
+ unsigned long reset_us;
+ unsigned long power_on_delay_us;
+ int (*init)(struct udevice *dev);
};
+static int usb5744_i2c_init(struct udevice *dev)
+{
+ /*
+ * Prevent the MCU from the putting the HUB in suspend mode through register write.
+ * The BYPASS_UDC_SUSPEND bit (Bit 3) of the RuntimeFlags2 register at address
+ * 0x411D controls this aspect of the hub.
+ * Format to write to hub registers via SMBus- 2D 00 00 05 00 01 41 1D 08
+ * Byte 0: Address of slave 2D
+ * Byte 1: Memory address 00
+ * Byte 2: Memory address 00
+ * Byte 3: Number of bytes to write to memory
+ * Byte 4: Write configuration register (00)
+ * Byte 5: Write the number of data bytes (01- 1 data byte)
+ * Byte 6: LSB of register address 0x41
+ * Byte 7: MSB of register address 0x1D
+ * Byte 8: value to be written to the register
+ */
+ u8 data_buf[8] = {0x0, 0x5, 0x0, 0x1, 0x41, 0x1D, 0x08};
+ u8 config_reg_access_buf = USB5744_CONFIG_REG_ACCESS;
+ struct udevice *i2c_bus = NULL, *i2c_dev;
+ struct ofnode_phandle_args phandle;
+ u8 buf = USB5744_COMMAND_ATTACH;
+ struct dm_i2c_chip *i2c_chip;
+ int ret, slave_addr;
+
+ ret = dev_read_phandle_with_args(dev, "i2c-bus", NULL, 0, 0, &phandle);
+ if (ret) {
+ dev_err(dev, "i2c-bus not specified\n");
+ return ret;
+ }
+
+ ret = device_get_global_by_ofnode(ofnode_get_parent(phandle.node), &i2c_bus);
+ if (ret) {
+ dev_err(dev, "Failed to get i2c node, err: %d\n", ret);
+ return ret;
+ }
+
+ ret = ofnode_read_u32(phandle.node, "reg", &slave_addr);
+ if (ret)
+ return ret;
+
+ ret = i2c_get_chip(i2c_bus, slave_addr, 1, &i2c_dev);
+ if (ret) {
+ dev_err(dev, "%s: can't find i2c chip device for addr 0x%x\n", __func__,
+ slave_addr);
+ return ret;
+ }
+
+ i2c_chip = dev_get_parent_plat(i2c_dev);
+ if (!i2c_chip) {
+ dev_err(dev, "parent platform data not found\n");
+ return -EINVAL;
+ }
+
+ i2c_chip->flags &= ~DM_I2C_CHIP_WR_ADDRESS;
+ /* SMBus write command */
+ ret = dm_i2c_write(i2c_dev, 0, (uint8_t *)&data_buf, 8);
+ if (ret) {
+ dev_err(dev, "data_buf i2c_write failed, err:%d\n", ret);
+ return ret;
+ }
+
+ /* Configuration register access command */
+ ret = dm_i2c_write(i2c_dev, USB5744_CONFIG_REG_ACCESS_LSB,
+ &config_reg_access_buf, 2);
+ if (ret) {
+ dev_err(dev, "config_reg_access i2c_write failed, err: %d\n", ret);
+ return ret;
+ }
+
+ /* USB Attach with SMBus */
+ ret = dm_i2c_write(i2c_dev, USB5744_COMMAND_ATTACH_LSB, &buf, 2);
+ if (ret) {
+ dev_err(dev, "usb_attach i2c_write failed, err: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int usb_onboard_hub_reset(struct udevice *dev)
+{
+ struct onboard_hub_data *data =
+ (struct onboard_hub_data *)dev_get_driver_data(dev);
+ struct onboard_hub *hub = dev_get_priv(dev);
+ int ret;
+
+ hub->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_IS_OUT);
+
+ /* property is optional, don't return error! */
+ if (!hub->reset_gpio)
+ return 0;
+
+ ret = dm_gpio_set_value(hub->reset_gpio, 1);
+ if (ret)
+ return ret;
+
+ udelay(data->reset_us);
+
+ ret = dm_gpio_set_value(hub->reset_gpio, 0);
+ if (ret)
+ return ret;
+
+ udelay(data->power_on_delay_us);
+
+ return 0;
+}
+
static int usb_onboard_hub_probe(struct udevice *dev)
{
+ struct onboard_hub_data *data =
+ (struct onboard_hub_data *)dev_get_driver_data(dev);
struct onboard_hub *hub = dev_get_priv(dev);
int ret;
ret = device_get_supply_regulator(dev, "vdd-supply", &hub->vdd);
- if (ret) {
+ if (ret && ret != -ENOENT) {
dev_err(dev, "can't get vdd-supply: %d\n", ret);
return ret;
}
- ret = regulator_set_enable_if_allowed(hub->vdd, true);
+ if (hub->vdd) {
+ ret = regulator_set_enable_if_allowed(hub->vdd, true);
+ if (ret && ret != -ENOSYS) {
+ dev_err(dev, "can't enable vdd-supply: %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = usb_onboard_hub_reset(dev);
if (ret)
- dev_err(dev, "can't enable vdd-supply: %d\n", ret);
+ return ret;
+ if (data->init) {
+ ret = data->init(dev);
+ if (ret) {
+ dev_err(dev, "onboard i2c init failed: %d\n", ret);
+ goto err;
+ }
+ }
+ return 0;
+err:
+ dm_gpio_set_value(hub->reset_gpio, 0);
return ret;
}
+static int usb_onboard_hub_bind(struct udevice *dev)
+{
+ struct ofnode_phandle_args phandle;
+ const void *fdt = gd->fdt_blob;
+ int ret, off;
+
+ ret = dev_read_phandle_with_args(dev, "peer-hub", NULL, 0, 0, &phandle);
+ if (ret) {
+ dev_err(dev, "peer-hub not specified\n");
+ return ret;
+ }
+
+ off = ofnode_to_offset(phandle.node);
+ ret = fdt_node_check_compatible(fdt, off, "usb424,5744");
+ if (!ret)
+ return 0;
+
+ return -ENODEV;
+}
+
static int usb_onboard_hub_remove(struct udevice *dev)
{
struct onboard_hub *hub = dev_get_priv(dev);
int ret;
+ if (hub->reset_gpio)
+ dm_gpio_free(hub->reset_gpio->dev, hub->reset_gpio);
+
ret = regulator_set_enable_if_allowed(hub->vdd, false);
if (ret)
dev_err(dev, "can't disable vdd-supply: %d\n", ret);
@@ -45,15 +211,34 @@ static int usb_onboard_hub_remove(struct udevice *dev)
return ret;
}
+static const struct onboard_hub_data usb2514_data = {
+ .power_on_delay_us = 500,
+ .reset_us = 1,
+};
+
+static const struct onboard_hub_data usb5744_data = {
+ .init = usb5744_i2c_init,
+ .power_on_delay_us = 1000,
+ .reset_us = 5,
+};
+
static const struct udevice_id usb_onboard_hub_ids[] = {
/* Use generic usbVID,PID dt-bindings (usb-device.yaml) */
- { .compatible = "usb424,2514" }, /* USB2514B USB 2.0 */
- { }
+ { .compatible = "usb424,2514", /* USB2514B USB 2.0 */
+ .data = (ulong)&usb2514_data,
+ }, {
+ .compatible = "usb424,2744", /* USB2744 USB 2.0 */
+ .data = (ulong)&usb5744_data,
+ }, {
+ .compatible = "usb424,5744", /* USB5744 USB 3.0 */
+ .data = (ulong)&usb5744_data,
+ }
};
U_BOOT_DRIVER(usb_onboard_hub) = {
.name = "usb_onboard_hub",
.id = UCLASS_USB_HUB,
+ .bind = usb_onboard_hub_bind,
.probe = usb_onboard_hub_probe,
.remove = usb_onboard_hub_remove,
.of_match = usb_onboard_hub_ids,
diff --git a/common/xyzModem.c b/common/xyzModem.c
index 09f74a1f0c7..698a538a148 100644
--- a/common/xyzModem.c
+++ b/common/xyzModem.c
@@ -280,6 +280,7 @@ xyzModem_get_hdr (void)
{
case SOH:
xyz.total_SOH++;
+ fallthrough;
case STX:
if (c == STX)
xyz.total_STX++;