Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * TI keystone reboot driver
0004  *
0005  * Copyright (C) 2014 Texas Instruments Incorporated. https://www.ti.com/
0006  *
0007  * Author: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
0008  */
0009 
0010 #include <linux/io.h>
0011 #include <linux/module.h>
0012 #include <linux/notifier.h>
0013 #include <linux/reboot.h>
0014 #include <linux/regmap.h>
0015 #include <linux/mfd/syscon.h>
0016 #include <linux/of_platform.h>
0017 
0018 #define RSTYPE_RG           0x0
0019 #define RSCTRL_RG           0x4
0020 #define RSCFG_RG            0x8
0021 #define RSISO_RG            0xc
0022 
0023 #define RSCTRL_KEY_MASK         0x0000ffff
0024 #define RSCTRL_RESET_MASK       BIT(16)
0025 #define RSCTRL_KEY          0x5a69
0026 
0027 #define RSMUX_OMODE_MASK        0xe
0028 #define RSMUX_OMODE_RESET_ON        0xa
0029 #define RSMUX_OMODE_RESET_OFF       0x0
0030 #define RSMUX_LOCK_MASK         0x1
0031 #define RSMUX_LOCK_SET          0x1
0032 
0033 #define RSCFG_RSTYPE_SOFT       0x300f
0034 #define RSCFG_RSTYPE_HARD       0x0
0035 
0036 #define WDT_MUX_NUMBER          0x4
0037 
0038 static int rspll_offset;
0039 static struct regmap *pllctrl_regs;
0040 
0041 /**
0042  * rsctrl_enable_rspll_write - enable access to RSCTRL, RSCFG
0043  * To be able to access to RSCTRL, RSCFG registers
0044  * we have to write a key before
0045  */
0046 static inline int rsctrl_enable_rspll_write(void)
0047 {
0048     return regmap_update_bits(pllctrl_regs, rspll_offset + RSCTRL_RG,
0049                   RSCTRL_KEY_MASK, RSCTRL_KEY);
0050 }
0051 
0052 static int rsctrl_restart_handler(struct notifier_block *this,
0053                   unsigned long mode, void *cmd)
0054 {
0055     /* enable write access to RSTCTRL */
0056     rsctrl_enable_rspll_write();
0057 
0058     /* reset the SOC */
0059     regmap_update_bits(pllctrl_regs, rspll_offset + RSCTRL_RG,
0060                RSCTRL_RESET_MASK, 0);
0061 
0062     return NOTIFY_DONE;
0063 }
0064 
0065 static struct notifier_block rsctrl_restart_nb = {
0066     .notifier_call = rsctrl_restart_handler,
0067     .priority = 128,
0068 };
0069 
0070 static const struct of_device_id rsctrl_of_match[] = {
0071     {.compatible = "ti,keystone-reset", },
0072     {},
0073 };
0074 MODULE_DEVICE_TABLE(of, rsctrl_of_match);
0075 
0076 static int rsctrl_probe(struct platform_device *pdev)
0077 {
0078     int i;
0079     int ret;
0080     u32 val;
0081     unsigned int rg;
0082     u32 rsmux_offset;
0083     struct regmap *devctrl_regs;
0084     struct device *dev = &pdev->dev;
0085     struct device_node *np = dev->of_node;
0086 
0087     if (!np)
0088         return -ENODEV;
0089 
0090     /* get regmaps */
0091     pllctrl_regs = syscon_regmap_lookup_by_phandle(np, "ti,syscon-pll");
0092     if (IS_ERR(pllctrl_regs))
0093         return PTR_ERR(pllctrl_regs);
0094 
0095     devctrl_regs = syscon_regmap_lookup_by_phandle(np, "ti,syscon-dev");
0096     if (IS_ERR(devctrl_regs))
0097         return PTR_ERR(devctrl_regs);
0098 
0099     ret = of_property_read_u32_index(np, "ti,syscon-pll", 1, &rspll_offset);
0100     if (ret) {
0101         dev_err(dev, "couldn't read the reset pll offset!\n");
0102         return -EINVAL;
0103     }
0104 
0105     ret = of_property_read_u32_index(np, "ti,syscon-dev", 1, &rsmux_offset);
0106     if (ret) {
0107         dev_err(dev, "couldn't read the rsmux offset!\n");
0108         return -EINVAL;
0109     }
0110 
0111     /* set soft/hard reset */
0112     val = of_property_read_bool(np, "ti,soft-reset");
0113     val = val ? RSCFG_RSTYPE_SOFT : RSCFG_RSTYPE_HARD;
0114 
0115     ret = rsctrl_enable_rspll_write();
0116     if (ret)
0117         return ret;
0118 
0119     ret = regmap_write(pllctrl_regs, rspll_offset + RSCFG_RG, val);
0120     if (ret)
0121         return ret;
0122 
0123     /* disable a reset isolation for all module clocks */
0124     ret = regmap_write(pllctrl_regs, rspll_offset + RSISO_RG, 0);
0125     if (ret)
0126         return ret;
0127 
0128     /* enable a reset for watchdogs from wdt-list */
0129     for (i = 0; i < WDT_MUX_NUMBER; i++) {
0130         ret = of_property_read_u32_index(np, "ti,wdt-list", i, &val);
0131         if (ret == -EOVERFLOW && !i) {
0132             dev_err(dev, "ti,wdt-list property has to contain at"
0133                 "least one entry\n");
0134             return -EINVAL;
0135         } else if (ret) {
0136             break;
0137         }
0138 
0139         if (val >= WDT_MUX_NUMBER) {
0140             dev_err(dev, "ti,wdt-list property can contain "
0141                 "only numbers < 4\n");
0142             return -EINVAL;
0143         }
0144 
0145         rg = rsmux_offset + val * 4;
0146 
0147         ret = regmap_update_bits(devctrl_regs, rg, RSMUX_OMODE_MASK,
0148                      RSMUX_OMODE_RESET_ON |
0149                      RSMUX_LOCK_SET);
0150         if (ret)
0151             return ret;
0152     }
0153 
0154     ret = register_restart_handler(&rsctrl_restart_nb);
0155     if (ret)
0156         dev_err(dev, "cannot register restart handler (err=%d)\n", ret);
0157 
0158     return ret;
0159 }
0160 
0161 static struct platform_driver rsctrl_driver = {
0162     .probe = rsctrl_probe,
0163     .driver = {
0164         .name = KBUILD_MODNAME,
0165         .of_match_table = rsctrl_of_match,
0166     },
0167 };
0168 module_platform_driver(rsctrl_driver);
0169 
0170 MODULE_AUTHOR("Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>");
0171 MODULE_DESCRIPTION("Texas Instruments keystone reset driver");
0172 MODULE_LICENSE("GPL v2");
0173 MODULE_ALIAS("platform:" KBUILD_MODNAME);