Few fixes and Port IRQ_Forward to a component (#8)

* Remove a unnecessary delay in the nvkvs
* update readme
* port IRQ_Forward Code to a component and update d0_lowload to use it
* add USB, Ethernet and GPIO for IRQ Forwarding
This commit is contained in:
Justin Hammond 2023-02-03 14:26:58 +08:00 committed by GitHub
parent 608b99f21d
commit e36316fa13
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 348 additions and 919 deletions

View file

@ -15,10 +15,6 @@ endif()
include(${SDK_PATH}/cmake/bflbsdk.cmake)
target_sources(app PRIVATE
src/bl808_ipc.c)
target_compile_options(app PRIVATE -ggdb -Os)
sdk_add_include_directories(include)
sdk_set_main_file(src/main.c)
project(m0_lowload)

View file

@ -1,14 +0,0 @@
config LL_IRQFWD_SDH
bool "Enable IRQ forwarding for SDH"
default y
config LL_IRQFWD_UART2
bool "Enable IRQ forwarding for UART2"
default y
config LL_IRQFWD_USB
bool "Enable IRQ forwarding for USB"
default n

View file

@ -1,14 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
/*
* Copyright (C) 2023 Allen Martin <armartin@gmail.com>
*/
#ifndef __DT_BINDINGS_MAILBOX_BFLB_IPC_H
#define __DT_BINDINGS_MAILBOX_BFLB_IPC_H
/* Peripheral device ID */
#define BFLB_IPC_DEVICE_SDHCI 0
#define BFLB_IPC_DEVICE_UART2 1
#define BLFB_IPC_DEVICE_USB 2
#endif

View file

@ -1,7 +1,3 @@
CONFIG_LL_IRQFWD_SDH=y
CONFIG_LL_IRQFWD_UART2=y
# CONFIG_LL_IRQFWD_USB is not set
CONFIG_PSRAM=y
CONFIG_BFLB_CHIP="bl808"
CONFIG_BLFB_CPU_ID="m0"
CONFIG_COMPONENT_MAILBOX=y
CONFIG_COMPONENT_MAILBOX_IRQFWD_SDH=y
CONFIG_COMPONENT_MAILBOX_IRQFWD_GPIO=y

View file

@ -1,738 +0,0 @@
/**
******************************************************************************
* @file bl808_ipc.c
* @version V1.2
* @date
* @brief This file is the standard driver c file
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2018 Bouffalo Lab</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of Bouffalo Lab nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
#include "bl808_ipc.h"
/** @addtogroup BL606P_Peripheral_Driver
* @{
*/
/** @addtogroup IPC
* @{
*/
/** @defgroup IPC_Private_Macros
* @{
*/
#define IPC_LP_OFFSET_IN_M0 0
#define IPC_D0_OFFSET_IN_M0 16
#define IPC_M0_OFFSET_IN_LP 0
#define IPC_D0_OFFSET_IN_LP 16
#define IPC_M0_OFFSET_IN_D0 0
#define IPC_LP_OFFSET_IN_D0 16
/*@} end of group IPC_Private_Macros */
/** @defgroup IPC_Private_Types
* @{
*/
/*@} end of group IPC_Private_Types */
/** @defgroup IPC_Private_Variables
* @{
*/
ipcIntCallback *m0IpcIntCbfArra[GLB_CORE_ID_MAX - 1] = { NULL };
ipcIntCallback *lpIpcIntCbfArra[GLB_CORE_ID_MAX - 1] = { NULL };
ipcIntCallback *d0IpcIntCbfArra[GLB_CORE_ID_MAX - 1] = { NULL };
/*@} end of group IPC_Private_Variables */
/** @defgroup IPC_Global_Variables
* @{
*/
/*@} end of group IPC_Global_Variables */
/** @defgroup IPC_Private_Fun_Declaration
* @{
*/
/*@} end of group IPC_Private_Fun_Declaration */
/** @defgroup IPC_Private_Functions
* @{
*/
/*@} end of group IPC_Private_Functions */
/** @defgroup IPC_Public_Functions
* @{
*/
#if defined(CPU_M0) || defined(CPU_LP)
/****************************************************************************/ /**
* @brief M0 IPC interrupt init
*
* @param onLPTriggerCallBack: Callback when LP trigger
*
* @param onD0TriggerCallBack: Callback when D0 trigger
*
* @return None
*
*******************************************************************************/
void IPC_M0_Init(ipcIntCallback *onLPTriggerCallBack,
ipcIntCallback *onD0TriggerCallBack)
{
m0IpcIntCbfArra[0] = onLPTriggerCallBack;
m0IpcIntCbfArra[1] = onD0TriggerCallBack;
IPC_M0_Int_Unmask_By_Word(0xffffffff);
#ifndef BFLB_USE_HAL_DRIVER
Interrupt_Handler_Register(IPC_M0_IRQn, IPC_M0_IRQHandler);
#endif
CPU_Interrupt_Enable(IPC_M0_IRQn);
}
#endif
/****************************************************************************/ /**
* @brief M0 unmask IPC interrupt
*
* @param src: M0 IPC interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_M0_Int_Unmask(IPC_Int_Src_Type src)
{
uint32_t tmpVal = 0;
/* Check the parameters */
CHECK_PARAM(IS_IPC_INT_SRC_TYPE(src));
tmpVal = (1 << src);
BL_WR_REG(IPC0_BASE, IPC_CPU0_IPC_IUSR, tmpVal);
}
/****************************************************************************/ /**
* @brief M0 unmask IPC interrupt by word
*
* @param src: IPC interrupt source in word,every bit is interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_M0_Int_Unmask_By_Word(uint32_t src)
{
BL_WR_REG(IPC0_BASE, IPC_CPU0_IPC_IUSR, src);
}
/****************************************************************************/ /**
* @brief M0 get IPC interrupt raw status
*
* @param None
*
* @return IPC interrupt raw status
*
*******************************************************************************/
uint32_t IPC_M0_Get_Int_Raw_Status(void)
{
return BL_RD_REG(IPC0_BASE, IPC_CPU0_IPC_IRSRR);
}
/****************************************************************************/ /**
* @brief M0 clear IPC interrupt
*
* @param src: M0 IPC interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_M0_Clear_Int(IPC_Int_Src_Type src)
{
uint32_t tmpVal = 0;
/* Check the parameters */
CHECK_PARAM(IS_IPC_INT_SRC_TYPE(src));
tmpVal = (1 << src);
BL_WR_REG(IPC0_BASE, IPC_CPU0_IPC_ICR, tmpVal);
}
/****************************************************************************/ /**
* @brief M0 clear IPC interrupt by word
*
* @param src: IPC interrupt source in word,every bit is interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_M0_Clear_Int_By_Word(uint32_t src)
{
BL_WR_REG(IPC0_BASE, IPC_CPU0_IPC_ICR, src);
}
/****************************************************************************/ /**
* @brief CPUx trigger IPC interrupt to M0
*
* @param src: IPC interrupt source
*
* @param cpuxOffset: CPU interrupt offset
*
* @return None
*
*******************************************************************************/
void IPC_CPUx_Trigger_M0(IPC_Grp_Int_Src_Type src, uint8_t cpuxOffset)
{
uint32_t tmpVal = 0;
/* Check the parameters */
CHECK_PARAM(IS_IPC_Grp_Int_Src_Type(src));
tmpVal = (1 << (src + cpuxOffset));
BL_WR_REG(IPC0_BASE, IPC_CPU1_IPC_ISWR, tmpVal);
}
/****************************************************************************/ /**
* @brief LP trigger IPC interrupt to M0
*
* @param src: LP IPC interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_LP_Trigger_M0(IPC_Grp_Int_Src_Type src)
{
IPC_CPUx_Trigger_M0(src, IPC_LP_OFFSET_IN_M0);
}
/****************************************************************************/ /**
* @brief D0 trigger IPC interrupt to M0
*
* @param src: D0 IPC interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_D0_Trigger_M0(IPC_Grp_Int_Src_Type src)
{
IPC_CPUx_Trigger_M0(src, IPC_D0_OFFSET_IN_M0);
}
#if defined(CPU_M0) || defined(CPU_LP)
/****************************************************************************/ /**
* @brief LP IPC interrupt init
*
* @param onM0TriggerCallBack: Callback when M0 trigger
*
* @param onD0TriggerCallBack: Callback when D0 trigger
*
* @return None
*
*******************************************************************************/
void IPC_LP_Init(ipcIntCallback *onM0TriggerCallBack,
ipcIntCallback *onD0TriggerCallBack)
{
lpIpcIntCbfArra[0] = onM0TriggerCallBack;
lpIpcIntCbfArra[1] = onD0TriggerCallBack;
IPC_LP_Int_Unmask_By_Word(0xffffffff);
#ifndef BFLB_USE_HAL_DRIVER
Interrupt_Handler_Register(IPC_LP_IRQn, IPC_LP_IRQHandler);
#endif
CPU_Interrupt_Enable(IPC_LP_IRQn);
}
#endif
/****************************************************************************/ /**
* @brief LP unmask IPC interrupt
*
* @param src: LP IPC interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_LP_Int_Unmask(IPC_Int_Src_Type src)
{
uint32_t tmpVal = 0;
/* Check the parameters */
CHECK_PARAM(IS_IPC_INT_SRC_TYPE(src));
tmpVal = (1 << src);
BL_WR_REG(IPC1_BASE, IPC_CPU0_IPC_IUSR, tmpVal);
}
/****************************************************************************/ /**
* @brief LP unmask IPC interrupt by word
*
* @param src: IPC interrupt source in word,every bit is interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_LP_Int_Unmask_By_Word(uint32_t src)
{
BL_WR_REG(IPC1_BASE, IPC_CPU0_IPC_IUSR, src);
}
/****************************************************************************/ /**
* @brief LP get IPC interrupt raw status
*
* @param None
*
* @return IPC interrupt raw status
*
*******************************************************************************/
uint32_t IPC_LP_Get_Int_Raw_Status(void)
{
return BL_RD_REG(IPC1_BASE, IPC_CPU0_IPC_IRSRR);
}
/****************************************************************************/ /**
* @brief LP clear IPC interrupt
*
* @param src: LP IPC interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_LP_Clear_Int(IPC_Int_Src_Type src)
{
uint32_t tmpVal = 0;
/* Check the parameters */
CHECK_PARAM(IS_IPC_INT_SRC_TYPE(src));
tmpVal = (1 << src);
BL_WR_REG(IPC1_BASE, IPC_CPU0_IPC_ICR, tmpVal);
}
/****************************************************************************/ /**
* @brief LP clear IPC interrupt by word
*
* @param src: IPC interrupt source in word,every bit is interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_LP_Clear_Int_By_Word(uint32_t src)
{
BL_WR_REG(IPC1_BASE, IPC_CPU0_IPC_ICR, src);
}
/****************************************************************************/ /**
* @brief CPUx trigger IPC interrupt to LP
*
* @param src: IPC interrupt source
*
* @param cpuxOffset: CPU interrupt offset
*
* @return None
*
*******************************************************************************/
void IPC_CPUx_Trigger_LP(IPC_Grp_Int_Src_Type src, uint8_t cpuxOffset)
{
uint32_t tmpVal = 0;
/* Check the parameters */
CHECK_PARAM(IS_IPC_Grp_Int_Src_Type(src));
tmpVal = (1 << (src + cpuxOffset));
BL_WR_REG(IPC1_BASE, IPC_CPU1_IPC_ISWR, tmpVal);
}
/****************************************************************************/ /**
* @brief M0 trigger IPC interrupt to LP
*
* @param src: M0 IPC interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_M0_Trigger_LP(IPC_Grp_Int_Src_Type src)
{
IPC_CPUx_Trigger_LP(src, IPC_M0_OFFSET_IN_LP);
}
/****************************************************************************/ /**
* @brief D0 trigger IPC interrupt to LP
*
* @param src: D0 IPC interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_D0_Trigger_LP(IPC_Grp_Int_Src_Type src)
{
IPC_CPUx_Trigger_LP(src, IPC_D0_OFFSET_IN_LP);
}
#if defined(CPU_D0) || defined(CPU_D1)
/****************************************************************************/ /**
* @brief D0 IPC interrupt init
*
* @param onM0TriggerCallBack: Callback when M0 trigger
*
* @param onLPTriggerCallBack: Callback when LP trigger
*
* @return None
*
*******************************************************************************/
void IPC_D0_Init(ipcIntCallback *onM0TriggerCallBack,
ipcIntCallback *onLPTriggerCallBack)
{
d0IpcIntCbfArra[0] = onM0TriggerCallBack;
d0IpcIntCbfArra[1] = onLPTriggerCallBack;
IPC_D0_Int_Unmask_By_Word(0xffffffff);
#ifndef BFLB_USE_HAL_DRIVER
Interrupt_Handler_Register(IPC_D0_IRQn, IPC_D0_IRQHandler);
#endif
CPU_Interrupt_Enable(IPC_D0_IRQn);
}
#endif
/****************************************************************************/ /**
* @brief D0 unmask IPC interrupt
*
* @param src: D0 IPC interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_D0_Int_Unmask(IPC_Int_Src_Type src)
{
uint32_t tmpVal = 0;
/* Check the parameters */
CHECK_PARAM(IS_IPC_INT_SRC_TYPE(src));
tmpVal = (1 << src);
BL_WR_REG(IPC2_BASE, IPC_CPU0_IPC_IUSR, tmpVal);
}
/****************************************************************************/ /**
* @brief D0 unmask IPC interrupt by word
*
* @param src: D0 IPC interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_D0_Int_Unmask_By_Word(uint32_t src)
{
BL_WR_REG(IPC2_BASE, IPC_CPU0_IPC_IUSR, src);
}
/****************************************************************************/ /**
* @brief D0 get IPC interrupt raw status
*
* @param None
*
* @return IPC interrupt raw status
*
*******************************************************************************/
uint32_t IPC_D0_Get_Int_Raw_Status(void)
{
return BL_RD_REG(IPC2_BASE, IPC_CPU0_IPC_IRSRR);
}
/****************************************************************************/ /**
* @brief D0 clear IPC interrupt
*
* @param src: D0 IPC interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_D0_Clear_Int(IPC_Int_Src_Type src)
{
uint32_t tmpVal = 0;
/* Check the parameters */
CHECK_PARAM(IS_IPC_INT_SRC_TYPE(src));
tmpVal = (1 << src);
BL_WR_REG(IPC2_BASE, IPC_CPU0_IPC_ICR, tmpVal);
}
/****************************************************************************/ /**
* @brief D0 clear IPC interrupt by word
*
* @param src: IPC interrupt source in word,every bit is interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_D0_Clear_Int_By_Word(uint32_t src)
{
BL_WR_REG(IPC2_BASE, IPC_CPU0_IPC_ICR, src);
}
/****************************************************************************/ /**
* @brief CPUx trigger IPC interrupt to D0
*
* @param src: IPC interrupt source
*
* @param cpuxOffset: CPU interrupt offset
*
* @return None
*
*******************************************************************************/
void IPC_CPUx_Trigger_D0(IPC_Grp_Int_Src_Type src, uint8_t cpuxOffset)
{
uint32_t tmpVal = 0;
/* Check the parameters */
CHECK_PARAM(IS_IPC_Grp_Int_Src_Type(src));
tmpVal = (1 << (src + cpuxOffset));
BL_WR_REG(IPC2_BASE, IPC_CPU1_IPC_ISWR, tmpVal);
}
/****************************************************************************/ /**
* @brief M0 trigger IPC interrupt to D0
*
* @param src: M0 IPC interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_M0_Trigger_D0(IPC_Grp_Int_Src_Type src)
{
IPC_CPUx_Trigger_D0(src, IPC_M0_OFFSET_IN_D0);
}
/****************************************************************************/ /**
* @brief LP trigger IPC interrupt to D0
*
* @param src: LP IPC interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_LP_Trigger_D0(IPC_Grp_Int_Src_Type src)
{
IPC_CPUx_Trigger_D0(src, IPC_LP_OFFSET_IN_D0);
}
/****************************************************************************/ /**
* @brief M0 trigger IPC interrupt to CPUx
*
* @param tgtCPU: Target CPU
*
* @param src: IPC interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_M0_Trigger_CPUx(GLB_CORE_ID_Type tgtCPU, IPC_Grp_Int_Src_Type src)
{
switch (tgtCPU) {
case GLB_CORE_ID_LP:
IPC_M0_Trigger_LP(src);
break;
case GLB_CORE_ID_D0:
IPC_M0_Trigger_D0(src);
break;
default:
break;
}
}
/****************************************************************************/ /**
* @brief LP trigger IPC interrupt to CPUx
*
* @param tgtCPU: Target CPU
*
* @param src: IPC interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_LP_Trigger_CPUx(GLB_CORE_ID_Type tgtCPU, IPC_Grp_Int_Src_Type src)
{
switch (tgtCPU) {
case GLB_CORE_ID_M0:
IPC_LP_Trigger_M0(src);
break;
case GLB_CORE_ID_D0:
IPC_LP_Trigger_D0(src);
break;
default:
break;
}
}
/****************************************************************************/ /**
* @brief D0 trigger IPC interrupt to CPUx
*
* @param tgtCPU: Target CPU
*
* @param src: IPC interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_D0_Trigger_CPUx(GLB_CORE_ID_Type tgtCPU, IPC_Grp_Int_Src_Type src)
{
switch (tgtCPU) {
case GLB_CORE_ID_M0:
IPC_D0_Trigger_M0(src);
break;
case GLB_CORE_ID_LP:
IPC_D0_Trigger_LP(src);
break;
default:
break;
}
}
/****************************************************************************/ /**
* @brief D0 trigger IPC interrupt to D1
*
* @param src: D0 IPC interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_Trigger_Target_CPU(GLB_CORE_ID_Type tgtCPU, IPC_Grp_Int_Src_Type src)
{
GLB_CORE_ID_Type localCPU = GLB_Get_Core_Type();
switch (localCPU) {
case GLB_CORE_ID_M0:
IPC_M0_Trigger_CPUx(tgtCPU, src);
break;
case GLB_CORE_ID_LP:
IPC_LP_Trigger_CPUx(tgtCPU, src);
break;
case GLB_CORE_ID_D0:
IPC_D0_Trigger_CPUx(tgtCPU, src);
break;
default:
break;
}
}
/****************************************************************************/ /**
* @brief D0 trigger IPC interrupt to D1
*
* @param src: D0 IPC interrupt source
*
* @return None
*
*******************************************************************************/
void IPC_Common_Interrupt_Handler(uint32_t irqStatus, ipcIntCallback *callBack[GLB_CORE_ID_MAX - 1])
{
uint32_t tmp;
uint32_t grp = 0;
for (grp = 0; grp < GLB_CORE_ID_MAX - 1; grp++) {
tmp = (irqStatus >> (16 * grp)) & 0xffff;
if (tmp != 0) {
if (callBack[grp] != NULL) {
callBack[grp](tmp);
}
}
}
}
/****************************************************************************/ /**
* @brief M0 IPC IRQ handler
*
* @param None
*
* @return None
*
*******************************************************************************/
#ifndef BFLB_USE_HAL_DRIVER
void IPC_M0_IRQHandler(void)
{
uint32_t irqStatus;
MSG("%s: wrong handler!!\n", __func__);
irqStatus = IPC_M0_Get_Int_Raw_Status();
IPC_Common_Interrupt_Handler(irqStatus, m0IpcIntCbfArra);
IPC_M0_Clear_Int_By_Word(irqStatus);
}
#endif
/****************************************************************************/ /**
* @brief LP IPC IRQ handler
*
* @param None
*
* @return None
*
*******************************************************************************/
#ifndef BFLB_USE_HAL_DRIVER
void IPC_LP_IRQHandler(void)
{
uint32_t irqStatus;
irqStatus = IPC_LP_Get_Int_Raw_Status();
IPC_Common_Interrupt_Handler(irqStatus, lpIpcIntCbfArra);
IPC_LP_Clear_Int_By_Word(irqStatus);
}
#endif
/****************************************************************************/ /**
* @brief D0 IPC IRQ handler
*
* @param None
*
* @return None
*
*******************************************************************************/
#ifndef BFLB_USE_HAL_DRIVER
void IPC_D0_IRQHandler(void)
{
uint32_t irqStatus;
irqStatus = IPC_D0_Get_Int_Raw_Status();
IPC_Common_Interrupt_Handler(irqStatus, d0IpcIntCbfArra);
IPC_D0_Clear_Int_By_Word(irqStatus);
}
#endif
/*@} end of group IPC_Public_Functions */
/*@} end of group IPC */
/*@} end of group BL606P_Peripheral_Driver */

