diff options
Diffstat (limited to 'board/amlogic/vim3/vim3.c')
-rw-r--r-- | board/amlogic/vim3/vim3.c | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/board/amlogic/vim3/vim3.c b/board/amlogic/vim3/vim3.c index 02d8cd0ce0a..09ef39ff30a 100644 --- a/board/amlogic/vim3/vim3.c +++ b/board/amlogic/vim3/vim3.c @@ -11,6 +11,123 @@ #include <net.h> #include <asm/io.h> #include <asm/arch/eth.h> +#include <i2c.h> +#include "khadas-mcu.h" + +/* + * The VIM3 on-board MCU can mux the PCIe/USB3.0 shared differential + * lines using a FUSB340TMX USB 3.1 SuperSpeed Data Switch between + * an USB3.0 Type A connector and a M.2 Key M slot. + * The PHY driving these differential lines is shared between + * the USB3.0 controller and the PCIe Controller, thus only + * a single controller can use it. + */ +int meson_ft_board_setup(void *blob, struct bd_info *bd) +{ + struct udevice *bus, *dev; + int node, i2c_node, ret; + unsigned int i2c_addr; + u32 *val; + + /* Find I2C device */ + node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "khadas,mcu"); + if (node < 0) { + printf("vim3: cannot find khadas,mcu node\n"); + return 0; + } + + /* Get addr */ + val = (u32 *)fdt_getprop(gd->fdt_blob, node, "reg", NULL); + if (!val) { + printf("vim3: cannot find khadas,mcu node i2c addr\n"); + return 0; + } + i2c_addr = fdt32_to_cpu(*val); + + /* Get i2c device */ + i2c_node = fdt_parent_offset(gd->fdt_blob, node); + if (node < 0) { + printf("vim3: cannot find khadas,mcu i2c node\n"); + return 0; + } + + ret = uclass_get_device_by_of_offset(UCLASS_I2C, i2c_node, &bus); + if (ret < 0) { + printf("vim3: cannot find i2c bus (%d)\n", ret); + return 0; + } + + ret = i2c_get_chip(bus, i2c_addr, 1, &dev); + if (ret < 0) { + printf("vim3: cannot find i2c chip (%d)\n", ret); + return 0; + } + + /* Read USB_PCIE_SWITCH_REG */ + ret = dm_i2c_reg_read(dev, KHADAS_MCU_USB_PCIE_SWITCH_REG); + if (ret < 0) { + printf("vim3: failed to read i2c reg (%d)\n", ret); + return 0; + } + debug("MCU_USB_PCIE_SWITCH_REG: %d\n", ret); + + /* + * If in PCIe mode, alter DT + * 0:Enable USB3.0,Disable PCIE, 1:Disable USB3.0, Enable PCIE + */ + if (ret > 0) { + static char data[32] __aligned(4); + const void *ptmp; + int len; + + /* Find USB node */ + node = fdt_node_offset_by_compatible(blob, -1, "amlogic,meson-g12a-usb-ctrl"); + if (node < 0) { + printf("vim3: cannot find amlogic,meson-g12a-usb-ctrl node\n"); + return 0; + } + + /* Update PHY names (mandatory to disable USB3.0) */ + len = strlcpy(data, "usb2-phy0", 32) + 1; + len += strlcpy(&data[len], "usb2-phy1", 32 - len) + 1; + ret = fdt_setprop(blob, node, "phy-names", data, len); + if (ret < 0) { + printf("vim3: failed to update usb phy names property (%d)\n", ret); + return 0; + } + + /* Update PHY list, by keeping the 2 first entries (optional) */ + ptmp = fdt_getprop(blob, node, "phys", &len); + if (ptmp) { + memcpy(data, ptmp, min_t(unsigned int, 2 * sizeof(u32), len)); + + ret = fdt_setprop(blob, node, "phys", data, + min_t(unsigned int, 2 * sizeof(u32), len)); + if (ret < 0) + printf("vim3: failed to update usb phys property (%d)\n", ret); + } else + printf("vim3: cannot find usb node phys property\n"); + + /* Find PCIe node */ + node = fdt_node_offset_by_compatible(blob, -1, "amlogic,g12a-pcie"); + if (node < 0) { + printf("vim3: cannot find amlogic,g12a-pcie node\n"); + return 0; + } + + /* Enable PCIe */ + len = strlcpy(data, "okay", 32); + ret = fdt_setprop(blob, node, "status", data, len); + if (ret < 0) { + printf("vim3: failed to enable pcie node (%d)\n", ret); + return 0; + } + + printf("vim3: successfully enabled PCIe\n"); + } + + return 0; +} int misc_init_r(void) { |