brintos

brintos / linux-shallow public Read only

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