reset: npcm: Add NPCM8XX support
authorTomer Maimon <tmaimon77@gmail.com>
Sun, 17 Jul 2022 09:16:02 +0000 (12:16 +0300)
committerArnd Bergmann <arnd@arndb.de>
Tue, 19 Jul 2022 13:41:03 +0000 (15:41 +0200)
Updated the NPCM reset driver to add support for Nuvoton BMC NPCM8XX SoC.
As part of adding NPCM8XX support:
- Add NPCM8XX specific compatible string.
- Add NPCM8XX USB reset.
- Add data to handle architecture-specific reset parameters.
- Some of the Reset Id and number of resets are different from NPCM7XX.

Signed-off-by: Tomer Maimon <tmaimon77@gmail.com>
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
drivers/reset/reset-npcm.c

index b08f8d8..24c55ef 100644 (file)
 
 /* NPCM7xx GCR registers */
 #define NPCM_MDLR_OFFSET       0x7C
-#define NPCM_MDLR_USBD0                BIT(9)
-#define NPCM_MDLR_USBD1                BIT(8)
-#define NPCM_MDLR_USBD2_4      BIT(21)
-#define NPCM_MDLR_USBD5_9      BIT(22)
+#define NPCM7XX_MDLR_USBD0     BIT(9)
+#define NPCM7XX_MDLR_USBD1     BIT(8)
+#define NPCM7XX_MDLR_USBD2_4   BIT(21)
+#define NPCM7XX_MDLR_USBD5_9   BIT(22)
+
+/* NPCM8xx MDLR bits */
+#define NPCM8XX_MDLR_USBD0_3   BIT(9)
+#define NPCM8XX_MDLR_USBD4_7   BIT(22)
+#define NPCM8XX_MDLR_USBD8     BIT(24)
+#define NPCM8XX_MDLR_USBD9     BIT(21)
 
 #define NPCM_USB1PHYCTL_OFFSET 0x140
 #define NPCM_USB2PHYCTL_OFFSET 0x144
+#define NPCM_USB3PHYCTL_OFFSET 0x148
 #define NPCM_USBXPHYCTL_RS     BIT(28)
 
 /* NPCM7xx Reset registers */
 #define NPCM_IPSRST3_USBPHY1   BIT(24)
 #define NPCM_IPSRST3_USBPHY2   BIT(25)
 
+#define NPCM_IPSRST4           0x74
+#define NPCM_IPSRST4_USBPHY3   BIT(25)
+#define NPCM_IPSRST4_USB_HOST2 BIT(31)
+
 #define NPCM_RC_RESETS_PER_REG 32
 #define NPCM_MASK_RESETS       GENMASK(4, 0)
 
