atmel_sdhci: SDMMC_CD pin still needed for card detection despite EMMC set to non-removable

2023-04-27 Thread Zixun Li
Hardware: SAMA5D27 customized board, EMMC connected to SDMMC0. SDMMC0_CD pin 
pulled-down for BootROM card detection, once booted it used as LED output.

Software: u-boot-at91 76f7f55

Issue:
U-Boot can't detect EMMC despite it set to non-removable in DT, unless 
SDMMC0_CD pin is used (so this pin can't be used for other purpose)

sdmmc0: sdio-host@a000 {
bus-width = <4>;
pinctrl-names = "default";
pinctrl-0 = 
<&pinctrl_sdmmc0_default>;
status = "okay";
non-removable;
no-1-8-v;
};

Workaround: I have to FCD bit of SDMMC_MC1R register.

diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 766e4a6b0c..89ceeaf3c1 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -758,7 +758,12 @@ static int sdhci_get_cd(struct udevice *dev)

/* If nonremovable, assume that the card is always present. */
if (mmc->cfg->host_caps & MMC_CAP_NONREMOVABLE)
+   {
+   value = sdhci_readb(host, SDHCI_HOST_MC1R);
+   sdhci_writeb(host, SDHCI_VENDOR_MC1R_FCD | value, 
SDHCI_HOST_MC1R);
return 1;
+   }
+
/* If polling, assume that the card is always present. */
if (mmc->cfg->host_caps & MMC_CAP_NEEDS_POLL)
return 1;
diff --git a/include/sdhci.h b/include/sdhci.h
index c718dd7206..61e7ebb2a1 100644
--- a/include/sdhci.h
+++ b/include/sdhci.h
@@ -223,6 +223,9 @@

#define SDHCI_GET_VERSION(x) (x->version & SDHCI_SPEC_VER_MASK)

+#define SDHCI_HOST_MC1R0x204
+
+#define SDHCI_VENDOR_MC1R_FCD  0x80
/*
  * End of controller registers.
  */



RE: atmel_sdhci: SDMMC_CD pin still needed for card detection despite EMMC set to non-removable

2023-05-01 Thread Zixun Li
Hi,

> Can you find some place to set this bit in the atmel sdhci driver, and not in 
> the core?
> The MC1R register is specific to at91 device.

I've overridden get_cd of the driver, below is the patch:

From e186af71297e9ae6ce241a85bff64683949f0e1b Mon Sep 17 00:00:00 2001
From: Zixun LI 
Date: Mon, 1 May 2023 14:02:21 +0200
Subject: [PATCH] atmel_sdhci: Force card-detect if MMC_CAP_NONREMOVABLE.

Signed-off-by:  Zixun LI 
---
 drivers/mmc/atmel_sdhci.c | 37 +
 1 file changed, 37 insertions(+)

diff --git a/drivers/mmc/atmel_sdhci.c b/drivers/mmc/atmel_sdhci.c
index 37b0beeed4..fa32055d1f 100644
--- a/drivers/mmc/atmel_sdhci.c
+++ b/drivers/mmc/atmel_sdhci.c
@@ -15,6 +15,9 @@
 #define ATMEL_SDHC_MIN_FREQ40
 #define ATMEL_SDHC_GCK_RATE24000

+#define ATMEL_SDHC_MC1R 0x204
+#define ATMEL_SDHC_MC1R_FCD0x80
+
 #ifndef CONFIG_DM_MMC
 int atmel_sdhci_init(void *regbase, u32 id)
 {
@@ -59,8 +62,42 @@ static int atmel_sdhci_deferred_probe(struct sdhci_host 
*host)
return sdhci_probe(dev);
 }

+static int atmel_sdhci_get_cd(struct sdhci_host *host)
+{
+   struct mmc *mmc = host->mmc;
+   int value;
+
+   /* If nonremovable, assume that the card is always present. */
+   if (mmc->cfg->host_caps & MMC_CAP_NONREMOVABLE)
+   {
+   value = sdhci_readb(host, ATMEL_SDHC_MC1R);
+   sdhci_writeb(host, ATMEL_SDHC_MC1R_FCD | value, 
ATMEL_SDHC_MC1R);
+   return 1;
+   }
+   /* If polling, assume that the card is always present. */
+   if (mmc->cfg->host_caps & MMC_CAP_NEEDS_POLL)
+   return 1;
+
+#if CONFIG_IS_ENABLED(DM_GPIO)
+   value = dm_gpio_get_value(&host->cd_gpio);
+   if (value >= 0) {
+   if (mmc->cfg->host_caps & MMC_CAP_CD_ACTIVE_HIGH)
+   return !value;
+   else
+   return value;
+   }
+#endif
+   value = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
+  SDHCI_CARD_PRESENT);
+   if (mmc->cfg->host_caps & MMC_CAP_CD_ACTIVE_HIGH)
+   return !value;
+   else
+   return value;
+}
+
 static const struct sdhci_ops atmel_sdhci_ops = {
.deferred_probe = atmel_sdhci_deferred_probe,
+   .get_cd = atmel_sdhci_get_cd,
 };

 static int atmel_sdhci_probe(struct udevice *dev)
--
2.40.1


RE: atmel_sdhci: SDMMC_CD pin still needed for card detection despite EMMC set to non-removable

2023-05-04 Thread Zixun Li
>  Can't we do this in a different place?
> When we parse the DT for example. If the card is non-removable, this is 
> described as a property in the DT.
> In this way you don't have to recreate all the below code from the common 
> sdhci_get_cd, and you avoid rewriting the MC1R every time the get_cd is 
> called.

The problem is inside sdhci_init() there is a sdhci_reset(), FCD bit will lost 
if we set it too early.

Then I've looked at the kernel driver, setting this bit is also a workaround of 
SAMA5D2 series, who doesn't drive CMD if using CD GPIO line.

https://github.com/linux4sam/linux-at91/blob/068eaa6b4b087b3a86fc4624d0f4083844e93f1c/drivers/mmc/host/sdhci-of-at91.c#L551

I've refactored the code, setting FCD bit after sdhci_probe() with a separate 
function to make the purpose more clear.


From 90177e7af8226b88dfbfc08639f768881562a3a2 Mon Sep 17 00:00:00 2001
From: Zixun LI 
Date: Thu, 4 May 2023 16:30:41 +0200
Subject: [PATCH] atmel_sdhci: Force card-detect if MMC_CAP_NONREMOVABLE.

---
 drivers/mmc/atmel_sdhci.c | 40 +--
 1 file changed, 38 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/atmel_sdhci.c b/drivers/mmc/atmel_sdhci.c
index 37b0beeed4..ae56266f57 100644
--- a/drivers/mmc/atmel_sdhci.c
+++ b/drivers/mmc/atmel_sdhci.c
@@ -15,6 +15,9 @@
 #define ATMEL_SDHC_MIN_FREQ40
 #define ATMEL_SDHC_GCK_RATE24000

+#define ATMEL_SDHC_MC1R 0x204
+#define ATMEL_SDHC_MC1R_FCD0x80
+
 #ifndef CONFIG_DM_MMC
 int atmel_sdhci_init(void *regbase, u32 id)
 {
@@ -52,11 +55,38 @@ struct atmel_sdhci_plat {
struct mmc mmc;
 };

+static void atmel_sdhci_config_fcd(struct sdhci_host *host)
+{
+   u8 mc1r;
+
+   /* If nonremovable, assume that the card is always present.
+*
+* WA: SAMA5D2 doesn't drive CMD if using CD GPIO line.
+*/
+   if ((host->mmc->cfg->host_caps & MMC_CAP_NONREMOVABLE)
+#if CONFIG_IS_ENABLED(DM_GPIO)
+   || dm_gpio_get_value(&host->cd_gpio) >= 0
+#endif
+  )
+   {
+   sdhci_readb(host, ATMEL_SDHC_MC1R);
+   mc1r |= ATMEL_SDHC_MC1R_FCD;
+   sdhci_writeb(host, mc1r, ATMEL_SDHC_MC1R);
+   }
+}
+
 static int atmel_sdhci_deferred_probe(struct sdhci_host *host)
 {
struct udevice *dev = host->mmc->dev;
+   int ret;

-   return sdhci_probe(dev);
+   ret = sdhci_probe(dev);
+   if (ret)
+   return ret;
+
+   atmel_sdhci_config_fcd(host);
+
+   return 0;
 }

 static const struct sdhci_ops atmel_sdhci_ops = {
@@ -120,7 +150,13 @@ static int atmel_sdhci_probe(struct udevice *dev)

clk_free(&clk);

-   return sdhci_probe(dev);
+   ret = sdhci_probe(dev);
+   if (ret)
+   return ret;
+
+   atmel_sdhci_config_fcd(host);
+
+   return 0;
 }

 static int atmel_sdhci_bind(struct udevice *dev)
--
2.40.1



[PATCH v2] atmel_sdhci: Force card-detect if MMC_CAP_NONREMOVABLE.

2023-05-15 Thread Zixun LI
Signed-off-by:  Zixun LI 
---
 drivers/mmc/atmel_sdhci.c | 40 +--
 1 file changed, 38 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/atmel_sdhci.c b/drivers/mmc/atmel_sdhci.c
index 37b0beeed4..ae56266f57 100644
--- a/drivers/mmc/atmel_sdhci.c
+++ b/drivers/mmc/atmel_sdhci.c
@@ -15,6 +15,9 @@
 #define ATMEL_SDHC_MIN_FREQ40
 #define ATMEL_SDHC_GCK_RATE24000
 
+#define ATMEL_SDHC_MC1R 0x204
+#define ATMEL_SDHC_MC1R_FCD0x80
+
 #ifndef CONFIG_DM_MMC
 int atmel_sdhci_init(void *regbase, u32 id)
 {
@@ -52,11 +55,38 @@ struct atmel_sdhci_plat {
struct mmc mmc;
 };
 
+static void atmel_sdhci_config_fcd(struct sdhci_host *host)
+{
+   u8 mc1r;
+
+   /* If nonremovable, assume that the card is always present.
+*
+* WA: SAMA5D2 doesn't drive CMD if using CD GPIO line.
+*/
+   if ((host->mmc->cfg->host_caps & MMC_CAP_NONREMOVABLE)
+#if CONFIG_IS_ENABLED(DM_GPIO)
+   || dm_gpio_get_value(&host->cd_gpio) >= 0
+#endif
+  )
+   {
+   sdhci_readb(host, ATMEL_SDHC_MC1R);
+   mc1r |= ATMEL_SDHC_MC1R_FCD;
+   sdhci_writeb(host, mc1r, ATMEL_SDHC_MC1R);
+   }
+}
+
 static int atmel_sdhci_deferred_probe(struct sdhci_host *host)
 {
struct udevice *dev = host->mmc->dev;
+   int ret;
 
-   return sdhci_probe(dev);
+   ret = sdhci_probe(dev);
+   if (ret)
+   return ret;
+
+   atmel_sdhci_config_fcd(host);
+
+   return 0;
 }
 
 static const struct sdhci_ops atmel_sdhci_ops = {
@@ -120,7 +150,13 @@ static int atmel_sdhci_probe(struct udevice *dev)
 
clk_free(&clk);
 
-   return sdhci_probe(dev);
+   ret = sdhci_probe(dev);
+   if (ret)
+   return ret;
+
+   atmel_sdhci_config_fcd(host);
+
+   return 0;
 }
 
 static int atmel_sdhci_bind(struct udevice *dev)
-- 
2.40.1



[PATCH v2] atmel_sdhci: Force card-detect if MMC_CAP_NONREMOVABLE.

2023-05-17 Thread Zixun LI
If the device attached to the MMC bus is not removable, set force card-detect
bit to bypass card detection procedure, so card detection pin can be used for
other purposes.

It's also a workaround for SAMA5D2 who doesn't drive CMD if using GPIO for card
detection.

Signed-off-by: Zixun LI 
---
 drivers/mmc/atmel_sdhci.c | 40 +--
 1 file changed, 38 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/atmel_sdhci.c b/drivers/mmc/atmel_sdhci.c
index 37b0beeed4..ae56266f57 100644
--- a/drivers/mmc/atmel_sdhci.c
+++ b/drivers/mmc/atmel_sdhci.c
@@ -15,6 +15,9 @@
 #define ATMEL_SDHC_MIN_FREQ40
 #define ATMEL_SDHC_GCK_RATE24000
 
+#define ATMEL_SDHC_MC1R 0x204
+#define ATMEL_SDHC_MC1R_FCD0x80
+
 #ifndef CONFIG_DM_MMC
 int atmel_sdhci_init(void *regbase, u32 id)
 {
@@ -52,11 +55,38 @@ struct atmel_sdhci_plat {
struct mmc mmc;
 };
 
+static void atmel_sdhci_config_fcd(struct sdhci_host *host)
+{
+   u8 mc1r;
+
+   /* If nonremovable, assume that the card is always present.
+*
+* WA: SAMA5D2 doesn't drive CMD if using CD GPIO line.
+*/
+   if ((host->mmc->cfg->host_caps & MMC_CAP_NONREMOVABLE)
+#if CONFIG_IS_ENABLED(DM_GPIO)
+   || dm_gpio_get_value(&host->cd_gpio) >= 0
+#endif
+  )
+   {
+   sdhci_readb(host, ATMEL_SDHC_MC1R);
+   mc1r |= ATMEL_SDHC_MC1R_FCD;
+   sdhci_writeb(host, mc1r, ATMEL_SDHC_MC1R);
+   }
+}
+
 static int atmel_sdhci_deferred_probe(struct sdhci_host *host)
 {
struct udevice *dev = host->mmc->dev;
+   int ret;
 
-   return sdhci_probe(dev);
+   ret = sdhci_probe(dev);
+   if (ret)
+   return ret;
+
+   atmel_sdhci_config_fcd(host);
+
+   return 0;
 }
 
 static const struct sdhci_ops atmel_sdhci_ops = {
@@ -120,7 +150,13 @@ static int atmel_sdhci_probe(struct udevice *dev)
 
clk_free(&clk);
 
-   return sdhci_probe(dev);
+   ret = sdhci_probe(dev);
+   if (ret)
+   return ret;
+
+   atmel_sdhci_config_fcd(host);
+
+   return 0;
 }
 
 static int atmel_sdhci_bind(struct udevice *dev)
-- 
2.40.1



[PATCH] mtd: nand: raw: atmel: Use ONFI ECC params if available

2024-07-09 Thread Zixun Li
When ECC parameters are not specified in DT, first try ONFI ECC parameters
before fallback to maximum strength. To be inline with kernel driver behavior.

Signed-off-by: Zixun LI 
---
 drivers/mtd/nand/raw/atmel/nand-controller.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c 
b/drivers/mtd/nand/raw/atmel/nand-controller.c
index 9873d11254..d29a9c6f10 100644
--- a/drivers/mtd/nand/raw/atmel/nand-controller.c
+++ b/drivers/mtd/nand/raw/atmel/nand-controller.c
@@ -1064,11 +1064,15 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip)
req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
else if (chip->ecc.strength)
req.ecc.strength = chip->ecc.strength;
+   else if(chip->ecc_strength_ds)
+   req.ecc.strength = chip->ecc_strength_ds;
else
req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
 
if (chip->ecc.size)
req.ecc.sectorsize = chip->ecc.size;
+   else if(chip->ecc_step_ds)
+   req.ecc.sectorsize = chip->ecc_step_ds;
else
req.ecc.sectorsize = ATMEL_PMECC_SECTOR_SIZE_AUTO;
 
-- 
2.45.1



RE: [PATCH] mtd: nand: raw: atmel: Use ONFI ECC params if available

2024-07-18 Thread Zixun Li
On 10/07/2024 09:28, Alexander Dahl wrote:

> Despite the missing space between 'if' and the opening bracket (checkpatch
> should have told you?) this looks very much like what got into linux with 
> v4.11
> but was changed/reworked multiple times afterwards.  I wonder why this was
> not ported to U-Boot when introducing this driver?  In 6a8dfd57220d ("nand:
> atmel: Add DM based NAND driver") it was claimed the driver was ported
> from linux-5.4-at91, so this feature was probably dropped intentionally?
> Does anyone know why?
> 

Hi,

Sorry for the format issue. Is there any comment from maintainers ?

I'll push a v2 if this patch is considered.
--
Zixun LI




[PATCH RFC] usb: gadget: atmel: Add DM_USB_GADGET support

2024-07-19 Thread Zixun Li
Add driver model support by using the uclass UCLASS_USB_GADGET_GENERIC.

Disable local usb_gadget_register_driver()/usb_gadget_unregister_driver()
implementation which is implemented in udc-core.c when DM_USB_GADGET
is enabled.

Compared to Linux driver sam9x60 and sama7g5 DT bindings are not included
as they are not supported by the driver yet.

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/atmel_usba_udc.c | 196 
 1 file changed, 169 insertions(+), 27 deletions(-)

diff --git a/drivers/usb/gadget/atmel_usba_udc.c 
b/drivers/usb/gadget/atmel_usba_udc.c
index f99553df8d..40e8b895a0 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -17,9 +17,19 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
+
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+#include 
+#endif /* CONFIG_IS_ENABLED(DM_USB_GADGET) */
 
 #include "atmel_usba_udc.h"
 
+static struct usba_udc *controller;
+
 static int vbus_is_present(struct usba_udc *udc)
 {
/* No Vbus detection: Assume always present */
@@ -506,12 +516,6 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int 
is_selfpowered)
return 0;
 }
 
-static const struct usb_gadget_ops usba_udc_ops = {
-   .get_frame  = usba_udc_get_frame,
-   .wakeup = usba_udc_wakeup,
-   .set_selfpowered= usba_udc_set_selfpowered,
-};
-
 static struct usb_endpoint_descriptor usba_ep0_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -1153,7 +1157,7 @@ static int usba_udc_irq(struct usba_udc *udc)
return 0;
 }
 
-static int atmel_usba_start(struct usba_udc *udc)
+static int usba_enable(struct usba_udc *udc)
 {
udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
 
@@ -1168,7 +1172,7 @@ static int atmel_usba_start(struct usba_udc *udc)
return 0;
 }
 
-static int atmel_usba_stop(struct usba_udc *udc)
+static int usba_disable(struct usba_udc *udc)
 {
udc->gadget.speed = USB_SPEED_UNKNOWN;
reset_all_endpoints(udc);
@@ -1179,28 +1183,29 @@ static int atmel_usba_stop(struct usba_udc *udc)
return 0;
 }
 
-static struct usba_udc controller = {
-   .regs = (unsigned *)ATMEL_BASE_UDPHS,
-   .fifo = (unsigned *)ATMEL_BASE_UDPHS_FIFO,
-   .gadget = {
-   .ops= &usba_udc_ops,
-   .ep_list= LIST_HEAD_INIT(controller.gadget.ep_list),
-   .speed  = USB_SPEED_HIGH,
-   .is_dualspeed   = 1,
-   .name   = "atmel_usba_udc",
-   },
-};
+static int usba_gadget_pullup(struct usb_gadget *g, int is_on)
+{
+   struct usba_udc *udc = controller;
+   u32 ctrl;
+
+   ctrl = usba_readl(udc, CTRL);
+
+   usba_writel(udc, CTRL, is_on ? ctrl & ~USBA_DETACH : ctrl | 
USBA_DETACH);
+
+   return 0;
+}
 
 int dm_usb_gadget_handle_interrupts(struct udevice *dev)
 {
-   struct usba_udc *udc = &controller;
+   struct usba_udc *udc = controller;
 
return usba_udc_irq(udc);
 }
 
+#if !CONFIG_IS_ENABLED(DM_USB_GADGET)
 int usb_gadget_register_driver(struct usb_gadget_driver *driver)
 {
-   struct usba_udc *udc = &controller;
+   struct usba_udc *udc = controller;
int ret;
 
if (!driver || !driver->bind || !driver->setup) {
@@ -1213,7 +1218,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver 
*driver)
return -EBUSY;
}
 
-   atmel_usba_start(udc);
+   usba_enable(udc);
 
udc->driver = driver;
 
@@ -1228,7 +1233,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver 
*driver)
 
 int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 {
-   struct usba_udc *udc = &controller;
+   struct usba_udc *udc = controller;
 
if (!driver || !driver->unbind || !driver->disconnect) {
pr_err("bad paramter\n");
@@ -1239,11 +1244,54 @@ int usb_gadget_unregister_driver(struct 
usb_gadget_driver *driver)
driver->unbind(&udc->gadget);
udc->driver = NULL;
 
-   atmel_usba_stop(udc);
+   usba_disable(udc);
+
+   return 0;
+}
+#else /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */
+
+static int usba_gadget_start(struct usb_gadget *g,
+struct usb_gadget_driver *driver)
+{
+   struct usba_udc *udc = controller;
+
+   if (!driver || !driver->bind || !driver->setup) {
+   printf("bad parameter\n");
+   return -EINVAL;
+   }
+
+   if (udc->driver) {
+   printf("UDC already has a gadget driver\n");
+   return -EBUSY;
+   }
+
+   usba_enable(udc);
+
+   udc->driver = driver;
+
+   return 0;
+}
+
+static int usba_gadget_stop(struct usb_gadget *g)
+{
+   struct usba_udc *udc = controller;
+
+   if (!udc)
+  

usb gadget driver initialization issue

2024-07-20 Thread Zixun Li
Hi,

In udc_bind_to_driver(), USB device controller is initialized by 
usb_gadget_udc_start() and entered connected state by usb_gadget_connect().

From the host's point of view, a device is ready to be enumerated.
However, since dm_usb_gadget_handle_interrupts() is only called inside 
function driver, at this stage USB events are not managed, host's
enumeration attempts will fail and resulting error like:
usb 1-1: new high-speed USB device number 50 using xhci_hcd
usb 1-1: device descriptor read/64, error -110
usb 1-1: device descriptor read/64, error -110
usb usb1-port1: attempt power cycle

I think it's better to leave the device in disconnected state while 
probing and connect it once a gadget function is invoked.

I see recently there are many DM related reworking, please forgive me 
if it's already on the Todo list.

--
Zixun LI


[PATCH v2] mtd: nand: raw: atmel: Use ONFI ECC params if available

2024-07-22 Thread Zixun LI
When ECC parameters are not specified in DT, first try ONFI ECC parameters
before fallback to maximum strength.

It's the Linux driver behavior since the driver rewriting in f88fc12.

>From then 2 nand system refactors have been done in 6a1b66d6 and 53576c7b,
chip->ecc_strength_ds and chip->ecc_step_ds became
nanddev_get_ecc_requirements(). U-Boot didn't follow the refactor and
always use these 2 fields.

v2: Fix formatting, add upstream commit hash.

Signed-off-by: Zixun LI 
---
 drivers/mtd/nand/raw/atmel/nand-controller.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c 
b/drivers/mtd/nand/raw/atmel/nand-controller.c
index ee4ec6da58..817fab4ca3 100644
--- a/drivers/mtd/nand/raw/atmel/nand-controller.c
+++ b/drivers/mtd/nand/raw/atmel/nand-controller.c
@@ -1029,11 +1029,15 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip)
req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
else if (chip->ecc.strength)
req.ecc.strength = chip->ecc.strength;
+   else if (chip->ecc_strength_ds)
+   req.ecc.strength = chip->ecc_strength_ds;
else
req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
 
if (chip->ecc.size)
req.ecc.sectorsize = chip->ecc.size;
+   else if (chip->ecc_step_ds)
+   req.ecc.sectorsize = chip->ecc_step_ds;
else
req.ecc.sectorsize = ATMEL_PMECC_SECTOR_SIZE_AUTO;
 
-- 
2.45.2



RE: usb gadget driver initialization issue

2024-07-22 Thread Zixun Li
> -Original Message-
> From: Marek Vasut 
> Sent: Saturday, July 20, 2024 22:12
> 
> Can you please send an RFC patch ?
> 
> > I see recently there are many DM related reworking, please forgive me
> > if it's already on the Todo list.
> 
> It is not on the ToDo list, no.
> 
> +CC Mattijs

Hi, this issue only affects usb_ether, as g_dnl will enter event loop right 
after driver register so the host won't see an un responsive device.

I think one solution is revert half of 718f1d41 to move
 usb_gadget_register_driver()/usb_gadget_unregister_driver() 
back to usb_eth_start()/usb_eth_stop().

It doesn't affect the ability of bind/unbind mentioned by the commit's 
description. In fact by reverting it usb_ether will behaves more like 
running 'ums' or 'dfu', since running a ethernet command like 'dhcp'
will do register->event loop->unregister just like 'ums' does.



[PATCH v2 0/4] usb: gadget: atmel: Code refactor and DM_USB_GADGET support

2024-07-23 Thread Zixun LI
Changes in v2:
- Fix null pointer deference in driver unbinding
- Separate code refactor into 2 parts
- Remove dead code

Changes in v1:
- Based on [PATCH RFC] usb: gadget: atmel: Add DM_USB_GADGET support:
  https://lists.denx.de/pipermail/u-boot/2024-July/559503.html
- Addressed comments, moved the refactoring to a preparatory patch.

Zixun LI (4):
  usb: gadget: atmel: Code refactor part 1
  usb: gadget: atmel: Code refactor part 2
  usb: gadget: atmel: Add attach/detach support
  usb: gadget: atmel: Add DM_USB_GADGET support

 drivers/usb/gadget/atmel_usba_udc.c | 214 +++-
 include/linux/usb/atmel_usba_udc.h  |   2 +
 2 files changed, 180 insertions(+), 36 deletions(-)

--
2.45.2



[PATCH v2 3/4] usb: gadget: atmel: Add attach/detach support

2024-07-23 Thread Zixun LI
Add controller attach/detach support by using
usb_gadget_ops.pullup() method.

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/atmel_usba_udc.c | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/drivers/usb/gadget/atmel_usba_udc.c 
b/drivers/usb/gadget/atmel_usba_udc.c
index 3e3c5cb403..46f7ae9a0c 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -1176,6 +1176,23 @@ static int usba_udc_disable(struct usba_udc *udc)
return 0;
 }
 
