[U-Boot] [PATCH 16/16] stm32mp1: add stusb1600 support for DK1 and DK2 board

Patrick Delaunay
2019-03-29T14:42:24Z

The DK1 and DK2 boards use the USB Type-C controller STUSB1600.
This patch updates:
- the device tree to add the I2C node in the DT
- the board stm32mp1 to probe this I2C device and use this controller
to check cable detection.
- the DWC2 driver to support a new dt property
"u-boot,force-b-session-valid" which forces B session and
device mode; it is a workaround because the VBUS sensing and
ID detection isn't available with stusb1600.

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
---

arch/arm/dts/stm32mp157-pinctrl.dtsi | 7 ++++
arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi | 2 +-
arch/arm/dts/stm32mp157a-dk1.dts | 18 ++++++++++
board/st/stm32mp1/stm32mp1.c | 56 ++++++++++++++++++++++++++++++++
doc/device-tree-bindings/usb/dwc2.txt | 2 ++
drivers/usb/gadget/dwc2_udc_otg.c | 8 +++--
6 files changed, 90 insertions(+), 3 deletions(-)

diff --git a/arch/arm/dts/stm32mp157-pinctrl.dtsi b/arch/arm/dts/stm32mp157-pinctrl.dtsi
index 867d244..1962267 100644
--- a/arch/arm/dts/stm32mp157-pinctrl.dtsi
+++ b/arch/arm/dts/stm32mp157-pinctrl.dtsi
@@ -380,6 +380,13 @@
};
};

