diff -ruN uart/Makefile uart_modified/Makefile
--- uart/Makefile	2024-05-10 18:48:54.596071439 +0530
+++ uart_modified/Makefile	2024-05-10 19:41:26.877092809 +0530
@@ -29,6 +29,7 @@
 OBJS +=build/main.o
 OBJS +=build/mmu_cfg.o
 OBJS +=build/uart.o
+OBJS +=build/io.o
 
 # From ../mmu
 OBJS +=build/mmu.o
diff -ruN uart/src/demo.h uart_modified/src/demo.h
--- uart/src/demo.h	2024-05-10 18:48:54.596071439 +0530
+++ uart_modified/src/demo.h	2024-05-10 19:41:57.137767412 +0530
@@ -1,6 +1,5 @@
 /* uart.c */
 void uart_putchar(uint8_t c);
-void uart_puts(const char* str);
 void uart_puthex(uint64_t v);
 uint32_t uart_read_bytes(uint8_t *buf, uint32_t length);
 void uart_init(void);
diff -ruN uart/src/io.c uart_modified/src/io.c
--- uart/src/io.c	1970-01-01 05:30:00.000000000 +0530
+++ uart_modified/src/io.c	2024-05-11 22:27:45.605269579 +0530
@@ -0,0 +1,104 @@
+// GPIO
+
+enum {
+    PERIPHERAL_BASE = 0xFE000000,
+    GPFSEL0         = PERIPHERAL_BASE + 0x200000,
+    GPSET0          = PERIPHERAL_BASE + 0x20001C,
+    GPCLR0          = PERIPHERAL_BASE + 0x200028,
+    GPPUPPDN0       = PERIPHERAL_BASE + 0x2000E4
+};
+
+enum {
+    GPIO_MAX_PIN       = 53,
+    GPIO_FUNCTION_ALT5 = 2,
+};
+
+enum {
+    Pull_None = 0,
+};
+
+void mmio_write(long reg, unsigned int val)
+{ 
+    *(volatile unsigned int *)reg = val;
+}
+
+unsigned int mmio_read(long reg) { return *(volatile unsigned int *)reg; }
+
+unsigned int gpio_call(unsigned int pin_number, unsigned int value, unsigned int base, unsigned int field_size, unsigned int field_max) {
+    unsigned int field_mask = (1 << field_size) - 1;
+  
+    if (pin_number > field_max) return 0;
+    if (value > field_mask) return 0; 
+
+    unsigned int num_fields = 32 / field_size;
+    unsigned int reg = base + ((pin_number / num_fields) * 4);
+    unsigned int shift = (pin_number % num_fields) * field_size;
+
+    unsigned int curval = mmio_read(reg);
+    curval &= ~(field_mask << shift);
+    curval |= value << shift;
+    mmio_write(reg, curval);
+
+    return 1;
+}
+
+unsigned int gpio_set     (unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPSET0, 1, GPIO_MAX_PIN); }
+unsigned int gpio_clear   (unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPCLR0, 1, GPIO_MAX_PIN); }
+unsigned int gpio_pull    (unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPPUPPDN0, 2, GPIO_MAX_PIN); }
+unsigned int gpio_function(unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPFSEL0, 3, GPIO_MAX_PIN); }
+
+void gpio_useAsAlt5(unsigned int pin_number) {
+    gpio_pull(pin_number, Pull_None);
+    gpio_function(pin_number, GPIO_FUNCTION_ALT5);
+}
+
+// UART
+
+enum {
+    AUX_BASE        = PERIPHERAL_BASE + 0x215000,
+    AUX_ENABLES     = AUX_BASE + 4,
+    AUX_MU_IO_REG   = AUX_BASE + 64,
+    AUX_MU_IER_REG  = AUX_BASE + 68,
+    AUX_MU_IIR_REG  = AUX_BASE + 72,
+    AUX_MU_LCR_REG  = AUX_BASE + 76,
+    AUX_MU_MCR_REG  = AUX_BASE + 80,
+    AUX_MU_LSR_REG  = AUX_BASE + 84,
+    AUX_MU_CNTL_REG = AUX_BASE + 96,
+    AUX_MU_BAUD_REG = AUX_BASE + 104,
+    AUX_UART_CLOCK  = 500000000,
+    UART_MAX_QUEUE  = 16 * 1024
+};
+
+#define AUX_MU_BAUD(baud) ((AUX_UART_CLOCK/(baud*8))-1)
+
+void uart_init() {
+    mmio_write(AUX_ENABLES, 1); //enable UART1
+    mmio_write(AUX_MU_IER_REG, 0);
+    mmio_write(AUX_MU_CNTL_REG, 0);
+    mmio_write(AUX_MU_LCR_REG, 3); //8 bits
+    mmio_write(AUX_MU_MCR_REG, 0);
+    mmio_write(AUX_MU_IER_REG, 0);
+    mmio_write(AUX_MU_IIR_REG, 0xC6); //disable interrupts
+    mmio_write(AUX_MU_BAUD_REG, AUX_MU_BAUD(115200));
+    gpio_useAsAlt5(14);
+    gpio_useAsAlt5(15);
+    mmio_write(AUX_MU_CNTL_REG, 3); //enable RX/TX
+}
+
+unsigned int uart_isWriteByteReady()
+{
+    return mmio_read(AUX_MU_LSR_REG) & 0x20;
+}
+
+void uart_writeByteBlockingActual(unsigned char ch) {
+    while (!uart_isWriteByteReady()); 
+    mmio_write(AUX_MU_IO_REG, (unsigned int)ch);
+}
+
+void uart_writeText(char *buffer) {
+    while (*buffer) {
+       if (*buffer == '\n') uart_writeByteBlockingActual('\r');
+       uart_writeByteBlockingActual(*buffer++);
+    }
+}
+
diff -ruN uart/src/io.h uart_modified/src/io.h
--- uart/src/io.h	1970-01-01 05:30:00.000000000 +0530
+++ uart_modified/src/io.h	2024-05-11 22:27:58.197281700 +0530
@@ -0,0 +1,2 @@
+void uart_init();
+void uart_writeText(char *buffer);
diff -ruN uart/src/main.c uart_modified/src/main.c
--- uart/src/main.c	2024-05-10 18:48:54.596071439 +0530
+++ uart_modified/src/main.c	2024-05-10 19:58:23.850314281 +0530
@@ -8,6 +8,7 @@
 #include "semphr.h"
 
 #include "uart.h"
