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

reset-microchip-sparx5.c (4323B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/* Microchip Sparx5 Switch Reset driver
      3 *
      4 * Copyright (c) 2020 Microchip Technology Inc. and its subsidiaries.
      5 *
      6 * The Sparx5 Chip Register Model can be browsed at this location:
      7 * https://github.com/microchip-ung/sparx-5_reginfo
      8 */
      9#include <linux/mfd/syscon.h>
     10#include <linux/of_device.h>
     11#include <linux/module.h>
     12#include <linux/platform_device.h>
     13#include <linux/regmap.h>
     14#include <linux/reset-controller.h>
     15
     16struct reset_props {
     17	u32 protect_reg;
     18	u32 protect_bit;
     19	u32 reset_reg;
     20	u32 reset_bit;
     21};
     22
     23struct mchp_reset_context {
     24	struct regmap *cpu_ctrl;
     25	struct regmap *gcb_ctrl;
     26	struct reset_controller_dev rcdev;
     27	const struct reset_props *props;
     28};
     29
     30static struct regmap_config sparx5_reset_regmap_config = {
     31	.reg_bits	= 32,
     32	.val_bits	= 32,
     33	.reg_stride	= 4,
     34};
     35
     36static int sparx5_switch_reset(struct reset_controller_dev *rcdev,
     37			       unsigned long id)
     38{
     39	struct mchp_reset_context *ctx =
     40		container_of(rcdev, struct mchp_reset_context, rcdev);
     41	u32 val;
     42
     43	/* Make sure the core is PROTECTED from reset */
     44	regmap_update_bits(ctx->cpu_ctrl, ctx->props->protect_reg,
     45			   ctx->props->protect_bit, ctx->props->protect_bit);
     46
     47	/* Start soft reset */
     48	regmap_write(ctx->gcb_ctrl, ctx->props->reset_reg,
     49		     ctx->props->reset_bit);
     50
     51	/* Wait for soft reset done */
     52	return regmap_read_poll_timeout(ctx->gcb_ctrl, ctx->props->reset_reg, val,
     53					(val & ctx->props->reset_bit) == 0,
     54					1, 100);
     55}
     56
     57static const struct reset_control_ops sparx5_reset_ops = {
     58	.reset = sparx5_switch_reset,
     59};
     60
     61static int mchp_sparx5_map_syscon(struct platform_device *pdev, char *name,
     62				  struct regmap **target)
     63{
     64	struct device_node *syscon_np;
     65	struct regmap *regmap;
     66	int err;
     67
     68	syscon_np = of_parse_phandle(pdev->dev.of_node, name, 0);
     69	if (!syscon_np)
     70		return -ENODEV;
     71	regmap = syscon_node_to_regmap(syscon_np);
     72	of_node_put(syscon_np);
     73	if (IS_ERR(regmap)) {
     74		err = PTR_ERR(regmap);
     75		dev_err(&pdev->dev, "No '%s' map: %d\n", name, err);
     76		return err;
     77	}
     78	*target = regmap;
     79	return 0;
     80}
     81
     82static int mchp_sparx5_map_io(struct platform_device *pdev, int index,
     83			      struct regmap **target)
     84{
     85	struct resource *res;
     86	struct regmap *map;
     87	void __iomem *mem;
     88
     89	mem = devm_platform_get_and_ioremap_resource(pdev, index, &res);
     90	if (IS_ERR(mem)) {
     91		dev_err(&pdev->dev, "Could not map resource %d\n", index);
     92		return PTR_ERR(mem);
     93	}
     94	sparx5_reset_regmap_config.name = res->name;
     95	map = devm_regmap_init_mmio(&pdev->dev, mem, &sparx5_reset_regmap_config);
     96	if (IS_ERR(map))
     97		return PTR_ERR(map);
     98	*target = map;
     99	return 0;
    100}
    101
    102static int mchp_sparx5_reset_probe(struct platform_device *pdev)
    103{
    104	struct device_node *dn = pdev->dev.of_node;
    105	struct mchp_reset_context *ctx;
    106	int err;
    107
    108	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
    109	if (!ctx)
    110		return -ENOMEM;
    111
    112	err = mchp_sparx5_map_syscon(pdev, "cpu-syscon", &ctx->cpu_ctrl);
    113	if (err)
    114		return err;
    115	err = mchp_sparx5_map_io(pdev, 0, &ctx->gcb_ctrl);
    116	if (err)
    117		return err;
    118
    119	ctx->rcdev.owner = THIS_MODULE;
    120	ctx->rcdev.nr_resets = 1;
    121	ctx->rcdev.ops = &sparx5_reset_ops;
    122	ctx->rcdev.of_node = dn;
    123	ctx->props = device_get_match_data(&pdev->dev);
    124
    125	return devm_reset_controller_register(&pdev->dev, &ctx->rcdev);
    126}
    127
    128static const struct reset_props reset_props_sparx5 = {
    129	.protect_reg    = 0x84,
    130	.protect_bit    = BIT(10),
    131	.reset_reg      = 0x0,
    132	.reset_bit      = BIT(1),
    133};
    134
    135static const struct reset_props reset_props_lan966x = {
    136	.protect_reg    = 0x88,
    137	.protect_bit    = BIT(5),
    138	.reset_reg      = 0x0,
    139	.reset_bit      = BIT(1),
    140};
    141
    142static const struct of_device_id mchp_sparx5_reset_of_match[] = {
    143	{
    144		.compatible = "microchip,sparx5-switch-reset",
    145		.data = &reset_props_sparx5,
    146	}, {
    147		.compatible = "microchip,lan966x-switch-reset",
    148		.data = &reset_props_lan966x,
    149	},
    150	{ }
    151};
    152
    153static struct platform_driver mchp_sparx5_reset_driver = {
    154	.probe = mchp_sparx5_reset_probe,
    155	.driver = {
    156		.name = "sparx5-switch-reset",
    157		.of_match_table = mchp_sparx5_reset_of_match,
    158	},
    159};
    160
    161static int __init mchp_sparx5_reset_init(void)
    162{
    163	return platform_driver_register(&mchp_sparx5_reset_driver);
    164}
    165
    166postcore_initcall(mchp_sparx5_reset_init);
    167
    168MODULE_DESCRIPTION("Microchip Sparx5 switch reset driver");
    169MODULE_AUTHOR("Steen Hegelund <steen.hegelund@microchip.com>");
    170MODULE_LICENSE("Dual MIT/GPL");