Home | History | Annotate | Line # | Download | only in amlogic
meson_platform.c revision 1.1
      1 /* $NetBSD: meson_platform.c,v 1.1 2019/01/19 20:56:03 jmcneill Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2019 Jared McNeill <jmcneill (at) invisible.ca>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include "opt_soc.h"
     30 #include "opt_multiprocessor.h"
     31 #include "opt_console.h"
     32 
     33 #include "arml2cc.h"
     34 
     35 #include <sys/cdefs.h>
     36 __KERNEL_RCSID(0, "$NetBSD: meson_platform.c,v 1.1 2019/01/19 20:56:03 jmcneill Exp $");
     37 
     38 #include <sys/param.h>
     39 #include <sys/bus.h>
     40 #include <sys/cpu.h>
     41 #include <sys/device.h>
     42 #include <sys/termios.h>
     43 
     44 #include <dev/fdt/fdtvar.h>
     45 #include <arm/fdt/arm_fdtvar.h>
     46 
     47 #include <uvm/uvm_extern.h>
     48 
     49 #include <machine/bootconfig.h>
     50 #include <arm/cpufunc.h>
     51 
     52 #include <arm/cortex/a9tmr_var.h>
     53 #include <arm/cortex/pl310_var.h>
     54 #include <arm/cortex/scu_reg.h>
     55 
     56 #include <arm/amlogic/meson_uart.h>
     57 
     58 #include <evbarm/fdt/platform.h>
     59 #include <evbarm/fdt/machdep.h>
     60 
     61 #include <libfdt.h>
     62 
     63 #define	MESON_CORE_APB3_VBASE	KERNEL_IO_VBASE
     64 #define	MESON_CORE_APB3_PBASE	0xc0000000
     65 #define	MESON_CORE_APB3_SIZE	0x01300000
     66 
     67 #define MESON_CBUS_OFFSET	0x01100000
     68 
     69 #define	MESON_WATCHDOG_BASE	0xc1109900
     70 #define	MESON_WATCHDOG_SIZE	0x8
     71 #define	 MESON_WATCHDOG_TC	0x00
     72 #define	  WATCHDOG_TC_CPUS	__BITS(27,24)
     73 #define	  WATCHDOG_TC_ENABLE	__BIT(19)
     74 #define	  WATCHDOG_TC_TCNT	__BITS(15,0)
     75 #define	 MESON_WATCHDOG_RESET	0x04
     76 #define	  WATCHDOG_RESET_COUNT	__BITS(15,0)
     77 
     78 #define MESON8B_ARM_VBASE	(MESON_CORE_APB3_VBASE + MESON_CORE_APB3_SIZE)
     79 #define	MESON8B_ARM_PBASE	0xc4200000
     80 #define MESON8B_ARM_SIZE	0x00200000
     81 #define MESON8B_ARM_PL310_BASE	0x00000000
     82 #define MESON8B_ARM_SCU_BASE	0x00100000
     83 
     84 #define MESON8B_AOBUS_VBASE	(MESON8B_ARM_VBASE + MESON8B_ARM_SIZE)
     85 #define	MESON8B_AOBUS_PBASE	0xc8100000
     86 #define MESON8B_AOBUS_SIZE	0x00100000
     87 
     88 #define MESON_AOBUS_PWR_CTRL0_REG	0xe0
     89 #define MESON_AOBUS_PWR_CTRL1_REG	0xe4
     90 #define MESON_AOBUS_PWR_MEM_PD0_REG	0xf4
     91 
     92 #define MESON_CBUS_CPU_CLK_CNTL_REG	0x419c
     93 
     94 
     95 #define MESON8B_SRAM_VBASE	(MESON8B_AOBUS_VBASE + MESON8B_AOBUS_SIZE)
     96 #define MESON8B_SRAM_PBASE	0xd9000000
     97 #define MESON8B_SRAM_SIZE	0x00010000	/* 0x10000 rounded up */
     98 
     99 #define MESON8B_SRAM_CPUCONF_OFFSET		0x1ff80
    100 #define MESON8B_SRAM_CPUCONF_CTRL_REG		0x00
    101 #define MESON8B_SRAM_CPUCONF_CPU_ADDR_REG(n)	(0x04 * (n))
    102 
    103 
    104 extern struct arm32_bus_dma_tag arm_generic_dma_tag;
    105 extern struct bus_space arm_generic_bs_tag;
    106 extern struct bus_space arm_generic_a4x_bs_tag;
    107 
    108 #define	meson_dma_tag		arm_generic_dma_tag
    109 #define	meson_bs_tag		arm_generic_bs_tag
    110 #define	meson_a4x_bs_tag	arm_generic_a4x_bs_tag
    111 
    112 static const struct pmap_devmap *
    113 meson_platform_devmap(void)
    114 {
    115 	static const struct pmap_devmap devmap[] = {
    116 		DEVMAP_ENTRY(MESON_CORE_APB3_VBASE,
    117 			     MESON_CORE_APB3_PBASE,
    118 			     MESON_CORE_APB3_SIZE),
    119 		DEVMAP_ENTRY(MESON8B_ARM_VBASE,
    120 			     MESON8B_ARM_PBASE,
    121 			     MESON8B_ARM_SIZE),
    122 		DEVMAP_ENTRY(MESON8B_AOBUS_VBASE,
    123 			     MESON8B_AOBUS_PBASE,
    124 			     MESON8B_AOBUS_SIZE),
    125 		DEVMAP_ENTRY(MESON8B_SRAM_VBASE,
    126 			     MESON8B_SRAM_PBASE,
    127 			     MESON8B_SRAM_SIZE),
    128 		DEVMAP_ENTRY_END
    129 	};
    130 
    131 	return devmap;
    132 }
    133 
    134 static void
    135 meson_platform_init_attach_args(struct fdt_attach_args *faa)
    136 {
    137 	faa->faa_bst = &meson_bs_tag;
    138 	faa->faa_a4x_bst = &meson_a4x_bs_tag;
    139 	faa->faa_dmat = &meson_dma_tag;
    140 }
    141 
    142 void meson_platform_early_putchar(char);
    143 
    144 void
    145 meson_platform_early_putchar(char c)
    146 {
    147 #ifdef CONSADDR
    148 #define CONSADDR_VA	((CONSADDR - MESON8B_AOBUS_PBASE) + MESON8B_AOBUS_VBASE)
    149 	volatile uint32_t *uartaddr = cpu_earlydevice_va_p() ?
    150 	    (volatile uint32_t *)CONSADDR_VA :
    151 	    (volatile uint32_t *)CONSADDR;
    152 	int timo = 150000;
    153 
    154 	while ((uartaddr[UART_STATUS_REG/4] & UART_STATUS_TX_EMPTY) == 0) {
    155 		if (--timo == 0)
    156 			break;
    157 	}
    158 
    159 	uartaddr[UART_WFIFO_REG/4] = c;
    160 
    161 	while ((uartaddr[UART_STATUS_REG/4] & UART_STATUS_TX_EMPTY) == 0) {
    162 		if (--timo == 0)
    163 			break;
    164 	}
    165 #endif
    166 }
    167 
    168 static void
    169 meson_platform_device_register(device_t self, void *aux)
    170 {
    171 }
    172 
    173 static u_int
    174 meson_platform_uart_freq(void)
    175 {
    176 	return 0;
    177 }
    178 
    179 static void
    180 meson_platform_bootstrap(void)
    181 {
    182 	arm_fdt_cpu_bootstrap();
    183 
    184 	void *fdt_data = __UNCONST(fdtbus_get_data());
    185 	const int chosen_off = fdt_path_offset(fdt_data, "/chosen");
    186 	if (chosen_off < 0)
    187 		return;
    188 
    189 	if (match_bootconf_option(boot_args, "console", "fb")) {
    190 		const int framebuffer_off =
    191 		    fdt_path_offset(fdt_data, "/chosen/framebuffer");
    192 		if (framebuffer_off >= 0) {
    193 			const char *status = fdt_getprop(fdt_data,
    194 			    framebuffer_off, "status", NULL);
    195 			if (status == NULL || strncmp(status, "ok", 2) == 0) {
    196 				fdt_setprop_string(fdt_data, chosen_off,
    197 				    "stdout-path", "/chosen/framebuffer");
    198 			}
    199 		}
    200 	} else if (match_bootconf_option(boot_args, "console", "serial")) {
    201 		fdt_setprop_string(fdt_data, chosen_off,
    202 		    "stdout-path", "serial0:115200n8");
    203 	}
    204 }
    205 
    206 #if defined(SOC_MESON8B)
    207 static void
    208 meson8b_platform_bootstrap(void)
    209 {
    210 
    211 #if NARML2CC > 0
    212 	const bus_space_handle_t pl310_bh = MESON8B_ARM_VBASE + MESON8B_ARM_PL310_BASE;
    213 	arml2cc_init(&arm_generic_bs_tag, pl310_bh, 0);
    214 #endif
    215 
    216 	meson_platform_bootstrap();
    217 }
    218 #endif
    219 
    220 static void
    221 meson_platform_reset(void)
    222 {
    223 	bus_space_tag_t bst = &meson_bs_tag;
    224 	bus_space_handle_t bsh;
    225 
    226 	bus_space_map(bst, MESON_WATCHDOG_BASE, MESON_WATCHDOG_SIZE, 0, &bsh);
    227 
    228 	bus_space_write_4(bst, bsh, MESON_WATCHDOG_TC,
    229 	    WATCHDOG_TC_CPUS | WATCHDOG_TC_ENABLE | __SHIFTIN(0xfff, WATCHDOG_TC_TCNT));
    230 	bus_space_write_4(bst, bsh, MESON_WATCHDOG_RESET, 0);
    231 
    232 	for (;;) {
    233 		__asm("wfi");
    234 	}
    235 }
    236 
    237 #if defined(MULTIPROCESSOR)
    238 static void
    239 meson8b_mpinit_delay(u_int n)
    240 {
    241 	for (volatile int i = 0; i < n; i++)
    242 		;
    243 }
    244 
    245 static int
    246 cpu_enable_meson8b(int phandle)
    247 {
    248 	const bus_addr_t cbar = armreg_cbar_read();
    249 	bus_space_tag_t bst = &arm_generic_bs_tag;
    250 
    251 	const bus_space_handle_t scu_bsh =
    252 	    cbar - MESON8B_ARM_PBASE + MESON8B_ARM_VBASE;
    253 	const bus_space_handle_t cpuconf_bsh =
    254 	    MESON8B_SRAM_VBASE + MESON8B_SRAM_CPUCONF_OFFSET;
    255 	const bus_space_handle_t ao_bsh =
    256 	    MESON8B_AOBUS_VBASE;
    257 	const bus_space_handle_t cbus_bsh =
    258 	    MESON_CORE_APB3_VBASE + MESON_CBUS_OFFSET;
    259 	uint32_t pwr_sts, pwr_cntl0, pwr_cntl1, cpuclk, mempd0;
    260 	uint64_t mpidr;
    261 
    262 	fdtbus_get_reg64(phandle, 0, &mpidr, NULL);
    263 
    264 	const u_int cpuno = __SHIFTOUT(mpidr, MPIDR_AFF0);
    265 
    266 	bus_space_write_4(bst, cpuconf_bsh, MESON8B_SRAM_CPUCONF_CPU_ADDR_REG(cpuno),
    267 	    KERN_VTOPHYS((vaddr_t)cpu_mpstart));
    268 
    269 	pwr_sts = bus_space_read_4(bst, scu_bsh, SCU_CPU_PWR_STS);
    270 	pwr_sts &= ~(3 << (8 * cpuno));
    271 	bus_space_write_4(bst, scu_bsh, SCU_CPU_PWR_STS, pwr_sts);
    272 
    273 	pwr_cntl0 = bus_space_read_4(bst, ao_bsh, MESON_AOBUS_PWR_CTRL0_REG);
    274 	pwr_cntl0 &= ~((3 << 18) << ((cpuno - 1) * 2));
    275 	bus_space_write_4(bst, ao_bsh, MESON_AOBUS_PWR_CTRL0_REG, pwr_cntl0);
    276 
    277 	meson8b_mpinit_delay(5000);
    278 
    279 	cpuclk = bus_space_read_4(bst, cbus_bsh, MESON_CBUS_CPU_CLK_CNTL_REG);
    280 	cpuclk |= (1 << (24 + cpuno));
    281 	bus_space_write_4(bst, cbus_bsh, MESON_CBUS_CPU_CLK_CNTL_REG, cpuclk);
    282 
    283 	mempd0 = bus_space_read_4(bst, ao_bsh, MESON_AOBUS_PWR_MEM_PD0_REG);
    284 	mempd0 &= ~((uint32_t)(0xf << 28) >> ((cpuno - 1) * 4));
    285 	bus_space_write_4(bst, ao_bsh, MESON_AOBUS_PWR_MEM_PD0_REG, mempd0);
    286 
    287 	pwr_cntl1 = bus_space_read_4(bst, ao_bsh, MESON_AOBUS_PWR_CTRL1_REG);
    288 	pwr_cntl1 &= ~((3 << 4) << ((cpuno - 1) * 2));
    289 	bus_space_write_4(bst, ao_bsh, MESON_AOBUS_PWR_CTRL1_REG, pwr_cntl1);
    290 
    291 	meson8b_mpinit_delay(10000);
    292 
    293 	for (;;) {
    294 		pwr_cntl1 = bus_space_read_4(bst, ao_bsh,
    295 		    MESON_AOBUS_PWR_CTRL1_REG) & ((1 << 17) << (cpuno - 1));
    296 		if (pwr_cntl1)
    297 			break;
    298 		meson8b_mpinit_delay(10000);
    299 	}
    300 
    301 	pwr_cntl0 = bus_space_read_4(bst, ao_bsh, MESON_AOBUS_PWR_CTRL0_REG);
    302 	pwr_cntl0 &= ~(1 << cpuno);
    303 	bus_space_write_4(bst, ao_bsh, MESON_AOBUS_PWR_CTRL0_REG, pwr_cntl0);
    304 
    305 	cpuclk = bus_space_read_4(bst, cbus_bsh, MESON_CBUS_CPU_CLK_CNTL_REG);
    306 	cpuclk &= ~(1 << (24 + cpuno));
    307 	bus_space_write_4(bst, cbus_bsh, MESON_CBUS_CPU_CLK_CNTL_REG, cpuclk);
    308 
    309 	bus_space_write_4(bst, cpuconf_bsh, MESON8B_SRAM_CPUCONF_CPU_ADDR_REG(cpuno),
    310 	    KERN_VTOPHYS((vaddr_t)cpu_mpstart));
    311 
    312 	uint32_t ctrl = bus_space_read_4(bst, cpuconf_bsh, MESON8B_SRAM_CPUCONF_CTRL_REG);
    313 	ctrl |= __BITS(cpuno,0);
    314 	bus_space_write_4(bst, cpuconf_bsh, MESON8B_SRAM_CPUCONF_CTRL_REG, ctrl);
    315 
    316 	return 0;
    317 }
    318 
    319 ARM_CPU_METHOD(meson8b, "amlogic,meson8b-smp", cpu_enable_meson8b);
    320 #endif
    321 
    322 static void
    323 meson_mpstart(void)
    324 {
    325 #ifdef MULTIPROCESSOR
    326 	const bus_addr_t cbar = armreg_cbar_read();
    327 	bus_space_tag_t bst = &arm_generic_bs_tag;
    328 
    329 	if (cbar == 0)
    330 		return;
    331 
    332 	const bus_space_handle_t scu_bsh =
    333 	    cbar - MESON8B_ARM_PBASE + MESON8B_ARM_VBASE;
    334 
    335 	const uint32_t scu_cfg = bus_space_read_4(bst, scu_bsh, SCU_CFG);
    336 	const u_int ncpus = (scu_cfg & SCU_CFG_CPUMAX) + 1;
    337 
    338 	if (ncpus < 2)
    339 		return;
    340 
    341 	/*
    342 	 * Invalidate all SCU cache tags. That is, for all cores (0-3)
    343 	 */
    344 	bus_space_write_4(bst, scu_bsh, SCU_INV_ALL_REG, 0xffff);
    345 
    346 	uint32_t scu_ctl = bus_space_read_4(bst, scu_bsh, SCU_CTL);
    347 	scu_ctl |= SCU_CTL_SCU_ENA;
    348 	bus_space_write_4(bst, scu_bsh, SCU_CTL, scu_ctl);
    349 
    350 	armv7_dcache_wbinv_all();
    351 
    352 	arm_fdt_cpu_mpstart();
    353 #endif
    354 }
    355 
    356 
    357 #if defined(SOC_MESON8B)
    358 static const struct arm_platform meson8b_platform = {
    359 	.ap_devmap = meson_platform_devmap,
    360 	.ap_bootstrap = meson8b_platform_bootstrap,
    361 	.ap_init_attach_args = meson_platform_init_attach_args,
    362 	.ap_device_register = meson_platform_device_register,
    363 	.ap_reset = meson_platform_reset,
    364 	.ap_delay = a9tmr_delay,
    365 	.ap_uart_freq = meson_platform_uart_freq,
    366 	.ap_mpstart = meson_mpstart,
    367 };
    368 
    369 ARM_PLATFORM(meson8b, "amlogic,meson8b", &meson8b_platform);
    370 #endif
    371