+enum {
+       BMC_NPCM7XX = 0,
+       BMC_NPCM8XX,
+};
+
+static const u32 npxm7xx_ipsrst[] = {NPCM_IPSRST1, NPCM_IPSRST2, NPCM_IPSRST3};
+static const u32 npxm8xx_ipsrst[] = {NPCM_IPSRST1, NPCM_IPSRST2, NPCM_IPSRST3,
+       NPCM_IPSRST4};
+
+struct npcm_reset_info {
+       u32 bmc_id;
+       u32 num_ipsrst;
+       const u32 *ipsrst;
+};
+
+static const struct npcm_reset_info npxm7xx_reset_info[] = {
+       {.bmc_id = BMC_NPCM7XX, .num_ipsrst = 3, .ipsrst = npxm7xx_ipsrst}};
+static const struct npcm_reset_info npxm8xx_reset_info[] = {
+       {.bmc_id = BMC_NPCM8XX, .num_ipsrst = 4, .ipsrst = npxm8xx_ipsrst}};
+
 struct npcm_rc_data {
        struct reset_controller_dev rcdev;
        struct notifier_block restart_nb;
+       const struct npcm_reset_info *info;
+       struct regmap *gcr_regmap;
        u32 sw_reset_number;
        void __iomem *base;
        spinlock_t lock;
@@ -120,14 +153,24 @@ static int npcm_rc_status(struct reset_controller_dev *rcdev,
 static int npcm_reset_xlate(struct reset_controller_dev *rcdev,
                            const struct of_phandle_args *reset_spec)
 {
+       struct npcm_rc_data *rc = to_rc_data(rcdev);
        unsigned int offset, bit;
+       bool offset_found = false;
+       int off_num;
 
        offset = reset_spec->args[0];
-       if (offset != NPCM_IPSRST1 && offset != NPCM_IPSRST2 &&
-           offset != NPCM_IPSRST3) {
+       for (off_num = 0 ; off_num < rc->info->num_ipsrst ; off_num++) {
+               if (offset == rc->info->ipsrst[off_num]) {
+                       offset_found = true;
+                       break;
+               }
+       }
+
+       if (!offset_found) {
                dev_err(rcdev->dev, "Error reset register (0x%x)\n", offset);
                return -EINVAL;
        }
+
        bit = reset_spec->args[1];
        if (bit >= NPCM_RC_RESETS_PER_REG) {
                dev_err(rcdev->dev, "Error reset number (%d)\n", bit);
@@ -138,49 +181,29 @@ static int npcm_reset_xlate(struct reset_controller_dev *rcdev,
 }
 
 static const struct of_device_id npcm_rc_match[] = {
-       { .compatible = "nuvoton,npcm750-reset" },
+       { .compatible = "nuvoton,npcm750-reset", .data = &npxm7xx_reset_info},
+       { .compatible = "nuvoton,npcm845-reset", .data = &npxm8xx_reset_info},
        { }
 };
 
-/*
- *  The following procedure should be observed in USB PHY, USB device and
- *  USB host initialization at BMC boot
- */
-static int npcm_usb_reset(struct platform_device *pdev, struct npcm_rc_data *rc)
+static void npcm_usb_reset_npcm7xx(struct npcm_rc_data *rc)
 {
        u32 mdlr, iprst1, iprst2, iprst3;
-       struct device *dev = &pdev->dev;
-       struct regmap *gcr_regmap;
        u32 ipsrst1_bits = 0;
        u32 ipsrst2_bits = NPCM_IPSRST2_USB_HOST;
        u32 ipsrst3_bits = 0;
-       const char *gcr_dt;
-
-       gcr_dt = (const char *)
-       of_match_device(dev->driver->of_match_table, dev)->data;
-
-       gcr_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "nuvoton,sysgcr");
-       if (IS_ERR(gcr_regmap)) {
-               dev_warn(&pdev->dev, "Failed to find nuvoton,sysgcr property, please update the device tree\n");
-               dev_info(&pdev->dev, "Using nuvoton,npcm750-gcr for Poleg backward compatibility\n");
-               gcr_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr");
-               if (IS_ERR(gcr_regmap)) {
-                       dev_err(&pdev->dev, "Failed to find nuvoton,npcm750-gcr");
-                       return PTR_ERR(gcr_regmap);
-               }
-       }
 
        /* checking which USB device is enabled */
-       regmap_read(gcr_regmap, NPCM_MDLR_OFFSET, &mdlr);
-       if (!(mdlr & NPCM_MDLR_USBD0))
+       regmap_read(rc->gcr_regmap, NPCM_MDLR_OFFSET, &mdlr);
+       if (!(mdlr & NPCM7XX_MDLR_USBD0))
                ipsrst3_bits |= NPCM_IPSRST3_USBD0;
-       if (!(mdlr & NPCM_MDLR_USBD1))
+       if (!(mdlr & NPCM7XX_MDLR_USBD1))
                ipsrst1_bits |= NPCM_IPSRST1_USBD1;
-       if (!(mdlr & NPCM_MDLR_USBD2_4))
+       if (!(mdlr & NPCM7XX_MDLR_USBD2_4))
                ipsrst1_bits |= (NPCM_IPSRST1_USBD2 |
                                 NPCM_IPSRST1_USBD3 |
                                 NPCM_IPSRST1_USBD4);
-       if (!(mdlr & NPCM_MDLR_USBD0)) {
+       if (!(mdlr & NPCM7XX_MDLR_USBD0)) {
                ipsrst1_bits |= (NPCM_IPSRST1_USBD5 |
                                 NPCM_IPSRST1_USBD6);
                ipsrst3_bits |= (NPCM_IPSRST3_USBD7 |
@@ -203,9 +226,9 @@ static int npcm_usb_reset(struct platform_device *pdev, struct npcm_rc_data *rc)
        writel(iprst3, rc->base + NPCM_IPSRST3);
 
        /* clear USB PHY RS bit */
-       regmap_update_bits(gcr_regmap, NPCM_USB1PHYCTL_OFFSET,
+       regmap_update_bits(rc->gcr_regmap, NPCM_USB1PHYCTL_OFFSET,
                           NPCM_USBXPHYCTL_RS, 0);
-       regmap_update_bits(gcr_regmap, NPCM_USB2PHYCTL_OFFSET,
+       regmap_update_bits(rc->gcr_regmap, NPCM_USB2PHYCTL_OFFSET,
                           NPCM_USBXPHYCTL_RS, 0);
 
        /* deassert reset USB PHY */
@@ -215,9 +238,9 @@ static int npcm_usb_reset(struct platform_device *pdev, struct npcm_rc_data *rc)
        udelay(50);
 
        /* set USB PHY RS bit */
-       regmap_update_bits(gcr_regmap, NPCM_USB1PHYCTL_OFFSET,
+       regmap_update_bits(rc->gcr_regmap, NPCM_USB1PHYCTL_OFFSET,
                           NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS);
-       regmap_update_bits(gcr_regmap, NPCM_USB2PHYCTL_OFFSET,
+       regmap_update_bits(rc->gcr_regmap, NPCM_USB2PHYCTL_OFFSET,
                           NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS);
 
        /* deassert reset USB devices*/
@@ -228,6 +251,118 @@ static int npcm_usb_reset(struct platform_device *pdev, struct npcm_rc_data *rc)
        writel(iprst1, rc->base + NPCM_IPSRST1);
        writel(iprst2, rc->base + NPCM_IPSRST2);
        writel(iprst3, rc->base + NPCM_IPSRST3);
+}
+
+static void npcm_usb_reset_npcm8xx(struct npcm_rc_data *rc)
+{
+       u32 mdlr, iprst1, iprst2, iprst3, iprst4;
+       u32 ipsrst1_bits = 0;
+       u32 ipsrst2_bits = NPCM_IPSRST2_USB_HOST;
+       u32 ipsrst3_bits = 0;
+       u32 ipsrst4_bits = NPCM_IPSRST4_USB_HOST2 | NPCM_IPSRST4_USBPHY3;
+
+       /* checking which USB device is enabled */
+       regmap_read(rc->gcr_regmap, NPCM_MDLR_OFFSET, &mdlr);
+       if (!(mdlr & NPCM8XX_MDLR_USBD0_3)) {
+               ipsrst3_bits |= NPCM_IPSRST3_USBD0;
+               ipsrst1_bits |= (NPCM_IPSRST1_USBD1 |
+                                NPCM_IPSRST1_USBD2 |
+                                NPCM_IPSRST1_USBD3);
+       }
+       if (!(mdlr & NPCM8XX_MDLR_USBD4_7)) {
+               ipsrst1_bits |= (NPCM_IPSRST1_USBD4 |
+                                NPCM_IPSRST1_USBD5 |
+                                NPCM_IPSRST1_USBD6);
+               ipsrst3_bits |= NPCM_IPSRST3_USBD7;
+       }
+
+       if (!(mdlr & NPCM8XX_MDLR_USBD8))
+               ipsrst3_bits |= NPCM_IPSRST3_USBD8;
+       if (!(mdlr & NPCM8XX_MDLR_USBD9))
+               ipsrst3_bits |= NPCM_IPSRST3_USBD9;
+
+       /* assert reset USB PHY and USB devices */
+       iprst1 = readl(rc->base + NPCM_IPSRST1);
+       iprst2 = readl(rc->base + NPCM_IPSRST2);
+       iprst3 = readl(rc->base + NPCM_IPSRST3);
+       iprst4 = readl(rc->base + NPCM_IPSRST4);
+
+       iprst1 |= ipsrst1_bits;
+       iprst2 |= ipsrst2_bits;
+       iprst3 |= (ipsrst3_bits | NPCM_IPSRST3_USBPHY1 |
+                  NPCM_IPSRST3_USBPHY2);
+       iprst2 |= ipsrst4_bits;
+
+       writel(iprst1, rc->base + NPCM_IPSRST1);
+       writel(iprst2, rc->base + NPCM_IPSRST2);
+       writel(iprst3, rc->base + NPCM_IPSRST3);
+       writel(iprst4, rc->base + NPCM_IPSRST4);
+
+       /* clear USB PHY RS bit */
+       regmap_update_bits(rc->gcr_regmap, NPCM_USB1PHYCTL_OFFSET,
+                          NPCM_USBXPHYCTL_RS, 0);
+       regmap_update_bits(rc->gcr_regmap, NPCM_USB2PHYCTL_OFFSET,
+                          NPCM_USBXPHYCTL_RS, 0);
+       regmap_update_bits(rc->gcr_regmap, NPCM_USB3PHYCTL_OFFSET,
+                          NPCM_USBXPHYCTL_RS, 0);
+
+       /* deassert reset USB PHY */
+       iprst3 &= ~(NPCM_IPSRST3_USBPHY1 | NPCM_IPSRST3_USBPHY2);
+       writel(iprst3, rc->base + NPCM_IPSRST3);
+       iprst4 &= ~NPCM_IPSRST4_USBPHY3;
+       writel(iprst4, rc->base + NPCM_IPSRST4);
+
+       /* set USB PHY RS bit */
+       regmap_update_bits(rc->gcr_regmap, NPCM_USB1PHYCTL_OFFSET,
+                          NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS);
+       regmap_update_bits(rc->gcr_regmap, NPCM_USB2PHYCTL_OFFSET,
+                          NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS);
+       regmap_update_bits(rc->gcr_regmap, NPCM_USB3PHYCTL_OFFSET,
+                          NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS);
+
+       /* deassert reset USB devices*/
+       iprst1 &= ~ipsrst1_bits;
+       iprst2 &= ~ipsrst2_bits;
+       iprst3 &= ~ipsrst3_bits;
+       iprst4 &= ~ipsrst4_bits;
+
+       writel(iprst1, rc->base + NPCM_IPSRST1);
+       writel(iprst2, rc->base + NPCM_IPSRST2);
+       writel(iprst3, rc->base + NPCM_IPSRST3);
+       writel(iprst4, rc->base + NPCM_IPSRST4);
+}
+
+/*
+ *  The following procedure should be observed in USB PHY, USB device and
+ *  USB host initialization at BMC boot
+ */
+static int npcm_usb_reset(struct platform_device *pdev, struct npcm_rc_data *rc)
+{
+       struct device *dev = &pdev->dev;
+
+       rc->gcr_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "nuvoton,sysgcr");
+       if (IS_ERR(rc->gcr_regmap)) {
+               dev_warn(&pdev->dev, "Failed to find nuvoton,sysgcr property, please update the device tree\n");
+               dev_info(&pdev->dev, "Using nuvoton,npcm750-gcr for Poleg backward compatibility\n");
+               rc->gcr_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr");
+               if (IS_ERR(rc->gcr_regmap)) {
+                       dev_err(&pdev->dev, "Failed to find nuvoton,npcm750-gcr");
+                       return PTR_ERR(rc->gcr_regmap);
+               }
+       }
+
+       rc->info = (const struct npcm_reset_info *)
+                       of_match_device(dev->driver->of_match_table, dev)->data;
+       switch (rc->info->bmc_id) {
+       case BMC_NPCM7XX:
+               npcm_usb_reset_npcm7xx(rc);
+               break;
+       case BMC_NPCM8XX:
+               npcm_usb_reset_npcm8xx(rc);
+               break;
+       default:
+               return -ENODEV;
+       }
 
        return 0;
 }