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
ipq4018_attach(platform_t plat)5502438ce5SAdrian Chadd ipq4018_attach(platform_t plat)
5602438ce5SAdrian Chadd {
5702438ce5SAdrian Chadd return (0);
5802438ce5SAdrian Chadd }
5902438ce5SAdrian Chadd
6002438ce5SAdrian Chadd static void
ipq4018_late_init(platform_t plat)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
ipq4018_devmap_init(platform_t plat)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
ipq4018_cpu_reset_pshold(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
ipq4018_cpu_reset(platform_t plat)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