[PATCH 6/8] imx8mm_evk: add usbotg1 host support

Peng Fan
2020-10-12T06:23:52Z

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 at 32e40000: USB EHCI 1.00
scanning bus usb at 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.fan@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