+ stusb1600_pins_a: stusb1600-0 {
+ pins {
+ pinmux = <STM32_PINMUX('I', 11, ANALOG)>;
+ bias-pull-up;
+ };
+ };
+
uart4_pins_a: uart4-0 {
pins1 {
pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
diff --git a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi
index 7e2c5d0..0f32a38 100644
--- a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi
+++ b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi
@@ -191,7 +191,7 @@
};

&usbotg_hs {
- force-b-session-valid;
+ u-boot,force-b-session-valid;
hnp-srp-disable;
};

diff --git a/arch/arm/dts/stm32mp157a-dk1.dts b/arch/arm/dts/stm32mp157a-dk1.dts
index b8ef820..e36773d 100644
--- a/arch/arm/dts/stm32mp157a-dk1.dts
+++ b/arch/arm/dts/stm32mp157a-dk1.dts
@@ -67,6 +67,24 @@
/delete-property/dmas;
/delete-property/dma-names;

+ typec: stusb1600 at 28 {
+ compatible = "st,stusb1600";
+ reg = <0x28>;
+ interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
+ interrupt-parent = <&gpioi>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&stusb1600_pins_a>;
+
+ status = "okay";
+
+ typec_con: connector {
+ compatible = "usb-c-connector";
+ label = "USB-C";
+ power-role = "sink";
+ power-opmode = "default";
+ };
+ };
+
pmic: stpmic at 33 {
compatible = "st,stpmic1";
reg = <0x33>;
diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
index 58b6d78..23737ce 100644
--- a/board/st/stm32mp1/stm32mp1.c
+++ b/board/st/stm32mp1/stm32mp1.c
@@ -9,15 +9,18 @@
#include <dm.h>
#include <g_dnl.h>
#include <generic-phy.h>
+#include <i2c.h>
#include <led.h>
#include <misc.h>
#include <phy.h>
#include <reset.h>
#include <syscon.h>
+#include <usb.h>
#include <asm/io.h>
#include <asm/gpio.h>
#include <asm/arch/stm32.h>
#include <power/regulator.h>
+#include <usb/dwc2_udc.h>

/* SYSCFG registers */
#define SYSCFG_BOOTR 0x00
@@ -151,11 +154,64 @@ static void board_key_check(void)

#if defined(CONFIG_USB_GADGET) && defined(CONFIG_USB_GADGET_DWC2_OTG)

+/* STMicroelectronics STUSB1600 Type-C controller */
+#define STUSB1600_CC_CONNECTION_STATUS 0x0E
+
+/* STUSB1600_CC_CONNECTION_STATUS bitfields */
+#define STUSB1600_CC_ATTACH BIT(0)
+
+static int stusb1600_init(struct udevice **dev_stusb1600)
+{
+ ofnode node;
+ struct udevice *dev, *bus;
+ int ret;
+ u32 chip_addr;
+
+ *dev_stusb1600 = NULL;
+
+ /* if node stusb1600 is present, means DK1 or DK2 board */
+ node = ofnode_by_compatible(ofnode_null(), "st,stusb1600");
+ if (!ofnode_valid(node))
+ return -ENODEV;
+
+ ret = ofnode_read_u32(node, "reg", &chip_addr);
+ if (ret)
+ return -EINVAL;
+
+ ret = uclass_get_device_by_ofnode(UCLASS_I2C, ofnode_get_parent(node),
+ &bus);
+ if (ret) {
+ printf("bus for stusb1600 not found\n");
+ return -ENODEV;
+ }
+
+ ret = dm_i2c_probe(bus, chip_addr, 0, &dev);
+ if (!ret)
+ *dev_stusb1600 = dev;
+
+ return ret;
+}
+
+static int stusb1600_cable_connected(struct udevice *dev)
+{
+ u8 status;
+
+ if (dm_i2c_read(dev, STUSB1600_CC_CONNECTION_STATUS, &status, 1))
+ return 0;
+
+ return status & STUSB1600_CC_ATTACH;
+}
+
+#include <usb/dwc2_udc.h>
int g_dnl_board_usb_cable_connected(void)
{
+ struct udevice *stusb1600;
struct udevice *dwc2_udc_otg;
int ret;

+ if (!stusb1600_init(&stusb1600))
+ return stusb1600_cable_connected(stusb1600);
+
ret = uclass_get_device_by_driver(UCLASS_USB_GADGET_GENERIC,
DM_GET_DRIVER(dwc2_udc_otg),
&dwc2_udc_otg);
diff --git a/doc/device-tree-bindings/usb/dwc2.txt b/doc/device-tree-bindings/usb/dwc2.txt
index eb60ffa..61493f7 100644
--- a/doc/device-tree-bindings/usb/dwc2.txt
+++ b/doc/device-tree-bindings/usb/dwc2.txt
@@ -39,6 +39,8 @@ Refer to phy/phy-bindings.txt for generic phy consumer properties
- g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) in gadget mode.
- usb33d-supply: external VBUS and ID sensing comparators supply, in order to
perform OTG operation, used on STM32MP1 SoCs.
+- u-boot,force-b-session-valid: force B-peripheral session instead of relying on
+ VBUS sensing (only valid when dr_mode = "peripheral" and for u-boot).

Deprecated properties:
- g-use-dma: gadget DMA mode is automatically detected
diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c
index 3fdaa10..494ab53 100644
--- a/drivers/usb/gadget/dwc2_udc_otg.c
+++ b/drivers/usb/gadget/dwc2_udc_otg.c
@@ -1053,7 +1053,7 @@ static int dwc2_udc_otg_ofdata_to_platdata(struct udevice *dev)
platdata->tx_fifo_sz = dev_read_u32_default(dev, "g-tx-fifo-size", 0);

platdata->force_b_session_valid =
- dev_read_bool(dev, "force-b-session-valid");
+ dev_read_bool(dev, "u-boot,force-b-session-valid");

/* force platdata according compatible */
drvdata = dev_get_driver_data(dev);
@@ -1075,6 +1075,9 @@ static void dwc2_set_stm32mp1_hsotg_params(struct dwc2_plat_otg_data *p)
| 0 << 8 /* [0:SRP disable 1:SRP enable]*/
| 0 << 6 /* 0: high speed utmi+, 1: full speed serial*/
| 0x7 << 0; /* FS timeout calibration**/
+
+ if (p->force_b_session_valid)
+ p->usb_gusbcfg |= 1 << 30; /* FDMOD: Force device mode */
}

static int dwc2_udc_otg_reset_init(struct udevice *dev,
@@ -1166,7 +1169,8 @@ static int dwc2_udc_otg_probe(struct udevice *dev)

if (platdata->force_b_session_valid)
/* Override B session bits : value and enable */
- setbits_le32(&usbotg_reg->gotgctl, B_VALOEN | B_VALOVAL);
+ setbits_le32(&usbotg_reg->gotgctl,
+ A_VALOEN | A_VALOVAL | B_VALOEN | B_VALOVAL);

ret = dwc2_udc_probe(platdata);
if (ret)
--
2.7.4