Re: [PATCH v4] ARM: rpi: parse useful data from vc fdt

2022-06-21 Thread Sascha Hauer
On Fri, Jun 17, 2022 at 11:58:11PM +0200, Daniel Brát wrote:
> Videocore first-stage loader on rpi passes us many useful information
> inside the vc fdt, including the real value of PM_RSTS register, not
> easily available by other means and which we can use to determine
> the reset cause.
> Also make the relevant funtions just print error/warning and continue
> in case of some errors, since the fdt from vc is now optional for
> barebox's basic function.
> 
> Signed-off-by: Daniel Brát 
> ---
>  arch/arm/boards/raspberry-pi/rpi-common.c | 183 +-
>  drivers/watchdog/bcm2835_wdt.c|  23 +--
>  include/soc/bcm283x/wdt.h |  40 +
>  3 files changed, 182 insertions(+), 64 deletions(-)
>  create mode 100644 include/soc/bcm283x/wdt.h

Applied, thanks

Sascha

> 
> diff --git a/arch/arm/boards/raspberry-pi/rpi-common.c 
> b/arch/arm/boards/raspberry-pi/rpi-common.c
> index 12a4f4a0a..eaca4edef 100644
> --- a/arch/arm/boards/raspberry-pi/rpi-common.c
> +++ b/arch/arm/boards/raspberry-pi/rpi-common.c
> @@ -23,13 +23,28 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  #include 
>  #include 
>  #include 
>  
> +#include 
> +
>  #include "lowlevel.h"
>  
> +//https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#BOOT_ORDER
> +static const char * const boot_mode_names[] = {
> + [0x0] = "unknown",
> + [0x1] = "sd",
> + [0x2] = "net",
> + [0x3] = "rpiboot",
> + [0x4] = "usbmsd",
> + [0x5] = "usbc",
> + [0x6] = "nvme",
> + [0x7] = "http",
> +};
> +
>  struct rpi_priv;
>  struct rpi_machine_data {
>   int (*init)(struct rpi_priv *priv);
> @@ -186,54 +201,131 @@ static int rpi_env_init(void)
>   return 0;
>  }
>  
> -/* Extract /chosen/bootargs from the VideoCore FDT into vc.bootargs
> - * global variable. */
> -static int rpi_vc_fdt_bootargs(void *fdt)
> +/* Some string properties in fdt passed to us from vc may be
> + * malformed by not being null terminated. In that case, create and
> + * return a null terminated copy.
> + */
> +static char *of_read_vc_string(struct device_node *node,
> +  const char *prop_name,
> +  bool *is_dyn)
> +{
> + int len;
> + char *str;
> +
> + str = (char *)of_get_property(node, prop_name, &len);
> + if (!str || len <= 0)
> + return NULL;
> + if (is_dyn)
> + *is_dyn = str[len - 1] != '\0';
> + return str[len - 1] == '\0' ? str : xstrndup(str, len);
> +}
> +
> +static u32 rpi_boot_mode, rpi_boot_part;
> +/* Extract useful information from the VideoCore FDT we got.
> + * Some parameters are defined here:
> + * 
> https://www.raspberrypi.com/documentation/computers/configuration.html#part4
> + */
> +static void rpi_vc_fdt_parse(void *fdt)
>  {
> - int ret = 0;
> - struct device_node *root = NULL, *node;
> - const char *cmdline;
> + int ret;
> + struct device_node *root, *chosen, *bootloader;
> + enum reset_src_type rst_src = RESET_UKWN;
> + char *str;
> + bool is_dyn;
> + u32 pm_rsts;
>  
>   root = of_unflatten_dtb(fdt, INT_MAX);
> - if (IS_ERR(root)) {
> - ret = PTR_ERR(root);
> - root = NULL;
> - goto out;
> + if (IS_ERR(root))
> + return;
> +
> + str = of_read_vc_string(root, "serial-number", &is_dyn);
> + if (str) {
> + barebox_set_serial_number(str);
> + if (is_dyn)
> + free(str);
> + } else {
> + pr_warn("no 'serial-number' property found in vc fdt root\n");
>   }
>  
> - node = of_find_node_by_path_from(root, "/chosen");
> - if (!node) {
> - pr_err("no /chosen node\n");
> - ret = -ENOENT;
> - goto out;
> + str = of_read_vc_string(root, "model", &is_dyn);
> + if (str) {
> + barebox_set_model(str);
> + if (is_dyn)
> + free(str);
> + } else {
> + pr_warn("no 'model' property found in vc fdt root\n");
>   }
>  
> - cmdline = of_get_property(node, "bootargs", NULL);
> - if (!cmdline) {
> - pr_err("no bootargs property in the /chosen node\n");
> - ret = -ENOENT;
> + chosen = of_find_node_by_path_from(root, "/chosen");
> + if (!chosen) {
> + pr_err("no '/chosen' node found in vc fdt\n");
>   goto out;
>   }
>  
> - globalvar_add_simple("vc.bootargs", cmdline);
> + bootloader = of_find_node_by_name(chosen, "bootloader");
> +
> + str = of_read_vc_string(chosen, "bootargs", NULL);
> + if (str)
> + globalvar_add_simple("vc.bootargs", str);
> + else
> + pr_warn("no 'bootargs' property found in vc fdt '/chosen'\n");
> +
> + str = of_read_vc_string(chosen, "overlay_prefix", NULL);
> + if (str)
> + globalvar_add_simple("vc.overlay_prefix", str);
> + else
> +

Re: Boot hangs during sdhci_transfer_data_dma

2022-06-21 Thread Sascha Hauer
Hi Robin,

On Mon, Jun 20, 2022 at 04:33:02PM +0200, Robin van der Gracht wrote:
> Hi,
> 
> Today I tried to run barebox with CONFIG_KEYBOARD_GPIO=y added to my config.
> and noticed my board hangs during boot. When I modify the probe function to
> run without registering the poller[1] it boots as expected.
> 
> I started digging into the code to see how far the boot gets when I do
> register the poller. I found that Barebox hangs in a do/while loop in
> sdhci_transfer_data_dma[2].
> 
> The contents of the interrupt status (SDHCI_INT_STATUS) is 0 and stays that
> way forever trapping the process in the loop.
> 
> Call stack:
> 
> initcall -> barebox_of_populate
>   state_probe  drivers/misc/state.c
> state_new_from_nodecommon/state/state.c
>   of_find_path_by_node drivers/of/of_path.c
> __of_find_path drivers/of/of_path.c
>   device_detectdrivers/base/driver.c
> mci_detect_carddrivers/mci/mci-core.c
>   mci_card_probe   drivers/mci/mci-core.c
> mci_startupdrivers/mci/mci-core.c
>   mci_startup_mmc  drivers/mci/mci-core.c
> mmc_compare_ext_csds   drivers/mci/mci-core.c
>   mci_send_ext_csd drivers/mci/mci-core.c
> mci_send_cmd   drivers/mci/mci-core.c
>   esdhc_send_cmd
> drivers/mci/imx-esdhc.c
> __esdhc_send_cmd
> drivers/mci/imx-esdhc-common.c
>   sdhci_transfer_data_dma  drivers/mci/sdhci.c
> 
> 
> I'm not sure how this happens. It's not the first transfer taking place. I
> figured that mayby the poller[1] just adds some cpu load that opens up a
> window for this to occur.
> 
> Maybe something else cleared the status register right before we entered the
> loop. Thats when I spotted this read/write construction[3]. It's executed
> right before we enter the do/while loop and (over)writes to the irq status
> register.
> 
> I removed the line with the write command[3] and my board boots as expected.
> Why are we (over)writing the status register right after reading it?

The idea is likely that we clear the interrupts that we just handled. It
seems by the time the status register is overwritten the DMA transfer is
already ongoing, and in your case even already done. We should only ever
clear the bits we have handled, like sdhci_transfer_data_dma() does with

sdhci_write32(sdhci, SDHCI_INT_STATUS, SDHCI_INT_DMA);

Apart from this line the code never checks the same bit twice, so
clearing anything shoudn't be necessary. Clearing the status register
once either at the start or the end of the function should be enough.

I think the right thing to do is just to remove the erroneous status
register write like you already did.

Sascha

-- 
Pengutronix e.K.   | |
Steuerwalder Str. 21   | http://www.pengutronix.de/  |
31137 Hildesheim, Germany  | Phone: +49-5121-206917-0|
Amtsgericht Hildesheim, HRA 2686   | Fax:   +49-5121-206917- |



[PATCH] arm: rockchip: radxa-rock3: enable deep probe support

2022-06-21 Thread Michael Riesch
Enable deep probe support on the Radxa ROCK3 boards.

Signed-off-by: Michael Riesch 
---
 arch/arm/boards/radxa-rock3/board.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/boards/radxa-rock3/board.c 
b/arch/arm/boards/radxa-rock3/board.c
index 30ad594d0a..aef5ec5df6 100644
--- a/arch/arm/boards/radxa-rock3/board.c
+++ b/arch/arm/boards/radxa-rock3/board.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -50,3 +51,5 @@ static struct driver_d rock3_board_driver = {
.of_compatible = rock3_of_match,
 };
 coredevice_platform_driver(rock3_board_driver);
+
+BAREBOX_DEEP_PROBE_ENABLE(rock3_of_match);
-- 
2.30.2




Re: Boot hangs during sdhci_transfer_data_dma

2022-06-21 Thread Robin van der Gracht

Hi Sascha,

On 2022-06-21 09:46, Sascha Hauer wrote:

Hi Robin,

On Mon, Jun 20, 2022 at 04:33:02PM +0200, Robin van der Gracht wrote:

Hi,

Today I tried to run barebox with CONFIG_KEYBOARD_GPIO=y added to my 
config.

and noticed my board hangs during boot. When I modify the probe function to
run without registering the poller[1] it boots as expected.

I started digging into the code to see how far the boot gets when I do
register the poller. I found that Barebox hangs in a do/while loop in
sdhci_transfer_data_dma[2].

The contents of the interrupt status (SDHCI_INT_STATUS) is 0 and stays that
way forever trapping the process in the loop.

Call stack:

initcall -> barebox_of_populate
  state_probe  drivers/misc/state.c
state_new_from_nodecommon/state/state.c
  of_find_path_by_node drivers/of/of_path.c
__of_find_path drivers/of/of_path.c
  device_detect
drivers/base/driver.c
mci_detect_card
drivers/mci/mci-core.c
  mci_card_probe   
drivers/mci/mci-core.c
mci_startup
drivers/mci/mci-core.c
  mci_startup_mmc  
drivers/mci/mci-core.c
mmc_compare_ext_csds   
drivers/mci/mci-core.c
  mci_send_ext_csd 
drivers/mci/mci-core.c
mci_send_cmd   
drivers/mci/mci-core.c

  esdhc_send_cmd
drivers/mci/imx-esdhc.c
__esdhc_send_cmd
drivers/mci/imx-esdhc-common.c
  sdhci_transfer_data_dma  drivers/mci/sdhci.c


I'm not sure how this happens. It's not the first transfer taking place. I
figured that mayby the poller[1] just adds some cpu load that opens up a
window for this to occur.

Maybe something else cleared the status register right before we entered 
the

loop. Thats when I spotted this read/write construction[3]. It's executed
right before we enter the do/while loop and (over)writes to the irq status
register.

I removed the line with the write command[3] and my board boots as 
expected.

Why are we (over)writing the status register right after reading it?


The idea is likely that we clear the interrupts that we just handled. It
seems by the time the status register is overwritten the DMA transfer is
already ongoing, and in your case even already done.


I can confirm this. When the data transfer is still ongoing the status
register holds 0x1 (SDHCI_INT_CMD_COMPLETE). A few lines above
the write there is a busy wait for this bit to be set.

When my board hangs the status register holds 0x000b at the timen it is
cleared. Which means the DMA engine has stopped on a buffer boundary.
Apparently this can sometimes happen shortly after starting.


We should only ever
clear the bits we have handled, like sdhci_transfer_data_dma() does with

sdhci_write32(sdhci, SDHCI_INT_STATUS, SDHCI_INT_DMA);


Ack. This would suffice:

sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, SDHCI_INT_CMD_COMPLETE);




Apart from this line the code never checks the same bit twice, so
clearing anything shoudn't be necessary. Clearing the status register
once either at the start or the end of the function should be enough.

I think the right thing to do is just to remove the erroneous status
register write like you already did.


I'll submit a patch that removes the write. Thank you for thinking along.

- Robin



Re: Boot hangs during sdhci_transfer_data_dma

2022-06-21 Thread Robin van der Gracht

On 2022-06-21 09:46, Sascha Hauer wrote:

Hi Robin,

...

We should only ever
clear the bits we have handled, like sdhci_transfer_data_dma() does with

sdhci_write32(sdhci, SDHCI_INT_STATUS, SDHCI_INT_DMA);


I just noticed that the tegra-sdmmc mci driver might have the same issue.

https://git.pengutronix.de/cgit/barebox/tree/drivers/mci/tegra-sdmmc.c#n149

It can prevent the following conditional from ever evaluating true trapping
the process in the while loop.
https://git.pengutronix.de/cgit/barebox/tree/drivers/mci/tegra-sdmmc.c#n203

This driver clears the status register on error (not on start/end of 
function)

with an old value 'val' which can be lacking status bits that popped up
along the way...

I can't test code changes for this platform.

- Robin



[PATCH] mci: imx-esdhc-common: Don't clear unhandled status bits

2022-06-21 Thread Robin van der Gracht
A DMA cmd + data transfer can finish or stop (i.e. on a block gap) before
the status register is cleared. In that case we'll lose track of state
causing sdhci_transfer_data_dma() to loop forever waiting for status bits
that are already cleared.

Clearing SDHCI_INT_CMD_COMPLETE should suffice here. Since it's not
evaluated a second time, clearing it at the start of the function is
sufficient so we can just remove the erroneous status write.

Signed-off-by: Robin van der Gracht 
---
 drivers/mci/imx-esdhc-common.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/mci/imx-esdhc-common.c b/drivers/mci/imx-esdhc-common.c
index a12db43c88..27293e44b7 100644
--- a/drivers/mci/imx-esdhc-common.c
+++ b/drivers/mci/imx-esdhc-common.c
@@ -176,7 +176,6 @@ int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct 
mci_cmd *cmd,
}
 
irqstat = sdhci_read32(&host->sdhci, SDHCI_INT_STATUS);
-   sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, irqstat);
 
if (irqstat & CMD_ERR)
return -EIO;
-- 
2.34.1




Re: [PATCH] arm: imx: mmdc_size: Increase row_max for imx8m

2022-06-21 Thread Teresa Remmet
Hi!

Am Montag, dem 20.06.2022 um 15:19 +0200 schrieb Ahmad Fatoum:
> Hi,
> 
> On 20.06.22 14:47, Teresa Remmet wrote:
> > Am Montag, dem 20.06.2022 um 14:38 +0200 schrieb Ahmad Fatoum:
> > > On 20.06.22 14:27, Teresa Remmet wrote:
> > > > I have set the DDRC_ADDRMAP7 register manually in the RAM
> > > > configuration
> > > > in such a case. As I don't see a solution that fits for all.
> > > > But
> > > > would
> > > > be happy for one. :)
> > > 
> > > What would the 'neutral' value to write into this register be?
> > > zero
> > > seems to not be it.
> > 
> > it's 
> > 
> > 0xf0f for ADDRMAP7.
> > 
> > Reference Manual says: "If set to 15, row address bit X is set to
> > 0"
> 
> Do newer spreadsheets always generate ADDRMAP7 writes even if the
> value is zero? If so, we could perhaps initialize it to 0xf0f before
> running ddr_cfg_umctl2(). The DDRC seems to be in reset while the
> registers are being written, so this might just work.

