bao-project / bao-demos

A guide on how to build and use a set of Bao guest configurations for various platforms
Other
33 stars 37 forks source link

rpi4: freertos+Linux: add gpio driver for freertos and fail to set gpio output level #4

Closed giraffesnn closed 2 years ago

giraffesnn commented 2 years ago

export PLATFORM=rpi4 export DEMO=linux+freertos

Based on your demo, I would like to try adding gpio peripherals for the freertos guest. Firstly, I added the gpio register resources to demos/linux+freertos/configs/rpi4.c.

diff --git a/demos/linux+freertos/configs/rpi4.c b/demos/linux+freertos/configs/rpi4.c
index e9a6b03..be0476c 100755
--- a/demos/linux+freertos/configs/rpi4.c
+++ b/demos/linux+freertos/configs/rpi4.c
@@ -104,7 +104,7 @@ struct config config = {
                     }
                 },

-                .dev_num = 2,
+                .dev_num = 3,
                 .devs =  (struct dev_region[]) {
                     {
                         /* UART1 */
@@ -119,6 +119,12 @@ struct config config = {
                         .interrupt_num = 1,
                         .interrupts =
                             (uint64_t[]) {27}
+                    },
+           {
+           /* GPIO */
+           .pa = 0x7e200000,
+           .va = 0x7e200000,
+           .size = 0x1000,
            }
                },

Then, I ported the gpio driver from arm-trusted-firmware.

diff --git a/src/platform/rpi4/rpi4.c b/src/platform/rpi4/rpi4.c
index 7e967f9..efef171 100644
--- a/src/platform/rpi4/rpi4.c
+++ b/src/platform/rpi4/rpi4.c
@@ -1,4 +1,5 @@
 #include <8250_uart.h>
+#include <gpio.h>

 #define VIRT_UART16550_ADDR            0xfe215040
 #define VIRT_UART_BAUDRATE         115200
@@ -28,3 +29,150 @@ void uart_clear_rxirq()
 {
     uart8250_interrupt_handler();
 }
+
+#define RPI4_GPIO_BASEADDR      0x7e200000UL
+
+#define RPI4_GPIO_GPFSEL(n)     ((n) * (0x04))
+#define RPI4_GPIO_GPSET(n)      (((n) * (0x04)) + (0x1C))
+#define RPI4_GPIO_GPCLR(n)      (((n) * (0x04)) + (0x28))
+#define RPI4_GPIO_GPLEV(n)      (((n) * (0x04)) + (0x34))
+#define RPI4_GPIO_PUP_PDN(n)    ((n) * (0x04) + (0xe4))
+
+static uintptr_t reg_base = RPI4_GPIO_BASEADDR;
+
+static void mmio_write_32(uintptr_t addr, uint32_t value)
+{
+   *(volatile uint32_t*)addr = value;
+}
+
+static uint32_t mmio_read_32(uintptr_t addr)
+{
+   return *(volatile uint32_t*)addr;
+}
+
+/**
+ * Get selection of GPIO pinmux settings.
+ *
+ * @param gpio The pin number of GPIO. From 0 to 53.
+ * @return The selection of pinmux. RPI4_GPIO_FUNC_INPUT: input,
+ *                                  RPI4_GPIO_FUNC_OUTPUT: output,
+ *                                  RPI4_GPIO_FUNC_ALT0: alt-0,
+ *                                  RPI4_GPIO_FUNC_ALT1: alt-1,
+ *                                  RPI4_GPIO_FUNC_ALT2: alt-2,
+ *                                  RPI4_GPIO_FUNC_ALT3: alt-3,
+ *                                  RPI4_GPIO_FUNC_ALT4: alt-4,
+ *                                  RPI4_GPIO_FUNC_ALT5: alt-5
+ */
+int rpi4_gpio_get_select(int gpio)
+{
+   int ret;
+   int regN = gpio / 10;
+   int shift = 3 * (gpio % 10);
+   uintptr_t reg_sel = reg_base + RPI4_GPIO_GPFSEL(regN);
+   uint32_t sel = mmio_read_32(reg_sel);
+
+   ret = (sel >> shift) & 0x07;
+
+   return ret;
+}
+
+/**
+ * Set selection of GPIO pinmux settings.
+ *
+ * @param gpio The pin number of GPIO. From 0 to 53.
+ * @param fsel The selection of pinmux. RPI4_GPIO_FUNC_INPUT: input,
+ *                                      RPI4_GPIO_FUNC_OUTPUT: output,
+ *                                      RPI4_GPIO_FUNC_ALT0: alt-0,
+ *                                      RPI4_GPIO_FUNC_ALT1: alt-1,
+ *                                      RPI4_GPIO_FUNC_ALT2: alt-2,
+ *                                      RPI4_GPIO_FUNC_ALT3: alt-3,
+ *                                      RPI4_GPIO_FUNC_ALT4: alt-4,
+ *                                      RPI4_GPIO_FUNC_ALT5: alt-5
+ */
+void rpi4_gpio_set_select(int gpio, int fsel)
+{
+   int regN = gpio / 10;
+   int shift = 3 * (gpio % 10);
+   uintptr_t reg_sel = reg_base + RPI4_GPIO_GPFSEL(regN);
+   uint32_t sel = mmio_read_32(reg_sel);
+   uint32_t mask = (0x07) << shift;
+
+   sel = (sel & (~mask)) | ((fsel << shift) & mask);
+   mmio_write_32(reg_sel, sel);
+}
+
+int rpi4_gpio_get_direction(int gpio)
+{
+   int result = rpi4_gpio_get_select(gpio);
+
+   if (result == RPI4_GPIO_FUNC_INPUT)
+       return GPIO_DIR_IN;
+   else if (result == RPI4_GPIO_FUNC_OUTPUT)
+       return GPIO_DIR_OUT;
+
+   return GPIO_DIR_IN;
+}
+
+void rpi4_gpio_set_direction(int gpio, int direction)
+{
+   switch (direction) {
+   case GPIO_DIR_IN:
+       rpi4_gpio_set_select(gpio, RPI4_GPIO_FUNC_INPUT);
+       break;
+   case GPIO_DIR_OUT:
+       rpi4_gpio_set_select(gpio, RPI4_GPIO_FUNC_OUTPUT);
+       break;
+   }
+}
+
+int rpi4_gpio_get_value(int gpio)
+{
+   int regN = gpio / 32;
+   int shift = gpio % 32;
+   uintptr_t reg_lev = reg_base + RPI4_GPIO_GPLEV(regN);
+   uint32_t value = mmio_read_32(reg_lev);
+
+   if ((value >> shift) & 0x01)
+       return GPIO_LEVEL_HIGH;
+   return GPIO_LEVEL_LOW;
+}
+
+void rpi4_gpio_set_value(int gpio, int value)
+{
+   int regN = gpio / 32;
+   int shift = gpio % 32;
+   uintptr_t reg_set = reg_base + RPI4_GPIO_GPSET(regN);
+   uintptr_t reg_clr = reg_base + RPI4_GPIO_GPCLR(regN);
+
+   switch (value) {
+   case GPIO_LEVEL_LOW:
+       mmio_write_32(reg_clr, (1) << shift);
+       break;
+   case GPIO_LEVEL_HIGH:
+       mmio_write_32(reg_set, (1) << shift);
+       break;
+   }
+}
+
+void rpi4_gpio_set_pull(int gpio, int pull)
+{
+   int regN = gpio / 16;
+   int shift = 2 * (gpio % 16);
+   uintptr_t reg = reg_base + RPI4_GPIO_PUP_PDN(regN);
+
+   switch (pull) {
+   case GPIO_PULL_NONE:
+       mmio_write_32(reg, 0x0 << shift);
+       break;
+   case GPIO_PULL_UP:
+       mmio_write_32(reg, 0x1 << shift);
+       break;
+   case GPIO_PULL_DOWN:
+       mmio_write_32(reg, 0x2 << shift);
+       break;
+
+   default:
+       mmio_write_32(reg, 0x0);
+       break;
+   }
+}

Finally, I tested the gpio driver and found that setting the GPIO output level failed.

diff --git a/src/baremetal-runtime b/src/baremetal-runtime
--- a/src/baremetal-runtime
+++ b/src/baremetal-runtime
@@ -1 +1 @@
-Subproject commit 4fca68d4fa54fe1790f0e7a9726785d812410ec6
+Subproject commit 4fca68d4fa54fe1790f0e7a9726785d812410ec6-dirty
diff --git a/src/main.c b/src/main.c
index 99fa9ef..c1e7d42 100644
--- a/src/main.c
+++ b/src/main.c
@@ -34,6 +34,7 @@
 #include <uart.h>
 #include <irq.h>
 #include <plat.h>
+#include <gpio.h>

 /*
  * Prototypes for the standard FreeRTOS callback/hook functions implemented
@@ -92,10 +93,28 @@ void shmem_init() {
     irq_enable(SHMEM_IRQ_ID);
 }

+#define GPIO_LED      6
+static void gpio_leds_control(int gpio)
+{
+   int i;
+
+   for (i = 0; i < 31; i++) {
+       printf("rpi4: gpio%d: select = 0x%x\n", i, rpi4_gpio_get_select(i));
+       printf("rpi4: gpio%d: level = 0x%x\n", i, rpi4_gpio_get_value(i));
+   }
+   rpi4_gpio_set_pull(gpio, GPIO_PULL_DOWN);
+   rpi4_gpio_set_select(gpio, RPI4_GPIO_FUNC_OUTPUT);
+   rpi4_gpio_set_direction(gpio, GPIO_DIR_OUT);
+   printf("rpi4: gpio%d: select = 0x%x\n", gpio, rpi4_gpio_get_select(gpio));
+   rpi4_gpio_set_value(gpio, GPIO_LEVEL_LOW);
+   printf("rpi4: gpio%d: level = 0x%x\n", gpio, rpi4_gpio_get_value(gpio));
+}
+
 int main(void){

     printf("Bao FreeRTOS guest\n");

+    gpio_leds_control(GPIO_LED);
     uart_enable_rxirq();
     irq_set_handler(UART_IRQ_ID, uart_rx_handler);
     irq_set_prio(UART_IRQ_ID, IRQ_MAX_PRIO);

This is log >>>>>>>>>>>>>>> U-Boot> fatload mmc 0 0x200000 bao.bin; go 0x200000 ERROR: reserving fdt memory region failed (addr=0 size=80000) 41529344 bytes read in 1752 ms (22.6 MiB/s)

Starting application at 0x00200000 ...

Bao Hypervisor Bao FreeRTOS guest rpi4: gpio0: select = 0x7 rpi4: gpio0: level = 0x1 rpi4: gpio1: select = 0x7 rpi4: gpio1: level = 0x1 rpi4: gpio2: select = 0x7 rpi4: gpio2: level = 0x1 rpi4: gpio3: select = 0x7 rpi4: gpio3: level = 0x1 rpi4: gpio4: select = 0x7 rpi4: gpio4: level = 0x1 rpi4: gpio5: select = 0x7 rpi4: gpio5: level = 0x1 rpi4: gpio6: select = 0x7 rpi4: gpio6: level = 0x1 rpi4: gpio7: select = 0x7 rpi4: gpio7: level = 0x1 rpi4: gpio8: select = 0x7 rpi4: gpio8: level = 0x1 rpi4: gpio9: select = 0x7 rpi4: gpio9: level = 0x1 rpi4: gpio10: select = 0x7 rpi4: gpio10: level = 0x1 rpi4: gpio11: select = 0x7 rpi4: gpio11: level = 0x1 rpi4: gpio12: select = 0x7 rpi4: gpio12: level = 0x1 rpi4: gpio13: select = 0x7 rpi4: gpio13: level = 0x1 rpi4: gpio14: select = 0x7 rpi4: gpio14: level = 0x1 rpi4: gpio15: select = 0x7 rpi4: gpio15: level = 0x1 rpi4: gpio16: select = 0x7 rpi4: gpio16: level = 0x1 rpi4: gpio17: select = 0x7 rpi4: gpio17: level = 0x1 rpi4: gpio18: select = 0x7 rpi4: gpio18: level = 0x1 rpi4: gpio19: select = 0x7 rpi4: gpio19: level = 0x1 rpi4: gpio20: select = 0x7 rpi4: gpio20: level = 0x1 rpi4: gpio21: select = 0x7 rpi4: gpio21: level = 0x1 rpi4: gpio22: select = 0x7 rpi4: gpio22: level = 0x1 rpi4: gpio23: select = 0x7 rpi4: gpio23: level = 0x1 rpi4: gpio24: select = 0x7 rpi4: gpio24: level = 0x1 rpi4: gpio25: select = 0x7 rpi4: gpio25: level = 0x1 rpi4: gpio26: select = 0x7 rpi4: gpio26: level = 0x1 rpi4: gpio27: select = 0x7 rpi4: gpio27: level = 0x1 rpi4: gpio28: select = 0x7 rpi4: gpio28: level = 0x1 rpi4: gpio29: select = 0x7 rpi4: gpio29: level = 0x1 rpi4: gpio30: select = 0x7 rpi4: gpio30: level = 0x1 rpi4: gpio6: select = 0x1 rpi4: gpio6: level = 0x1 Task1: 0 Task2: 0 Task1: 1 Task2: 1 Task1: 2 ...

We can see GPIO Function Select register is successfully set. However, according to the value read from GPIO Pin Level register, GPIO Pin Output Clear register setting failed. I can't understand why this is. So asking for your help.

giraffesnn commented 2 years ago

I found the root cause, the base address of GPIO should be 0xfe200000 instead of 0x7e200000. I'm sorry, this is due to my carelessness.