cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

bcm63xx_pmb.c (4958B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Broadcom BCM63138 PMB initialization for secondary CPU(s)
      4 *
      5 * Copyright (C) 2015 Broadcom Corporation
      6 * Author: Florian Fainelli <f.fainelli@gmail.com>
      7 */
      8#include <linux/kernel.h>
      9#include <linux/io.h>
     10#include <linux/spinlock.h>
     11#include <linux/reset/bcm63xx_pmb.h>
     12#include <linux/of.h>
     13#include <linux/of_address.h>
     14
     15#include "bcm63xx_smp.h"
     16
     17/* ARM Control register definitions */
     18#define CORE_PWR_CTRL_SHIFT	0
     19#define CORE_PWR_CTRL_MASK	0x3
     20#define PLL_PWR_ON		BIT(8)
     21#define PLL_LDO_PWR_ON		BIT(9)
     22#define PLL_CLAMP_ON		BIT(10)
     23#define CPU_RESET_N(x)		BIT(13 + (x))
     24#define NEON_RESET_N		BIT(15)
     25#define PWR_CTRL_STATUS_SHIFT	28
     26#define PWR_CTRL_STATUS_MASK	0x3
     27#define PWR_DOWN_SHIFT		30
     28#define PWR_DOWN_MASK		0x3
     29
     30/* CPU Power control register definitions */
     31#define MEM_PWR_OK		BIT(0)
     32#define MEM_PWR_ON		BIT(1)
     33#define MEM_CLAMP_ON		BIT(2)
     34#define MEM_PWR_OK_STATUS	BIT(4)
     35#define MEM_PWR_ON_STATUS	BIT(5)
     36#define MEM_PDA_SHIFT		8
     37#define MEM_PDA_MASK		0xf
     38#define  MEM_PDA_CPU_MASK	0x1
     39#define  MEM_PDA_NEON_MASK	0xf
     40#define CLAMP_ON		BIT(15)
     41#define PWR_OK_SHIFT		16
     42#define PWR_OK_MASK		0xf
     43#define PWR_ON_SHIFT		20
     44#define  PWR_CPU_MASK		0x03
     45#define  PWR_NEON_MASK		0x01
     46#define PWR_ON_MASK		0xf
     47#define PWR_OK_STATUS_SHIFT	24
     48#define PWR_OK_STATUS_MASK	0xf
     49#define PWR_ON_STATUS_SHIFT	28
     50#define PWR_ON_STATUS_MASK	0xf
     51
     52#define ARM_CONTROL		0x30
     53#define ARM_PWR_CONTROL_BASE	0x34
     54#define ARM_PWR_CONTROL(x)	(ARM_PWR_CONTROL_BASE + (x) * 0x4)
     55#define ARM_NEON_L2		0x3c
     56
     57/* Perform a value write, then spin until the value shifted by
     58 * shift is seen, masked with mask and is different from cond.
     59 */
     60static int bpcm_wr_rd_mask(void __iomem *master,
     61			   unsigned int addr, u32 off, u32 *val,
     62			   u32 shift, u32 mask, u32 cond)
     63{
     64	int ret;
     65
     66	ret = bpcm_wr(master, addr, off, *val);
     67	if (ret)
     68		return ret;
     69
     70	do {
     71		ret = bpcm_rd(master, addr, off, val);
     72		if (ret)
     73			return ret;
     74
     75		cpu_relax();
     76	} while (((*val >> shift) & mask) != cond);
     77
     78	return ret;
     79}
     80
     81/* Global lock to serialize accesses to the PMB registers while we
     82 * are bringing up the secondary CPU
     83 */
     84static DEFINE_SPINLOCK(pmb_lock);
     85
     86static int bcm63xx_pmb_get_resources(struct device_node *dn,
     87				     void __iomem **base,
     88				     unsigned int *cpu,
     89				     unsigned int *addr)
     90{
     91	struct of_phandle_args args;
     92	int ret;
     93
     94	*cpu = of_get_cpu_hwid(dn, 0);
     95	if (*cpu == ~0U) {
     96		pr_err("CPU is missing a reg node\n");
     97		return -ENODEV;
     98	}
     99
    100	ret = of_parse_phandle_with_args(dn, "resets", "#reset-cells",
    101					 0, &args);
    102	if (ret) {
    103		pr_err("CPU is missing a resets phandle\n");
    104		return ret;
    105	}
    106
    107	if (args.args_count != 2) {
    108		pr_err("reset-controller does not conform to reset-cells\n");
    109		return -EINVAL;
    110	}
    111
    112	*base = of_iomap(args.np, 0);
    113	if (!*base) {
    114		pr_err("failed remapping PMB register\n");
    115		return -ENOMEM;
    116	}
    117
    118	/* We do not need the number of zones */
    119	*addr = args.args[0];
    120
    121	return 0;
    122}
    123
    124int bcm63xx_pmb_power_on_cpu(struct device_node *dn)
    125{
    126	void __iomem *base;
    127	unsigned int cpu, addr;
    128	unsigned long flags;
    129	u32 val, ctrl;
    130	int ret;
    131
    132	ret = bcm63xx_pmb_get_resources(dn, &base, &cpu, &addr);
    133	if (ret)
    134		return ret;
    135
    136	/* We would not know how to enable a third and greater CPU */
    137	WARN_ON(cpu > 1);
    138
    139	spin_lock_irqsave(&pmb_lock, flags);
    140
    141	/* Check if the CPU is already on and save the ARM_CONTROL register
    142	 * value since we will use it later for CPU de-assert once done with
    143	 * the CPU-specific power sequence
    144	 */
    145	ret = bpcm_rd(base, addr, ARM_CONTROL, &ctrl);
    146	if (ret)
    147		goto out;
    148
    149	if (ctrl & CPU_RESET_N(cpu)) {
    150		pr_info("PMB: CPU%d is already powered on\n", cpu);
    151		ret = 0;
    152		goto out;
    153	}
    154
    155	/* Power on PLL */
    156	ret = bpcm_rd(base, addr, ARM_PWR_CONTROL(cpu), &val);
    157	if (ret)
    158		goto out;
    159
    160	val |= (PWR_CPU_MASK << PWR_ON_SHIFT);
    161
    162	ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val,
    163			PWR_ON_STATUS_SHIFT, PWR_CPU_MASK, PWR_CPU_MASK);
    164	if (ret)
    165		goto out;
    166
    167	val |= (PWR_CPU_MASK << PWR_OK_SHIFT);
    168
    169	ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val,
    170			PWR_OK_STATUS_SHIFT, PWR_CPU_MASK, PWR_CPU_MASK);
    171	if (ret)
    172		goto out;
    173
    174	val &= ~CLAMP_ON;
    175
    176	ret = bpcm_wr(base, addr, ARM_PWR_CONTROL(cpu), val);
    177	if (ret)
    178		goto out;
    179
    180	/* Power on CPU<N> RAM */
    181	val &= ~(MEM_PDA_MASK << MEM_PDA_SHIFT);
    182
    183	ret = bpcm_wr(base, addr, ARM_PWR_CONTROL(cpu), val);
    184	if (ret)
    185		goto out;
    186
    187	val |= MEM_PWR_ON;
    188
    189	ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val,
    190			0, MEM_PWR_ON_STATUS, MEM_PWR_ON_STATUS);
    191	if (ret)
    192		goto out;
    193
    194	val |= MEM_PWR_OK;
    195
    196	ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val,
    197			0, MEM_PWR_OK_STATUS, MEM_PWR_OK_STATUS);
    198	if (ret)
    199		goto out;
    200
    201	val &= ~MEM_CLAMP_ON;
    202
    203	ret = bpcm_wr(base, addr, ARM_PWR_CONTROL(cpu), val);
    204	if (ret)
    205		goto out;
    206
    207	/* De-assert CPU reset */
    208	ctrl |= CPU_RESET_N(cpu);
    209
    210	ret = bpcm_wr(base, addr, ARM_CONTROL, ctrl);
    211out:
    212	spin_unlock_irqrestore(&pmb_lock, flags);
    213	iounmap(base);
    214	return ret;
    215}