zynq uboot下控制gpio

zynq (7020/ultrascale+)uboot下控制gpio

在制作bsp的过程中 经常需要对外设在操作 初始化之前进行复位操作

当然可以在fsbl中进行操作,但是这样可能 每一次进行vivado的更新后都要进行fsbl的更新

所以这里我在zynq的uboot中做了gpio的部分控制


git diff board/xilinx/zynqmp/zynqmp.c
diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c
index 9883ad2..4db760a 100644
--- a/board/xilinx/zynqmp/zynqmp.c
+++ b/board/xilinx/zynqmp/zynqmp.c
@@ -408,6 +408,169 @@ void reset_cpu(ulong addr)
 {
 }
 
+/**
+ * @brief copy from zynq_gpio.c
+ * 
+ */
+
+#define ZYNQ_GPIO_DATA_LSW_OFFSET(BANK)        (0x000 + (8 * BANK))
+/* MSW Mask & Data -WO */
+#define ZYNQ_GPIO_DATA_MSW_OFFSET(BANK)        (0x004 + (8 * BANK))
+/* Data Register-RW */
+#define ZYNQ_GPIO_DATA_RO_OFFSET(BANK) (0x060 + (4 * BANK))
+/* Direction mode reg-RW */
+#define ZYNQ_GPIO_DIRM_OFFSET(BANK)    (0x204 + (0x40 * BANK))
+/* Output enable reg-RW */
+#define ZYNQ_GPIO_OUTEN_OFFSET(BANK)   (0x208 + (0x40 * BANK))
+/* Interrupt mask reg-RO */
+#define ZYNQ_GPIO_INTMASK_OFFSET(BANK) (0x20C + (0x40 * BANK))
+/* Interrupt enable reg-WO */
+#define ZYNQ_GPIO_INTEN_OFFSET(BANK)   (0x210 + (0x40 * BANK))
+/* Interrupt disable reg-WO */
+#define ZYNQ_GPIO_INTDIS_OFFSET(BANK)  (0x214 + (0x40 * BANK))
+/* Interrupt status reg-RO */
+#define ZYNQ_GPIO_INTSTS_OFFSET(BANK)  (0x218 + (0x40 * BANK))
+/* Interrupt type reg-RW */
+#define ZYNQ_GPIO_INTTYPE_OFFSET(BANK) (0x21C + (0x40 * BANK))
+/* Interrupt polarity reg-RW */
+#define ZYNQ_GPIO_INTPOL_OFFSET(BANK)  (0x220 + (0x40 * BANK))
+/* Interrupt on any, reg-RW */
+#define ZYNQ_GPIO_INTANY_OFFSET(BANK)  (0x224 + (0x40 * BANK))
+/* Mid pin number of a bank */
+#define ZYNQ_GPIO_MID_PIN_NUM 16
+/* GPIO upper 16 bit mask */
+#define ZYNQ_GPIO_UPPER_MASK 0xFFFF0000
+/**
+ * @brief copy and modify from fsbl
+ * 
+ * @param pin_num 
+ * @param bank_num 
+ * @param bank_pin_num 
+ */
+void zynq_gpio_get_bank_pin(unsigned int pin_num, unsigned int *bank_num, unsigned int *bank_pin_num )
+{
+       unsigned int gpio_pin_table[6] = {0};
+       
+
+       if (1) //暂时只增加zynqmp的
+       {
+               /*
+                * This structure defines the mapping of the pin numbers to the banks when
+                * the driver APIs are used for working on the individual pins.
+                */
+
+               gpio_pin_table[0] = (unsigned int)25; /* 0 - 25, Bank 0 */
+               gpio_pin_table[1] = (unsigned int)51; /* 26 - 51, Bank 1 */
+               gpio_pin_table[2] = (unsigned int)77; /* 52 - 77, Bank 2 */
+               gpio_pin_table[3] = (unsigned int)109; /* 78 - 109, Bank 3 */
+               gpio_pin_table[4] = (unsigned int)141; /* 110 - 141, Bank 4 */
+               gpio_pin_table[5] = (unsigned int)173; /* 142 - 173 Bank 5 */
+
+               *bank_num = 0U;
+               while (*bank_num < 6U) {
+                       if (pin_num <= gpio_pin_table[*bank_num]) {
+                               break;
+                       }
+                       (*bank_num)++;
+               }
+       } 
+       if (*bank_num == (unsigned char)0) {
+               *bank_pin_num = pin_num;
+       } else {
+               *bank_pin_num = (unsigned char)((unsigned int)pin_num %
+                                       (gpio_pin_table[*bank_num - (unsigned char)1] + (unsigned int)1));
+       }
+}
+
+#define ZYNQ_GPIO_BASEADDR 0xFF0A0000
+#define ZYNQ_GPIO_HIGHADDR 0xFF0AFFFF
+
+
+static int zynq_gpio_direction_output(unsigned pin, int direction)
+{
+       u32 reg;
+       unsigned int bank_num, bank_pin_num;
+
+       zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
+
+       /* set the GPIO pin as output */
+       reg = readl(ZYNQ_GPIO_BASEADDR + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
+       if (direction!=(u32)0) { /*  Output Direction */
+               reg |= ((u32)1 << (u32)bank_pin_num);
+       } else { /* Input Direction */
+               reg &= ~ ((u32)1 << (u32)bank_pin_num);
+       }
+       writel(reg, ZYNQ_GPIO_BASEADDR + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
+       return 0;
+}
+
+static int zynq_gpio_enable_output(unsigned pin, int value)
+{
+       u32 reg;
+       unsigned int bank_num, bank_pin_num;
+
+       zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
+
+       /* set the GPIO pin as output */
+       reg = readl(ZYNQ_GPIO_BASEADDR + ZYNQ_GPIO_OUTEN_OFFSET(bank_num));
+       if (value!=(u32)0) { /*  Output Direction */
+               reg |= ((u32)1 << (u32)bank_pin_num);
+       } else { /* Input Direction */
+               reg &= ~ ((u32)1 << (u32)bank_pin_num);
+       }
+       writel(reg, ZYNQ_GPIO_BASEADDR + ZYNQ_GPIO_OUTEN_OFFSET(bank_num));
+       return 0;
+}
+
+static int zynq_gpio_set_value(unsigned pin, int value)
+{
+       unsigned int reg_offset, bank_num, bank_pin_num;
+
+
+       zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
+
+       if (bank_pin_num >= ZYNQ_GPIO_MID_PIN_NUM) {
+               /* only 16 data bits in bit maskable reg */
+               bank_pin_num -= ZYNQ_GPIO_MID_PIN_NUM;
+               reg_offset = ZYNQ_GPIO_DATA_MSW_OFFSET(bank_num);
+       } else {
+               reg_offset = ZYNQ_GPIO_DATA_LSW_OFFSET(bank_num);
+       }
+
+       /*
+        * get the 32 bit value to be written to the mask/data register where
+        * the upper 16 bits is the mask and lower 16 bits is the data
+        */
+       value = !!value;
+       value = ~(1 << (bank_pin_num + ZYNQ_GPIO_MID_PIN_NUM)) &
+               ((value << bank_pin_num) | ZYNQ_GPIO_UPPER_MASK);
+
+       writel(value, ZYNQ_GPIO_BASEADDR + reg_offset);
+
+       return 0;
+}
+
+int board_reset_init()
+{
+       printf("board_reset_init will do \r\n");
+       zynq_gpio_direction_output(45, 1);
+       zynq_gpio_enable_output(45, 1);
+       zynq_gpio_set_value(45, 0);
+       udelay(500000);
+       zynq_gpio_set_value(45, 1);
+       zynq_gpio_direction_output(78, 1);
+       zynq_gpio_enable_output(78, 1);
+       zynq_gpio_set_value(78, 0);
+       udelay(500000);
+       zynq_gpio_set_value(78, 1);
+} 
+
 int board_late_init(void)
 {
        u32 ver, reg = 0;
@@ -512,7 +675,7 @@ int board_late_init(void)
        }
 
        env_set("boot_targets", new_targets);
-
+       board_reset_init();
        return 0;
 }
 
(END)

gpio侧关于mio/emio的pin脚说明将在另一篇博客中说明

posted @ 2022-04-27 10:11  tccxy  阅读(668)  评论(0编辑  收藏  举报