diff options
| author | Tom Rini <[email protected]> | 2024-11-25 17:23:49 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2024-11-25 17:34:08 -0600 |
| commit | 48380f9b2a12e3fc6339d6af5a154bded769d911 (patch) | |
| tree | 4782d21bfc7ddf81f757a38a85bf47d18f20e69d /common | |
| parent | dc1859f8d2ac3faaa5e2e1d465ec4bd8980520a5 (diff) | |
| parent | 3073246d1be682071d8b3d07d06c2484907aed60 (diff) | |
Merge tag 'v2025.01-rc3' into next
Prepare v2025.01-rc3
Diffstat (limited to 'common')
| -rw-r--r-- | common/Makefile | 1 | ||||
| -rw-r--r-- | common/memtop.c | 171 | ||||
| -rw-r--r-- | common/usb_onboard_hub.c | 195 | ||||
| -rw-r--r-- | common/xyzModem.c | 1 |
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++; |
