102438ce5SAdrian Chadd /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 302438ce5SAdrian Chadd * 402438ce5SAdrian Chadd * Copyright (c) 2021 Adrian Chadd <adrian@FreeBSD.org> 502438ce5SAdrian Chadd * 602438ce5SAdrian Chadd * Redistribution and use in source and binary forms, with or without 702438ce5SAdrian Chadd * modification, are permitted provided that the following conditions 802438ce5SAdrian Chadd * are met: 902438ce5SAdrian Chadd * 1. Redistributions of source code must retain the above copyright 1002438ce5SAdrian Chadd * notice, this list of conditions and the following disclaimer. 1102438ce5SAdrian Chadd * 2. Redistributions in binary form must reproduce the above copyright 1202438ce5SAdrian Chadd * notice, this list of conditions and the following disclaimer in the 1302438ce5SAdrian Chadd * documentation and/or other materials provided with the distribution. 1402438ce5SAdrian Chadd * 1502438ce5SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1602438ce5SAdrian Chadd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1702438ce5SAdrian Chadd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1802438ce5SAdrian Chadd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1902438ce5SAdrian Chadd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2002438ce5SAdrian Chadd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2102438ce5SAdrian Chadd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2202438ce5SAdrian Chadd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2302438ce5SAdrian Chadd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2402438ce5SAdrian Chadd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2502438ce5SAdrian Chadd * SUCH DAMAGE. 2602438ce5SAdrian Chadd */ 2702438ce5SAdrian Chadd 2802438ce5SAdrian Chadd #include "opt_platform.h" 2902438ce5SAdrian Chadd 3002438ce5SAdrian Chadd #include <sys/param.h> 3102438ce5SAdrian Chadd #include <sys/systm.h> 3202438ce5SAdrian Chadd #include <sys/bus.h> 3302438ce5SAdrian Chadd #include <sys/reboot.h> 3402438ce5SAdrian Chadd #include <sys/devmap.h> 3502438ce5SAdrian Chadd #include <sys/physmem.h> 366325f105SAdrian Chadd #include <sys/lock.h> 3702438ce5SAdrian Chadd 3802438ce5SAdrian Chadd #include <vm/vm.h> 3902438ce5SAdrian Chadd 4002438ce5SAdrian Chadd #include <machine/bus.h> 416325f105SAdrian Chadd #include <machine/fdt.h> 4202438ce5SAdrian Chadd #include <machine/intr.h> 4302438ce5SAdrian Chadd #include <machine/machdep.h> 4402438ce5SAdrian Chadd #include <machine/platformvar.h> 4502438ce5SAdrian Chadd 4602438ce5SAdrian Chadd #include <dev/fdt/fdt_common.h> 4702438ce5SAdrian Chadd #include <dev/ofw/openfirm.h> 4802438ce5SAdrian Chadd 4902438ce5SAdrian Chadd #include <arm/qualcomm/ipq4018_machdep.h> 5002438ce5SAdrian Chadd #include <arm/qualcomm/ipq4018_reg.h> 5102438ce5SAdrian Chadd 5202438ce5SAdrian Chadd #include "platform_if.h" 5302438ce5SAdrian Chadd 5402438ce5SAdrian Chadd static int 5502438ce5SAdrian Chadd ipq4018_attach(platform_t plat) 5602438ce5SAdrian Chadd { 5702438ce5SAdrian Chadd return (0); 5802438ce5SAdrian Chadd } 5902438ce5SAdrian Chadd 6002438ce5SAdrian Chadd static void 6102438ce5SAdrian Chadd ipq4018_late_init(platform_t plat) 6202438ce5SAdrian Chadd { 6302438ce5SAdrian Chadd /* 6402438ce5SAdrian Chadd * XXX FIXME This is needed because we're not parsing 6502438ce5SAdrian Chadd * the fdt reserved memory regions in a consistent way 6602438ce5SAdrian Chadd * between arm/arm64. Once the reserved region parsing 67*fad3e1fbSGordon Bergling * is fixed up this will become unnecessary. 6802438ce5SAdrian Chadd * 6902438ce5SAdrian Chadd * These cover the SRAM/TZ regions that are not fully 7002438ce5SAdrian Chadd * accessible from the OS. They're in the ipq4018.dtsi 7102438ce5SAdrian Chadd * tree. 7202438ce5SAdrian Chadd * 7302438ce5SAdrian Chadd * Without these, the system fails to boot because we 7402438ce5SAdrian Chadd * aren't parsing the regions correctly. 7502438ce5SAdrian Chadd * 7602438ce5SAdrian Chadd * These will be unnecessary once the parser and setup 7702438ce5SAdrian Chadd * code is fixed. 7802438ce5SAdrian Chadd */ 7902438ce5SAdrian Chadd physmem_exclude_region(IPQ4018_MEM_SMEM_START, 8002438ce5SAdrian Chadd IPQ4018_MEM_SMEM_SIZE, 8102438ce5SAdrian Chadd EXFLAG_NODUMP | EXFLAG_NOALLOC); 8202438ce5SAdrian Chadd physmem_exclude_region(IPQ4018_MEM_TZ_START, 8302438ce5SAdrian Chadd IPQ4018_MEM_TZ_SIZE, 8402438ce5SAdrian Chadd EXFLAG_NODUMP | EXFLAG_NOALLOC); 8502438ce5SAdrian Chadd } 8602438ce5SAdrian Chadd 8702438ce5SAdrian Chadd static int 8802438ce5SAdrian Chadd ipq4018_devmap_init(platform_t plat) 8902438ce5SAdrian Chadd { 9002438ce5SAdrian Chadd /* 9102438ce5SAdrian Chadd * This covers the boot UART. Without it we can't boot successfully: 9202438ce5SAdrian Chadd * there's a mutex uninit panic in subr_vmem.c that occurs when doing 9302438ce5SAdrian Chadd * a call to pmap_mapdev() when the bus space code is doing its thing. 9402438ce5SAdrian Chadd */ 9502438ce5SAdrian Chadd devmap_add_entry(IPQ4018_MEM_UART1_START, IPQ4018_MEM_UART1_SIZE); 966325f105SAdrian Chadd 976325f105SAdrian Chadd /* 986325f105SAdrian Chadd * This covers a bunch of the reset block, which includes the PS-HOLD 996325f105SAdrian Chadd * register for dropping power. 1006325f105SAdrian Chadd */ 1016325f105SAdrian Chadd devmap_add_entry(IPQ4018_MEM_PSHOLD_START, IPQ4018_MEM_PSHOLD_SIZE); 1026325f105SAdrian Chadd 10302438ce5SAdrian Chadd return (0); 10402438ce5SAdrian Chadd } 10502438ce5SAdrian Chadd 1066325f105SAdrian Chadd /* 1076325f105SAdrian Chadd * This toggles the PS-HOLD register which on most IPQ devices will toggle 1086325f105SAdrian Chadd * the power control block and reset the SoC. 1096325f105SAdrian Chadd * 1106325f105SAdrian Chadd * However, there are apparently some units out there where this is not 1116325f105SAdrian Chadd * appropriate and instead the watchdog needs to be used. 1126325f105SAdrian Chadd * 1136325f105SAdrian Chadd * For now since there's only going to be one or two initial supported boards 1146325f105SAdrian Chadd * this will be fine. But if this doesn't reboot cleanly, now you know. 1156325f105SAdrian Chadd */ 1166325f105SAdrian Chadd static void 1176325f105SAdrian Chadd ipq4018_cpu_reset_pshold(void) 1186325f105SAdrian Chadd { 1196325f105SAdrian Chadd bus_space_handle_t pshold; 1206325f105SAdrian Chadd 1216325f105SAdrian Chadd printf("%s: called\n", __func__); 1226325f105SAdrian Chadd 1236325f105SAdrian Chadd bus_space_map(fdtbus_bs_tag, IPQ4018_MEM_PSHOLD_START, 1246325f105SAdrian Chadd IPQ4018_MEM_PSHOLD_SIZE, 0, &pshold); 1256325f105SAdrian Chadd bus_space_write_4(fdtbus_bs_tag, pshold, 0, 0); 1266325f105SAdrian Chadd bus_space_barrier(fdtbus_bs_tag, pshold, 0, 0x4, 1276325f105SAdrian Chadd BUS_SPACE_BARRIER_WRITE); 1286325f105SAdrian Chadd } 1296325f105SAdrian Chadd 13002438ce5SAdrian Chadd static void 13102438ce5SAdrian Chadd ipq4018_cpu_reset(platform_t plat) 13202438ce5SAdrian Chadd { 1336325f105SAdrian Chadd spinlock_enter(); 1346325f105SAdrian Chadd dsb(); 1356325f105SAdrian Chadd 1366325f105SAdrian Chadd ipq4018_cpu_reset_pshold(); 1376325f105SAdrian Chadd 1386325f105SAdrian Chadd /* Spin */ 1396325f105SAdrian Chadd printf("%s: spinning\n", __func__); 1406325f105SAdrian Chadd while(1) 1416325f105SAdrian Chadd ; 14202438ce5SAdrian Chadd } 14302438ce5SAdrian Chadd 14402438ce5SAdrian Chadd /* 14502438ce5SAdrian Chadd * Early putc routine for EARLY_PRINTF support. To use, add to kernel config: 14602438ce5SAdrian Chadd * option SOCDEV_PA=0x07800000 14702438ce5SAdrian Chadd * option SOCDEV_VA=0x07800000 14802438ce5SAdrian Chadd * option EARLY_PRINTF 14902438ce5SAdrian Chadd * Resist the temptation to change the #if 0 to #ifdef EARLY_PRINTF here. It 15002438ce5SAdrian Chadd * makes sense now, but if multiple SOCs do that it will make early_putc another 15102438ce5SAdrian Chadd * duplicate symbol to be eliminated on the path to a generic kernel. 15202438ce5SAdrian Chadd */ 15302438ce5SAdrian Chadd #if 0 15402438ce5SAdrian Chadd void 15502438ce5SAdrian Chadd qca_msm_early_putc(int c) 15602438ce5SAdrian Chadd { 15702438ce5SAdrian Chadd static int is_init = 0; 15802438ce5SAdrian Chadd 15902438ce5SAdrian Chadd int limit; 16002438ce5SAdrian Chadd /* 16102438ce5SAdrian Chadd * This must match what's put into SOCDEV_VA. You have to change them 16202438ce5SAdrian Chadd * both together. 16302438ce5SAdrian Chadd * 16402438ce5SAdrian Chadd * XXX TODO I should really go and just make UART_BASE here depend upon 16502438ce5SAdrian Chadd * SOCDEV_VA so they move together. 16602438ce5SAdrian Chadd */ 16702438ce5SAdrian Chadd #define UART_BASE IPQ4018_MEM_UART1_START 16802438ce5SAdrian Chadd volatile uint32_t * UART_DM_TF0 = (uint32_t *)(UART_BASE + 0x70); 16902438ce5SAdrian Chadd volatile uint32_t * UART_DM_SR = (uint32_t *)(UART_BASE + 0x08); 17002438ce5SAdrian Chadd #define UART_DM_SR_TXEMT (1 << 3) 17102438ce5SAdrian Chadd #define UART_DM_SR_TXRDY (1 << 2) 17202438ce5SAdrian Chadd volatile uint32_t * UART_DM_ISR = (uint32_t *)(UART_BASE + 0x14); 17302438ce5SAdrian Chadd volatile uint32_t * UART_DM_CR = (uint32_t *)(UART_BASE + 0x10); 17402438ce5SAdrian Chadd #define UART_DM_TX_READY (1 << 7) 17502438ce5SAdrian Chadd #define UART_DM_CLEAR_TX_READY 0x300 17602438ce5SAdrian Chadd volatile uint32_t * UART_DM_NO_CHARS_FOR_TX = (uint32_t *)(UART_BASE + 0x40); 17702438ce5SAdrian Chadd volatile uint32_t * UART_DM_TFWR = (uint32_t *)(UART_BASE + 0x1c); 17802438ce5SAdrian Chadd #define UART_DM_TFW_VALUE 0 17902438ce5SAdrian Chadd volatile uint32_t * UART_DM_IPR = (uint32_t *)(UART_BASE + 0x18); 18002438ce5SAdrian Chadd #define UART_DM_STALE_TIMEOUT_LSB 0xf 18102438ce5SAdrian Chadd 18202438ce5SAdrian Chadd if (is_init == 0) { 18302438ce5SAdrian Chadd is_init = 1; 18402438ce5SAdrian Chadd *UART_DM_TFWR = UART_DM_TFW_VALUE; 18502438ce5SAdrian Chadd wmb(); 18602438ce5SAdrian Chadd *UART_DM_IPR = UART_DM_STALE_TIMEOUT_LSB; 18702438ce5SAdrian Chadd wmb(); 18802438ce5SAdrian Chadd } 18902438ce5SAdrian Chadd 19002438ce5SAdrian Chadd /* Wait until TXFIFO is empty via ISR */ 19102438ce5SAdrian Chadd limit = 100000; 19202438ce5SAdrian Chadd if ((*UART_DM_SR & UART_DM_SR_TXEMT) == 0) { 19302438ce5SAdrian Chadd while (((*UART_DM_ISR & UART_DM_TX_READY) == 0) && --limit) { 19402438ce5SAdrian Chadd /* Note - can't use DELAY here yet, too early */ 19502438ce5SAdrian Chadd rmb(); 19602438ce5SAdrian Chadd } 19702438ce5SAdrian Chadd *UART_DM_CR = UART_DM_CLEAR_TX_READY; 19802438ce5SAdrian Chadd wmb(); 19902438ce5SAdrian Chadd } 20002438ce5SAdrian Chadd 20102438ce5SAdrian Chadd /* FIFO is ready. Say we're going to write one byte */ 20202438ce5SAdrian Chadd *UART_DM_NO_CHARS_FOR_TX = 1; 20302438ce5SAdrian Chadd wmb(); 20402438ce5SAdrian Chadd 20502438ce5SAdrian Chadd limit = 100000; 20602438ce5SAdrian Chadd while (((*UART_DM_SR & UART_DM_SR_TXRDY) == 0) && --limit) { 20702438ce5SAdrian Chadd /* Note - can't use DELAY here yet, too early */ 20802438ce5SAdrian Chadd rmb(); 20902438ce5SAdrian Chadd } 21002438ce5SAdrian Chadd 21102438ce5SAdrian Chadd /* Put character in first fifo slot */ 21202438ce5SAdrian Chadd *UART_DM_TF0 = c; 21302438ce5SAdrian Chadd wmb(); 21402438ce5SAdrian Chadd } 21502438ce5SAdrian Chadd early_putc_t *early_putc = qca_msm_early_putc; 21602438ce5SAdrian Chadd #endif 21702438ce5SAdrian Chadd 21802438ce5SAdrian Chadd static platform_method_t ipq4018_methods[] = { 21902438ce5SAdrian Chadd PLATFORMMETHOD(platform_attach, ipq4018_attach), 22002438ce5SAdrian Chadd PLATFORMMETHOD(platform_devmap_init, ipq4018_devmap_init), 22102438ce5SAdrian Chadd PLATFORMMETHOD(platform_late_init, ipq4018_late_init), 22202438ce5SAdrian Chadd PLATFORMMETHOD(platform_cpu_reset, ipq4018_cpu_reset), 22302438ce5SAdrian Chadd 22402438ce5SAdrian Chadd #ifdef SMP 22502438ce5SAdrian Chadd PLATFORMMETHOD(platform_mp_start_ap, ipq4018_mp_start_ap), 22602438ce5SAdrian Chadd PLATFORMMETHOD(platform_mp_setmaxid, ipq4018_mp_setmaxid), 22702438ce5SAdrian Chadd #endif 22802438ce5SAdrian Chadd 22902438ce5SAdrian Chadd PLATFORMMETHOD_END, 23002438ce5SAdrian Chadd }; 23102438ce5SAdrian Chadd 23202438ce5SAdrian Chadd FDT_PLATFORM_DEF2(ipq4018, ipq4018_ac58u, "ASUS RT-AC58U", 0, 23302438ce5SAdrian Chadd "asus,rt-ac58u", 80); 234