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

physmap-versatile.c (5775B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Versatile OF physmap driver add-on
      4 *
      5 * Copyright (c) 2016, Linaro Limited
      6 * Author: Linus Walleij <linus.walleij@linaro.org>
      7 */
      8#include <linux/export.h>
      9#include <linux/io.h>
     10#include <linux/of.h>
     11#include <linux/of_address.h>
     12#include <linux/of_device.h>
     13#include <linux/mtd/map.h>
     14#include <linux/mfd/syscon.h>
     15#include <linux/regmap.h>
     16#include <linux/bitops.h>
     17#include "physmap-versatile.h"
     18
     19static struct regmap *syscon_regmap;
     20
     21enum versatile_flashprot {
     22	INTEGRATOR_AP_FLASHPROT,
     23	INTEGRATOR_CP_FLASHPROT,
     24	VERSATILE_FLASHPROT,
     25	REALVIEW_FLASHPROT,
     26};
     27
     28static const struct of_device_id syscon_match[] = {
     29	{
     30		.compatible = "arm,integrator-ap-syscon",
     31		.data = (void *)INTEGRATOR_AP_FLASHPROT,
     32	},
     33	{
     34		.compatible = "arm,integrator-cp-syscon",
     35		.data = (void *)INTEGRATOR_CP_FLASHPROT,
     36	},
     37	{
     38		.compatible = "arm,core-module-versatile",
     39		.data = (void *)VERSATILE_FLASHPROT,
     40	},
     41	{
     42		.compatible = "arm,realview-eb-syscon",
     43		.data = (void *)REALVIEW_FLASHPROT,
     44	},
     45	{
     46		.compatible = "arm,realview-pb1176-syscon",
     47		.data = (void *)REALVIEW_FLASHPROT,
     48	},
     49	{
     50		.compatible = "arm,realview-pb11mp-syscon",
     51		.data = (void *)REALVIEW_FLASHPROT,
     52	},
     53	{
     54		.compatible = "arm,realview-pba8-syscon",
     55		.data = (void *)REALVIEW_FLASHPROT,
     56	},
     57	{
     58		.compatible = "arm,realview-pbx-syscon",
     59		.data = (void *)REALVIEW_FLASHPROT,
     60	},
     61	{},
     62};
     63
     64/*
     65 * Flash protection handling for the Integrator/AP
     66 */
     67#define INTEGRATOR_SC_CTRLS_OFFSET	0x08
     68#define INTEGRATOR_SC_CTRLC_OFFSET	0x0C
     69#define INTEGRATOR_SC_CTRL_FLVPPEN	BIT(1)
     70#define INTEGRATOR_SC_CTRL_FLWP		BIT(2)
     71
     72#define INTEGRATOR_EBI_CSR1_OFFSET	0x04
     73/* The manual says bit 2, the code says bit 3, trust the code */
     74#define INTEGRATOR_EBI_WRITE_ENABLE	BIT(3)
     75#define INTEGRATOR_EBI_LOCK_OFFSET	0x20
     76#define INTEGRATOR_EBI_LOCK_VAL		0xA05F
     77
     78static const struct of_device_id ebi_match[] = {
     79	{ .compatible = "arm,external-bus-interface"},
     80	{ },
     81};
     82
     83static int ap_flash_init(struct platform_device *pdev)
     84{
     85	struct device_node *ebi;
     86	void __iomem *ebi_base;
     87	u32 val;
     88	int ret;
     89
     90	/* Look up the EBI */
     91	ebi = of_find_matching_node(NULL, ebi_match);
     92	if (!ebi) {
     93		return -ENODEV;
     94	}
     95	ebi_base = of_iomap(ebi, 0);
     96	if (!ebi_base)
     97		return -ENODEV;
     98
     99	/* Clear VPP and write protection bits */
    100	ret = regmap_write(syscon_regmap,
    101		INTEGRATOR_SC_CTRLC_OFFSET,
    102		INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
    103	if (ret)
    104		dev_err(&pdev->dev, "error clearing Integrator VPP/WP\n");
    105
    106	/* Unlock the EBI */
    107	writel(INTEGRATOR_EBI_LOCK_VAL, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
    108
    109	/* Enable write cycles on the EBI, CSR1 (flash) */
    110	val = readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);
    111	val |= INTEGRATOR_EBI_WRITE_ENABLE;
    112	writel(val, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);
    113
    114	/* Lock the EBI again */
    115	writel(0, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
    116	iounmap(ebi_base);
    117
    118	return 0;
    119}
    120
    121static void ap_flash_set_vpp(struct map_info *map, int on)
    122{
    123	int ret;
    124
    125	if (on) {
    126		ret = regmap_write(syscon_regmap,
    127			INTEGRATOR_SC_CTRLS_OFFSET,
    128			INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
    129		if (ret)
    130			pr_err("error enabling AP VPP\n");
    131	} else {
    132		ret = regmap_write(syscon_regmap,
    133			INTEGRATOR_SC_CTRLC_OFFSET,
    134			INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
    135		if (ret)
    136			pr_err("error disabling AP VPP\n");
    137	}
    138}
    139
    140/*
    141 * Flash protection handling for the Integrator/CP
    142 */
    143
    144#define INTCP_FLASHPROG_OFFSET		0x04
    145#define CINTEGRATOR_FLVPPEN		BIT(0)
    146#define CINTEGRATOR_FLWREN		BIT(1)
    147#define CINTEGRATOR_FLMASK		BIT(0)|BIT(1)
    148
    149static void cp_flash_set_vpp(struct map_info *map, int on)
    150{
    151	int ret;
    152
    153	if (on) {
    154		ret = regmap_update_bits(syscon_regmap,
    155				INTCP_FLASHPROG_OFFSET,
    156				CINTEGRATOR_FLMASK,
    157				CINTEGRATOR_FLVPPEN | CINTEGRATOR_FLWREN);
    158		if (ret)
    159			pr_err("error setting CP VPP\n");
    160	} else {
    161		ret = regmap_update_bits(syscon_regmap,
    162				INTCP_FLASHPROG_OFFSET,
    163				CINTEGRATOR_FLMASK,
    164				0);
    165		if (ret)
    166			pr_err("error setting CP VPP\n");
    167	}
    168}
    169
    170/*
    171 * Flash protection handling for the Versatiles and RealViews
    172 */
    173
    174#define VERSATILE_SYS_FLASH_OFFSET            0x4C
    175
    176static void versatile_flash_set_vpp(struct map_info *map, int on)
    177{
    178	int ret;
    179
    180	ret = regmap_update_bits(syscon_regmap, VERSATILE_SYS_FLASH_OFFSET,
    181				 0x01, !!on);
    182	if (ret)
    183		pr_err("error setting Versatile VPP\n");
    184}
    185
    186int of_flash_probe_versatile(struct platform_device *pdev,
    187			     struct device_node *np,
    188			     struct map_info *map)
    189{
    190	struct device_node *sysnp;
    191	const struct of_device_id *devid;
    192	struct regmap *rmap;
    193	static enum versatile_flashprot versatile_flashprot;
    194	int ret;
    195
    196	/* Not all flash chips use this protection line */
    197	if (!of_device_is_compatible(np, "arm,versatile-flash"))
    198		return 0;
    199
    200	/* For first chip probed, look up the syscon regmap */
    201	if (!syscon_regmap) {
    202		sysnp = of_find_matching_node_and_match(NULL,
    203							syscon_match,
    204							&devid);
    205		if (!sysnp)
    206			return -ENODEV;
    207
    208		versatile_flashprot = (enum versatile_flashprot)devid->data;
    209		rmap = syscon_node_to_regmap(sysnp);
    210		if (IS_ERR(rmap))
    211			return PTR_ERR(rmap);
    212
    213		syscon_regmap = rmap;
    214	}
    215
    216	switch (versatile_flashprot) {
    217	case INTEGRATOR_AP_FLASHPROT:
    218		ret = ap_flash_init(pdev);
    219		if (ret)
    220			return ret;
    221		map->set_vpp = ap_flash_set_vpp;
    222		dev_info(&pdev->dev, "Integrator/AP flash protection\n");
    223		break;
    224	case INTEGRATOR_CP_FLASHPROT:
    225		map->set_vpp = cp_flash_set_vpp;
    226		dev_info(&pdev->dev, "Integrator/CP flash protection\n");
    227		break;
    228	case VERSATILE_FLASHPROT:
    229	case REALVIEW_FLASHPROT:
    230		map->set_vpp = versatile_flash_set_vpp;
    231		dev_info(&pdev->dev, "versatile/realview flash protection\n");
    232		break;
    233	default:
    234		dev_info(&pdev->dev, "device marked as Versatile flash "
    235			 "but no system controller was found\n");
    236		break;
    237	}
    238
    239	return 0;
    240}