summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arc/dts/axs10x_mb.dtsi4
-rw-r--r--arch/arc/dts/hsdk-common.dtsi11
-rw-r--r--arch/arm/dts/meson-gxbb-odroidc2-u-boot.dtsi8
-rw-r--r--arch/sandbox/dts/test.dts4
-rw-r--r--board/synopsys/hsdk/hsdk.c7
-rw-r--r--configs/odroid-c2_defconfig7
-rw-r--r--drivers/clk/Kconfig7
-rw-r--r--drivers/clk/clk-hsdk-cgu.c355
-rw-r--r--drivers/gpio/gpio-uclass.c15
-rw-r--r--drivers/usb/dwc3/core.c6
-rw-r--r--drivers/usb/dwc3/core.h1
-rw-r--r--drivers/usb/dwc3/dwc3-generic.c1
-rw-r--r--include/dwc3-uboot.h1
-rw-r--r--test/dm/gpio.c89
14 files changed, 351 insertions, 165 deletions
diff --git a/arch/arc/dts/axs10x_mb.dtsi b/arch/arc/dts/axs10x_mb.dtsi
index 5b77642b8d7..33b05934387 100644
--- a/arch/arc/dts/axs10x_mb.dtsi
+++ b/arch/arc/dts/axs10x_mb.dtsi
@@ -62,12 +62,12 @@
max-speed = <100>;
};
- ehci@0x40000 {
+ ehci@40000 {
compatible = "generic-ehci";
reg = < 0x40000 0x100 >;
};
- ohci@0x60000 {
+ ohci@60000 {
compatible = "generic-ohci";
reg = < 0x60000 0x100 >;
};
diff --git a/arch/arc/dts/hsdk-common.dtsi b/arch/arc/dts/hsdk-common.dtsi
index fd4245e1646..9aa10e4b25d 100644
--- a/arch/arc/dts/hsdk-common.dtsi
+++ b/arch/arc/dts/hsdk-common.dtsi
@@ -84,12 +84,19 @@
phy-mode = "gmii";
};
- ehci@0xf0040000 {
+ ehci@f0040000 {
compatible = "generic-ehci";
reg = <0xf0040000 0x100>;
+
+ /*
+ * OHCI and EHCI have reset line shared so we don't add
+ * reset property to OHCI node as it is probed later and
+ * it will reset sucessfuly probed and configured EHCI HW.
+ */
+ resets = <&cgu_rst HSDK_USB_RESET>;
};
- ohci@0xf0060000 {
+ ohci@f0060000 {
compatible = "generic-ohci";
reg = <0xf0060000 0x100>;
};
diff --git a/arch/arm/dts/meson-gxbb-odroidc2-u-boot.dtsi b/arch/arm/dts/meson-gxbb-odroidc2-u-boot.dtsi
index c35158d7e9e..484b40504dc 100644
--- a/arch/arm/dts/meson-gxbb-odroidc2-u-boot.dtsi
+++ b/arch/arm/dts/meson-gxbb-odroidc2-u-boot.dtsi
@@ -5,3 +5,11 @@
*/
#include "meson-gx-u-boot.dtsi"
+
+&usb0 {
+ status = "disabled";
+};
+
+&usb1 {
+ hnp-srp-disable;
+};
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 15cd2330a38..5ce5e284764 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -104,7 +104,9 @@
<&gpio_c 2 GPIO_OUT>,
<&gpio_c 3 (GPIO_IN|GPIO_PULL_UP)>,
<&gpio_c 4 (GPIO_IN|GPIO_PULL_DOWN)>,
- <&gpio_c 5 GPIO_IN>;
+ <&gpio_c 5 GPIO_IN>,
+ <&gpio_c 6 (GPIO_ACTIVE_LOW|GPIO_OUT|GPIO_OPEN_DRAIN)>,
+ <&gpio_c 7 (GPIO_ACTIVE_LOW|GPIO_OUT|GPIO_OPEN_SOURCE)>;
int-value = <1234>;
uint-value = <(-1234)>;
int64-value = /bits/ 64 <0x1111222233334444>;
diff --git a/board/synopsys/hsdk/hsdk.c b/board/synopsys/hsdk/hsdk.c
index a3e0563ff45..8ccd84ca600 100644
--- a/board/synopsys/hsdk/hsdk.c
+++ b/board/synopsys/hsdk/hsdk.c
@@ -42,6 +42,8 @@ DECLARE_GLOBAL_DATA_PTR;
#define CREG_CPU_START_MASK 0xF
#define CREG_CPU_START_POL BIT(4)
+#define CREG_CORE_BOOT_IMAGE GENMASK(5, 4)
+
#define CREG_CPU_0_ENTRY (CREG_BASE + 0x404)
#define SDIO_BASE (ARC_PERIPHERAL_BASE + 0xA000)
@@ -1241,11 +1243,16 @@ int board_late_init(void)
int checkboard(void)
{
+ u32 reg;
+
printf("Board: Synopsys %s\n", board_name(get_board_type_runtime()));
if (board_mismatch())
printf("WARN: U-boot is configured NOT for this board but for %s!\n",
board_name(get_board_type_config()));
+ reg = readl(CREG_AXI_M_HS_CORE_BOOT) & CREG_CORE_BOOT_IMAGE;
+ printf("U-boot autostart: %s\n", reg ? "enabled" : "disabled");
+
return 0;
};
diff --git a/configs/odroid-c2_defconfig b/configs/odroid-c2_defconfig
index 39279b40db1..3fb6f2d0898 100644
--- a/configs/odroid-c2_defconfig
+++ b/configs/odroid-c2_defconfig
@@ -19,6 +19,7 @@ CONFIG_CMD_GPIO=y
CONFIG_CMD_I2C=y
# CONFIG_CMD_LOADS is not set
CONFIG_CMD_MMC=y
+CONFIG_CMD_USB=y
# CONFIG_CMD_SETEXPR is not set
CONFIG_CMD_REGULATOR=y
CONFIG_OF_CONTROL=y
@@ -32,14 +33,20 @@ CONFIG_MMC_MESON_GX=y
CONFIG_PHY_REALTEK=y
CONFIG_DM_ETH=y
CONFIG_ETH_DESIGNWARE=y
+CONFIG_PHY=y
+CONFIG_MESON_GXBB_USB_PHY=y
CONFIG_PINCTRL=y
CONFIG_PINCTRL_MESON_GXBB=y
CONFIG_DM_REGULATOR=y
CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_DM_REGULATOR_GPIO=y
CONFIG_DM_RESET=y
CONFIG_DEBUG_UART_MESON=y
CONFIG_DEBUG_UART_ANNOUNCE=y
CONFIG_DEBUG_UART_SKIP_INIT=y
CONFIG_MESON_SERIAL=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_DWC2=y
CONFIG_OF_LIBFDT_OVERLAY=y
CONFIG_SMBIOS_MANUFACTURER="Hardkernel Co., Ltd."
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 1992d4a4b47..8b8b7199995 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -100,10 +100,11 @@ config CLK_TI_SCI
managed by the TI System Controller, say Y here. Otherwise, say N.
config CLK_HSDK
- bool "Enable cgu clock driver for HSDK"
- depends on CLK
+ bool "Enable cgu clock driver for HSDK boards"
+ depends on CLK && TARGET_HSDK
help
- Enable this to support the cgu clocks on Synopsys ARC HSDK
+ Enable this to support the cgu clocks on Synopsys ARC HSDK and
+ Synopsys ARC HSDK-4xD boards
config CLK_VERSAL
bool "Enable clock driver support for Versal"
diff --git a/drivers/clk/clk-hsdk-cgu.c b/drivers/clk/clk-hsdk-cgu.c
index 3035c5fb38e..2de3a6a30b0 100644
--- a/drivers/clk/clk-hsdk-cgu.c
+++ b/drivers/clk/clk-hsdk-cgu.c
@@ -14,6 +14,9 @@
#include <div64.h>
#include <dm.h>
#include <linux/io.h>
+#include <asm/arcregs.h>
+
+#include <dt-bindings/clock/snps,hsdk-cgu.h>
/*
* Synopsys ARC HSDK clock tree.
@@ -126,45 +129,41 @@
#define PARENT_RATE_27 27000000 /* fixed clock - xtal */
#define CGU_MAX_CLOCKS 27
-#define CGU_SYS_CLOCKS 16
-#define MAX_AXI_CLOCKS 4
-
-#define CGU_TUN_CLOCKS 4
-#define MAX_TUN_CLOCKS 6
+#define MAX_FREQ_VARIATIONS 6
-struct hsdk_tun_idiv_cfg {
- u32 oft;
- u8 val[MAX_TUN_CLOCKS];
+struct hsdk_idiv_cfg {
+ const u32 oft;
+ const u8 val[MAX_FREQ_VARIATIONS];
};
-struct hsdk_tun_clk_cfg {
- const u32 clk_rate[MAX_TUN_CLOCKS];
- const u32 pll_rate[MAX_TUN_CLOCKS];
- const struct hsdk_tun_idiv_cfg idiv[CGU_TUN_CLOCKS];
+struct hsdk_div_full_cfg {
+ const u32 clk_rate[MAX_FREQ_VARIATIONS];
+ const u32 pll_rate[MAX_FREQ_VARIATIONS];
+ const struct hsdk_idiv_cfg idiv[];
};
-static const struct hsdk_tun_clk_cfg tun_clk_cfg = {
+static const struct hsdk_div_full_cfg hsdk_4xd_tun_clk_cfg = {
{ 25000000, 50000000, 75000000, 100000000, 125000000, 150000000 },
{ 600000000, 600000000, 600000000, 600000000, 750000000, 600000000 }, {
{ CGU_TUN_IDIV_TUN, { 24, 12, 8, 6, 6, 4 } },
{ CGU_TUN_IDIV_ROM, { 4, 4, 4, 4, 5, 4 } },
{ CGU_TUN_IDIV_PWM, { 8, 8, 8, 8, 10, 8 } },
- { CGU_TUN_IDIV_TIMER, { 12, 12, 12, 12, 15, 12 } }
+ { CGU_TUN_IDIV_TIMER, { 12, 12, 12, 12, 15, 12 } },
+ { /* last one */ }
}
};
-struct hsdk_sys_idiv_cfg {
- u32 oft;
- u8 val[MAX_AXI_CLOCKS];
-};
-
-struct hsdk_axi_clk_cfg {
- const u32 clk_rate[MAX_AXI_CLOCKS];
- const u32 pll_rate[MAX_AXI_CLOCKS];
- const struct hsdk_sys_idiv_cfg idiv[CGU_SYS_CLOCKS];
+static const struct hsdk_div_full_cfg hsdk_tun_clk_cfg = {
+ { 25000000, 50000000, 75000000, 100000000, 125000000, 150000000 },
+ { 600000000, 600000000, 600000000, 600000000, 750000000, 600000000 }, {
+ { CGU_TUN_IDIV_TUN, { 24, 12, 8, 6, 6, 4 } },
+ { CGU_TUN_IDIV_ROM, { 4, 4, 4, 4, 5, 4 } },
+ { CGU_TUN_IDIV_PWM, { 8, 8, 8, 8, 10, 8 } },
+ { /* last one */ }
+ }
};
-static const struct hsdk_axi_clk_cfg axi_clk_cfg = {
+static const struct hsdk_div_full_cfg axi_clk_cfg = {
{ 200000000, 400000000, 600000000, 800000000 },
{ 800000000, 800000000, 600000000, 800000000 }, {
{ CGU_SYS_IDIV_APB, { 4, 4, 3, 4 } }, /* APB */
@@ -182,16 +181,17 @@ static const struct hsdk_axi_clk_cfg axi_clk_cfg = {
{ CGU_SYS_IDIV_SPI_REF, { 24, 24, 18, 24 } }, /* SPI-REF */
{ CGU_SYS_IDIV_I2C_REF, { 4, 4, 3, 4 } }, /* I2C-REF */
{ CGU_SYS_IDIV_UART_REF, { 24, 24, 18, 24 } }, /* UART-REF */
- { CGU_SYS_IDIV_EBI_REF, { 16, 16, 12, 16 } } /* EBI-REF */
+ { CGU_SYS_IDIV_EBI_REF, { 16, 16, 12, 16 } }, /* EBI-REF */
+ { /* last one */ }
}
};
struct hsdk_pll_cfg {
- u32 rate;
- u32 idiv;
- u32 fbdiv;
- u32 odiv;
- u32 band;
+ const u32 rate;
+ const u8 idiv;
+ const u8 fbdiv;
+ const u8 odiv;
+ const u8 band;
};
static const struct hsdk_pll_cfg asdt_pll_cfg[] = {
@@ -227,28 +227,35 @@ static const struct hsdk_pll_cfg hdmi_pll_cfg[] = {
{}
};
-struct hsdk_cgu_clk {
- /* CGU block register */
- void __iomem *cgu_regs;
- /* CREG block register */
- void __iomem *creg_regs;
-
+struct hsdk_cgu_domain {
/* PLLs registers */
- void __iomem *regs;
+ void __iomem *pll_regs;
/* PLLs special registers */
void __iomem *spec_regs;
/* PLLs devdata */
- const struct hsdk_pll_devdata *pll_devdata;
+ const struct hsdk_pll_devdata *pll;
/* Dividers registers */
void __iomem *idiv_regs;
};
+struct hsdk_cgu_clk {
+ const struct cgu_clk_map *map;
+ /* CGU block register */
+ void __iomem *cgu_regs;
+ /* CREG block register */
+ void __iomem *creg_regs;
+
+ /* The domain we are working with */
+ struct hsdk_cgu_domain curr_domain;
+};
+
struct hsdk_pll_devdata {
const u32 parent_rate;
- const struct hsdk_pll_cfg *pll_cfg;
- int (*update_rate)(struct hsdk_cgu_clk *clk, unsigned long rate,
- const struct hsdk_pll_cfg *cfg);
+ const struct hsdk_pll_cfg *const pll_cfg;
+ const int (*const update_rate)(struct hsdk_cgu_clk *clk,
+ unsigned long rate,
+ const struct hsdk_pll_cfg *cfg);
};
static int hsdk_pll_core_update_rate(struct hsdk_cgu_clk *, unsigned long,
@@ -277,80 +284,110 @@ static const struct hsdk_pll_devdata hdmi_pll_dat = {
static ulong idiv_set(struct clk *, ulong);
static ulong cpu_clk_set(struct clk *, ulong);
static ulong axi_clk_set(struct clk *, ulong);
-static ulong tun_clk_set(struct clk *, ulong);
+static ulong tun_hsdk_set(struct clk *, ulong);
+static ulong tun_h4xd_set(struct clk *, ulong);
static ulong idiv_get(struct clk *);
static int idiv_off(struct clk *);
static ulong pll_set(struct clk *, ulong);
static ulong pll_get(struct clk *);
-struct hsdk_cgu_clock_map {
- u32 cgu_pll_oft;
- u32 creg_div_oft;
- u32 cgu_div_oft;
- const struct hsdk_pll_devdata *pll_devdata;
- ulong (*get_rate)(struct clk *clk);
- ulong (*set_rate)(struct clk *clk, ulong rate);
- int (*disable)(struct clk *clk);
+struct cgu_clk_map {
+ const u32 cgu_pll_oft;
+ const u32 cgu_div_oft;
+ const struct hsdk_pll_devdata *const pll_devdata;
+ const ulong (*const get_rate)(struct clk *clk);
+ const ulong (*const set_rate)(struct clk *clk, ulong rate);
+ const int (*const disable)(struct clk *clk);
+};
+
+static const struct cgu_clk_map hsdk_clk_map[] = {
+ [CLK_ARC_PLL] = { CGU_ARC_PLL, 0, &core_pll_dat, pll_get, pll_set, NULL },
+ [CLK_ARC] = { CGU_ARC_PLL, CGU_ARC_IDIV, &core_pll_dat, idiv_get, cpu_clk_set, idiv_off },
+ [CLK_DDR_PLL] = { CGU_DDR_PLL, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
+ [CLK_SYS_PLL] = { CGU_SYS_PLL, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
+ [CLK_SYS_APB] = { CGU_SYS_PLL, CGU_SYS_IDIV_APB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_AXI] = { CGU_SYS_PLL, CGU_SYS_IDIV_AXI, &sdt_pll_dat, idiv_get, axi_clk_set, idiv_off },
+ [CLK_SYS_ETH] = { CGU_SYS_PLL, CGU_SYS_IDIV_ETH, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_USB] = { CGU_SYS_PLL, CGU_SYS_IDIV_USB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_SDIO] = { CGU_SYS_PLL, CGU_SYS_IDIV_SDIO, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_HDMI] = { CGU_SYS_PLL, CGU_SYS_IDIV_HDMI, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_GFX_CORE] = { CGU_SYS_PLL, CGU_SYS_IDIV_GFX_CORE, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_GFX_DMA] = { CGU_SYS_PLL, CGU_SYS_IDIV_GFX_DMA, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_GFX_CFG] = { CGU_SYS_PLL, CGU_SYS_IDIV_GFX_CFG, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_DMAC_CORE] = { CGU_SYS_PLL, CGU_SYS_IDIV_DMAC_CORE, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_DMAC_CFG] = { CGU_SYS_PLL, CGU_SYS_IDIV_DMAC_CFG, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_SDIO_REF] = { CGU_SYS_PLL, CGU_SYS_IDIV_SDIO_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_SPI_REF] = { CGU_SYS_PLL, CGU_SYS_IDIV_SPI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_I2C_REF] = { CGU_SYS_PLL, CGU_SYS_IDIV_I2C_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_UART_REF] = { CGU_SYS_PLL, CGU_SYS_IDIV_UART_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_EBI_REF] = { CGU_SYS_PLL, CGU_SYS_IDIV_EBI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_TUN_PLL] = { CGU_TUN_PLL, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
+ [CLK_TUN_TUN] = { CGU_TUN_PLL, CGU_TUN_IDIV_TUN, &sdt_pll_dat, idiv_get, tun_hsdk_set, idiv_off },
+ [CLK_TUN_ROM] = { CGU_TUN_PLL, CGU_TUN_IDIV_ROM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_TUN_PWM] = { CGU_TUN_PLL, CGU_TUN_IDIV_PWM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_TUN_TIMER] = { /* missing in HSDK */ },
+ [CLK_HDMI_PLL] = { CGU_HDMI_PLL, 0, &hdmi_pll_dat, pll_get, pll_set, NULL },
+ [CLK_HDMI] = { CGU_HDMI_PLL, CGU_HDMI_IDIV_APB, &hdmi_pll_dat, idiv_get, idiv_set, idiv_off }
};
-static const struct hsdk_cgu_clock_map clock_map[] = {
- { CGU_ARC_PLL, 0, 0, &core_pll_dat, pll_get, pll_set, NULL },
- { CGU_ARC_PLL, 0, CGU_ARC_IDIV, &core_pll_dat, idiv_get, cpu_clk_set, idiv_off },
- { CGU_DDR_PLL, 0, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
- { CGU_SYS_PLL, 0, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
- { CGU_SYS_PLL, 0, CGU_SYS_IDIV_APB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
- { CGU_SYS_PLL, 0, CGU_SYS_IDIV_AXI, &sdt_pll_dat, idiv_get, axi_clk_set, idiv_off },
- { CGU_SYS_PLL, 0, CGU_SYS_IDIV_ETH, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
- { CGU_SYS_PLL, 0, CGU_SYS_IDIV_USB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
- { CGU_SYS_PLL, 0, CGU_SYS_IDIV_SDIO, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
- { CGU_SYS_PLL, 0, CGU_SYS_IDIV_HDMI, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
- { CGU_SYS_PLL, 0, CGU_SYS_IDIV_GFX_CORE, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
- { CGU_SYS_PLL, 0, CGU_SYS_IDIV_GFX_DMA, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
- { CGU_SYS_PLL, 0, CGU_SYS_IDIV_GFX_CFG, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
- { CGU_SYS_PLL, 0, CGU_SYS_IDIV_DMAC_CORE, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
- { CGU_SYS_PLL, 0, CGU_SYS_IDIV_DMAC_CFG, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
- { CGU_SYS_PLL, 0, CGU_SYS_IDIV_SDIO_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
- { CGU_SYS_PLL, 0, CGU_SYS_IDIV_SPI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
- { CGU_SYS_PLL, 0, CGU_SYS_IDIV_I2C_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
- { CGU_SYS_PLL, 0, CGU_SYS_IDIV_UART_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
- { CGU_SYS_PLL, 0, CGU_SYS_IDIV_EBI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
- { CGU_TUN_PLL, 0, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
- { CGU_TUN_PLL, 0, CGU_TUN_IDIV_TUN, &sdt_pll_dat, idiv_get, tun_clk_set, idiv_off },
- { CGU_TUN_PLL, 0, CGU_TUN_IDIV_ROM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
- { CGU_TUN_PLL, 0, CGU_TUN_IDIV_PWM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
- { CGU_TUN_PLL, 0, CGU_TUN_IDIV_TIMER, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
- { CGU_HDMI_PLL, 0, 0, &hdmi_pll_dat, pll_get, pll_set, NULL },
- { CGU_HDMI_PLL, 0, CGU_HDMI_IDIV_APB, &hdmi_pll_dat, idiv_get, idiv_set, idiv_off }
+static const struct cgu_clk_map hsdk_4xd_clk_map[] = {
+ [CLK_ARC_PLL] = { CGU_ARC_PLL, 0, &core_pll_dat, pll_get, pll_set, NULL },
+ [CLK_ARC] = { CGU_ARC_PLL, CGU_ARC_IDIV, &core_pll_dat, idiv_get, cpu_clk_set, idiv_off },
+ [CLK_DDR_PLL] = { CGU_DDR_PLL, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
+ [CLK_SYS_PLL] = { CGU_SYS_PLL, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
+ [CLK_SYS_APB] = { CGU_SYS_PLL, CGU_SYS_IDIV_APB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_AXI] = { CGU_SYS_PLL, CGU_SYS_IDIV_AXI, &sdt_pll_dat, idiv_get, axi_clk_set, idiv_off },
+ [CLK_SYS_ETH] = { CGU_SYS_PLL, CGU_SYS_IDIV_ETH, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_USB] = { CGU_SYS_PLL, CGU_SYS_IDIV_USB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_SDIO] = { CGU_SYS_PLL, CGU_SYS_IDIV_SDIO, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_HDMI] = { CGU_SYS_PLL, CGU_SYS_IDIV_HDMI, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_GFX_CORE] = { CGU_SYS_PLL, CGU_SYS_IDIV_GFX_CORE, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_GFX_DMA] = { /* missing in HSDK-4xD */ },
+ [CLK_SYS_GFX_CFG] = { /* missing in HSDK-4xD */ },
+ [CLK_SYS_DMAC_CORE] = { CGU_SYS_PLL, CGU_SYS_IDIV_DMAC_CORE, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_DMAC_CFG] = { CGU_SYS_PLL, CGU_SYS_IDIV_DMAC_CFG, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_SDIO_REF] = { CGU_SYS_PLL, CGU_SYS_IDIV_SDIO_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_SPI_REF] = { CGU_SYS_PLL, CGU_SYS_IDIV_SPI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_I2C_REF] = { CGU_SYS_PLL, CGU_SYS_IDIV_I2C_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_UART_REF] = { CGU_SYS_PLL, CGU_SYS_IDIV_UART_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_SYS_EBI_REF] = { CGU_SYS_PLL, CGU_SYS_IDIV_EBI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_TUN_PLL] = { CGU_TUN_PLL, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
+ [CLK_TUN_TUN] = { CGU_TUN_PLL, CGU_TUN_IDIV_TUN, &sdt_pll_dat, idiv_get, tun_h4xd_set, idiv_off },
+ [CLK_TUN_ROM] = { CGU_TUN_PLL, CGU_TUN_IDIV_ROM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_TUN_PWM] = { CGU_TUN_PLL, CGU_TUN_IDIV_PWM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_TUN_TIMER] = { CGU_TUN_PLL, CGU_TUN_IDIV_TIMER, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+ [CLK_HDMI_PLL] = { CGU_HDMI_PLL, 0, &hdmi_pll_dat, pll_get, pll_set, NULL },
+ [CLK_HDMI] = { CGU_HDMI_PLL, CGU_HDMI_IDIV_APB, &hdmi_pll_dat, idiv_get, idiv_set, idiv_off }
};
static inline void hsdk_idiv_write(struct hsdk_cgu_clk *clk, u32 val)
{
- iowrite32(val, clk->idiv_regs);
+ iowrite32(val, clk->curr_domain.idiv_regs);
}
static inline u32 hsdk_idiv_read(struct hsdk_cgu_clk *clk)
{
- return ioread32(clk->idiv_regs);
+ return ioread32(clk->curr_domain.idiv_regs);
}
static inline void hsdk_pll_write(struct hsdk_cgu_clk *clk, u32 reg, u32 val)
{
- iowrite32(val, clk->regs + reg);
+ iowrite32(val, clk->curr_domain.pll_regs + reg);
}
static inline u32 hsdk_pll_read(struct hsdk_cgu_clk *clk, u32 reg)
{
- return ioread32(clk->regs + reg);
+ return ioread32(clk->curr_domain.pll_regs + reg);
}
static inline void hsdk_pll_spcwrite(struct hsdk_cgu_clk *clk, u32 reg, u32 val)
{
- iowrite32(val, clk->spec_regs + reg);
+ iowrite32(val, clk->curr_domain.spec_regs + reg);
}
static inline u32 hsdk_pll_spcread(struct hsdk_cgu_clk *clk, u32 reg)
{
- return ioread32(clk->spec_regs + reg);
+ return ioread32(clk->curr_domain.spec_regs + reg);
}
static inline void hsdk_pll_set_cfg(struct hsdk_cgu_clk *clk,
@@ -359,10 +396,10 @@ static inline void hsdk_pll_set_cfg(struct hsdk_cgu_clk *clk,
u32 val = 0;
/* Powerdown and Bypass bits should be cleared */
- val |= cfg->idiv << CGU_PLL_CTRL_IDIV_SHIFT;
- val |= cfg->fbdiv << CGU_PLL_CTRL_FBDIV_SHIFT;
- val |= cfg->odiv << CGU_PLL_CTRL_ODIV_SHIFT;
- val |= cfg->band << CGU_PLL_CTRL_BAND_SHIFT;
+ val |= (u32)cfg->idiv << CGU_PLL_CTRL_IDIV_SHIFT;
+ val |= (u32)cfg->fbdiv << CGU_PLL_CTRL_FBDIV_SHIFT;
+ val |= (u32)cfg->odiv << CGU_PLL_CTRL_ODIV_SHIFT;
+ val |= (u32)cfg->band << CGU_PLL_CTRL_BAND_SHIFT;
pr_debug("write configurarion: %#x\n", val);
@@ -385,7 +422,7 @@ static ulong pll_get(struct clk *sclk)
u64 rate;
u32 idiv, fbdiv, odiv;
struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
- u32 parent_rate = clk->pll_devdata->parent_rate;
+ u32 parent_rate = clk->curr_domain.pll->parent_rate;
val = hsdk_pll_read(clk, CGU_PLL_CTRL);
@@ -417,7 +454,7 @@ static unsigned long hsdk_pll_round_rate(struct clk *sclk, unsigned long rate)
int i;
unsigned long best_rate;
struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
- const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg;
+ const struct hsdk_pll_cfg *pll_cfg = clk->curr_domain.pll->pll_cfg;
if (pll_cfg[0].rate == 0)
return -EINVAL;
@@ -493,19 +530,17 @@ static ulong pll_set(struct clk *sclk, ulong rate)
int i;
unsigned long best_rate;
struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
- const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg;
+ const struct hsdk_pll_devdata *pll = clk->curr_domain.pll;
+ const struct hsdk_pll_cfg *pll_cfg = pll->pll_cfg;
best_rate = hsdk_pll_round_rate(sclk, rate);
- for (i = 0; pll_cfg[i].rate != 0; i++) {
- if (pll_cfg[i].rate == best_rate) {
- return clk->pll_devdata->update_rate(clk, best_rate,
- &pll_cfg[i]);
- }
- }
+ for (i = 0; pll_cfg[i].rate != 0; i++)
+ if (pll_cfg[i].rate == best_rate)
+ return pll->update_rate(clk, best_rate, &pll_cfg[i]);
pr_err("invalid rate=%ld Hz, parent_rate=%d Hz\n", best_rate,
- clk->pll_devdata->parent_rate);
+ pll->parent_rate);
return -EINVAL;
}
@@ -546,8 +581,13 @@ static ulong cpu_clk_set(struct clk *sclk, ulong rate)
return ret;
}
-/* Special behavior: wen we set this clock we set both idiv and pll and all pll dividers */
-static ulong axi_clk_set(struct clk *sclk, ulong rate)
+/*
+ * Special behavior:
+ * when we set these clocks we set both PLL and all idiv dividers related to
+ * this PLL domain.
+ */
+static ulong common_div_clk_set(struct clk *sclk, ulong rate,
+ const struct hsdk_div_full_cfg *cfg)
{
struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
ulong pll_rate;
@@ -556,71 +596,52 @@ static ulong axi_clk_set(struct clk *sclk, ulong rate)
pll_rate = pll_get(sclk);
- for (i = 0; i < MAX_AXI_CLOCKS; i++) {
- if (axi_clk_cfg.clk_rate[i] == rate) {
+ for (i = 0; i < MAX_FREQ_VARIATIONS; i++) {
+ /* unused freq variations are filled with 0 */
+ if (!cfg->clk_rate[i])
+ break;
+
+ if (cfg->clk_rate[i] == rate) {
freq_idx = i;
break;
}
}
if (freq_idx < 0) {
- pr_err("axi clk: invalid rate=%ld Hz\n", rate);
+ pr_err("clk: invalid rate=%ld Hz\n", rate);
return -EINVAL;
}
/* configure PLL before dividers */
- if (axi_clk_cfg.pll_rate[freq_idx] < pll_rate)
- ret = pll_set(sclk, axi_clk_cfg.pll_rate[freq_idx]);
+ if (cfg->pll_rate[freq_idx] < pll_rate)
+ ret = pll_set(sclk, cfg->pll_rate[freq_idx]);
/* configure SYS dividers */
- for (i = 0; i < CGU_SYS_CLOCKS; i++) {
- clk->idiv_regs = clk->cgu_regs + axi_clk_cfg.idiv[i].oft;
- hsdk_idiv_write(clk, axi_clk_cfg.idiv[i].val[freq_idx]);
+ for (i = 0; cfg->idiv[i].oft != 0; i++) {
+ clk->curr_domain.idiv_regs = clk->cgu_regs + cfg->idiv[i].oft;
+ hsdk_idiv_write(clk, cfg->idiv[i].val[freq_idx]);
}
/* configure PLL after dividers */
- if (axi_clk_cfg.pll_rate[freq_idx] >= pll_rate)
- ret = pll_set(sclk, axi_clk_cfg.pll_rate[freq_idx]);
+ if (cfg->pll_rate[freq_idx] >= pll_rate)
+ ret = pll_set(sclk, cfg->pll_rate[freq_idx]);
return ret;
}
-static ulong tun_clk_set(struct clk *sclk, ulong rate)
+static ulong axi_clk_set(struct clk *sclk, ulong rate)
{
- struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
- ulong pll_rate;
- int i, freq_idx = -1;
- ulong ret = 0;
-
- pll_rate = pll_get(sclk);
-
- for (i = 0; i < MAX_TUN_CLOCKS; i++) {
- if (tun_clk_cfg.clk_rate[i] == rate) {
- freq_idx = i;
- break;
- }
- }
-
- if (freq_idx < 0) {
- pr_err("tun clk: invalid rate=%ld Hz\n", rate);
- return -EINVAL;
- }
-
- /* configure PLL before dividers */
- if (tun_clk_cfg.pll_rate[freq_idx] < pll_rate)
- ret = pll_set(sclk, tun_clk_cfg.pll_rate[freq_idx]);
-
- /* configure SYS dividers */
- for (i = 0; i < CGU_TUN_CLOCKS; i++) {
- clk->idiv_regs = clk->cgu_regs + tun_clk_cfg.idiv[i].oft;
- hsdk_idiv_write(clk, tun_clk_cfg.idiv[i].val[freq_idx]);
- }
+ return common_div_clk_set(sclk, rate, &axi_clk_cfg);
+}
- /* configure PLL after dividers */
- if (tun_clk_cfg.pll_rate[freq_idx] >= pll_rate)
- ret = pll_set(sclk, tun_clk_cfg.pll_rate[freq_idx]);
+static ulong tun_hsdk_set(struct clk *sclk, ulong rate)
+{
+ return common_div_clk_set(sclk, rate, &hsdk_tun_clk_cfg);
+}
- return ret;
+static ulong tun_h4xd_set(struct clk *sclk, ulong rate)
+{
+ return common_div_clk_set(sclk, rate, &hsdk_4xd_tun_clk_cfg);
}
static ulong idiv_set(struct clk *sclk, ulong rate)
@@ -661,37 +682,50 @@ static int hsdk_prepare_clock_tree_branch(struct clk *sclk)
if (sclk->id >= CGU_MAX_CLOCKS)
return -EINVAL;
- clk->pll_devdata = clock_map[sclk->id].pll_devdata;
- clk->regs = clk->cgu_regs + clock_map[sclk->id].cgu_pll_oft;
- clk->spec_regs = clk->creg_regs + clock_map[sclk->id].creg_div_oft;
- clk->idiv_regs = clk->cgu_regs + clock_map[sclk->id].cgu_div_oft;
+ /* clocks missing in current map have their entry zeroed */
+ if (!clk->map[sclk->id].pll_devdata)
+ return -EINVAL;
+
+ clk->curr_domain.pll = clk->map[sclk->id].pll_devdata;
+ clk->curr_domain.pll_regs = clk->cgu_regs + clk->map[sclk->id].cgu_pll_oft;
+ clk->curr_domain.spec_regs = clk->creg_regs;
+ clk->curr_domain.idiv_regs = clk->cgu_regs + clk->map[sclk->id].cgu_div_oft;
return 0;
}
static ulong hsdk_cgu_get_rate(struct clk *sclk)
{
+ struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
+
if (hsdk_prepare_clock_tree_branch(sclk))
return -EINVAL;
- return clock_map[sclk->id].get_rate(sclk);
+ return clk->map[sclk->id].get_rate(sclk);
}
static ulong hsdk_cgu_set_rate(struct clk *sclk, ulong rate)
{
+ struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
+
if (hsdk_prepare_clock_tree_branch(sclk))
return -EINVAL;
- return clock_map[sclk->id].set_rate(sclk, rate);
+ if (clk->map[sclk->id].set_rate)
+ return clk->map[sclk->id].set_rate(sclk, rate);
+
+ return -ENOTSUPP;
}
static int hsdk_cgu_disable(struct clk *sclk)
{
+ struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
+
if (hsdk_prepare_clock_tree_branch(sclk))
return -EINVAL;
- if (clock_map[sclk->id].disable)
- return clock_map[sclk->id].disable(sclk);
+ if (clk->map[sclk->id].disable)
+ return clk->map[sclk->id].disable(sclk);
return -ENOTSUPP;
}
@@ -704,16 +738,23 @@ static const struct clk_ops hsdk_cgu_ops = {
static int hsdk_cgu_clk_probe(struct udevice *dev)
{
- struct hsdk_cgu_clk *pll_clk = dev_get_priv(dev);
+ struct hsdk_cgu_clk *hsdk_clk = dev_get_priv(dev);
+
+ BUILD_BUG_ON(ARRAY_SIZE(hsdk_clk_map) != CGU_MAX_CLOCKS);
+ BUILD_BUG_ON(ARRAY_SIZE(hsdk_4xd_clk_map) != CGU_MAX_CLOCKS);
- BUILD_BUG_ON(ARRAY_SIZE(clock_map) != CGU_MAX_CLOCKS);
+ /* Choose which clock map to use in runtime */
+ if ((read_aux_reg(ARC_AUX_IDENTITY) & 0xFF) == 0x52)
+ hsdk_clk->map = hsdk_clk_map;
+ else
+ hsdk_clk->map = hsdk_4xd_clk_map;
- pll_clk->cgu_regs = (void __iomem *)devfdt_get_addr_index(dev, 0);
- if (!pll_clk->cgu_regs)
+ hsdk_clk->cgu_regs = (void __iomem *)devfdt_get_addr_index(dev, 0);
+ if (!hsdk_clk->cgu_regs)
return -EINVAL;
- pll_clk->creg_regs = (void __iomem *)devfdt_get_addr_index(dev, 1);
- if (!pll_clk->creg_regs)
+ hsdk_clk->creg_regs = (void __iomem *)devfdt_get_addr_index(dev, 1);
+ if (!hsdk_clk->creg_regs)
return -EINVAL;
return 0;
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 757ab7106ee..d3cea11f76e 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -526,6 +526,21 @@ int dm_gpio_set_value(const struct gpio_desc *desc, int value)
if (desc->flags & GPIOD_ACTIVE_LOW)
value = !value;
+
+ /*
+ * Emulate open drain by not actively driving the line high or
+ * Emulate open source by not actively driving the line low
+ */
+ if ((desc->flags & GPIOD_OPEN_DRAIN && value) ||
+ (desc->flags & GPIOD_OPEN_SOURCE && !value))
+ return gpio_get_ops(desc->dev)->direction_input(desc->dev,
+ desc->offset);
+ else if (desc->flags & GPIOD_OPEN_DRAIN ||
+ desc->flags & GPIOD_OPEN_SOURCE)
+ return gpio_get_ops(desc->dev)->direction_output(desc->dev,
+ desc->offset,
+ value);
+
gpio_get_ops(desc->dev)->set_value(desc->dev, desc->offset, value);
return 0;
}
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index a8982bdc094..0972e458eb0 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -377,6 +377,9 @@ static void dwc3_phy_setup(struct dwc3 *dwc)
if (dwc->dis_u3_susphy_quirk)
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
+ if (dwc->dis_del_phy_power_chg_quirk)
+ reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE;
+
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
mdelay(100);
@@ -715,6 +718,7 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev)
dwc->rx_detect_poll_quirk = dwc3_dev->rx_detect_poll_quirk;
dwc->dis_u3_susphy_quirk = dwc3_dev->dis_u3_susphy_quirk;
dwc->dis_u2_susphy_quirk = dwc3_dev->dis_u2_susphy_quirk;
+ dwc->dis_del_phy_power_chg_quirk = dwc3_dev->dis_del_phy_power_chg_quirk;
dwc->tx_de_emphasis_quirk = dwc3_dev->tx_de_emphasis_quirk;
if (dwc3_dev->tx_de_emphasis)
@@ -920,6 +924,8 @@ void dwc3_of_parse(struct dwc3 *dwc)
"snps,dis_u3_susphy_quirk");
dwc->dis_u2_susphy_quirk = dev_read_bool(dev,
"snps,dis_u2_susphy_quirk");
+ dwc->dis_del_phy_power_chg_quirk = dev_read_bool(dev,
+ "snps,dis-del-phy-power-chg-quirk");
dwc->tx_de_emphasis_quirk = dev_read_bool(dev,
"snps,tx_de_emphasis_quirk");
tmp = dev_read_u8_array_ptr(dev, "snps,tx_de_emphasis", 1);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 1c08a2c5b6e..7f45a9c4597 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -821,6 +821,7 @@ struct dwc3 {
unsigned rx_detect_poll_quirk:1;
unsigned dis_u3_susphy_quirk:1;
unsigned dis_u2_susphy_quirk:1;
+ unsigned dis_del_phy_power_chg_quirk:1;
unsigned tx_de_emphasis_quirk:1;
unsigned tx_de_emphasis:2;
diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c
index eabd53a36dc..175866cf4de 100644
--- a/drivers/usb/dwc3/dwc3-generic.c
+++ b/drivers/usb/dwc3/dwc3-generic.c
@@ -420,6 +420,7 @@ static int dwc3_glue_remove(struct udevice *dev)
static const struct udevice_id dwc3_glue_ids[] = {
{ .compatible = "xlnx,zynqmp-dwc3" },
+ { .compatible = "xlnx,versal-dwc3" },
{ .compatible = "ti,keystone-dwc3"},
{ .compatible = "ti,dwc3", .data = (ulong)&ti_ops },
{ .compatible = "ti,am437x-dwc3", .data = (ulong)&ti_ops },
diff --git a/include/dwc3-uboot.h b/include/dwc3-uboot.h
index ce835fd1b2b..ecae34bf069 100644
--- a/include/dwc3-uboot.h
+++ b/include/dwc3-uboot.h
@@ -33,6 +33,7 @@ struct dwc3_device {
unsigned rx_detect_poll_quirk;
unsigned dis_u3_susphy_quirk;
unsigned dis_u2_susphy_quirk;
+ unsigned dis_del_phy_power_chg_quirk;
unsigned tx_de_emphasis_quirk;
unsigned tx_de_emphasis;
int index;
diff --git a/test/dm/gpio.c b/test/dm/gpio.c
index f5c7aaf3bce..7c18e5c4119 100644
--- a/test/dm/gpio.c
+++ b/test/dm/gpio.c
@@ -112,6 +112,95 @@ static int dm_test_gpio(struct unit_test_state *uts)
}
DM_TEST(dm_test_gpio, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+/* Test that GPIO open-drain/open-source emulation works correctly */
+static int dm_test_gpio_opendrain_opensource(struct unit_test_state *uts)
+{
+ struct gpio_desc desc_list[8];
+ struct udevice *dev, *gpio_c;
+ char buf[80];
+
+ ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+ ut_asserteq_str("a-test", dev->name);
+
+ ut_assertok(uclass_get_device(UCLASS_GPIO, 3, &gpio_c));
+ ut_asserteq_str("pinmux-gpios", gpio_c->name);
+
+ ut_asserteq(8, gpio_request_list_by_name(dev, "test3-gpios", desc_list,
+ ARRAY_SIZE(desc_list), 0))
+
+ ut_asserteq(true, !!device_active(gpio_c));
+ ut_asserteq_ptr(gpio_c, desc_list[0].dev);
+ ut_asserteq_ptr(gpio_c, desc_list[1].dev);
+ ut_asserteq_ptr(gpio_c, desc_list[2].dev);
+ ut_asserteq_ptr(gpio_c, desc_list[3].dev);
+ ut_asserteq_ptr(gpio_c, desc_list[4].dev);
+ ut_asserteq_ptr(gpio_c, desc_list[5].dev);
+ ut_asserteq_ptr(gpio_c, desc_list[6].dev);
+ ut_asserteq_ptr(gpio_c, desc_list[7].dev);
+
+ /* GPIO 0 is (GPIO_OUT|GPIO_OPEN_DRAIN) */
+ ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN,
+ sandbox_gpio_get_dir_flags(gpio_c, 0));
+
+ /* Set it as output high, should become an input */
+ ut_assertok(dm_gpio_set_value(&desc_list[0], 1));
+ ut_assertok(gpio_get_status(gpio_c, 0, buf, sizeof(buf)));
+ ut_asserteq_str("c0: input: 0 [x] a-test.test3-gpios0", buf);
+
+ /* Set it as output low, should become output low */
+ ut_assertok(dm_gpio_set_value(&desc_list[0], 0));
+ ut_assertok(gpio_get_status(gpio_c, 0, buf, sizeof(buf)));
+ ut_asserteq_str("c0: output: 0 [x] a-test.test3-gpios0", buf);
+
+ /* GPIO 1 is (GPIO_OUT|GPIO_OPEN_SOURCE) */
+ ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_SOURCE,
+ sandbox_gpio_get_dir_flags(gpio_c, 1));
+
+ /* Set it as output high, should become output high */
+ ut_assertok(dm_gpio_set_value(&desc_list[1], 1));
+ ut_assertok(gpio_get_status(gpio_c, 1, buf, sizeof(buf)));
+ ut_asserteq_str("c1: output: 1 [x] a-test.test3-gpios1", buf);
+
+ /* Set it as output low, should become an input */
+ ut_assertok(dm_gpio_set_value(&desc_list[1], 0));
+ ut_assertok(gpio_get_status(gpio_c, 1, buf, sizeof(buf)));
+ ut_asserteq_str("c1: input: 1 [x] a-test.test3-gpios1", buf);
+
+ /* GPIO 6 is (GPIO_ACTIVE_LOW|GPIO_OUT|GPIO_OPEN_DRAIN) */
+ ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_DRAIN,
+ sandbox_gpio_get_dir_flags(gpio_c, 6));
+
+ /* Set it as output high, should become output low */
+ ut_assertok(dm_gpio_set_value(&desc_list[6], 1));
+ ut_assertok(gpio_get_status(gpio_c, 6, buf, sizeof(buf)));
+ ut_asserteq_str("c6: output: 0 [x] a-test.test3-gpios6", buf);
+
+ /* Set it as output low, should become an input */
+ ut_assertok(dm_gpio_set_value(&desc_list[6], 0));
+ ut_assertok(gpio_get_status(gpio_c, 6, buf, sizeof(buf)));
+ ut_asserteq_str("c6: input: 0 [x] a-test.test3-gpios6", buf);
+
+ /* GPIO 7 is (GPIO_ACTIVE_LOW|GPIO_OUT|GPIO_OPEN_SOURCE) */
+ ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_SOURCE,
+ sandbox_gpio_get_dir_flags(gpio_c, 7));
+
+ /* Set it as output high, should become an input */
+ ut_assertok(dm_gpio_set_value(&desc_list[7], 1));
+ ut_assertok(gpio_get_status(gpio_c, 7, buf, sizeof(buf)));
+ ut_asserteq_str("c7: input: 0 [x] a-test.test3-gpios7", buf);
+
+ /* Set it as output low, should become output high */
+ ut_assertok(dm_gpio_set_value(&desc_list[7], 0));
+ ut_assertok(gpio_get_status(gpio_c, 7, buf, sizeof(buf)));
+ ut_asserteq_str("c7: output: 1 [x] a-test.test3-gpios7", buf);
+
+ ut_assertok(gpio_free_list(dev, desc_list, 8));
+
+ return 0;
+}
+DM_TEST(dm_test_gpio_opendrain_opensource,
+ DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
/* Test that sandbox anonymous GPIOs work correctly */
static int dm_test_gpio_anon(struct unit_test_state *uts)
{