thermosphere: major refactor of memory map
- use recursive stage 1 page table (thanks @fincs for this idea) - NULL now unmapped - no identity mapping - image + GICv2 now mapped at the same address for every platform - tempbss mapped just after "real" bss, can now steal unused mem from the latter - no hardcoded VAs for other MMIO devices - tegra: remove timers, use the generic timer instead
This commit is contained in:
27
thermosphere/src/platform/devices.h
Normal file
27
thermosphere/src/platform/devices.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef PLATFORM_TEGRA
|
||||
|
||||
#include "tegra/devices.h"
|
||||
|
||||
#elif defined(PLATFORM_QEMU)
|
||||
|
||||
#include "qemu/devices.h"
|
||||
|
||||
#endif
|
||||
31
thermosphere/src/platform/qemu/devices.c
Normal file
31
thermosphere/src/platform/qemu/devices.c
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "devices.h"
|
||||
#include "../../memory_map.h"
|
||||
#include "../../utils.h"
|
||||
|
||||
#include "uart.h"
|
||||
|
||||
void devicesMapAllExtra(void)
|
||||
{
|
||||
uartSetRegisterBase(memoryMapPlatformMmio(MEMORY_MAP_PA_UART, 0x1000));
|
||||
|
||||
// Don't broadcast, since it's only ran once per boot by only one core, before the others are started...
|
||||
__tlb_invalidate_el2_local();
|
||||
__dsb();
|
||||
__isb();
|
||||
}
|
||||
19
thermosphere/src/platform/qemu/devices.h
Normal file
19
thermosphere/src/platform/qemu/devices.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
void devicesMapAllExtra(void);
|
||||
@@ -18,17 +18,17 @@
|
||||
|
||||
#include "../../gicv2.h"
|
||||
|
||||
// For both guest and host
|
||||
#define MAX_NUM_REGISTERED_INTERRUPTS 512
|
||||
#define MEMORY_MAP_PA_GICD 0x08000000ull
|
||||
#define MEMORY_MAP_PA_GICC 0x08010000ull
|
||||
#define MEMORY_MAP_PA_GICH 0x08030000ull
|
||||
#define MEMORY_MAP_PA_GICV 0x08040000ull
|
||||
|
||||
#define GIC_IRQID_PMU 23
|
||||
#define GIC_IRQID_MAINTENANCE 25
|
||||
#define GIC_IRQID_NS_PHYS_HYP_TIMER 26
|
||||
#define GIC_IRQID_NS_VIRT_TIMER 27
|
||||
//#define GIC_IRQID_LEGACY_NFIQ 28 not defined?
|
||||
#define GIC_IRQID_SEC_PHYS_TIMER 29
|
||||
#define GIC_IRQID_NS_PHYS_TIMER 30
|
||||
//#define GIC_IRQID_LEGACY_NIRQ 31 not defined?
|
||||
|
||||
|
||||
#define GIC_IRQID_NS_VIRT_HYP_TIMER GIC_IRQID_SPURIOUS // SBSA: 28. Unimplemented
|
||||
@@ -36,11 +36,3 @@
|
||||
#define GIC_IRQID_SEC_VIRT_HYP_TIMER GIC_IRQID_SPURIOUS // SBSA: 19. Unimplemented
|
||||
|
||||
#define GIC_IRQID_UART (32 + 1)
|
||||
|
||||
static inline void initGicV2Pointers(ArmGicV2 *gic)
|
||||
{
|
||||
gic->gicd = (volatile ArmGicV2Distributor *)0x08000000ull;
|
||||
gic->gicc = (volatile ArmGicV2Controller *)0x08010000ull;
|
||||
gic->gich = (volatile ArmGicV2VirtualInterfaceController *)0x08030000ull;
|
||||
gic->gicv = (volatile ArmGicV2Controller *)0x08040000ull;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "memory_map.h"
|
||||
#include "stage2_config.h"
|
||||
#include "interrupt_config.h"
|
||||
#include "../../memory_map.h"
|
||||
#include "../../utils.h"
|
||||
#include "../../mmu.h"
|
||||
#include "../../core_ctx.h"
|
||||
@@ -23,11 +25,10 @@
|
||||
#define ADDRSPACESZ 39
|
||||
#define ADDRSPACESZ2 ADDRSPACESZ
|
||||
|
||||
static ALIGN(0x1000) u64 g_ttbl[BIT(ADDRSPACESZ - 30)] = {0};
|
||||
|
||||
static ALIGN(0x1000) u64 g_vttbl[BIT(ADDRSPACESZ2 - 30)] = {0};
|
||||
static TEMPORARY ALIGN(0x1000) u64 g_vttbl[BIT(ADDRSPACESZ2 - 30)] = {0};
|
||||
static TEMPORARY ALIGN(0x1000) u64 g_vttbl_l2_mmio_0_0[512] = {0};
|
||||
static TEMPORARY ALIGN(0x1000) u64 g_vttbl_l3_0[512] = {0};
|
||||
static TEMPORARY uintptr_t g_vttblPaddr;
|
||||
|
||||
static inline void identityMapL1(u64 *tbl, uintptr_t addr, size_t size, u64 attribs)
|
||||
{
|
||||
@@ -44,39 +45,31 @@ static inline void identityMapL3(u64 *tbl, uintptr_t addr, size_t size, u64 attr
|
||||
mmu_map_block_range(3, tbl, addr, addr, size, attribs | MMU_PTE_BLOCK_INNER_SHAREBLE);
|
||||
}
|
||||
|
||||
uintptr_t configureMemoryMap(u32 *addrSpaceSize)
|
||||
{
|
||||
// QEMU virt RAM address space starts at 0x40000000
|
||||
*addrSpaceSize = ADDRSPACESZ;
|
||||
if (currentCoreCtx->isBootCore && !currentCoreCtx->warmboot) {
|
||||
identityMapL1(g_ttbl, 0x00000000ull, BITL(30), ATTRIB_MEMTYPE_DEVICE);
|
||||
identityMapL1(g_ttbl, 0x40000000ull, (BITL(ADDRSPACESZ - 30) - 1ull) << 30, ATTRIB_MEMTYPE_NORMAL);
|
||||
}
|
||||
|
||||
return (uintptr_t)g_ttbl;
|
||||
}
|
||||
|
||||
uintptr_t configureStage2MemoryMap(u32 *addrSpaceSize)
|
||||
uintptr_t stage2Configure(u32 *addrSpaceSize)
|
||||
{
|
||||
*addrSpaceSize = ADDRSPACESZ2;
|
||||
static const u64 devattrs = MMU_S2AP_RW | MMU_MEMATTR_DEVICE_NGNRE;
|
||||
static const u64 devattrs = 0 | MMU_S2AP_RW | MMU_MEMATTR_DEVICE_NGNRE;
|
||||
static const u64 unchanged = MMU_S2AP_RW | MMU_MEMATTR_NORMAL_CACHEABLE_OR_UNCHANGED;
|
||||
|
||||
if (currentCoreCtx->isBootCore) {
|
||||
g_vttblPaddr = va2pa(g_vttbl);
|
||||
uintptr_t *l2pa = (uintptr_t *)va2pa(g_vttbl_l2_mmio_0_0);
|
||||
uintptr_t *l3pa = (uintptr_t *)va2pa(g_vttbl_l3_0);
|
||||
|
||||
identityMapL1(g_vttbl, 0, 4ull << 30, unchanged);
|
||||
identityMapL1(g_vttbl, 0x40000000ull, (BITL(ADDRSPACESZ2 - 30) - 1ull) << 30, unchanged);
|
||||
mmu_map_table(1, g_vttbl, 0x00000000ull, g_vttbl_l2_mmio_0_0, 0);
|
||||
mmu_map_table(1, g_vttbl, 0x00000000ull, l2pa, 0);
|
||||
|
||||
identityMapL2(g_vttbl_l2_mmio_0_0, 0x08000000ull, BITL(30), unchanged);
|
||||
mmu_map_table(2, g_vttbl_l2_mmio_0_0, 0x08000000ull, g_vttbl_l3_0, 0);
|
||||
mmu_map_table(2, g_vttbl_l2_mmio_0_0, 0x08000000ull, l3pa, 0);
|
||||
|
||||
identityMapL3(g_vttbl_l3_0, 0x08000000ull, BITL(21), unchanged);
|
||||
|
||||
// GICD -> trapped, GICv2 CPU -> vCPU interface, GICH -> trapped (deny access)
|
||||
mmu_unmap_range(3, g_vttbl_l3_0, 0x08000000ull, 0x10000ull);
|
||||
mmu_unmap_range(3, g_vttbl_l3_0, 0x08030000ull, 0x10000ull);
|
||||
mmu_map_page_range(g_vttbl_l3_0, 0x08010000ull, 0x08040000ull, 0x10000ull, devattrs);
|
||||
mmu_unmap_range(3, g_vttbl_l3_0, MEMORY_MAP_PA_GICD, 0x10000ull);
|
||||
mmu_unmap_range(3, g_vttbl_l3_0, MEMORY_MAP_PA_GICH, 0x10000ull);
|
||||
mmu_map_page_range(g_vttbl_l3_0, MEMORY_MAP_PA_GICC, MEMORY_MAP_PA_GICV, 0x10000ull, devattrs);
|
||||
}
|
||||
|
||||
return (uintptr_t)g_vttbl;
|
||||
return g_vttblPaddr;
|
||||
}
|
||||
@@ -18,5 +18,4 @@
|
||||
|
||||
#include "../../types.h"
|
||||
|
||||
uintptr_t configureMemoryMap(u32 *addrSpaceSize);
|
||||
uintptr_t configureStage2MemoryMap(u32 *addrSpaceSize);
|
||||
uintptr_t stage2Configure(u32 *addrSpaceSize);
|
||||
@@ -28,16 +28,23 @@
|
||||
|
||||
//115200
|
||||
|
||||
static uintptr_t g_uartRegBase;
|
||||
|
||||
static inline volatile PL011UartRegisters *uartGetRegisters(UartDevice dev)
|
||||
{
|
||||
switch (dev) {
|
||||
case UART_A:
|
||||
return (volatile PL011UartRegisters *)0x09000000;
|
||||
return (volatile PL011UartRegisters *)g_uartRegBase;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void uartSetRegisterBase(uintptr_t regBase)
|
||||
{
|
||||
g_uartRegBase = regBase;
|
||||
}
|
||||
|
||||
void uartInit(UartDevice dev, u32 baudRate, u32 flags)
|
||||
{
|
||||
/* The TRM (DDI0183) reads:
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "../../utils.h"
|
||||
#include "interrupt_config.h"
|
||||
|
||||
#define MEMORY_MAP_PA_UART 0x09000000ull
|
||||
|
||||
// AMBA PL011 driver
|
||||
// Originally from
|
||||
/*
|
||||
@@ -56,10 +58,10 @@ typedef struct PL011UartRegisters {
|
||||
} PL011UartRegisters;
|
||||
|
||||
// Data status bits
|
||||
#define UART_DATA_ERROR_MASK 0x0F00
|
||||
#define PL011_DATA_ERROR_MASK 0x0F00
|
||||
|
||||
// Status reg bits
|
||||
#define UART_STATUS_ERROR_MASK 0x0F
|
||||
#define PL011_STATUS_ERROR_MASK 0x0F
|
||||
|
||||
// Errors
|
||||
#define PL011_OE BIT(3) // Overrun error
|
||||
@@ -128,6 +130,7 @@ typedef struct PL011UartRegisters {
|
||||
|
||||
#define UART_CLK_IN_HZ 1
|
||||
|
||||
void uartSetRegisterBase(uintptr_t regBase);
|
||||
void uartInit(UartDevice dev, u32 baudRate, u32 flags);
|
||||
void uartWriteData(UartDevice dev, const void *buffer, size_t size);
|
||||
void uartReadData(UartDevice dev, void *buffer, size_t size);
|
||||
|
||||
@@ -17,56 +17,12 @@
|
||||
#include "../utils.h"
|
||||
#include "../sysreg.h"
|
||||
#include "../mmu.h"
|
||||
#include "memory_map_mmu_cfg.h"
|
||||
#include "stage2.h"
|
||||
|
||||
void configureMemoryMapEnableMmu(void)
|
||||
void stage2ConfigureAndEnable(void)
|
||||
{
|
||||
u32 addrSpaceSize;
|
||||
uintptr_t ttbr0 = configureMemoryMap(&addrSpaceSize);
|
||||
|
||||
u32 ps = GET_SYSREG(id_aa64mmfr0_el1) & 0xF;
|
||||
/*
|
||||
- PA size: from ID_AA64MMFR0_EL1
|
||||
- Granule size: 4KB
|
||||
- Shareability attribute for memory associated with translation table walks using TTBR0_EL2: Inner Shareable
|
||||
- Outer cacheability attribute for memory associated with translation table walks using TTBR0_EL2: Normal memory, Outer Write-Back Read-Allocate Write-Allocate Cacheable
|
||||
- Inner cacheability attribute for memory associated with translation table walks using TTBR0_EL2: Normal memory, Inner Write-Back Read-Allocate Write-Allocate Cacheable
|
||||
- T0SZ = from configureMemoryMap
|
||||
*/
|
||||
u64 tcr = TCR_EL2_RSVD | TCR_PS(ps) | TCR_TG0_4K | TCR_SHARED_INNER | TCR_ORGN_WBWA | TCR_IRGN_WBWA | TCR_T0SZ(addrSpaceSize);
|
||||
|
||||
|
||||
/*
|
||||
- Attribute 0: Normal memory, Inner and Outer Write-Back Read-Allocate Write-Allocate Non-transient
|
||||
- Attribute 1: Device-nGnRE memory
|
||||
- Other attributes: Device-nGnRnE memory
|
||||
*/
|
||||
u64 mair = 0x4FFull;
|
||||
|
||||
// MMU regs config
|
||||
SET_SYSREG(ttbr0_el2, ttbr0);
|
||||
SET_SYSREG(tcr_el2, tcr);
|
||||
SET_SYSREG(mair_el2, mair);
|
||||
__dsb();
|
||||
__isb();
|
||||
|
||||
// TLB invalidation
|
||||
__tlb_invalidate_el2();
|
||||
__dsb();
|
||||
__isb();
|
||||
|
||||
// Enable MMU & enable caching
|
||||
u64 sctlr = GET_SYSREG(sctlr_el2);
|
||||
sctlr |= SCTLR_ELx_I | SCTLR_ELx_C | SCTLR_ELx_M;
|
||||
SET_SYSREG(sctlr_el2, sctlr);
|
||||
__dsb();
|
||||
__isb();
|
||||
}
|
||||
|
||||
void configureMemoryMapEnableStage2(void)
|
||||
{
|
||||
u32 addrSpaceSize;
|
||||
uintptr_t vttbr = configureStage2MemoryMap(&addrSpaceSize);
|
||||
uintptr_t vttbr = stage2Configure(&addrSpaceSize);
|
||||
|
||||
u32 ps = GET_SYSREG(id_aa64mmfr0_el1) & 0xF;
|
||||
/*
|
||||
@@ -86,15 +42,15 @@ void configureMemoryMapEnableStage2(void)
|
||||
__dsb();
|
||||
__isb();
|
||||
|
||||
// TLB invalidation
|
||||
__tlb_invalidate_el1_stage12();
|
||||
__dsb();
|
||||
__isb();
|
||||
|
||||
// Enable stage 2
|
||||
u64 hcr = GET_SYSREG(hcr_el2);
|
||||
hcr |= HCR_VM;
|
||||
SET_SYSREG(hcr_el2, hcr);
|
||||
__dsb();
|
||||
__isb();
|
||||
|
||||
// TLB invalidation
|
||||
__tlb_invalidate_el1_stage12_local();
|
||||
__dsb();
|
||||
__isb();
|
||||
}
|
||||
@@ -18,13 +18,12 @@
|
||||
|
||||
#ifdef PLATFORM_TEGRA
|
||||
|
||||
#include "tegra/memory_map.h"
|
||||
#include "tegra/stage2_config.h"
|
||||
|
||||
#elif defined(PLATFORM_QEMU)
|
||||
|
||||
#include "qemu/memory_map.h"
|
||||
#include "qemu/stage2_config.h"
|
||||
|
||||
#endif
|
||||
|
||||
void configureMemoryMapEnableMmu(void);
|
||||
void configureMemoryMapEnableStage2(void);
|
||||
void stage2ConfigureAndEnable(void);
|
||||
@@ -15,9 +15,20 @@
|
||||
*/
|
||||
|
||||
#include "car.h"
|
||||
#include "timers.h"
|
||||
#include "../../utils.h"
|
||||
|
||||
static uintptr_t g_carRegs;
|
||||
|
||||
static inline volatile tegra_car_t *car_get_regs(void)
|
||||
{
|
||||
return (volatile tegra_car_t *)g_carRegs;
|
||||
}
|
||||
|
||||
static inline volatile uint32_t *car_reg_at(uint32_t offset)
|
||||
{
|
||||
return (volatile uint32_t *)(g_carRegs + offset);
|
||||
}
|
||||
|
||||
static inline uint32_t get_clk_source_reg(CarDevice dev) {
|
||||
switch (dev) {
|
||||
case CARDEVICE_UARTA: return 0x178;
|
||||
@@ -93,24 +104,29 @@ static inline uint32_t get_clk_source_div(CarDevice dev) {
|
||||
static uint32_t g_clk_reg_offsets[NUM_CAR_BANKS] = {0x010, 0x014, 0x018, 0x360, 0x364, 0x280, 0x298};
|
||||
static uint32_t g_rst_reg_offsets[NUM_CAR_BANKS] = {0x004, 0x008, 0x00C, 0x358, 0x35C, 0x28C, 0x2A4};
|
||||
|
||||
void car_set_regs(uintptr_t regs)
|
||||
{
|
||||
g_carRegs = regs;
|
||||
}
|
||||
|
||||
void clk_enable(CarDevice dev) {
|
||||
uint32_t clk_source_reg;
|
||||
if ((clk_source_reg = get_clk_source_reg(dev))) {
|
||||
MAKE_CAR_REG(clk_source_reg) = (get_clk_source_val(dev) << 29) | get_clk_source_div(dev);
|
||||
*car_reg_at(clk_source_reg) = (get_clk_source_val(dev) << 29) | get_clk_source_div(dev);
|
||||
}
|
||||
MAKE_CAR_REG(g_clk_reg_offsets[dev >> 5]) |= BIT(dev & 0x1F);
|
||||
*car_reg_at(g_clk_reg_offsets[dev >> 5]) |= BIT(dev & 0x1F);
|
||||
}
|
||||
|
||||
void clk_disable(CarDevice dev) {
|
||||
MAKE_CAR_REG(g_clk_reg_offsets[dev >> 5]) &= ~(BIT(dev & 0x1F));
|
||||
*car_reg_at(g_clk_reg_offsets[dev >> 5]) &= ~(BIT(dev & 0x1F));
|
||||
}
|
||||
|
||||
void rst_enable(CarDevice dev) {
|
||||
MAKE_CAR_REG(g_rst_reg_offsets[dev >> 5]) |= BIT(dev & 0x1F);
|
||||
*car_reg_at(g_rst_reg_offsets[dev >> 5]) |= BIT(dev & 0x1F);
|
||||
}
|
||||
|
||||
void rst_disable(CarDevice dev) {
|
||||
MAKE_CAR_REG(g_rst_reg_offsets[dev >> 5]) &= ~(BIT(dev & 0x1F));
|
||||
*car_reg_at(g_rst_reg_offsets[dev >> 5]) &= ~(BIT(dev & 0x1F));
|
||||
}
|
||||
|
||||
void clkrst_enable(CarDevice dev) {
|
||||
@@ -127,10 +143,10 @@ void clkrst_reboot(CarDevice dev) {
|
||||
clkrst_disable(dev);
|
||||
if (dev == CARDEVICE_KFUSE) {
|
||||
/* Workaround for KFUSE clock. */
|
||||
clk_enable(dev);
|
||||
/*clk_enable(dev);
|
||||
udelay(100);
|
||||
rst_disable(dev);
|
||||
udelay(200);
|
||||
udelay(200);*/
|
||||
} else {
|
||||
clkrst_enable(dev);
|
||||
}
|
||||
|
||||
@@ -17,8 +17,7 @@
|
||||
#pragma once
|
||||
#include "../../utils.h"
|
||||
|
||||
#define CAR_BASE 0x60006000
|
||||
#define MAKE_CAR_REG(n) MAKE_REG32(CAR_BASE + n)
|
||||
#define MEMORY_MAP_PA_CAR 0x60006000ul
|
||||
|
||||
#define CLK_L_SDMMC1 (1 << 14)
|
||||
#define CLK_L_SDMMC2 (1 << 9)
|
||||
@@ -485,9 +484,7 @@ typedef struct {
|
||||
uint32_t sdmmc4_div_clk_shaper_ctrl; /* _SDMMC4_DIV_CLK_SHAPER_CTRL_0, 0x744 */
|
||||
} tegra_car_t;
|
||||
|
||||
static inline volatile tegra_car_t *car_get_regs(void) {
|
||||
return (volatile tegra_car_t *)CAR_BASE;
|
||||
}
|
||||
void car_set_regs(uintptr_t regs);
|
||||
|
||||
void clk_enable(CarDevice dev);
|
||||
void clk_disable(CarDevice dev);
|
||||
|
||||
38
thermosphere/src/platform/tegra/devices.c
Normal file
38
thermosphere/src/platform/tegra/devices.c
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "devices.h"
|
||||
#include "../../memory_map.h"
|
||||
#include "../../utils.h"
|
||||
|
||||
#include "uart.h"
|
||||
#include "car.h"
|
||||
#include "gpio.h"
|
||||
#include "pinmux.h"
|
||||
|
||||
void devicesMapAllExtra(void)
|
||||
{
|
||||
uartSetRegisterBase(memoryMapPlatformMmio(MEMORY_MAP_PA_UART, 0x1000));
|
||||
|
||||
car_set_regs(memoryMapPlatformMmio(MEMORY_MAP_PA_CAR, 0x1000));
|
||||
gpio_set_regs(memoryMapPlatformMmio(MEMORY_MAP_PA_GPIO, 0x1000));
|
||||
pinmux_set_regs(memoryMapPlatformMmio(MEMORY_MAP_PA_PINMUX, 0x1000));
|
||||
|
||||
// Don't broadcast, since it's only ran once per boot by only one core, before the others are started...
|
||||
__tlb_invalidate_el2_local();
|
||||
__dsb();
|
||||
__isb();
|
||||
}
|
||||
19
thermosphere/src/platform/tegra/devices.h
Normal file
19
thermosphere/src/platform/tegra/devices.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
void devicesMapAllExtra(void);
|
||||
@@ -19,6 +19,13 @@
|
||||
#include "gpio.h"
|
||||
#include "../../utils.h"
|
||||
|
||||
static uintptr_t g_gpioRegs;
|
||||
|
||||
static inline volatile tegra_gpio_t *gpio_get_regs(void)
|
||||
{
|
||||
return (volatile tegra_gpio_t *)g_gpioRegs;
|
||||
}
|
||||
|
||||
static volatile tegra_gpio_bank_t *gpio_get_bank(uint32_t pin) {
|
||||
volatile tegra_gpio_t *gpio = gpio_get_regs();
|
||||
uint32_t bank_number = (pin >> GPIO_BANK_SHIFT);
|
||||
@@ -67,6 +74,11 @@ static bool gpio_simple_register_get(uint32_t pin, uint32_t offset) {
|
||||
return !!(cluster[port] & mask);
|
||||
}
|
||||
|
||||
void gpio_set_regs(uintptr_t regs)
|
||||
{
|
||||
g_gpioRegs = regs;
|
||||
}
|
||||
|
||||
void gpio_configure_mode(uint32_t pin, uint32_t mode) {
|
||||
gpio_simple_register_set(pin, mode == GPIO_MODE_GPIO, offsetof(tegra_gpio_bank_t, config));
|
||||
}
|
||||
|
||||
@@ -17,16 +17,15 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#define GPIO_BASE 0x6000D000
|
||||
#define MAKE_GPIO_REG(n) MAKE_REG32(GPIO_BASE + n)
|
||||
#define MEMORY_MAP_PA_GPIO 0x6000D000ul
|
||||
|
||||
#define TEGRA_GPIO_PORTS 4
|
||||
#define TEGRA_GPIO_BANKS 8
|
||||
#define GPIO_BANK_SHIFT 5
|
||||
#define GPIO_BANK_SHIFT 5
|
||||
#define GPIO_PORT_SHIFT 3
|
||||
#define GPIO_PORT_MASK 0x03
|
||||
#define GPIO_PIN_MASK 0x07
|
||||
|
||||
|
||||
typedef enum {
|
||||
TEGRA_GPIO_PORT_A = 0,
|
||||
TEGRA_GPIO_PORT_B = 1,
|
||||
@@ -85,11 +84,6 @@ typedef struct {
|
||||
tegra_gpio_bank_t bank[TEGRA_GPIO_BANKS];
|
||||
} tegra_gpio_t;
|
||||
|
||||
static inline volatile tegra_gpio_t *gpio_get_regs(void)
|
||||
{
|
||||
return (volatile tegra_gpio_t *)GPIO_BASE;
|
||||
}
|
||||
|
||||
#define TEGRA_GPIO(port, offset) \
|
||||
((TEGRA_GPIO_PORT_##port * 8) + offset)
|
||||
|
||||
@@ -117,6 +111,7 @@ static inline volatile tegra_gpio_t *gpio_get_regs(void)
|
||||
#define GPIO_LCD_BL_EN TEGRA_GPIO(V, 1)
|
||||
#define GPIO_LCD_BL_RST TEGRA_GPIO(V, 2)
|
||||
|
||||
void gpio_set_regs(uintptr_t regs);
|
||||
void gpio_configure_mode(uint32_t pin, uint32_t mode);
|
||||
void gpio_configure_direction(uint32_t pin, uint32_t dir);
|
||||
void gpio_write(uint32_t pin, uint32_t value);
|
||||
|
||||
@@ -18,8 +18,10 @@
|
||||
|
||||
#include "../../gicv2.h"
|
||||
|
||||
// For both guest and host
|
||||
#define MAX_NUM_REGISTERED_INTERRUPTS 512
|
||||
#define MEMORY_MAP_PA_GICD 0x50041000ull
|
||||
#define MEMORY_MAP_PA_GICC 0x50042000ull
|
||||
#define MEMORY_MAP_PA_GICH 0x50044000ull
|
||||
#define MEMORY_MAP_PA_GICV 0x50046000ull
|
||||
|
||||
#define GIC_IRQID_MAINTENANCE 25
|
||||
#define GIC_IRQID_NS_PHYS_HYP_TIMER 26
|
||||
@@ -37,11 +39,3 @@
|
||||
#define GIC_IRQID_UARTB (32 + 37)
|
||||
#define GIC_IRQID_UARTC (32 + 46)
|
||||
#define GIC_IRQID_UARTD (32 + 90)
|
||||
|
||||
static inline void initGicV2Pointers(ArmGicV2 *gic)
|
||||
{
|
||||
gic->gicd = (volatile ArmGicV2Distributor *)0x50041000ull;
|
||||
gic->gicc = (volatile ArmGicV2Controller *)0x50042000ull;
|
||||
gic->gich = (volatile ArmGicV2VirtualInterfaceController *)0x50044000ull;
|
||||
gic->gicv = (volatile ArmGicV2Controller *)0x50046000ull;
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../utils.h"
|
||||
|
||||
#define MISC_BASE 0x70000000ull
|
||||
|
||||
#define MAKE_MISC_REG(n) MAKE_REG32(MISC_BASE + n)
|
||||
|
||||
|
||||
#define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 MAKE_MISC_REG(0x0C00)
|
||||
#define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0 MAKE_MISC_REG(0x0C04)
|
||||
#define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0 MAKE_MISC_REG(0x0C08)
|
||||
|
||||
#define PINMUX_AUX_GEN1_I2C_SCL_0 MAKE_MISC_REG(0x30BC)
|
||||
#define PINMUX_AUX_GEN1_I2C_SDA_0 MAKE_MISC_REG(0x30C0)
|
||||
|
||||
#define PINMUX_AUX_UARTn_TX_0(n) MAKE_MISC_REG(0x30E4 + 0x10 * (n))
|
||||
#define PINMUX_AUX_UARTn_RX_0(n) MAKE_MISC_REG(0x30E8 + 0x10 * (n))
|
||||
#define PINMUX_AUX_UARTn_RTS_0(n) MAKE_MISC_REG(0x30EC + 0x10 * (n))
|
||||
#define PINMUX_AUX_UARTn_CTS_0(n) MAKE_MISC_REG(0x30F0 + 0x10 * (n))
|
||||
19
thermosphere/src/platform/tegra/pinmux.c
Normal file
19
thermosphere/src/platform/tegra/pinmux.c
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pinmux.h"
|
||||
|
||||
uintptr_t g_pinmuxRegs;
|
||||
@@ -18,8 +18,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PINMUX_BASE 0x70003000
|
||||
#define MAKE_PINMUX_REG(n) MAKE_REG32(PINMUX_BASE + n)
|
||||
#define MEMORY_MAP_PA_PINMUX 0x70003000ul
|
||||
|
||||
#define PINMUX_TRISTATE (1 << 4)
|
||||
#define PINMUX_PARKED (1 << 5)
|
||||
@@ -30,7 +29,7 @@
|
||||
#define PINMUX_SELECT_FUNCTION0 0
|
||||
#define PINMUX_SELECT_FUNCTION1 1
|
||||
#define PINMUX_SELECT_FUNCTION2 2
|
||||
#define PINMUX_SELECT_FUNCTION3 3
|
||||
#define PINMUX_SELECT_FUNCTION3 3
|
||||
#define PINMUX_DRIVE_1X (0 << 13)
|
||||
#define PINMUX_DRIVE_2X (1 << 13)
|
||||
#define PINMUX_DRIVE_3X (2 << 13)
|
||||
@@ -204,7 +203,14 @@ typedef struct {
|
||||
uint32_t pz5;
|
||||
} tegra_pinmux_t;
|
||||
|
||||
extern uintptr_t g_pinmuxRegs;
|
||||
|
||||
static inline void pinmux_set_regs(uintptr_t regs)
|
||||
{
|
||||
g_pinmuxRegs = regs;
|
||||
}
|
||||
|
||||
static inline volatile tegra_pinmux_t *pinmux_get_regs(void)
|
||||
{
|
||||
return (volatile tegra_pinmux_t *)PINMUX_BASE;
|
||||
return (volatile tegra_pinmux_t *)g_pinmuxRegs;
|
||||
}
|
||||
|
||||
@@ -14,21 +14,19 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "memory_map.h"
|
||||
#include "stage2_config.h"
|
||||
#include "interrupt_config.h"
|
||||
#include "../../utils.h"
|
||||
#include "../../mmu.h"
|
||||
#include "../../core_ctx.h"
|
||||
|
||||
// Tegra PA size is 36-bit... should we limit ourselves to 34?
|
||||
// i.e. 14GB of dram max
|
||||
#define ADDRSPACESZ 36
|
||||
#define ADDRSPACESZ2 ADDRSPACESZ
|
||||
|
||||
static ALIGN(0x1000) u64 g_ttbl[BIT(ADDRSPACESZ - 30)] = {0};
|
||||
|
||||
static ALIGN(0x1000) u64 g_vttbl[BIT(ADDRSPACESZ2 - 30)] = {0};
|
||||
static TEMPORARY ALIGN(0x1000) u64 g_vttbl[BIT(ADDRSPACESZ2 - 30)] = {0};
|
||||
static TEMPORARY ALIGN(0x1000) u64 g_vttbl_l2_mmio_0[512] = {0};
|
||||
static TEMPORARY ALIGN(0x1000) u64 g_vttbl_l3_0[512] = {0};
|
||||
static TEMPORARY uintptr_t g_vttblPaddr;
|
||||
|
||||
static inline void identityMapL1(u64 *tbl, uintptr_t addr, size_t size, u64 attribs)
|
||||
{
|
||||
@@ -45,37 +43,30 @@ static inline void identityMapL3(u64 *tbl, uintptr_t addr, size_t size, u64 attr
|
||||
mmu_map_block_range(3, tbl, addr, addr, size, attribs | MMU_PTE_BLOCK_INNER_SHAREBLE);
|
||||
}
|
||||
|
||||
uintptr_t configureMemoryMap(u32 *addrSpaceSize)
|
||||
{
|
||||
*addrSpaceSize = ADDRSPACESZ;
|
||||
if (currentCoreCtx->isBootCore && !currentCoreCtx->warmboot) {
|
||||
identityMapL1(g_ttbl, 0x00000000ull, 2 * BITL(30), ATTRIB_MEMTYPE_DEVICE);
|
||||
identityMapL1(g_ttbl, 0x80000000ull, (BITL(ADDRSPACESZ - 30) - 2ull) << 30, ATTRIB_MEMTYPE_NORMAL);
|
||||
}
|
||||
|
||||
return (uintptr_t)g_ttbl;
|
||||
}
|
||||
|
||||
uintptr_t configureStage2MemoryMap(u32 *addrSpaceSize)
|
||||
uintptr_t stage2Configure(u32 *addrSpaceSize)
|
||||
{
|
||||
*addrSpaceSize = ADDRSPACESZ2;
|
||||
static const u64 devattrs = MMU_S2AP_RW | MMU_MEMATTR_DEVICE_NGNRE;
|
||||
static const u64 devattrs = MMU_PTE_BLOCK_XN | MMU_S2AP_RW | MMU_MEMATTR_DEVICE_NGNRE;
|
||||
static const u64 unchanged = MMU_S2AP_RW | MMU_MEMATTR_NORMAL_CACHEABLE_OR_UNCHANGED;
|
||||
if (currentCoreCtx->isBootCore) {
|
||||
g_vttblPaddr = va2pa(g_vttbl);
|
||||
uintptr_t *l2pa = (uintptr_t *)va2pa(g_vttbl_l2_mmio_0);
|
||||
uintptr_t *l3pa = (uintptr_t *)va2pa(g_vttbl_l3_0);
|
||||
|
||||
identityMapL1(g_vttbl, 0x00000000ull, BITL(30), unchanged);
|
||||
identityMapL1(g_vttbl, 0x80000000ull, (BITL(ADDRSPACESZ2 - 30) - 2ull) << 30, unchanged);
|
||||
mmu_map_table(1, g_vttbl, 0x40000000ull, g_vttbl_l2_mmio_0, 0);
|
||||
mmu_map_table(1, g_vttbl, 0x40000000ull, l2pa, 0);
|
||||
|
||||
identityMapL2(g_vttbl_l2_mmio_0, 0x40000000ull, BITL(30), unchanged);
|
||||
mmu_map_table(2, g_vttbl_l2_mmio_0, 0x50000000ull, g_vttbl_l3_0, 0);
|
||||
mmu_map_table(2, g_vttbl_l2_mmio_0, 0x50000000ull, l3pa, 0);
|
||||
|
||||
identityMapL3(g_vttbl_l3_0, 0x00000000ull, BITL(21), unchanged);
|
||||
|
||||
// GICD -> trapped, GICv2 CPU -> vCPU interface, GICH -> trapped (access denied including for the unused view)
|
||||
mmu_unmap_page(g_vttbl_l3_0, 0x50401000ull);
|
||||
mmu_unmap_page(g_vttbl_l3_0, 0x50404000ull);
|
||||
mmu_unmap_page(g_vttbl_l3_0, 0x50405000ull);
|
||||
mmu_map_page_range(g_vttbl_l3_0, 0x50042000ull, 0x50046000ull, 0x2000ull, devattrs);
|
||||
mmu_unmap_page(g_vttbl_l3_0, MEMORY_MAP_PA_GICD);
|
||||
mmu_unmap_page(g_vttbl_l3_0, MEMORY_MAP_PA_GICH);
|
||||
mmu_unmap_page(g_vttbl_l3_0, MEMORY_MAP_PA_GICH + 0x1000ull);
|
||||
mmu_map_page_range(g_vttbl_l3_0, MEMORY_MAP_PA_GICC, MEMORY_MAP_PA_GICD, 0x2000ull, devattrs);
|
||||
}
|
||||
|
||||
return (uintptr_t)g_vttbl;
|
||||
@@ -18,6 +18,5 @@
|
||||
|
||||
#include "../../types.h"
|
||||
|
||||
uintptr_t configureMemoryMap(u32 *addrSpaceSize);
|
||||
uintptr_t configureStage2MemoryMap(u32 *addrSpaceSize);
|
||||
uintptr_t stage2Configure(u32 *addrSpaceSize);
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../../utils.h"
|
||||
|
||||
#define TIMERS_BASE 0x60005000
|
||||
#define MAKE_TIMERS_REG(n) MAKE_REG32(TIMERS_BASE + n)
|
||||
|
||||
#define TIMERUS_CNTR_1US_0 MAKE_TIMERS_REG(0x10)
|
||||
#define TIMERUS_USEC_CFG_0 MAKE_TIMERS_REG(0x14)
|
||||
#define SHARED_INTR_STATUS_0 MAKE_TIMERS_REG(0x1A0)
|
||||
#define SHARED_TIMER_SECURE_CFG_0 MAKE_TIMERS_REG(0x1A4)
|
||||
|
||||
#define RTC_BASE 0x7000E000
|
||||
#define MAKE_RTC_REG(n) MAKE_REG32(RTC_BASE + n)
|
||||
|
||||
#define RTC_SECONDS MAKE_RTC_REG(0x08)
|
||||
#define RTC_SHADOW_SECONDS MAKE_RTC_REG(0x0C)
|
||||
#define RTC_MILLI_SECONDS MAKE_RTC_REG(0x10)
|
||||
|
||||
typedef struct {
|
||||
uint32_t CONFIG;
|
||||
uint32_t STATUS;
|
||||
uint32_t COMMAND;
|
||||
uint32_t PATTERN;
|
||||
} watchdog_timers_t;
|
||||
|
||||
#define GET_WDT(n) ((volatile watchdog_timers_t *)(TIMERS_BASE + 0x100 + 0x20 * n))
|
||||
#define WDT_REBOOT_PATTERN 0xC45A
|
||||
#define GET_WDT_REBOOT_CFG_REG(n) MAKE_REG32(TIMERS_BASE + 0x60 + 0x8 * n)
|
||||
|
||||
void wait(uint32_t microseconds);
|
||||
|
||||
static inline uint32_t get_time_s(void) {
|
||||
return RTC_SECONDS;
|
||||
}
|
||||
|
||||
static inline uint32_t get_time_ms(void) {
|
||||
return (RTC_MILLI_SECONDS | (RTC_SHADOW_SECONDS << 10));
|
||||
}
|
||||
|
||||
static inline uint32_t get_time_us(void) {
|
||||
return TIMERUS_CNTR_1US_0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time in microseconds.
|
||||
*/
|
||||
static inline uint32_t get_time(void) {
|
||||
return get_time_us();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of microseconds that have passed since a given get_time().
|
||||
*/
|
||||
static inline uint32_t get_time_since(uint32_t base) {
|
||||
return get_time_us() - base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delays for a given number of microseconds.
|
||||
*/
|
||||
static inline void udelay(uint32_t usecs) {
|
||||
uint32_t start = get_time_us();
|
||||
while (get_time_us() - start < usecs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delays until a number of usecs have passed since an absolute start time.
|
||||
*/
|
||||
static inline void udelay_absolute(uint32_t start, uint32_t usecs) {
|
||||
while (get_time_us() - start < usecs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delays for a given number of milliseconds.
|
||||
*/
|
||||
static inline void mdelay(uint32_t msecs) {
|
||||
uint32_t start = get_time_ms();
|
||||
while (get_time_ms() - start < msecs);
|
||||
}
|
||||
@@ -16,28 +16,28 @@
|
||||
*/
|
||||
|
||||
#include "uart.h"
|
||||
#include "timers.h"
|
||||
#include "pinmux.h"
|
||||
#include "gpio.h"
|
||||
#include "car.h"
|
||||
#include "../../irq.h"
|
||||
#include "../../timer.h"
|
||||
|
||||
#define UART_BASE 0x70006000
|
||||
static uintptr_t g_uartRegBase;
|
||||
|
||||
static inline volatile tegra_uart_t *uartGetRegisters(UartDevice dev)
|
||||
{
|
||||
static const size_t offsets[] = { 0, 0x40, 0x200, 0x300, 0x400 };
|
||||
return (volatile tegra_uart_t *)(UART_BASE + offsets[dev]);
|
||||
return (volatile tegra_uart_t *)(g_uartRegBase + offsets[dev]);
|
||||
}
|
||||
|
||||
static inline void uartWaitCycles(u32 baud, u32 num)
|
||||
{
|
||||
udelay((num * 1000000 + 16 * baud - 1) / (16 * baud));
|
||||
timerWaitUsecs((num * 1000000 + 16 * baud - 1) / (16 * baud));
|
||||
}
|
||||
|
||||
static inline void uartWaitSyms(u32 baud, u32 num)
|
||||
{
|
||||
udelay((num * 1000000 + baud - 1) / baud);
|
||||
timerWaitUsecs((num * 1000000 + baud - 1) / baud);
|
||||
}
|
||||
|
||||
static void uartSetPinmuxConfig(UartDevice dev) {
|
||||
@@ -96,7 +96,7 @@ static void uartReset(UartDevice dev)
|
||||
|
||||
|
||||
// This function blocks until the UART device is in the desired state.
|
||||
void uartWaitIdle(UartDevice dev, UartVendorStatus status)
|
||||
static void uartWaitIdle(UartDevice dev, UartVendorStatus status)
|
||||
{
|
||||
volatile tegra_uart_t *uart = uartGetRegisters(dev);
|
||||
|
||||
@@ -109,6 +109,11 @@ void uartWaitIdle(UartDevice dev, UartVendorStatus status)
|
||||
}
|
||||
}
|
||||
|
||||
void uartSetRegisterBase(uintptr_t regBase)
|
||||
{
|
||||
g_uartRegBase = regBase;
|
||||
}
|
||||
|
||||
void uartInit(UartDevice dev, u32 baud, u32 flags)
|
||||
{
|
||||
volatile tegra_uart_t *uart = uartGetRegisters(dev);
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include "../../utils.h"
|
||||
#include "interrupt_config.h"
|
||||
|
||||
#define MEMORY_MAP_PA_UART 0x70006000ul
|
||||
|
||||
/* UART devices */
|
||||
typedef enum UartDevice {
|
||||
UART_A = 0,
|
||||
@@ -191,6 +193,7 @@ typedef struct {
|
||||
u32 asr;
|
||||
} tegra_uart_t;
|
||||
|
||||
void uartSetRegisterBase(uintptr_t regBase);
|
||||
void uartInit(UartDevice dev, u32 baud, u32 flags);
|
||||
void uartWriteData(UartDevice dev, const void *buffer, size_t size);
|
||||
void uartReadData(UartDevice dev, void *buffer, size_t size);
|
||||
|
||||
Reference in New Issue
Block a user