Add tcpc port and pd switch code board code Add U-Boot specific dtsi property, we use nop-phy driver for the phy Add relevant config options
Test: u-boot=> usb start starting USB... Bus usb@32e40000: USB EHCI 1.00 scanning bus usb@32e40000 for devices... 2 USB Device(s) found scanning usb for storage devices... 1 Storage Device(s) found u-boot=> usb tree USB device tree: 1 Hub (480 Mb/s, 0mA) | u-boot EHCI Host Controller | +-2 Mass Storage (480 Mb/s, 300mA) Kingston DataTraveler 2.0 50E54951344CB04199CA8CE6 Signed-off-by: Peng Fan <peng....@nxp.com> --- arch/arm/dts/imx8mm-evk-u-boot.dtsi | 26 ++++ board/freescale/imx8mm_evk/Kconfig | 1 + board/freescale/imx8mm_evk/imx8mm_evk.c | 181 ++++++++++++++++++++++++ configs/imx8mm_evk_defconfig | 12 ++ include/configs/imx8mm_evk.h | 3 + 5 files changed, 223 insertions(+) diff --git a/arch/arm/dts/imx8mm-evk-u-boot.dtsi b/arch/arm/dts/imx8mm-evk-u-boot.dtsi index b5c12105a9..241dfd656f 100644 --- a/arch/arm/dts/imx8mm-evk-u-boot.dtsi +++ b/arch/arm/dts/imx8mm-evk-u-boot.dtsi @@ -4,6 +4,12 @@ */ / { + + aliases { + usb0 = &usbotg1; + usb1 = &usbotg2; + }; + wdt-reboot { compatible = "wdt-reboot"; wdt = <&wdog1>; @@ -129,3 +135,23 @@ &wdog1 { u-boot,dm-spl; }; + +&usbotg1 { + extcon = "tcpc"; + phys = <&usbphynop1>; +}; + +&usbphynop1 { + compatible = "nop-phy"; + #phy-cells = <0>; +}; + +&usbotg2 { + extcon = "tcpc"; + phys = <&usbphynop2>; +}; + +&usbphynop2 { + compatible = "nop-phy"; + #phy-cells = <0>; +}; diff --git a/board/freescale/imx8mm_evk/Kconfig b/board/freescale/imx8mm_evk/Kconfig index 299691a619..cbd9d4e8f2 100644 --- a/board/freescale/imx8mm_evk/Kconfig +++ b/board/freescale/imx8mm_evk/Kconfig @@ -9,4 +9,5 @@ config SYS_VENDOR config SYS_CONFIG_NAME default "imx8mm_evk" +source "board/freescale/common/Kconfig" endif diff --git a/board/freescale/imx8mm_evk/imx8mm_evk.c b/board/freescale/imx8mm_evk/imx8mm_evk.c index 6af7100696..187ea19b91 100644 --- a/board/freescale/imx8mm_evk/imx8mm_evk.c +++ b/board/freescale/imx8mm_evk/imx8mm_evk.c @@ -6,11 +6,14 @@ #include <common.h> #include <env.h> #include <init.h> +#include <i2c.h> #include <miiphy.h> #include <netdev.h> +#include <usb.h> #include <asm/arch/clock.h> #include <asm/arch/sys_proto.h> +#include "../common/tcpc.h" #include <asm/io.h> DECLARE_GLOBAL_DATA_PTR; @@ -44,8 +47,186 @@ int board_phy_config(struct phy_device *phydev) } #endif +#if IS_ENABLED(CONFIG_USB_TCPC) +struct tcpc_port port1; +struct tcpc_port port2; + +static int setup_pd_switch(uint8_t i2c_bus, uint8_t addr) +{ + struct udevice *bus; + struct udevice *i2c_dev = NULL; + int ret; + uint8_t valb; + + ret = uclass_get_device_by_seq(UCLASS_I2C, i2c_bus, &bus); + if (ret) { + printf("%s: Can't find bus\n", __func__); + return -EINVAL; + } + + ret = dm_i2c_probe(bus, addr, 0, &i2c_dev); + if (ret) { + printf("%s: Can't find device id=0x%x\n", + __func__, addr); + return -ENODEV; + } + + ret = dm_i2c_read(i2c_dev, 0xB, &valb, 1); + if (ret) { + printf("%s dm_i2c_read failed, err %d\n", __func__, ret); + return -EIO; + } + valb |= 0x4; /* Set DB_EXIT to exit dead battery mode */ + ret = dm_i2c_write(i2c_dev, 0xB, (const uint8_t *)&valb, 1); + if (ret) { + printf("%s dm_i2c_write failed, err %d\n", __func__, ret); + return -EIO; + } + + /* Set OVP threshold to 23V */ + valb = 0x6; + ret = dm_i2c_write(i2c_dev, 0x8, (const uint8_t *)&valb, 1); + if (ret) { + printf("%s dm_i2c_write failed, err %d\n", __func__, ret); + return -EIO; + } + + return 0; +} + +int pd_switch_snk_enable(struct tcpc_port *port) +{ + if (port == &port1) { + debug("Setup pd switch on port 1\n"); + return setup_pd_switch(1, 0x72); + } else if (port == &port2) { + debug("Setup pd switch on port 2\n"); + return setup_pd_switch(1, 0x73); + } else + return -EINVAL; +} + +struct tcpc_port_config port1_config = { + .i2c_bus = 1, /*i2c2*/ + .addr = 0x50, + .port_type = TYPEC_PORT_UFP, + .max_snk_mv = 5000, + .max_snk_ma = 3000, + .max_snk_mw = 40000, + .op_snk_mv = 9000, + .switch_setup_func = &pd_switch_snk_enable, +}; + +struct tcpc_port_config port2_config = { + .i2c_bus = 1, /*i2c2*/ + .addr = 0x52, + .port_type = TYPEC_PORT_UFP, + .max_snk_mv = 9000, + .max_snk_ma = 3000, + .max_snk_mw = 40000, + .op_snk_mv = 9000, + .switch_setup_func = &pd_switch_snk_enable, +}; + +static int setup_typec(void) +{ + int ret; + + debug("tcpc_init port 2\n"); + ret = tcpc_init(&port2, port2_config, NULL); + if (ret) { + printf("%s: tcpc port2 init failed, err=%d\n", + __func__, ret); + } else if (tcpc_pd_sink_check_charging(&port2)) { + /* Disable PD for USB1, since USB2 has priority */ + port1_config.disable_pd = true; + printf("Power supply on USB2\n"); + } + + debug("tcpc_init port 1\n"); + ret = tcpc_init(&port1, port1_config, NULL); + if (ret) { + printf("%s: tcpc port1 init failed, err=%d\n", + __func__, ret); + } else { + if (!port1_config.disable_pd) + printf("Power supply on USB1\n"); + return ret; + } + + return ret; +} + +int board_usb_init(int index, enum usb_init_type init) +{ + int ret = 0; + struct tcpc_port *port_ptr; + + debug("board_usb_init %d, type %d\n", index, init); + + if (index == 0) + port_ptr = &port1; + else + port_ptr = &port2; + + imx8m_usb_power(index, true); + + if (init == USB_INIT_HOST) + tcpc_setup_dfp_mode(port_ptr); + else + tcpc_setup_ufp_mode(port_ptr); + + return ret; +} + +int board_usb_cleanup(int index, enum usb_init_type init) +{ + int ret = 0; + + debug("board_usb_cleanup %d, type %d\n", index, init); + + if (init == USB_INIT_HOST) { + if (index == 0) + ret = tcpc_disable_src_vbus(&port1); + else + ret = tcpc_disable_src_vbus(&port2); + } + + imx8m_usb_power(index, false); + return ret; +} + +int board_ehci_usb_phy_mode(struct udevice *dev) +{ + int ret = 0; + enum typec_cc_polarity pol; + enum typec_cc_state state; + struct tcpc_port *port_ptr; + + if (dev->req_seq == 0) + port_ptr = &port1; + else + port_ptr = &port2; + + tcpc_setup_ufp_mode(port_ptr); + + ret = tcpc_get_cc_status(port_ptr, &pol, &state); + if (!ret) { + if (state == TYPEC_STATE_SRC_RD_RA || state == TYPEC_STATE_SRC_RD) + return USB_INIT_HOST; + } + + return USB_INIT_DEVICE; +} + +#endif + + int board_init(void) { + if (IS_ENABLED(CONFIG_USB_TCPC)) + setup_typec(); + if (IS_ENABLED(CONFIG_FEC_MXC)) setup_fec(); diff --git a/configs/imx8mm_evk_defconfig b/configs/imx8mm_evk_defconfig index 91d3bc3ac9..10e95d8d5c 100644 --- a/configs/imx8mm_evk_defconfig +++ b/configs/imx8mm_evk_defconfig @@ -12,12 +12,14 @@ CONFIG_SYS_I2C_MXC_I2C2=y CONFIG_SYS_I2C_MXC_I2C3=y CONFIG_DM_GPIO=y CONFIG_SPL_TEXT_BASE=0x7E1000 +CONFIG_USB_TCPC=y CONFIG_TARGET_IMX8MM_EVK=y CONFIG_SPL_MMC_SUPPORT=y CONFIG_SPL_SERIAL_SUPPORT=y CONFIG_SPL_DRIVERS_MISC_SUPPORT=y CONFIG_SPL=y CONFIG_DEFAULT_DEVICE_TREE="imx8mm-evk" +CONFIG_ANDROID_BOOT_IMAGE=y CONFIG_FIT=y CONFIG_FIT_EXTERNAL_OFFSET=0x3000 CONFIG_SPL_LOAD_FIT=y @@ -40,6 +42,7 @@ CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y +CONFIG_CMD_USB=y CONFIG_CMD_DHCP=y CONFIG_CMD_MII=y CONFIG_CMD_PING=y @@ -73,6 +76,8 @@ CONFIG_DM_ETH=y CONFIG_PHY_GIGE=y CONFIG_FEC_MXC=y CONFIG_MII=y +CONFIG_PHY=y +CONFIG_NOP_PHY=y CONFIG_PINCTRL=y CONFIG_SPL_PINCTRL=y CONFIG_PINCTRL_IMX8M=y @@ -87,4 +92,11 @@ CONFIG_SPL_SYSRESET=y CONFIG_SYSRESET_PSCI=y CONFIG_SYSRESET_WATCHDOG=y CONFIG_DM_THERMAL=y +CONFIG_USB=y +CONFIG_DM_USB=y +# CONFIG_SPL_DM_USB is not set +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_MX7 is not set +CONFIG_USB_EHCI_IMX=y +CONFIG_USB_STORAGE=y CONFIG_IMX_WATCHDOG=y diff --git a/include/configs/imx8mm_evk.h b/include/configs/imx8mm_evk.h index 83521ad401..5e865f0bef 100644 --- a/include/configs/imx8mm_evk.h +++ b/include/configs/imx8mm_evk.h @@ -145,4 +145,7 @@ #define IMX_FEC_BASE 0x30BE0000 +#define CONFIG_MXC_USB_PORTSC (PORT_PTS_UTMI | PORT_PTS_PTW) +#define CONFIG_USB_MAX_CONTROLLER_COUNT 2 + #endif -- 2.28.0