cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
itays
Visitor
Visitor
1,124 Views
Registered: ‎07-04-2019

ZynqMP - Control of GPIO from U-BOOT fails

Hello,
We are using a custom board based on the XCZU5EV.

U-BOOT is build using PetaLinux using the HDF we created from the Vivado app.

It seems like we can't control the gpios from the U-BOOT command

ZynqMP> gpio set 84
gpio: pin 84 (gpio 84) value is 1
   Warning: value of pin is still 0

gpio: pin 10 (gpio 10) value is 1
   Warning: value of pin is still 0
ZynqMP> gpio input 84

This is happens from bot MIO and EMIO gpios.

These gpios should be free and they are not part of the device tree genereted by PetaLinux.
This happens for most of the GPIOS we try to set.

If I using the command 'gpio status -a' , I can see in the list that the direction of the GPIO did change, but the value isn't.

Any advice will be appreciated.


Thanks

Tags (2)
0 Kudos
2 Replies
672 Views
Registered: ‎05-15-2019

Hi,

 

Were you able to solve this? Even I'm facing the same issue. It will be helpful if you could post the solution(if you found one).

 

Thanks in advance!!

Regards,

Prajna

0 Kudos
slocke
Observer
Observer
241 Views
Registered: ‎01-26-2018

I have seen this same issue on a Zynq platform. It is related to the statement in the TRM: 

The inputs are wires from the PL and are unrelated to the output values or the OEN register. They can be read from the DATA_RO register when DIRM is set to 0 , making it an input.

It seems the EMIO input lines are not connected to the output lines (unless done so in the fabric). This quirk is patched in the linux driver (for EMIO banks, the driver reads from the DATA register which reflects the output set value instead of the DATA_RO register).  The u-boot driver does not do this, which is why it always reports zero for EMIO gp-outputs.  My patch (for xilinx release 2020.2 of u-boot) is below.

Subject: [PATCH] Zynq EMIO gpios that are set as outputs cannot be read from
 the DATA_RO register.  They are separate interfaces (lines) in the FPGA. For
 these gpios, read the normal DATA (output-set register) to get the value

---
 drivers/gpio/zynq_gpio.c | 60 +++++++++++++++++++++++++---------------
 1 file changed, 37 insertions(+), 23 deletions(-)

diff --git a/drivers/gpio/zynq_gpio.c b/drivers/gpio/zynq_gpio.c
index fe3b2c3b..bb0b3e8c 100644
--- a/drivers/gpio/zynq_gpio.c
+++ b/drivers/gpio/zynq_gpio.c
@@ -64,6 +64,7 @@
 /* MSW Mask & Data -WO */
 #define ZYNQ_GPIO_DATA_MSW_OFFSET(BANK)	(0x004 + (8 * BANK))
 /* Data Register-RW */
+#define ZYNQ_GPIO_DATA_OFFSET(BANK)	(0x040 + (4 * BANK))
 #define ZYNQ_GPIO_DATA_RO_OFFSET(BANK)	(0x060 + (4 * BANK))
 /* Direction mode reg-RW */
 #define ZYNQ_GPIO_DIRM_OFFSET(BANK)	(0x204 + (0x40 * BANK))
@@ -228,6 +229,26 @@ static int check_gpio(unsigned gpio, struct udevice *dev)
 	return 0;
 }
 
+static int zynq_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+	u32 reg;
+	unsigned int bank_num, bank_pin_num;
+	struct zynq_gpio_platdata *platdata = dev_get_platdata(dev);
+
+	if (check_gpio(offset, dev) < 0)
+		return -1;
+
+	zynq_gpio_get_bank_pin(offset, &bank_num, &bank_pin_num, dev);
+
+	/* set the GPIO pin as output */
+	reg = readl(platdata->base + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
+	reg &= BIT(bank_pin_num);
+	if (reg)
+		return GPIOF_OUTPUT;
+	else
+		return GPIOF_INPUT;
+}
+
 static int zynq_gpio_get_value(struct udevice *dev, unsigned gpio)
 {
 	u32 data;
@@ -239,9 +260,22 @@ static int zynq_gpio_get_value(struct udevice *dev, unsigned gpio)
 
 	zynq_gpio_get_bank_pin(gpio, &bank_num, &bank_pin_num, dev);
 
-	data = readl(platdata->base +
-			     ZYNQ_GPIO_DATA_RO_OFFSET(bank_num));
-
+	/* For EMIO pins (banks 2 and 3), the input values are unrelated to the output vlaues (as per TRM),
+	 * So when an EMIO pin is set as an output, reading the DATA_RO register will not return the
+	 * actual value being output.
+	 */
+	if(zynq_gpio_get_function(dev,gpio)==GPIOF_OUTPUT){
+		if (bank_num <= 1) {
+			data = readl(platdata->base +
+					ZYNQ_GPIO_DATA_RO_OFFSET(bank_num));
+		} else {
+			data = readl(platdata->base +
+					ZYNQ_GPIO_DATA_OFFSET(bank_num));
+		}
+	}else{
+		data = readl(platdata->base +
+				ZYNQ_GPIO_DATA_RO_OFFSET(bank_num));
+	}
 	return (data >> bank_pin_num) & 1;
 }
 
@@ -326,26 +360,6 @@ static int zynq_gpio_direction_output(struct udevice *dev, unsigned gpio,
 	return 0;
 }
 
-static int zynq_gpio_get_function(struct udevice *dev, unsigned offset)
-{
-	u32 reg;
-	unsigned int bank_num, bank_pin_num;
-	struct zynq_gpio_platdata *platdata = dev_get_platdata(dev);
-
-	if (check_gpio(offset, dev) < 0)
-		return -1;
-
-	zynq_gpio_get_bank_pin(offset, &bank_num, &bank_pin_num, dev);
-
-	/* set the GPIO pin as output */
-	reg = readl(platdata->base + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
-	reg &= BIT(bank_pin_num);
-	if (reg)
-		return GPIOF_OUTPUT;
-	else
-		return GPIOF_INPUT;
-}
-
 static const struct dm_gpio_ops gpio_zynq_ops = {
 	.direction_input	= zynq_gpio_direction_input,
 	.direction_output	= zynq_gpio_direction_output,
-- 
2.17.1