wolfBoot/hal/raspi3.c

379 lines
9.5 KiB
C

/* raspi3.c
*
* Copyright (C) 2021 wolfSSL Inc.
*
* This file is part of wolfBoot.
*
* wolfBoot is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <target.h>
#include "image.h"
#include "printf.h"
#ifndef ARCH_AARCH64
# error "wolfBoot raspi3 HAL: wrong architecture selected. Please compile with ARCH=AARCH64."
#endif
#define TEST_ENCRYPT
#if defined(DEBUG_UART)
#define PRINTF_ENABLED
#endif
#define CORTEXA53_0_CPU_CLK_FREQ_HZ 1099989014
#define CORTEXA53_0_TIMESTAMP_CLK_FREQ 99998999
#define MMIO_BASE 0x3F000000
#define GPIO_BASE MMIO_BASE + 0x200000
#define GPFSEL1 ((volatile unsigned int*)(GPIO_BASE+0x04))
#define GPPUD ((volatile unsigned int*)(GPIO_BASE+0x94))
#define GPPUDCLK0 ((volatile unsigned int*)(GPIO_BASE+0x98))
/* PL011 UART registers */
#define UART0_BASE GPIO_BASE + 0x1000
#define UART0_DR ((volatile unsigned int*)(UART0_BASE+0x00))
#define UART0_FR ((volatile unsigned int*)(UART0_BASE+0x18))
#define UART0_IBRD ((volatile unsigned int*)(UART0_BASE+0x24))
#define UART0_FBRD ((volatile unsigned int*)(UART0_BASE+0x28))
#define UART0_LCRH ((volatile unsigned int*)(UART0_BASE+0x2C))
#define UART0_CR ((volatile unsigned int*)(UART0_BASE+0x30))
#define UART0_IMSC ((volatile unsigned int*)(UART0_BASE+0x38))
#define UART0_ICR ((volatile unsigned int*)(UART0_BASE+0x44))
/* mail box message buffer */
volatile unsigned int __attribute__((aligned(16))) mbox[36];
#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880)
#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0))
#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10))
#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14))
#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18))
#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C))
#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20))
#define MBOX_RESPONSE 0x80000000
#define MBOX_FULL 0x80000000
#define MBOX_EMPTY 0x40000000
#define MBOX_REQUEST 0
/* channels */
#define MBOX_CH_POWER 0
#define MBOX_CH_FB 1
#define MBOX_CH_VUART 2
#define MBOX_CH_VCHIQ 3
#define MBOX_CH_LEDS 4
#define MBOX_CH_BTNS 5
#define MBOX_CH_TOUCH 6
#define MBOX_CH_COUNT 7
#define MBOX_CH_PROP 8
/* tags */
#define MBOX_TAG_GETBRDVERSION 0x10002
#define MBOX_TAG_GETSERIAL 0x10004
#define MBOX_TAG_GET_CLOCK_RATE 0x30002
#define MBOX_TAG_SETCLKRATE 0x38002
#define MBOX_TAG_LAST 0
/* Fixed addresses */
extern void *kernel_addr, *update_addr, *dts_addr;
/* Loop <delay> times */
static inline void delay(int32_t count)
{
register unsigned int c;
c = count;
while (c--) {
asm volatile("nop");
}
}
/**
* write message to mailbox
*/
static void mailbox_write(uint8_t chan)
{
uint32_t ch = (((uint32_t)((unsigned long)&mbox) & ~0xf)
| (chan & 0xf));
/* wait until mail box becomes ready to write */
while ((*MBOX_STATUS & MBOX_FULL) != 0) { }
/* write the address of the message to mail-box channel */
*MBOX_WRITE = ch;
}
/**
* read message from mailbox
*/
static int mailbox_read(uint8_t chan)
{
uint32_t ch = (((uint32_t)((unsigned long)&mbox) & ~0xf)
| (chan & 0xf));
/* now wait for the response */
while(1) {
while ((*MBOX_STATUS & MBOX_EMPTY) != 0) { }
if(ch == *MBOX_READ)
/* is it a valid successful response */
return mbox[1] == MBOX_RESPONSE;
}
return 0;
}
/* UART functions for Raspberry Pi 3 UART */
void uart_tx(char c)
{
/* wait until uart channel is ready to send */
do{
asm volatile("nop");
} while(*UART0_FR & 0x20);
*UART0_DR = c;
}
char uart_read(void)
{
char c;
/* wait until data is comming */
do{
asm volatile("nop");
} while(*UART0_FR & 0x10);
/* read it and return */
c = (char)(*UART0_DR);
return c;
}
/**
* Send string to UART
*/
void uart_write(const char* buf, uint32_t sz) {
uint32_t len = sz;
while (len > 0 && *buf) {
uart_tx(*buf++);
len--;
}
}
void uart_init()
{
register unsigned int c;
/* initialize UART. turn off UART 0*/
*UART0_CR = 0;
/* set up clock for consistent divisor values */
mbox[0] = 9 * 4;
mbox[1] = MBOX_REQUEST;
/* tag for setting clock rate */
mbox[2] = MBOX_TAG_SETCLKRATE;
mbox[3] = 12;
mbox[4] = 8;
/* specify UART clock channel */
mbox[5] = 2;
/* UART clock rate in hz(4Mhz)*/
mbox[6] = 4000000;
/* not use turbo */
mbox[7] = 0;
mbox[8] = MBOX_TAG_LAST;
mailbox_write(MBOX_CH_PROP);
mailbox_read(MBOX_CH_PROP);
/* disable pull up/down for all GPIO pins */
*GPPUD = 0;
delay(150);
/* Disable pull up/down for pin 14 and 15 */
*GPPUDCLK0 = (1<<14)|(1<<15);
delay(150);
/* flush GPIO setting to make it take effect */
*GPPUDCLK0 = 0;
/* clear pending interrupts */
*UART0_ICR = 0x7FF;
/* select 115200 baud rate */
/* divider = 4000000 / (16 * 115200) = 2.17 = ~2 */
*UART0_IBRD = 2;
/* Fractional part register = (.17013 * 64) + 0.5 = 11.38 = ~11 */
*UART0_FBRD = 0xB;
/* Enable fifo, 8bit data transmission (1 stop bit, no parity) */
*UART0_LCRH = (1 << 4) | (1 << 5) | (1 << 6);
/* enable UART0 transfer & receive*/
*UART0_CR = (1 << 0) | (1 << 8) | (1 << 9);
}
void* hal_get_primary_address(void)
{
return (void*)&kernel_addr;
}
void* hal_get_update_address(void)
{
return (void*)&update_addr;
}
void* hal_get_dts_address(void)
{
return (void*)&dts_addr;
}
#ifdef EXT_FLASH
int ext_flash_read(unsigned long address, uint8_t *data, int len)
{
XMEMCPY(data, (void *)address, len);
return len;
}
int ext_flash_erase(unsigned long address, int len)
{
XMEMSET((void *)address, 0xFF, len);
return len;
}
int ext_flash_write(unsigned long address, const uint8_t *data, int len)
{
XMEMCPY((void *)address, data, len);
return len;
}
void ext_flash_lock(void)
{
}
void ext_flash_unlock(void)
{
}
#endif
void* hal_get_dts_update_address(void)
{
return NULL; /* Not yet supported */
}
/* QSPI functions */
void qspi_init(uint32_t cpu_clock, uint32_t flash_freq)
{
}
void zynq_init(uint32_t cpu_clock)
{
}
#if defined(DISPLAY_CLOCKS)
static uint32_t getclocks(uint8_t cid)
{
/* Retrive clock rate */
/* length of the message */
mbox[0] = 8 * 4;
mbox[1] = MBOX_REQUEST;
/* tag for get board version */
mbox[2] = MBOX_TAG_GET_CLOCK_RATE;
/* buffer size */
mbox[3] = 8;
mbox[4] = 8;
/* clock id CORE*/
mbox[5] = cid;
/* clock frequency */
mbox[6] = 0;
mbox[7] = MBOX_TAG_LAST;
mailbox_write(MBOX_CH_PROP);
if (mailbox_read(MBOX_CH_PROP)) {
return mbox[6];
}
else {
return 0;
}
}
#endif /* DISPLAY clocks */
/* public HAL functions */
void hal_init(void)
{
#if defined(TEST_ENCRYPT) && defined (EXT_ENCRYPTED)
char enc_key[] = "0123456789abcdef0123456789abcdef"
"0123456789abcdef";
wolfBoot_set_encrypt_key((uint8_t *)enc_key,(uint8_t *)(enc_key + 32));
#endif
uart_init();
/* length of the message */
mbox[0] = 7 * 4;
mbox[1] = MBOX_REQUEST;
/* tag for get board version */
mbox[2] = MBOX_TAG_GETBRDVERSION;
/* buffer size */
mbox[3] = 4;
mbox[4] = 0;
mbox[5] = 0;
mbox[6] = MBOX_TAG_LAST;
/* send the message to the GPU */
mailbox_write(MBOX_CH_PROP);
if (mailbox_read(MBOX_CH_PROP)) {
wolfBoot_printf("My board version is: 0x%08x", mbox[5]);
wolfBoot_printf("\n");
} else {
wolfBoot_printf("Unable to query board version!\n");
}
#if defined(DISPLAY_CLOCKS) && defined(PRINTF_ENABLED)
/* Get clocks */
wolfBoot_printf("\n EMMC clock : %d Hz", getclocks(1));
wolfBoot_printf("\n UART clock : %d Hz", getclocks(2));
wolfBoot_printf("\n ARM clock : %d Hz", getclocks(3));
wolfBoot_printf("\n CORE clock : %d Hz", getclocks(4));
wolfBoot_printf("\n V3D clock : %d Hz", getclocks(5));
wolfBoot_printf("\n H264 clock : %d Hz", getclocks(6));
wolfBoot_printf("\n ISP clock : %d Hz", getclocks(7));
wolfBoot_printf("\n SDRAM clock : %d Hz", getclocks(8));
wolfBoot_printf("\n PIXEL clock : %d Hz", getclocks(9));
wolfBoot_printf("\n PWM clock : %d Hz", getclocks(10));
wolfBoot_printf("\n HEVC clock : %d Hz", getclocks(11));
wolfBoot_printf("\n EMMC2 clock : %d Hz", getclocks(12));
wolfBoot_printf("\n M2MC clock : %d Hz", getclocks(13));
wolfBoot_printf("\n PIXEL_BVB clock : %d Hz\n", getclocks(14));
#endif
}
void hal_prepare_boot(void)
{
}
int RAMFUNCTION hal_flash_write(uintptr_t address, const uint8_t *data, int len)
{
return 0;
}
void RAMFUNCTION hal_flash_unlock(void)
{
}
void RAMFUNCTION hal_flash_lock(void)
{
}
int RAMFUNCTION hal_flash_erase(uintptr_t address, int len)
{
return 0;
}