#include "opt_soc.h"
#include "opt_console.h"
#include "arml2cc.h"
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: omap3_platform.c,v 1.11 2026/01/08 00:26:38 christos Exp $");
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/cpu.h>
#include <sys/device.h>
#include <sys/termios.h>
#include <dev/fdt/fdtvar.h>
#include <dev/fdt/fdt_platform.h>
#include <arm/fdt/arm_fdtvar.h>
#include <uvm/uvm_extern.h>
#include <machine/bootconfig.h>
#include <arm/cpufunc.h>
#include <dev/ic/ns16550reg.h>
#include <dev/ic/comreg.h>
#include <evbarm/fdt/platform.h>
#include <evbarm/fdt/machdep.h>
#include <net/if_ether.h>
#include <libfdt.h>
#include <arm/cortex/pl310_var.h>
#include <arm/cortex/scu_reg.h>
#include <arm/ti/smc.h>
#define OMAP3_L4_CORE_VBASE KERNEL_IO_VBASE
#define OMAP3_L4_CORE_PBASE 0x48000000
#define OMAP3_L4_CORE_SIZE 0x00100000
#define OMAP3_L4_WKUP_VBASE (OMAP3_L4_CORE_VBASE + OMAP3_L4_CORE_SIZE)
#define OMAP3_L4_WKUP_PBASE 0x48300000
#define OMAP3_L4_WKUP_SIZE 0x00100000
#define OMAP3_L4_PER_VBASE (OMAP3_L4_WKUP_VBASE + OMAP3_L4_WKUP_SIZE)
#define OMAP3_L4_PER_PBASE 0x49000000
#define OMAP3_L4_PER_SIZE 0x00100000
#define OMAP3_PRCM_BASE 0x48306000
#define OMAP3_PRCM_GR_BASE (OMAP3_PRCM_BASE + 0x1200)
#define OMAP3_PRM_RSTCTRL (OMAP3_PRCM_GR_BASE + 0x50)
#define OMAP3_PRM_RSTCTRL_RST_DPLL3 __BIT(2)
#define OMAP3_32KTIMER_BASE 0x48320000
#define OMAP3_REG_32KSYNCNT_CR (OMAP3_32KTIMER_BASE + 0x10)
#define OMAP4_L4_PER_VBASE KERNEL_IO_VBASE
#define OMAP4_L4_PER_PBASE 0x48000000
#define OMAP4_L4_PER_SIZE 0x01000000
#define OMAP4_L4_ABE_VBASE (OMAP4_L4_PER_VBASE + OMAP4_L4_PER_SIZE)
#define OMAP4_L4_ABE_PBASE 0x49000000
#define OMAP4_L4_ABE_SIZE 0x01000000
#define OMAP4_L4_CFG_VBASE (OMAP4_L4_ABE_VBASE + OMAP4_L4_ABE_SIZE)
#define OMAP4_L4_CFG_PBASE 0x4a000000
#define OMAP4_L4_CFG_SIZE 0x01000000
#define OMAP4_SCU_BASE 0x48240000
#define OMAP4_PL310_BASE 0x48242000
#define OMAP4_WUGEN_BASE 0x48281000
#define OMAP4_AUX_CORE_BOOT0 0x800
#define OMAP4_AUX_CORE_BOOT1 0x804
#define OMAP4_CM1_BASE 0x4a004000
#define OMAP4_CKGEN_CM1_BASE (OMAP4_CM1_BASE + 0x100)
#define OMAP4_CLKSEL_DPLL_MPU (OMAP4_CKGEN_CM1_BASE + 0x6c)
#define OMAP4_DIV_M2_DPLL_MPU (OMAP4_CKGEN_CM1_BASE + 0x70)
#define OMAP4_PRM_BASE 0x4a306000
#define OMAP4_CKGEN_PRM_BASE (OMAP4_PRM_BASE + 0x100)
#define OMAP4_SYS_CLKSEL (OMAP4_CKGEN_PRM_BASE + 0x10)
#define OMAP4_SYS_CLKSEL_CLKIN __BITS(2,0)
#define OMAP4_DEVICE_PRM_BASE (OMAP4_PRM_BASE + 0x1b00)
#define OMAP4_PRM_RSTCTRL OMAP4_DEVICE_PRM_BASE
#define OMAP4_RST_GLOBAL_COLD __BIT(1)
#define OMAP4_32KTIMER_BASE 0x4a304000
#define OMAP4_REG_32KSYNCNT_CR (OMAP4_32KTIMER_BASE + 0x10)
#define OMAP4_DPLL_MULT __BITS(18,8)
#define OMAP4_DPLL_DIV __BITS(6,0)
#define OMAP4_DPLL_CLKOUT_DIV __BITS(4,0)
#define OMAP4_SYS_CLKSEL_FREQS { 0, 12000, 0, 16800, 19200, 26000, 0, 38400 }
static inline vaddr_t
omap3_phystovirt(paddr_t pa)
{
if (pa >= OMAP3_L4_CORE_PBASE &&
pa < OMAP3_L4_CORE_PBASE + OMAP3_L4_CORE_SIZE)
return (pa - OMAP3_L4_CORE_PBASE) + OMAP3_L4_CORE_VBASE;
if (pa >= OMAP3_L4_WKUP_PBASE &&
pa < OMAP3_L4_WKUP_PBASE + OMAP3_L4_WKUP_SIZE)
return (pa - OMAP3_L4_WKUP_PBASE) + OMAP3_L4_WKUP_VBASE;
if (pa >= OMAP3_L4_PER_PBASE &&
pa < OMAP3_L4_PER_PBASE + OMAP3_L4_PER_SIZE)
return (pa - OMAP3_L4_PER_PBASE) + OMAP3_L4_PER_VBASE;
panic("%s: pa %#x not in devmap", __func__, (uint32_t)pa);
}
#define OMAP3_PHYSTOVIRT(pa) \
(((pa) - OMAP3_L4_CORE_VBASE) + OMAP3_L4_CORE_PBASE)
static inline vaddr_t
omap4_phystovirt(paddr_t pa)
{
if (pa >= OMAP4_L4_PER_PBASE &&
pa < OMAP4_L4_PER_PBASE + OMAP4_L4_PER_SIZE)
return (pa - OMAP4_L4_PER_PBASE) + OMAP4_L4_PER_VBASE;
if (pa >= OMAP4_L4_ABE_PBASE &&
pa < OMAP4_L4_ABE_PBASE + OMAP4_L4_ABE_SIZE)
return (pa - OMAP4_L4_ABE_PBASE) + OMAP4_L4_ABE_VBASE;
if (pa >= OMAP4_L4_CFG_PBASE &&
pa < OMAP4_L4_CFG_PBASE + OMAP4_L4_CFG_SIZE)
return (pa - OMAP4_L4_CFG_PBASE) + OMAP4_L4_CFG_VBASE;
panic("%s: pa %#x not in devmap", __func__, (uint32_t)pa);
}
extern struct arm32_bus_dma_tag arm_generic_dma_tag;
extern struct bus_space arm_generic_bs_tag;
static const struct pmap_devmap *
omap3_platform_devmap(void)
{
static const struct pmap_devmap devmap[] = {
DEVMAP_ENTRY(OMAP3_L4_CORE_VBASE,
OMAP3_L4_CORE_PBASE,
OMAP3_L4_CORE_SIZE),
DEVMAP_ENTRY(OMAP3_L4_WKUP_VBASE,
OMAP3_L4_WKUP_PBASE,
OMAP3_L4_WKUP_SIZE),
DEVMAP_ENTRY(OMAP3_L4_PER_VBASE,
OMAP3_L4_PER_PBASE,
OMAP3_L4_PER_SIZE),
DEVMAP_ENTRY_END
};
return devmap;
}
static const struct pmap_devmap *
omap4_platform_devmap(void)
{
static const struct pmap_devmap devmap[] = {
DEVMAP_ENTRY(OMAP4_L4_PER_VBASE,
OMAP4_L4_PER_PBASE,
OMAP4_L4_PER_SIZE),
DEVMAP_ENTRY(OMAP4_L4_ABE_VBASE,
OMAP4_L4_ABE_PBASE,
OMAP4_L4_ABE_SIZE),
DEVMAP_ENTRY(OMAP4_L4_CFG_VBASE,
OMAP4_L4_CFG_PBASE,
OMAP4_L4_CFG_SIZE),
DEVMAP_ENTRY_END
};
return devmap;
}
static void
omap3_platform_init_attach_args(struct fdt_attach_args *faa)
{
faa->faa_bst = &arm_generic_bs_tag;
faa->faa_dmat = &arm_generic_dma_tag;
}
void omap3_platform_early_putchar(char);
void __noasan
omap3_platform_early_putchar(char c)
{
#ifdef CONSADDR
volatile uint32_t *uartaddr = cpu_earlydevice_va_p() ?
(volatile uint32_t *)omap3_phystovirt(CONSADDR):
(volatile uint32_t *)CONSADDR;
while ((le32toh(uartaddr[com_lsr]) & LSR_TXRDY) == 0)
;
uartaddr[com_data] = htole32(c);
#endif
}
void omap4_platform_early_putchar(char);
void __noasan
omap4_platform_early_putchar(char c)
{
#ifdef CONSADDR
volatile uint32_t *uartaddr = cpu_earlydevice_va_p() ?
(volatile uint32_t *)omap4_phystovirt(CONSADDR):
(volatile uint32_t *)CONSADDR;
while ((le32toh(uartaddr[com_lsr]) & LSR_TXRDY) == 0)
;
uartaddr[com_data] = htole32(c);
#endif
}
static void
omap3_platform_device_register(device_t self, void *aux)
{
}
static u_int
omap3_platform_uart_freq(void)
{
return 48000000U;
}
#if NARML2CC > 0
static void
omap4_enable_ll2c(bool enable)
{
omap_smc(enable ? 1 : 0, OMAP4_CMD_L2X0_CTRL);
}
#endif
static void
omap4_platform_bootstrap(void)
{
uint32_t sys_clksel, sys_clk, dpll1, dpll2, m, n, m2;
u_int clksel;
static const uint32_t clksel_freqs[] = OMAP4_SYS_CLKSEL_FREQS;
sys_clksel = *(volatile uint32_t *)omap4_phystovirt(OMAP4_SYS_CLKSEL);
clksel = __SHIFTOUT(sys_clksel, OMAP4_SYS_CLKSEL_CLKIN);
sys_clk = clksel_freqs[clksel];
dpll1 = *(volatile uint32_t *)omap4_phystovirt(OMAP4_CLKSEL_DPLL_MPU);
dpll2 = *(volatile uint32_t *)omap4_phystovirt(OMAP4_DIV_M2_DPLL_MPU);
m = __SHIFTOUT(dpll1, OMAP4_DPLL_MULT);
n = __SHIFTOUT(dpll1, OMAP4_DPLL_DIV);
m2 = __SHIFTOUT(dpll2, OMAP4_DPLL_CLKOUT_DIV);
curcpu()->ci_data.cpu_cc_freq = ((sys_clk * 2 * m) / ((n + 1) * m2)) * 1000 / 2;
#if NARML2CC > 0
bus_space_tag_t bst = &arm_generic_bs_tag;
const bus_space_handle_t pl310_bsh = OMAP4_PL310_BASE
+ OMAP4_L4_PER_VBASE - OMAP4_L4_PER_PBASE;
arml2cc_get_cacheinfo(bst, pl310_bsh, 0);
arml2cc_set_enable_func(omap4_enable_ll2c);
#endif
arm_fdt_cpu_bootstrap();
}
static void
omap3_platform_reset(void)
{
volatile uint32_t *rstctrl =
(volatile uint32_t *)omap3_phystovirt(OMAP3_PRM_RSTCTRL);
*rstctrl |= OMAP3_PRM_RSTCTRL_RST_DPLL3;
for (;;)
__asm("wfi");
}
static void
omap4_platform_reset(void)
{
volatile uint32_t *rstctrl =
(volatile uint32_t *)omap4_phystovirt(OMAP4_PRM_RSTCTRL);
*rstctrl |= OMAP4_RST_GLOBAL_COLD;
for (;;)
__asm("wfi");
}
static void
omap3_platform_delay(u_int n)
{
volatile uint32_t *cr =
(volatile uint32_t *)omap3_phystovirt(OMAP3_REG_32KSYNCNT_CR);
uint32_t cur, prev;
long ticks = howmany(n * 32768, 1000000);
prev = *cr;
while (ticks > 0) {
cur = *cr;
if (cur >= prev)
ticks -= (cur - prev);
else
ticks -= (UINT32_MAX - cur + prev);
prev = cur;
}
}
static void
omap4_platform_delay(u_int n)
{
volatile uint32_t *cr =
(volatile uint32_t *)omap4_phystovirt(OMAP4_REG_32KSYNCNT_CR);
uint32_t cur, prev;
long ticks = howmany(n * 32768, 1000000);
prev = *cr;
while (ticks > 0) {
cur = *cr;
if (cur >= prev)
ticks -= (cur - prev);
else
ticks -= (UINT32_MAX - cur + prev);
prev = cur;
}
}
#ifdef MULTIPROCESSOR
static int
omap4_platform_mpstart(void)
{
bus_space_tag_t bst = &arm_generic_bs_tag;
uint32_t val;
const bus_space_handle_t scu_bsh = OMAP4_SCU_BASE
+ OMAP4_L4_PER_VBASE - OMAP4_L4_PER_PBASE;
bus_space_write_4(bst, scu_bsh, SCU_INV_ALL_REG, 0xffff);
val = bus_space_read_4(bst, scu_bsh, SCU_DIAG_CONTROL);
val |= SCU_DIAG_DISABLE_MIGBIT;
bus_space_write_4(bst, scu_bsh, SCU_DIAG_CONTROL, val);
val = bus_space_read_4(bst, scu_bsh, SCU_CTL);
val |= SCU_CTL_SCU_ENA;
bus_space_write_4(bst, scu_bsh, SCU_CTL, val);
armv7_dcache_wbinv_all();
const bus_space_handle_t wugen_bsh = OMAP4_WUGEN_BASE
+ OMAP4_L4_PER_VBASE - OMAP4_L4_PER_PBASE;
const paddr_t mpstart = KERN_VTOPHYS((vaddr_t)cpu_mpstart);
bus_space_write_4(bst, wugen_bsh, OMAP4_AUX_CORE_BOOT1, mpstart);
for (size_t i = 1; i < arm_cpu_max; i++) {
val = bus_space_read_4(bst, wugen_bsh, OMAP4_AUX_CORE_BOOT0);
val |= __SHIFTIN(0xf, i * 4);
bus_space_write_4(bst, wugen_bsh, OMAP4_AUX_CORE_BOOT0, val);
}
dsb(sy);
sev();
u_int hatched = 0;
for (u_int cpuindex = 1; cpuindex < arm_cpu_max; cpuindex++) {
u_int i;
for (i = 1500000; i > 0; i--) {
if (cpu_hatched_p(cpuindex)) {
hatched |= __BIT(cpuindex);
break;
}
}
if (i == 0) {
aprint_error("cpu%d: WARNING: AP failed to start\n", cpuindex);
return EIO;
}
}
return 0;
}
#endif
static const struct fdt_platform omap3_platform = {
.fp_devmap = omap3_platform_devmap,
.fp_bootstrap = arm_fdt_cpu_bootstrap,
.fp_init_attach_args = omap3_platform_init_attach_args,
.fp_device_register = omap3_platform_device_register,
.fp_reset = omap3_platform_reset,
.fp_delay = omap3_platform_delay,
.fp_uart_freq = omap3_platform_uart_freq,
};
FDT_PLATFORM(omap3, "ti,omap3", &omap3_platform);
static const struct fdt_platform omap4_platform = {
.fp_devmap = omap4_platform_devmap,
.fp_bootstrap = omap4_platform_bootstrap,
.fp_init_attach_args = omap3_platform_init_attach_args,
.fp_device_register = omap3_platform_device_register,
.fp_reset = omap4_platform_reset,
.fp_delay = omap4_platform_delay,
.fp_uart_freq = omap3_platform_uart_freq,
#ifdef MULTIPROCESSOR
.fp_mpstart = omap4_platform_mpstart,
#endif
};
FDT_PLATFORM(omap4, "ti,omap4", &omap4_platform);