1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2c392b65bSJoachim Eastwood /* 3c392b65bSJoachim Eastwood * Reset driver for NXP LPC18xx/43xx Reset Generation Unit (RGU). 4c392b65bSJoachim Eastwood * 5c392b65bSJoachim Eastwood * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com> 6c392b65bSJoachim Eastwood */ 7c392b65bSJoachim Eastwood 8c392b65bSJoachim Eastwood #include <linux/clk.h> 9c392b65bSJoachim Eastwood #include <linux/delay.h> 10c392b65bSJoachim Eastwood #include <linux/err.h> 11c392b65bSJoachim Eastwood #include <linux/io.h> 12cdd24f76SPaul Gortmaker #include <linux/init.h> 13c392b65bSJoachim Eastwood #include <linux/of.h> 14c392b65bSJoachim Eastwood #include <linux/platform_device.h> 15c392b65bSJoachim Eastwood #include <linux/reboot.h> 16c392b65bSJoachim Eastwood #include <linux/reset-controller.h> 17c392b65bSJoachim Eastwood #include <linux/spinlock.h> 18c392b65bSJoachim Eastwood 19c392b65bSJoachim Eastwood /* LPC18xx RGU registers */ 20c392b65bSJoachim Eastwood #define LPC18XX_RGU_CTRL0 0x100 21c392b65bSJoachim Eastwood #define LPC18XX_RGU_CTRL1 0x104 22c392b65bSJoachim Eastwood #define LPC18XX_RGU_ACTIVE_STATUS0 0x150 23c392b65bSJoachim Eastwood #define LPC18XX_RGU_ACTIVE_STATUS1 0x154 24c392b65bSJoachim Eastwood 25c392b65bSJoachim Eastwood #define LPC18XX_RGU_RESETS_PER_REG 32 26c392b65bSJoachim Eastwood 27c392b65bSJoachim Eastwood /* Internal reset outputs */ 28c392b65bSJoachim Eastwood #define LPC18XX_RGU_CORE_RST 0 29c392b65bSJoachim Eastwood #define LPC43XX_RGU_M0SUB_RST 12 30c392b65bSJoachim Eastwood #define LPC43XX_RGU_M0APP_RST 56 31c392b65bSJoachim Eastwood 32c392b65bSJoachim Eastwood struct lpc18xx_rgu_data { 33c392b65bSJoachim Eastwood struct reset_controller_dev rcdev; 34773fe726SJoachim Eastwood struct notifier_block restart_nb; 35c392b65bSJoachim Eastwood struct clk *clk_delay; 36c392b65bSJoachim Eastwood struct clk *clk_reg; 37c392b65bSJoachim Eastwood void __iomem *base; 38c392b65bSJoachim Eastwood spinlock_t lock; 39c392b65bSJoachim Eastwood u32 delay_us; 40c392b65bSJoachim Eastwood }; 41c392b65bSJoachim Eastwood 42c392b65bSJoachim Eastwood #define to_rgu_data(p) container_of(p, struct lpc18xx_rgu_data, rcdev) 43c392b65bSJoachim Eastwood 44773fe726SJoachim Eastwood static int lpc18xx_rgu_restart(struct notifier_block *nb, unsigned long mode, 45c392b65bSJoachim Eastwood void *cmd) 46c392b65bSJoachim Eastwood { 47773fe726SJoachim Eastwood struct lpc18xx_rgu_data *rc = container_of(nb, struct lpc18xx_rgu_data, 48773fe726SJoachim Eastwood restart_nb); 49773fe726SJoachim Eastwood 50773fe726SJoachim Eastwood writel(BIT(LPC18XX_RGU_CORE_RST), rc->base + LPC18XX_RGU_CTRL0); 51c392b65bSJoachim Eastwood mdelay(2000); 52c392b65bSJoachim Eastwood 53c392b65bSJoachim Eastwood pr_emerg("%s: unable to restart system\n", __func__); 54c392b65bSJoachim Eastwood 55c392b65bSJoachim Eastwood return NOTIFY_DONE; 56c392b65bSJoachim Eastwood } 57c392b65bSJoachim Eastwood 58c392b65bSJoachim Eastwood /* 59c392b65bSJoachim Eastwood * The LPC18xx RGU has mostly self-deasserting resets except for the 60c392b65bSJoachim Eastwood * two reset lines going to the internal Cortex-M0 cores. 61c392b65bSJoachim Eastwood * 62c392b65bSJoachim Eastwood * To prevent the M0 core resets from accidentally getting deasserted 63c392b65bSJoachim Eastwood * status register must be check and bits in control register set to 64c392b65bSJoachim Eastwood * preserve the state. 65c392b65bSJoachim Eastwood */ 66c392b65bSJoachim Eastwood static int lpc18xx_rgu_setclear_reset(struct reset_controller_dev *rcdev, 67c392b65bSJoachim Eastwood unsigned long id, bool set) 68c392b65bSJoachim Eastwood { 69c392b65bSJoachim Eastwood struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev); 70c392b65bSJoachim Eastwood u32 stat_offset = LPC18XX_RGU_ACTIVE_STATUS0; 71c392b65bSJoachim Eastwood u32 ctrl_offset = LPC18XX_RGU_CTRL0; 72c392b65bSJoachim Eastwood unsigned long flags; 73c392b65bSJoachim Eastwood u32 stat, rst_bit; 74c392b65bSJoachim Eastwood 75c392b65bSJoachim Eastwood stat_offset += (id / LPC18XX_RGU_RESETS_PER_REG) * sizeof(u32); 76c392b65bSJoachim Eastwood ctrl_offset += (id / LPC18XX_RGU_RESETS_PER_REG) * sizeof(u32); 77c392b65bSJoachim Eastwood rst_bit = 1 << (id % LPC18XX_RGU_RESETS_PER_REG); 78c392b65bSJoachim Eastwood 79c392b65bSJoachim Eastwood spin_lock_irqsave(&rc->lock, flags); 80c392b65bSJoachim Eastwood stat = ~readl(rc->base + stat_offset); 81c392b65bSJoachim Eastwood if (set) 82c392b65bSJoachim Eastwood writel(stat | rst_bit, rc->base + ctrl_offset); 83c392b65bSJoachim Eastwood else 84c392b65bSJoachim Eastwood writel(stat & ~rst_bit, rc->base + ctrl_offset); 85c392b65bSJoachim Eastwood spin_unlock_irqrestore(&rc->lock, flags); 86c392b65bSJoachim Eastwood 87c392b65bSJoachim Eastwood return 0; 88c392b65bSJoachim Eastwood } 89c392b65bSJoachim Eastwood 90c392b65bSJoachim Eastwood static int lpc18xx_rgu_assert(struct reset_controller_dev *rcdev, 91c392b65bSJoachim Eastwood unsigned long id) 92c392b65bSJoachim Eastwood { 93c392b65bSJoachim Eastwood return lpc18xx_rgu_setclear_reset(rcdev, id, true); 94c392b65bSJoachim Eastwood } 95c392b65bSJoachim Eastwood 96c392b65bSJoachim Eastwood static int lpc18xx_rgu_deassert(struct reset_controller_dev *rcdev, 97c392b65bSJoachim Eastwood unsigned long id) 98c392b65bSJoachim Eastwood { 99c392b65bSJoachim Eastwood return lpc18xx_rgu_setclear_reset(rcdev, id, false); 100c392b65bSJoachim Eastwood } 101c392b65bSJoachim Eastwood 102c392b65bSJoachim Eastwood /* Only M0 cores require explicit reset deassert */ 103c392b65bSJoachim Eastwood static int lpc18xx_rgu_reset(struct reset_controller_dev *rcdev, 104c392b65bSJoachim Eastwood unsigned long id) 105c392b65bSJoachim Eastwood { 106c392b65bSJoachim Eastwood struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev); 107c392b65bSJoachim Eastwood 108c392b65bSJoachim Eastwood lpc18xx_rgu_assert(rcdev, id); 109c392b65bSJoachim Eastwood udelay(rc->delay_us); 110c392b65bSJoachim Eastwood 111c392b65bSJoachim Eastwood switch (id) { 112c392b65bSJoachim Eastwood case LPC43XX_RGU_M0SUB_RST: 113c392b65bSJoachim Eastwood case LPC43XX_RGU_M0APP_RST: 114c392b65bSJoachim Eastwood lpc18xx_rgu_setclear_reset(rcdev, id, false); 115c392b65bSJoachim Eastwood } 116c392b65bSJoachim Eastwood 117c392b65bSJoachim Eastwood return 0; 118c392b65bSJoachim Eastwood } 119c392b65bSJoachim Eastwood 120c392b65bSJoachim Eastwood static int lpc18xx_rgu_status(struct reset_controller_dev *rcdev, 121c392b65bSJoachim Eastwood unsigned long id) 122c392b65bSJoachim Eastwood { 123c392b65bSJoachim Eastwood struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev); 124c392b65bSJoachim Eastwood u32 bit, offset = LPC18XX_RGU_ACTIVE_STATUS0; 125c392b65bSJoachim Eastwood 126c392b65bSJoachim Eastwood offset += (id / LPC18XX_RGU_RESETS_PER_REG) * sizeof(u32); 127c392b65bSJoachim Eastwood bit = 1 << (id % LPC18XX_RGU_RESETS_PER_REG); 128c392b65bSJoachim Eastwood 129c392b65bSJoachim Eastwood return !(readl(rc->base + offset) & bit); 130c392b65bSJoachim Eastwood } 131c392b65bSJoachim Eastwood 1321a55cad1SPhilipp Zabel static const struct reset_control_ops lpc18xx_rgu_ops = { 133c392b65bSJoachim Eastwood .reset = lpc18xx_rgu_reset, 134c392b65bSJoachim Eastwood .assert = lpc18xx_rgu_assert, 135c392b65bSJoachim Eastwood .deassert = lpc18xx_rgu_deassert, 136c392b65bSJoachim Eastwood .status = lpc18xx_rgu_status, 137c392b65bSJoachim Eastwood }; 138c392b65bSJoachim Eastwood 139c392b65bSJoachim Eastwood static int lpc18xx_rgu_probe(struct platform_device *pdev) 140c392b65bSJoachim Eastwood { 141c392b65bSJoachim Eastwood struct lpc18xx_rgu_data *rc; 142c392b65bSJoachim Eastwood u32 fcclk, firc; 143c392b65bSJoachim Eastwood int ret; 144c392b65bSJoachim Eastwood 145c392b65bSJoachim Eastwood rc = devm_kzalloc(&pdev->dev, sizeof(*rc), GFP_KERNEL); 146c392b65bSJoachim Eastwood if (!rc) 147c392b65bSJoachim Eastwood return -ENOMEM; 148c392b65bSJoachim Eastwood 149*68fda5a9SYe Xingchen rc->base = devm_platform_ioremap_resource(pdev, 0); 150c392b65bSJoachim Eastwood if (IS_ERR(rc->base)) 151c392b65bSJoachim Eastwood return PTR_ERR(rc->base); 152c392b65bSJoachim Eastwood 153c392b65bSJoachim Eastwood rc->clk_reg = devm_clk_get(&pdev->dev, "reg"); 154c392b65bSJoachim Eastwood if (IS_ERR(rc->clk_reg)) { 155c392b65bSJoachim Eastwood dev_err(&pdev->dev, "reg clock not found\n"); 156c392b65bSJoachim Eastwood return PTR_ERR(rc->clk_reg); 157c392b65bSJoachim Eastwood } 158c392b65bSJoachim Eastwood 159c392b65bSJoachim Eastwood rc->clk_delay = devm_clk_get(&pdev->dev, "delay"); 160c392b65bSJoachim Eastwood if (IS_ERR(rc->clk_delay)) { 161c392b65bSJoachim Eastwood dev_err(&pdev->dev, "delay clock not found\n"); 162c392b65bSJoachim Eastwood return PTR_ERR(rc->clk_delay); 163c392b65bSJoachim Eastwood } 164c392b65bSJoachim Eastwood 165c392b65bSJoachim Eastwood ret = clk_prepare_enable(rc->clk_reg); 166c392b65bSJoachim Eastwood if (ret) { 167c392b65bSJoachim Eastwood dev_err(&pdev->dev, "unable to enable reg clock\n"); 168c392b65bSJoachim Eastwood return ret; 169c392b65bSJoachim Eastwood } 170c392b65bSJoachim Eastwood 171c392b65bSJoachim Eastwood ret = clk_prepare_enable(rc->clk_delay); 172c392b65bSJoachim Eastwood if (ret) { 173c392b65bSJoachim Eastwood dev_err(&pdev->dev, "unable to enable delay clock\n"); 174c392b65bSJoachim Eastwood goto dis_clk_reg; 175c392b65bSJoachim Eastwood } 176c392b65bSJoachim Eastwood 177c392b65bSJoachim Eastwood fcclk = clk_get_rate(rc->clk_reg) / USEC_PER_SEC; 178c392b65bSJoachim Eastwood firc = clk_get_rate(rc->clk_delay) / USEC_PER_SEC; 179c392b65bSJoachim Eastwood if (fcclk == 0 || firc == 0) 180c392b65bSJoachim Eastwood rc->delay_us = 2; 181c392b65bSJoachim Eastwood else 182c392b65bSJoachim Eastwood rc->delay_us = DIV_ROUND_UP(fcclk, firc * firc); 183c392b65bSJoachim Eastwood 184c392b65bSJoachim Eastwood spin_lock_init(&rc->lock); 185c392b65bSJoachim Eastwood 186c392b65bSJoachim Eastwood rc->rcdev.owner = THIS_MODULE; 187c392b65bSJoachim Eastwood rc->rcdev.nr_resets = 64; 188c392b65bSJoachim Eastwood rc->rcdev.ops = &lpc18xx_rgu_ops; 189c392b65bSJoachim Eastwood rc->rcdev.of_node = pdev->dev.of_node; 190c392b65bSJoachim Eastwood 191c392b65bSJoachim Eastwood platform_set_drvdata(pdev, rc); 192c392b65bSJoachim Eastwood 193c392b65bSJoachim Eastwood ret = reset_controller_register(&rc->rcdev); 194c392b65bSJoachim Eastwood if (ret) { 195c392b65bSJoachim Eastwood dev_err(&pdev->dev, "unable to register device\n"); 196c392b65bSJoachim Eastwood goto dis_clks; 197c392b65bSJoachim Eastwood } 198c392b65bSJoachim Eastwood 199773fe726SJoachim Eastwood rc->restart_nb.priority = 192, 200773fe726SJoachim Eastwood rc->restart_nb.notifier_call = lpc18xx_rgu_restart, 201773fe726SJoachim Eastwood ret = register_restart_handler(&rc->restart_nb); 202c392b65bSJoachim Eastwood if (ret) 203c392b65bSJoachim Eastwood dev_warn(&pdev->dev, "failed to register restart handler\n"); 204c392b65bSJoachim Eastwood 205c392b65bSJoachim Eastwood return 0; 206c392b65bSJoachim Eastwood 207c392b65bSJoachim Eastwood dis_clks: 208c392b65bSJoachim Eastwood clk_disable_unprepare(rc->clk_delay); 209c392b65bSJoachim Eastwood dis_clk_reg: 210c392b65bSJoachim Eastwood clk_disable_unprepare(rc->clk_reg); 211c392b65bSJoachim Eastwood 212c392b65bSJoachim Eastwood return ret; 213c392b65bSJoachim Eastwood } 214c392b65bSJoachim Eastwood 215c392b65bSJoachim Eastwood static const struct of_device_id lpc18xx_rgu_match[] = { 216c392b65bSJoachim Eastwood { .compatible = "nxp,lpc1850-rgu" }, 217c392b65bSJoachim Eastwood { } 218c392b65bSJoachim Eastwood }; 219c392b65bSJoachim Eastwood 220c392b65bSJoachim Eastwood static struct platform_driver lpc18xx_rgu_driver = { 221c392b65bSJoachim Eastwood .probe = lpc18xx_rgu_probe, 222c392b65bSJoachim Eastwood .driver = { 223c392b65bSJoachim Eastwood .name = "lpc18xx-reset", 224c392b65bSJoachim Eastwood .of_match_table = lpc18xx_rgu_match, 225cdd24f76SPaul Gortmaker .suppress_bind_attrs = true, 226c392b65bSJoachim Eastwood }, 227c392b65bSJoachim Eastwood }; 228cdd24f76SPaul Gortmaker builtin_platform_driver(lpc18xx_rgu_driver); 229