linux/drivers/power/reset/at91-reset.c
<<
>>
Prefs
   1/*
   2 * Atmel AT91 SAM9 & SAMA5 SoCs reset code
   3 *
   4 * Copyright (C) 2007 Atmel Corporation.
   5 * Copyright (C) BitBox Ltd 2010
   6 * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcosoft.com>
   7 * Copyright (C) 2014 Free Electrons
   8 *
   9 * This file is licensed under the terms of the GNU General Public
  10 * License version 2.  This program is licensed "as is" without any
  11 * warranty of any kind, whether express or implied.
  12 */
  13
  14#include <linux/clk.h>
  15#include <linux/io.h>
  16#include <linux/module.h>
  17#include <linux/of_address.h>
  18#include <linux/platform_device.h>
  19#include <linux/reboot.h>
  20
  21#include <soc/at91/at91sam9_ddrsdr.h>
  22#include <soc/at91/at91sam9_sdramc.h>
  23
  24#define AT91_RSTC_CR    0x00            /* Reset Controller Control Register */
  25#define AT91_RSTC_PROCRST       BIT(0)          /* Processor Reset */
  26#define AT91_RSTC_PERRST        BIT(2)          /* Peripheral Reset */
  27#define AT91_RSTC_EXTRST        BIT(3)          /* External Reset */
  28#define AT91_RSTC_KEY           (0xa5 << 24)    /* KEY Password */
  29
  30#define AT91_RSTC_SR    0x04            /* Reset Controller Status Register */
  31#define AT91_RSTC_URSTS         BIT(0)          /* User Reset Status */
  32#define AT91_RSTC_RSTTYP        GENMASK(10, 8)  /* Reset Type */
  33#define AT91_RSTC_NRSTL         BIT(16)         /* NRST Pin Level */
  34#define AT91_RSTC_SRCMP         BIT(17)         /* Software Reset Command in Progress */
  35
  36#define AT91_RSTC_MR    0x08            /* Reset Controller Mode Register */
  37#define AT91_RSTC_URSTEN        BIT(0)          /* User Reset Enable */
  38#define AT91_RSTC_URSTIEN       BIT(4)          /* User Reset Interrupt Enable */
  39#define AT91_RSTC_ERSTL         GENMASK(11, 8)  /* External Reset Length */
  40
  41enum reset_type {
  42        RESET_TYPE_GENERAL      = 0,
  43        RESET_TYPE_WAKEUP       = 1,
  44        RESET_TYPE_WATCHDOG     = 2,
  45        RESET_TYPE_SOFTWARE     = 3,
  46        RESET_TYPE_USER         = 4,
  47};
  48
  49static void __iomem *at91_ramc_base[2], *at91_rstc_base;
  50static struct clk *sclk;
  51
  52/*
  53* unless the SDRAM is cleanly shutdown before we hit the
  54* reset register it can be left driving the data bus and
  55* killing the chance of a subsequent boot from NAND
  56*/
  57static int at91sam9260_restart(struct notifier_block *this, unsigned long mode,
  58                               void *cmd)
  59{
  60        asm volatile(
  61                /* Align to cache lines */
  62                ".balign 32\n\t"
  63
  64                /* Disable SDRAM accesses */
  65                "str    %2, [%0, #" __stringify(AT91_SDRAMC_TR) "]\n\t"
  66
  67                /* Power down SDRAM */
  68                "str    %3, [%0, #" __stringify(AT91_SDRAMC_LPR) "]\n\t"
  69
  70                /* Reset CPU */
  71                "str    %4, [%1, #" __stringify(AT91_RSTC_CR) "]\n\t"
  72
  73                "b      .\n\t"
  74                :
  75                : "r" (at91_ramc_base[0]),
  76                  "r" (at91_rstc_base),
  77                  "r" (1),
  78                  "r" cpu_to_le32(AT91_SDRAMC_LPCB_POWER_DOWN),
  79                  "r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST));
  80
  81        return NOTIFY_DONE;
  82}
  83
  84static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode,
  85                               void *cmd)
  86{
  87        asm volatile(
  88                /*
  89                 * Test wether we have a second RAM controller to care
  90                 * about.
  91                 *
  92                 * First, test that we can dereference the virtual address.
  93                 */
  94                "cmp    %1, #0\n\t"
  95                "beq    1f\n\t"
  96
  97                /* Then, test that the RAM controller is enabled */
  98                "ldr    r0, [%1]\n\t"
  99                "cmp    r0, #0\n\t"
 100
 101                /* Align to cache lines */
 102                ".balign 32\n\t"
 103
 104                /* Disable SDRAM0 accesses */
 105                "1:     str     %3, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t"
 106                /* Power down SDRAM0 */
 107                "       str     %4, [%0, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t"
 108                /* Disable SDRAM1 accesses */
 109                "       strne   %3, [%1, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t"
 110                /* Power down SDRAM1 */
 111                "       strne   %4, [%1, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t"
 112                /* Reset CPU */
 113                "       str     %5, [%2, #" __stringify(AT91_RSTC_CR) "]\n\t"
 114
 115                "       b       .\n\t"
 116                :
 117                : "r" (at91_ramc_base[0]),
 118                  "r" (at91_ramc_base[1]),
 119                  "r" (at91_rstc_base),
 120                  "r" (1),
 121                  "r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN),
 122                  "r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST)
 123                : "r0");
 124
 125        return NOTIFY_DONE;
 126}
 127
 128static int sama5d3_restart(struct notifier_block *this, unsigned long mode,
 129                           void *cmd)
 130{
 131        writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST),
 132               at91_rstc_base);
 133
 134        return NOTIFY_DONE;
 135}
 136
 137static void __init at91_reset_status(struct platform_device *pdev)
 138{
 139        u32 reg = readl(at91_rstc_base + AT91_RSTC_SR);
 140        char *reason;
 141
 142        switch ((reg & AT91_RSTC_RSTTYP) >> 8) {
 143        case RESET_TYPE_GENERAL:
 144                reason = "general reset";
 145                break;
 146        case RESET_TYPE_WAKEUP:
 147                reason = "wakeup";
 148                break;
 149        case RESET_TYPE_WATCHDOG:
 150                reason = "watchdog reset";
 151                break;
 152        case RESET_TYPE_SOFTWARE:
 153                reason = "software reset";
 154                break;
 155        case RESET_TYPE_USER:
 156                reason = "user reset";
 157                break;
 158        default:
 159                reason = "unknown reset";
 160                break;
 161        }
 162
 163        pr_info("AT91: Starting after %s\n", reason);
 164}
 165
 166static const struct of_device_id at91_ramc_of_match[] = {
 167        { .compatible = "atmel,at91sam9260-sdramc", },
 168        { .compatible = "atmel,at91sam9g45-ddramc", },
 169        { /* sentinel */ }
 170};
 171
 172static const struct of_device_id at91_reset_of_match[] = {
 173        { .compatible = "atmel,at91sam9260-rstc", .data = at91sam9260_restart },
 174        { .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart },
 175        { .compatible = "atmel,sama5d3-rstc", .data = sama5d3_restart },
 176        { /* sentinel */ }
 177};
 178
 179static struct notifier_block at91_restart_nb = {
 180        .priority = 192,
 181};
 182
 183static int __init at91_reset_probe(struct platform_device *pdev)
 184{
 185        const struct of_device_id *match;
 186        struct device_node *np;
 187        int ret, idx = 0;
 188
 189        at91_rstc_base = of_iomap(pdev->dev.of_node, 0);
 190        if (!at91_rstc_base) {
 191                dev_err(&pdev->dev, "Could not map reset controller address\n");
 192                return -ENODEV;
 193        }
 194
 195        if (!of_device_is_compatible(pdev->dev.of_node, "atmel,sama5d3-rstc")) {
 196                /* we need to shutdown the ddr controller, so get ramc base */
 197                for_each_matching_node(np, at91_ramc_of_match) {
 198                        at91_ramc_base[idx] = of_iomap(np, 0);
 199                        if (!at91_ramc_base[idx]) {
 200                                dev_err(&pdev->dev, "Could not map ram controller address\n");
 201                                of_node_put(np);
 202                                return -ENODEV;
 203                        }
 204                        idx++;
 205                }
 206        }
 207
 208        match = of_match_node(at91_reset_of_match, pdev->dev.of_node);
 209        at91_restart_nb.notifier_call = match->data;
 210
 211        sclk = devm_clk_get(&pdev->dev, NULL);
 212        if (IS_ERR(sclk))
 213                return PTR_ERR(sclk);
 214
 215        ret = clk_prepare_enable(sclk);
 216        if (ret) {
 217                dev_err(&pdev->dev, "Could not enable slow clock\n");
 218                return ret;
 219        }
 220
 221        ret = register_restart_handler(&at91_restart_nb);
 222        if (ret) {
 223                clk_disable_unprepare(sclk);
 224                return ret;
 225        }
 226
 227        at91_reset_status(pdev);
 228
 229        return 0;
 230}
 231
 232static int __exit at91_reset_remove(struct platform_device *pdev)
 233{
 234        unregister_restart_handler(&at91_restart_nb);
 235        clk_disable_unprepare(sclk);
 236
 237        return 0;
 238}
 239
 240static const struct platform_device_id at91_reset_plat_match[] = {
 241        { "at91-sam9260-reset", (unsigned long)at91sam9260_restart },
 242        { "at91-sam9g45-reset", (unsigned long)at91sam9g45_restart },
 243        { /* sentinel */ }
 244};
 245
 246static struct platform_driver at91_reset_driver = {
 247        .remove = __exit_p(at91_reset_remove),
 248        .driver = {
 249                .name = "at91-reset",
 250                .of_match_table = at91_reset_of_match,
 251        },
 252        .id_table = at91_reset_plat_match,
 253};
 254module_platform_driver_probe(at91_reset_driver, at91_reset_probe);
 255
 256MODULE_AUTHOR("Atmel Corporation");
 257MODULE_DESCRIPTION("Reset driver for Atmel SoCs");
 258MODULE_LICENSE("GPL v2");
 259