Hi,
Please find an example patch from my customer to solve the uninitialized R30 register state in the ICSS that cause unexpected boot phase levels on the RS485 for Profibus applications. Please consider using this as inspiration to stabilizing the SDK in this regard.
Cheers. /Magnus
"When powering up a AM3359 (I have a Beaglebone) it seems the R30 register in the PRU(s) is in an undefined state. If the PRU GPIO’s are used, it means the output values of the GPIO pins will be undefined and not deterministic after a power on. The problem is first seen after the mux is programmed to use the PRU GPIO as GPIO outputs.
If arch/arm/mach-omap2/devices.c is modified according to the patch seen below, the problem can easily be reproduced, and corrected. (The patch is not supposed to give a final solution, but merely a hint what has to be done)
So basically what has to be done, as far as I can see, is to move parts of the code in drivers/uio/uio_pruss.c to arch/arm/mach-omap2/devices.c to be able to clear out the R30 register in the PRU earlier. The R30 register must be cleared _before_ the mux is configured, to get a reliable state out from the PRU GPIO’s once the mux is configured.
The patch below shows an example of this. But maybe the pruss_clk and the virtual remapped io-address could be saved in a ”struct uio_pruss_dev” already in arch/arm/mach-omap2/devices.c ? I cannot say if this would be OK, from an architechtural point of view. Anyway, it boils down to that the PRU has to be ”reseted” (register R30 cleared) before the mux is configured to use the GPIO’s from the PRU.
Doing it in drivers/uio/uio_pruss.c would be too late. That will make the GPIO pins potentially go high (undefined) from when the mux is configured to when the uio-driver is started, and that is not OK.
Background; I use one bit in R30 to control RX/TX on a Profibus RS485 interface, and having an undefined state of that pin during power up will potentially (if it goes high) block all traffic on the RS485 bus for ~½ a second."
Patch:
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 8e2f4a0..15ec5ef 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -1212,8 +1212,52 @@ static struct platform_device am335x_pruss_uio_dev = {
int __init am335x_register_pruss_uio(struct uio_pruss_pdata *config)
{
+ int rc;
+
am335x_pruss_uio_dev.dev.platform_data = config;
- return platform_device_register(&am335x_pruss_uio_dev);
+ rc=platform_device_register(&am335x_pruss_uio_dev);
+ if (!rc) {
+ struct clk *pruss_clk =
+ clk_get(&(am335x_pruss_uio_dev.dev), "pruss");
+
+ if (IS_ERR(pruss_clk))
+ printk(KERN_INFO "hejdu1.1: Failed to get clock\n");
+ else {
+ void __iomem *mapping;
+
+ clk_enable(pruss_clk);
+ mapping = ioremap(AM33XX_ICSS_BASE, AM33XX_ICSS_LEN + 1);
+ if(mapping) {
+ printk(KERN_INFO "hejdu1.2, R30 before: %08x\n",
+ __raw_readl(mapping + 0x22400 + 0x78));
+ printk(KERN_INFO "hejdu1.2.1, Control Reg before: %08x\n",
+ __raw_readl(mapping + 0x22000));
+
+ /* Attempted reset, as done in am335x_pru_package (does not reset R30) */
+ __raw_writel(0, mapping + 0x22000);
+ printk(KERN_INFO "hejdu1.2.2, R30 after \"reset\": %08x\n",
+ __raw_readl(mapping + 0x22400 + 0x78));
+ printk(KERN_INFO "hejdu1.2.3, Control Reg after \"reset\": %08x\n",
+ __raw_readl(mapping + 0x22000));
+
+ /* Checking R30 again, when we know Control Reg bit 0 is 1 again (seen above) */
+ printk(KERN_INFO "hejdu1.2.4, R30 again after \"reset\": %08x\n",
+ __raw_readl(mapping + 0x22400 + 0x78));
+
+ /* Explicitly write 0 to R30, solves the problem */
+ __raw_writel(0, mapping + 0x22400 + 0x78);
+
+ /* Checking R30 again, now zero */
+ printk(KERN_INFO "hejdu1.2.5, after explicitly setting it to 0: %08x\n",
+ __raw_readl(mapping + 0x22400 + 0x78));
+ iounmap(mapping);
+ } else {
+ printk(KERN_INFO "hejdu1.3\n");
+ printk(KERN_INFO "ioremap() failed\n");
+ }
+ }
+ }
+ return rc;
}
Some examples of printout after power up:
# dmesg | grep hejdu
[ 0.084625] hejdu1.2, R30 before: 42d176be
[ 0.084625] hejdu1.2.1, Control Reg before: 00000001
[ 0.084655] hejdu1.2.2, R30 after "reset": 42d176be
[ 0.084655] hejdu1.2.3, Control Reg after "reset": 00000001
[ 0.084686] hejdu1.2.4, R30 again after "reset": 42d176be
[ 0.084686] hejdu1.2.5, after explicitly setting it to 0: 00000000
#
Another power up (same value in R30):
# dmesg | grep hejdu
[ 0.084564] hejdu1.2, R30 before: 42d176be
[ 0.084564] hejdu1.2.1, Control Reg before: 00000001
[ 0.084594] hejdu1.2.2, R30 after "reset": 42d176be
[ 0.084594] hejdu1.2.3, Control Reg after "reset": 00000001
[ 0.084594] hejdu1.2.4, R30 again after "reset": 42d176be
[ 0.084625] hejdu1.2.5, after explicitly setting it to 0: 00000000
#
Another power up, another value in R30:
# dmesg | grep hejdu
[ 0.084533] hejdu1.2, R30 before: 42f1743e
[ 0.084564] hejdu1.2.1, Control Reg before: 00000001
[ 0.084564] hejdu1.2.2, R30 after "reset": 42f1743e
[ 0.084564] hejdu1.2.3, Control Reg after "reset": 00000001
[ 0.084594] hejdu1.2.4, R30 again after "reset": 42f1743e
[ 0.084594] hejdu1.2.5, after explicitly setting it to 0: 00000000
#
#