+#include "io.h"
 
 /* 
  * Prototypes for the standard FreeRTOS callback/hook functions implemented
@@ -29,9 +30,9 @@
 
     for( ;; )
     {
-        uart_puts("\r\n");
+        uart_writeText("\r\n");
         uart_puthex(xTaskGetTickCount());
-        uart_puts("\r\n");
+        uart_writeText("\r\n");
         vTaskDelay(1000 / portTICK_RATE_MS);
     }
 
@@ -50,7 +51,7 @@
 
     len = uart_read_bytes(buf, sizeof(buf) - 1);
     if (len)
-        uart_puts((char *)buf);
+        uart_writeText((char *)buf);
 
     return;
 }
@@ -61,10 +62,10 @@
     TaskHandle_t task_a;
 
     uart_init();
-    uart_puts("\r\n****************************\r\n");
-    uart_puts("\r\n    FreeRTOS UART Sample\r\n");
-    uart_puts("\r\n  (This sample uses UART2)\r\n");
-    uart_puts("\r\n****************************\r\n");
+    uart_writeText("\r\n****************************\r\n");
+    uart_writeText("\r\n    FreeRTOS UART Sample\r\n");
+    uart_writeText("\r\n  (This sample uses UART2)\r\n");
+    uart_writeText("\r\n****************************\r\n");
 
     xTaskCreate(TaskA, "Task A", 512, NULL, 0x10, &task_a);
 
diff -ruN uart/src/uart.c uart_modified/src/uart.c
--- uart/src/uart.c	2024-05-10 18:48:54.596071439 +0530
+++ uart_modified/src/uart.c	2024-05-11 22:25:20.533039351 +0530
@@ -53,13 +53,6 @@
 }
 /*-----------------------------------------------------------*/
 
-void uart_puts(const char* str)
-{
-    for (size_t i = 0; str[i] != '\0'; i ++)
-        uart_putchar((uint8_t)str[i]);
-}
-/*-----------------------------------------------------------*/
-
 void uart_puthex(uint64_t v)
 {
     const char *hexdigits = "0123456789ABCDEF";
@@ -91,50 +84,3 @@
 }
 /*-----------------------------------------------------------*/
 
-/* 
- * wait_linux()
- * This is a busy loop function to wait until Linux completes GIC initialization
- */
-static void wait_linux(void)
-{
-    wait_gic_init();
-    return;
-}
-/*-----------------------------------------------------------*/
-
-void uart_init(void)
-{
-    uint32_t r;
-
-    /* GPIO0 GPIO1 settings for UART2 */
-    r = GPFSEL0;
-    r &= ~((0x7U << 3) | 0x7U);
-    r |= ((0x3U << 3) | 0x3U); /* ALT4 */
-    GPFSEL0 = r;
-
-    r = GPIO_PUP_PDN_CNTRL_REG0;
-    r &= ~((0x3U << 2) | 0x3U);
-    GPIO_PUP_PDN_CNTRL_REG0 = r;
-
-    /* PL011 settings with assumption of 48MHz clock */
-    UART_ICR  = 0x7FFU;         /* Clears an interrupt */
-    UART_IBRD = 0x1AU;          /* 115200 baud */
-    UART_FBRD = 0x3U;
-    UART_LCRH = ((0x3U << 5) | (0x0U << 4));    /* 8/n/1, FIFO disabled */
-    UART_IMSC = (0x1U << 4);    /* RX interrupt enabled */
-    UART_CR   = 0x301;          /* Enables Tx, Rx and UART */
-    asm volatile ("isb");
-
-    uartctl = pvPortMalloc(sizeof (struct UARTCTL));
-    uartctl->tx_mux = xSemaphoreCreateMutex();
-    uartctl->rx_queue = xQueueCreate(16, sizeof (uint8_t));
-
-#if defined(__LINUX__)
-    uart_puts("\r\nWaiting until Linux starts booting up ...\r\n");
-    wait_linux();
-#endif
-
-    isr_register(IRQ_VC_UART, UART_PRIORITY, (0x1U << 0x3U), uart_isr);
-    return;
-}
-/*-----------------------------------------------------------*/
diff -ruN uart/src/uart.h uart_modified/src/uart.h
--- uart/src/uart.h	2024-05-10 18:48:54.596071439 +0530
+++ uart_modified/src/uart.h	2024-05-11 22:26:49.505202122 +0530
@@ -1,7 +1,6 @@
 #define UART_PRIORITY (0xA0)
 
 void uart_putchar(uint8_t c);
-void uart_puts(const char* str);
 void uart_puthex(uint64_t v);
 uint32_t uart_read_bytes(uint8_t *buf, uint32_t length);
 void uart_init(void);
