119304Speter/*-
219304Speter * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
319304Speter * All rights reserved.
419304Speter *
519304Speter * Redistribution and use in source and binary forms, with or without
619304Speter * modification, are permitted provided that the following conditions
719304Speter * are met:
819304Speter * 1. Redistributions of source code must retain the above copyright
919304Speter *    notice, this list of conditions and the following disclaimer.
1019304Speter * 2. Redistributions in binary form must reproduce the above copyright
11254225Speter *    notice, this list of conditions and the following disclaimer in the
1219304Speter *    documentation and/or other materials provided with the distribution.
1319304Speter *
1419304Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1519304Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1619304Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1719304Speter * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1819304Speter * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19254225Speter * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2019304Speter * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21254225Speter * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22254225Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23254225Speter * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24254225Speter */
2519304Speter
2619304Speter#include <sys/cdefs.h>
2719304Speter__FBSDID("$FreeBSD: stable/11/sys/arm/nvidia/tegra124/tegra124_mp.c 307344 2016-10-15 08:27:54Z mmel $");
2819304Speter
2919304Speter#include <sys/param.h>
3019304Speter#include <sys/systm.h>
3119304Speter#include <sys/bus.h>
3219304Speter#include <sys/kernel.h>
3319304Speter#include <sys/lock.h>
3419304Speter#include <sys/mutex.h>
3519304Speter#include <sys/smp.h>
3619304Speter
3719304Speter#include <vm/vm.h>
3819304Speter#include <vm/pmap.h>
3919304Speter
4019304Speter#include <machine/cpu.h>
4119304Speter#include <machine/intr.h>
4219304Speter#include <machine/fdt.h>
4319304Speter#include <machine/smp.h>
4419304Speter#include <machine/platformvar.h>
4519304Speter#include <machine/pmap.h>
4619304Speter
4719304Speter#include <arm/nvidia/tegra124/tegra124_mp.h>
4819304Speter
4919304Speter#define	PMC_PHYSBASE			0x7000e400
5019304Speter#define	PMC_SIZE			0x400
5119304Speter#define	PMC_CONTROL_REG			0x0
5219304Speter#define	PMC_PWRGATE_TOGGLE		0x30
5319304Speter#define	 PCM_PWRGATE_TOGGLE_START	(1 << 8)
5419304Speter#define	PMC_PWRGATE_STATUS		0x38
5519304Speter
5619304Speter#define	TEGRA_EXCEPTION_VECTORS_BASE	0x6000F000 /* exception vectors */
5719304Speter#define	TEGRA_EXCEPTION_VECTORS_SIZE	1024
5819304Speter#define	 TEGRA_EXCEPTION_VECTOR_ENTRY	0x100
5919304Speter
6019304Spetervoid
6119304Spetertegra124_mp_setmaxid(platform_t plat)
6219304Speter{
6319304Speter	int ncpu;
6419304Speter
6519304Speter	/* If we've already set the global vars don't bother to do it again. */
6619304Speter	if (mp_ncpus != 0)
6719304Speter		return;
6819304Speter
6919304Speter	/* Read current CP15 Cache Size ID Register */
7019304Speter	ncpu = cp15_l2ctlr_get();
7119304Speter	ncpu = CPUV7_L2CTLR_NPROC(ncpu);
7219304Speter
7319304Speter	mp_ncpus = ncpu;
7419304Speter	mp_maxid = ncpu - 1;
7519304Speter}
7619304Speter
77254225Spetervoid
7819304Spetertegra124_mp_start_ap(platform_t plat)
7919304Speter{
8019304Speter	bus_space_handle_t pmc;
8119304Speter	bus_space_handle_t exvec;
8219304Speter	int i;
8319304Speter	uint32_t val;
8419304Speter	uint32_t mask;
8519304Speter
8619304Speter	if (bus_space_map(fdtbus_bs_tag, PMC_PHYSBASE, PMC_SIZE, 0, &pmc) != 0)
87254225Speter		panic("Couldn't map the PMC\n");
8819304Speter	if (bus_space_map(fdtbus_bs_tag, TEGRA_EXCEPTION_VECTORS_BASE,
89254225Speter	    TEGRA_EXCEPTION_VECTORS_SIZE, 0, &exvec) != 0)
90254225Speter		panic("Couldn't map the exception vectors\n");
9119304Speter
92254225Speter	bus_space_write_4(fdtbus_bs_tag, exvec , TEGRA_EXCEPTION_VECTOR_ENTRY,
9319304Speter			  pmap_kextract((vm_offset_t)mpentry));
9419304Speter	bus_space_read_4(fdtbus_bs_tag, exvec , TEGRA_EXCEPTION_VECTOR_ENTRY);
9519304Speter
96254225Speter
9719304Speter	/* Wait until POWERGATE is ready (max 20 APB cycles). */
98254225Speter	do {
9919304Speter		val = bus_space_read_4(fdtbus_bs_tag, pmc,
10019304Speter		    PMC_PWRGATE_TOGGLE);
10119304Speter	} while ((val & PCM_PWRGATE_TOGGLE_START) != 0);
10219304Speter
10319304Speter	for (i = 1; i < mp_ncpus; i++) {
10419304Speter		val = bus_space_read_4(fdtbus_bs_tag, pmc, PMC_PWRGATE_STATUS);
10519304Speter		mask = 1 << (i + 8);	/* cpu mask */
10619304Speter		if ((val & mask) == 0) {
10719304Speter			/* Wait until POWERGATE is ready (max 20 APB cycles). */
10819304Speter			do {
10919304Speter				val = bus_space_read_4(fdtbus_bs_tag, pmc,
110				PMC_PWRGATE_TOGGLE);
111			} while ((val & PCM_PWRGATE_TOGGLE_START) != 0);
112			bus_space_write_4(fdtbus_bs_tag, pmc,
113			    PMC_PWRGATE_TOGGLE,
114			    PCM_PWRGATE_TOGGLE_START | (8 + i));
115
116			/* Wait until CPU is powered */
117			do {
118				val = bus_space_read_4(fdtbus_bs_tag, pmc,
119				    PMC_PWRGATE_STATUS);
120			} while ((val & mask) == 0);
121		}
122
123	}
124	dsb();
125	sev();
126	bus_space_unmap(fdtbus_bs_tag, pmc, PMC_SIZE);
127	bus_space_unmap(fdtbus_bs_tag, exvec, TEGRA_EXCEPTION_VECTORS_SIZE);
128}
129