View file

@ -21,158 +21,32 @@
*
*/
#define DBG_TAG "MAIN"
#include <bl808_common.h>
#include <bflb_irq.h>
#include <bflb_clock.h>
#include <bflb_gpio.h>
#include <bl808_ipc.h>
#include <ipc_reg.h>
#include <sdh_reg.h>
#include <log.h>
#include <stdio.h>
#include <board.h>
#include "irq-forward.h"
#include <bflb_mtimer.h>
#include "oblfr_mailbox.h"
#include "sdkconfig.h"
#define DBG_TAG "MAIN"
#include <log.h>
static uint32_t ipc_irqs[32] = {
#ifdef CONFIG_LL_IRQFWD_SDH
[BFLB_IPC_DEVICE_SDHCI] = SDH_IRQn,
#endif
#ifdef CONFIG_LL_IRQFWD_UART2
[BFLB_IPC_DEVICE_UART2] = UART2_IRQn,
#endif
#ifdef CONFIG_LL_IRQFWD_USB
[BLFB_IPC_DEVICE_USB] = USB_IRQn,
#endif
0,
};
static void Send_IPC_IRQ(int device)
{
bflb_irq_disable(ipc_irqs[device]);
BL_WR_REG(IPC2_BASE, IPC_CPU1_IPC_ISWR, (1 << device));
}
#ifdef CONFIG_LL_IRQFWD_SDH
void SDH_MMC1_IRQHandler(int irq, void *arg)
{
LOG_D("Got SDH IRQ\r\n");
Send_IPC_IRQ(BFLB_IPC_DEVICE_SDHCI);
}
#endif
#ifdef CONFIG_LL_IRQFWD_UART2
void UART2_IRQHandler(int irq, void *arg)
{
LOG_D("Got UART IRQ\r\n");
Send_IPC_IRQ(BFLB_IPC_DEVICE_UART2);
}
#endif
#ifdef CONFIG_LL_IRQFWD_USB
void USB_IRQHandler(int irq, void *arg)
{
LOG_D("Got USB IRQ\r\n");
Send_IPC_IRQ(BLFB_IPC_DEVICE_USB);
}
#endif
void IPC_M0_IRQHandler(int irq, void *arg)
{
int i;
uint32_t irqStatus = IPC_M0_Get_Int_Raw_Status();
for (i = 0; i < sizeof(irqStatus) * 8; i++)
{
if (irqStatus & (1 << i)) {
LOG_D("Got IPC EOI for device %d\r\n");
bflb_irq_enable(ipc_irqs[i]);
}
}
BL_WR_REG(IPC0_BASE, IPC_CPU0_IPC_ICR, irqStatus);
}
#ifdef CONFIG_LL_IRQFWD_SDH
int setup_sdh_peripheral() {
LOG_D("setting up SDH peripheral\r\n");
struct bflb_device_s *gpio;
gpio = bflb_device_get_by_name("gpio");
bflb_gpio_init(gpio, GPIO_PIN_0, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
bflb_gpio_init(gpio, GPIO_PIN_1, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
bflb_gpio_init(gpio, GPIO_PIN_2, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
bflb_gpio_init(gpio, GPIO_PIN_3, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
bflb_gpio_init(gpio, GPIO_PIN_4, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
bflb_gpio_init(gpio, GPIO_PIN_5, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
PERIPHERAL_CLOCK_SDH_ENABLE();
// uint32_t tmp_val;
// tmp_val = BL_RD_REG(PDS_BASE, PDS_CTL5);
// uint32_t tmp_val2 = BL_GET_REG_BITS_VAL(tmp_val, PDS_CR_PDS_GPIO_KEEP_EN);
// tmp_val2 &= ~(1 << 0);
// tmp_val = BL_SET_REG_BITS_VAL(tmp_val, PDS_CR_PDS_GPIO_KEEP_EN, tmp_val2);
// BL_WR_REG(PDS_BASE, PDS_CTL5, tmp_val);
// GLB_AHB_MCU_Software_Reset(GLB_AHB_MCU_SW_SDH);
LOG_D("SDH peripheral clock: %d\r\n", bflb_clk_get_peripheral_clock(BFLB_DEVICE_TYPE_SDH, 0)/1000000);
return SUCCESS;
}
#endif
int main(void)
{
board_init();
LOG_I("M0 CPU start...\r\n");
LOG_I("Starting Mailbox Handlers\r\n");
LOG_I("registering IPC interrupt handler\r\n");
bflb_irq_attach(IPC_M0_IRQn, IPC_M0_IRQHandler, NULL);
IPC_M0_Int_Unmask_By_Word(0xffffffff);
bflb_irq_enable(IPC_M0_IRQn);
#ifdef CONFIG_LL_IRQFWD_SDH
LOG_I("registering SDH interrupt handler\r\n");
bflb_irq_attach(SDH_IRQn, SDH_MMC1_IRQHandler, NULL);
bflb_irq_enable(SDH_IRQn);
if (setup_sdh_peripheral() != SUCCESS) {
LOG_E("Failed to setup SDH peripheral\r\n");
if (oblfr_mailbox_init() != OBLFR_OK) {
LOG_E("oblfr_mailbox_init failed\r\n");
while (1) {
;
}
}
#endif
#ifdef CONFIG_LL_IRQFWD_UART2
LOG_I("registering UART2 interrupt handler\r\n");
bflb_irq_attach(UART2_IRQn, UART2_IRQHandler, NULL);
bflb_irq_enable(UART2_IRQn);
#endif
#ifdef CONFIG_LL_IRQFWD_USB
LOG_I("registering USB interrupt handler\r\n");
bflb_irq_attach(USB_IRQn, UART2_IRQHandler, NULL);
bflb_irq_enable(USB_IRQn);
#endif
LOG_I("Running...\r\n");
while (1)
{
{
static int x = 0;
if ((x++ % 999999999) == 0)
{
{
// dump_ipc(IPC0_BASE);
// dump_ipc(IPC1_BASE);
LOG_I(".\n");
}
}
}
int dummy;
/* In lieu of a halt instruction, induce a long-latency stall. */
__asm__ __volatile__("div %0, %0, zero"
: "=r"(dummy));
oblfr_mailbox_dump();
bflb_mtimer_delay_ms(5000);
}
}

View file

@ -44,6 +44,7 @@ if(BOARD_DIR)
endif()
find_package(bouffalo_sdk REQUIRED HINTS $ENV{BL_SDK_BASE})
include(${SDK_PATH}/cmake/sdk.cmake)
include(${SDK_PATH}/cmake/kconfig.cmake)
add_subdirectory(${SDK_PATH}/bsp/common/ bsp_common)

6
cmake/sdk.cmake Normal file
View file

@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.15)
function(sdk_add_include_directories_ifndef feature)
if(NOT DEFINED ${feature})
sdk_add_include_directories(${ARGN})
endif()
endfunction()

View file

@ -1,5 +1,9 @@
sdk_add_subdirectory_ifdef(CONFIG_COMPONENT_SYSTEM oblfr)
#if we do not include the SYSTEM component, we need to at add the include directory */
sdk_add_include_directories_ifndef(CONFIG_COMPONENT_SYSTEM_OBLFR oblfr/include)
sdk_add_subdirectory_ifdef(CONFIG_COMPONENT_BUTTON button)
sdk_add_subdirectory_ifdef(CONFIG_COMPONENT_STATUS_LED indicator)
sdk_add_subdirectory_ifdef(CONFIG_COMPONENT_TIMER timer)
sdk_add_subdirectory_ifdef(CONFIG_COMPONENT_NVKVS nvkvs)
sdk_add_subdirectory_ifdef(CONFIG_COMPONENT_NVKVS nvkvs)
sdk_add_subdirectory_ifdef(CONFIG_COMPONENT_MAILBOX mailbox)

View file

@ -0,0 +1,4 @@
sdk_generate_library(oblfr_mailbox)
sdk_add_include_directories(include)
sdk_library_add_sources(${CMAKE_CURRENT_SOURCE_DIR}/src/oblfr_mailbox.c)

View file

@ -0,0 +1,44 @@
config COMPONENT_MAILBOX
bool "Mailbox Support for Linux"
default y
help
Mailbox Component forwards IRQ's to the D0 core for Linux
support. Enable this component if you are running linux on
the D0 core.
Please see the README.md file in the Mailbox component directory
for more information
menu "Mailbox Configuration"
visible if COMPONENT_MAILBOX
config COMPONENT_MAILBOX_IRQFWD_SDH
bool "Enable IRQ forwarding for SDH"
default y
config COMPONENT_MAILBOX_IRQFWD_UART2
bool "Enable IRQ forwarding for UART2"
default n
help
Enable if you wish to use UART2 for linux
config COMPONENT_MAILBOX_IRQFWD_USB
bool "Enable IRQ forwarding for USB"
default n
help
Curently disabled as USB is not working
config COMPONENT_MAILBOX_IRQFWD_GPIO
bool "Enable IRQ forwarding for GPIO"
default y
help
enable if you need Interupt Support for GPIO on Linux
config COMPONENT_MAILBOX_IRQFWD_EMAC
bool "Enable IRQ forwarding for Ethernet"
default y if BOARD_M1SDOCK
default n
help
enable if you need Interupt Support for Ethernet on Linux
Currently supported on M1SDock to to vddio2 being
wrong voltage for OX64
endmenu

View file

@ -0,0 +1,30 @@
## Mailbox
This components supports running linux on the D0 core
Include this in your M0 firmware to allow linux to continue to operate
## Description
Several Peripherals of the BL808 only have their IRQ attached to the M0 core.
This component "forwards" these IRQs to the M0 core to allow Linux to operate.
This component also includes support for the bl808-ipc driver on linux, which is
mailbox driver. It allows Linux running on the D0 core to send interupts to the M0 core.
## Peripherals Forwarded
The following Peripherals can be forwarded to the M0 core. (You can
change this via ```make config```) under your project configuartion, but be aware,
some peripherals might not work in linux if you disable them here.
* SD Card Support (Mandatory to have your rootfs on the SD card)
* UART2 of the M0 core forwarded to Linux
* USB Support
* GPIO Pins (See below for caveats)
* Ethernet
## GPIO Interupt Support
To be documented.
## Ethernet Support
Enabling Ethernet Support also initilizes the Ethernet Peripheral via the M0 core.
## SDHCI Support
Enabling SD Card Support also initializes the SDHCI Peripheral via the M0 core.

View file

@ -0,0 +1,23 @@
#ifndef __OBLFR_MAILBOX_H__
#define __OBLFR_MAILBOX_H__
#include <stdint.h>
#include <stdbool.h>
#include "oblfr_common.h"
#include "sdkconfig.h"
/* Peripheral device ID */
#define BFLB_IPC_DEVICE_SDHCI 0
#define BFLB_IPC_DEVICE_UART2 1
#define BLFB_IPC_DEVICE_USB 2
#define BFLB_IPC_DEVICE_EMAC 3
#define BFLB_IPC_DEVICE_GPIO 4
#define BFLB_IPC_DEVICE_MAILBOX 5
oblfr_err_t oblfr_mailbox_init(void);
oblfr_err_t oblfr_mailbox_dump();
#endif

View file

@ -0,0 +1,217 @@
// Copyright 2020-2021 Espressif Systems (Shanghai) CO LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdbool.h>
#include <string.h>
#include <board.h>
#include <bl808.h>
#include <bl808_common.h>
#include <bl808_glb.h>
#include <ipc_reg.h>
#include <bflb_clock.h>
#include <bflb_gpio.h>
#include "oblfr_mailbox.h"
#define DBG_TAG "MBOX"
#include "log.h"
#ifndef CONFIG_CHIP_BL808
#error "This component is only for BL808"
#endif
typedef struct {
char name[16];
uint32_t irq;
uint32_t count;
void (*handler)(int irq, void *arg);
} mbox_irq_t;
static void Send_IPC_IRQ(int device);
#ifdef CONFIG_COMPONENT_MAILBOX_IRQFWD_SDH
static void SDHCI_IRQHandler(int irq, void *arg)
{
LOG_T("Got SDH IRQ\r\n");
Send_IPC_IRQ(BFLB_IPC_DEVICE_SDHCI);
}
#endif
#ifdef CONFIG_COMPONENT_MAILBOX_IRQFWD_UART2
static void UART2_IRQHandler(int irq, void *arg)
{
LOG_T("Got UART IRQ\r\n");
Send_IPC_IRQ(BFLB_IPC_DEVICE_UART2);
}
#endif
#ifdef CONFIG_COMPONENT_MAILBOX_IRQFWD_USB
static void USB_IRQHandler(int irq, void *arg)
{
LOG_T("Got USB IRQ\r\n");
Send_IPC_IRQ(BLFB_IPC_DEVICE_USB);
}
#endif
#ifdef CONFIG_COMPONENT_MAILBOX_IRQFWD_EMAC
static void EMAC_IRQHandler(int irq, void *arg)
{
LOG_T("Got EMAC IRQ\r\n");
Send_IPC_IRQ(BFLB_IPC_DEVICE_EMAC);
}
#endif
#ifdef CONFIG_COMPONENT_MAILBOX_IRQFWD_GPIO
static void GPIO_IRQHandler(int irq, void *arg)
{
LOG_T("Got GPIO IRQ\r\n");
Send_IPC_IRQ(BFLB_IPC_DEVICE_GPIO);
}
#endif
static mbox_irq_t ipc_irqs[32] = {
#ifdef CONFIG_COMPONENT_MAILBOX_IRQFWD_SDH
[BFLB_IPC_DEVICE_SDHCI] = { "SDH", SDH_IRQn, 0, SDHCI_IRQHandler},
#endif
#ifdef CONFIG_COMPONENT_MAILBOX_IRQFWD_UART2
[BFLB_IPC_DEVICE_UART2] = { "UART2", UART2_IRQn, 0, UART2_IRQHandler},
#endif
#ifdef CONFIG_COMPONENT_MAILBOX_IRQFWD_USB
[BLFB_IPC_DEVICE_USB] = { "USB", USB_IRQn, 0, USB_IRQHandler},
#endif
#ifdef CONFIG_COMPONENT_MAILBOX_IRQFWD_EMAC
[BFLB_IPC_DEVICE_EMAC] = { "EMAC", EMAC_IRQn, 0, EMAC_IRQHandler},
#endif
#ifdef CONFIG_COMPONENT_MAILBOX_IRQFWD_GPIO
[BFLB_IPC_DEVICE_GPIO] = { "GPIO", GPIO_INT0_IRQn, 0, GPIO_IRQHandler},
#endif
};
static void Send_IPC_IRQ(int device)
{
if (ipc_irqs[device].irq == 0) {
LOG_E("Invalid IPC IRQ %d\r\n", device);
return;
}
bflb_irq_disable(ipc_irqs[device].irq);
BL_WR_REG(IPC2_BASE, IPC_CPU1_IPC_ISWR, (1 << device));
ipc_irqs[device].count++;
}
void IPC_M0_IRQHandler(int irq, void *arg)
{
int i;
uint32_t irqStatus = BL_RD_REG(IPC0_BASE, IPC_CPU0_IPC_IRSRR);
for (i = 0; i < sizeof(irqStatus) * 8; i++)
{
if (irqStatus & (1 << i)) {
if (i == BFLB_IPC_DEVICE_MAILBOX) {
LOG_I("Got Mailbox IRQ\r\n");
} else {
if (ipc_irqs[i].irq == 0) {
LOG_W("Got IPC IRQ for unknown peripheral %d\r\n", i);
} else {
LOG_T("Got IPC EOI for Peripheral %s (%d - %d)\r\n", ipc_irqs[i].name, irqStatus, ipc_irqs[i].irq);
//assert(irqStatus == ipc_irqs[irqStatus].irq);
bflb_irq_enable(ipc_irqs[i].irq);
}
}
}
}
BL_WR_REG(IPC0_BASE, IPC_CPU0_IPC_ICR, irqStatus);
}
#ifdef CONFIG_COMPONENT_MAILBOX_IRQFWD_SDH
oblfr_err_t setup_sdh_peripheral() {
LOG_D("setting up SDH peripheral\r\n");
struct bflb_device_s *gpio;
gpio = bflb_device_get_by_name("gpio");
bflb_gpio_init(gpio, GPIO_PIN_0, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
bflb_gpio_init(gpio, GPIO_PIN_1, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
bflb_gpio_init(gpio, GPIO_PIN_2, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
bflb_gpio_init(gpio, GPIO_PIN_3, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
bflb_gpio_init(gpio, GPIO_PIN_4, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
bflb_gpio_init(gpio, GPIO_PIN_5, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
PERIPHERAL_CLOCK_SDH_ENABLE();
LOG_D("SDH peripheral clock: %d\r\n", bflb_clk_get_peripheral_clock(BFLB_DEVICE_TYPE_SDH, 0)/1000000);
return OBLFR_OK;
}
#endif
#ifdef COMPONENT_MAILBOX_IRQFWD_EMAC
static oblfr_err_t setup_emac_peripheral(void)
{
GLB_GPIO_Cfg_Type gpio_cfg;
int pin;
PERIPHERAL_CLOCK_EMAC_ENABLE();
struct bflb_device_s *gpio = bflb_device_get_by_name("gpio");
for (pin = GLB_GPIO_PIN_24; pin <= GLB_GPIO_PIN_33; pin++) {
bflb_gpio_init(gpio, pin, GPIO_FUNC_EMAC | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
}
return OBLFR_OK;
}
#endif
oblfr_err_t oblfr_mailbox_init()
{
int i;
/* setup the IPC Interupt */
bflb_irq_attach(IPC_M0_IRQn, IPC_M0_IRQHandler, NULL);
BL_WR_REG(IPC0_BASE, IPC_CPU0_IPC_IUSR, 0xffffffff);
bflb_irq_enable(IPC_M0_IRQn);
/* register our Interupt Handlers to forward over */
for (i = 0; i < sizeof(ipc_irqs) / sizeof(ipc_irqs[0]); i++) {
if (ipc_irqs[i].irq != 0) {
LOG_I("Forwarding Interupt %s (%d) to D0 (%p)\r\n", ipc_irqs[i].name, ipc_irqs[i].irq, ipc_irqs[i].handler);
bflb_irq_attach(ipc_irqs[i].irq, ipc_irqs[i].handler, NULL);
bflb_irq_enable(ipc_irqs[i].irq);
}
}
#ifdef CONFIG_COMPONENT_MAILBOX_IRQFWD_SDH
if (setup_sdh_peripheral() != SUCCESS) {
LOG_E("Failed to setup SDH peripheral\r\n");
return OBLFR_ERR_ERROR;
}
#endif
#ifdef COMPONENT_MAILBOX_IRQFWD_EMAC
if (setup_emac_peripheral() != SUCCESS) {
LOG_E("Failed to setup EMAC peripheral\r\n");
return OBLFR_ERR_ERROR;
}
#endif
return OBLFR_OK;
}
oblfr_err_t oblfr_mailbox_dump()
{
LOG_I("Mailbox IRQ Stats:\r\n");
for (uint8_t i = 0; i < sizeof(ipc_irqs) / sizeof(ipc_irqs[0]); i++) {
if (ipc_irqs[i].irq != 0) {
LOG_I("Peripheral %s (%d): %d\r\n", ipc_irqs[i].name, ipc_irqs[i].irq, ipc_irqs[i].count);
}
}
LOG_I("====================================\r\n");
return OBLFR_OK;
}

View file

@ -5,6 +5,6 @@ config COMPONENT_TIMER
help
"Timer Component"
menu "Timer Configuration"
visible if COMPONENT_TIMER
endmenu