+static int usba_udc_pullup(struct usb_gadget *g, int is_on)
+{
+   struct usba_udc *udc = controller;
+   u32 ctrl;
+
+   ctrl = usba_readl(udc, CTRL);
+
+   if (is_on)
+   ctrl &= ~USBA_DETACH;
+   else
+   ctrl |= USBA_DETACH;
+
+   usba_writel(udc, CTRL, ctrl);
+
+   return 0;
+}
+
 int dm_usb_gadget_handle_interrupts(struct udevice *dev)
 {
struct usba_udc *udc = controller;
@@ -1233,6 +1250,7 @@ static const struct usb_gadget_ops usba_udc_ops = {
.get_frame  = usba_udc_get_frame,
.wakeup = usba_udc_wakeup,
.set_selfpowered= usba_udc_set_selfpowered,
+   .pullup = usba_udc_pullup,
 };
 
 static struct usba_udc udc_controller = {
-- 
2.45.2



[PATCH v2 1/4] usb: gadget: atmel: Code refactor part 1

2024-07-23 Thread Zixun LI
- Sort includes
- Forward declare controller structures

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/atmel_usba_udc.c | 59 +++--
 1 file changed, 30 insertions(+), 29 deletions(-)

diff --git a/drivers/usb/gadget/atmel_usba_udc.c 
b/drivers/usb/gadget/atmel_usba_udc.c
index f99553df8d..476e7ed619 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -7,19 +7,22 @@
  *Bo Shen 
  */
 
-#include 
-#include 
+#include 
+#include 
+#include 
 #include 
 #include 
+#include 
+#include 
 #include 
-#include 
 #include 
 #include 
 #include 
-#include 
 
 #include "atmel_usba_udc.h"
 
+static struct usba_udc *controller;
+
 static int vbus_is_present(struct usba_udc *udc)
 {
/* No Vbus detection: Assume always present */
@@ -506,12 +509,6 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int 
is_selfpowered)
return 0;
 }
 
-static const struct usb_gadget_ops usba_udc_ops = {
-   .get_frame  = usba_udc_get_frame,
-   .wakeup = usba_udc_wakeup,
-   .set_selfpowered= usba_udc_set_selfpowered,
-};
-
 static struct usb_endpoint_descriptor usba_ep0_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -1179,28 +1176,16 @@ static int atmel_usba_stop(struct usba_udc *udc)
return 0;
 }
 
-static struct usba_udc controller = {
-   .regs = (unsigned *)ATMEL_BASE_UDPHS,
-   .fifo = (unsigned *)ATMEL_BASE_UDPHS_FIFO,
-   .gadget = {
-   .ops= &usba_udc_ops,
-   .ep_list= LIST_HEAD_INIT(controller.gadget.ep_list),
-   .speed  = USB_SPEED_HIGH,
-   .is_dualspeed   = 1,
-   .name   = "atmel_usba_udc",
-   },
-};
-
 int dm_usb_gadget_handle_interrupts(struct udevice *dev)
 {
-   struct usba_udc *udc = &controller;
+   struct usba_udc *udc = controller;
 
return usba_udc_irq(udc);
 }
 
 int usb_gadget_register_driver(struct usb_gadget_driver *driver)
 {
-   struct usba_udc *udc = &controller;
+   struct usba_udc *udc = controller;
int ret;
 
if (!driver || !driver->bind || !driver->setup) {
@@ -1228,7 +1213,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver 
*driver)
 
 int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 {
-   struct usba_udc *udc = &controller;
+   struct usba_udc *udc = controller;
 
if (!driver || !driver->unbind || !driver->disconnect) {
pr_err("bad paramter\n");
@@ -1244,6 +1229,24 @@ int usb_gadget_unregister_driver(struct 
usb_gadget_driver *driver)
return 0;
 }
 
+static const struct usb_gadget_ops usba_udc_ops = {
+   .get_frame  = usba_udc_get_frame,
+   .wakeup = usba_udc_wakeup,
+   .set_selfpowered= usba_udc_set_selfpowered,
+};
+
+static struct usba_udc udc_controller = {
+   .regs = (unsigned int *)ATMEL_BASE_UDPHS,
+   .fifo = (unsigned int *)ATMEL_BASE_UDPHS_FIFO,
+   .gadget = {
+   .ops= &usba_udc_ops,
+   .ep_list= LIST_HEAD_INIT(udc_controller.gadget.ep_list),
+   .speed  = USB_SPEED_HIGH,
+   .is_dualspeed   = 1,
+   .name   = "atmel_usba_udc",
+   },
+};
+
 static struct usba_ep *usba_udc_pdata(struct usba_platform_data *pdata,
  struct usba_udc *udc)
 {
@@ -1286,11 +1289,9 @@ static struct usba_ep *usba_udc_pdata(struct 
usba_platform_data *pdata,
 
 int usba_udc_probe(struct usba_platform_data *pdata)
 {
-   struct usba_udc *udc;
-
-   udc = &controller;
+   controller = &udc_controller;
 
-   udc->usba_ep = usba_udc_pdata(pdata, udc);
+   controller->usba_ep = usba_udc_pdata(pdata, controller);
 
return 0;
 }
-- 
2.45.2



[PATCH v2 2/4] usb: gadget: atmel: Code refactor part 2

2024-07-23 Thread Zixun LI
- Rename atmel_usba_start() / atmel_usba_stop() to usba_udc_enable()
  / usba_udc_disable(), remove atmel_ prefix to be inline with other
  functions. Also avoid confusion with DM start() / stop() functions.
- Replace printf() by log_err()
- Spelling paramter -> parameter

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/atmel_usba_udc.c | 18 +-
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/gadget/atmel_usba_udc.c 
b/drivers/usb/gadget/atmel_usba_udc.c
index 476e7ed619..3e3c5cb403 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -1150,7 +1150,7 @@ static int usba_udc_irq(struct usba_udc *udc)
return 0;
 }
 
-static int atmel_usba_start(struct usba_udc *udc)
+static int usba_udc_enable(struct usba_udc *udc)
 {
udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
 
@@ -1165,7 +1165,7 @@ static int atmel_usba_start(struct usba_udc *udc)
return 0;
 }
 
-static int atmel_usba_stop(struct usba_udc *udc)
+static int usba_udc_disable(struct usba_udc *udc)
 {
udc->gadget.speed = USB_SPEED_UNKNOWN;
reset_all_endpoints(udc);
@@ -1189,22 +1189,22 @@ int usb_gadget_register_driver(struct usb_gadget_driver 
*driver)
int ret;
 
if (!driver || !driver->bind || !driver->setup) {
-   printf("bad paramter\n");
+   log_err("bad parameter\n");
return -EINVAL;
}
 
if (udc->driver) {
-   printf("UDC already has a gadget driver\n");
+   log_err("UDC already has a gadget driver\n");
return -EBUSY;
}
 
-   atmel_usba_start(udc);
+   usba_udc_enable(udc);
 
udc->driver = driver;
 
ret = driver->bind(&udc->gadget);
if (ret) {
-   pr_err("driver->bind() returned %d\n", ret);
+   log_err("driver->bind() returned %d\n", ret);
udc->driver = NULL;
}
 
@@ -1216,7 +1216,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver 
*driver)
struct usba_udc *udc = controller;
 
if (!driver || !driver->unbind || !driver->disconnect) {
-   pr_err("bad paramter\n");
+   log_err("bad parameter\n");
return -EINVAL;
}
 
@@ -1224,7 +1224,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver 
*driver)
driver->unbind(&udc->gadget);
udc->driver = NULL;
 
-   atmel_usba_stop(udc);
+   usba_udc_disable(udc);
 
return 0;
 }
@@ -1255,7 +1255,7 @@ static struct usba_ep *usba_udc_pdata(struct 
usba_platform_data *pdata,
 
eps = malloc(sizeof(struct usba_ep) * pdata->num_ep);
if (!eps) {
-   pr_err("failed to alloc eps\n");
+   log_err("failed to alloc eps\n");
return NULL;
}
 
-- 
2.45.2



[PATCH v2 4/4] usb: gadget: atmel: Add DM_USB_GADGET support

2024-07-23 Thread Zixun LI
Add driver model support by using the uclass UCLASS_USB_GADGET_GENERIC.

Disable local usb_gadget_register_driver()/usb_gadget_unregister_driver()
implementation which is implemented in udc-core.c when DM_USB_GADGET
is enabled.

Replace dm_usb_gadget_handle_interrupts() with handle_interrupts ops
when DM_USB_GADGET is enabled.

Disable legacy usba_udc_probe() to avoid conflict with DM when it's
enabled.

Compared to Linux driver only supported devices' DT bindings are included
(sorted as Linux driver)

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/atmel_usba_udc.c | 123 
 include/linux/usb/atmel_usba_udc.h  |   2 +
 2 files changed, 125 insertions(+)

diff --git a/drivers/usb/gadget/atmel_usba_udc.c 
b/drivers/usb/gadget/atmel_usba_udc.c
index 46f7ae9a0c..95abb86840 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -8,10 +8,13 @@
  */
 
 #include 
+#include 
 #include 
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -19,6 +22,10 @@
 #include 
 #include 
 
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+#include 
+#endif /* CONFIG_IS_ENABLED(DM_USB_GADGET) */
+
 #include "atmel_usba_udc.h"
 
 static struct usba_udc *controller;
@@ -1193,6 +1200,7 @@ static int usba_udc_pullup(struct usb_gadget *g, int 
is_on)
return 0;
 }
 
+#if !CONFIG_IS_ENABLED(DM_USB_GADGET)
 int dm_usb_gadget_handle_interrupts(struct udevice *dev)
 {
struct usba_udc *udc = controller;
@@ -1246,11 +1254,40 @@ int usb_gadget_unregister_driver(struct 
usb_gadget_driver *driver)
return 0;
 }
 
+#else /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */
+static int usba_udc_start(struct usb_gadget *g,
+ struct usb_gadget_driver *driver)
+{
+   struct usba_udc *udc = controller;
+
+   usba_udc_enable(udc);
+
+   udc->driver = driver;
+
+   return 0;
+}
+
+static int usba_udc_stop(struct usb_gadget *g)
+{
+   struct usba_udc *udc = controller;
+
+   udc->driver = NULL;
+
+   usba_udc_disable(udc);
+
+   return 0;
+}
+#endif /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */
+
 static const struct usb_gadget_ops usba_udc_ops = {
.get_frame  = usba_udc_get_frame,
.wakeup = usba_udc_wakeup,
.set_selfpowered= usba_udc_set_selfpowered,
.pullup = usba_udc_pullup,
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+   .udc_start  = usba_udc_start,
+   .udc_stop   = usba_udc_stop,
+#endif
 };
 
 static struct usba_udc udc_controller = {
@@ -1305,6 +1342,7 @@ static struct usba_ep *usba_udc_pdata(struct 
usba_platform_data *pdata,
return eps;
 }
 
+#if !CONFIG_IS_ENABLED(DM_USB_GADGET)
 int usba_udc_probe(struct usba_platform_data *pdata)
 {
controller = &udc_controller;
@@ -1313,3 +1351,88 @@ int usba_udc_probe(struct usba_platform_data *pdata)
 
return 0;
 }
+
+#else /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */
+struct usba_priv_data {
+   struct clk_bulk clks;
+};
+
+static int usba_udc_clk_init(struct udevice *dev, struct clk_bulk *clks)
+{
+   int ret;
+
+   ret = clk_get_bulk(dev, clks);
+   if (ret == -ENOSYS)
+   return 0;
+
+   if (ret)
+   return ret;
+
+   ret = clk_enable_bulk(clks);
+   if (ret) {
+   clk_release_bulk(clks);
+   return ret;
+   }
+
+   return 0;
+}
+
+static int usba_udc_probe(struct udevice *dev)
+{
+   struct usba_priv_data *priv = dev_get_priv(dev);
+   int ret;
+
+   ret = usba_udc_clk_init(dev, &priv->clks);
+   if (ret)
+   return ret;
+
+   controller = &udc_controller;
+
+   controller->usba_ep = usba_udc_pdata(&pdata, controller);
+
+   controller->driver = 0;
+
+   ret = usb_add_gadget_udc((struct device *)dev, &controller->gadget);
+
+   return ret;
+}
+
+static int usba_udc_remove(struct udevice *dev)
+{
+   struct usba_priv_data *priv = dev_get_priv(dev);
+
+   usb_del_gadget_udc(&controller->gadget);
+
+   clk_release_bulk(&priv->clks);
+
+   return dm_scan_fdt_dev(dev);
+}
+
+static int usba_udc_handle_interrupts(struct udevice *dev)
+{
+   struct usba_udc *udc = controller;
+
+   return usba_udc_irq(udc);
+}
+
+static const struct usb_gadget_generic_ops usba_udc_gadget_ops = {
+   .handle_interrupts  = usba_udc_handle_interrupts,
+};
+
+static const struct udevice_id usba_udc_ids[] = {
+   { .compatible = "atmel,at91sam9rl-udc" },
+   { .compatible = "atmel,at91sam9g45-udc" },
+   { .compatible = "atmel,sama5d3-udc" },
+   {}
+};
+
+U_BOOT_DRIVER(ateml_usba_udc) = {
+   .name   = "ateml_usba_udc",
+   .id = UCLASS_USB_GADGET_GENERIC,
+   .of_match = usba_udc_ids,
+   .ops = &usba_udc_gadget_ops,
+

[PATCH v3 0/7] usb: gadget: atmel: Code refactor and DM_USB_GADGET support

2024-07-23 Thread Zixun LI
Changes in v3:
- Separate code refactor into individual commits
- Extract the controller point from udevice private data in DM functions

Changes in v2:
- Fix null pointer deference in driver unbinding
- Separate code refactor into 2 parts
- Remove dead code

Changes in v1:
- Based on [PATCH RFC] usb: gadget: atmel: Add DM_USB_GADGET support:
  https://lists.denx.de/pipermail/u-boot/2024-July/559503.html
- Addressed comments, moved the refactoring to a preparatory patch.

Zixun LI (7):
  usb: gadget: atmel: Sort includes
  usb: gadget: atmel: Replace printf() and pr_err() by log_err()
  usb: gadget: atmel: Fix typo in usb_gadget_register_driver()
  usb: gadget: atmel: Move usba_udc_pdata() with other static functions
  usb: gadget: atmel: Rename atmel_usba_start()/_stop() to
usba_udc_enable()/_disable()
  usb: gadget: atmel: Add attach/detach support
  usb: gadget: atmel: Add DM_USB_GADGET support

 drivers/usb/gadget/atmel_usba_udc.c | 250 ++--
 drivers/usb/gadget/atmel_usba_udc.h |   3 +
 include/linux/usb/atmel_usba_udc.h  |   2 +
 3 files changed, 208 insertions(+), 47 deletions(-)

--
2.45.2



[PATCH v3 1/7] usb: gadget: atmel: Sort includes

2024-07-23 Thread Zixun LI
Sort includes in alphabetical order.

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/atmel_usba_udc.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/gadget/atmel_usba_udc.c 
b/drivers/usb/gadget/atmel_usba_udc.c
index f99553df8d..5f78251fdb 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -7,16 +7,16 @@
  *Bo Shen 
  */
 
-#include 
-#include 
+#include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
-#include 
 
 #include "atmel_usba_udc.h"
 
-- 
2.45.2



[PATCH v3 3/7] usb: gadget: atmel: Fix typo in usb_gadget_register_driver()

2024-07-23 Thread Zixun LI
Replace "paramter" by "parameter".

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/atmel_usba_udc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/gadget/atmel_usba_udc.c 
b/drivers/usb/gadget/atmel_usba_udc.c
index 83fdc36870..2e3d8f36a2 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -1204,7 +1204,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver 
*driver)
int ret;
 
if (!driver || !driver->bind || !driver->setup) {
-   log_err("bad paramter\n");
+   log_err("bad parameter\n");
return -EINVAL;
}
 
-- 
2.45.2



[PATCH v3 2/7] usb: gadget: atmel: Replace printf() and pr_err() by log_err()

2024-07-23 Thread Zixun LI
To have a uniform printing function, also drop linux/printk.h as no
longer used.

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/atmel_usba_udc.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/gadget/atmel_usba_udc.c 
b/drivers/usb/gadget/atmel_usba_udc.c
index 5f78251fdb..83fdc36870 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -7,13 +7,13 @@
  *Bo Shen 
  */
 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 
@@ -1204,12 +1204,12 @@ int usb_gadget_register_driver(struct usb_gadget_driver 
*driver)
int ret;
 
if (!driver || !driver->bind || !driver->setup) {
-   printf("bad paramter\n");
+   log_err("bad paramter\n");
return -EINVAL;
}
 
if (udc->driver) {
-   printf("UDC already has a gadget driver\n");
+   log_err("UDC already has a gadget driver\n");
return -EBUSY;
}
 
@@ -1219,7 +1219,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver 
*driver)
 
ret = driver->bind(&udc->gadget);
if (ret) {
-   pr_err("driver->bind() returned %d\n", ret);
+   log_err("driver->bind() returned %d\n", ret);
udc->driver = NULL;
}
 
@@ -1231,7 +1231,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver 
*driver)
struct usba_udc *udc = &controller;
 
if (!driver || !driver->unbind || !driver->disconnect) {
-   pr_err("bad paramter\n");
+   log_err("bad parameter\n");
return -EINVAL;
}
 
@@ -1252,7 +1252,7 @@ static struct usba_ep *usba_udc_pdata(struct 
usba_platform_data *pdata,
 
eps = malloc(sizeof(struct usba_ep) * pdata->num_ep);
if (!eps) {
-   pr_err("failed to alloc eps\n");
+   log_err("failed to alloc eps\n");
return NULL;
}
 
-- 
2.45.2



[PATCH v3 4/7] usb: gadget: atmel: Move usba_udc_pdata() with other static functions

2024-07-23 Thread Zixun LI
To make all static functions in the top, no functional change.

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/atmel_usba_udc.c | 80 ++---
 1 file changed, 40 insertions(+), 40 deletions(-)

diff --git a/drivers/usb/gadget/atmel_usba_udc.c 
b/drivers/usb/gadget/atmel_usba_udc.c
index 2e3d8f36a2..a3d24501ba 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -1179,6 +1179,46 @@ static int atmel_usba_stop(struct usba_udc *udc)
return 0;
 }
 
+static struct usba_ep *usba_udc_pdata(struct usba_platform_data *pdata,
+ struct usba_udc *udc)
+{
+   struct usba_ep *eps;
+   int i;
+
+   eps = malloc(sizeof(struct usba_ep) * pdata->num_ep);
+   if (!eps) {
+   log_err("failed to alloc eps\n");
+   return NULL;
+   }
+
+   udc->gadget.ep0 = &eps[0].ep;
+
+   INIT_LIST_HEAD(&udc->gadget.ep_list);
+   INIT_LIST_HEAD(&eps[0].ep.ep_list);
+
+   for (i = 0; i < pdata->num_ep; i++) {
+   struct usba_ep *ep = &eps[i];
+
+   ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
+   ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
+   ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
+   ep->ep.ops = &usba_ep_ops;
+   ep->ep.name = pdata->ep[i].name;
+   ep->ep.maxpacket = pdata->ep[i].fifo_size;
+   ep->fifo_size = ep->ep.maxpacket;
+   ep->udc = udc;
+   INIT_LIST_HEAD(&ep->queue);
+   ep->nr_banks = pdata->ep[i].nr_banks;
+   ep->index = pdata->ep[i].index;
+   ep->can_dma = pdata->ep[i].can_dma;
+   ep->can_isoc = pdata->ep[i].can_isoc;
+   if (i)
+   list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+   };
+
+   return eps;
+}
+
 static struct usba_udc controller = {
.regs = (unsigned *)ATMEL_BASE_UDPHS,
.fifo = (unsigned *)ATMEL_BASE_UDPHS_FIFO,
@@ -1244,46 +1284,6 @@ int usb_gadget_unregister_driver(struct 
usb_gadget_driver *driver)
return 0;
 }
 
-static struct usba_ep *usba_udc_pdata(struct usba_platform_data *pdata,
- struct usba_udc *udc)
-{
-   struct usba_ep *eps;
-   int i;
-
-   eps = malloc(sizeof(struct usba_ep) * pdata->num_ep);
-   if (!eps) {
-   log_err("failed to alloc eps\n");
-   return NULL;
-   }
-
-   udc->gadget.ep0 = &eps[0].ep;
-
-   INIT_LIST_HEAD(&udc->gadget.ep_list);
-   INIT_LIST_HEAD(&eps[0].ep.ep_list);
-
-   for (i = 0; i < pdata->num_ep; i++) {
-   struct usba_ep *ep = &eps[i];
-
-   ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
-   ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
-   ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
-   ep->ep.ops = &usba_ep_ops;
-   ep->ep.name = pdata->ep[i].name;
-   ep->ep.maxpacket = pdata->ep[i].fifo_size;
-   ep->fifo_size = ep->ep.maxpacket;
-   ep->udc = udc;
-   INIT_LIST_HEAD(&ep->queue);
-   ep->nr_banks = pdata->ep[i].nr_banks;
-   ep->index = pdata->ep[i].index;
-   ep->can_dma = pdata->ep[i].can_dma;
-   ep->can_isoc = pdata->ep[i].can_isoc;
-   if (i)
-   list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
-   };
-
-   return eps;
-}
-
 int usba_udc_probe(struct usba_platform_data *pdata)
 {
struct usba_udc *udc;
-- 
2.45.2



[PATCH v3 5/7] usb: gadget: atmel: Rename atmel_usba_start()/_stop() to usba_udc_enable()/_disable()

2024-07-23 Thread Zixun LI
Rename atmel_usba_start() / atmel_usba_stop() to usba_udc_enable()
/ usba_udc_disable(), remove atmel_ prefix to be inline with other
functions. Also avoid confusion with DM start() / stop() functions.

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/atmel_usba_udc.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/gadget/atmel_usba_udc.c 
b/drivers/usb/gadget/atmel_usba_udc.c
index a3d24501ba..ea9ad7585e 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -1153,7 +1153,7 @@ static int usba_udc_irq(struct usba_udc *udc)
return 0;
 }
 
-static int atmel_usba_start(struct usba_udc *udc)
+static int usba_udc_enable(struct usba_udc *udc)
 {
udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
 
@@ -1168,7 +1168,7 @@ static int atmel_usba_start(struct usba_udc *udc)
return 0;
 }
 
-static int atmel_usba_stop(struct usba_udc *udc)
+static int usba_udc_disable(struct usba_udc *udc)
 {
udc->gadget.speed = USB_SPEED_UNKNOWN;
reset_all_endpoints(udc);
@@ -1253,7 +1253,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver 
*driver)
return -EBUSY;
}
 
-   atmel_usba_start(udc);
+   usba_udc_enable(udc);
 
udc->driver = driver;
 
@@ -1279,7 +1279,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver 
*driver)
driver->unbind(&udc->gadget);
udc->driver = NULL;
 
-   atmel_usba_stop(udc);
+   usba_udc_disable(udc);
 
return 0;
 }
-- 
2.45.2



[PATCH v3 6/7] usb: gadget: atmel: Add attach/detach support

2024-07-23 Thread Zixun LI
Add controller attach/detach support by using
usb_gadget_ops.pullup() method.

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/atmel_usba_udc.c | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/drivers/usb/gadget/atmel_usba_udc.c 
b/drivers/usb/gadget/atmel_usba_udc.c
index ea9ad7585e..a7b96449f8 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -506,10 +506,28 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int 
is_selfpowered)
return 0;
 }
 
