Path: blob/main/sys/arm/qualcomm/ipq4018_machdep.c
39507 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2021 Adrian Chadd <[email protected]>4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND15* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24* SUCH DAMAGE.25*/2627#include "opt_platform.h"2829#include <sys/param.h>30#include <sys/systm.h>31#include <sys/bus.h>32#include <sys/reboot.h>33#include <sys/devmap.h>34#include <sys/physmem.h>35#include <sys/lock.h>3637#include <vm/vm.h>3839#include <machine/bus.h>40#include <machine/fdt.h>41#include <machine/intr.h>42#include <machine/machdep.h>43#include <machine/platformvar.h>4445#include <dev/fdt/fdt_common.h>46#include <dev/ofw/openfirm.h>4748#include <arm/qualcomm/ipq4018_machdep.h>49#include <arm/qualcomm/ipq4018_reg.h>5051#include "platform_if.h"5253static int54ipq4018_attach(platform_t plat)55{56return (0);57}5859static void60ipq4018_late_init(platform_t plat)61{62/*63* XXX FIXME This is needed because we're not parsing64* the fdt reserved memory regions in a consistent way65* between arm/arm64. Once the reserved region parsing66* is fixed up this will become unnecessary.67*68* These cover the SRAM/TZ regions that are not fully69* accessible from the OS. They're in the ipq4018.dtsi70* tree.71*72* Without these, the system fails to boot because we73* aren't parsing the regions correctly.74*75* These will be unnecessary once the parser and setup76* code is fixed.77*/78physmem_exclude_region(IPQ4018_MEM_SMEM_START,79IPQ4018_MEM_SMEM_SIZE,80EXFLAG_NODUMP | EXFLAG_NOALLOC);81physmem_exclude_region(IPQ4018_MEM_TZ_START,82IPQ4018_MEM_TZ_SIZE,83EXFLAG_NODUMP | EXFLAG_NOALLOC);84}8586static int87ipq4018_devmap_init(platform_t plat)88{89/*90* This covers the boot UART. Without it we can't boot successfully:91* there's a mutex uninit panic in subr_vmem.c that occurs when doing92* a call to pmap_mapdev() when the bus space code is doing its thing.93*/94devmap_add_entry(IPQ4018_MEM_UART1_START, IPQ4018_MEM_UART1_SIZE);9596/*97* This covers a bunch of the reset block, which includes the PS-HOLD98* register for dropping power.99*/100devmap_add_entry(IPQ4018_MEM_PSHOLD_START, IPQ4018_MEM_PSHOLD_SIZE);101102return (0);103}104105/*106* This toggles the PS-HOLD register which on most IPQ devices will toggle107* the power control block and reset the SoC.108*109* However, there are apparently some units out there where this is not110* appropriate and instead the watchdog needs to be used.111*112* For now since there's only going to be one or two initial supported boards113* this will be fine. But if this doesn't reboot cleanly, now you know.114*/115static void116ipq4018_cpu_reset_pshold(void)117{118bus_space_handle_t pshold;119120printf("%s: called\n", __func__);121122bus_space_map(fdtbus_bs_tag, IPQ4018_MEM_PSHOLD_START,123IPQ4018_MEM_PSHOLD_SIZE, 0, &pshold);124bus_space_write_4(fdtbus_bs_tag, pshold, 0, 0);125bus_space_barrier(fdtbus_bs_tag, pshold, 0, 0x4,126BUS_SPACE_BARRIER_WRITE);127}128129static void130ipq4018_cpu_reset(platform_t plat)131{132spinlock_enter();133dsb();134135ipq4018_cpu_reset_pshold();136137/* Spin */138printf("%s: spinning\n", __func__);139while(1)140;141}142143/*144* Early putc routine for EARLY_PRINTF support. To use, add to kernel config:145* option SOCDEV_PA=0x07800000146* option SOCDEV_VA=0x07800000147* option EARLY_PRINTF148* Resist the temptation to change the #if 0 to #ifdef EARLY_PRINTF here. It149* makes sense now, but if multiple SOCs do that it will make early_putc another150* duplicate symbol to be eliminated on the path to a generic kernel.151*/152#if 0153void154qca_msm_early_putc(int c)155{156static int is_init = 0;157158int limit;159/*160* This must match what's put into SOCDEV_VA. You have to change them161* both together.162*163* XXX TODO I should really go and just make UART_BASE here depend upon164* SOCDEV_VA so they move together.165*/166#define UART_BASE IPQ4018_MEM_UART1_START167volatile uint32_t * UART_DM_TF0 = (uint32_t *)(UART_BASE + 0x70);168volatile uint32_t * UART_DM_SR = (uint32_t *)(UART_BASE + 0x08);169#define UART_DM_SR_TXEMT (1 << 3)170#define UART_DM_SR_TXRDY (1 << 2)171volatile uint32_t * UART_DM_ISR = (uint32_t *)(UART_BASE + 0x14);172volatile uint32_t * UART_DM_CR = (uint32_t *)(UART_BASE + 0x10);173#define UART_DM_TX_READY (1 << 7)174#define UART_DM_CLEAR_TX_READY 0x300175volatile uint32_t * UART_DM_NO_CHARS_FOR_TX = (uint32_t *)(UART_BASE + 0x40);176volatile uint32_t * UART_DM_TFWR = (uint32_t *)(UART_BASE + 0x1c);177#define UART_DM_TFW_VALUE 0178volatile uint32_t * UART_DM_IPR = (uint32_t *)(UART_BASE + 0x18);179#define UART_DM_STALE_TIMEOUT_LSB 0xf180181if (is_init == 0) {182is_init = 1;183*UART_DM_TFWR = UART_DM_TFW_VALUE;184wmb();185*UART_DM_IPR = UART_DM_STALE_TIMEOUT_LSB;186wmb();187}188189/* Wait until TXFIFO is empty via ISR */190limit = 100000;191if ((*UART_DM_SR & UART_DM_SR_TXEMT) == 0) {192while (((*UART_DM_ISR & UART_DM_TX_READY) == 0) && --limit) {193/* Note - can't use DELAY here yet, too early */194rmb();195}196*UART_DM_CR = UART_DM_CLEAR_TX_READY;197wmb();198}199200/* FIFO is ready. Say we're going to write one byte */201*UART_DM_NO_CHARS_FOR_TX = 1;202wmb();203204limit = 100000;205while (((*UART_DM_SR & UART_DM_SR_TXRDY) == 0) && --limit) {206/* Note - can't use DELAY here yet, too early */207rmb();208}209210/* Put character in first fifo slot */211*UART_DM_TF0 = c;212wmb();213}214early_putc_t *early_putc = qca_msm_early_putc;215#endif216217static platform_method_t ipq4018_methods[] = {218PLATFORMMETHOD(platform_attach, ipq4018_attach),219PLATFORMMETHOD(platform_devmap_init, ipq4018_devmap_init),220PLATFORMMETHOD(platform_late_init, ipq4018_late_init),221PLATFORMMETHOD(platform_cpu_reset, ipq4018_cpu_reset),222223#ifdef SMP224PLATFORMMETHOD(platform_mp_start_ap, ipq4018_mp_start_ap),225PLATFORMMETHOD(platform_mp_setmaxid, ipq4018_mp_setmaxid),226#endif227228PLATFORMMETHOD_END,229};230231FDT_PLATFORM_DEF2(ipq4018, ipq4018_ac58u, "ASUS RT-AC58U", 0,232"asus,rt-ac58u", 80);233234235