Commit fc5d2a2f authored by Tomer Maimon's avatar Tomer Maimon Committed by Arnd Bergmann

reset: npcm: Add NPCM8XX support

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: default avatarTomer Maimon <tmaimon77@gmail.com>
Acked-by: default avatarPhilipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parent 85331f56
...@@ -17,13 +17,20 @@ ...@@ -17,13 +17,20 @@
/* NPCM7xx GCR registers */ /* NPCM7xx GCR registers */
#define NPCM_MDLR_OFFSET 0x7C #define NPCM_MDLR_OFFSET 0x7C
#define NPCM_MDLR_USBD0 BIT(9) #define NPCM7XX_MDLR_USBD0 BIT(9)
#define NPCM_MDLR_USBD1 BIT(8) #define NPCM7XX_MDLR_USBD1 BIT(8)
#define NPCM_MDLR_USBD2_4 BIT(21) #define NPCM7XX_MDLR_USBD2_4 BIT(21)
#define NPCM_MDLR_USBD5_9 BIT(22) #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_USB1PHYCTL_OFFSET 0x140
#define NPCM_USB2PHYCTL_OFFSET 0x144 #define NPCM_USB2PHYCTL_OFFSET 0x144
#define NPCM_USB3PHYCTL_OFFSET 0x148
#define NPCM_USBXPHYCTL_RS BIT(28) #define NPCM_USBXPHYCTL_RS BIT(28)
/* NPCM7xx Reset registers */ /* NPCM7xx Reset registers */
...@@ -49,12 +56,38 @@ ...@@ -49,12 +56,38 @@
#define NPCM_IPSRST3_USBPHY1 BIT(24) #define NPCM_IPSRST3_USBPHY1 BIT(24)
#define NPCM_IPSRST3_USBPHY2 BIT(25) #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_RC_RESETS_PER_REG 32
#define NPCM_MASK_RESETS GENMASK(4, 0) #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 npcm_rc_data {
struct reset_controller_dev rcdev; struct reset_controller_dev rcdev;
struct notifier_block restart_nb; struct notifier_block restart_nb;
const struct npcm_reset_info *info;
struct regmap *gcr_regmap;
u32 sw_reset_number; u32 sw_reset_number;
void __iomem *base; void __iomem *base;
spinlock_t lock; spinlock_t lock;
...@@ -120,14 +153,24 @@ static int npcm_rc_status(struct reset_controller_dev *rcdev, ...@@ -120,14 +153,24 @@ static int npcm_rc_status(struct reset_controller_dev *rcdev,
static int npcm_reset_xlate(struct reset_controller_dev *rcdev, static int npcm_reset_xlate(struct reset_controller_dev *rcdev,
const struct of_phandle_args *reset_spec) const struct of_phandle_args *reset_spec)
{ {
struct npcm_rc_data *rc = to_rc_data(rcdev);
unsigned int offset, bit; unsigned int offset, bit;
bool offset_found = false;
int off_num;
offset = reset_spec->args[0]; offset = reset_spec->args[0];
if (offset != NPCM_IPSRST1 && offset != NPCM_IPSRST2 && for (off_num = 0 ; off_num < rc->info->num_ipsrst ; off_num++) {
offset != NPCM_IPSRST3) { 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); dev_err(rcdev->dev, "Error reset register (0x%x)\n", offset);
return -EINVAL; return -EINVAL;
} }
bit = reset_spec->args[1]; bit = reset_spec->args[1];
if (bit >= NPCM_RC_RESETS_PER_REG) { if (bit >= NPCM_RC_RESETS_PER_REG) {
dev_err(rcdev->dev, "Error reset number (%d)\n", bit); dev_err(rcdev->dev, "Error reset number (%d)\n", bit);
...@@ -138,49 +181,29 @@ static int npcm_reset_xlate(struct reset_controller_dev *rcdev, ...@@ -138,49 +181,29 @@ static int npcm_reset_xlate(struct reset_controller_dev *rcdev,
} }
static const struct of_device_id npcm_rc_match[] = { 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},
{ } { }
}; };
/* static void npcm_usb_reset_npcm7xx(struct npcm_rc_data *rc)
* 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)
{ {
u32 mdlr, iprst1, iprst2, iprst3; u32 mdlr, iprst1, iprst2, iprst3;
struct device *dev = &pdev->dev;
struct regmap *gcr_regmap;
u32 ipsrst1_bits = 0; u32 ipsrst1_bits = 0;
u32 ipsrst2_bits = NPCM_IPSRST2_USB_HOST; u32 ipsrst2_bits = NPCM_IPSRST2_USB_HOST;
u32 ipsrst3_bits = 0; 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 */ /* checking which USB device is enabled */
regmap_read(gcr_regmap, NPCM_MDLR_OFFSET, &mdlr); regmap_read(rc->gcr_regmap, NPCM_MDLR_OFFSET, &mdlr);
if (!(mdlr & NPCM_MDLR_USBD0)) if (!(mdlr & NPCM7XX_MDLR_USBD0))
ipsrst3_bits |= NPCM_IPSRST3_USBD0; ipsrst3_bits |= NPCM_IPSRST3_USBD0;
if (!(mdlr & NPCM_MDLR_USBD1)) if (!(mdlr & NPCM7XX_MDLR_USBD1))
ipsrst1_bits |= NPCM_IPSRST1_USBD1; ipsrst1_bits |= NPCM_IPSRST1_USBD1;
if (!(mdlr & NPCM_MDLR_USBD2_4)) if (!(mdlr & NPCM7XX_MDLR_USBD2_4))
ipsrst1_bits |= (NPCM_IPSRST1_USBD2 | ipsrst1_bits |= (NPCM_IPSRST1_USBD2 |
NPCM_IPSRST1_USBD3 | NPCM_IPSRST1_USBD3 |
NPCM_IPSRST1_USBD4); NPCM_IPSRST1_USBD4);
if (!(mdlr & NPCM_MDLR_USBD0)) { if (!(mdlr & NPCM7XX_MDLR_USBD0)) {
ipsrst1_bits |= (NPCM_IPSRST1_USBD5 | ipsrst1_bits |= (NPCM_IPSRST1_USBD5 |
NPCM_IPSRST1_USBD6); NPCM_IPSRST1_USBD6);
ipsrst3_bits |= (NPCM_IPSRST3_USBD7 | ipsrst3_bits |= (NPCM_IPSRST3_USBD7 |
...@@ -203,9 +226,9 @@ static int npcm_usb_reset(struct platform_device *pdev, struct npcm_rc_data *rc) ...@@ -203,9 +226,9 @@ static int npcm_usb_reset(struct platform_device *pdev, struct npcm_rc_data *rc)
writel(iprst3, rc->base + NPCM_IPSRST3); writel(iprst3, rc->base + NPCM_IPSRST3);
/* clear USB PHY RS bit */ /* 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); 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); NPCM_USBXPHYCTL_RS, 0);
/* deassert reset USB PHY */ /* deassert reset USB PHY */
...@@ -215,9 +238,9 @@ static int npcm_usb_reset(struct platform_device *pdev, struct npcm_rc_data *rc) ...@@ -215,9 +238,9 @@ static int npcm_usb_reset(struct platform_device *pdev, struct npcm_rc_data *rc)
udelay(50); udelay(50);
/* set USB PHY RS bit */ /* 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); 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); NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS);
/* deassert reset USB devices*/ /* deassert reset USB devices*/
...@@ -228,6 +251,118 @@ static int npcm_usb_reset(struct platform_device *pdev, struct npcm_rc_data *rc) ...@@ -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(iprst1, rc->base + NPCM_IPSRST1);
writel(iprst2, rc->base + NPCM_IPSRST2); writel(iprst2, rc->base + NPCM_IPSRST2);
writel(iprst3, rc->base + NPCM_IPSRST3); 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; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment