162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// Copyright (c) 2019 Nuvoton Technology corporation. 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/delay.h> 562306a36Sopenharmony_ci#include <linux/err.h> 662306a36Sopenharmony_ci#include <linux/io.h> 762306a36Sopenharmony_ci#include <linux/init.h> 862306a36Sopenharmony_ci#include <linux/of.h> 962306a36Sopenharmony_ci#include <linux/of_device.h> 1062306a36Sopenharmony_ci#include <linux/platform_device.h> 1162306a36Sopenharmony_ci#include <linux/reboot.h> 1262306a36Sopenharmony_ci#include <linux/reset-controller.h> 1362306a36Sopenharmony_ci#include <linux/spinlock.h> 1462306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 1562306a36Sopenharmony_ci#include <linux/regmap.h> 1662306a36Sopenharmony_ci#include <linux/of_address.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* NPCM7xx GCR registers */ 1962306a36Sopenharmony_ci#define NPCM_MDLR_OFFSET 0x7C 2062306a36Sopenharmony_ci#define NPCM7XX_MDLR_USBD0 BIT(9) 2162306a36Sopenharmony_ci#define NPCM7XX_MDLR_USBD1 BIT(8) 2262306a36Sopenharmony_ci#define NPCM7XX_MDLR_USBD2_4 BIT(21) 2362306a36Sopenharmony_ci#define NPCM7XX_MDLR_USBD5_9 BIT(22) 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* NPCM8xx MDLR bits */ 2662306a36Sopenharmony_ci#define NPCM8XX_MDLR_USBD0_3 BIT(9) 2762306a36Sopenharmony_ci#define NPCM8XX_MDLR_USBD4_7 BIT(22) 2862306a36Sopenharmony_ci#define NPCM8XX_MDLR_USBD8 BIT(24) 2962306a36Sopenharmony_ci#define NPCM8XX_MDLR_USBD9 BIT(21) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define NPCM_USB1PHYCTL_OFFSET 0x140 3262306a36Sopenharmony_ci#define NPCM_USB2PHYCTL_OFFSET 0x144 3362306a36Sopenharmony_ci#define NPCM_USB3PHYCTL_OFFSET 0x148 3462306a36Sopenharmony_ci#define NPCM_USBXPHYCTL_RS BIT(28) 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* NPCM7xx Reset registers */ 3762306a36Sopenharmony_ci#define NPCM_SWRSTR 0x14 3862306a36Sopenharmony_ci#define NPCM_SWRST BIT(2) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define NPCM_IPSRST1 0x20 4162306a36Sopenharmony_ci#define NPCM_IPSRST1_USBD1 BIT(5) 4262306a36Sopenharmony_ci#define NPCM_IPSRST1_USBD2 BIT(8) 4362306a36Sopenharmony_ci#define NPCM_IPSRST1_USBD3 BIT(25) 4462306a36Sopenharmony_ci#define NPCM_IPSRST1_USBD4 BIT(22) 4562306a36Sopenharmony_ci#define NPCM_IPSRST1_USBD5 BIT(23) 4662306a36Sopenharmony_ci#define NPCM_IPSRST1_USBD6 BIT(24) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define NPCM_IPSRST2 0x24 4962306a36Sopenharmony_ci#define NPCM_IPSRST2_USB_HOST BIT(26) 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define NPCM_IPSRST3 0x34 5262306a36Sopenharmony_ci#define NPCM_IPSRST3_USBD0 BIT(4) 5362306a36Sopenharmony_ci#define NPCM_IPSRST3_USBD7 BIT(5) 5462306a36Sopenharmony_ci#define NPCM_IPSRST3_USBD8 BIT(6) 5562306a36Sopenharmony_ci#define NPCM_IPSRST3_USBD9 BIT(7) 5662306a36Sopenharmony_ci#define NPCM_IPSRST3_USBPHY1 BIT(24) 5762306a36Sopenharmony_ci#define NPCM_IPSRST3_USBPHY2 BIT(25) 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define NPCM_IPSRST4 0x74 6062306a36Sopenharmony_ci#define NPCM_IPSRST4_USBPHY3 BIT(25) 6162306a36Sopenharmony_ci#define NPCM_IPSRST4_USB_HOST2 BIT(31) 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define NPCM_RC_RESETS_PER_REG 32 6462306a36Sopenharmony_ci#define NPCM_MASK_RESETS GENMASK(4, 0) 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cienum { 6762306a36Sopenharmony_ci BMC_NPCM7XX = 0, 6862306a36Sopenharmony_ci BMC_NPCM8XX, 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic const u32 npxm7xx_ipsrst[] = {NPCM_IPSRST1, NPCM_IPSRST2, NPCM_IPSRST3}; 7262306a36Sopenharmony_cistatic const u32 npxm8xx_ipsrst[] = {NPCM_IPSRST1, NPCM_IPSRST2, NPCM_IPSRST3, 7362306a36Sopenharmony_ci NPCM_IPSRST4}; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistruct npcm_reset_info { 7662306a36Sopenharmony_ci u32 bmc_id; 7762306a36Sopenharmony_ci u32 num_ipsrst; 7862306a36Sopenharmony_ci const u32 *ipsrst; 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic const struct npcm_reset_info npxm7xx_reset_info[] = { 8262306a36Sopenharmony_ci {.bmc_id = BMC_NPCM7XX, .num_ipsrst = 3, .ipsrst = npxm7xx_ipsrst}}; 8362306a36Sopenharmony_cistatic const struct npcm_reset_info npxm8xx_reset_info[] = { 8462306a36Sopenharmony_ci {.bmc_id = BMC_NPCM8XX, .num_ipsrst = 4, .ipsrst = npxm8xx_ipsrst}}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistruct npcm_rc_data { 8762306a36Sopenharmony_ci struct reset_controller_dev rcdev; 8862306a36Sopenharmony_ci struct notifier_block restart_nb; 8962306a36Sopenharmony_ci const struct npcm_reset_info *info; 9062306a36Sopenharmony_ci struct regmap *gcr_regmap; 9162306a36Sopenharmony_ci u32 sw_reset_number; 9262306a36Sopenharmony_ci void __iomem *base; 9362306a36Sopenharmony_ci spinlock_t lock; 9462306a36Sopenharmony_ci}; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci#define to_rc_data(p) container_of(p, struct npcm_rc_data, rcdev) 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic int npcm_rc_restart(struct notifier_block *nb, unsigned long mode, 9962306a36Sopenharmony_ci void *cmd) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct npcm_rc_data *rc = container_of(nb, struct npcm_rc_data, 10262306a36Sopenharmony_ci restart_nb); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci writel(NPCM_SWRST << rc->sw_reset_number, rc->base + NPCM_SWRSTR); 10562306a36Sopenharmony_ci mdelay(1000); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci pr_emerg("%s: unable to restart system\n", __func__); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci return NOTIFY_DONE; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic int npcm_rc_setclear_reset(struct reset_controller_dev *rcdev, 11362306a36Sopenharmony_ci unsigned long id, bool set) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct npcm_rc_data *rc = to_rc_data(rcdev); 11662306a36Sopenharmony_ci unsigned int rst_bit = BIT(id & NPCM_MASK_RESETS); 11762306a36Sopenharmony_ci unsigned int ctrl_offset = id >> 8; 11862306a36Sopenharmony_ci unsigned long flags; 11962306a36Sopenharmony_ci u32 stat; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci spin_lock_irqsave(&rc->lock, flags); 12262306a36Sopenharmony_ci stat = readl(rc->base + ctrl_offset); 12362306a36Sopenharmony_ci if (set) 12462306a36Sopenharmony_ci writel(stat | rst_bit, rc->base + ctrl_offset); 12562306a36Sopenharmony_ci else 12662306a36Sopenharmony_ci writel(stat & ~rst_bit, rc->base + ctrl_offset); 12762306a36Sopenharmony_ci spin_unlock_irqrestore(&rc->lock, flags); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci return 0; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic int npcm_rc_assert(struct reset_controller_dev *rcdev, unsigned long id) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci return npcm_rc_setclear_reset(rcdev, id, true); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic int npcm_rc_deassert(struct reset_controller_dev *rcdev, 13862306a36Sopenharmony_ci unsigned long id) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci return npcm_rc_setclear_reset(rcdev, id, false); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic int npcm_rc_status(struct reset_controller_dev *rcdev, 14462306a36Sopenharmony_ci unsigned long id) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci struct npcm_rc_data *rc = to_rc_data(rcdev); 14762306a36Sopenharmony_ci unsigned int rst_bit = BIT(id & NPCM_MASK_RESETS); 14862306a36Sopenharmony_ci unsigned int ctrl_offset = id >> 8; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci return (readl(rc->base + ctrl_offset) & rst_bit); 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic int npcm_reset_xlate(struct reset_controller_dev *rcdev, 15462306a36Sopenharmony_ci const struct of_phandle_args *reset_spec) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct npcm_rc_data *rc = to_rc_data(rcdev); 15762306a36Sopenharmony_ci unsigned int offset, bit; 15862306a36Sopenharmony_ci bool offset_found = false; 15962306a36Sopenharmony_ci int off_num; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci offset = reset_spec->args[0]; 16262306a36Sopenharmony_ci for (off_num = 0 ; off_num < rc->info->num_ipsrst ; off_num++) { 16362306a36Sopenharmony_ci if (offset == rc->info->ipsrst[off_num]) { 16462306a36Sopenharmony_ci offset_found = true; 16562306a36Sopenharmony_ci break; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (!offset_found) { 17062306a36Sopenharmony_ci dev_err(rcdev->dev, "Error reset register (0x%x)\n", offset); 17162306a36Sopenharmony_ci return -EINVAL; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci bit = reset_spec->args[1]; 17562306a36Sopenharmony_ci if (bit >= NPCM_RC_RESETS_PER_REG) { 17662306a36Sopenharmony_ci dev_err(rcdev->dev, "Error reset number (%d)\n", bit); 17762306a36Sopenharmony_ci return -EINVAL; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci return (offset << 8) | bit; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic const struct of_device_id npcm_rc_match[] = { 18462306a36Sopenharmony_ci { .compatible = "nuvoton,npcm750-reset", .data = &npxm7xx_reset_info}, 18562306a36Sopenharmony_ci { .compatible = "nuvoton,npcm845-reset", .data = &npxm8xx_reset_info}, 18662306a36Sopenharmony_ci { } 18762306a36Sopenharmony_ci}; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic void npcm_usb_reset_npcm7xx(struct npcm_rc_data *rc) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci u32 mdlr, iprst1, iprst2, iprst3; 19262306a36Sopenharmony_ci u32 ipsrst1_bits = 0; 19362306a36Sopenharmony_ci u32 ipsrst2_bits = NPCM_IPSRST2_USB_HOST; 19462306a36Sopenharmony_ci u32 ipsrst3_bits = 0; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* checking which USB device is enabled */ 19762306a36Sopenharmony_ci regmap_read(rc->gcr_regmap, NPCM_MDLR_OFFSET, &mdlr); 19862306a36Sopenharmony_ci if (!(mdlr & NPCM7XX_MDLR_USBD0)) 19962306a36Sopenharmony_ci ipsrst3_bits |= NPCM_IPSRST3_USBD0; 20062306a36Sopenharmony_ci if (!(mdlr & NPCM7XX_MDLR_USBD1)) 20162306a36Sopenharmony_ci ipsrst1_bits |= NPCM_IPSRST1_USBD1; 20262306a36Sopenharmony_ci if (!(mdlr & NPCM7XX_MDLR_USBD2_4)) 20362306a36Sopenharmony_ci ipsrst1_bits |= (NPCM_IPSRST1_USBD2 | 20462306a36Sopenharmony_ci NPCM_IPSRST1_USBD3 | 20562306a36Sopenharmony_ci NPCM_IPSRST1_USBD4); 20662306a36Sopenharmony_ci if (!(mdlr & NPCM7XX_MDLR_USBD0)) { 20762306a36Sopenharmony_ci ipsrst1_bits |= (NPCM_IPSRST1_USBD5 | 20862306a36Sopenharmony_ci NPCM_IPSRST1_USBD6); 20962306a36Sopenharmony_ci ipsrst3_bits |= (NPCM_IPSRST3_USBD7 | 21062306a36Sopenharmony_ci NPCM_IPSRST3_USBD8 | 21162306a36Sopenharmony_ci NPCM_IPSRST3_USBD9); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* assert reset USB PHY and USB devices */ 21562306a36Sopenharmony_ci iprst1 = readl(rc->base + NPCM_IPSRST1); 21662306a36Sopenharmony_ci iprst2 = readl(rc->base + NPCM_IPSRST2); 21762306a36Sopenharmony_ci iprst3 = readl(rc->base + NPCM_IPSRST3); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci iprst1 |= ipsrst1_bits; 22062306a36Sopenharmony_ci iprst2 |= ipsrst2_bits; 22162306a36Sopenharmony_ci iprst3 |= (ipsrst3_bits | NPCM_IPSRST3_USBPHY1 | 22262306a36Sopenharmony_ci NPCM_IPSRST3_USBPHY2); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci writel(iprst1, rc->base + NPCM_IPSRST1); 22562306a36Sopenharmony_ci writel(iprst2, rc->base + NPCM_IPSRST2); 22662306a36Sopenharmony_ci writel(iprst3, rc->base + NPCM_IPSRST3); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* clear USB PHY RS bit */ 22962306a36Sopenharmony_ci regmap_update_bits(rc->gcr_regmap, NPCM_USB1PHYCTL_OFFSET, 23062306a36Sopenharmony_ci NPCM_USBXPHYCTL_RS, 0); 23162306a36Sopenharmony_ci regmap_update_bits(rc->gcr_regmap, NPCM_USB2PHYCTL_OFFSET, 23262306a36Sopenharmony_ci NPCM_USBXPHYCTL_RS, 0); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci /* deassert reset USB PHY */ 23562306a36Sopenharmony_ci iprst3 &= ~(NPCM_IPSRST3_USBPHY1 | NPCM_IPSRST3_USBPHY2); 23662306a36Sopenharmony_ci writel(iprst3, rc->base + NPCM_IPSRST3); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci udelay(50); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* set USB PHY RS bit */ 24162306a36Sopenharmony_ci regmap_update_bits(rc->gcr_regmap, NPCM_USB1PHYCTL_OFFSET, 24262306a36Sopenharmony_ci NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS); 24362306a36Sopenharmony_ci regmap_update_bits(rc->gcr_regmap, NPCM_USB2PHYCTL_OFFSET, 24462306a36Sopenharmony_ci NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* deassert reset USB devices*/ 24762306a36Sopenharmony_ci iprst1 &= ~ipsrst1_bits; 24862306a36Sopenharmony_ci iprst2 &= ~ipsrst2_bits; 24962306a36Sopenharmony_ci iprst3 &= ~ipsrst3_bits; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci writel(iprst1, rc->base + NPCM_IPSRST1); 25262306a36Sopenharmony_ci writel(iprst2, rc->base + NPCM_IPSRST2); 25362306a36Sopenharmony_ci writel(iprst3, rc->base + NPCM_IPSRST3); 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic void npcm_usb_reset_npcm8xx(struct npcm_rc_data *rc) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci u32 mdlr, iprst1, iprst2, iprst3, iprst4; 25962306a36Sopenharmony_ci u32 ipsrst1_bits = 0; 26062306a36Sopenharmony_ci u32 ipsrst2_bits = NPCM_IPSRST2_USB_HOST; 26162306a36Sopenharmony_ci u32 ipsrst3_bits = 0; 26262306a36Sopenharmony_ci u32 ipsrst4_bits = NPCM_IPSRST4_USB_HOST2 | NPCM_IPSRST4_USBPHY3; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* checking which USB device is enabled */ 26562306a36Sopenharmony_ci regmap_read(rc->gcr_regmap, NPCM_MDLR_OFFSET, &mdlr); 26662306a36Sopenharmony_ci if (!(mdlr & NPCM8XX_MDLR_USBD0_3)) { 26762306a36Sopenharmony_ci ipsrst3_bits |= NPCM_IPSRST3_USBD0; 26862306a36Sopenharmony_ci ipsrst1_bits |= (NPCM_IPSRST1_USBD1 | 26962306a36Sopenharmony_ci NPCM_IPSRST1_USBD2 | 27062306a36Sopenharmony_ci NPCM_IPSRST1_USBD3); 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci if (!(mdlr & NPCM8XX_MDLR_USBD4_7)) { 27362306a36Sopenharmony_ci ipsrst1_bits |= (NPCM_IPSRST1_USBD4 | 27462306a36Sopenharmony_ci NPCM_IPSRST1_USBD5 | 27562306a36Sopenharmony_ci NPCM_IPSRST1_USBD6); 27662306a36Sopenharmony_ci ipsrst3_bits |= NPCM_IPSRST3_USBD7; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (!(mdlr & NPCM8XX_MDLR_USBD8)) 28062306a36Sopenharmony_ci ipsrst3_bits |= NPCM_IPSRST3_USBD8; 28162306a36Sopenharmony_ci if (!(mdlr & NPCM8XX_MDLR_USBD9)) 28262306a36Sopenharmony_ci ipsrst3_bits |= NPCM_IPSRST3_USBD9; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* assert reset USB PHY and USB devices */ 28562306a36Sopenharmony_ci iprst1 = readl(rc->base + NPCM_IPSRST1); 28662306a36Sopenharmony_ci iprst2 = readl(rc->base + NPCM_IPSRST2); 28762306a36Sopenharmony_ci iprst3 = readl(rc->base + NPCM_IPSRST3); 28862306a36Sopenharmony_ci iprst4 = readl(rc->base + NPCM_IPSRST4); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci iprst1 |= ipsrst1_bits; 29162306a36Sopenharmony_ci iprst2 |= ipsrst2_bits; 29262306a36Sopenharmony_ci iprst3 |= (ipsrst3_bits | NPCM_IPSRST3_USBPHY1 | 29362306a36Sopenharmony_ci NPCM_IPSRST3_USBPHY2); 29462306a36Sopenharmony_ci iprst4 |= ipsrst4_bits; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci writel(iprst1, rc->base + NPCM_IPSRST1); 29762306a36Sopenharmony_ci writel(iprst2, rc->base + NPCM_IPSRST2); 29862306a36Sopenharmony_ci writel(iprst3, rc->base + NPCM_IPSRST3); 29962306a36Sopenharmony_ci writel(iprst4, rc->base + NPCM_IPSRST4); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* clear USB PHY RS bit */ 30262306a36Sopenharmony_ci regmap_update_bits(rc->gcr_regmap, NPCM_USB1PHYCTL_OFFSET, 30362306a36Sopenharmony_ci NPCM_USBXPHYCTL_RS, 0); 30462306a36Sopenharmony_ci regmap_update_bits(rc->gcr_regmap, NPCM_USB2PHYCTL_OFFSET, 30562306a36Sopenharmony_ci NPCM_USBXPHYCTL_RS, 0); 30662306a36Sopenharmony_ci regmap_update_bits(rc->gcr_regmap, NPCM_USB3PHYCTL_OFFSET, 30762306a36Sopenharmony_ci NPCM_USBXPHYCTL_RS, 0); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* deassert reset USB PHY */ 31062306a36Sopenharmony_ci iprst3 &= ~(NPCM_IPSRST3_USBPHY1 | NPCM_IPSRST3_USBPHY2); 31162306a36Sopenharmony_ci writel(iprst3, rc->base + NPCM_IPSRST3); 31262306a36Sopenharmony_ci iprst4 &= ~NPCM_IPSRST4_USBPHY3; 31362306a36Sopenharmony_ci writel(iprst4, rc->base + NPCM_IPSRST4); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* set USB PHY RS bit */ 31662306a36Sopenharmony_ci regmap_update_bits(rc->gcr_regmap, NPCM_USB1PHYCTL_OFFSET, 31762306a36Sopenharmony_ci NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS); 31862306a36Sopenharmony_ci regmap_update_bits(rc->gcr_regmap, NPCM_USB2PHYCTL_OFFSET, 31962306a36Sopenharmony_ci NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS); 32062306a36Sopenharmony_ci regmap_update_bits(rc->gcr_regmap, NPCM_USB3PHYCTL_OFFSET, 32162306a36Sopenharmony_ci NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* deassert reset USB devices*/ 32462306a36Sopenharmony_ci iprst1 &= ~ipsrst1_bits; 32562306a36Sopenharmony_ci iprst2 &= ~ipsrst2_bits; 32662306a36Sopenharmony_ci iprst3 &= ~ipsrst3_bits; 32762306a36Sopenharmony_ci iprst4 &= ~ipsrst4_bits; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci writel(iprst1, rc->base + NPCM_IPSRST1); 33062306a36Sopenharmony_ci writel(iprst2, rc->base + NPCM_IPSRST2); 33162306a36Sopenharmony_ci writel(iprst3, rc->base + NPCM_IPSRST3); 33262306a36Sopenharmony_ci writel(iprst4, rc->base + NPCM_IPSRST4); 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci/* 33662306a36Sopenharmony_ci * The following procedure should be observed in USB PHY, USB device and 33762306a36Sopenharmony_ci * USB host initialization at BMC boot 33862306a36Sopenharmony_ci */ 33962306a36Sopenharmony_cistatic int npcm_usb_reset(struct platform_device *pdev, struct npcm_rc_data *rc) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct device *dev = &pdev->dev; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci rc->gcr_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "nuvoton,sysgcr"); 34462306a36Sopenharmony_ci if (IS_ERR(rc->gcr_regmap)) { 34562306a36Sopenharmony_ci dev_warn(&pdev->dev, "Failed to find nuvoton,sysgcr property, please update the device tree\n"); 34662306a36Sopenharmony_ci dev_info(&pdev->dev, "Using nuvoton,npcm750-gcr for Poleg backward compatibility\n"); 34762306a36Sopenharmony_ci rc->gcr_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr"); 34862306a36Sopenharmony_ci if (IS_ERR(rc->gcr_regmap)) { 34962306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to find nuvoton,npcm750-gcr"); 35062306a36Sopenharmony_ci return PTR_ERR(rc->gcr_regmap); 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci rc->info = (const struct npcm_reset_info *) 35562306a36Sopenharmony_ci of_match_device(dev->driver->of_match_table, dev)->data; 35662306a36Sopenharmony_ci switch (rc->info->bmc_id) { 35762306a36Sopenharmony_ci case BMC_NPCM7XX: 35862306a36Sopenharmony_ci npcm_usb_reset_npcm7xx(rc); 35962306a36Sopenharmony_ci break; 36062306a36Sopenharmony_ci case BMC_NPCM8XX: 36162306a36Sopenharmony_ci npcm_usb_reset_npcm8xx(rc); 36262306a36Sopenharmony_ci break; 36362306a36Sopenharmony_ci default: 36462306a36Sopenharmony_ci return -ENODEV; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci return 0; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic const struct reset_control_ops npcm_rc_ops = { 37162306a36Sopenharmony_ci .assert = npcm_rc_assert, 37262306a36Sopenharmony_ci .deassert = npcm_rc_deassert, 37362306a36Sopenharmony_ci .status = npcm_rc_status, 37462306a36Sopenharmony_ci}; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic int npcm_rc_probe(struct platform_device *pdev) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci struct npcm_rc_data *rc; 37962306a36Sopenharmony_ci int ret; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci rc = devm_kzalloc(&pdev->dev, sizeof(*rc), GFP_KERNEL); 38262306a36Sopenharmony_ci if (!rc) 38362306a36Sopenharmony_ci return -ENOMEM; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci rc->base = devm_platform_ioremap_resource(pdev, 0); 38662306a36Sopenharmony_ci if (IS_ERR(rc->base)) 38762306a36Sopenharmony_ci return PTR_ERR(rc->base); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci spin_lock_init(&rc->lock); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci rc->rcdev.owner = THIS_MODULE; 39262306a36Sopenharmony_ci rc->rcdev.ops = &npcm_rc_ops; 39362306a36Sopenharmony_ci rc->rcdev.of_node = pdev->dev.of_node; 39462306a36Sopenharmony_ci rc->rcdev.of_reset_n_cells = 2; 39562306a36Sopenharmony_ci rc->rcdev.of_xlate = npcm_reset_xlate; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci ret = devm_reset_controller_register(&pdev->dev, &rc->rcdev); 39862306a36Sopenharmony_ci if (ret) { 39962306a36Sopenharmony_ci dev_err(&pdev->dev, "unable to register device\n"); 40062306a36Sopenharmony_ci return ret; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (npcm_usb_reset(pdev, rc)) 40462306a36Sopenharmony_ci dev_warn(&pdev->dev, "NPCM USB reset failed, can cause issues with UDC and USB host\n"); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci if (!of_property_read_u32(pdev->dev.of_node, "nuvoton,sw-reset-number", 40762306a36Sopenharmony_ci &rc->sw_reset_number)) { 40862306a36Sopenharmony_ci if (rc->sw_reset_number && rc->sw_reset_number < 5) { 40962306a36Sopenharmony_ci rc->restart_nb.priority = 192, 41062306a36Sopenharmony_ci rc->restart_nb.notifier_call = npcm_rc_restart, 41162306a36Sopenharmony_ci ret = register_restart_handler(&rc->restart_nb); 41262306a36Sopenharmony_ci if (ret) 41362306a36Sopenharmony_ci dev_warn(&pdev->dev, "failed to register restart handler\n"); 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci return ret; 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic struct platform_driver npcm_rc_driver = { 42162306a36Sopenharmony_ci .probe = npcm_rc_probe, 42262306a36Sopenharmony_ci .driver = { 42362306a36Sopenharmony_ci .name = "npcm-reset", 42462306a36Sopenharmony_ci .of_match_table = npcm_rc_match, 42562306a36Sopenharmony_ci .suppress_bind_attrs = true, 42662306a36Sopenharmony_ci }, 42762306a36Sopenharmony_ci}; 42862306a36Sopenharmony_cibuiltin_platform_driver(npcm_rc_driver); 429