this is not so easy to figure out because the spread sheet does 
not generate the c headers directly. 
But it is true for other ADDRMAP registers where the reset value is also zero.
So I would give it a try.

> 
> As 0 is a valid value, I am wondering if this snippet introduced with
> 42d45ef380c5 ("ARM: imx: Add imx8 support for SDRAM with two or more
> bank groups")
> is correct:
> 
> if (addrmap[8]) {
> if (FIELD_GET(DDRC_ADDRMAP8_BG_B0, addrmap[8]) != 0b1)
> banks++;
> if (FIELD_GET(DDRC_ADDRMAP8_BG_B1, addrmap[8]) != 0b11)
> banks++;
> }

yes, this is wrong. LPDDR4 is no problem at the moment as the
spreadsheet does not set the value and the reset value here is zero.
But DDR4 uses it and there could be a "real" zero set which is then
ignored.

Regards,
Teresa

> 
> Thanks,
> Ahmad
> 
> > Regards,
> > Teresa
> > 
> > 
> > > Thanks,
> > > Ahmad
> > > 
> > > > Regards,
> > > > Teresa
> > > > 
> > > > > > ---
> > > > > >  arch/arm/mach-imx/esdctl.c | 2 +-
> > > > > >  1 file changed, 1 insertion(+), 1 deletion(-)
> > > > > > 
> > > > > > diff --git a/arch/arm/mach-imx/esdctl.c b/arch/arm/mach-
> > > > > > imx/esdctl.c
> > > > > > index 8dd0ddbbc965..b070ebc62a45 100644
> > > > > > --- a/arch/arm/mach-imx/esdctl.c
> > > > > > +++ b/arch/arm/mach-imx/esdctl.c
> > > > > > @@ -488,7 +488,7 @@ static resource_size_t
> > > > > > imx8m_ddrc_sdram_size(void __iomem *ddrc)
> > > > > >  
> > > > > > return imx_ddrc_sdram_size(ddrc, addrmap,
> > > > > >12, ARRAY_AND_SIZE(col_b),
> > > > > > -  16, ARRAY_AND_SIZE(row_b),
> > > > > > +  18, ARRAY_AND_SIZE(row_b),
> > > > > >reduced_adress_space, true);
> > > > > >  }
> > > > > >  
> 
> 
-- 
PHYTEC Messtechnik GmbH | Robert-Koch-Str. 39 | 55129 Mainz, Germany

Geschäftsführer: Dipl.-Ing. Michael Mitezki, Dipl.-Ing. Bodo Huber |
Handelsregister Mainz HRB 4656 | Finanzamt Mainz | St.Nr. 266500608, DE
149059855


[PATCH] ARM: rpi: cleanup parsing of vc fdt

2022-06-21 Thread Daniel Brát
Refactoring and cleanup of vc fdt parsing based on advice
from Ahmad Fatoum.

Signed-off-by: Daniel Brát 
---
I originally wanted to send these as part of v5 of
'ARM: rpi: parse useful data from vc fdt' patch, but you
were quicker with accepting the v4 :)
Hope that's not a problem.

 arch/arm/boards/raspberry-pi/rpi-common.c | 114 +++---
 1 file changed, 58 insertions(+), 56 deletions(-)

diff --git a/arch/arm/boards/raspberry-pi/rpi-common.c 
b/arch/arm/boards/raspberry-pi/rpi-common.c
index eaca4edef..77935e5c8 100644
--- a/arch/arm/boards/raspberry-pi/rpi-common.c
+++ b/arch/arm/boards/raspberry-pi/rpi-common.c
@@ -202,22 +202,52 @@ static int rpi_env_init(void)
 }
 
 /* Some string properties in fdt passed to us from vc may be
- * malformed by not being null terminated. In that case, create and
- * return a null terminated copy.
+ * malformed by not being null terminated, so just create and
+ * return a fixed copy.
  */
 static char *of_read_vc_string(struct device_node *node,
-const char *prop_name,
-bool *is_dyn)
+  const char *prop_name)
 {
int len;
-   char *str;
+   const char *str;
 
-   str = (char *)of_get_property(node, prop_name, &len);
-   if (!str || len <= 0)
+   str = of_get_property(node, prop_name, &len);
+   if (!str) {
+   pr_warn("no property '%s' found in vc fdt's '%s' node\n",
+   prop_name, node->full_name);
return NULL;
-   if (is_dyn)
-   *is_dyn = str[len - 1] != '\0';
-   return str[len - 1] == '\0' ? str : xstrndup(str, len);
+   }
+   return xstrndup(str, len);
+}
+
+static enum reset_src_type rpi_decode_pm_rsts(struct device_node *chosen,
+ struct device_node *bootloader)
+{
+   u32 pm_rsts;
+   int ret;
+
+   ret = of_property_read_u32(chosen, "pm_rsts", &pm_rsts);
+   if (ret && bootloader)
+ret = of_property_read_u32(bootloader, "rsts", &pm_rsts);
+
+   if (ret) {
+   pr_warn("'pm_rsts' value not found in vc fdt\n");
+   return RESET_UKWN;
+   }
+   /*
+* https://github.com/raspberrypi/linux/issues/932#issuecomment-93989581
+*/
+
+   if (pm_rsts & PM_RSTS_HADPOR_SET)
+   return RESET_POR;
+   if (pm_rsts & PM_RSTS_HADDR_SET)
+   return RESET_JTAG;
+   if (pm_rsts & PM_RSTS_HADWR_SET)
+   return RESET_WDG;
+   if (pm_rsts & PM_RSTS_HADSR_SET)
+   return RESET_RST;
+
+   return RESET_UKWN;
 }
 
 static u32 rpi_boot_mode, rpi_boot_part;
