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脚说明将在另一篇博客中说明