/*-
* Copyright (c) 2012 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Matt Thomas of 3am Software Foundry.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/*
* Static device mappings. These peripheral registers are mapped at
* fixed virtual addresses very early in initarm() so that we can use
* them while booting the kernel, and stay at the same address
* throughout whole kernel's life time.
*
* We use this table twice; once with bootstrap page table, and once
* with kernel's page table which we build up in initarm().
*
* Since we map these registers into the bootstrap page table using
* pmap_devmap_bootstrap() which calls pmap_map_chunk(), we map
* registers segment-aligned and segment-rounded in order to avoid
* using the 2nd page tables.
*/
void
bcm53xx_mpstart(void)
{
#ifdef MULTIPROCESSOR
/*
* Invalidate all SCU cache tags. That is, for all cores (0-3)
*/
bus_space_write_4(bcm53xx_armcore_bst, bcm53xx_armcore_bsh,
ARMCORE_SCU_BASE + SCU_INV_ALL_REG, 0xffff);
int error = bus_space_map(bcm53xx_rom_bst, BCM53xx_ROM_CPU_ENTRY,
4, 0, &bcm53xx_rom_entry_bsh);
/*
* Before we turn on the MMU, let's the other process out of the
* SKU ROM but setting the magic LUT address to our own mp_start
* routine.
*/
bus_space_write_4(bcm53xx_rom_bst, bcm53xx_rom_entry_bsh, mpstart);
dsb(sy);
sev();
/* Bitmask of CPUs (non-BP) to start */
for (u_int cpuindex = 1; cpuindex < arm_cpu_max; cpuindex++) {
u_int i ;
for (i = 1500000; i > 0; i--) {
if (cpu_hatched_p(cpuindex))
break;
}
if (i == 0) {
ret++;
aprint_error("cpu%d: WARNING: AP failed to start\n",
cpuindex);
}
}
#endif /* MULTIPROCESSOR */
}
/*
* vaddr_t initarm(...)
*
* Initial entry point on startup. This gets called before main() is
* entered.
* It should be responsible for setting up everything that must be
* in place when main is called.
* This includes
* Taking a copy of the boot configuration structure.
* Initialising the physical console so characters can be printed.
* Setting up page tables for the kernel
*/
vaddr_t
initarm(void *arg)
{
/*
* Heads up ... Setup the CPU / MMU / TLB functions
*/
if (set_cpufuncs()) // starts PMC counter
panic("cpu not recognized!");
/*
* This is going to do all the hard work of setting up the first and
* and second level page tables. Pages of memory will be allocated
* and mapped for other structures that are required for system
* operation. When it returns, physical_freestart and free_pages will
* have been updated to reflect the allocations that were made. In
* addition, kernel_l1pt, kernel_pt_table[], systempage, irqstack,
* abtstack, undstack, kernelstack, msgbufphys will be set to point to
* the memory that was allocated for them.
*/
arm32_kernel_vm_init(KERNEL_VM_BASE, ARM_VECTORS_HIGH, 0, devmap,
mapallmem_p);
cpu_reset_address = bcm53xx_system_reset;
/* we've a specific device_register routine */
evbarm_device_register = bcm53xx_device_register;
if (bigmem_p) {
/*
* If we have more than 256MB
*/
arm_poolpage_vmfreelist = bp_first256.bp_freelist;
}
/*
* If we have more than 256MB of RAM, set aside the first 256MB for
* non-default VM allocations.
*/
vaddr_t sp = initarm_common(KERNEL_VM_BASE, KERNEL_VM_SIZE,
(bigmem_p ? &bp_first256 : NULL), (bigmem_p ? 1 : 0));
/*
* initarm_common flushes cache if required before AP start
*/
bcm53xx_mpstart();
/*
* Force UART clock to the reference clock
*/
v = bus_space_read_4(bcm53xx_ioreg_bst, bcm53xx_ioreg_bsh,
IDM_BASE + IDM_APBX_BASE + IDM_IO_CONTROL_DIRECT);
v &= ~IO_CONTROL_DIRECT_UARTCLKSEL;
bus_space_write_4(bcm53xx_ioreg_bst, bcm53xx_ioreg_bsh,
IDM_BASE + IDM_APBX_BASE + IDM_IO_CONTROL_DIRECT, v);
/*
* Switch to the reference clock
*/
v = bus_space_read_4(bcm53xx_ioreg_bst, bcm53xx_ioreg_bsh,
CCA_MISC_BASE + MISC_CORECTL);
v &= ~CORECTL_UART_CLK_OVERRIDE;
bus_space_write_4(bcm53xx_ioreg_bst, bcm53xx_ioreg_bsh,
CCA_MISC_BASE + MISC_CORECTL, v);
if (comcnattach(bcm53xx_ioreg_bst, comcnaddr, comcnspeed,
BCM53XX_REF_CLK, COM_TYPE_NORMAL, comcnmode))
panic("Serial console can not be initialized.");
}