+static int usba_udc_pullup(struct usb_gadget *gadget, int is_on)
+{
+   struct usba_udc *udc = to_usba_udc(gadget);
+   u32 ctrl;
+
+   ctrl = usba_readl(udc, CTRL);
+
+   if (is_on)
+   ctrl &= ~USBA_DETACH;
+   else
+   ctrl |= USBA_DETACH;
+
+   usba_writel(udc, CTRL, ctrl);
+
+   return 0;
+}
+
 static const struct usb_gadget_ops usba_udc_ops = {
.get_frame  = usba_udc_get_frame,
.wakeup = usba_udc_wakeup,
.set_selfpowered= usba_udc_set_selfpowered,
+   .pullup = usba_udc_pullup,
 };
 
 static struct usb_endpoint_descriptor usba_ep0_desc = {
-- 
2.45.2



[PATCH v3 7/7] usb: gadget: atmel: Add DM_USB_GADGET support

2024-07-23 Thread Zixun LI
Add driver model support by using the uclass UCLASS_USB_GADGET_GENERIC.

Disable local usb_gadget_register_driver()/usb_gadget_unregister_driver()
implementation which is implemented in udc-core.c when DM_USB_GADGET
is enabled.

Replace dm_usb_gadget_handle_interrupts() with handle_interrupts ops
when DM_USB_GADGET is enabled.

Disable legacy struct usba_udc controller as controller point is extracted
from udevice private data with DM.

Disable legacy usba_udc_probe() to avoid conflict with DM when it's
enabled.

Compared to Linux driver only supported devices' DT bindings are included
(sorted as Linux driver)

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/atmel_usba_udc.c | 138 
 drivers/usb/gadget/atmel_usba_udc.h |   3 +
 include/linux/usb/atmel_usba_udc.h  |   2 +
 3 files changed, 143 insertions(+)

diff --git a/drivers/usb/gadget/atmel_usba_udc.c 
b/drivers/usb/gadget/atmel_usba_udc.c
index a7b96449f8..b7b2e5196b 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -7,10 +7,14 @@
  *Bo Shen 
  */
 
+#include 
+#include 
 #include 
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -18,6 +22,14 @@
 #include 
 #include 
 
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+#include 
+
+static int usba_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
+static int usba_udc_stop(struct usb_gadget *gadget);
+#endif /* CONFIG_IS_ENABLED(DM_USB_GADGET) */
+
 #include "atmel_usba_udc.h"
 
 static int vbus_is_present(struct usba_udc *udc)
@@ -528,6 +540,10 @@ static const struct usb_gadget_ops usba_udc_ops = {
.wakeup = usba_udc_wakeup,
.set_selfpowered= usba_udc_set_selfpowered,
.pullup = usba_udc_pullup,
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+   .udc_start  = usba_udc_start,
+   .udc_stop   = usba_udc_stop,
+#endif
 };
 
 static struct usb_endpoint_descriptor usba_ep0_desc = {
@@ -1237,6 +1253,7 @@ static struct usba_ep *usba_udc_pdata(struct 
usba_platform_data *pdata,
return eps;
 }
 
+#if !CONFIG_IS_ENABLED(DM_USB_GADGET)
 static struct usba_udc controller = {
.regs = (unsigned *)ATMEL_BASE_UDPHS,
.fifo = (unsigned *)ATMEL_BASE_UDPHS_FIFO,
@@ -1312,3 +1329,124 @@ int usba_udc_probe(struct usba_platform_data *pdata)
 
return 0;
 }
+
+#else /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */
+struct usba_priv_data {
+   struct clk_bulk clks;
+   struct usba_udc udc;
+};
+
+static int usba_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+   struct usba_udc *udc = to_usba_udc(gadget);
+
+   usba_udc_enable(udc);
+
+   udc->driver = driver;
+
+   return 0;
+}
+
+static int usba_udc_stop(struct usb_gadget *gadget)
+{
+   struct usba_udc *udc = to_usba_udc(gadget);
+
+   udc->driver = NULL;
+
+   usba_udc_disable(udc);
+
+   return 0;
+}
+
+static int usba_udc_clk_init(struct udevice *dev, struct clk_bulk *clks)
+{
+   int ret;
+
+   ret = clk_get_bulk(dev, clks);
+   if (ret == -ENOSYS)
+   return 0;
+
+   if (ret)
+   return ret;
+
+   ret = clk_enable_bulk(clks);
+   if (ret) {
+   clk_release_bulk(clks);
+   return ret;
+   }
+
+   return 0;
+}
+
+static int usba_udc_probe(struct udevice *dev)
+{
+   struct usba_priv_data *priv = dev_get_priv(dev);
+   struct usba_udc *udc = &priv->udc;
+   int ret;
+
+   ret = usba_udc_clk_init(dev, &priv->clks);
+   if (ret)
+   return ret;
+
+   udc->fifo = (void __iomem *)dev_remap_addr_index(dev, FIFO_IOMEM_ID);
+   if (!udc->fifo)
+   return -EINVAL;
+
+   udc->regs = (void __iomem *)dev_remap_addr_index(dev, CTRL_IOMEM_ID);
+   if (!udc->regs)
+   return -EINVAL;
+
+   udc->gadget.ops = &usba_udc_ops;
+   udc->gadget.speed = USB_SPEED_HIGH,
+   udc->gadget.is_dualspeed = 1,
+   udc->gadget.name = "atmel_usba_udc",
+
+   udc->usba_ep = usba_udc_pdata(&pdata, udc);
+
+   udc->driver = NULL;
+
+   ret = usb_add_gadget_udc((struct device *)dev, &udc->gadget);
+
+   return ret;
+}
+
+static int usba_udc_remove(struct udevice *dev)
+{
+   struct usba_priv_data *priv = dev_get_priv(dev);
+
+   usb_del_gadget_udc(&priv->udc.gadget);
+
+   clk_release_bulk(&priv->clks);
+
+   return dm_scan_fdt_dev(dev);
+}
+
+static int usba_udc_handle_interrupts(struct udevice *dev)
+{
+   struct usba_priv_data *priv = dev_get_priv(dev);
+
+   return usba_udc_irq(&priv->udc);
+}
+
+static const struct usb_gadget_generic_ops usba_udc_gadget_ops = {
+   .handle_interrupts  =

RE: usb gadget driver initialization issue

2024-07-23 Thread Zixun Li
> -Original Message-
> From: Zixun Li
> Sent: Monday, July 22, 2024 17:53
> To: 'Marek Vasut' ; Lukasz Majewski ;
> open list ; Mattijs Korpershoek
> 
> Subject: RE: usb gadget driver initialization issue
> 
> Hi, this issue only affects usb_ether, as g_dnl will enter event loop right 
> after
> driver register so the host won't see an un responsive device.
> 
> I think one solution is revert half of 718f1d41 to move
>  usb_gadget_register_driver()/usb_gadget_unregister_driver()
> back to usb_eth_start()/usb_eth_stop().
> 
> It doesn't affect the ability of bind/unbind mentioned by the commit's
> description. In fact by reverting it usb_ether will behaves more like running
> 'ums' or 'dfu', since running a ethernet command like 'dhcp'
> will do register->event loop->unregister just like 'ums' does.

More precisely I'm thinking about the following patch:

Subject: [PATCH] usb: gadget: ether: Handle gadget driver registration in
 start and stop

Revert part of 718f1d41 to move
 usb_gadget_register_driver()/usb_gadget_unregister_driver()
back to usb_eth_start()/usb_eth_stop().

usb_gadget_register_driver() will initialize the USB controller and
enter ready to connect state.

>From the host's point of view, a device is ready to be enumerated.
However, since dm_usb_gadget_handle_interrupts() is only called when
ethernet function is started, at this stage USB events are not managed,
host's enumeration attempts will fail and resulting error like:
usb 1-1: new high-speed USB device number 50 using xhci_hcd
usb 1-1: device descriptor read/64, error -110
usb 1-1: device descriptor read/64, error -110
usb usb1-port1: attempt power cycle

With this change the USB controller will only be initialized when ethernet
function is used so the host won't see an unresponsive device.

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/ether.c | 15 +--
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index b7b7bacb00..ed55f12662 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -2277,6 +2277,9 @@ static int usb_eth_start(struct udevice *udev)
packet_received = 0;
packet_sent = 0;
 
+   if (usb_gadget_register_driver(&priv->eth_driver) < 0)
+   goto fail;
+
gadget = dev->gadget;
usb_gadget_connect(gadget);
 
@@ -2398,6 +2401,8 @@ static void usb_eth_stop(struct udevice *udev)
dm_usb_gadget_handle_interrupts(udev->parent);
dev->network_started = 0;
}
+
+   usb_gadget_unregister_driver(&priv->eth_driver);
 }
 
 static int usb_eth_recv(struct udevice *dev, int flags, uchar **packetp)
@@ -2503,15 +2508,6 @@ static int usb_eth_probe(struct udevice *dev)
priv->eth_driver.disconnect = eth_disconnect;
priv->eth_driver.suspend= eth_suspend;
priv->eth_driver.resume = eth_resume;
-   return usb_gadget_register_driver(&priv->eth_driver);
-}
-
-static int usb_eth_remove(struct udevice *dev)
-{
-   struct ether_priv *priv = dev_get_priv(dev);
-
-   usb_gadget_unregister_driver(&priv->eth_driver);
-
return 0;
 }
 
@@ -2526,7 +2522,6 @@ U_BOOT_DRIVER(eth_usb) = {
.name   = "usb_ether",
.id = UCLASS_ETH,
.probe  = usb_eth_probe,
-   .remove = usb_eth_remove,
.unbind = usb_eth_unbind,
.ops= &usb_eth_ops,
.priv_auto  = sizeof(struct ether_priv),
-- 
2.45.2



[PATCH v4 0/7] usb: gadget: atmel: Code refactor and DM_USB_GADGET support

2024-07-25 Thread Zixun LI
Changes in v4:
- Release clocks if probe failed
- Add missing endpoint data free
- Addressed comments

Changes in v3:
- Separate code refactor into individual commits
- Extract the controller point from udevice private data in DM functions

Changes in v2:
- Fix null pointer deference in driver unbinding
- Separate code refactor into 2 parts
- Remove dead code

Changes in v1:
- Based on [PATCH RFC] usb: gadget: atmel: Add DM_USB_GADGET support:
  https://lists.denx.de/pipermail/u-boot/2024-July/559503.html
- Addressed comments, moved the refactoring to a preparatory patch.

Zixun LI (7):
  usb: gadget: atmel: Sort includes
  usb: gadget: atmel: Replace printf() and pr_err() by log_err()
  usb: gadget: atmel: Fix typo in usb gadget driver register and
unregister
  usb: gadget: atmel: Move usba_udc_pdata() with other static functions
  usb: gadget: atmel: Rename atmel_usba_start()/_stop() to
usba_udc_enable()/_disable()
  usb: gadget: atmel: Add attach/detach support
  usb: gadget: atmel: Add DM_USB_GADGET support

 drivers/usb/gadget/atmel_usba_udc.c | 256 +++-
 drivers/usb/gadget/atmel_usba_udc.h |   3 +
 include/linux/usb/atmel_usba_udc.h  |   2 +
 3 files changed, 214 insertions(+), 47 deletions(-)

--
2.45.2



[PATCH v4 1/7] usb: gadget: atmel: Sort includes

2024-07-25 Thread Zixun LI
Sort includes in alphabetical order.

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/atmel_usba_udc.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/gadget/atmel_usba_udc.c 
b/drivers/usb/gadget/atmel_usba_udc.c
index f99553df8d..5f78251fdb 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -7,16 +7,16 @@
  *Bo Shen 
  */
 
-#include 
-#include 
+#include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
-#include 
 
 #include "atmel_usba_udc.h"
 
-- 
2.45.2



[PATCH v4 2/7] usb: gadget: atmel: Replace printf() and pr_err() by log_err()

2024-07-25 Thread Zixun LI
To have a uniform printing function, also drop linux/printk.h as no
longer used.

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/atmel_usba_udc.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/gadget/atmel_usba_udc.c 
b/drivers/usb/gadget/atmel_usba_udc.c
index 5f78251fdb..4641638412 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -7,13 +7,13 @@
  *Bo Shen 
  */
 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 
@@ -1204,12 +1204,12 @@ int usb_gadget_register_driver(struct usb_gadget_driver 
*driver)
int ret;
 
if (!driver || !driver->bind || !driver->setup) {
-   printf("bad paramter\n");
+   log_err("bad paramter\n");
return -EINVAL;
}
 
if (udc->driver) {
-   printf("UDC already has a gadget driver\n");
+   log_err("UDC already has a gadget driver\n");
return -EBUSY;
}
 
@@ -1219,7 +1219,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver 
*driver)
 
ret = driver->bind(&udc->gadget);
if (ret) {
-   pr_err("driver->bind() returned %d\n", ret);
+   log_err("driver->bind() returned %d\n", ret);
udc->driver = NULL;
}
 
@@ -1231,7 +1231,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver 
*driver)
struct usba_udc *udc = &controller;
 
if (!driver || !driver->unbind || !driver->disconnect) {
-   pr_err("bad paramter\n");
+   log_err("bad paramter\n");
return -EINVAL;
}
 
@@ -1252,7 +1252,7 @@ static struct usba_ep *usba_udc_pdata(struct 
usba_platform_data *pdata,
 
eps = malloc(sizeof(struct usba_ep) * pdata->num_ep);
if (!eps) {
-   pr_err("failed to alloc eps\n");
+   log_err("failed to alloc eps\n");
return NULL;
}
 
-- 
2.45.2



[PATCH v4 3/7] usb: gadget: atmel: Fix typo in usb gadget driver register and unregister

2024-07-25 Thread Zixun LI
Replace "paramter" by "parameter".

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/atmel_usba_udc.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/gadget/atmel_usba_udc.c 
b/drivers/usb/gadget/atmel_usba_udc.c
index 4641638412..2e3d8f36a2 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -1204,7 +1204,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver 
*driver)
int ret;
 
if (!driver || !driver->bind || !driver->setup) {
-   log_err("bad paramter\n");
+   log_err("bad parameter\n");
return -EINVAL;
}
 
@@ -1231,7 +1231,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver 
*driver)
struct usba_udc *udc = &controller;
 
if (!driver || !driver->unbind || !driver->disconnect) {
-   log_err("bad paramter\n");
+   log_err("bad parameter\n");
return -EINVAL;
}
 
-- 
2.45.2



[PATCH v4 4/7] usb: gadget: atmel: Move usba_udc_pdata() with other static functions

2024-07-25 Thread Zixun LI
To make all static functions in the top, no functional change.

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/atmel_usba_udc.c | 80 ++---
 1 file changed, 40 insertions(+), 40 deletions(-)

diff --git a/drivers/usb/gadget/atmel_usba_udc.c 
b/drivers/usb/gadget/atmel_usba_udc.c
index 2e3d8f36a2..a3d24501ba 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -1179,6 +1179,46 @@ static int atmel_usba_stop(struct usba_udc *udc)
return 0;
 }
 
+static struct usba_ep *usba_udc_pdata(struct usba_platform_data *pdata,
+ struct usba_udc *udc)
+{
+   struct usba_ep *eps;
+   int i;
+
+   eps = malloc(sizeof(struct usba_ep) * pdata->num_ep);
+   if (!eps) {
+   log_err("failed to alloc eps\n");
+   return NULL;
+   }
+
+   udc->gadget.ep0 = &eps[0].ep;
+
+   INIT_LIST_HEAD(&udc->gadget.ep_list);
+   INIT_LIST_HEAD(&eps[0].ep.ep_list);
+
+   for (i = 0; i < pdata->num_ep; i++) {
+   struct usba_ep *ep = &eps[i];
+
+   ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
+   ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
+   ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
+   ep->ep.ops = &usba_ep_ops;
+   ep->ep.name = pdata->ep[i].name;
+   ep->ep.maxpacket = pdata->ep[i].fifo_size;
+   ep->fifo_size = ep->ep.maxpacket;
+   ep->udc = udc;
+   INIT_LIST_HEAD(&ep->queue);
+   ep->nr_banks = pdata->ep[i].nr_banks;
+   ep->index = pdata->ep[i].index;
+   ep->can_dma = pdata->ep[i].can_dma;
+   ep->can_isoc = pdata->ep[i].can_isoc;
+   if (i)
+   list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+   };
+
+   return eps;
+}
+
 static struct usba_udc controller = {
.regs = (unsigned *)ATMEL_BASE_UDPHS,
.fifo = (unsigned *)ATMEL_BASE_UDPHS_FIFO,
@@ -1244,46 +1284,6 @@ int usb_gadget_unregister_driver(struct 
usb_gadget_driver *driver)
return 0;
 }
 
-static struct usba_ep *usba_udc_pdata(struct usba_platform_data *pdata,
- struct usba_udc *udc)
-{
-   struct usba_ep *eps;
-   int i;
-
-   eps = malloc(sizeof(struct usba_ep) * pdata->num_ep);
-   if (!eps) {
-   log_err("failed to alloc eps\n");
-   return NULL;
-   }
-
-   udc->gadget.ep0 = &eps[0].ep;
-
-   INIT_LIST_HEAD(&udc->gadget.ep_list);
-   INIT_LIST_HEAD(&eps[0].ep.ep_list);
-
-   for (i = 0; i < pdata->num_ep; i++) {
-   struct usba_ep *ep = &eps[i];
-
-   ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
-   ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
-   ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
-   ep->ep.ops = &usba_ep_ops;
-   ep->ep.name = pdata->ep[i].name;
-   ep->ep.maxpacket = pdata->ep[i].fifo_size;
-   ep->fifo_size = ep->ep.maxpacket;
-   ep->udc = udc;
-   INIT_LIST_HEAD(&ep->queue);
-   ep->nr_banks = pdata->ep[i].nr_banks;
-   ep->index = pdata->ep[i].index;
-   ep->can_dma = pdata->ep[i].can_dma;
-   ep->can_isoc = pdata->ep[i].can_isoc;
-   if (i)
-   list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
-   };
-
-   return eps;
-}
-
 int usba_udc_probe(struct usba_platform_data *pdata)
 {
struct usba_udc *udc;
-- 
2.45.2



[PATCH v4 5/7] usb: gadget: atmel: Rename atmel_usba_start()/_stop() to usba_udc_enable()/_disable()

2024-07-25 Thread Zixun LI
Rename atmel_usba_start() / atmel_usba_stop() to usba_udc_enable()
/ usba_udc_disable(), remove atmel_ prefix to be inline with other
functions. Also avoid confusion with DM start() / stop() functions.

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/atmel_usba_udc.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/gadget/atmel_usba_udc.c 
b/drivers/usb/gadget/atmel_usba_udc.c
index a3d24501ba..ea9ad7585e 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -1153,7 +1153,7 @@ static int usba_udc_irq(struct usba_udc *udc)
return 0;
 }
 
-static int atmel_usba_start(struct usba_udc *udc)
+static int usba_udc_enable(struct usba_udc *udc)
 {
udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
 
@@ -1168,7 +1168,7 @@ static int atmel_usba_start(struct usba_udc *udc)
return 0;
 }
 
-static int atmel_usba_stop(struct usba_udc *udc)
+static int usba_udc_disable(struct usba_udc *udc)
 {
udc->gadget.speed = USB_SPEED_UNKNOWN;
reset_all_endpoints(udc);
@@ -1253,7 +1253,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver 
*driver)
return -EBUSY;
}
 
-   atmel_usba_start(udc);
+   usba_udc_enable(udc);
 
udc->driver = driver;
 
@@ -1279,7 +1279,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver 
*driver)
driver->unbind(&udc->gadget);
udc->driver = NULL;
 
-   atmel_usba_stop(udc);
+   usba_udc_disable(udc);
 
return 0;
 }
-- 
2.45.2



[PATCH v4 6/7] usb: gadget: atmel: Add attach/detach support

2024-07-25 Thread Zixun LI
Add controller attach/detach support by using
usb_gadget_ops.pullup() function.

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/atmel_usba_udc.c | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/drivers/usb/gadget/atmel_usba_udc.c 
b/drivers/usb/gadget/atmel_usba_udc.c
index ea9ad7585e..a7b96449f8 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -506,10 +506,28 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int 
is_selfpowered)
return 0;
 }
 
+static int usba_udc_pullup(struct usb_gadget *gadget, int is_on)
+{
+   struct usba_udc *udc = to_usba_udc(gadget);
+   u32 ctrl;
+
+   ctrl = usba_readl(udc, CTRL);
+
+   if (is_on)
+   ctrl &= ~USBA_DETACH;
+   else
+   ctrl |= USBA_DETACH;
+
+   usba_writel(udc, CTRL, ctrl);
+
+   return 0;
+}
+
 static const struct usb_gadget_ops usba_udc_ops = {
.get_frame  = usba_udc_get_frame,
.wakeup = usba_udc_wakeup,
.set_selfpowered= usba_udc_set_selfpowered,
+   .pullup = usba_udc_pullup,
 };
 
 static struct usb_endpoint_descriptor usba_ep0_desc = {
-- 
2.45.2



[PATCH v4 7/7] usb: gadget: atmel: Add DM_USB_GADGET support

2024-07-25 Thread Zixun LI
Add driver model support by using the uclass UCLASS_USB_GADGET_GENERIC.

Disable local usb_gadget_register_driver()/usb_gadget_unregister_driver()
implementation which is implemented in udc-core.c when DM_USB_GADGET
is enabled.

Replace dm_usb_gadget_handle_interrupts() with handle_interrupts ops
when DM_USB_GADGET is enabled.

Disable legacy struct usba_udc controller as controller point is extracted
from udevice private data with DM.

Disable legacy usba_udc_probe() to avoid conflict with DM when it's
enabled.

Compared to Linux driver only supported devices' DT bindings are included
(sorted as Linux driver)

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/atmel_usba_udc.c | 144 
 drivers/usb/gadget/atmel_usba_udc.h |   3 +
 include/linux/usb/atmel_usba_udc.h  |   2 +
 3 files changed, 149 insertions(+)

diff --git a/drivers/usb/gadget/atmel_usba_udc.c 
b/drivers/usb/gadget/atmel_usba_udc.c
index a7b96449f8..a77037a709 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -7,10 +7,14 @@
  *Bo Shen 
  */
 
+#include 
+#include 
 #include 
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -18,6 +22,14 @@
 #include 
 #include 
 
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+#include 
+
+static int usba_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
+static int usba_udc_stop(struct usb_gadget *gadget);
+#endif /* CONFIG_IS_ENABLED(DM_USB_GADGET) */
+
 #include "atmel_usba_udc.h"
 
 static int vbus_is_present(struct usba_udc *udc)
@@ -528,6 +540,10 @@ static const struct usb_gadget_ops usba_udc_ops = {
.wakeup = usba_udc_wakeup,
.set_selfpowered= usba_udc_set_selfpowered,
.pullup = usba_udc_pullup,
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+   .udc_start  = usba_udc_start,
+   .udc_stop   = usba_udc_stop,
+#endif
 };
 
 static struct usb_endpoint_descriptor usba_ep0_desc = {
@@ -1237,6 +1253,7 @@ static struct usba_ep *usba_udc_pdata(struct 
usba_platform_data *pdata,
return eps;
 }
 
+#if !CONFIG_IS_ENABLED(DM_USB_GADGET)
 static struct usba_udc controller = {
.regs = (unsigned *)ATMEL_BASE_UDPHS,
.fifo = (unsigned *)ATMEL_BASE_UDPHS_FIFO,
@@ -1312,3 +1329,130 @@ int usba_udc_probe(struct usba_platform_data *pdata)
 
return 0;
 }
+
+#else /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */
+struct usba_priv_data {
+   struct clk_bulk clks;
+   struct usba_udc udc;
+};
+
+static int usba_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+   struct usba_udc *udc = to_usba_udc(gadget);
+
+   usba_udc_enable(udc);
+
+   udc->driver = driver;
+   return 0;
+}
+
+static int usba_udc_stop(struct usb_gadget *gadget)
+{
+   struct usba_udc *udc = to_usba_udc(gadget);
+
+   udc->driver = NULL;
+
+   usba_udc_disable(udc);
+   return 0;
+}
+
+static int usba_udc_clk_init(struct udevice *dev, struct clk_bulk *clks)
+{
+   int ret;
+
+   ret = clk_get_bulk(dev, clks);
+   if (ret == -ENOSYS)
+   return 0;
+
+   if (ret)
+   return ret;
+
+   ret = clk_enable_bulk(clks);
+   if (ret) {
+   clk_release_bulk(clks);
+   return ret;
+   }
+
+   return 0;
+}
+
+static int usba_udc_probe(struct udevice *dev)
+{
+   struct usba_priv_data *priv = dev_get_priv(dev);
+   struct usba_udc *udc = &priv->udc;
+   int ret;
+
+   udc->fifo = (void __iomem *)dev_remap_addr_index(dev, FIFO_IOMEM_ID);
+   if (!udc->fifo)
+   return -EINVAL;
+
+   udc->regs = (void __iomem *)dev_remap_addr_index(dev, CTRL_IOMEM_ID);
+   if (!udc->regs)
+   return -EINVAL;
+
+   ret = usba_udc_clk_init(dev, &priv->clks);
+   if (ret)
+   return ret;
+
+   udc->usba_ep = usba_udc_pdata(&pdata, udc);
+
+   udc->gadget.ops = &usba_udc_ops;
+   udc->gadget.speed = USB_SPEED_HIGH,
+   udc->gadget.is_dualspeed = 1,
+   udc->gadget.name = "atmel_usba_udc",
+
+   ret = usb_add_gadget_udc((struct device *)dev, &udc->gadget);
+   if (ret)
+   goto err;
+
+   return 0;
+err:
+   free(udc->usba_ep);
+
+   clk_release_bulk(&priv->clks);
+
+   return ret;
+}
+
+static int usba_udc_remove(struct udevice *dev)
+{
+   struct usba_priv_data *priv = dev_get_priv(dev);
+
+   usb_del_gadget_udc(&priv->udc.gadget);
+
+   free(priv->udc.usba_ep);
+
+   clk_release_bulk(&priv->clks);
+
+   return dm_scan_fdt_dev(dev);
+}
+
+static int usba_udc_handle_interrupts(struct udevice *dev)
+{
+   struct usba_priv_data *priv = dev_get_pri

Re: [PATCH v4 0/7] usb: gadget: atmel: Code refactor and DM_USB_GADGET support

2024-07-25 Thread Zixun LI
On Thu, Jul 25, 2024 at 8:24 PM Marek Vasut  wrote:
>
> On 7/25/24 5:31 PM, Zixun LI wrote:
> > Changes in v4:
> > - Release clocks if probe failed
> > - Add missing endpoint data free
> > - Addressed comments
>
> Please collect any AB/RB/TB tags that were provided in v3 too.

Sorry didn't know that, should I spin a v5 ?


[PATCH] usb: gadget: ether: Handle gadget driver registration in start and stop

2024-07-26 Thread Zixun LI
Revert part of 718f1d41 to move
 usb_gadget_register_driver()/usb_gadget_unregister_driver()
back to usb_eth_start()/usb_eth_stop().

usb_gadget_register_driver() will initialize the USB controller which
enters ready to connect state with pull-up resistor enabled.

>From the host's point of view, a device is ready to be enumerated.
However, since dm_usb_gadget_handle_interrupts() is only called when
ethernet function is started, at this stage USB events are not managed,
host's enumeration attempts will fail and resulting error like:
usb 1-1: new high-speed USB device number 50 using xhci_hcd
usb 1-1: device descriptor read/64, error -110
usb 1-1: device descriptor read/64, error -110
usb usb1-port1: attempt power cycle

With this patch the USB controller will only be initialized when ethernet
function is used, in which case USB controller events are handled, so the
host won't see an unresponsive device.

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/ether.c | 15 +--
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index b7b7bacb00..ed55f12662 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -2277,6 +2277,9 @@ static int usb_eth_start(struct udevice *udev)
packet_received = 0;
packet_sent = 0;

+   if (usb_gadget_register_driver(&priv->eth_driver) < 0)
+   goto fail;
+
gadget = dev->gadget;
usb_gadget_connect(gadget);

@@ -2398,6 +2401,8 @@ static void usb_eth_stop(struct udevice *udev)
dm_usb_gadget_handle_interrupts(udev->parent);
dev->network_started = 0;
}
+
+   usb_gadget_unregister_driver(&priv->eth_driver);
 }

 static int usb_eth_recv(struct udevice *dev, int flags, uchar **packetp)
