@@ -116,7 +116,7 @@ config RESET_LPC18XX
config RESET_MCHP_SPARX5
bool "Microchip Sparx5 reset driver"
- depends on ARCH_SPARX5 || COMPILE_TEST
+ depends on ARCH_SPARX5 || SOC_LAN966 || COMPILE_TEST
default y if SPARX5_SWITCH
select MFD_SYSCON
help
@@ -6,6 +6,7 @@
* The Sparx5 Chip Register Model can be browsed at this location:
* https://github.com/microchip-ung/sparx-5_reginfo
*/
+#include <linux/gpio/consumer.h>
#include <linux/mfd/syscon.h>
#include <linux/of_device.h>
#include <linux/module.h>
@@ -13,15 +14,22 @@
#include <linux/regmap.h>
#include <linux/reset-controller.h>
-#define PROTECT_REG 0x84
-#define PROTECT_BIT BIT(10)
-#define SOFT_RESET_REG 0x00
-#define SOFT_RESET_BIT BIT(1)
+struct reset_props {
+ u32 protect_reg;
+ u32 protect_bit;
+ u32 reset_reg;
+ u32 reset_bit;
+ u32 cuphy_reg;
+ u32 cuphy_bit;
+};
struct mchp_reset_context {
struct regmap *cpu_ctrl;
struct regmap *gcb_ctrl;
+ struct regmap *cuphy_ctrl;
struct reset_controller_dev rcdev;
+ const struct reset_props *props;
+ struct gpio_desc *reset_gpio;
};
static struct regmap_config sparx5_reset_regmap_config = {
@@ -36,17 +44,39 @@ static int sparx5_switch_reset(struct reset_controller_dev *rcdev,
struct mchp_reset_context *ctx =
container_of(rcdev, struct mchp_reset_context, rcdev);
u32 val;
+ int err;
/* Make sure the core is PROTECTED from reset */
- regmap_update_bits(ctx->cpu_ctrl, PROTECT_REG, PROTECT_BIT, PROTECT_BIT);
+ regmap_update_bits(ctx->cpu_ctrl, ctx->props->protect_reg,
+ ctx->props->protect_bit, ctx->props->protect_bit);
/* Start soft reset */
- regmap_write(ctx->gcb_ctrl, SOFT_RESET_REG, SOFT_RESET_BIT);
+ regmap_write(ctx->gcb_ctrl, ctx->props->reset_reg,
+ ctx->props->reset_bit);
/* Wait for soft reset done */
- return regmap_read_poll_timeout(ctx->gcb_ctrl, SOFT_RESET_REG, val,
- (val & SOFT_RESET_BIT) == 0,
+ err = regmap_read_poll_timeout(ctx->gcb_ctrl, ctx->props->reset_reg, val,
+ (val & ctx->props->reset_bit) == 0,
1, 100);
+ if (err)
+ return err;
+
+ if (!ctx->cuphy_ctrl)
+ return 0;
+
+ /* In case there are external PHYs toggle the GPIO to release the reset
+ * of the PHYs
+ */
+ if (ctx->reset_gpio) {
+ gpiod_direction_output(ctx->reset_gpio, 1);
+ gpiod_set_value(ctx->reset_gpio, 0);
+ gpiod_set_value(ctx->reset_gpio, 1);
+ gpiod_set_value(ctx->reset_gpio, 0);
+ }
+
+ /* Release the reset of internal PHY */
+ return regmap_update_bits(ctx->cuphy_ctrl, ctx->props->cuphy_reg,
+ ctx->props->cuphy_bit, ctx->props->cuphy_bit);
}
static const struct reset_control_ops sparx5_reset_ops = {
@@ -111,17 +141,51 @@ static int mchp_sparx5_reset_probe(struct platform_device *pdev)
if (err)
return err;
+ /* This resource is required on lan966x, to take the internal PHYs out
+ * of reset
+ */
+ err = mchp_sparx5_map_syscon(pdev, "cuphy-syscon", &ctx->cuphy_ctrl);
+ if (err && err != -ENODEV)
+ return err;
+
ctx->rcdev.owner = THIS_MODULE;
ctx->rcdev.nr_resets = 1;
ctx->rcdev.ops = &sparx5_reset_ops;
ctx->rcdev.of_node = dn;
+ ctx->props = device_get_match_data(&pdev->dev);
+
+ ctx->reset_gpio = devm_gpiod_get_optional(&pdev->dev, NULL, GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->reset_gpio)) {
+ dev_err(&pdev->dev, "Could not get reset GPIO\n");
+ return PTR_ERR(ctx->reset_gpio);
+ }
return devm_reset_controller_register(&pdev->dev, &ctx->rcdev);
}
+static const struct reset_props reset_props_sparx5 = {
+ .protect_reg = 0x84,
+ .protect_bit = BIT(10),
+ .reset_reg = 0x0,
+ .reset_bit = BIT(1),
+};
+
+static const struct reset_props reset_props_lan966x = {
+ .protect_reg = 0x88,
+ .protect_bit = BIT(5),
+ .reset_reg = 0x0,
+ .reset_bit = BIT(1),
+ .cuphy_reg = 0x10,
+ .cuphy_bit = BIT(0),
+};
+
static const struct of_device_id mchp_sparx5_reset_of_match[] = {
{
.compatible = "microchip,sparx5-switch-reset",
+ .data = &reset_props_sparx5,
+ }, {
+ .compatible = "microchip,lan966x-switch-reset",
+ .data = &reset_props_lan966x,
},
{ }
};