18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// Copyright (c) 2019 Nuvoton Technology corporation. 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/delay.h> 58c2ecf20Sopenharmony_ci#include <linux/err.h> 68c2ecf20Sopenharmony_ci#include <linux/io.h> 78c2ecf20Sopenharmony_ci#include <linux/init.h> 88c2ecf20Sopenharmony_ci#include <linux/of.h> 98c2ecf20Sopenharmony_ci#include <linux/of_device.h> 108c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 118c2ecf20Sopenharmony_ci#include <linux/reboot.h> 128c2ecf20Sopenharmony_ci#include <linux/reset-controller.h> 138c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 148c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 158c2ecf20Sopenharmony_ci#include <linux/regmap.h> 168c2ecf20Sopenharmony_ci#include <linux/of_address.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* NPCM7xx GCR registers */ 198c2ecf20Sopenharmony_ci#define NPCM_MDLR_OFFSET 0x7C 208c2ecf20Sopenharmony_ci#define NPCM_MDLR_USBD0 BIT(9) 218c2ecf20Sopenharmony_ci#define NPCM_MDLR_USBD1 BIT(8) 228c2ecf20Sopenharmony_ci#define NPCM_MDLR_USBD2_4 BIT(21) 238c2ecf20Sopenharmony_ci#define NPCM_MDLR_USBD5_9 BIT(22) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define NPCM_USB1PHYCTL_OFFSET 0x140 268c2ecf20Sopenharmony_ci#define NPCM_USB2PHYCTL_OFFSET 0x144 278c2ecf20Sopenharmony_ci#define NPCM_USBXPHYCTL_RS BIT(28) 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* NPCM7xx Reset registers */ 308c2ecf20Sopenharmony_ci#define NPCM_SWRSTR 0x14 318c2ecf20Sopenharmony_ci#define NPCM_SWRST BIT(2) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define NPCM_IPSRST1 0x20 348c2ecf20Sopenharmony_ci#define NPCM_IPSRST1_USBD1 BIT(5) 358c2ecf20Sopenharmony_ci#define NPCM_IPSRST1_USBD2 BIT(8) 368c2ecf20Sopenharmony_ci#define NPCM_IPSRST1_USBD3 BIT(25) 378c2ecf20Sopenharmony_ci#define NPCM_IPSRST1_USBD4 BIT(22) 388c2ecf20Sopenharmony_ci#define NPCM_IPSRST1_USBD5 BIT(23) 398c2ecf20Sopenharmony_ci#define NPCM_IPSRST1_USBD6 BIT(24) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define NPCM_IPSRST2 0x24 428c2ecf20Sopenharmony_ci#define NPCM_IPSRST2_USB_HOST BIT(26) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define NPCM_IPSRST3 0x34 458c2ecf20Sopenharmony_ci#define NPCM_IPSRST3_USBD0 BIT(4) 468c2ecf20Sopenharmony_ci#define NPCM_IPSRST3_USBD7 BIT(5) 478c2ecf20Sopenharmony_ci#define NPCM_IPSRST3_USBD8 BIT(6) 488c2ecf20Sopenharmony_ci#define NPCM_IPSRST3_USBD9 BIT(7) 498c2ecf20Sopenharmony_ci#define NPCM_IPSRST3_USBPHY1 BIT(24) 508c2ecf20Sopenharmony_ci#define NPCM_IPSRST3_USBPHY2 BIT(25) 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define NPCM_RC_RESETS_PER_REG 32 538c2ecf20Sopenharmony_ci#define NPCM_MASK_RESETS GENMASK(4, 0) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistruct npcm_rc_data { 568c2ecf20Sopenharmony_ci struct reset_controller_dev rcdev; 578c2ecf20Sopenharmony_ci struct notifier_block restart_nb; 588c2ecf20Sopenharmony_ci u32 sw_reset_number; 598c2ecf20Sopenharmony_ci void __iomem *base; 608c2ecf20Sopenharmony_ci spinlock_t lock; 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define to_rc_data(p) container_of(p, struct npcm_rc_data, rcdev) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic int npcm_rc_restart(struct notifier_block *nb, unsigned long mode, 668c2ecf20Sopenharmony_ci void *cmd) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci struct npcm_rc_data *rc = container_of(nb, struct npcm_rc_data, 698c2ecf20Sopenharmony_ci restart_nb); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci writel(NPCM_SWRST << rc->sw_reset_number, rc->base + NPCM_SWRSTR); 728c2ecf20Sopenharmony_ci mdelay(1000); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci pr_emerg("%s: unable to restart system\n", __func__); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci return NOTIFY_DONE; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic int npcm_rc_setclear_reset(struct reset_controller_dev *rcdev, 808c2ecf20Sopenharmony_ci unsigned long id, bool set) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci struct npcm_rc_data *rc = to_rc_data(rcdev); 838c2ecf20Sopenharmony_ci unsigned int rst_bit = BIT(id & NPCM_MASK_RESETS); 848c2ecf20Sopenharmony_ci unsigned int ctrl_offset = id >> 8; 858c2ecf20Sopenharmony_ci unsigned long flags; 868c2ecf20Sopenharmony_ci u32 stat; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci spin_lock_irqsave(&rc->lock, flags); 898c2ecf20Sopenharmony_ci stat = readl(rc->base + ctrl_offset); 908c2ecf20Sopenharmony_ci if (set) 918c2ecf20Sopenharmony_ci writel(stat | rst_bit, rc->base + ctrl_offset); 928c2ecf20Sopenharmony_ci else 938c2ecf20Sopenharmony_ci writel(stat & ~rst_bit, rc->base + ctrl_offset); 948c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rc->lock, flags); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return 0; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int npcm_rc_assert(struct reset_controller_dev *rcdev, unsigned long id) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci return npcm_rc_setclear_reset(rcdev, id, true); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic int npcm_rc_deassert(struct reset_controller_dev *rcdev, 1058c2ecf20Sopenharmony_ci unsigned long id) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci return npcm_rc_setclear_reset(rcdev, id, false); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic int npcm_rc_status(struct reset_controller_dev *rcdev, 1118c2ecf20Sopenharmony_ci unsigned long id) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct npcm_rc_data *rc = to_rc_data(rcdev); 1148c2ecf20Sopenharmony_ci unsigned int rst_bit = BIT(id & NPCM_MASK_RESETS); 1158c2ecf20Sopenharmony_ci unsigned int ctrl_offset = id >> 8; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return (readl(rc->base + ctrl_offset) & rst_bit); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic int npcm_reset_xlate(struct reset_controller_dev *rcdev, 1218c2ecf20Sopenharmony_ci const struct of_phandle_args *reset_spec) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci unsigned int offset, bit; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci offset = reset_spec->args[0]; 1268c2ecf20Sopenharmony_ci if (offset != NPCM_IPSRST1 && offset != NPCM_IPSRST2 && 1278c2ecf20Sopenharmony_ci offset != NPCM_IPSRST3) { 1288c2ecf20Sopenharmony_ci dev_err(rcdev->dev, "Error reset register (0x%x)\n", offset); 1298c2ecf20Sopenharmony_ci return -EINVAL; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci bit = reset_spec->args[1]; 1328c2ecf20Sopenharmony_ci if (bit >= NPCM_RC_RESETS_PER_REG) { 1338c2ecf20Sopenharmony_ci dev_err(rcdev->dev, "Error reset number (%d)\n", bit); 1348c2ecf20Sopenharmony_ci return -EINVAL; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci return (offset << 8) | bit; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic const struct of_device_id npcm_rc_match[] = { 1418c2ecf20Sopenharmony_ci { .compatible = "nuvoton,npcm750-reset", 1428c2ecf20Sopenharmony_ci .data = (void *)"nuvoton,npcm750-gcr" }, 1438c2ecf20Sopenharmony_ci { } 1448c2ecf20Sopenharmony_ci}; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* 1478c2ecf20Sopenharmony_ci * The following procedure should be observed in USB PHY, USB device and 1488c2ecf20Sopenharmony_ci * USB host initialization at BMC boot 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_cistatic int npcm_usb_reset(struct platform_device *pdev, struct npcm_rc_data *rc) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci u32 mdlr, iprst1, iprst2, iprst3; 1538c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 1548c2ecf20Sopenharmony_ci struct regmap *gcr_regmap; 1558c2ecf20Sopenharmony_ci u32 ipsrst1_bits = 0; 1568c2ecf20Sopenharmony_ci u32 ipsrst2_bits = NPCM_IPSRST2_USB_HOST; 1578c2ecf20Sopenharmony_ci u32 ipsrst3_bits = 0; 1588c2ecf20Sopenharmony_ci const char *gcr_dt; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci gcr_dt = (const char *) 1618c2ecf20Sopenharmony_ci of_match_device(dev->driver->of_match_table, dev)->data; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci gcr_regmap = syscon_regmap_lookup_by_compatible(gcr_dt); 1648c2ecf20Sopenharmony_ci if (IS_ERR(gcr_regmap)) { 1658c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to find %s\n", gcr_dt); 1668c2ecf20Sopenharmony_ci return PTR_ERR(gcr_regmap); 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* checking which USB device is enabled */ 1708c2ecf20Sopenharmony_ci regmap_read(gcr_regmap, NPCM_MDLR_OFFSET, &mdlr); 1718c2ecf20Sopenharmony_ci if (!(mdlr & NPCM_MDLR_USBD0)) 1728c2ecf20Sopenharmony_ci ipsrst3_bits |= NPCM_IPSRST3_USBD0; 1738c2ecf20Sopenharmony_ci if (!(mdlr & NPCM_MDLR_USBD1)) 1748c2ecf20Sopenharmony_ci ipsrst1_bits |= NPCM_IPSRST1_USBD1; 1758c2ecf20Sopenharmony_ci if (!(mdlr & NPCM_MDLR_USBD2_4)) 1768c2ecf20Sopenharmony_ci ipsrst1_bits |= (NPCM_IPSRST1_USBD2 | 1778c2ecf20Sopenharmony_ci NPCM_IPSRST1_USBD3 | 1788c2ecf20Sopenharmony_ci NPCM_IPSRST1_USBD4); 1798c2ecf20Sopenharmony_ci if (!(mdlr & NPCM_MDLR_USBD0)) { 1808c2ecf20Sopenharmony_ci ipsrst1_bits |= (NPCM_IPSRST1_USBD5 | 1818c2ecf20Sopenharmony_ci NPCM_IPSRST1_USBD6); 1828c2ecf20Sopenharmony_ci ipsrst3_bits |= (NPCM_IPSRST3_USBD7 | 1838c2ecf20Sopenharmony_ci NPCM_IPSRST3_USBD8 | 1848c2ecf20Sopenharmony_ci NPCM_IPSRST3_USBD9); 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci /* assert reset USB PHY and USB devices */ 1888c2ecf20Sopenharmony_ci iprst1 = readl(rc->base + NPCM_IPSRST1); 1898c2ecf20Sopenharmony_ci iprst2 = readl(rc->base + NPCM_IPSRST2); 1908c2ecf20Sopenharmony_ci iprst3 = readl(rc->base + NPCM_IPSRST3); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci iprst1 |= ipsrst1_bits; 1938c2ecf20Sopenharmony_ci iprst2 |= ipsrst2_bits; 1948c2ecf20Sopenharmony_ci iprst3 |= (ipsrst3_bits | NPCM_IPSRST3_USBPHY1 | 1958c2ecf20Sopenharmony_ci NPCM_IPSRST3_USBPHY2); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci writel(iprst1, rc->base + NPCM_IPSRST1); 1988c2ecf20Sopenharmony_ci writel(iprst2, rc->base + NPCM_IPSRST2); 1998c2ecf20Sopenharmony_ci writel(iprst3, rc->base + NPCM_IPSRST3); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* clear USB PHY RS bit */ 2028c2ecf20Sopenharmony_ci regmap_update_bits(gcr_regmap, NPCM_USB1PHYCTL_OFFSET, 2038c2ecf20Sopenharmony_ci NPCM_USBXPHYCTL_RS, 0); 2048c2ecf20Sopenharmony_ci regmap_update_bits(gcr_regmap, NPCM_USB2PHYCTL_OFFSET, 2058c2ecf20Sopenharmony_ci NPCM_USBXPHYCTL_RS, 0); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* deassert reset USB PHY */ 2088c2ecf20Sopenharmony_ci iprst3 &= ~(NPCM_IPSRST3_USBPHY1 | NPCM_IPSRST3_USBPHY2); 2098c2ecf20Sopenharmony_ci writel(iprst3, rc->base + NPCM_IPSRST3); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci udelay(50); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* set USB PHY RS bit */ 2148c2ecf20Sopenharmony_ci regmap_update_bits(gcr_regmap, NPCM_USB1PHYCTL_OFFSET, 2158c2ecf20Sopenharmony_ci NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS); 2168c2ecf20Sopenharmony_ci regmap_update_bits(gcr_regmap, NPCM_USB2PHYCTL_OFFSET, 2178c2ecf20Sopenharmony_ci NPCM_USBXPHYCTL_RS, NPCM_USBXPHYCTL_RS); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* deassert reset USB devices*/ 2208c2ecf20Sopenharmony_ci iprst1 &= ~ipsrst1_bits; 2218c2ecf20Sopenharmony_ci iprst2 &= ~ipsrst2_bits; 2228c2ecf20Sopenharmony_ci iprst3 &= ~ipsrst3_bits; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci writel(iprst1, rc->base + NPCM_IPSRST1); 2258c2ecf20Sopenharmony_ci writel(iprst2, rc->base + NPCM_IPSRST2); 2268c2ecf20Sopenharmony_ci writel(iprst3, rc->base + NPCM_IPSRST3); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci return 0; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic const struct reset_control_ops npcm_rc_ops = { 2328c2ecf20Sopenharmony_ci .assert = npcm_rc_assert, 2338c2ecf20Sopenharmony_ci .deassert = npcm_rc_deassert, 2348c2ecf20Sopenharmony_ci .status = npcm_rc_status, 2358c2ecf20Sopenharmony_ci}; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic int npcm_rc_probe(struct platform_device *pdev) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct npcm_rc_data *rc; 2408c2ecf20Sopenharmony_ci int ret; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci rc = devm_kzalloc(&pdev->dev, sizeof(*rc), GFP_KERNEL); 2438c2ecf20Sopenharmony_ci if (!rc) 2448c2ecf20Sopenharmony_ci return -ENOMEM; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci rc->base = devm_platform_ioremap_resource(pdev, 0); 2478c2ecf20Sopenharmony_ci if (IS_ERR(rc->base)) 2488c2ecf20Sopenharmony_ci return PTR_ERR(rc->base); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci spin_lock_init(&rc->lock); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci rc->rcdev.owner = THIS_MODULE; 2538c2ecf20Sopenharmony_ci rc->rcdev.ops = &npcm_rc_ops; 2548c2ecf20Sopenharmony_ci rc->rcdev.of_node = pdev->dev.of_node; 2558c2ecf20Sopenharmony_ci rc->rcdev.of_reset_n_cells = 2; 2568c2ecf20Sopenharmony_ci rc->rcdev.of_xlate = npcm_reset_xlate; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, rc); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci ret = devm_reset_controller_register(&pdev->dev, &rc->rcdev); 2618c2ecf20Sopenharmony_ci if (ret) { 2628c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "unable to register device\n"); 2638c2ecf20Sopenharmony_ci return ret; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (npcm_usb_reset(pdev, rc)) 2678c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "NPCM USB reset failed, can cause issues with UDC and USB host\n"); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (!of_property_read_u32(pdev->dev.of_node, "nuvoton,sw-reset-number", 2708c2ecf20Sopenharmony_ci &rc->sw_reset_number)) { 2718c2ecf20Sopenharmony_ci if (rc->sw_reset_number && rc->sw_reset_number < 5) { 2728c2ecf20Sopenharmony_ci rc->restart_nb.priority = 192, 2738c2ecf20Sopenharmony_ci rc->restart_nb.notifier_call = npcm_rc_restart, 2748c2ecf20Sopenharmony_ci ret = register_restart_handler(&rc->restart_nb); 2758c2ecf20Sopenharmony_ci if (ret) 2768c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "failed to register restart handler\n"); 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci return ret; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic struct platform_driver npcm_rc_driver = { 2848c2ecf20Sopenharmony_ci .probe = npcm_rc_probe, 2858c2ecf20Sopenharmony_ci .driver = { 2868c2ecf20Sopenharmony_ci .name = "npcm-reset", 2878c2ecf20Sopenharmony_ci .of_match_table = npcm_rc_match, 2888c2ecf20Sopenharmony_ci .suppress_bind_attrs = true, 2898c2ecf20Sopenharmony_ci }, 2908c2ecf20Sopenharmony_ci}; 2918c2ecf20Sopenharmony_cibuiltin_platform_driver(npcm_rc_driver); 292