162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci#include <linux/kernel.h> 362306a36Sopenharmony_ci#include <linux/module.h> 462306a36Sopenharmony_ci#include <linux/delay.h> 562306a36Sopenharmony_ci#include <linux/gpio.h> 662306a36Sopenharmony_ci#include <linux/io.h> 762306a36Sopenharmony_ci#include <asm/proc-fns.h> 862306a36Sopenharmony_ci#include <asm/system_misc.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "regs-ost.h" 1162306a36Sopenharmony_ci#include "reset.h" 1262306a36Sopenharmony_ci#include "smemc.h" 1362306a36Sopenharmony_ci#include "generic.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic void do_hw_reset(void); 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic int reset_gpio = -1; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ciint init_gpio_reset(int gpio, int output, int level) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci int rc; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci rc = gpio_request(gpio, "reset generator"); 2462306a36Sopenharmony_ci if (rc) { 2562306a36Sopenharmony_ci printk(KERN_ERR "Can't request reset_gpio\n"); 2662306a36Sopenharmony_ci goto out; 2762306a36Sopenharmony_ci } 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci if (output) 3062306a36Sopenharmony_ci rc = gpio_direction_output(gpio, level); 3162306a36Sopenharmony_ci else 3262306a36Sopenharmony_ci rc = gpio_direction_input(gpio); 3362306a36Sopenharmony_ci if (rc) { 3462306a36Sopenharmony_ci printk(KERN_ERR "Can't configure reset_gpio\n"); 3562306a36Sopenharmony_ci gpio_free(gpio); 3662306a36Sopenharmony_ci goto out; 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ciout: 4062306a36Sopenharmony_ci if (!rc) 4162306a36Sopenharmony_ci reset_gpio = gpio; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci return rc; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* 4762306a36Sopenharmony_ci * Trigger GPIO reset. 4862306a36Sopenharmony_ci * This covers various types of logic connecting gpio pin 4962306a36Sopenharmony_ci * to RESET pins (nRESET or GPIO_RESET): 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_cistatic void do_gpio_reset(void) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci BUG_ON(reset_gpio == -1); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* drive it low */ 5662306a36Sopenharmony_ci gpio_direction_output(reset_gpio, 0); 5762306a36Sopenharmony_ci mdelay(2); 5862306a36Sopenharmony_ci /* rising edge or drive high */ 5962306a36Sopenharmony_ci gpio_set_value(reset_gpio, 1); 6062306a36Sopenharmony_ci mdelay(2); 6162306a36Sopenharmony_ci /* falling edge */ 6262306a36Sopenharmony_ci gpio_set_value(reset_gpio, 0); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci /* give it some time */ 6562306a36Sopenharmony_ci mdelay(10); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci WARN_ON(1); 6862306a36Sopenharmony_ci /* fallback */ 6962306a36Sopenharmony_ci do_hw_reset(); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic void do_hw_reset(void) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci /* Initialize the watchdog and let it fire */ 7562306a36Sopenharmony_ci writel_relaxed(OWER_WME, OWER); 7662306a36Sopenharmony_ci writel_relaxed(OSSR_M3, OSSR); 7762306a36Sopenharmony_ci /* ... in 100 ms */ 7862306a36Sopenharmony_ci writel_relaxed(readl_relaxed(OSCR) + 368640, OSMR3); 7962306a36Sopenharmony_ci /* 8062306a36Sopenharmony_ci * SDRAM hangs on watchdog reset on Marvell PXA270 (erratum 71) 8162306a36Sopenharmony_ci * we put SDRAM into self-refresh to prevent that 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_ci while (1) 8462306a36Sopenharmony_ci writel_relaxed(MDREFR_SLFRSH, MDREFR); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_civoid pxa_restart(enum reboot_mode mode, const char *cmd) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci local_irq_disable(); 9062306a36Sopenharmony_ci local_fiq_disable(); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci clear_reset_status(RESET_STATUS_ALL); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci switch (mode) { 9562306a36Sopenharmony_ci case REBOOT_SOFT: 9662306a36Sopenharmony_ci /* Jump into ROM at address 0 */ 9762306a36Sopenharmony_ci soft_restart(0); 9862306a36Sopenharmony_ci break; 9962306a36Sopenharmony_ci case REBOOT_GPIO: 10062306a36Sopenharmony_ci do_gpio_reset(); 10162306a36Sopenharmony_ci break; 10262306a36Sopenharmony_ci case REBOOT_HARD: 10362306a36Sopenharmony_ci default: 10462306a36Sopenharmony_ci do_hw_reset(); 10562306a36Sopenharmony_ci break; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci} 108