diff options
Diffstat (limited to 'md')
-rw-r--r-- | md/index.md | 5 | ||||
-rw-r--r-- | md/writeup/raspberry5_baremetal_uart.md | 255 |
2 files changed, 259 insertions, 1 deletions
diff --git a/md/index.md b/md/index.md index 5b9d384..4dd1538 100644 --- a/md/index.md +++ b/md/index.md @@ -5,7 +5,10 @@ title: Writeup page ## Writeup's <!-- Test [AM modulation](writeup/am_modulation.md)--> - +[WIP] [Raspberry PI5 baremetal GPIO](writeup/raspberry5_baremetal_gpio.md) +[WIP] [GDB Python scripting](writeup/gdb_python_scripting.md) +[Raspberry PI5 baremetal UART](writeup/raspberry5_baremetal_uart.md) +[Raspberry PI5 baremetal detect board](writeup/raspberry5_baremetal_detect_board.md) [Raspberry PI5 baremetal hello world](writeup/raspberry5_baremetal_helloworld.md) [Kernel programming](notes/kernel/topics.md) [QEMU ARM64](writeup/qemu_arm64.md) diff --git a/md/writeup/raspberry5_baremetal_uart.md b/md/writeup/raspberry5_baremetal_uart.md new file mode 100644 index 0000000..f6500da --- /dev/null +++ b/md/writeup/raspberry5_baremetal_uart.md @@ -0,0 +1,255 @@ +title: Raspberry 5 baremetal UART example +keywords:raspi5,asm,c,kernel,arm64,uart,tty,serial + +# Raspberry 5 bare metal UART example + + +## Intro + +As base can check the [/writeup/raspberry5_baremetal_helloworld.md](/writeup/raspberry5_baremetal_helloworld.md) + + +Getting basic communication for Raspberry 5 UART bare metal. + +## Enabling UART + +To find out MMIO base for UART, first step to set flag so +PCIe bus doesn't reset UART, + +``` +enable_rp1_uart=1 +``` + +if flag is set then UART will output string +``` +RP1_UART 0000001c00030000 +``` + +where MMIO base is + +```c +#define MMIO_BASE 0x1c00000000UL +``` + +and UART base +```c +#define PL011_REG_OFFSET MMIO_BASE+0x30000 +``` + +## Configure UART + +Disable UART before configure it and then set desired settings. +This case just to set to 8 bit mode. After configuration done +enable RX/TX and UART. + +```c + //disable UART + pl011_write32(PL011_CR,0x0); + //config uart + pl011_write32(PL011_LCRH, PL011_LCRH_WLEN_8BIT); + //enable UART + pl011_write32( + PL011_CR, + PL011_CR_UARTEN|PL011_CR_TXE|PL011_CR_RXE + ); +``` + +## Sending first characters + +Sending characters is done by writing 8 bits to register DR + +```c +#define PL011_DR 0x00 /* Data read or written from the interface. */ +``` + +if just write then raspi5 will do it faster then UART can process and +characters will be lost in basic case only first 2 characters where out. +So before writing to DR check that TX FIFO is not full and wait if its full + +```c +void pl011_putc(const uint8_t c) { + while (pl011_read32(PL011_FR)&PL011_FR_TXFF); + pl011_write32(PL011_DR,c); +} +``` + +## Receiving characters + +to receive characters read register DR and to check if RX is empty +check registers FR RX FIFO Empty flag. + +```c +uint8_t pl011_getc() { + return pl011_read8(PL011_DR); +} +``` + +## Basic command line + +Here is basic echo terminal loop that echo's back characters sent over UART. +Loop checks FR register to see if RX FIFO isn't empty, and read character. +Extra processing set for Enter to output "\r\n" and move to new line + +```c +while (1) { + uint32_t rx_status = pl011_read32(PL011_FR); + //empty? if not printout + if (!(rx_status&PL011_FR_RXFE)) { + uint8_t c = pl011_read8(PL011_DR); + if (c == 0xD) { + pl011_puts("\r\n"); + } else { + pl011_write8(PL011_DR,c); + } + } + } +``` + +## Source code +For base setup check hello world example [/writeup/raspberry5_baremetal_helloworld.md](/writeup/raspberry5_baremetal_helloworld.md) + +### pl011.h +```c +#ifndef __PL011_H +#define __PL011_H + +//#include <stdint.h> + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; + +//static for now for raspi5 +#define MMIO_BASE 0x1c00000000UL +#define PL011_REG_OFFSET MMIO_BASE+0x30000 + + +#define PL011_DR 0x00 /* Data read or written from the interface. */ + +#define PL011_FR 0x18 /* Flag register (Read only). */ +#define PL011_IBRD 0x24 /* Integer baud rate divisor register. */ +#define PL011_FBRD 0x28 /* Fractional baud rate divisor register. */ +#define PL011_LCRH 0x2c /* Line control register. */ +#define PL011_CR 0x30 /* Control register. */ +#define PL011_IFLS 0x34 /* Interrupt fifo level select. */ +#define PL011_IMSC 0x38 /* Interrupt mask. */ +#define PL011_RIS 0x3c /* Raw interrupt status. */ +#define PL011_MIS 0x40 /* Masked interrupt status. */ +#define PL011_ICR 0x44 /* Interrupt clear register. */ +#define PL011_DMACR 0x48 /* DMA control register. */ + +#define PL011_FR_RXFE (1 << 4)/* RX FIFO Empty */ +#define PL011_FR_TXFF (1 << 5)/* TX FIFO full */ + +#define PL011_LCRH_WLEN_8BIT (3 << 5) /* 8bit */ + +#define PL011_CR_CTSEN (1 << 15) /* CTS hardware flow control enable */ +#define PL011_CR_RTSEN (1 << 14) /* RTS hardware flow control enable */ +#define PL011_CR_RTS (1 << 11) /* Request to send */ +#define PL011_CR_DTR (1 << 10) /* Data transmit ready. */ +#define PL011_CR_RXE (1 << 9) /* Receive enable */ +#define PL011_CR_TXE (1 << 8) /* Transmit enable */ +#define PL011_CR_LBE (1 << 7) /* Loopback enable */ +#define PL011_CR_UARTEN (1 << 0) /* UART Enable */ + +#define pl011_read8(offset) (*(volatile uint8_t *)(PL011_REG_OFFSET+offset)) +#define pl011_write8(offset,val) (*(volatile uint8_t *)(PL011_REG_OFFSET+offset)) = val +#define pl011_read32(offset) (*(volatile uint32_t *)(PL011_REG_OFFSET+offset)) +#define pl011_write32(offset,val) (*(volatile uint32_t *)(PL011_REG_OFFSET+offset)) = val + +void pl011_init(); +void pl011_putc(const uint8_t c); +void pl011_puts(const char *str); +uint8_t pl011_getc(); + +``` +### pl011.c +```c + +#include "pl011.h" + +void pl011_init() { + //disable UART + pl011_write32(PL011_CR,0x0); + //config uart + pl011_write32(PL011_LCRH, PL011_LCRH_WLEN_8BIT); + //enable UART + pl011_write32( + PL011_CR, + PL011_CR_UARTEN|PL011_CR_TXE|PL011_CR_RXE + ); +} + +void pl011_putc(const uint8_t c) { + while (pl011_read32(PL011_FR)&PL011_FR_TXFF); + pl011_write32(PL011_DR,c); +} + +void pl011_puts(const char *str) { + uint16_t cnt = 0; + while (cnt<256) { + if (str[cnt] != 0) { + pl011_putc(str[cnt]); + } else { + break; + } + cnt++; + } +} +uint8_t pl011_getc() { + return pl011_read8(PL011_DR); + +} +``` + +### kernel.c +```c +#include <pl011.h> + +void main() +{ + pl011_init(); + pl011_puts("Raspberry Pi5 UART demo?!\r\n"); + while (1) { + uint32_t rx_status = pl011_read32(PL011_FR); + //empty? if not printout + if (!(rx_status&PL011_FR_RXFE)) { + uint8_t c = pl011_read8(PL011_DR); + if (c == 0xD) { + pl011_puts("\r\n"); + } else { + pl011_write8(PL011_DR,c); + } + } + } + +} +``` + +Creating Makefile and linker script is left as exercise + +## Links +https://github.com/BarrelfishOS/barrelfish/blob/master/kernel/arch/arm/pl011.c +https://github.com/DSERIOUSGUY/HobOS/blob/main/uart.c +https://github.com/rsta2/circle/blob/master/lib/serial.cpp +https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/tty/serial/amba-pl011.c?h=v6.16-rc4 +https://developer.arm.com/documentation/ddi0183/latest/ +[/writeup/raspberry5_baremetal_helloworld.md](/writeup/raspberry5_baremetal_helloworld.md) +https://wiki.osdev.org/Detecting_Raspberry_Pi_Board +https://github.com/dwelch67/raspberrypi/tree/master/uart01 +https://github.com/bztsrc/raspi3-tutorial/blob/master/03_uart1/uart.c +https://www.rpi4os.com/part3-helloworld/ +https://www.valvers.com/open-software/raspberry-pi/bare-metal-programming-in-c-part-5/#aux-peripheral +https://github.com/valvers/arm-tutorial-rpi/tree/master/part-5 +https://jsandler18.github.io/tutorial/boot.html +https://github.com/ARM-software/arm-trusted-firmware/blob/master/plat/rpi/rpi5/include/rpi_hw.h +https://github.com/ARM-software/arm-trusted-firmware/blob/master/drivers/arm/pl011/aarch64/pl011_console.S +https://elixir.bootlin.com/linux/v6.15.5/source/include/linux/amba/serial.h#L39 +https://github.com/ARM-software/arm-trusted-firmware/blob/master/include/drivers/arm/pl011.h +[/writeup/raspberry5_baremetal_helloworld.md](/writeup/raspberry5_baremetal_helloworld.md) +https://krinkinmu.github.io/2020/11/29/PL011.html +https://forums.raspberrypi.com/viewtopic.php?t=34112 +https://datasheets.raspberrypi.com/bcm2711/bcm2711-peripherals.pdf +https://datasheets.raspberrypi.com/rp1/rp1-peripherals.pdf +https://github.com/raspberrypi/linux/blob/rpi-6.12.y/arch/arm64/boot/dts/broadcom/bcm2712.dtsi +https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf
\ No newline at end of file |