| From 54a5c6a0235b15d33a7bca51f0b187aa4b1200ef Mon Sep 17 00:00:00 2001 |
| From: David Wang <davidwang@quantatw.com> |
| Date: Mon, 6 Nov 2023 10:28:47 +0800 |
| Subject: [PATCH 03/16] drivers: reset: sync npcm reset |
| |
| --- |
| drivers/reset/reset-npcm.c | 209 +++++++++++++++++++++++++++++++------ |
| 1 file changed, 175 insertions(+), 34 deletions(-) |
| |
| diff --git a/drivers/reset/reset-npcm.c b/drivers/reset/reset-npcm.c |
| index 2ea4d3136e15..004d567fb23f 100644 |
| --- a/drivers/reset/reset-npcm.c |
| +++ b/drivers/reset/reset-npcm.c |
| @@ -17,13 +17,20 @@ |
| |
| /* 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 */ |
| @@ -49,12 +56,38 @@ |
| #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,45 +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", |
| - .data = (void *)"nuvoton,npcm750-gcr" }, |
| + { .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_compatible(gcr_dt); |
| - if (IS_ERR(gcr_regmap)) { |
| - dev_err(&pdev->dev, "Failed to find %s\n", gcr_dt); |
| - 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 | |
| @@ -199,31 +226,145 @@ 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(rc->gcr_regmap, NPCM_USB2PHYCTL_OFFSET, |
| + NPCM_USBXPHYCTL_RS, 0); |
| + |
| + /* deassert reset USB PHY */ |
| + iprst3 &= ~(NPCM_IPSRST3_USBPHY1 | NPCM_IPSRST3_USBPHY2); |
| + writel(iprst3, rc->base + NPCM_IPSRST3); |
| + |
| + udelay(50); |
| + |
| + /* 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); |
| + |
| + /* deassert reset USB devices*/ |
| + iprst1 &= ~ipsrst1_bits; |
| + iprst2 &= ~ipsrst2_bits; |
| + iprst3 &= ~ipsrst3_bits; |
| + |
| + 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); |
| + 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); |
| + |
| + /* clear USB PHY RS bit */ |
| + 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); |
| + 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); |
| |
| 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(rc->gcr_regmap, NPCM_USB2PHYCTL_OFFSET, |
| NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS); |
| - regmap_update_bits(gcr_regmap, NPCM_USB2PHYCTL_OFFSET, |
| + 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; |
| } |
| -- |
| 2.25.1 |
| |