1*2e4048e4Sskrll /* $NetBSD: meson_platform.c,v 1.21 2023/04/07 08:55:29 skrll Exp $ */
288499cefSjmcneill
388499cefSjmcneill /*-
488499cefSjmcneill * Copyright (c) 2019 Jared McNeill <jmcneill@invisible.ca>
588499cefSjmcneill * All rights reserved.
688499cefSjmcneill *
788499cefSjmcneill * Redistribution and use in source and binary forms, with or without
888499cefSjmcneill * modification, are permitted provided that the following conditions
988499cefSjmcneill * are met:
1088499cefSjmcneill * 1. Redistributions of source code must retain the above copyright
1188499cefSjmcneill * notice, this list of conditions and the following disclaimer.
1288499cefSjmcneill * 2. Redistributions in binary form must reproduce the above copyright
1388499cefSjmcneill * notice, this list of conditions and the following disclaimer in the
1488499cefSjmcneill * documentation and/or other materials provided with the distribution.
1588499cefSjmcneill *
1688499cefSjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1788499cefSjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1888499cefSjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1988499cefSjmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2088499cefSjmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2188499cefSjmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2288499cefSjmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2388499cefSjmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2488499cefSjmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2588499cefSjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2688499cefSjmcneill * SUCH DAMAGE.
2788499cefSjmcneill */
2888499cefSjmcneill
2988499cefSjmcneill #include "opt_soc.h"
3088499cefSjmcneill #include "opt_multiprocessor.h"
3188499cefSjmcneill #include "opt_console.h"
3288499cefSjmcneill
3388499cefSjmcneill #include "arml2cc.h"
3488499cefSjmcneill
3588499cefSjmcneill #include <sys/cdefs.h>
36*2e4048e4Sskrll __KERNEL_RCSID(0, "$NetBSD: meson_platform.c,v 1.21 2023/04/07 08:55:29 skrll Exp $");
3788499cefSjmcneill
3888499cefSjmcneill #include <sys/param.h>
3988499cefSjmcneill #include <sys/bus.h>
4088499cefSjmcneill #include <sys/cpu.h>
4188499cefSjmcneill #include <sys/device.h>
4288499cefSjmcneill #include <sys/termios.h>
4388499cefSjmcneill
4488499cefSjmcneill #include <dev/fdt/fdtvar.h>
45*2e4048e4Sskrll
4688499cefSjmcneill #include <arm/fdt/arm_fdtvar.h>
4788499cefSjmcneill
4888499cefSjmcneill #include <uvm/uvm_extern.h>
4988499cefSjmcneill
5088499cefSjmcneill #include <machine/bootconfig.h>
5188499cefSjmcneill #include <arm/cpufunc.h>
5288499cefSjmcneill
5388499cefSjmcneill #include <arm/cortex/a9tmr_var.h>
5482a9c324Sjmcneill #include <arm/cortex/gtmr_var.h>
5588499cefSjmcneill #include <arm/cortex/pl310_var.h>
5688499cefSjmcneill #include <arm/cortex/scu_reg.h>
5788499cefSjmcneill
5888499cefSjmcneill #include <arm/amlogic/meson_uart.h>
5988499cefSjmcneill
6088499cefSjmcneill #include <evbarm/fdt/platform.h>
6188499cefSjmcneill #include <evbarm/fdt/machdep.h>
6288499cefSjmcneill
63ce2792c5Sjmcneill #include <net/if_ether.h>
64ce2792c5Sjmcneill
6588499cefSjmcneill #include <libfdt.h>
6688499cefSjmcneill
6788499cefSjmcneill #define MESON_CORE_APB3_VBASE KERNEL_IO_VBASE
6888499cefSjmcneill #define MESON_CORE_APB3_PBASE 0xc0000000
6982a9c324Sjmcneill #define MESON_CORE_APB3_SIZE 0x01400000
7088499cefSjmcneill
7188499cefSjmcneill #define MESON_CBUS_OFFSET 0x01100000
7288499cefSjmcneill
73f0949908Sjmcneill #define MESON8B_WATCHDOG_BASE 0xc1109900
74f0949908Sjmcneill #define MESON8B_WATCHDOG_SIZE 0x8
75f0949908Sjmcneill #define MESON8B_WATCHDOG_TC 0x00
76f0949908Sjmcneill #define MESON8B_WATCHDOG_TC_CPUS __BITS(27,24)
77f0949908Sjmcneill #define MESON8B_WATCHDOG_TC_ENABLE __BIT(19)
78f0949908Sjmcneill #define MESON8B_WATCHDOG_TC_TCNT __BITS(15,0)
79f0949908Sjmcneill #define MESON8B_WATCHDOG_RESET 0x04
80f0949908Sjmcneill #define MESON8B_WATCHDOG_RESET_COUNT __BITS(15,0)
81f0949908Sjmcneill
82f0949908Sjmcneill #define MESONGX_WATCHDOG_BASE 0xc11098d0
83f0949908Sjmcneill #define MESONGX_WATCHDOG_SIZE 0x10
84f0949908Sjmcneill #define MESONGX_WATCHDOG_CNTL 0x00
8532461851Sjmcneill #define MESONGX_WATCHDOG_CNTL_CLK_EN __BIT(24)
8632461851Sjmcneill #define MESONGX_WATCHDOG_CNTL_SYS_RESET_N_EN __BIT(21)
87f0949908Sjmcneill #define MESONGX_WATCHDOG_CNTL_WDOG_EN __BIT(18)
88f0949908Sjmcneill #define MESONGX_WATCHDOG_CNTL1 0x04
89f0949908Sjmcneill #define MESONGX_WATCHDOG_TCNT 0x08
90f0949908Sjmcneill #define MESONGX_WATCHDOG_TCNT_COUNT __BITS(15,0)
91f0949908Sjmcneill #define MESONGX_WATCHDOG_RESET 0x0c
9288499cefSjmcneill
9388499cefSjmcneill #define MESON8B_ARM_VBASE (MESON_CORE_APB3_VBASE + MESON_CORE_APB3_SIZE)
9488499cefSjmcneill #define MESON8B_ARM_PBASE 0xc4200000
9588499cefSjmcneill #define MESON8B_ARM_SIZE 0x00200000
9688499cefSjmcneill #define MESON8B_ARM_PL310_BASE 0x00000000
9788499cefSjmcneill #define MESON8B_ARM_SCU_BASE 0x00100000
9888499cefSjmcneill
9988499cefSjmcneill #define MESON8B_AOBUS_VBASE (MESON8B_ARM_VBASE + MESON8B_ARM_SIZE)
10082a9c324Sjmcneill #define MESON8B_AOBUS_PBASE 0xc8000000
10182a9c324Sjmcneill #define MESON8B_AOBUS_SIZE 0x00200000
1021b232e6cSjmcneill #define MESON8B_AOBUS_RTI_OFFSET 0x00100000
10388499cefSjmcneill
10488499cefSjmcneill #define MESON_AOBUS_PWR_CTRL0_REG 0xe0
10588499cefSjmcneill #define MESON_AOBUS_PWR_CTRL1_REG 0xe4
10688499cefSjmcneill #define MESON_AOBUS_PWR_MEM_PD0_REG 0xf4
10788499cefSjmcneill
10888499cefSjmcneill #define MESON_CBUS_CPU_CLK_CNTL_REG 0x419c
10988499cefSjmcneill
11088499cefSjmcneill
11188499cefSjmcneill #define MESON8B_SRAM_VBASE (MESON8B_AOBUS_VBASE + MESON8B_AOBUS_SIZE)
11288499cefSjmcneill #define MESON8B_SRAM_PBASE 0xd9000000
11382a9c324Sjmcneill #define MESON8B_SRAM_SIZE 0x00200000 /* 0x10000 rounded up */
11488499cefSjmcneill
11588499cefSjmcneill #define MESON8B_SRAM_CPUCONF_OFFSET 0x1ff80
11688499cefSjmcneill #define MESON8B_SRAM_CPUCONF_CTRL_REG 0x00
11788499cefSjmcneill #define MESON8B_SRAM_CPUCONF_CPU_ADDR_REG(n) (0x04 * (n))
11888499cefSjmcneill
11988499cefSjmcneill
12088499cefSjmcneill extern struct arm32_bus_dma_tag arm_generic_dma_tag;
12188499cefSjmcneill extern struct bus_space arm_generic_bs_tag;
12288499cefSjmcneill
12388499cefSjmcneill #define meson_dma_tag arm_generic_dma_tag
12488499cefSjmcneill #define meson_bs_tag arm_generic_bs_tag
12588499cefSjmcneill
12688499cefSjmcneill static const struct pmap_devmap *
meson_platform_devmap(void)12788499cefSjmcneill meson_platform_devmap(void)
12888499cefSjmcneill {
12988499cefSjmcneill static const struct pmap_devmap devmap[] = {
13088499cefSjmcneill DEVMAP_ENTRY(MESON_CORE_APB3_VBASE,
13188499cefSjmcneill MESON_CORE_APB3_PBASE,
13288499cefSjmcneill MESON_CORE_APB3_SIZE),
13388499cefSjmcneill DEVMAP_ENTRY(MESON8B_ARM_VBASE,
13488499cefSjmcneill MESON8B_ARM_PBASE,
13588499cefSjmcneill MESON8B_ARM_SIZE),
13688499cefSjmcneill DEVMAP_ENTRY(MESON8B_AOBUS_VBASE,
13788499cefSjmcneill MESON8B_AOBUS_PBASE,
13888499cefSjmcneill MESON8B_AOBUS_SIZE),
13988499cefSjmcneill DEVMAP_ENTRY(MESON8B_SRAM_VBASE,
14088499cefSjmcneill MESON8B_SRAM_PBASE,
14188499cefSjmcneill MESON8B_SRAM_SIZE),
14288499cefSjmcneill DEVMAP_ENTRY_END
14388499cefSjmcneill };
14488499cefSjmcneill
14588499cefSjmcneill return devmap;
14688499cefSjmcneill }
14788499cefSjmcneill
14888499cefSjmcneill static void
meson_platform_init_attach_args(struct fdt_attach_args * faa)14988499cefSjmcneill meson_platform_init_attach_args(struct fdt_attach_args *faa)
15088499cefSjmcneill {
15188499cefSjmcneill faa->faa_bst = &meson_bs_tag;
15288499cefSjmcneill faa->faa_dmat = &meson_dma_tag;
15388499cefSjmcneill }
15488499cefSjmcneill
15588499cefSjmcneill void meson_platform_early_putchar(char);
15688499cefSjmcneill
157078bd70bSskrll void __noasan
meson_platform_early_putchar(char c)15888499cefSjmcneill meson_platform_early_putchar(char c)
15988499cefSjmcneill {
16088499cefSjmcneill #ifdef CONSADDR
16188499cefSjmcneill #define CONSADDR_VA ((CONSADDR - MESON8B_AOBUS_PBASE) + MESON8B_AOBUS_VBASE)
16288499cefSjmcneill volatile uint32_t *uartaddr = cpu_earlydevice_va_p() ?
16388499cefSjmcneill (volatile uint32_t *)CONSADDR_VA :
16488499cefSjmcneill (volatile uint32_t *)CONSADDR;
16588499cefSjmcneill int timo = 150000;
16688499cefSjmcneill
16788499cefSjmcneill while ((uartaddr[UART_STATUS_REG/4] & UART_STATUS_TX_EMPTY) == 0) {
16888499cefSjmcneill if (--timo == 0)
16988499cefSjmcneill break;
17088499cefSjmcneill }
17188499cefSjmcneill
17288499cefSjmcneill uartaddr[UART_WFIFO_REG/4] = c;
17388499cefSjmcneill
17488499cefSjmcneill while ((uartaddr[UART_STATUS_REG/4] & UART_STATUS_TX_EMPTY) == 0) {
17588499cefSjmcneill if (--timo == 0)
17688499cefSjmcneill break;
17788499cefSjmcneill }
17888499cefSjmcneill #endif
17988499cefSjmcneill }
18088499cefSjmcneill
18188499cefSjmcneill static void
meson_platform_device_register(device_t self,void * aux)18288499cefSjmcneill meson_platform_device_register(device_t self, void *aux)
18388499cefSjmcneill {
184ce2792c5Sjmcneill prop_dictionary_t dict = device_properties(self);
185ce2792c5Sjmcneill
186ce2792c5Sjmcneill if (device_is_a(self, "awge") && device_unit(self) == 0) {
187ce2792c5Sjmcneill uint8_t enaddr[ETHER_ADDR_LEN];
188ce2792c5Sjmcneill if (get_bootconf_option(boot_args, "awge0.mac-address",
189ce2792c5Sjmcneill BOOTOPT_TYPE_MACADDR, enaddr)) {
190280931ccSskrll prop_dictionary_set_data(dict, "mac-address", enaddr,
191ce2792c5Sjmcneill sizeof(enaddr));
192ce2792c5Sjmcneill }
193ce2792c5Sjmcneill }
194ce2792c5Sjmcneill
19582a9c324Sjmcneill if (device_is_a(self, "mesonfb")) {
196ce2792c5Sjmcneill int scale, depth;
197ce2792c5Sjmcneill
198ce2792c5Sjmcneill if (get_bootconf_option(boot_args, "fb.scale",
199ce2792c5Sjmcneill BOOTOPT_TYPE_INT, &scale) && scale > 0) {
200ce2792c5Sjmcneill prop_dictionary_set_uint32(dict, "scale", scale);
201ce2792c5Sjmcneill }
202ce2792c5Sjmcneill if (get_bootconf_option(boot_args, "fb.depth",
203ce2792c5Sjmcneill BOOTOPT_TYPE_INT, &depth)) {
204ce2792c5Sjmcneill prop_dictionary_set_uint32(dict, "depth", depth);
205ce2792c5Sjmcneill }
206ce2792c5Sjmcneill }
20788499cefSjmcneill }
20888499cefSjmcneill
209d52edb14Sjmcneill #if defined(SOC_MESON8B)
210d52edb14Sjmcneill #define MESON8B_BOOTINFO_REG 0xd901ff04
211d52edb14Sjmcneill static int
meson8b_get_boot_id(void)212d52edb14Sjmcneill meson8b_get_boot_id(void)
213d52edb14Sjmcneill {
214d52edb14Sjmcneill static int boot_id = -1;
215d52edb14Sjmcneill bus_space_tag_t bst = &arm_generic_bs_tag;
216d52edb14Sjmcneill bus_space_handle_t bsh;
217d52edb14Sjmcneill
218d52edb14Sjmcneill if (boot_id == -1) {
219d52edb14Sjmcneill if (bus_space_map(bst, MESON8B_BOOTINFO_REG, 4, 0, &bsh) != 0)
220d52edb14Sjmcneill return -1;
221d52edb14Sjmcneill
222d52edb14Sjmcneill boot_id = (int)bus_space_read_4(bst, bsh, 0);
223d52edb14Sjmcneill
224d52edb14Sjmcneill bus_space_unmap(bst, bsh, 4);
225d52edb14Sjmcneill }
226d52edb14Sjmcneill
227d52edb14Sjmcneill return boot_id;
228d52edb14Sjmcneill }
229d52edb14Sjmcneill
230d52edb14Sjmcneill static void
meson8b_platform_device_register(device_t self,void * aux)231d52edb14Sjmcneill meson8b_platform_device_register(device_t self, void *aux)
232d52edb14Sjmcneill {
233d52edb14Sjmcneill device_t parent = device_parent(self);
234d52edb14Sjmcneill char *ptr;
235d52edb14Sjmcneill
236d52edb14Sjmcneill if (device_is_a(self, "ld") &&
237d52edb14Sjmcneill device_is_a(parent, "sdmmc") &&
238d52edb14Sjmcneill (device_is_a(device_parent(parent), "mesonsdhc") ||
239d52edb14Sjmcneill device_is_a(device_parent(parent), "mesonsdio"))) {
240d52edb14Sjmcneill
241d52edb14Sjmcneill const int boot_id = meson8b_get_boot_id();
242d52edb14Sjmcneill const bool has_rootdev = get_bootconf_option(boot_args, "root", BOOTOPT_TYPE_STRING, &ptr) != 0;
243d52edb14Sjmcneill
244d52edb14Sjmcneill if (!has_rootdev) {
245d52edb14Sjmcneill char rootarg[64];
246d52edb14Sjmcneill snprintf(rootarg, sizeof(rootarg), " root=%sa", device_xname(self));
247d52edb14Sjmcneill
248d52edb14Sjmcneill /* Assume that SDIO is used for SD cards and SDHC is used for eMMC */
249d52edb14Sjmcneill if (device_is_a(device_parent(parent), "mesonsdhc") && boot_id == 0)
250d52edb14Sjmcneill strcat(boot_args, rootarg);
251d52edb14Sjmcneill else if (device_is_a(device_parent(parent), "mesonsdio") && boot_id != 0)
252d52edb14Sjmcneill strcat(boot_args, rootarg);
253d52edb14Sjmcneill }
254d52edb14Sjmcneill }
255d52edb14Sjmcneill
256d52edb14Sjmcneill meson_platform_device_register(self, aux);
257d52edb14Sjmcneill }
258d52edb14Sjmcneill #endif
259d52edb14Sjmcneill
26088499cefSjmcneill static u_int
meson_platform_uart_freq(void)26188499cefSjmcneill meson_platform_uart_freq(void)
26288499cefSjmcneill {
26388499cefSjmcneill return 0;
26488499cefSjmcneill }
26588499cefSjmcneill
26688499cefSjmcneill static void
meson_platform_bootstrap(void)26788499cefSjmcneill meson_platform_bootstrap(void)
26888499cefSjmcneill {
26988499cefSjmcneill arm_fdt_cpu_bootstrap();
27088499cefSjmcneill
27188499cefSjmcneill void *fdt_data = __UNCONST(fdtbus_get_data());
27288499cefSjmcneill const int chosen_off = fdt_path_offset(fdt_data, "/chosen");
27388499cefSjmcneill if (chosen_off < 0)
27488499cefSjmcneill return;
27588499cefSjmcneill
27688499cefSjmcneill if (match_bootconf_option(boot_args, "console", "fb")) {
27788499cefSjmcneill const int framebuffer_off =
27888499cefSjmcneill fdt_path_offset(fdt_data, "/chosen/framebuffer");
27988499cefSjmcneill if (framebuffer_off >= 0) {
28088499cefSjmcneill const char *status = fdt_getprop(fdt_data,
28188499cefSjmcneill framebuffer_off, "status", NULL);
28288499cefSjmcneill if (status == NULL || strncmp(status, "ok", 2) == 0) {
28388499cefSjmcneill fdt_setprop_string(fdt_data, chosen_off,
28488499cefSjmcneill "stdout-path", "/chosen/framebuffer");
28588499cefSjmcneill }
28688499cefSjmcneill }
28788499cefSjmcneill } else if (match_bootconf_option(boot_args, "console", "serial")) {
28888499cefSjmcneill fdt_setprop_string(fdt_data, chosen_off,
28988499cefSjmcneill "stdout-path", "serial0:115200n8");
29088499cefSjmcneill }
29188499cefSjmcneill }
29288499cefSjmcneill
29388499cefSjmcneill #if defined(SOC_MESON8B)
29488499cefSjmcneill static void
meson8b_platform_bootstrap(void)29588499cefSjmcneill meson8b_platform_bootstrap(void)
29688499cefSjmcneill {
29788499cefSjmcneill
29888499cefSjmcneill #if NARML2CC > 0
29988499cefSjmcneill const bus_space_handle_t pl310_bh = MESON8B_ARM_VBASE + MESON8B_ARM_PL310_BASE;
30088499cefSjmcneill arml2cc_init(&arm_generic_bs_tag, pl310_bh, 0);
30188499cefSjmcneill #endif
30288499cefSjmcneill
30388499cefSjmcneill meson_platform_bootstrap();
30488499cefSjmcneill }
30588499cefSjmcneill
30688499cefSjmcneill static void
meson8b_platform_reset(void)307f0949908Sjmcneill meson8b_platform_reset(void)
30888499cefSjmcneill {
30988499cefSjmcneill bus_space_tag_t bst = &meson_bs_tag;
31088499cefSjmcneill bus_space_handle_t bsh;
31188499cefSjmcneill
312f0949908Sjmcneill bus_space_map(bst, MESON8B_WATCHDOG_BASE, MESON8B_WATCHDOG_SIZE, 0, &bsh);
31388499cefSjmcneill
314f0949908Sjmcneill bus_space_write_4(bst, bsh, MESON8B_WATCHDOG_TC,
315f0949908Sjmcneill MESON8B_WATCHDOG_TC_CPUS | MESON8B_WATCHDOG_TC_ENABLE | __SHIFTIN(0xfff, MESON8B_WATCHDOG_TC_TCNT));
316f0949908Sjmcneill bus_space_write_4(bst, bsh, MESON8B_WATCHDOG_RESET, 0);
31788499cefSjmcneill
31888499cefSjmcneill for (;;) {
31988499cefSjmcneill __asm("wfi");
32088499cefSjmcneill }
32188499cefSjmcneill }
32288499cefSjmcneill
3238e6b5205Srin #ifdef MULTIPROCESSOR
32488499cefSjmcneill static void
meson8b_mpinit_delay(u_int n)32588499cefSjmcneill meson8b_mpinit_delay(u_int n)
32688499cefSjmcneill {
32788499cefSjmcneill for (volatile int i = 0; i < n; i++)
32888499cefSjmcneill ;
32988499cefSjmcneill }
3308e6b5205Srin #endif
33188499cefSjmcneill
33288499cefSjmcneill static int
cpu_enable_meson8b(int phandle)33388499cefSjmcneill cpu_enable_meson8b(int phandle)
33488499cefSjmcneill {
3358e6b5205Srin #ifdef MULTIPROCESSOR
33688499cefSjmcneill const bus_addr_t cbar = armreg_cbar_read();
33788499cefSjmcneill bus_space_tag_t bst = &arm_generic_bs_tag;
33888499cefSjmcneill
33988499cefSjmcneill const bus_space_handle_t scu_bsh =
34088499cefSjmcneill cbar - MESON8B_ARM_PBASE + MESON8B_ARM_VBASE;
34188499cefSjmcneill const bus_space_handle_t cpuconf_bsh =
34288499cefSjmcneill MESON8B_SRAM_VBASE + MESON8B_SRAM_CPUCONF_OFFSET;
34388499cefSjmcneill const bus_space_handle_t ao_bsh =
3441b232e6cSjmcneill MESON8B_AOBUS_VBASE + MESON8B_AOBUS_RTI_OFFSET;
34588499cefSjmcneill const bus_space_handle_t cbus_bsh =
34688499cefSjmcneill MESON_CORE_APB3_VBASE + MESON_CBUS_OFFSET;
34788499cefSjmcneill uint32_t pwr_sts, pwr_cntl0, pwr_cntl1, cpuclk, mempd0;
34888499cefSjmcneill uint64_t mpidr;
34988499cefSjmcneill
35088499cefSjmcneill fdtbus_get_reg64(phandle, 0, &mpidr, NULL);
35188499cefSjmcneill
35288499cefSjmcneill const u_int cpuno = __SHIFTOUT(mpidr, MPIDR_AFF0);
35388499cefSjmcneill
35488499cefSjmcneill bus_space_write_4(bst, cpuconf_bsh, MESON8B_SRAM_CPUCONF_CPU_ADDR_REG(cpuno),
35588499cefSjmcneill KERN_VTOPHYS((vaddr_t)cpu_mpstart));
35688499cefSjmcneill
35788499cefSjmcneill pwr_sts = bus_space_read_4(bst, scu_bsh, SCU_CPU_PWR_STS);
35888499cefSjmcneill pwr_sts &= ~(3 << (8 * cpuno));
35988499cefSjmcneill bus_space_write_4(bst, scu_bsh, SCU_CPU_PWR_STS, pwr_sts);
36088499cefSjmcneill
36188499cefSjmcneill pwr_cntl0 = bus_space_read_4(bst, ao_bsh, MESON_AOBUS_PWR_CTRL0_REG);
36288499cefSjmcneill pwr_cntl0 &= ~((3 << 18) << ((cpuno - 1) * 2));
36388499cefSjmcneill bus_space_write_4(bst, ao_bsh, MESON_AOBUS_PWR_CTRL0_REG, pwr_cntl0);
36488499cefSjmcneill
36588499cefSjmcneill meson8b_mpinit_delay(5000);
36688499cefSjmcneill
36788499cefSjmcneill cpuclk = bus_space_read_4(bst, cbus_bsh, MESON_CBUS_CPU_CLK_CNTL_REG);
36888499cefSjmcneill cpuclk |= (1 << (24 + cpuno));
36988499cefSjmcneill bus_space_write_4(bst, cbus_bsh, MESON_CBUS_CPU_CLK_CNTL_REG, cpuclk);
37088499cefSjmcneill
37188499cefSjmcneill mempd0 = bus_space_read_4(bst, ao_bsh, MESON_AOBUS_PWR_MEM_PD0_REG);
37288499cefSjmcneill mempd0 &= ~((uint32_t)(0xf << 28) >> ((cpuno - 1) * 4));
37388499cefSjmcneill bus_space_write_4(bst, ao_bsh, MESON_AOBUS_PWR_MEM_PD0_REG, mempd0);
37488499cefSjmcneill
37588499cefSjmcneill pwr_cntl1 = bus_space_read_4(bst, ao_bsh, MESON_AOBUS_PWR_CTRL1_REG);
37688499cefSjmcneill pwr_cntl1 &= ~((3 << 4) << ((cpuno - 1) * 2));
37788499cefSjmcneill bus_space_write_4(bst, ao_bsh, MESON_AOBUS_PWR_CTRL1_REG, pwr_cntl1);
37888499cefSjmcneill
37988499cefSjmcneill meson8b_mpinit_delay(10000);
38088499cefSjmcneill
38188499cefSjmcneill for (;;) {
38288499cefSjmcneill pwr_cntl1 = bus_space_read_4(bst, ao_bsh,
38388499cefSjmcneill MESON_AOBUS_PWR_CTRL1_REG) & ((1 << 17) << (cpuno - 1));
38488499cefSjmcneill if (pwr_cntl1)
38588499cefSjmcneill break;
38688499cefSjmcneill meson8b_mpinit_delay(10000);
38788499cefSjmcneill }
38888499cefSjmcneill
38988499cefSjmcneill pwr_cntl0 = bus_space_read_4(bst, ao_bsh, MESON_AOBUS_PWR_CTRL0_REG);
39088499cefSjmcneill pwr_cntl0 &= ~(1 << cpuno);
39188499cefSjmcneill bus_space_write_4(bst, ao_bsh, MESON_AOBUS_PWR_CTRL0_REG, pwr_cntl0);
39288499cefSjmcneill
39388499cefSjmcneill cpuclk = bus_space_read_4(bst, cbus_bsh, MESON_CBUS_CPU_CLK_CNTL_REG);
39488499cefSjmcneill cpuclk &= ~(1 << (24 + cpuno));
39588499cefSjmcneill bus_space_write_4(bst, cbus_bsh, MESON_CBUS_CPU_CLK_CNTL_REG, cpuclk);
39688499cefSjmcneill
39788499cefSjmcneill bus_space_write_4(bst, cpuconf_bsh, MESON8B_SRAM_CPUCONF_CPU_ADDR_REG(cpuno),
39888499cefSjmcneill KERN_VTOPHYS((vaddr_t)cpu_mpstart));
39988499cefSjmcneill
40088499cefSjmcneill uint32_t ctrl = bus_space_read_4(bst, cpuconf_bsh, MESON8B_SRAM_CPUCONF_CTRL_REG);
40188499cefSjmcneill ctrl |= __BITS(cpuno,0);
40288499cefSjmcneill bus_space_write_4(bst, cpuconf_bsh, MESON8B_SRAM_CPUCONF_CTRL_REG, ctrl);
4038e6b5205Srin #endif
40488499cefSjmcneill
40588499cefSjmcneill return 0;
40688499cefSjmcneill }
40788499cefSjmcneill
40888499cefSjmcneill ARM_CPU_METHOD(meson8b, "amlogic,meson8b-smp", cpu_enable_meson8b);
40988499cefSjmcneill
410679fad90Sskrll static int
meson8b_mpstart(void)41182a9c324Sjmcneill meson8b_mpstart(void)
41288499cefSjmcneill {
413679fad90Sskrll int ret = 0;
41488499cefSjmcneill const bus_addr_t cbar = armreg_cbar_read();
41588499cefSjmcneill bus_space_tag_t bst = &arm_generic_bs_tag;
41688499cefSjmcneill
41788499cefSjmcneill if (cbar == 0)
418679fad90Sskrll return ret;
41988499cefSjmcneill
42088499cefSjmcneill const bus_space_handle_t scu_bsh =
42188499cefSjmcneill cbar - MESON8B_ARM_PBASE + MESON8B_ARM_VBASE;
42288499cefSjmcneill
42388499cefSjmcneill const uint32_t scu_cfg = bus_space_read_4(bst, scu_bsh, SCU_CFG);
42488499cefSjmcneill const u_int ncpus = (scu_cfg & SCU_CFG_CPUMAX) + 1;
42588499cefSjmcneill
42688499cefSjmcneill if (ncpus < 2)
427679fad90Sskrll return ret;
42888499cefSjmcneill
42988499cefSjmcneill /*
43088499cefSjmcneill * Invalidate all SCU cache tags. That is, for all cores (0-3)
43188499cefSjmcneill */
43288499cefSjmcneill bus_space_write_4(bst, scu_bsh, SCU_INV_ALL_REG, 0xffff);
43388499cefSjmcneill
43488499cefSjmcneill uint32_t scu_ctl = bus_space_read_4(bst, scu_bsh, SCU_CTL);
43588499cefSjmcneill scu_ctl |= SCU_CTL_SCU_ENA;
43688499cefSjmcneill bus_space_write_4(bst, scu_bsh, SCU_CTL, scu_ctl);
43788499cefSjmcneill
43888499cefSjmcneill armv7_dcache_wbinv_all();
43988499cefSjmcneill
440679fad90Sskrll ret = arm_fdt_cpu_mpstart();
441679fad90Sskrll return ret;
44288499cefSjmcneill }
44388499cefSjmcneill
444*2e4048e4Sskrll static const struct fdt_platform meson8b_platform = {
445*2e4048e4Sskrll .fp_devmap = meson_platform_devmap,
446*2e4048e4Sskrll .fp_bootstrap = meson8b_platform_bootstrap,
447*2e4048e4Sskrll .fp_init_attach_args = meson_platform_init_attach_args,
448*2e4048e4Sskrll .fp_device_register = meson8b_platform_device_register,
449*2e4048e4Sskrll .fp_reset = meson8b_platform_reset,
450*2e4048e4Sskrll .fp_delay = a9ptmr_delay,
451*2e4048e4Sskrll .fp_uart_freq = meson_platform_uart_freq,
452*2e4048e4Sskrll .fp_mpstart = meson8b_mpstart,
45388499cefSjmcneill };
45488499cefSjmcneill
455*2e4048e4Sskrll FDT_PLATFORM(meson8b, "amlogic,meson8b", &meson8b_platform);
45682a9c324Sjmcneill #endif /* SOC_MESON8B */
45782a9c324Sjmcneill
458838e36f6Sjmcneill #if defined(SOC_MESONGX)
459f0949908Sjmcneill static void
mesongx_platform_reset(void)460f0949908Sjmcneill mesongx_platform_reset(void)
461f0949908Sjmcneill {
462f0949908Sjmcneill bus_space_tag_t bst = &meson_bs_tag;
463f0949908Sjmcneill bus_space_handle_t bsh;
464f0949908Sjmcneill uint32_t val;
465f0949908Sjmcneill
466f0949908Sjmcneill bus_space_map(bst, MESONGX_WATCHDOG_BASE, MESONGX_WATCHDOG_SIZE, 0, &bsh);
467f0949908Sjmcneill
46832461851Sjmcneill val = MESONGX_WATCHDOG_CNTL_SYS_RESET_N_EN |
46932461851Sjmcneill MESONGX_WATCHDOG_CNTL_WDOG_EN |
47032461851Sjmcneill MESONGX_WATCHDOG_CNTL_CLK_EN;
471f0949908Sjmcneill bus_space_write_4(bst, bsh, MESONGX_WATCHDOG_CNTL, val);
472f0949908Sjmcneill
473f0949908Sjmcneill bus_space_write_4(bst, bsh, MESONGX_WATCHDOG_TCNT, 1);
474f0949908Sjmcneill
475f0949908Sjmcneill bus_space_write_4(bst, bsh, MESONGX_WATCHDOG_RESET, 0);
476f0949908Sjmcneill
477f0949908Sjmcneill for (;;) {
478f0949908Sjmcneill __asm("wfi");
479f0949908Sjmcneill }
480f0949908Sjmcneill }
481f0949908Sjmcneill
482*2e4048e4Sskrll static const struct fdt_platform mesongx_platform = {
483*2e4048e4Sskrll .fp_devmap = meson_platform_devmap,
484*2e4048e4Sskrll .fp_bootstrap = meson_platform_bootstrap,
485*2e4048e4Sskrll .fp_init_attach_args = meson_platform_init_attach_args,
486*2e4048e4Sskrll .fp_device_register = meson_platform_device_register,
487*2e4048e4Sskrll .fp_reset = mesongx_platform_reset,
488*2e4048e4Sskrll .fp_delay = gtmr_delay,
489*2e4048e4Sskrll .fp_uart_freq = meson_platform_uart_freq,
490*2e4048e4Sskrll .fp_mpstart = arm_fdt_cpu_mpstart,
49182a9c324Sjmcneill };
49282a9c324Sjmcneill
493838e36f6Sjmcneill #if defined(SOC_MESONGXBB)
494*2e4048e4Sskrll FDT_PLATFORM(mesongxbb, "amlogic,meson-gxbb", &mesongx_platform);
495838e36f6Sjmcneill #endif /* SOC_MESONGXBB */
496838e36f6Sjmcneill #if defined(SOC_MESONGXL)
497*2e4048e4Sskrll FDT_PLATFORM(mesongxl, "amlogic,meson-gxl", &mesongx_platform);
498838e36f6Sjmcneill #endif /* SOC_MESONGXL */
499838e36f6Sjmcneill #endif /* SOC_MESONGX */
500