@@ -2503,15 +2508,6 @@ static int usb_eth_probe(struct udevice *dev)
priv->eth_driver.disconnect = eth_disconnect;
priv->eth_driver.suspend= eth_suspend;
priv->eth_driver.resume = eth_resume;
-   return usb_gadget_register_driver(&priv->eth_driver);
-}
-
-static int usb_eth_remove(struct udevice *dev)
-{
-   struct ether_priv *priv = dev_get_priv(dev);
-
-   usb_gadget_unregister_driver(&priv->eth_driver);
-
return 0;
 }

@@ -2526,7 +2522,6 @@ U_BOOT_DRIVER(eth_usb) = {
.name   = "usb_ether",
.id = UCLASS_ETH,
.probe  = usb_eth_probe,
-   .remove = usb_eth_remove,
.unbind = usb_eth_unbind,
.ops= &usb_eth_ops,
.priv_auto  = sizeof(struct ether_priv),
--
2.45.2



cmd: bind/unbind by class index doesn't work with usb gadget

2024-07-26 Thread Zixun LI
Bind/unbind a gadget function driver to a USB gadget device doesn't work
with class index, while using node path is ok. For example:

U-Boot> dm tree

 Class Index  Probed  DriverName
---
 root  0  [ + ]   root_driver   root_driver
 simple_bus0  [ + ]   simple_bus|-- ahb
 simple_bus1  [ + ]   simple_bus|   |-- apb
 ...
 usb   0  [   ]   atmel_usba_udc|   |   |-- gadget@f803c000

U-Boot> bind usb 0 usb_ether
Cannot find device 0 of class usb

Both USB host uclass and USB gadget uclass are using the same name "usb"
while they are under different class id of UCLASS_USB and
UCLASS_USB_GADGET_GENERIC.

bind_by_class_index() of cmd/bind.c uses uclass_get_by_name() to find
class id, since both class have the same name it will get the id of
UCLASS_USB instead since it is at the front of the uclass id list.

Then uclass_find_device() will try to find the wrong device and fail.

But fixing this issue simply by renaming gadget uclass name will break
the DT alias feature DM_UC_FLAG_SEQ_ALIAS.

Any idea how to fix it ? Like adding a name_seq_alias field to
uclass_driver structure ?


[RFC PATCH 1/4] dm: core: Add a way to specify an alt name for alias sequence numbering

2024-07-31 Thread Zixun LI
A new field name_seq_alias is added to uclass_driver structure, which
allows an uclass driver to use an alternate name for alias sequence
numbering.

For example an uclass named "usb_gadget" can share alias with
"usb" uclass :
UCLASS_DRIVER(usb_gadget_generic) = {
.id = UCLASS_USB_GADGET_GENERIC,
.name = "usb_gadget",
.name_seq_alias = "usb",
.flags = DM_UC_FLAG_SEQ_ALIAS,
};

Currently there are some uclasses with duplicate name which break uclass
functions like uclass_get_by_name(), with this patch it's now possible
to rename these classes without break the existing alias function.

Signed-off-by: Zixun LI 
---
 drivers/core/device.c |  3 ++-
 drivers/core/read.c   |  7 ++-
 drivers/core/uclass.c | 11 +--
 include/dm/read.h |  9 -
 include/dm/uclass.h   |  2 ++
 5 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/drivers/core/device.c b/drivers/core/device.c
index 779f371b9d..a98e75b0b8 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -89,7 +89,8 @@ static int device_bind_common(struct udevice *parent, const 
struct driver *drv,
 */
if (CONFIG_IS_ENABLED(OF_CONTROL) &&
!CONFIG_IS_ENABLED(OF_PLATDATA)) {
-   if (uc->uc_drv->name && ofnode_valid(node)) {
+   if ((uc->uc_drv->name || uc->uc_drv->name_seq_alias) &&
+   ofnode_valid(node)) {
if (!dev_read_alias_seq(dev, &dev->seq_)) {
auto_seq = false;
log_debug("   - seq=%d\n", dev->seq_);
diff --git a/drivers/core/read.c b/drivers/core/read.c
index 55c19f335a..97b12fb7a9 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -347,9 +347,14 @@ const void *dev_read_prop_by_prop(struct ofprop *prop,
 int dev_read_alias_seq(const struct udevice *dev, int *devnump)
 {
ofnode node = dev_ofnode(dev);
-   const char *uc_name = dev->uclass->uc_drv->name;
+   const char *uc_name;
int ret = -ENOTSUPP;
 
+   if (dev->uclass->uc_drv->name_seq_alias)
+   uc_name = dev->uclass->uc_drv->name_seq_alias;
+   else
+   uc_name = dev->uclass->uc_drv->name;
+
if (ofnode_is_np(node)) {
ret = of_alias_get_id(ofnode_to_np(node), uc_name);
if (ret >= 0) {
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 7ae0884a75..6dfbee2e78 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -308,11 +308,18 @@ int uclass_find_next_free_seq(struct uclass *uc)
 {
struct udevice *dev;
int max = -1;
+   const char *uc_name;
 
/* If using aliases, start with the highest alias value */
if (CONFIG_IS_ENABLED(DM_SEQ_ALIAS) &&
-   (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS))
-   max = dev_read_alias_highest_id(uc->uc_drv->name);
+   (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS)) {
+   if (uc->uc_drv->name_seq_alias)
+   uc_name = uc->uc_drv->name_seq_alias;
+   else
+   uc_name = uc->uc_drv->name;
+
+   max = dev_read_alias_highest_id(uc_name);
+   }
 
/* Avoid conflict with existing devices */
list_for_each_entry(dev, &uc->dev_head, uclass_node) {
diff --git a/include/dm/read.h b/include/dm/read.h
index 894bc698bb..5a86e43d86 100644
--- a/include/dm/read.h
+++ b/include/dm/read.h
@@ -1169,7 +1169,14 @@ static inline const void *dev_read_prop_by_prop(struct 
ofprop *prop,
 static inline int dev_read_alias_seq(const struct udevice *dev, int *devnump)
 {
 #if CONFIG_IS_ENABLED(OF_CONTROL)
-   return fdtdec_get_alias_seq(gd->fdt_blob, dev->uclass->uc_drv->name,
+   const char *uc_name;
+
+   if (dev->uclass->uc_drv->name_seq_alias)
+   uc_name = dev->uclass->uc_drv->name_seq_alias;
+   else
+   uc_name = dev->uclass->uc_drv->name;
+
+   return fdtdec_get_alias_seq(gd->fdt_blob, uc_name,
dev_of_offset(dev), devnump);
 #else
return -ENOTSUPP;
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index 456eef7f2f..8339e0d88b 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -57,6 +57,7 @@ struct udevice;
  * drivers.
  *
  * @name: Name of uclass driver
+ * @name_seq_alias: Name used for alias sequence numbering
  * @id: ID number of this uclass
  * @post_bind: Called after a new device is bound to this uclass
  * @pre_unbind: Called before a device is unbound from this uclass
@@ -88,6 +89,7 @@ struct udevice;
  */
 struct uclass_driver {
const char *name;
+   const char *name_seq_alias;
enum uclass_id id;
int (*post_bind)(struct udevice *dev);
int (*pre_unbind)(struct udevice *dev);
-- 
2.45.2



[RFC PATCH 0/4] dm: Duplicate uclass name fix and alias improvements

2024-07-31 Thread Zixun LI
Patch 1 is a tentative fix for duplicate uclass name issue met in
https://lists.denx.de/pipermail/u-boot/2024-July/560189.html

The idea is to use orignal class name only for sequence alias to keep this
alias function working and rename the class something else.

Patch 2 and 3 make "dm tree", "bind" and "unbind" commands to take care
of alias sequence numbering. As the alias sequence numbering is more
meanful than uclass index.

Patch 4 is the actual fix for usb gadet class.

There are some situations where uclass index and device sequence number
are misused which is not convered by this patch set, for example in
drivers/net/sandbox.c, uclass_get_device() is used which is based on
uclass index, while in the comments it says "index - The alias index
(also DM seq number)"

Zixun LI (4):
  dm: core: Add a way to specify an alt name for alias sequence
numbering
  dm: core: Show device sequence instead in dm_dump_tree()
  cmd: bind: Use device sequence instead for driver bind/unbind
  usb: gadget: udc: Fix duplicate uclass name

 cmd/bind.c  |  4 ++--
 drivers/core/device.c   |  3 ++-
 drivers/core/dump.c |  2 +-
 drivers/core/read.c |  7 ++-
 drivers/core/uclass.c   | 11 +--
 drivers/usb/gadget/udc/udc-uclass.c |  3 ++-
 include/dm/read.h   |  9 -
 include/dm/uclass.h |  2 ++
 8 files changed, 32 insertions(+), 9 deletions(-)

--
2.45.2



[RFC PATCH 2/4] dm: core: Show device sequence instead in dm_dump_tree()

2024-07-31 Thread Zixun LI
Currently uclass index is shown in DM tree dump which ignores alias
sequence numbering. The result could be confusing since these 2 numbers
could be different. Show device sequence number instead.

Signed-off-by: Zixun LI 
---
 drivers/core/dump.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/core/dump.c b/drivers/core/dump.c
index 5ec30d5b3c..c812d87fa4 100644
--- a/drivers/core/dump.c
+++ b/drivers/core/dump.c
@@ -40,7 +40,7 @@ static void show_devices(struct udevice *dev, int depth, int 
last_flag,
/* print the first 20 characters to not break the tree-format. */
printf(CONFIG_IS_ENABLED(USE_TINY_PRINTF) ? " %s  %d  [ %c ]   %s  " :
   " %-10.10s  %3d  [ %c ]   %-20.20s  ", dev->uclass->uc_drv->name,
-  dev_get_uclass_index(dev, NULL),
+  dev->seq_,
   flags & DM_FLAG_ACTIVATED ? '+' : ' ', dev->driver->name);
 
for (i = depth; i >= 0; i--) {
-- 
2.45.2



[RFC PATCH 3/4] cmd: bind: Use device sequence instead for driver bind/unbind

2024-07-31 Thread Zixun LI
Currently uclass index is used for bind/unbind which ignores alias
sequence numbering. Use device sequence number instead as it's
the number explicitly set in the DT.

Signed-off-by: Zixun LI 
---
 cmd/bind.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/cmd/bind.c b/cmd/bind.c
index 3a59eefd5c..30f1163e17 100644
--- a/cmd/bind.c
+++ b/cmd/bind.c
@@ -31,7 +31,7 @@ static int bind_by_class_index(const char *uclass, int index,
return -EINVAL;
}
 
-   ret = uclass_find_device(uclass_id, index, &parent);
+   ret = uclass_find_device_by_seq(uclass_id, index, &parent);
if (!parent || ret) {
printf("Cannot find device %d of class %s\n", index, uclass);
return ret;
@@ -58,7 +58,7 @@ static int find_dev(const char *uclass, int index, struct 
udevice **devp)
return -EINVAL;
}
 
-   rc = uclass_find_device(uclass_id, index, devp);
+   rc = uclass_find_device_by_seq(uclass_id, index, devp);
if (!*devp || rc) {
printf("Cannot find device %d of class %s\n", index, uclass);
return rc;
-- 
2.45.2



[RFC PATCH 4/4] usb: gadget: udc: Fix duplicate uclass name

2024-07-31 Thread Zixun LI
Currently both USB host uclass and USB gadget uclass are using the same
name "usb" which break uclass functions like uclass_get_by_name().

Rename the uclass to "usb_gadget" while using "usb" as sequence alias
naming to keep the alias function working.

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/udc/udc-uclass.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/gadget/udc/udc-uclass.c 
b/drivers/usb/gadget/udc/udc-uclass.c
index fbe62bbce4..b14f84e818 100644
--- a/drivers/usb/gadget/udc/udc-uclass.c
+++ b/drivers/usb/gadget/udc/udc-uclass.c
@@ -83,7 +83,8 @@ __weak int dm_usb_gadget_handle_interrupts(struct udevice 
*dev)
 #if CONFIG_IS_ENABLED(DM)
 UCLASS_DRIVER(usb_gadget_generic) = {
.id = UCLASS_USB_GADGET_GENERIC,
-   .name   = "usb",
+   .name   = "usb_gadget",
+   .name_seq_alias = "usb",
.flags  = DM_UC_FLAG_SEQ_ALIAS,
 };
 #endif
-- 
2.45.2



Re: [RFC PATCH 0/4] dm: Duplicate uclass name fix and alias improvements

2024-08-01 Thread Zixun LI
Hi Simon,

On Thu, Aug 1, 2024 at 4:42 PM Simon Glass  wrote:
>
> Can we rename the gadget uclass to usb_gadget or similar, then update
> the aliases?
>

You mean split patch no.4 into 2 parts, first rename the class to usb_gadget
before doing the alias job ?

> I think it makes sense to show the seq instead of the index, but
> please update the header for the table to say 'Seq'

Will do.

> I assume no tests need updating, but please do add a note to
> doc/usage/cmd/bind.rst

Will do.

Regards,
Zixun LI


[PATCH] usb: gadget: udc: Fix duplicate uclass name

2024-08-02 Thread Zixun LI
Currently both USB host uclass and USB gadget uclass are using the same
name "usb" which break uclass functions like uclass_get_by_name().

Rename the uclass to "usb_gadget" to fix, also makes bind/unbind by class
index (or sequence) working.

This breaks the capacity of using "usb" as DT alias sequence numbering
which needs a fix afterwards.

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/udc/udc-uclass.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/gadget/udc/udc-uclass.c 
b/drivers/usb/gadget/udc/udc-uclass.c
index fbe62bbce4..723d1cdfd7 100644
--- a/drivers/usb/gadget/udc/udc-uclass.c
+++ b/drivers/usb/gadget/udc/udc-uclass.c
@@ -83,7 +83,7 @@ __weak int dm_usb_gadget_handle_interrupts(struct udevice 
*dev)
 #if CONFIG_IS_ENABLED(DM)
 UCLASS_DRIVER(usb_gadget_generic) = {
.id = UCLASS_USB_GADGET_GENERIC,
-   .name   = "usb",
+   .name   = "usb_gadget",
.flags  = DM_UC_FLAG_SEQ_ALIAS,
 };
 #endif
--
2.45.2



[PATCH] dm: core: Show device sequence instead in dm_dump_tree()

2024-08-02 Thread Zixun LI
Currently uclass index is shown in DM tree dump which ignores alias
sequence numbering. The result could be confusing since these 2 numbers
could be different. Show device sequence number instead as it's more
meaningful.

Also update documentation to use sequence number.

Signed-off-by: Zixun LI 
---
 doc/usage/cmd/dm.rst | 7 +++
 drivers/core/dump.c  | 4 ++--
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/doc/usage/cmd/dm.rst b/doc/usage/cmd/dm.rst
index 7651507937..196b22d137 100644
--- a/doc/usage/cmd/dm.rst
+++ b/doc/usage/cmd/dm.rst
@@ -112,9 +112,8 @@ This shows the full tree of devices including the following 
fields:
 uclass
 Shows the name of the uclass for the device

-Index
-Shows the index number of the device, within the uclass. This shows the
-ordering within the uclass, but not the sequence number.
+Seq
+Shows the sequence number of the device, within the uclass.

 Probed
 Shows `+` if the device is active
@@ -366,7 +365,7 @@ dm tree
 This example shows the abridged sandbox output::

 => dm tree
-Class Index  Probed  DriverName
+Class SeqProbed  DriverName
 ---
 root  0  [ + ]   root_driver   root_driver
 demo  0  [   ]   demo_shape_drv|-- demo_shape_drv
diff --git a/drivers/core/dump.c b/drivers/core/dump.c
index 5ec30d5b3c..5cbaa97fa3 100644
--- a/drivers/core/dump.c
+++ b/drivers/core/dump.c
@@ -40,7 +40,7 @@ static void show_devices(struct udevice *dev, int depth, int 
last_flag,
/* print the first 20 characters to not break the tree-format. */
printf(CONFIG_IS_ENABLED(USE_TINY_PRINTF) ? " %s  %d  [ %c ]   %s  " :
   " %-10.10s  %3d  [ %c ]   %-20.20s  ", dev->uclass->uc_drv->name,
-  dev_get_uclass_index(dev, NULL),
+  dev->seq_,
   flags & DM_FLAG_ACTIVATED ? '+' : ' ', dev->driver->name);

for (i = depth; i >= 0; i--) {
@@ -129,7 +129,7 @@ void dm_dump_tree(char *dev_name, bool extended, bool sort)
 {
struct udevice *root;

-   printf(" Class Index  Probed  DriverName\n");
+   printf(" Class SeqProbed  DriverName\n");
printf("---\n");

root = dm_root();
--
2.45.2



[PATCH] cmd: bind: Use device sequence instead for driver bind/unbind

2024-08-02 Thread Zixun LI
Currently uclass index is used for bind/unbind which ignores alias
sequence numbering. Use device sequence number instead as it's
the number explicitly set in the DT.

Also update documentation to use sequence number.

Signed-off-by: Zixun LI 
---
 cmd/bind.c   | 46 
 doc/usage/cmd/bind.rst   | 12 +--
 doc/usage/cmd/unbind.rst | 14 ++--
 3 files changed, 36 insertions(+), 36 deletions(-)

diff --git a/cmd/bind.c b/cmd/bind.c
index 3a59eefd5c..c0d31f5eb1 100644
--- a/cmd/bind.c
+++ b/cmd/bind.c
@@ -10,8 +10,8 @@
 #include 
 #include 

-static int bind_by_class_index(const char *uclass, int index,
-  const char *drv_name)
+static int bind_by_class_seq(const char *uclass, int seq,
+const char *drv_name)
 {
static enum uclass_id uclass_id;
struct udevice *dev;
@@ -31,9 +31,9 @@ static int bind_by_class_index(const char *uclass, int index,
return -EINVAL;
}

-   ret = uclass_find_device(uclass_id, index, &parent);
+   ret = uclass_find_device_by_seq(uclass_id, seq, &parent);
if (!parent || ret) {
-   printf("Cannot find device %d of class %s\n", index, uclass);
+   printf("Cannot find device %d of class %s\n", seq, uclass);
return ret;
}

@@ -47,7 +47,7 @@ static int bind_by_class_index(const char *uclass, int index,
return 0;
 }

-static int find_dev(const char *uclass, int index, struct udevice **devp)
+static int find_dev(const char *uclass, int seq, struct udevice **devp)
 {
static enum uclass_id uclass_id;
int rc;
@@ -58,21 +58,21 @@ static int find_dev(const char *uclass, int index, struct 
udevice **devp)
return -EINVAL;
}

-   rc = uclass_find_device(uclass_id, index, devp);
+   rc = uclass_find_device_by_seq(uclass_id, seq, devp);
if (!*devp || rc) {
-   printf("Cannot find device %d of class %s\n", index, uclass);
+   printf("Cannot find device %d of class %s\n", seq, uclass);
return rc;
}

return 0;
 }

-static int unbind_by_class_index(const char *uclass, int index)
+static int unbind_by_class_seq(const char *uclass, int seq)
 {
int ret;
struct udevice *dev;

-   ret = find_dev(uclass, index, &dev);
+   ret = find_dev(uclass, seq, &dev);
if (ret)
return ret;

@@ -91,8 +91,8 @@ static int unbind_by_class_index(const char *uclass, int 
index)
return 0;
 }

-static int unbind_child_by_class_index(const char *uclass, int index,
-  const char *drv_name)
+static int unbind_child_by_class_seq(const char *uclass, int seq,
+const char *drv_name)
 {
struct udevice *parent;
int ret;
@@ -104,7 +104,7 @@ static int unbind_child_by_class_index(const char *uclass, 
int index,
return -ENOENT;
}

-   ret = find_dev(uclass, index, &parent);
+   ret = find_dev(uclass, seq, &parent);
if (ret)
return ret;

@@ -217,19 +217,19 @@ static int do_bind_unbind(struct cmd_tbl *cmdtp, int 
flag, int argc,
return CMD_RET_USAGE;
ret = unbind_by_node_path(argv[1]);
} else if (!by_node && bind) {
-   int index = (argc > 2) ? dectoul(argv[2], NULL) : 0;
+   int seq = (argc > 2) ? dectoul(argv[2], NULL) : 0;

if (argc != 4)
return CMD_RET_USAGE;
-   ret = bind_by_class_index(argv[1], index, argv[3]);
+   ret = bind_by_class_seq(argv[1], seq, argv[3]);
} else if (!by_node && !bind) {
-   int index = (argc > 2) ? dectoul(argv[2], NULL) : 0;
+   int seq = (argc > 2) ? dectoul(argv[2], NULL) : 0;

if (argc == 3)
-   ret = unbind_by_class_index(argv[1], index);
+   ret = unbind_by_class_seq(argv[1], seq);
else if (argc == 4)
-   ret = unbind_child_by_class_index(argv[1], index,
- argv[3]);
+   ret = unbind_child_by_class_seq(argv[1], seq,
+   argv[3]);
else
return CMD_RET_USAGE;
}
@@ -244,17 +244,17 @@ U_BOOT_CMD(
bind,   4,  0,  do_bind_unbind,
"Bind a device to a driver",
" \n"
-   "bind   \n"
+   "bind   \n"
"Use 'dm tree' to list all devices registered in the driver model,\n"
-   "their path, class, index and current driver.\n"
+   &qu

Re: [PATCH] usb: gadget: ether: Handle gadget driver registration in start and stop

2024-08-07 Thread Zixun LI
Hi Mattijs,

On Tue, Aug 6, 2024 at 4:00 PM Mattijs Korpershoek
 wrote:
>
> I'd like to test this on my end as well. Could you please give some
> details on how this has been tested?
>
> A sequence of U-Boot commands would be helpful, for example.

My tests are done on a custom ATMEL SAM9G25 board powered
by USB Gadget port.

Gadget is enabled in the DT:
&usb2 {
status = "okay";
};

usb_ether enabled in board late init:
int board_late_init(void)
{
#ifdef CONFIG_USB_ETHER
usb_ether_init();
#endif
return 0;
}

Without this patch the host will try to enumerate the USB device once
 U-Boot is loaded and result in the error I mentioned.

With this patch USB is connected only when ethernet command, like dhcp
is run, then disconnect when it's finished:
usb 1-1: new high-speed USB device number 91 using xhci_hcd
usb 1-1: New USB device found, idVendor=, idProduct=, bcdDevice= 3.17
usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 1-1: Product: Ethernet Gadget
usb 1-1: Manufacturer: U-Boot
cdc_ether 1-1:1.0 usb0: register 'cdc_ether' at usb-:04:00.3-1,
CDC Ethernet Device, de:ad:be:ef:00:00
cdc_ether 1-1:1.0 enp4s0f3u1: renamed from usb0
gadget0: port 1(enp4s0f3u1) entered blocking state
gadget0: port 1(enp4s0f3u1) entered disabled state
cdc_ether 1-1:1.0 enp4s0f3u1: entered allmulticast mode
cdc_ether 1-1:1.0 enp4s0f3u1: entered promiscuous mode
gadget0: port 1(enp4s0f3u1) entered blocking state
gadget0: port 1(enp4s0f3u1) entered forwarding state
usb 1-1: USB disconnect, device number 91


Re: [PATCH] usb: gadget: udc: Fix duplicate uclass name

2024-08-07 Thread Zixun LI
Hi Mattijs,

On Wed, Aug 7, 2024 at 9:07 AM Mattijs Korpershoek
 wrote:
>
>
> Have you identified boards which use the DT alias that will break
> with this patch?
>
> Maybe we can detail the required fix in the commit message a bit as well?
> Or, if you know of a board that uses "usb" as DT alias sequence number,
> we can submit a fix alongside with this one to document the fix.

I did a search and it affects mostly i.MX devices and Nuvoton npcm845 where
host and device controller use the same alias.

like imx6qdl.dtsi:
aliases {
...
usb0 = &usbotg;
usb1 = &usbh1;
usb2 = &usbh2;
usb3 = &usbh3;
};

nuvoton-npcm845-evb.dts:
aliases {
...
usb0 = &udc0;
usb1 = &ehci1;
usb2 = &ehci2;
};

But I got lost in EHCI's code, like in ehci_register() when ctrl->init ==
USB_INIT_DEVICE the function returns without the actual device init ?
I'm not sure how their gadget mode works and if it's really broken or not.


Re: [PATCH] usb: gadget: udc: Fix duplicate uclass name

2024-08-13 Thread Zixun LI
Hi Mattijs,

On Tue, Aug 13, 2024 at 10:28 AM Mattijs Korpershoek
 wrote:
>
> Thank you for giving some board examples. I am still a bit unclear on
> the meaning of:
>
> """
> This breaks the capacity of using "usb" as DT alias sequence numbering
> which needs a fix afterwards.
> """
>
> I have added Jagan, Stefano, Fabio and the NXP team in CC. Does anyone
> of you have any concerns with this patch ?
>
> If someone could test it, that would be helpful.

The device sequence number is affected by uclass_find_next_free_seq() in
uclass.c, in this function uclass name is used to determine the number.

Since the gadget class's name changed to "usb_gadget" from "usb", alias
binding "usb1 = &usbotg;" is not effective anymore. As now it searches for
"usb_gadget1 = &usbotg;".

uclass_find_device_by_seq(UCLASS_USB_GADGET_GENERIC,) would fail as sequence
number is changed.

I made a tentative fix in
https://lore.kernel.org/u-boot/20240731134257.686017-2-ad...@hifiphile.com/
But Simon doesn't want to modify uclass_driver structure only for gadget
class.

Regards,
Zixun


[PATCH 1/1] usb: gadget: ether: Disable USB pullup in eth probe

2024-08-21 Thread Zixun LI
usb_gadget_register_driver() called by probe will initialize the USB
controller which enters ready to connect state with pull-up resistor
enabled.

>From the host's point of view, a device is ready to be enumerated.
However, since dm_usb_gadget_handle_interrupts() is only called when
ethernet function is started, at this stage USB events are not managed,
host's enumeration attempts will fail and resulting error like:
usb 1-1: new high-speed USB device number 50 using xhci_hcd
usb 1-1: device descriptor read/64, error -110
usb 1-1: device descriptor read/64, error -110
usb usb1-port1: attempt power cycle

Disable USB pullup to prevent unwanted enumeration attempt.

Signed-off-by: Zixun LI 
---
 drivers/usb/gadget/ether.c | 11 ++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 7973927e8a..c864beeaa7 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -2459,6 +2459,8 @@ static int usb_eth_probe(struct udevice *dev)
 {
struct ether_priv *priv = dev_get_priv(dev);
struct eth_pdata *pdata = dev_get_plat(dev);
+   struct eth_dev *ethdev = &priv->ethdev;
+   int ret;

priv->netdev = dev;
l_priv = priv;
@@ -2499,7 +2501,14 @@ static int usb_eth_probe(struct udevice *dev)
priv->eth_driver.disconnect = eth_disconnect;
priv->eth_driver.suspend= eth_suspend;
priv->eth_driver.resume = eth_resume;
-   return usb_gadget_register_driver(&priv->eth_driver);
+
+   ret = usb_gadget_register_driver(&priv->eth_driver);
+   if (ret)
+   return ret;
+
+   /* Keep pullup disabled until interrupt is available */
+   usb_gadget_disconnect(ethdev->gadget);
+   return 0;
 }

 static int usb_eth_remove(struct udevice *dev)
--
2.45.2



Re: [PATCH 1/1] usb: gadget: ether: Disable USB pullup in eth probe

2024-08-21 Thread Zixun LI
Hi Marek,

On Wed, Aug 21, 2024 at 11:43 PM Marek Vasut  wrote:
>
> Wouldn't it be better if usb_gadget_register_driver() started in
> disconnected state right away ?

That's what I did initially. But since g_dnl doesn't do connection after
register (I explained in cover letter) doing so will keep g_dnl always in
disconnected state.


Re: [PATCH 1/1] usb: gadget: ether: Disable USB pullup in eth probe

2024-08-22 Thread Zixun LI
Hi,

On Thu, Aug 22, 2024 at 1:26 AM Marek Vasut  wrote:
>
> Would it be possible to fix up the g_dnl ?

g_dnl's interface is pretty different from usb_ether, I can't find a
way to access
usb_gadget struct in g_dnl_register().

Meanwhile it can be fixed in udc core, by doing gadget_driver bind
after udc start,
in addition to keeping the controller in disconnected state.

diff --git a/drivers/usb/gadget/udc/udc-core.c
b/drivers/usb/gadget/udc/udc-core.c
index 6bb419ae2a..b917a79892 100644
--- a/drivers/usb/gadget/udc/udc-core.c
+++ b/drivers/usb/gadget/udc/udc-core.c
@@ -300,15 +300,17 @@ static int udc_bind_to_driver(struct usb_udc
*udc, struct usb_gadget_driver *dri

 usb_gadget_udc_set_speed(udc, driver->speed);

-ret = driver->bind(udc->gadget);
-if (ret)
-goto err1;
 ret = usb_gadget_udc_start(udc);
 if (ret) {
-driver->unbind(udc->gadget);
 goto err1;
 }
-usb_gadget_connect(udc->gadget);
+
+/* Keep pullup disabled until interrupt is available */
+usb_gadget_disconnect(udc->gadget);
+
+ret = driver->bind(udc->gadget);
+if (ret)
+goto err1;

 return 0;
 err1:


Re: [PATCH 1/1] usb: gadget: ether: Disable USB pullup in eth probe

2024-08-22 Thread Zixun LI
On Thu, Aug 22, 2024 at 5:24 PM Marek Vasut  wrote:
>
> Can you change the g_dnl_register() prototype and pass he structure in ?
> I suspect it should be available in the commands which register g_dnl ?
>

There are many places where g_dnl_register() is called, like fastboot, dfu, ums,
etc, need to modify all of them ?

>
> This is no good, this is a workaround, let's not do this.
>

You mean which part, order change or disconnect call ?

Is there a fixed order of udc_start (device init) and driver->bind ?
In non-DM mode most device drivers do init first in their
usb_gadget_register_driver(), except udc-core and DWC2 who does
driver->bind first.

Call usb_gadget_disconnect here could avoid modifying all device driver's init.


Re: [PATCH 1/1] usb: gadget: ether: Disable USB pullup in eth probe

2024-08-23 Thread Zixun LI
On Fri, Aug 23, 2024 at 4:54 AM Marek Vasut  wrote:
>
> I think udc_bind_to_driver() should not call usb_gadget_connect() , that
> connect should likely be called by at some later point.

Yes it's more logical, to keep it in disconnected state you prefer modify
controllers drivers init (I can do usba_udc and dwc2) or add a disconnect()
call ?

> I also think
> that drivers/usb/gadget/udc/udc-core.c might have to be extended to
> provide some way to convert controller struct udevice to struct
> usb_gadget , so when e.g. run_usb_dnl_gadget() calls
> udc_device_get_by_index() and obtains struct udevice * , it can also get
> matching struct usb_gadget * , and call the usb_gadget_connect().
>
> What do you think ?

I think it's a good idea.

If there are multiple gadget controllers (very rare), since
usb_gadget_probe_driver() simply takes the first one from udc list,
is there a chance that the one to be started is different from the one
used by udc_device_get_by_index() ?


Re: [PATCH 1/1] usb: gadget: ether: Disable USB pullup in eth probe

2024-08-26 Thread Zixun LI
On Sun, Aug 25, 2024 at 2:13 AM Marek Vasut  wrote:
>
> >
> > I am looking at the usb_add_gadget_udc_release() and
> > usb_gadget_probe_driver() and I am thinking, sigh, all that code is
> > ready to be replaced by something cleaner which does not use this
> > special struct usb_udc and udc_list, but instead only uses U-Boot DM
> > udevices . But I am reluctant to ask you to do all that rework, because
> > that is WAY out of scope of the problem you are trying to fix.
>

Thank you for looking into this, refactor udc core could make things clear.

> Maybe this could be a start (compile tested only):
>
> https://source.denx.de/u-boot/custodians/u-boot-sh/-/commits/usb-udc-udevice

Tested no regression with usba_udc.


Re: [PATCH v2] mtd: nand: raw: atmel: Use ONFI ECC params if available

2024-10-09 Thread Zixun LI
Hi, sorry to bother, it seems like the patch is not picked up yet ?

Zixun


[PATCH 3/3] gpio: at91: Implement ops get_flags

2024-10-18 Thread Zixun LI
Add ops get_dir_flags() to read status from GPIO registers.

Signed-off-by: Zixun LI 
---
 drivers/gpio/at91_gpio.c | 45 
 1 file changed, 45 insertions(+)

diff --git a/drivers/gpio/at91_gpio.c b/drivers/gpio/at91_gpio.c
index 7828f9b447..c986007716 100644
--- a/drivers/gpio/at91_gpio.c
+++ b/drivers/gpio/at91_gpio.c
@@ -240,6 +240,24 @@ static void at91_set_port_multi_drive(struct at91_port 
*at91_port, int offset, i
else
writel(mask, &at91_port->mddr);
 }
+
+static bool at91_get_port_multi_drive(struct at91_port *at91_port, int offset)
+{
+   u32 mask, val;
+
+   mask = 1 << offset;
+   val = readl(&at91_port->mdsr);
+   return val & mask;
+}
+
+static bool at91_get_port_pullup(struct at91_port *at91_port, int offset)
+{
+   u32 mask, val;
+
+   mask = 1 << offset;
+   val = readl(&at91_port->pusr);
+   return val & mask;
+}
 #endif
 
 static void at91_set_port_input(struct at91_port *at91_port, int offset,
@@ -608,6 +626,32 @@ static int at91_gpio_set_flags(struct udevice *dev, 
unsigned int offset,
return 0;
 }
 
+static int at91_gpio_get_flags(struct udevice *dev, unsigned int offset,
+   ulong *flagsp)
+{
+   struct at91_port_priv *port = dev_get_priv(dev);
+   ulong dir_flags = 0;
+
+   if (at91_get_port_output(port->regs, offset)) {
+   dir_flags |= GPIOD_IS_OUT;
+
+   if (at91_get_port_multi_drive(port->regs, offset))
+   dir_flags |= GPIOD_OPEN_DRAIN;
+
+   if (at91_get_port_value(port->regs, offset))
+   dir_flags |= GPIOD_IS_OUT_ACTIVE;
+   } else {
+   dir_flags |= GPIOD_IS_IN;
+   }
+
+   if (at91_get_port_pullup(port->regs, offset))
+   dir_flags |= GPIOD_PULL_UP;
+
+   *flagsp = dir_flags;
+
+   return 0;
+}
+
 static const char *at91_get_bank_name(uint32_t base_addr)
 {
switch (base_addr) {
@@ -637,6 +681,7 @@ static const struct dm_gpio_ops gpio_at91_ops = {
.set_value  = at91_gpio_set_value,
.get_function   = at91_gpio_get_function,
.set_flags  = at91_gpio_set_flags,
+   .get_flags  = at91_gpio_get_flags,
 };
 
 static int at91_gpio_probe(struct udevice *dev)
-- 
2.46.2



[PATCH 1/3] gpio: at91: Implement GPIOF_FUNC in get_function()

2024-10-18 Thread Zixun LI
This patch adds support for determining whether a gpio pin is mapped as
peripheral function.

Signed-off-by: Zixun LI 
---
 drivers/gpio/at91_gpio.c | 13 -
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/gpio/at91_gpio.c b/drivers/gpio/at91_gpio.c
index 1409db5dc1..64a6e8a4a5 100644
--- a/drivers/gpio/at91_gpio.c
+++ b/drivers/gpio/at91_gpio.c
@@ -220,6 +220,15 @@ static bool at91_get_port_output(struct at91_port 
*at91_port, int offset)
val = readl(&at91_port->osr);
return val & mask;
 }
+
+static bool at91_get_port_pio(struct at91_port *at91_port, int offset)
+{
+   u32 mask, val;
+
+   mask = 1 << offset;
+   val = readl(&at91_port->psr);
+   return val & mask;
+}
 #endif
 
 static void at91_set_port_input(struct at91_port *at91_port, int offset,
@@ -550,7 +559,9 @@ static int at91_gpio_get_function(struct udevice *dev, 
unsigned offset)
 {
struct at91_port_priv *port = dev_get_priv(dev);
 
-   /* GPIOF_FUNC is not implemented yet */
+   if (!at91_get_port_pio(port->regs, offset))
+   return GPIOF_FUNC;
+
if (at91_get_port_output(port->regs, offset))
return GPIOF_OUTPUT;
else
-- 
2.46.2



[PATCH 2/3] gpio: at91: Implement ops set_flags

2024-10-18 Thread Zixun LI
Support GPIO configuration with following flags:
- in, out, out_active
- open_drain, pull_up

Signed-off-by: Zixun LI 
---
 drivers/gpio/at91_gpio.c | 41 
 1 file changed, 41 insertions(+)

diff --git a/drivers/gpio/at91_gpio.c b/drivers/gpio/at91_gpio.c
index 64a6e8a4a5..7828f9b447 100644
--- a/drivers/gpio/at91_gpio.c
+++ b/drivers/gpio/at91_gpio.c
@@ -229,6 +229,17 @@ static bool at91_get_port_pio(struct at91_port *at91_port, 
int offset)
val = readl(&at91_port->psr);
return val & mask;
 }
+
+static void at91_set_port_multi_drive(struct at91_port *at91_port, int offset, 
int is_on)
+{
+   u32 mask;
+
+   mask = 1 << offset;
+   if (is_on)
+   writel(mask, &at91_port->mder);
+   else
+   writel(mask, &at91_port->mddr);
+}
 #endif
 
 static void at91_set_port_input(struct at91_port *at91_port, int offset,
@@ -568,6 +579,35 @@ static int at91_gpio_get_function(struct udevice *dev, 
unsigned offset)
return GPIOF_INPUT;
 }
 
+static int at91_gpio_set_flags(struct udevice *dev, unsigned int offset,
+   ulong flags)
+{
+   struct at91_port_priv *port = dev_get_priv(dev);
+   ulong supported_mask;
+
+   supported_mask = GPIOD_OPEN_DRAIN | GPIOD_MASK_DIR | GPIOD_PULL_UP;
+   if (flags & ~supported_mask)
+   return -EINVAL;
+
+   if (flags & GPIOD_IS_OUT) {
+   bool value = flags & GPIOD_IS_OUT_ACTIVE;
+
+   if (flags & GPIOD_OPEN_DRAIN)
+   at91_set_port_multi_drive(port->regs, offset, true);
+   else
+   at91_set_port_multi_drive(port->regs, offset, false);
+
+   at91_set_port_output(port->regs, offset, value);
+
+   } else if (flags & GPIOD_IS_IN) {
+   at91_set_port_input(port->regs, offset, false);
+   }
+   if (flags & GPIOD_PULL_UP)
+   at91_set_port_pullup(port->regs, offset, true);
+
+   return 0;
+}
+
 static const char *at91_get_bank_name(uint32_t base_addr)
 {
switch (base_addr) {
@@ -596,6 +636,7 @@ static const struct dm_gpio_ops gpio_at91_ops = {
.get_value  = at91_gpio_get_value,
.set_value  = at91_gpio_set_value,
.get_function   = at91_gpio_get_function,
+   .set_flags  = at91_gpio_set_flags,
 };
 
 static int at91_gpio_probe(struct udevice *dev)
-- 
2.46.2



[PATCH v2 3/3] gpio: at91: Implement ops get_flags

2024-10-18 Thread Zixun LI
Add ops get_dir_flags() to read status from GPIO registers.

Signed-off-by: Zixun LI 

---
Changes in v2:
- Fix pullup read polarity
---
 drivers/gpio/at91_gpio.c | 45 
 1 file changed, 45 insertions(+)

diff --git a/drivers/gpio/at91_gpio.c b/drivers/gpio/at91_gpio.c
index 7828f9b447..c44e02cd90 100644
--- a/drivers/gpio/at91_gpio.c
+++ b/drivers/gpio/at91_gpio.c
@@ -240,6 +240,24 @@ static void at91_set_port_multi_drive(struct at91_port 
*at91_port, int offset, i
else
writel(mask, &at91_port->mddr);
 }
+
+static bool at91_get_port_multi_drive(struct at91_port *at91_port, int offset)
+{
+   u32 mask, val;
+
+   mask = 1 << offset;
+   val = readl(&at91_port->mdsr);
+   return val & mask;
+}
+
+static bool at91_get_port_pullup(struct at91_port *at91_port, int offset)
+{
+   u32 mask, val;
+
+   mask = 1 << offset;
+   val = readl(&at91_port->pusr);
+   return !(val & mask);
+}
 #endif
 
 static void at91_set_port_input(struct at91_port *at91_port, int offset,
@@ -608,6 +626,32 @@ static int at91_gpio_set_flags(struct udevice *dev, 
unsigned int offset,
return 0;
 }
 
+static int at91_gpio_get_flags(struct udevice *dev, unsigned int offset,
+   ulong *flagsp)
+{
+   struct at91_port_priv *port = dev_get_priv(dev);
+   ulong dir_flags = 0;
+
+   if (at91_get_port_output(port->regs, offset)) {
+   dir_flags |= GPIOD_IS_OUT;
+
+   if (at91_get_port_multi_drive(port->regs, offset))
+   dir_flags |= GPIOD_OPEN_DRAIN;
+
+   if (at91_get_port_value(port->regs, offset))
+   dir_flags |= GPIOD_IS_OUT_ACTIVE;
+   } else {
+   dir_flags |= GPIOD_IS_IN;
+   }
+
+   if (at91_get_port_pullup(port->regs, offset))
+   dir_flags |= GPIOD_PULL_UP;
+
+   *flagsp = dir_flags;
+
+   return 0;
+}
+
 static const char *at91_get_bank_name(uint32_t base_addr)
 {
switch (base_addr) {
@@ -637,6 +681,7 @@ static const struct dm_gpio_ops gpio_at91_ops = {
.set_value  = at91_gpio_set_value,
.get_function   = at91_gpio_get_function,
.set_flags  = at91_gpio_set_flags,
+   .get_flags  = at91_gpio_get_flags,
 };
 
 static int at91_gpio_probe(struct udevice *dev)
-- 
2.46.2



[PATCH] dm: gpio: Return error when pull up/down is requested but set_flags ops is not implmentated

2024-10-21 Thread Zixun LI
Currently in _dm_gpio_set_flags() when set_flags ops is not implemented
direction_output()/_input() is used, but pull up/down is not supported by
these ops.

Signed-off-by: Zixun LI 
---
We have updated our AT91 BSP to use DM, on field testing few boards
went into a failed state due to gpio pullup is not enabled. A floating
gpio doesn't always fail and can sometimes be hard to diagostic.
---
 drivers/gpio/gpio-uclass.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 712119c341..a58513c946 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -661,6 +661,9 @@ static int _dm_gpio_set_flags(struct gpio_desc *desc, ulong 
flags)
if (ops->set_flags) {
ret = ops->set_flags(dev, desc->offset, flags);
} else {
+   if (flags & GPIOD_MASK_PULL)
+   return -EINVAL;
+
if (flags & GPIOD_IS_OUT) {
bool value = flags & GPIOD_IS_OUT_ACTIVE;
 
-- 
2.46.2



env: ENV_WRITEABLE_LIST with ".flags" variable

2024-10-30 Thread Zixun LI
Hello,

I read the code about environment variable protection and an old
discussion: https://lists.denx.de/pipermail/u-boot/2021-April/446247.html
but I still have a question.

In env_flags_init() we have:
  if (first_call) {
#ifdef CONFIG_ENV_WRITEABLE_LIST
  flags_list = ENV_FLAGS_LIST_STATIC;
#else
  flags_list = env_get(ENV_FLAGS_VAR);
#endif
first_call = 0;
  }

When ENV_WRITEABLE_LIST is enabled, why do we have to initialize the list
with ENV_FLAGS_LIST_STATIC instead of ".flags" ? Doing so makes ".flags"
being ignored.

In env_flags_lookup() there is already a fallback when a flag is not
found, the static list will be checked.

Since default env is firstly loaded in env_load(), external ".flags" are
rejected and don't affect the security:
  change_ok() rejected setting variable .flags, skipping it!

Advantage of using .flags is being able to use a .env file to
group all variables together without modifying the included header.

Best regards,
Zixun


Re: [PATCH 1/3] gpio: at91: Implement GPIOF_FUNC in get_function()

2024-11-12 Thread Zixun LI
Hello,


On Tue, Nov 12, 2024 at 2:13 PM Eugen Hristev  wrote:
>
>
> > +static bool at91_get_port_pio(struct at91_port *at91_port, int offset)
>
> The name get_port_pio is a bit confusing, can you rename it to something
> more meaningful, like maybe is_periph_func or something ?

How about at91_is_port_pio_active, more inline to the datasheet.


Re: [PATCH 2/3] gpio: at91: Implement ops set_flags

2024-11-12 Thread Zixun LI
Hi,

On Tue, Nov 12, 2024 at 2:21 PM Eugen Hristev  wrote:
>
> Does this change the current behavior? there is no set_flag ops
> implemented, previously it would use a default that would just return
> success regardless of the given flags parameters ?
> Btw maybe ENOTSUPP ?
>

Currently without .set_flags ops it just returns success regardless of the
given flags parameters. It's problematic especially when pull-up/down is used.
I've another patch to fix the silent failure:
https://lists.denx.de/pipermail/u-boot/2024-October/569044.html

Most drivers just ignore unsupported flags, I copied flag check from mcp230xx
driver. Is it better to return ENOTSUPP instead ?

> > +
> > + if (flags & GPIOD_IS_OUT) {
> > + bool value = flags & GPIOD_IS_OUT_ACTIVE;
>
> Can you please declare this value at the start of the function, or
> inline it below when it's being used
>

Will do.


Re: [PATCH 1/3] gpio: at91: Implement GPIOF_FUNC in get_function()

2024-11-12 Thread Zixun LI
On Tue, Nov 12, 2024 at 4:59 PM Eugen Hristev  wrote:
>
>
>
> On 11/12/24 17:57, Zixun LI wrote:
> > Hello,
> >
> >
> > On Tue, Nov 12, 2024 at 2:13 PM Eugen Hristev  
> > wrote:
> >>
> >>
> >>> +static bool at91_get_port_pio(struct at91_port *at91_port, int offset)
> >>
> >> The name get_port_pio is a bit confusing, can you rename it to something
> >> more meaningful, like maybe is_periph_func or something ?
> >
> > How about at91_is_port_pio_active, more inline to the datasheet.
>
>
> I am not sure. It appears confusing to me.
> The pin is either in GPIO or peripheral function mode.
> Being 'PIO active' appears to be something different, or common to both
> options.
> What does the datasheet say exactly ?

>From SAM9G25 datasheet, 22.6.3 PIO Status Register

0: PIO is inactive on the corresponding I/O line (peripheral is active).
1: PIO is active on the corresponding I/O line (peripheral is inactive).

"PIO" is the port controller itself but also means GPIO which is not very clear.

Or at91_is_port_gpio ?


Re: [PATCH v2 3/3] gpio: at91: Implement ops get_flags

2024-11-12 Thread Zixun LI
Hi,

On Tue, Nov 12, 2024 at 2:27 PM Eugen Hristev  wrote:
>
> Use clamp (!!) to turn this into a bool.
>

Should I also fix the existing function at91_get_port_output() ?


[PATCH v2 1/3] gpio: at91: Implement GPIOF_FUNC in get_function()

2024-11-13 Thread Zixun LI
This patch adds support for determining whether a gpio pin is mapped as
peripheral function.

Signed-off-by: Zixun LI 
---
Changes in v2:
- Rename function
---
 drivers/gpio/at91_gpio.c | 13 -
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/gpio/at91_gpio.c b/drivers/gpio/at91_gpio.c
index 1409db5dc1..173315d45f 100644
--- a/drivers/gpio/at91_gpio.c
+++ b/drivers/gpio/at91_gpio.c
@@ -220,6 +220,15 @@ static bool at91_get_port_output(struct at91_port 
*at91_port, int offset)
val = readl(&at91_port->osr);
return val & mask;
 }
+
+static bool at91_is_port_gpio(struct at91_port *at91_port, int offset)
+{
+   u32 mask, val;
+
+   mask = 1 << offset;
+   val = readl(&at91_port->psr);
+   return !!(val & mask);
+}
 #endif

 static void at91_set_port_input(struct at91_port *at91_port, int offset,
@@ -550,7 +559,9 @@ static int at91_gpio_get_function(struct udevice *dev, 
unsigned offset)
 {
struct at91_port_priv *port = dev_get_priv(dev);

-   /* GPIOF_FUNC is not implemented yet */
+   if (!at91_is_port_gpio(port->regs, offset))
+   return GPIOF_FUNC;
+
if (at91_get_port_output(port->regs, offset))
return GPIOF_OUTPUT;
else
--
2.46.2



[PATCH v2 2/3] gpio: at91: Implement ops set_flags

2024-11-13 Thread Zixun LI
Support GPIO configuration with following flags:
- in, out, out_active
- open_drain, pull_up

Signed-off-by: Zixun LI 
---
Changes in v2:
- Return ENOTSUPP if flag is unsupported.
- Inline port output variable.
---
 drivers/gpio/at91_gpio.c | 39 +++
 1 file changed, 39 insertions(+)

diff --git a/drivers/gpio/at91_gpio.c b/drivers/gpio/at91_gpio.c
index 173315d45f..758cb4a806 100644
--- a/drivers/gpio/at91_gpio.c
+++ b/drivers/gpio/at91_gpio.c
@@ -229,6 +229,17 @@ static bool at91_is_port_gpio(struct at91_port *at91_port, 
int offset)
val = readl(&at91_port->psr);
return !!(val & mask);
 }
+
+static void at91_set_port_multi_drive(struct at91_port *at91_port, int offset, 
int is_on)
+{
+   u32 mask;
+
+   mask = 1 << offset;
+   if (is_on)
+   writel(mask, &at91_port->mder);
+   else
+   writel(mask, &at91_port->mddr);
+}
 #endif

 static void at91_set_port_input(struct at91_port *at91_port, int offset,
@@ -568,6 +579,33 @@ static int at91_gpio_get_function(struct udevice *dev, 
unsigned offset)
return GPIOF_INPUT;
 }

+static int at91_gpio_set_flags(struct udevice *dev, unsigned int offset,
+  ulong flags)
+{
+   struct at91_port_priv *port = dev_get_priv(dev);
+   ulong supported_mask;
+
+   supported_mask = GPIOD_OPEN_DRAIN | GPIOD_MASK_DIR | GPIOD_PULL_UP;
+   if (flags & ~supported_mask)
+   return -ENOTSUPP;
+
+   if (flags & GPIOD_IS_OUT) {
+   if (flags & GPIOD_OPEN_DRAIN)
+   at91_set_port_multi_drive(port->regs, offset, true);
+   else
+   at91_set_port_multi_drive(port->regs, offset, false);
+
+   at91_set_port_output(port->regs, offset, flags & 
GPIOD_IS_OUT_ACTIVE);
+
+   } else if (flags & GPIOD_IS_IN) {
+   at91_set_port_input(port->regs, offset, false);
+   }
+   if (flags & GPIOD_PULL_UP)
+   at91_set_port_pullup(port->regs, offset, true);
+
+   return 0;
+}
+
 static const char *at91_get_bank_name(uint32_t base_addr)
 {
switch (base_addr) {
@@ -596,6 +634,7 @@ static const struct dm_gpio_ops gpio_at91_ops = {
.get_value  = at91_gpio_get_value,
.set_value  = at91_gpio_set_value,
.get_function   = at91_gpio_get_function,
+   .set_flags  = at91_gpio_set_flags,
 };

 static int at91_gpio_probe(struct udevice *dev)
--
2.46.2



[PATCH v3 3/3] gpio: at91: Implement ops get_flags

2024-11-13 Thread Zixun LI
Add ops get_dir_flags() to read status from GPIO registers.

Signed-off-by: Zixun LI 

---
Changes in v2:
- Fix pullup read polarity
Changes in v3:
- Use clamp (!!) to turn return value into a bool
---
 drivers/gpio/at91_gpio.c | 45 
 1 file changed, 45 insertions(+)

diff --git a/drivers/gpio/at91_gpio.c b/drivers/gpio/at91_gpio.c
index 758cb4a806..a0a200b3ca 100644
--- a/drivers/gpio/at91_gpio.c
+++ b/drivers/gpio/at91_gpio.c
@@ -240,6 +240,24 @@ static void at91_set_port_multi_drive(struct at91_port 
*at91_port, int offset, i
else
writel(mask, &at91_port->mddr);
 }
+
+static bool at91_get_port_multi_drive(struct at91_port *at91_port, int offset)
+{
+   u32 mask, val;
+
+   mask = 1 << offset;
+   val = readl(&at91_port->mdsr);
+   return !!(val & mask);
+}
+
+static bool at91_get_port_pullup(struct at91_port *at91_port, int offset)
+{
+   u32 mask, val;
+
+   mask = 1 << offset;
+   val = readl(&at91_port->pusr);
+   return !(val & mask);
+}
 #endif

 static void at91_set_port_input(struct at91_port *at91_port, int offset,
@@ -606,6 +624,32 @@ static int at91_gpio_set_flags(struct udevice *dev, 
unsigned int offset,
return 0;
 }

+static int at91_gpio_get_flags(struct udevice *dev, unsigned int offset,
+  ulong *flagsp)
+{
+   struct at91_port_priv *port = dev_get_priv(dev);
+   ulong dir_flags = 0;
+
+   if (at91_get_port_output(port->regs, offset)) {
+   dir_flags |= GPIOD_IS_OUT;
+
+   if (at91_get_port_multi_drive(port->regs, offset))
+   dir_flags |= GPIOD_OPEN_DRAIN;
+
+   if (at91_get_port_value(port->regs, offset))
+   dir_flags |= GPIOD_IS_OUT_ACTIVE;
+   } else {
+   dir_flags |= GPIOD_IS_IN;
+   }
+
+   if (at91_get_port_pullup(port->regs, offset))
+   dir_flags |= GPIOD_PULL_UP;
+
+   *flagsp = dir_flags;
+
+   return 0;
+}
+
 static const char *at91_get_bank_name(uint32_t base_addr)
 {
switch (base_addr) {
@@ -635,6 +679,7 @@ static const struct dm_gpio_ops gpio_at91_ops = {
.set_value  = at91_gpio_set_value,
.get_function   = at91_gpio_get_function,
.set_flags  = at91_gpio_set_flags,
+   .get_flags  = at91_gpio_get_flags,
 };

 static int at91_gpio_probe(struct udevice *dev)
--
2.46.2



[PATCH] usb: gadget: atmel: Add SAM9X60 support

2025-03-23 Thread Zixun LI
Add compatible "microchip,sam9x60-udc" and device tree binding.
Compared to SAM9X5 the only difference is the DPRAM memory from the
USB High Speed Device Port (UDPHS) hardware block was increased,
so we can reuse the same endpoint data.

Tested on SAM9X60-Curiosity board with nfs and ums commands.

Signed-off-by: Zixun LI 
---
 arch/arm/dts/sam9x60.dtsi| 14 ++
 arch/arm/mach-at91/include/mach/atmel_usba_udc.h |  2 +-
 drivers/usb/gadget/atmel_usba_udc.c  |  1 +
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/arch/arm/dts/sam9x60.dtsi b/arch/arm/dts/sam9x60.dtsi
index 3b684fc63d5..96a8faf09b3 100644
--- a/arch/arm/dts/sam9x60.dtsi
+++ b/arch/arm/dts/sam9x60.dtsi
@@ -69,6 +69,20 @@
#size-cells = <1>;
ranges;
 
+   usb0: gadget@50 {
+   compatible = "microchip,sam9x60-udc";
+   reg = <0x50 0x10>,
+   <0xf803c000 0x400>;
+   #address-cells = <1>;
+   #size-cells = <0>;
+   interrupts = <23 IRQ_TYPE_LEVEL_HIGH 2>;
+   clocks = <&pmc PMC_TYPE_PERIPHERAL 23>, <&pmc 
PMC_TYPE_CORE 8>;
+   clock-names = "pclk", "hclk";
+   assigned-clocks = <&pmc PMC_TYPE_CORE 8>;
+   assigned-clock-rates = <48000>;
+   status = "disabled";
+   };
+
usb1: usb@60 {
compatible = "atmel,at91rm9200-ohci", "usb-ohci";
reg = <0x0060 0x10>;
diff --git a/arch/arm/mach-at91/include/mach/atmel_usba_udc.h 
b/arch/arm/mach-at91/include/mach/atmel_usba_udc.h
index 835b47d91ba..23c71985c90 100644
--- a/arch/arm/mach-at91/include/mach/atmel_usba_udc.h
+++ b/arch/arm/mach-at91/include/mach/atmel_usba_udc.h
@@ -20,7 +20,7 @@
}
 
 #if defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) || \
-   defined(CONFIG_AT91SAM9X5)
+   defined(CONFIG_AT91SAM9X5) || defined(CONFIG_SAM9X60)
 static struct usba_ep_data usba_udc_ep[] = {
EP("ep0", 0, 64, 1, 0, 0),
EP("ep1", 1, 1024, 2, 1, 1),
diff --git a/drivers/usb/gadget/atmel_usba_udc.c 
b/drivers/usb/gadget/atmel_usba_udc.c
index a77037a7094..f9326f0a7e7 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -1443,6 +1443,7 @@ static const struct udevice_id usba_udc_ids[] = {
{ .compatible = "atmel,at91sam9rl-udc" },
{ .compatible = "atmel,at91sam9g45-udc" },
{ .compatible = "atmel,sama5d3-udc" },
+   { .compatible = "microchip,sam9x60-udc" },
{}
 };
 
-- 
2.39.5



Re: usb:composite: data abort on second ums launch

2025-03-24 Thread Zixun LI
On Mon, Mar 24, 2025 at 3:12 PM Marek Vasut  wrote:
> Can you reproduce this on u-boot/master too ?

Yes I can reproduce it on master 2025.04-244e61f, since fsg init/deinit code
are the same.


Re: usb:composite: data abort on second ums launch

2025-03-24 Thread Zixun LI
On Mon, Mar 24, 2025 at 6:21 PM Mattijs Korpershoek
 wrote:
> I've tried to reproduce this on master (2025.04-rc4-g244e61fbb7f5) and I
> don't reproduce this with the VIM3 board using 
> khadas-vim3_android_ab_defconfig:
>
> I'll try to understand why it's behaving differently between the
> sam9x60-curiosity and the vim3.

Thank you for your test, I think it's because VIM3 is a large SoC with
plenty of RAM
(SYS_MALLOC_LEN=0x0800) while SAM9X60 is much smaller
(SYS_MALLOC_LEN=0x81000).

Each time when ums is called 2*FSG_BUFLEN, 256kB buffer is allocated
and it seems not
freed as fsg_common_release() is not called.

Zixun


usb:composite: data abort on second ums launch

2025-03-24 Thread Zixun LI
Hi,

I encountered a data abort on the 2nd "ums 0 mmc 0" command on
u-boot-at91 2024.07 with sam9x60-curiosity board.

U-Boot> ums 0 mmc 0
UMS: LUN 0, dev mmc 0, hwpart 0, sector 0x0, count 0x1d29000
CTRL+C - Operation aborted
U-Boot> ums 0 mmc 0
UMS: LUN 0, dev mmc 0, hwpart 0, sector 0x0, count 0x1d29000
data abort
pc : [<27f93428>]  lr : [<27ef7e80>]
reloc pc : [<23f16428>]lr : [<23e7ae80>]
sp : 27ef4cf0  ip : a520 fp : 23f6915c
r10: deadbeef  r9 : 27ef7e80 r8 : 27f7d2a0
r7 : a520  r6 :  r5 :   r4 : 27f01668
r3 :   r2 :  r1 : 27fe1d88  r0 : 27f01668
Flags: nzCV  IRQs off  FIQs off  Mode SVC_32 (T)
Code: 45ac d017 68c5 4667 (60fd) 60af

>From backtrace the abort happened in fREe_impl(), with some debugging
I've localized the abort in fact happened in fsg buffer allocation in
fsg_common_init() [1]

It looks like the buffer is not freed on driver unregister since
fsg_common_release() is only called if fsg_common_init() met an error.


[1] 
https://elixir.bootlin.com/u-boot/v2025.01/source/drivers/usb/gadget/f_mass_storage.c#L2511


[PATCH 7/7] ARM: dts: at91: sam9x60-curiosity: Enable watchdog node

2025-04-05 Thread Zixun LI
Enable watchdog node on SAM9X60-Curiosity board.

Signed-off-by: Zixun LI 
---
 arch/arm/dts/at91-sam9x60_curiosity.dts | 5 +
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/dts/at91-sam9x60_curiosity.dts 
b/arch/arm/dts/at91-sam9x60_curiosity.dts
index 99867d2bf8e..cdb782e28ff 100644
--- a/arch/arm/dts/at91-sam9x60_curiosity.dts
+++ b/arch/arm/dts/at91-sam9x60_curiosity.dts
@@ -248,6 +248,11 @@
};
 };
 
+&watchdog {
+   status = "okay";
+   timeout-sec = <16>;
+};
+
 &usb1 {
num-ports = <3>;
atmel,vbus-gpio = <0
-- 
2.49.0



[PATCH 2/7] arm: at91: wdt: Rename regval in priv data to mr

2025-04-04 Thread Zixun LI
Use the name "mr" since we are referring to timer mode register.

Signed-off-by: Zixun LI 
---
 arch/arm/mach-at91/include/mach/at91_wdt.h | 2 +-
 drivers/watchdog/at91sam9_wdt.c| 8 
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-at91/include/mach/at91_wdt.h 
b/arch/arm/mach-at91/include/mach/at91_wdt.h
index 78ad0453fd9..a5accbae521 100644
--- a/arch/arm/mach-at91/include/mach/at91_wdt.h
+++ b/arch/arm/mach-at91/include/mach/at91_wdt.h
@@ -21,7 +21,7 @@
 
 struct at91_wdt_priv {
void __iomem *regs;
-   u32 regval;
+   u32 mr;
 };
 
 #endif
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index c809a8936b8..dab7b6a9b8c 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -60,11 +60,11 @@ static int at91_wdt_start(struct udevice *dev, u64 
timeout_ms, ulong flags)
 * Since WDV is a 12-bit counter, the maximum period is
 * 4096 / 256 = 16 seconds.
 */
-   priv->regval = AT91_WDT_MR_WDRSTEN  /* causes watchdog reset */
+   priv->mr = AT91_WDT_MR_WDRSTEN  /* causes watchdog reset */
| AT91_WDT_MR_WDDBGHLT  /* disabled in debug mode */
| AT91_WDT_MR_WDD(0xfff)/* restart at any time */
| AT91_WDT_MR_WDV(ticks);   /* timer value */
-   writel(priv->regval, priv->regs + AT91_WDT_MR);
+   writel(priv->mr, priv->regs + AT91_WDT_MR);
 
return 0;
 }
@@ -74,8 +74,8 @@ static int at91_wdt_stop(struct udevice *dev)
struct at91_wdt_priv *priv = dev_get_priv(dev);
 
/* Disable Watchdog Timer */
-   priv->regval |= AT91_WDT_MR_WDDIS;
-   writel(priv->regval, priv->regs + AT91_WDT_MR);
+   priv->mr |= AT91_WDT_MR_WDDIS;
+   writel(priv->mr, priv->regs + AT91_WDT_MR);
 
return 0;
 }
-- 
2.49.0



Re: [PATCH 1/7] arm: at91: wdt: Remove unused at91_wdt struct

2025-04-10 Thread Zixun LI
On Thu, Apr 10, 2025 at 12:28 PM Eugen Hristev  wrote:
>
> This breaks sama5d2_xplained_mmc_defconfig for example.
>
> In file included from arch/arm/mach-at91/spl.c:8:
> arch/arm/mach-at91/spl.c: In function ‘at91_disable_wdt’:
> arch/arm/mach-at91/spl.c:19:39: error: invalid use of undefined type
> ‘struct at91_wdt’
>19 | writel(AT91_WDT_MR_WDDIS, &wdt->mr);
>   |   ^~
> ./arch/arm/include/asm/io.h:31:69: note: in definition of macro
> ‘__arch_putl’
>31 | #define __arch_putl(v,a)(*(volatile unsigned int
> *)(a) = (v))
>   |
>^
> arch/arm/mach-at91/spl.c:19:9: note: in expansion of macro ‘writel’
>19 | writel(AT91_WDT_MR_WDDIS, &wdt->mr);
>   | ^~
>

Thank you for the spot. I can add a patch like this:

 #if !defined(CONFIG_WDT_AT91)
 void at91_disable_wdt(void)
 {
-struct at91_wdt *wdt = (struct at91_wdt *)ATMEL_BASE_WDT;
-
-writel(AT91_WDT_MR_WDDIS, &wdt->mr);
+#if defined(CONFIG_SAM9X60)
+writel(AT91_SAM9X60_MR_WDDIS, ATMEL_BASE_WDT + AT91_WDT_MR);
+#else
+writel(AT91_WDT_MR_WDDIS, ATMEL_BASE_WDT + AT91_WDT_MR);
+#endif
 }
 #endif

Zixun


[PATCH 3/7] watchdog: at91sam9_wdt: Rename priv to wdt

2025-03-31 Thread Zixun LI
"wdt" is a better name for watchdog rather than generic "priv".

Signed-off-by: Zixun LI 
---
 drivers/watchdog/at91sam9_wdt.c | 24 
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index dab7b6a9b8c..5ca3e5a5fde 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -38,7 +38,7 @@ DECLARE_GLOBAL_DATA_PTR;
  */
 static int at91_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
 {
-   struct at91_wdt_priv *priv = dev_get_priv(dev);
+   struct at91_wdt_priv *wdt = dev_get_priv(dev);
u64 timeout;
u32 ticks;
 
@@ -49,7 +49,7 @@ static int at91_wdt_start(struct udevice *dev, u64 
timeout_ms, ulong flags)
ticks = WDT_SEC2TICKS(timeout);
 
/* Check if disabled */
-   if (readl(priv->regs + AT91_WDT_MR) & AT91_WDT_MR_WDDIS) {
+   if (readl(wdt->regs + AT91_WDT_MR) & AT91_WDT_MR_WDDIS) {
printf("sorry, watchdog is disabled\n");
return -1;
}
@@ -60,31 +60,31 @@ static int at91_wdt_start(struct udevice *dev, u64 
timeout_ms, ulong flags)
 * Since WDV is a 12-bit counter, the maximum period is
 * 4096 / 256 = 16 seconds.
 */
-   priv->mr = AT91_WDT_MR_WDRSTEN  /* causes watchdog reset */
+   wdt->mr = AT91_WDT_MR_WDRSTEN   /* causes watchdog reset */
| AT91_WDT_MR_WDDBGHLT  /* disabled in debug mode */
| AT91_WDT_MR_WDD(0xfff)/* restart at any time */
| AT91_WDT_MR_WDV(ticks);   /* timer value */
-   writel(priv->mr, priv->regs + AT91_WDT_MR);
+   writel(wdt->mr, wdt->regs + AT91_WDT_MR);
 
return 0;
 }
 
 static int at91_wdt_stop(struct udevice *dev)
 {
-   struct at91_wdt_priv *priv = dev_get_priv(dev);
+   struct at91_wdt_priv *wdt = dev_get_priv(dev);
 
/* Disable Watchdog Timer */
-   priv->mr |= AT91_WDT_MR_WDDIS;
-   writel(priv->mr, priv->regs + AT91_WDT_MR);
+   wdt->mr |= AT91_WDT_MR_WDDIS;
+   writel(wdt->mr, wdt->regs + AT91_WDT_MR);
 
return 0;
 }
 
 static int at91_wdt_reset(struct udevice *dev)
 {
-   struct at91_wdt_priv *priv = dev_get_priv(dev);
+   struct at91_wdt_priv *wdt = dev_get_priv(dev);
 
-   writel(AT91_WDT_CR_WDRSTT | AT91_WDT_CR_KEY, priv->regs + AT91_WDT_CR);
+   writel(AT91_WDT_CR_WDRSTT | AT91_WDT_CR_KEY, wdt->regs + AT91_WDT_CR);
 
return 0;
 }
@@ -102,10 +102,10 @@ static const struct udevice_id at91_wdt_ids[] = {
 
 static int at91_wdt_probe(struct udevice *dev)
 {
-   struct at91_wdt_priv *priv = dev_get_priv(dev);
+   struct at91_wdt_priv *wdt = dev_get_priv(dev);
 
-   priv->regs = dev_remap_addr(dev);
-   if (!priv->regs)
+   wdt->regs = dev_remap_addr(dev);
+   if (!wdt->regs)
return -EINVAL;
 
debug("%s: Probing wdt%u\n", __func__, dev_seq(dev));
-- 
2.49.0



[PATCH 4/7] arm: at91: wdt: Add SAM9X60 register definition

2025-03-31 Thread Zixun LI
SAM9X60 has different watchdog register definition.

Signed-off-by: Zixun LI 
---
 arch/arm/mach-at91/include/mach/at91_wdt.h | 12 ++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-at91/include/mach/at91_wdt.h 
b/arch/arm/mach-at91/include/mach/at91_wdt.h
index a5accbae521..9ba5283123b 100644
--- a/arch/arm/mach-at91/include/mach/at91_wdt.h
+++ b/arch/arm/mach-at91/include/mach/at91_wdt.h
@@ -33,14 +33,22 @@ struct at91_wdt_priv {
 
 /* Watchdog Mode Register*/
 #define AT91_WDT_MR0X04
-#define AT91_WDT_MR_WDV(x) (x & 0xfff)
+#define AT91_WDT_MR_WDV(x) ((x) & 0xfff)
+#define AT91_SAM9X60_MR_PERIODRST  0x0010
 #define AT91_WDT_MR_WDFIEN 0x1000
+#define AT91_SAM9X60_MR_WDDIS  0x1000
 #define AT91_WDT_MR_WDRSTEN0x2000
 #define AT91_WDT_MR_WDRPROC0x4000
 #define AT91_WDT_MR_WDDIS  0x8000
-#define AT91_WDT_MR_WDD(x) ((x & 0xfff) << 16)
+#define AT91_WDT_MR_WDD(x) (((x) & 0xfff) << 16)
 #define AT91_WDT_MR_WDDBGHLT   0x1000
+#define AT91_SAM9X60_MR_WDIDLEHLT  0x1000
 #define AT91_WDT_MR_WDIDLEHLT  0x2000
+#define AT91_SAM9X60_MR_WDDBGHLT   0x2000
+
+/* Watchdog Window Level Register */
+#define AT91_SAM9X60_WLR   0x0c
+#define AT91_SAM9X60_WLR_COUNTER(x)((x) & 0xfff)
 
 /* Hardware timeout in seconds */
 #define WDT_MAX_TIMEOUT16
-- 
2.49.0



[PATCH v2 2/3] ARM: dts: sam9x60: Add USB gadget DT node.

2025-03-31 Thread Zixun LI
Add the USB gadget DT node for the sam9x60 SoC's.

Signed-off-by: Zixun LI 
---
 arch/arm/dts/sam9x60.dtsi | 13 +
 1 file changed, 13 insertions(+)

diff --git a/arch/arm/dts/sam9x60.dtsi b/arch/arm/dts/sam9x60.dtsi
index 3b684fc63d5..ea2647e5fc9 100644
--- a/arch/arm/dts/sam9x60.dtsi
+++ b/arch/arm/dts/sam9x60.dtsi
@@ -69,6 +69,19 @@
#size-cells = <1>;
ranges;
 
+   usb0: gadget@50 {
+   #address-cells = <1>;
+   #size-cells = <0>;
+   compatible = "microchip,sam9x60-udc";
+   reg = <0x50 0x10>,
+   <0xf803c000 0x400>;
+   clocks = <&pmc PMC_TYPE_PERIPHERAL 23>, <&pmc 
PMC_TYPE_CORE 8>;
+   clock-names = "pclk", "hclk";
+   assigned-clocks = <&pmc PMC_TYPE_CORE 8>;
+   assigned-clock-rates = <48000>;
+   status = "disabled";
+   };
+
usb1: usb@60 {
compatible = "atmel,at91rm9200-ohci", "usb-ohci";
reg = <0x0060 0x10>;
-- 
2.49.0



Re: [PATCH 0/4] usb: gadget: f_mass_storage: Fix crashes on low memory devices

2025-03-30 Thread Zixun LI
On Sat, Mar 29, 2025 at 11:04 AM Mattijs Korpershoek
 wrote:
>
> If you are OK with being mentioned in the commit log, could you please
> answer this email thread with the special "Tested-by:" line.
>
> Mattijs

Hi Mattijs,

Yes of course, I searched a bit for tag usage but did end up with the right
document you linked ;)

Tested-by: Zixun LI  # on SAM9X60

Zixun


[PATCH 1/7] arm: at91: wdt: Remove unused at91_wdt struct

2025-03-31 Thread Zixun LI
at91_wdt struct is not used by anyone, let's remove it.

Signed-off-by: Zixun LI 
---
 arch/arm/mach-at91/include/mach/at91_wdt.h | 6 --
 1 file changed, 6 deletions(-)

diff --git a/arch/arm/mach-at91/include/mach/at91_wdt.h 
b/arch/arm/mach-at91/include/mach/at91_wdt.h
index 8ef8e007d77..78ad0453fd9 100644
--- a/arch/arm/mach-at91/include/mach/at91_wdt.h
+++ b/arch/arm/mach-at91/include/mach/at91_wdt.h
@@ -19,12 +19,6 @@
 
 #else
 
-typedef struct at91_wdt {
-   u32 cr;
-   u32 mr;
-   u32 sr;
-} at91_wdt_t;
-
 struct at91_wdt_priv {
void __iomem *regs;
u32 regval;
-- 
2.49.0



[PATCH 5/7] watchdog: at91sam9_wdt: Add SAM9X60 support

2025-03-31 Thread Zixun LI
SAM9X60 has a slightly different watchdog implementation:
- Timer value moved into a new register WLR
- Some MR register fields have their position changed

This patch add SAM9X60 support, also adds a compatible
for SAMA5D4 who is the same as existing SAM9260.

Signed-off-by: Zixun LI 
---
 arch/arm/mach-at91/include/mach/at91_wdt.h |  7 
 drivers/watchdog/at91sam9_wdt.c| 39 +-
 2 files changed, 38 insertions(+), 8 deletions(-)

diff --git a/arch/arm/mach-at91/include/mach/at91_wdt.h 
b/arch/arm/mach-at91/include/mach/at91_wdt.h
index 9ba5283123b..9a3976d9e97 100644
--- a/arch/arm/mach-at91/include/mach/at91_wdt.h
+++ b/arch/arm/mach-at91/include/mach/at91_wdt.h
@@ -19,9 +19,16 @@
 
 #else
 
+enum {
+   AT91_WDT_MODE_SAM9260 = 0,
+   AT91_WDT_MODE_SAM9X60 = 1
+};
+
 struct at91_wdt_priv {
void __iomem *regs;
u32 mr;
+   u32 wddis;
+   u8 mode;
 };
 
 #endif
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index 5ca3e5a5fde..72e13787448 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -49,7 +49,7 @@ static int at91_wdt_start(struct udevice *dev, u64 
timeout_ms, ulong flags)
ticks = WDT_SEC2TICKS(timeout);
 
/* Check if disabled */
-   if (readl(wdt->regs + AT91_WDT_MR) & AT91_WDT_MR_WDDIS) {
+   if (readl(wdt->regs + AT91_WDT_MR) & wdt->wddis) {
printf("sorry, watchdog is disabled\n");
return -1;
}
@@ -60,11 +60,21 @@ static int at91_wdt_start(struct udevice *dev, u64 
timeout_ms, ulong flags)
 * Since WDV is a 12-bit counter, the maximum period is
 * 4096 / 256 = 16 seconds.
 */
-   wdt->mr = AT91_WDT_MR_WDRSTEN   /* causes watchdog reset */
-   | AT91_WDT_MR_WDDBGHLT  /* disabled in debug mode */
-   | AT91_WDT_MR_WDD(0xfff)/* restart at any time */
-   | AT91_WDT_MR_WDV(ticks);   /* timer value */
-   writel(wdt->mr, wdt->regs + AT91_WDT_MR);
+
+   if (wdt->mode == AT91_WDT_MODE_SAM9260) {
+   wdt->mr = AT91_WDT_MR_WDRSTEN   /* causes watchdog reset */
+   | AT91_WDT_MR_WDDBGHLT  /* disabled in debug mode */
+   | AT91_WDT_MR_WDD(0xfff)/* restart at any time */
+   | AT91_WDT_MR_WDV(ticks);   /* timer value */
+   writel(wdt->mr, wdt->regs + AT91_WDT_MR);
+   } else if (wdt->mode == AT91_WDT_MODE_SAM9X60) {
+   writel(AT91_SAM9X60_WLR_COUNTER(ticks), /* timer value */
+  wdt->regs + AT91_SAM9X60_WLR);
+
+   wdt->mr = AT91_SAM9X60_MR_PERIODRST /* causes watchdog reset */
+   | AT91_SAM9X60_MR_WDDBGHLT; /* disabled in debug mode */
+   writel(wdt->mr, wdt->regs + AT91_WDT_MR);
+   }
 
return 0;
 }
@@ -74,7 +84,7 @@ static int at91_wdt_stop(struct udevice *dev)
struct at91_wdt_priv *wdt = dev_get_priv(dev);
 
/* Disable Watchdog Timer */
-   wdt->mr |= AT91_WDT_MR_WDDIS;
+   wdt->mr |= wdt->wddis;
writel(wdt->mr, wdt->regs + AT91_WDT_MR);
 
return 0;
@@ -96,7 +106,14 @@ static const struct wdt_ops at91_wdt_ops = {
 };
 
 static const struct udevice_id at91_wdt_ids[] = {
-   { .compatible = "atmel,at91sam9260-wdt" },
+   { .compatible = "atmel,at91sam9260-wdt",
+ .data = AT91_WDT_MODE_SAM9260 },
+   { .compatible = "atmel,sama5d4-wdt",
+ .data = AT91_WDT_MODE_SAM9260 },
+   { .compatible = "microchip,sam9x60-wdt",
+ .data = AT91_WDT_MODE_SAM9X60 },
+   { .compatible = "microchip,sama7g5-wdt",
+ .data = AT91_WDT_MODE_SAM9X60 },
{}
 };
 
@@ -108,6 +125,12 @@ static int at91_wdt_probe(struct udevice *dev)
if (!wdt->regs)
return -EINVAL;
 
+   wdt->mode = dev_get_driver_data(dev);
+   if (wdt->mode == AT91_WDT_MODE_SAM9260)
+   wdt->wddis = AT91_WDT_MR_WDDIS;
+   else if (wdt->mode == AT91_WDT_MODE_SAM9X60)
+   wdt->wddis = AT91_SAM9X60_MR_WDDIS;
+
debug("%s: Probing wdt%u\n", __func__, dev_seq(dev));
 
return 0;
-- 
2.49.0



[PATCH v2 7/8] ARM: dts: sam9x60: Add watchdog DT node.

2025-04-17 Thread Zixun LI
Add the watchdog timer node for the sam9x60 SoC's.

Signed-off-by: Zixun LI 
---
 arch/arm/dts/sam9x60.dtsi | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm/dts/sam9x60.dtsi b/arch/arm/dts/sam9x60.dtsi
index 
60de9140226981003c06747e103966b696b7b700..6a5465cf31d5ab48e1205896884f41d2203b5812
 100644
--- a/arch/arm/dts/sam9x60.dtsi
+++ b/arch/arm/dts/sam9x60.dtsi
@@ -298,6 +298,13 @@
clocks = <&slow_rc_osc>, <&slow_xtal>;
#clock-cells = <1>;
};
+
+   watchdog: watchdog@ff80 {
+   compatible = "microchip,sam9x60-wdt";
+   reg = <0xff80 0x24>;
+   clocks = <&clk32 0>;
+   status = "disabled";
+   };
};
};
 

-- 
2.49.0



[PATCH v2 4/8] watchdog: at91sam9_wdt: Rename priv to wdt

2025-04-17 Thread Zixun LI
"wdt" is a better name for watchdog rather than generic "priv".

Signed-off-by: Zixun LI 
---
 drivers/watchdog/at91sam9_wdt.c | 24 
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index 
dab7b6a9b8ca09e6113109391560434ffe1f7cb6..5ca3e5a5fdefb3101c97754f10b65c0acd69a522
 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -38,7 +38,7 @@ DECLARE_GLOBAL_DATA_PTR;
  */
 static int at91_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
 {
-   struct at91_wdt_priv *priv = dev_get_priv(dev);
+   struct at91_wdt_priv *wdt = dev_get_priv(dev);
u64 timeout;
u32 ticks;
 
@@ -49,7 +49,7 @@ static int at91_wdt_start(struct udevice *dev, u64 
timeout_ms, ulong flags)
ticks = WDT_SEC2TICKS(timeout);
 
/* Check if disabled */
-   if (readl(priv->regs + AT91_WDT_MR) & AT91_WDT_MR_WDDIS) {
+   if (readl(wdt->regs + AT91_WDT_MR) & AT91_WDT_MR_WDDIS) {
printf("sorry, watchdog is disabled\n");
return -1;
}
@@ -60,31 +60,31 @@ static int at91_wdt_start(struct udevice *dev, u64 
timeout_ms, ulong flags)
 * Since WDV is a 12-bit counter, the maximum period is
 * 4096 / 256 = 16 seconds.
 */
-   priv->mr = AT91_WDT_MR_WDRSTEN  /* causes watchdog reset */
+   wdt->mr = AT91_WDT_MR_WDRSTEN   /* causes watchdog reset */
| AT91_WDT_MR_WDDBGHLT  /* disabled in debug mode */
| AT91_WDT_MR_WDD(0xfff)/* restart at any time */
| AT91_WDT_MR_WDV(ticks);   /* timer value */
-   writel(priv->mr, priv->regs + AT91_WDT_MR);
+   writel(wdt->mr, wdt->regs + AT91_WDT_MR);
 
return 0;
 }
 
 static int at91_wdt_stop(struct udevice *dev)
 {
-   struct at91_wdt_priv *priv = dev_get_priv(dev);
+   struct at91_wdt_priv *wdt = dev_get_priv(dev);
 
/* Disable Watchdog Timer */
-   priv->mr |= AT91_WDT_MR_WDDIS;
-   writel(priv->mr, priv->regs + AT91_WDT_MR);
+   wdt->mr |= AT91_WDT_MR_WDDIS;
+   writel(wdt->mr, wdt->regs + AT91_WDT_MR);
 
return 0;
 }
 
 static int at91_wdt_reset(struct udevice *dev)
 {
-   struct at91_wdt_priv *priv = dev_get_priv(dev);
+   struct at91_wdt_priv *wdt = dev_get_priv(dev);
 
-   writel(AT91_WDT_CR_WDRSTT | AT91_WDT_CR_KEY, priv->regs + AT91_WDT_CR);
+   writel(AT91_WDT_CR_WDRSTT | AT91_WDT_CR_KEY, wdt->regs + AT91_WDT_CR);
 
return 0;
 }
@@ -102,10 +102,10 @@ static const struct udevice_id at91_wdt_ids[] = {
 
 static int at91_wdt_probe(struct udevice *dev)
 {
-   struct at91_wdt_priv *priv = dev_get_priv(dev);
+   struct at91_wdt_priv *wdt = dev_get_priv(dev);
 
-   priv->regs = dev_remap_addr(dev);
-   if (!priv->regs)
+   wdt->regs = dev_remap_addr(dev);
+   if (!wdt->regs)
return -EINVAL;
 
debug("%s: Probing wdt%u\n", __func__, dev_seq(dev));

-- 
2.49.0



[PATCH v2 1/8] arm: at91: remove at91_wdt struct in spl

2025-04-18 Thread Zixun LI
at91_wdt struct is only used by spl, remove this reference to
allow at91_wdt_t removal.

Signed-off-by: Zixun LI 
---
 arch/arm/mach-at91/spl.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/arch/arm/mach-at91/spl.c b/arch/arm/mach-at91/spl.c
index 
5feb8f735511a45dd37ee04bb3742f57d8f2e067..a814973242a723c47af210bd76db9210db061063
 100644
--- a/arch/arm/mach-at91/spl.c
+++ b/arch/arm/mach-at91/spl.c
@@ -14,9 +14,7 @@
 #if !defined(CONFIG_WDT_AT91)
 void at91_disable_wdt(void)
 {
-   struct at91_wdt *wdt = (struct at91_wdt *)ATMEL_BASE_WDT;
-
-   writel(AT91_WDT_MR_WDDIS, &wdt->mr);
+   writel(AT91_WDT_MR_WDDIS, ATMEL_BASE_WDT + AT91_WDT_MR);
 }
 #endif
 

-- 
2.49.0



[PATCH v3 0/6] watchdog: at91sam9_wdt driver enhancement

2025-04-28 Thread Zixun LI
This patch series includes some code refactor and adds new device support
for at91sam9_wdt driver.

Instead of add a new driver like Linux kernel, at91sam9_wdt driver is
extended as new watchdog variant is similar to existing one, especially
for the function subset used by u-boot.

1. Remove typedef struct and rename variables for readability.

2. Add SAMA5D4 compatible, it has the same watchdog as SAM9260 except a
new lockout feature is added. Currently this feature is unimplemented.

3. SAM9X60, SAM9X7 and SAMA7 series have a new watchdog variant, some
bitfields bof MR register shifted their position, a new register is added
for timer value.

4. Add DT node to SAM9X60-Currently board

It has been tested on SAM9X60-Currently board:
- Start & stop
- Set timeout from DT node
- Reset kick in with a while(1) loop

Changes in v3:
- Merge relevant commits into one
- Match DT node with Linux
- Move default timeout from board dts to sam9x60.dtsi

Changes in v2:
- Fix SPL build

Zixun LI (7):
  arm: at91: wdt: Remove unused at91_wdt struct
  arm: at91: wdt: Rename regval in priv data to mr
  watchdog: at91sam9_wdt: Rename priv to wdt
  arm: at91: wdt: Add SAM9X60 register definition
  watchdog: at91sam9_wdt: Add SAM9X60 support
  ARM: dts: sam9x60: Add watchdog DT node.
  ARM: dts: at91: sam9x60-curiosity: Enable watchdog node

 arch/arm/dts/at91-sam9x60_curiosity.dts|  5 ++
 arch/arm/dts/sam9x60.dtsi  |  7 +++
 arch/arm/mach-at91/include/mach/at91_wdt.h | 25 ++
 drivers/watchdog/at91sam9_wdt.c| 55 +++---
 4 files changed, 68 insertions(+), 24 deletions(-)

--
2.49.0

---
Zixun LI (6):
  arm: at91: wdt: Remove at91_wdt struct
  arm: at91: wdt: Rename regval in priv data to mr
  watchdog: at91sam9_wdt: Rename priv to wdt
  watchdog: at91sam9_wdt: Add SAM9X60 support
  ARM: dts: sam9x60: Add watchdog DT node
  ARM: dts: at91: sam9x60-curiosity: Enable watchdog node

 arch/arm/dts/at91-sam9x60_curiosity.dts|  4 +++
 arch/arm/dts/sam9x60.dtsi  |  9 +
 arch/arm/mach-at91/include/mach/at91_wdt.h | 25 +-
 arch/arm/mach-at91/spl.c   |  4 +--
 drivers/watchdog/at91sam9_wdt.c| 55 +-
 5 files changed, 70 insertions(+), 27 deletions(-)
---
base-commit: 10f48365112b164bee6564033ab682747efcb483
change-id: 20250417-wdt-da6560c1b258

Best regards,
-- 
Zixun LI 



[PATCH v3 3/6] watchdog: at91sam9_wdt: Rename priv to wdt

2025-04-28 Thread Zixun LI
"wdt" is a better name for watchdog rather than generic "priv".

Signed-off-by: Zixun LI 
---
 drivers/watchdog/at91sam9_wdt.c | 24 
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index 
dab7b6a9b8ca09e6113109391560434ffe1f7cb6..5ca3e5a5fdefb3101c97754f10b65c0acd69a522
 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -38,7 +38,7 @@ DECLARE_GLOBAL_DATA_PTR;
  */
 static int at91_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
 {
-   struct at91_wdt_priv *priv = dev_get_priv(dev);
+   struct at91_wdt_priv *wdt = dev_get_priv(dev);
u64 timeout;
u32 ticks;
 
@@ -49,7 +49,7 @@ static int at91_wdt_start(struct udevice *dev, u64 
timeout_ms, ulong flags)
ticks = WDT_SEC2TICKS(timeout);
 
/* Check if disabled */
-   if (readl(priv->regs + AT91_WDT_MR) & AT91_WDT_MR_WDDIS) {
+   if (readl(wdt->regs + AT91_WDT_MR) & AT91_WDT_MR_WDDIS) {
printf("sorry, watchdog is disabled\n");
return -1;
}
@@ -60,31 +60,31 @@ static int at91_wdt_start(struct udevice *dev, u64 
timeout_ms, ulong flags)
 * Since WDV is a 12-bit counter, the maximum period is
 * 4096 / 256 = 16 seconds.
 */
-   priv->mr = AT91_WDT_MR_WDRSTEN  /* causes watchdog reset */
+   wdt->mr = AT91_WDT_MR_WDRSTEN   /* causes watchdog reset */
| AT91_WDT_MR_WDDBGHLT  /* disabled in debug mode */
| AT91_WDT_MR_WDD(0xfff)/* restart at any time */
| AT91_WDT_MR_WDV(ticks);   /* timer value */
-   writel(priv->mr, priv->regs + AT91_WDT_MR);
+   writel(wdt->mr, wdt->regs + AT91_WDT_MR);
 
return 0;
 }
 
 static int at91_wdt_stop(struct udevice *dev)
 {
-   struct at91_wdt_priv *priv = dev_get_priv(dev);
+   struct at91_wdt_priv *wdt = dev_get_priv(dev);
 
/* Disable Watchdog Timer */
-   priv->mr |= AT91_WDT_MR_WDDIS;
-   writel(priv->mr, priv->regs + AT91_WDT_MR);
+   wdt->mr |= AT91_WDT_MR_WDDIS;
+   writel(wdt->mr, wdt->regs + AT91_WDT_MR);
 
return 0;
 }
 
 static int at91_wdt_reset(struct udevice *dev)
 {
-   struct at91_wdt_priv *priv = dev_get_priv(dev);
+   struct at91_wdt_priv *wdt = dev_get_priv(dev);
 
-   writel(AT91_WDT_CR_WDRSTT | AT91_WDT_CR_KEY, priv->regs + AT91_WDT_CR);
+   writel(AT91_WDT_CR_WDRSTT | AT91_WDT_CR_KEY, wdt->regs + AT91_WDT_CR);
 
return 0;
 }
@@ -102,10 +102,10 @@ static const struct udevice_id at91_wdt_ids[] = {
 
 static int at91_wdt_probe(struct udevice *dev)
 {
-   struct at91_wdt_priv *priv = dev_get_priv(dev);
+   struct at91_wdt_priv *wdt = dev_get_priv(dev);
 
-   priv->regs = dev_remap_addr(dev);
-   if (!priv->regs)
+   wdt->regs = dev_remap_addr(dev);
+   if (!wdt->regs)
return -EINVAL;
 
debug("%s: Probing wdt%u\n", __func__, dev_seq(dev));

-- 
2.49.0



[PATCH v3 1/6] arm: at91: wdt: Remove at91_wdt struct

2025-04-28 Thread Zixun LI
at91_wdt struct is only used by spl, remove this reference and the struct
itself.

Signed-off-by: Zixun LI 
---
 arch/arm/mach-at91/include/mach/at91_wdt.h | 6 --
 arch/arm/mach-at91/spl.c   | 4 +---
 2 files changed, 1 insertion(+), 9 deletions(-)

diff --git a/arch/arm/mach-at91/include/mach/at91_wdt.h 
b/arch/arm/mach-at91/include/mach/at91_wdt.h
index 
8ef8e007d7767308a5b46be46b02c51073723a41..78ad0453fd9eb3e42674d10cb11ce3da820cdc6a
 100644
--- a/arch/arm/mach-at91/include/mach/at91_wdt.h
+++ b/arch/arm/mach-at91/include/mach/at91_wdt.h
@@ -19,12 +19,6 @@
 
 #else
 
-typedef struct at91_wdt {
-   u32 cr;
-   u32 mr;
-   u32 sr;
-} at91_wdt_t;
-
 struct at91_wdt_priv {
void __iomem *regs;
u32 regval;
diff --git a/arch/arm/mach-at91/spl.c b/arch/arm/mach-at91/spl.c
index 
5feb8f735511a45dd37ee04bb3742f57d8f2e067..a814973242a723c47af210bd76db9210db061063
 100644
--- a/arch/arm/mach-at91/spl.c
+++ b/arch/arm/mach-at91/spl.c
@@ -14,9 +14,7 @@
 #if !defined(CONFIG_WDT_AT91)
 void at91_disable_wdt(void)
 {
-   struct at91_wdt *wdt = (struct at91_wdt *)ATMEL_BASE_WDT;
-
-   writel(AT91_WDT_MR_WDDIS, &wdt->mr);
+   writel(AT91_WDT_MR_WDDIS, ATMEL_BASE_WDT + AT91_WDT_MR);
 }
 #endif
 

-- 
2.49.0



[PATCH v4 2/6] arm: at91: wdt: Rename regval in priv data to mr

2025-04-28 Thread Zixun LI
Use the name "mr" since we are referring to timer mode register.

Signed-off-by: Zixun LI 
---
 arch/arm/mach-at91/include/mach/at91_wdt.h | 2 +-
 drivers/watchdog/at91sam9_wdt.c| 8 
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-at91/include/mach/at91_wdt.h 
b/arch/arm/mach-at91/include/mach/at91_wdt.h
index 
78ad0453fd9eb3e42674d10cb11ce3da820cdc6a..a5accbae52186e99de0b113d6982a4cc54e36095
 100644
--- a/arch/arm/mach-at91/include/mach/at91_wdt.h
+++ b/arch/arm/mach-at91/include/mach/at91_wdt.h
@@ -21,7 +21,7 @@
 
 struct at91_wdt_priv {
void __iomem *regs;
-   u32 regval;
+   u32 mr;
 };
 
 #endif
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index 
c809a8936b8968c3322db4c86bc0571fbdfe3ae2..dab7b6a9b8ca09e6113109391560434ffe1f7cb6
 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -60,11 +60,11 @@ static int at91_wdt_start(struct udevice *dev, u64 
timeout_ms, ulong flags)
 * Since WDV is a 12-bit counter, the maximum period is
 * 4096 / 256 = 16 seconds.
 */
-   priv->regval = AT91_WDT_MR_WDRSTEN  /* causes watchdog reset */
+   priv->mr = AT91_WDT_MR_WDRSTEN  /* causes watchdog reset */
| AT91_WDT_MR_WDDBGHLT  /* disabled in debug mode */
| AT91_WDT_MR_WDD(0xfff)/* restart at any time */
| AT91_WDT_MR_WDV(ticks);   /* timer value */
-   writel(priv->regval, priv->regs + AT91_WDT_MR);
+   writel(priv->mr, priv->regs + AT91_WDT_MR);
 
return 0;
 }
@@ -74,8 +74,8 @@ static int at91_wdt_stop(struct udevice *dev)
struct at91_wdt_priv *priv = dev_get_priv(dev);
 
/* Disable Watchdog Timer */
-   priv->regval |= AT91_WDT_MR_WDDIS;
-   writel(priv->regval, priv->regs + AT91_WDT_MR);
+   priv->mr |= AT91_WDT_MR_WDDIS;
+   writel(priv->mr, priv->regs + AT91_WDT_MR);
 
return 0;
 }

-- 
2.49.0



[PATCH v3 4/6] watchdog: at91sam9_wdt: Add SAM9X60 support

2025-04-28 Thread Zixun LI
SAM9X60 has a slightly different watchdog implementation:
- Timer value moved into a new register WLR
- Some MR register fields have their position changed

This patch add SAM9X60 support, also adds a compatible
for SAMA5D4 which is the same as existing SAM9260.

Signed-off-by: Zixun LI 
---
 arch/arm/mach-at91/include/mach/at91_wdt.h | 19 +--
 drivers/watchdog/at91sam9_wdt.c| 39 --
 2 files changed, 48 insertions(+), 10 deletions(-)

diff --git a/arch/arm/mach-at91/include/mach/at91_wdt.h 
b/arch/arm/mach-at91/include/mach/at91_wdt.h
index 
a5accbae52186e99de0b113d6982a4cc54e36095..9a3976d9e970c212d348daeabc14c2fd6c54a8b5
 100644
--- a/arch/arm/mach-at91/include/mach/at91_wdt.h
+++ b/arch/arm/mach-at91/include/mach/at91_wdt.h
@@ -19,9 +19,16 @@
 
 #else
 
+enum {
+   AT91_WDT_MODE_SAM9260 = 0,
+   AT91_WDT_MODE_SAM9X60 = 1
+};
+
 struct at91_wdt_priv {
void __iomem *regs;
u32 mr;
+   u32 wddis;
+   u8 mode;
 };
 
 #endif
@@ -33,14 +40,22 @@ struct at91_wdt_priv {
 
 /* Watchdog Mode Register*/
 #define AT91_WDT_MR0X04
-#define AT91_WDT_MR_WDV(x) (x & 0xfff)
+#define AT91_WDT_MR_WDV(x) ((x) & 0xfff)
+#define AT91_SAM9X60_MR_PERIODRST  0x0010
 #define AT91_WDT_MR_WDFIEN 0x1000
+#define AT91_SAM9X60_MR_WDDIS  0x1000
 #define AT91_WDT_MR_WDRSTEN0x2000
 #define AT91_WDT_MR_WDRPROC0x4000
 #define AT91_WDT_MR_WDDIS  0x8000
-#define AT91_WDT_MR_WDD(x) ((x & 0xfff) << 16)
+#define AT91_WDT_MR_WDD(x) (((x) & 0xfff) << 16)
 #define AT91_WDT_MR_WDDBGHLT   0x1000
+#define AT91_SAM9X60_MR_WDIDLEHLT  0x1000
 #define AT91_WDT_MR_WDIDLEHLT  0x2000
+#define AT91_SAM9X60_MR_WDDBGHLT   0x2000
+
+/* Watchdog Window Level Register */
+#define AT91_SAM9X60_WLR   0x0c
+#define AT91_SAM9X60_WLR_COUNTER(x)((x) & 0xfff)
 
 /* Hardware timeout in seconds */
 #define WDT_MAX_TIMEOUT16
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index 
5ca3e5a5fdefb3101c97754f10b65c0acd69a522..72e13787448e366036dce4a451cc2294e5b60a0d
 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -49,7 +49,7 @@ static int at91_wdt_start(struct udevice *dev, u64 
timeout_ms, ulong flags)
ticks = WDT_SEC2TICKS(timeout);
 
/* Check if disabled */
-   if (readl(wdt->regs + AT91_WDT_MR) & AT91_WDT_MR_WDDIS) {
+   if (readl(wdt->regs + AT91_WDT_MR) & wdt->wddis) {
printf("sorry, watchdog is disabled\n");
return -1;
}
@@ -60,11 +60,21 @@ static int at91_wdt_start(struct udevice *dev, u64 
timeout_ms, ulong flags)
 * Since WDV is a 12-bit counter, the maximum period is
 * 4096 / 256 = 16 seconds.
 */
-   wdt->mr = AT91_WDT_MR_WDRSTEN   /* causes watchdog reset */
-   | AT91_WDT_MR_WDDBGHLT  /* disabled in debug mode */
-   | AT91_WDT_MR_WDD(0xfff)/* restart at any time */
-   | AT91_WDT_MR_WDV(ticks);   /* timer value */
-   writel(wdt->mr, wdt->regs + AT91_WDT_MR);
+
+   if (wdt->mode == AT91_WDT_MODE_SAM9260) {
+   wdt->mr = AT91_WDT_MR_WDRSTEN   /* causes watchdog reset */
+   | AT91_WDT_MR_WDDBGHLT  /* disabled in debug mode */
+   | AT91_WDT_MR_WDD(0xfff)/* restart at any time */
+   | AT91_WDT_MR_WDV(ticks);   /* timer value */
+   writel(wdt->mr, wdt->regs + AT91_WDT_MR);
+   } else if (wdt->mode == AT91_WDT_MODE_SAM9X60) {
+   writel(AT91_SAM9X60_WLR_COUNTER(ticks), /* timer value */
+  wdt->regs + AT91_SAM9X60_WLR);
+
+   wdt->mr = AT91_SAM9X60_MR_PERIODRST /* causes watchdog reset */
+   | AT91_SAM9X60_MR_WDDBGHLT; /* disabled in debug mode */
+   writel(wdt->mr, wdt->regs + AT91_WDT_MR);
+   }
 
return 0;
 }
@@ -74,7 +84,7 @@ static int at91_wdt_stop(struct udevice *dev)
struct at91_wdt_priv *wdt = dev_get_priv(dev);
 
/* Disable Watchdog Timer */
-   wdt->mr |= AT91_WDT_MR_WDDIS;
+   wdt->mr |= wdt->wddis;
writel(wdt->mr, wdt->regs + AT91_WDT_MR);
 
return 0;
@@ -96,7 +106,14 @@ static const struct wdt_ops at91_wdt_ops = {
 };
 
 static const struct udevice_id at91_wdt_ids[] = {
-   { .compatible = "atmel,at91sam9260-wdt" },
+   { .compatible = "atmel,at91sam9260-wdt",
+ .data = AT91_WDT_MODE_SAM9260 },
+   { .compatible = "atmel,sama5d4-wdt",
+ .data = AT91_WDT_MODE_SAM9260 },
+   { .compatible = "microchip,sam9x60-wdt",
+ .data = A

[PATCH v4 0/6] watchdog: at91sam9_wdt driver enhancement

2025-04-28 Thread Zixun LI
This patch series includes some code refactor and adds new device support
for at91sam9_wdt driver.

Instead of add a new driver like Linux kernel, at91sam9_wdt driver is
extended as new watchdog variant is similar to existing one, especially
for the function subset used by u-boot.

1. Remove typedef struct and rename variables for readability.

2. Add SAMA5D4 compatible, it has the same watchdog as SAM9260 except a
new lockout feature is added. Currently this feature is unimplemented.

3. SAM9X60, SAM9X7 and SAMA7 series have a new watchdog variant, some
bitfields bof MR register shifted their position, a new register is added
for timer value.

4. Add DT node to SAM9X60-Currently board

It has been tested on SAM9X60-Currently board:
- Start & stop
- Set timeout from DT node
- Reset kick in with a while(1) loop

Changes in v4:
- Move 'timeout-sec' to at91-sam9x60-curiosity-u-boot.dtsi

Changes in v3:
- Merge relevant commits into one
- Match DT node with Linux
- Move default timeout from board dts to sam9x60.dtsi

Changes in v2:
- Fix SPL build

Zixun LI (7):
  arm: at91: wdt: Remove unused at91_wdt struct
  arm: at91: wdt: Rename regval in priv data to mr
  watchdog: at91sam9_wdt: Rename priv to wdt
  arm: at91: wdt: Add SAM9X60 register definition
  watchdog: at91sam9_wdt: Add SAM9X60 support
  ARM: dts: sam9x60: Add watchdog DT node.
  ARM: dts: at91: sam9x60-curiosity: Enable watchdog node

 arch/arm/dts/at91-sam9x60_curiosity.dts|  5 ++
 arch/arm/dts/sam9x60.dtsi  |  7 +++
 arch/arm/mach-at91/include/mach/at91_wdt.h | 25 ++
 drivers/watchdog/at91sam9_wdt.c| 55 +++---
 4 files changed, 68 insertions(+), 24 deletions(-)

--
2.49.0

---
Zixun LI (6):
  arm: at91: wdt: Remove at91_wdt struct
  arm: at91: wdt: Rename regval in priv data to mr
  watchdog: at91sam9_wdt: Rename priv to wdt
  watchdog: at91sam9_wdt: Add SAM9X60 support
  ARM: dts: sam9x60: Add watchdog DT node
  ARM: dts: at91: sam9x60-curiosity: Enable watchdog node

 arch/arm/dts/at91-sam9x60_curiosity-u-boot.dtsi |  4 ++
 arch/arm/dts/at91-sam9x60_curiosity.dts |  4 ++
 arch/arm/dts/sam9x60.dtsi   |  8 
 arch/arm/mach-at91/include/mach/at91_wdt.h  | 25 +++
 arch/arm/mach-at91/spl.c|  4 +-
 drivers/watchdog/at91sam9_wdt.c | 55 ++---
 6 files changed, 73 insertions(+), 27 deletions(-)
---
base-commit: 10f48365112b164bee6564033ab682747efcb483
change-id: 20250417-wdt-da6560c1b258

Best regards,
-- 
Zixun LI 



[PATCH v4 1/6] arm: at91: wdt: Remove at91_wdt struct

2025-04-28 Thread Zixun LI
at91_wdt struct is only used by spl, remove this reference and the struct
itself.

Signed-off-by: Zixun LI 
---
 arch/arm/mach-at91/include/mach/at91_wdt.h | 6 --
 arch/arm/mach-at91/spl.c   | 4 +---
 2 files changed, 1 insertion(+), 9 deletions(-)

diff --git a/arch/arm/mach-at91/include/mach/at91_wdt.h 
b/arch/arm/mach-at91/include/mach/at91_wdt.h
index 
8ef8e007d7767308a5b46be46b02c51073723a41..78ad0453fd9eb3e42674d10cb11ce3da820cdc6a
 100644
--- a/arch/arm/mach-at91/include/mach/at91_wdt.h
+++ b/arch/arm/mach-at91/include/mach/at91_wdt.h
@@ -19,12 +19,6 @@
 
 #else
 
-typedef struct at91_wdt {
-   u32 cr;
-   u32 mr;
-   u32 sr;
-} at91_wdt_t;
-
 struct at91_wdt_priv {
void __iomem *regs;
u32 regval;
diff --git a/arch/arm/mach-at91/spl.c b/arch/arm/mach-at91/spl.c
index 
5feb8f735511a45dd37ee04bb3742f57d8f2e067..a814973242a723c47af210bd76db9210db061063
 100644
--- a/arch/arm/mach-at91/spl.c
+++ b/arch/arm/mach-at91/spl.c
@@ -14,9 +14,7 @@
 #if !defined(CONFIG_WDT_AT91)
 void at91_disable_wdt(void)
 {
-   struct at91_wdt *wdt = (struct at91_wdt *)ATMEL_BASE_WDT;
-
-   writel(AT91_WDT_MR_WDDIS, &wdt->mr);
+   writel(AT91_WDT_MR_WDDIS, ATMEL_BASE_WDT + AT91_WDT_MR);
 }
 #endif
 

-- 
2.49.0



[PATCH v3 5/6] ARM: dts: sam9x60: Add watchdog DT node

2025-04-28 Thread Zixun LI
Add the watchdog timer node for the sam9x60 SoC's.

A default timeout of 16s is added which is the maximum supported value,
also matching Linux driver's behavior.

Signed-off-by: Zixun LI 
---
 arch/arm/dts/sam9x60.dtsi | 9 +
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/dts/sam9x60.dtsi b/arch/arm/dts/sam9x60.dtsi
index 
7631dfaa07fc1e7c605c70840da1196c1daeb638..588d2cb9f5109396b11a11e497eac282dffb4fb0
 100644
--- a/arch/arm/dts/sam9x60.dtsi
+++ b/arch/arm/dts/sam9x60.dtsi
@@ -311,6 +311,15 @@
clocks = <&slow_rc_osc>, <&slow_xtal>;
#clock-cells = <1>;
};
+
+   watchdog: watchdog@ff80 {
+   compatible = "microchip,sam9x60-wdt";
+   reg = <0xff80 0x24>;
+   interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+   clocks = <&clk32 0>;
+   timeout-sec = <16>;
+   status = "disabled";
+   };
};
};
 

-- 
2.49.0



[PATCH v3 2/6] arm: at91: wdt: Rename regval in priv data to mr

2025-04-28 Thread Zixun LI
Use the name "mr" since we are referring to timer mode register.

Signed-off-by: Zixun LI 
---
 arch/arm/mach-at91/include/mach/at91_wdt.h | 2 +-
 drivers/watchdog/at91sam9_wdt.c| 8 
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-at91/include/mach/at91_wdt.h 
b/arch/arm/mach-at91/include/mach/at91_wdt.h
index 
78ad0453fd9eb3e42674d10cb11ce3da820cdc6a..a5accbae52186e99de0b113d6982a4cc54e36095
 100644
--- a/arch/arm/mach-at91/include/mach/at91_wdt.h
+++ b/arch/arm/mach-at91/include/mach/at91_wdt.h
@@ -21,7 +21,7 @@
 
 struct at91_wdt_priv {
void __iomem *regs;
-   u32 regval;
+   u32 mr;
 };
 
 #endif
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index 
c809a8936b8968c3322db4c86bc0571fbdfe3ae2..dab7b6a9b8ca09e6113109391560434ffe1f7cb6
 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -60,11 +60,11 @@ static int at91_wdt_start(struct udevice *dev, u64 
timeout_ms, ulong flags)
 * Since WDV is a 12-bit counter, the maximum period is
 * 4096 / 256 = 16 seconds.
 */
-   priv->regval = AT91_WDT_MR_WDRSTEN  /* causes watchdog reset */
+   priv->mr = AT91_WDT_MR_WDRSTEN  /* causes watchdog reset */
| AT91_WDT_MR_WDDBGHLT  /* disabled in debug mode */
| AT91_WDT_MR_WDD(0xfff)/* restart at any time */
| AT91_WDT_MR_WDV(ticks);   /* timer value */
-   writel(priv->regval, priv->regs + AT91_WDT_MR);
+   writel(priv->mr, priv->regs + AT91_WDT_MR);
 
return 0;
 }
@@ -74,8 +74,8 @@ static int at91_wdt_stop(struct udevice *dev)
struct at91_wdt_priv *priv = dev_get_priv(dev);
 
/* Disable Watchdog Timer */
-   priv->regval |= AT91_WDT_MR_WDDIS;
-   writel(priv->regval, priv->regs + AT91_WDT_MR);
+   priv->mr |= AT91_WDT_MR_WDDIS;
+   writel(priv->mr, priv->regs + AT91_WDT_MR);
 
return 0;
 }

-- 
2.49.0



[PATCH v3 6/6] ARM: dts: at91: sam9x60-curiosity: Enable watchdog node

2025-04-28 Thread Zixun LI
Enable watchdog node on SAM9X60-Curiosity board.

Signed-off-by: Zixun LI 
---
 arch/arm/dts/at91-sam9x60_curiosity.dts | 4 
 1 file changed, 4 insertions(+)

diff --git a/arch/arm/dts/at91-sam9x60_curiosity.dts 
b/arch/arm/dts/at91-sam9x60_curiosity.dts
index 
1c7f0fa6a49004943e5a4ac6637db5e806cc92f3..f165fdadb9e4abd08f9166e7cbec0507616c9939
 100644
--- a/arch/arm/dts/at91-sam9x60_curiosity.dts
+++ b/arch/arm/dts/at91-sam9x60_curiosity.dts
@@ -336,3 +336,7 @@
 &usb2 {
status = "okay";
 };
+
+&watchdog {
+   status = "okay";
+};

-- 
2.49.0



[PATCH v4 3/6] watchdog: at91sam9_wdt: Rename priv to wdt

2025-04-28 Thread Zixun LI
"wdt" is a better name for watchdog rather than generic "priv".

Signed-off-by: Zixun LI 
---
 drivers/watchdog/at91sam9_wdt.c | 24 
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index 
dab7b6a9b8ca09e6113109391560434ffe1f7cb6..5ca3e5a5fdefb3101c97754f10b65c0acd69a522
 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -38,7 +38,7 @@ DECLARE_GLOBAL_DATA_PTR;
  */
 static int at91_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
 {
-   struct at91_wdt_priv *priv = dev_get_priv(dev);
+   struct at91_wdt_priv *wdt = dev_get_priv(dev);
u64 timeout;
u32 ticks;
 
@@ -49,7 +49,7 @@ static int at91_wdt_start(struct udevice *dev, u64 
timeout_ms, ulong flags)
ticks = WDT_SEC2TICKS(timeout);
 
/* Check if disabled */
-   if (readl(priv->regs + AT91_WDT_MR) & AT91_WDT_MR_WDDIS) {
+   if (readl(wdt->regs + AT91_WDT_MR) & AT91_WDT_MR_WDDIS) {
printf("sorry, watchdog is disabled\n");
return -1;
}
@@ -60,31 +60,31 @@ static int at91_wdt_start(struct udevice *dev, u64 
timeout_ms, ulong flags)
 * Since WDV is a 12-bit counter, the maximum period is
 * 4096 / 256 = 16 seconds.
 */
-   priv->mr = AT91_WDT_MR_WDRSTEN  /* causes watchdog reset */
+   wdt->mr = AT91_WDT_MR_WDRSTEN   /* causes watchdog reset */
| AT91_WDT_MR_WDDBGHLT  /* disabled in debug mode */
| AT91_WDT_MR_WDD(0xfff)/* restart at any time */
| AT91_WDT_MR_WDV(ticks);   /* timer value */
-   writel(priv->mr, priv->regs + AT91_WDT_MR);
+   writel(wdt->mr, wdt->regs + AT91_WDT_MR);
 
return 0;
 }
 
 static int at91_wdt_stop(struct udevice *dev)
 {
-   struct at91_wdt_priv *priv = dev_get_priv(dev);
+   struct at91_wdt_priv *wdt = dev_get_priv(dev);
 
/* Disable Watchdog Timer */
-   priv->mr |= AT91_WDT_MR_WDDIS;
-   writel(priv->mr, priv->regs + AT91_WDT_MR);
+   wdt->mr |= AT91_WDT_MR_WDDIS;
+   writel(wdt->mr, wdt->regs + AT91_WDT_MR);
 
return 0;
 }
 
 static int at91_wdt_reset(struct udevice *dev)
 {
-   struct at91_wdt_priv *priv = dev_get_priv(dev);
+   struct at91_wdt_priv *wdt = dev_get_priv(dev);
 
-   writel(AT91_WDT_CR_WDRSTT | AT91_WDT_CR_KEY, priv->regs + AT91_WDT_CR);
+   writel(AT91_WDT_CR_WDRSTT | AT91_WDT_CR_KEY, wdt->regs + AT91_WDT_CR);
 
return 0;
 }
@@ -102,10 +102,10 @@ static const struct udevice_id at91_wdt_ids[] = {
 
 static int at91_wdt_probe(struct udevice *dev)
 {
-   struct at91_wdt_priv *priv = dev_get_priv(dev);
+   struct at91_wdt_priv *wdt = dev_get_priv(dev);
 
-   priv->regs = dev_remap_addr(dev);
-   if (!priv->regs)
+   wdt->regs = dev_remap_addr(dev);
+   if (!wdt->regs)
return -EINVAL;
 
debug("%s: Probing wdt%u\n", __func__, dev_seq(dev));

-- 
2.49.0



[PATCH v4 4/6] watchdog: at91sam9_wdt: Add SAM9X60 support

2025-04-28 Thread Zixun LI
SAM9X60 has a slightly different watchdog implementation:
- Timer value moved into a new register WLR
- Some MR register fields have their position changed

This patch add SAM9X60 support, also adds a compatible
for SAMA5D4 which is the same as existing SAM9260.

Signed-off-by: Zixun LI 
---
 arch/arm/mach-at91/include/mach/at91_wdt.h | 19 +--
 drivers/watchdog/at91sam9_wdt.c| 39 --
 2 files changed, 48 insertions(+), 10 deletions(-)

diff --git a/arch/arm/mach-at91/include/mach/at91_wdt.h 
b/arch/arm/mach-at91/include/mach/at91_wdt.h
index 
a5accbae52186e99de0b113d6982a4cc54e36095..9a3976d9e970c212d348daeabc14c2fd6c54a8b5
 100644
--- a/arch/arm/mach-at91/include/mach/at91_wdt.h
+++ b/arch/arm/mach-at91/include/mach/at91_wdt.h
@@ -19,9 +19,16 @@
 
 #else
 
+enum {
+   AT91_WDT_MODE_SAM9260 = 0,
+   AT91_WDT_MODE_SAM9X60 = 1
+};
+
 struct at91_wdt_priv {
void __iomem *regs;
u32 mr;
+   u32 wddis;
+   u8 mode;
 };
 
 #endif
@@ -33,14 +40,22 @@ struct at91_wdt_priv {
 
 /* Watchdog Mode Register*/
 #define AT91_WDT_MR0X04
-#define AT91_WDT_MR_WDV(x) (x & 0xfff)
+#define AT91_WDT_MR_WDV(x) ((x) & 0xfff)
+#define AT91_SAM9X60_MR_PERIODRST  0x0010
 #define AT91_WDT_MR_WDFIEN 0x1000
+#define AT91_SAM9X60_MR_WDDIS  0x1000
 #define AT91_WDT_MR_WDRSTEN0x2000
 #define AT91_WDT_MR_WDRPROC0x4000
 #define AT91_WDT_MR_WDDIS  0x8000
-#define AT91_WDT_MR_WDD(x) ((x & 0xfff) << 16)
+#define AT91_WDT_MR_WDD(x) (((x) & 0xfff) << 16)
 #define AT91_WDT_MR_WDDBGHLT   0x1000
+#define AT91_SAM9X60_MR_WDIDLEHLT  0x1000
 #define AT91_WDT_MR_WDIDLEHLT  0x2000
+#define AT91_SAM9X60_MR_WDDBGHLT   0x2000
+
+/* Watchdog Window Level Register */
+#define AT91_SAM9X60_WLR   0x0c
+#define AT91_SAM9X60_WLR_COUNTER(x)((x) & 0xfff)
 
 /* Hardware timeout in seconds */
 #define WDT_MAX_TIMEOUT16
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index 
5ca3e5a5fdefb3101c97754f10b65c0acd69a522..72e13787448e366036dce4a451cc2294e5b60a0d
 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -49,7 +49,7 @@ static int at91_wdt_start(struct udevice *dev, u64 
timeout_ms, ulong flags)
ticks = WDT_SEC2TICKS(timeout);
 
/* Check if disabled */
-   if (readl(wdt->regs + AT91_WDT_MR) & AT91_WDT_MR_WDDIS) {
+   if (readl(wdt->regs + AT91_WDT_MR) & wdt->wddis) {
printf("sorry, watchdog is disabled\n");
return -1;
}
@@ -60,11 +60,21 @@ static int at91_wdt_start(struct udevice *dev, u64 
timeout_ms, ulong flags)
 * Since WDV is a 12-bit counter, the maximum period is
 * 4096 / 256 = 16 seconds.
 */
-   wdt->mr = AT91_WDT_MR_WDRSTEN   /* causes watchdog reset */
-   | AT91_WDT_MR_WDDBGHLT  /* disabled in debug mode */
-   | AT91_WDT_MR_WDD(0xfff)/* restart at any time */
-   | AT91_WDT_MR_WDV(ticks);   /* timer value */
-   writel(wdt->mr, wdt->regs + AT91_WDT_MR);
+
+   if (wdt->mode == AT91_WDT_MODE_SAM9260) {
+   wdt->mr = AT91_WDT_MR_WDRSTEN   /* causes watchdog reset */
+   | AT91_WDT_MR_WDDBGHLT  /* disabled in debug mode */
+   | AT91_WDT_MR_WDD(0xfff)/* restart at any time */
+   | AT91_WDT_MR_WDV(ticks);   /* timer value */
+   writel(wdt->mr, wdt->regs + AT91_WDT_MR);
+   } else if (wdt->mode == AT91_WDT_MODE_SAM9X60) {
+   writel(AT91_SAM9X60_WLR_COUNTER(ticks), /* timer value */
+  wdt->regs + AT91_SAM9X60_WLR);
+
+   wdt->mr = AT91_SAM9X60_MR_PERIODRST /* causes watchdog reset */
+   | AT91_SAM9X60_MR_WDDBGHLT; /* disabled in debug mode */
+   writel(wdt->mr, wdt->regs + AT91_WDT_MR);
+   }
 
return 0;
 }
@@ -74,7 +84,7 @@ static int at91_wdt_stop(struct udevice *dev)
struct at91_wdt_priv *wdt = dev_get_priv(dev);
 
/* Disable Watchdog Timer */
-   wdt->mr |= AT91_WDT_MR_WDDIS;
+   wdt->mr |= wdt->wddis;
writel(wdt->mr, wdt->regs + AT91_WDT_MR);
 
return 0;
@@ -96,7 +106,14 @@ static const struct wdt_ops at91_wdt_ops = {
 };
 
 static const struct udevice_id at91_wdt_ids[] = {
-   { .compatible = "atmel,at91sam9260-wdt" },
+   { .compatible = "atmel,at91sam9260-wdt",
+ .data = AT91_WDT_MODE_SAM9260 },
+   { .compatible = "atmel,sama5d4-wdt",
+ .data = AT91_WDT_MODE_SAM9260 },
+   { .compatible = "microchip,sam9x60-wdt",
+ .data = A

[PATCH v4 5/6] ARM: dts: sam9x60: Add watchdog DT node

2025-04-28 Thread Zixun LI
Add the watchdog timer node for the sam9x60 SoC's.

Signed-off-by: Zixun LI 
---
 arch/arm/dts/sam9x60.dtsi | 8 
 1 file changed, 8 insertions(+)

diff --git a/arch/arm/dts/sam9x60.dtsi b/arch/arm/dts/sam9x60.dtsi
index 
7631dfaa07fc1e7c605c70840da1196c1daeb638..79449042c24f90686613f0082f40d4f2c13f122f
 100644
--- a/arch/arm/dts/sam9x60.dtsi
+++ b/arch/arm/dts/sam9x60.dtsi
@@ -311,6 +311,14 @@
clocks = <&slow_rc_osc>, <&slow_xtal>;
#clock-cells = <1>;
};
+
+   watchdog: watchdog@ff80 {
+   compatible = "microchip,sam9x60-wdt";
+   reg = <0xff80 0x24>;
+   interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+   clocks = <&clk32 0>;
+   status = "disabled";
+   };
};
};
 

-- 
2.49.0



[PATCH v4 6/6] ARM: dts: at91: sam9x60-curiosity: Enable watchdog node

2025-04-28 Thread Zixun LI
Enable watchdog node on SAM9X60-Curiosity board.

A default timeout of 16s is added which is the maximum supported value,
also matching Linux driver's behavior.

Signed-off-by: Zixun LI 
---
 arch/arm/dts/at91-sam9x60_curiosity-u-boot.dtsi | 4 
 arch/arm/dts/at91-sam9x60_curiosity.dts | 4 
 2 files changed, 8 insertions(+)

diff --git a/arch/arm/dts/at91-sam9x60_curiosity-u-boot.dtsi 
b/arch/arm/dts/at91-sam9x60_curiosity-u-boot.dtsi
index 
dd4623311c9df6004c1715d406d3873bbcc254b5..9144387861eca5ab14b756063b89866d280d7dea
 100644
--- a/arch/arm/dts/at91-sam9x60_curiosity-u-boot.dtsi
+++ b/arch/arm/dts/at91-sam9x60_curiosity-u-boot.dtsi
@@ -95,3 +95,7 @@
 &slow_xtal {
bootph-all;
 };
+
+&watchdog {
+   timeout-sec = <16>;
+};
diff --git a/arch/arm/dts/at91-sam9x60_curiosity.dts 
b/arch/arm/dts/at91-sam9x60_curiosity.dts
index 
1c7f0fa6a49004943e5a4ac6637db5e806cc92f3..f165fdadb9e4abd08f9166e7cbec0507616c9939
 100644
--- a/arch/arm/dts/at91-sam9x60_curiosity.dts
+++ b/arch/arm/dts/at91-sam9x60_curiosity.dts
@@ -336,3 +336,7 @@
 &usb2 {
status = "okay";
 };
+
+&watchdog {
+   status = "okay";
+};

-- 
2.49.0



[PATCH v2 0/8] watchdog: at91sam9_wdt driver enhancement

2025-04-17 Thread Zixun LI
This patch series includes some code refactor and adds new device support
for at91sam9_wdt driver.

Instead of add a new driver like Linux kernel, at91sam9_wdt driver is
extended as new watchdog variant is similar to existing one, especially
for the function subset used by u-boot.

1. Remove typedef struct and rename variables for readability.

2. Add SAMA5D4 compatible, it has the same watchdog as SAM9260 except a
new lockout feature is added. Currently this feature is unimplemented.

3. SAM9X60, SAM9X7 and SAMA7 series have a new watchdog variant, some
bitfields bof MR register shifted their position, a new register is added
for timer value.

4. Add DT node to SAM9X60-Currently board

It has been tested on SAM9X60-Currently board:
- Start & stop
- Set timeout from DT node
- Reset kick in with a while(1) loop

Changes in v2:
- Fix SPL build

Zixun LI (7):
  arm: at91: wdt: Remove unused at91_wdt struct
  arm: at91: wdt: Rename regval in priv data to mr
  watchdog: at91sam9_wdt: Rename priv to wdt
  arm: at91: wdt: Add SAM9X60 register definition
  watchdog: at91sam9_wdt: Add SAM9X60 support
  ARM: dts: sam9x60: Add watchdog DT node.
  ARM: dts: at91: sam9x60-curiosity: Enable watchdog node

 arch/arm/dts/at91-sam9x60_curiosity.dts|  5 ++
 arch/arm/dts/sam9x60.dtsi  |  7 +++
 arch/arm/mach-at91/include/mach/at91_wdt.h | 25 ++
 drivers/watchdog/at91sam9_wdt.c| 55 +++---
 4 files changed, 68 insertions(+), 24 deletions(-)

--
2.49.0

---
Zixun LI (8):
  arm: at91: remove at91_wdt struct in spl
  arm: at91: wdt: Remove unused at91_wdt struct
  arm: at91: wdt: Rename regval in priv data to mr
  watchdog: at91sam9_wdt: Rename priv to wdt
  arm: at91: wdt: Add SAM9X60 register definition
  watchdog: at91sam9_wdt: Add SAM9X60 support
  ARM: dts: sam9x60: Add watchdog DT node.
  ARM: dts: at91: sam9x60-curiosity: Enable watchdog node

 arch/arm/dts/at91-sam9x60_curiosity.dts|  5 +++
 arch/arm/dts/sam9x60.dtsi  |  7 
 arch/arm/mach-at91/include/mach/at91_wdt.h | 25 +-
 arch/arm/mach-at91/spl.c   |  4 +--
 drivers/watchdog/at91sam9_wdt.c| 55 +-
 5 files changed, 69 insertions(+), 27 deletions(-)
---
base-commit: 5b4ae0f3f040908602c80908c3023b5454883d4a
change-id: 20250417-wdt-da6560c1b258

Best regards,
-- 
Zixun LI 



[PATCH v2 3/8] arm: at91: wdt: Rename regval in priv data to mr

2025-04-17 Thread Zixun LI
Use the name "mr" since we are referring to timer mode register.

Signed-off-by: Zixun LI 
---
 arch/arm/mach-at91/include/mach/at91_wdt.h | 2 +-
 drivers/watchdog/at91sam9_wdt.c| 8 
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-at91/include/mach/at91_wdt.h 
b/arch/arm/mach-at91/include/mach/at91_wdt.h
index 
78ad0453fd9eb3e42674d10cb11ce3da820cdc6a..a5accbae52186e99de0b113d6982a4cc54e36095
 100644
--- a/arch/arm/mach-at91/include/mach/at91_wdt.h
+++ b/arch/arm/mach-at91/include/mach/at91_wdt.h
@@ -21,7 +21,7 @@
 
 struct at91_wdt_priv {
void __iomem *regs;
-   u32 regval;
+   u32 mr;
 };
 
 #endif
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index 
c809a8936b8968c3322db4c86bc0571fbdfe3ae2..dab7b6a9b8ca09e6113109391560434ffe1f7cb6
 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -60,11 +60,11 @@ static int at91_wdt_start(struct udevice *dev, u64 
timeout_ms, ulong flags)
 * Since WDV is a 12-bit counter, the maximum period is
 * 4096 / 256 = 16 seconds.
 */
-   priv->regval = AT91_WDT_MR_WDRSTEN  /* causes watchdog reset */
+   priv->mr = AT91_WDT_MR_WDRSTEN  /* causes watchdog reset */
| AT91_WDT_MR_WDDBGHLT  /* disabled in debug mode */
| AT91_WDT_MR_WDD(0xfff)/* restart at any time */
| AT91_WDT_MR_WDV(ticks);   /* timer value */
-   writel(priv->regval, priv->regs + AT91_WDT_MR);
+   writel(priv->mr, priv->regs + AT91_WDT_MR);
 
return 0;
 }
@@ -74,8 +74,8 @@ static int at91_wdt_stop(struct udevice *dev)
struct at91_wdt_priv *priv = dev_get_priv(dev);
 
/* Disable Watchdog Timer */
-   priv->regval |= AT91_WDT_MR_WDDIS;
-   writel(priv->regval, priv->regs + AT91_WDT_MR);
+   priv->mr |= AT91_WDT_MR_WDDIS;
+   writel(priv->mr, priv->regs + AT91_WDT_MR);
 
return 0;
 }

-- 
2.49.0



  1   2   >