@@ -229,31 +259,22 @@ static void rpi_vc_fdt_parse(void *fdt)
 {
int ret;
struct device_node *root, *chosen, *bootloader;
-   enum reset_src_type rst_src = RESET_UKWN;
char *str;
-   bool is_dyn;
-   u32 pm_rsts;
 
root = of_unflatten_dtb(fdt, INT_MAX);
if (IS_ERR(root))
return;
 
-   str = of_read_vc_string(root, "serial-number", &is_dyn);
+   str = of_read_vc_string(root, "serial-number");
if (str) {
barebox_set_serial_number(str);
-   if (is_dyn)
-   free(str);
-   } else {
-   pr_warn("no 'serial-number' property found in vc fdt root\n");
+   free(str);
}
 
-   str = of_read_vc_string(root, "model", &is_dyn);
+   str = of_read_vc_string(root, "model");
if (str) {
barebox_set_model(str);
-   if (is_dyn)
-   free(str);
-   } else {
-   pr_warn("no 'model' property found in vc fdt root\n");
+   free(str);
}
 
chosen = of_find_node_by_path_from(root, "/chosen");
@@ -264,23 +285,23 @@ static void rpi_vc_fdt_parse(void *fdt)
 
bootloader = of_find_node_by_name(chosen, "bootloader");
 
-   str = of_read_vc_string(chosen, "bootargs", NULL);
-   if (str)
+   str = of_read_vc_string(chosen, "bootargs");
+   if (str) {
globalvar_add_simple("vc.bootargs", str);
-   else
-   pr_warn("no 'bootargs' property found in vc fdt '/chosen'\n");
+   free(str);
+   }
 
-   str = of_read_vc_string(chosen, "overlay_prefix", NULL);
-   if (str)
+   str = of_read_vc_string(chosen, "overlay_prefix");
+   if (str) {
globalvar_add_simple("vc.overlay_prefix", str);
-   else
-   pr_warn("no 'overlay_prefix' property found in vc fdt 
'/chosen'\n");
+   free(str);
+   }
 
-   str = of_read_vc_string(chosen, "os_prefix", NULL);
-   if (str)
+   str = of_read_vc_string(chosen, "os_prefix");
+   if (str) {
globalvar_add_simple("vc.os_prefix", str);
-   else
-   pr_warn("no 'os_prefix' property found in vc fdt '