#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: cats_machdep.c,v 1.96 2024/10/21 13:37:07 skrll Exp $");
#include "opt_arm_debug.h"
#include "opt_cats.h"
#include "opt_ddb.h"
#include "opt_modular.h"
#include "isadma.h"
#include <sys/param.h>
#include <sys/device.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/exec.h>
#include <sys/proc.h>
#include <sys/msgbuf.h>
#include <sys/reboot.h>
#include <sys/termios.h>
#include <sys/ksyms.h>
#include <sys/cpu.h>
#include <sys/intr.h>
#include <dev/cons.h>
#include <machine/db_machdep.h>
#include <ddb/db_sym.h>
#include <ddb/db_extern.h>
#include <machine/bootconfig.h>
#define _ARM32_BUS_DMA_PRIVATE
#include <sys/bus.h>
#include <arm/locore.h>
#include <arm/undefined.h>
#include <arm/arm32/machdep.h>
#include <machine/cyclone_boot.h>
#include <arm/footbridge/dc21285mem.h>
#include <arm/footbridge/dc21285reg.h>
#include "ksyms.h"
#include "opt_ableelf.h"
#include "isa.h"
#if NISA > 0
#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#endif
#ifdef VERBOSE_INIT_ARM
#define VPRINTF(...) printf(__VA_ARGS__)
#else
#define VPRINTF(...) __nothing
#endif
#define KERNEL_TEXT_BASE (KERNEL_BASE + 0x00000000)
#define KERNEL_VM_BASE (KERNEL_BASE + 0x01000000)
#define KERNEL_VM_SIZE 0x0c000000
u_int dc21285_fclk = FCLK;
struct ebsaboot ebsabootinfo;
BootConfig bootconfig;
static char bootargs[MAX_BOOT_STRING + 1];
char *boot_args = NULL;
char *boot_file = NULL;
void consinit(void);
int fcomcnattach(u_int iobase, int rate, tcflag_t cflag);
int fcomcndetach(void);
static void process_kernel_args(const char *);
extern void configure(void);
#include "vga.h"
#if (NVGA > 0)
#include <dev/ic/mc6845reg.h>
#include <dev/ic/pcdisplayvar.h>
#include <dev/ic/vgareg.h>
#include <dev/ic/vgavar.h>
#endif
#include "pckbc.h"
#if (NPCKBC > 0)
#include <dev/ic/i8042reg.h>
#include <dev/ic/pckbcvar.h>
#endif
#include "com.h"
#if (NCOM > 0)
#include <dev/ic/comreg.h>
#include <dev/ic/comvar.h>
#ifndef CONCOMADDR
#define CONCOMADDR 0x3f8
#endif
#endif
#ifndef CONSDEVNAME
#define CONSDEVNAME "vga"
#endif
#define CONSPEED B38400
#ifndef CONSPEED
#define CONSPEED B9600
#endif
#ifndef CONMODE
#define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8)
#endif
int comcnspeed = CONSPEED;
int comcnmode = CONMODE;
static const struct pmap_devmap cats_devmap[] = {
DEVMAP_ENTRY(DC21285_ARMCSR_VBASE,
DC21285_ARMCSR_BASE,
DC21285_ARMCSR_VSIZE),
DEVMAP_ENTRY(DC21285_CACHE_FLUSH_VBASE,
DC21285_SA_CACHE_FLUSH_BASE,
DC21285_CACHE_FLUSH_VSIZE),
DEVMAP_ENTRY(DC21285_PCI_IO_VBASE,
DC21285_PCI_IO_BASE,
DC21285_PCI_IO_VSIZE),
DEVMAP_ENTRY(DC21285_PCI_IACK_VBASE,
DC21285_PCI_IACK_SPECIAL,
DC21285_PCI_IACK_VSIZE),
DEVMAP_ENTRY(DC21285_PCI_TYPE_1_CONFIG_VBASE,
DC21285_PCI_TYPE_1_CONFIG,
DC21285_PCI_TYPE_1_CONFIG_VSIZE),
DEVMAP_ENTRY(DC21285_PCI_TYPE_0_CONFIG_VBASE,
DC21285_PCI_TYPE_0_CONFIG,
DC21285_PCI_TYPE_0_CONFIG_VSIZE),
DEVMAP_ENTRY(DC21285_PCI_ISA_MEM_VBASE,
DC21285_PCI_MEM_BASE,
DC21285_PCI_ISA_MEM_VSIZE),
DEVMAP_ENTRY_END
};
#define MAX_PHYSMEM 4
static struct boot_physmem cats_physmem[MAX_PHYSMEM];
int ncats_physmem = 0;
extern struct bus_space footbridge_pci_io_bs_tag;
extern struct bus_space footbridge_pci_mem_bs_tag;
void footbridge_pci_bs_tag_init(void);
vaddr_t
initarm(void *arm_bootargs)
{
struct ebsaboot *bootinfo = arm_bootargs;
extern u_int cpu_get_control(void);
set_cpufuncs();
ebsabootinfo = *bootinfo;
if (ebsabootinfo.bt_fclk >= 50000000
&& ebsabootinfo.bt_fclk <= 66000000)
dc21285_fclk = ebsabootinfo.bt_fclk;
bootconfig.dramblocks = 1;
bootconfig.dram[0].address = ebsabootinfo.bt_memstart;
bootconfig.dram[0].pages = (ebsabootinfo.bt_memend
- ebsabootinfo.bt_memstart) / PAGE_SIZE;
pmap_devmap_bootstrap((vaddr_t)ebsabootinfo.bt_l1, cats_devmap);
#ifdef FCOM_INIT_ARM
fcomcnattach(DC21285_ARMCSR_VBASE, comcnspeed, comcnmode);
#endif
printf("NetBSD/cats booting ...\n");
if (ebsabootinfo.bt_magic != BT_MAGIC_NUMBER_EBSA
&& ebsabootinfo.bt_magic != BT_MAGIC_NUMBER_CATS)
panic("Incompatible magic number %#x passed in boot args",
ebsabootinfo.bt_magic);
VPRINTF("bootinfo @ %p\n", arm_bootargs);
VPRINTF("bt_magic = 0x%08x\n", ebsabootinfo.bt_magic);
VPRINTF("bt_vargp = 0x%08x\n", ebsabootinfo.bt_vargp);
VPRINTF("bt_pargp = 0x%08x\n", ebsabootinfo.bt_pargp);
VPRINTF("bt_args @ %p, contents = \"%s\"\n", ebsabootinfo.bt_args, ebsabootinfo.bt_args);
VPRINTF("bt_l1 = %p\n", ebsabootinfo.bt_l1);
VPRINTF("bt_memstart = 0x%08x\n", ebsabootinfo.bt_memstart);
VPRINTF("bt_memend = 0x%08x\n", ebsabootinfo.bt_memend);
VPRINTF("bt_memavail = 0x%08x\n", ebsabootinfo.bt_memavail);
VPRINTF("bt_fclk = 0x%08x\n", ebsabootinfo.bt_fclk);
VPRINTF("bt_pciclk = 0x%08x\n", ebsabootinfo.bt_pciclk);
VPRINTF("bt_vers = 0x%08x\n", ebsabootinfo.bt_vers);
VPRINTF("bt_features = 0x%08x\n", ebsabootinfo.bt_features);
process_kernel_args(ebsabootinfo.bt_args);
psize_t ram_size = ebsabootinfo.bt_memend - ebsabootinfo.bt_memstart;
#ifdef MEMSIZE
if (ram_size == 0 || ram_size > (unsigned)MEMSIZE * 1024 * 1024)
ram_size = (unsigned)MEMSIZE * 1024 * 1024;
VPRINTF("ram_size = 0x%x\n", (int)ram_size);
#else
KASSERTMSG(ram_size > 0, "RAM size unknown and MEMSIZE undefined");
#endif
#ifdef __HAVE_MM_MD_DIRECT_MAPPED_PHYS
const bool mapallmem_p = true;
if (ram_size > KERNEL_VM_BASE - KERNEL_BASE) {
printf("%s: dropping RAM size from %luMB to %uMB\n",
__func__, (unsigned long) (ram_size >> 20),
(KERNEL_VM_BASE - KERNEL_BASE) >> 20);
ram_size = KERNEL_VM_BASE - KERNEL_BASE;
}
#else
const bool mapallmem_p = false;
#endif
printf("ram_size = 0x%08lx\n", ram_size);
arm32_bootmem_init(ebsabootinfo.bt_memstart, ram_size,
ebsabootinfo.bt_memstart);
extern struct bootmem_info bootmem_info;
struct bootmem_info * const bmi = &bootmem_info;
pv_addr_t *pv0 = &bmi->bmi_freeblocks[0];
KASSERTMSG(pv0->pv_pa == bmi->bmi_kernelend,
"pv_pa %#lx kernelend %#lx", pv0->pv_pa, bmi->bmi_kernelend);
pv0->pv_pa = ebsabootinfo.bt_memavail;
pv0->pv_va = KERN_PHYSTOV(pv0->pv_pa);
pv0->pv_size = bmi->bmi_end - pv0->pv_pa;
printf("First freeblock adjusted to: %lx -> %lx\n", pv0->pv_pa,
pv0->pv_pa + pv0->pv_size - 1);
arm32_kernel_vm_init(KERNEL_VM_BASE, ARM_VECTORS_LOW, 0, cats_devmap,
mapallmem_p);
printf("init subsystems: patch ");
*((u_int *)KERNEL_TEXT_BASE) = 0xe28ff441;
#if NISA > 0
isa_footbridge_init(DC21285_PCI_IO_VBASE, DC21285_PCI_ISA_MEM_VBASE);
#endif
footbridge_pci_bs_tag_init();
printf("busses done.\n");
if (ebsabootinfo.bt_vargp != vector_page) {
pmap_map_entry(kernel_l1pt.pv_va, ebsabootinfo.bt_vargp,
ebsabootinfo.bt_pargp, VM_PROT_READ, PTE_CACHE);
}
printf("Doing freeblocks: %d\n", bmi->bmi_nfreeblocks);
for (size_t i = 0; i < bmi->bmi_nfreeblocks; i++) {
pv_addr_t * const pv = &bmi->bmi_freeblocks[i];
paddr_t start = pv->pv_pa;
paddr_t end = pv->pv_pa + pv->pv_size;
struct boot_physmem *bp;
#if NISADMA > 0
paddr_t istart, isize;
extern struct arm32_dma_range *footbridge_isa_dma_ranges;
extern int footbridge_isa_dma_nranges;
#endif
VPRINTF("%zu: 0x08%lx -> 0x08%lx\n", i, start, end - 1);
#if NISADMA > 0
if (arm32_dma_range_intersect(footbridge_isa_dma_ranges,
footbridge_isa_dma_nranges, start, end - start,
&istart, &isize)) {
VPRINTF(" ISADMA 0x08%lx -> 0x%08lx\n", istart,
istart + isize - 1);
bp = &cats_physmem[ncats_physmem++];
KASSERT(ncats_physmem < MAX_PHYSMEM);
bp->bp_start = atop(istart);
bp->bp_pages = atop(isize);
bp->bp_freelist = VM_FREELIST_ISADMA;
if (start < istart) {
VPRINTF(" BEFORE 0x08%lx -> 0x08%lx\n",
start, istart - 1);
bp = &cats_physmem[ncats_physmem++];
KASSERT(ncats_physmem < MAX_PHYSMEM);
bp->bp_start = atop(start);
bp->bp_pages = atop(istart - start);
bp->bp_freelist = VM_FREELIST_DEFAULT;
}
if ((istart + isize) < end) {
VPRINTF(" AFTER 0x%08lx -> 0x%08lx\n",
(istart + isize), end - 1);
bp = &cats_physmem[ncats_physmem++];
KASSERT(ncats_physmem < MAX_PHYSMEM);
bp->bp_start = atop(istart + isize);
bp->bp_pages = atop(end - (istart + isize));
bp->bp_freelist = VM_FREELIST_DEFAULT;
}
} else {
bp = &cats_physmem[ncats_physmem++];
KASSERT(ncats_physmem < MAX_PHYSMEM);
bp->bp_start = atop(start);
bp->bp_pages = atop(end - start);
bp->bp_freelist = VM_FREELIST_DEFAULT;
}
#else
bp = &cats_physmem[ncats_physmem++];
KASSERT(ncats_physmem < MAX_PHYSMEM);
bp->bp_start = atop(start);
bp->bp_pages = atop(end - start);
bp->bp_freelist = VM_FREELIST_DEFAULT;
#endif
}
cpu_reset_address_paddr = DC21285_ROM_BASE;
vaddr_t sp;
sp = initarm_common(KERNEL_VM_BASE, KERNEL_VM_SIZE, cats_physmem,
ncats_physmem);
printf("init subsystems: irq ");
footbridge_intr_init();
printf("done.\n");
#ifdef FCOM_INIT_ARM
fcomcndetach();
#endif
#ifdef DDB
if (boothowto & RB_KDB)
Debugger();
#endif
consinit();
return sp;
}
static void
process_kernel_args(const char *loader_args)
{
char *args;
boothowto = 0;
strncpy(bootargs, loader_args, MAX_BOOT_STRING);
args = bootargs;
boot_file = bootargs;
while (*args != ' ' && *args != 0)
++args;
if (*args != 0)
*args++ = 0;
while (*args == ' ')
++args;
boot_args = args;
printf("bootfile: %s\n", boot_file);
printf("bootargs: %s\n", boot_args);
parse_mi_bootargs(boot_args);
}
void
consinit(void)
{
static int consinit_called = 0;
const char *console = CONSDEVNAME;
if (consinit_called != 0)
return;
consinit_called = 1;
get_bootconf_option(boot_args, "console", BOOTOPT_TYPE_STRING,
&console);
if (strncmp(console, "fcom", 4) == 0
|| strncmp(console, "diag", 4) == 0)
fcomcnattach(DC21285_ARMCSR_VBASE, comcnspeed, comcnmode);
#if (NVGA > 0)
else if (strncmp(console, "vga", 3) == 0) {
vga_cnattach(&footbridge_pci_io_bs_tag,
&footbridge_pci_mem_bs_tag, - 1, 0);
#if (NPCKBC > 0)
pckbc_cnattach(&isa_io_bs_tag, IO_KBD, KBCMDP, PCKBC_KBD_SLOT,
0);
#endif
}
#endif
#if (NCOM > 0)
else if (strncmp(console, "com", 3) == 0) {
if (comcnattach(&isa_io_bs_tag, CONCOMADDR, comcnspeed,
COM_FREQ, COM_TYPE_NORMAL, comcnmode))
panic("can't init serial console @%x", CONCOMADDR);
}
#endif
else
fcomcnattach(DC21285_ARMCSR_VBASE, comcnspeed, comcnmode);
}