1d2912cb1SThomas Gleixner// SPDX-License-Identifier: GPL-2.0-only
275f10b46SDmitry Baryshkov#include <linux/kernel.h>
375f10b46SDmitry Baryshkov#include <linux/module.h>
475f10b46SDmitry Baryshkov#include <linux/delay.h>
575f10b46SDmitry Baryshkov#include <linux/gpio.h>
6fced80c7SRussell King#include <linux/io.h>
775f10b46SDmitry Baryshkov#include <asm/proc-fns.h>
89f97da78SDavid Howells#include <asm/system_misc.h>
975f10b46SDmitry Baryshkov
105bf3df3fSEric Miao#include <mach/regs-ost.h>
11afd2fc02SRussell King#include <mach/reset.h>
12ff88b472SSergei Ianovich#include <mach/smemc.h>
1375f10b46SDmitry Baryshkov
1404fef228SEric Miaounsigned int reset_status;
1504fef228SEric MiaoEXPORT_SYMBOL(reset_status);
1675f10b46SDmitry Baryshkov
1775f10b46SDmitry Baryshkovstatic void do_hw_reset(void);
1875f10b46SDmitry Baryshkov
1975f10b46SDmitry Baryshkovstatic int reset_gpio = -1;
2075f10b46SDmitry Baryshkov
21216e3b7aSDaniel Ribeiroint init_gpio_reset(int gpio, int output, int level)
2275f10b46SDmitry Baryshkov{
2375f10b46SDmitry Baryshkov	int rc;
2475f10b46SDmitry Baryshkov
2575f10b46SDmitry Baryshkov	rc = gpio_request(gpio, "reset generator");
2675f10b46SDmitry Baryshkov	if (rc) {
2775f10b46SDmitry Baryshkov		printk(KERN_ERR "Can't request reset_gpio\n");
2875f10b46SDmitry Baryshkov		goto out;
2975f10b46SDmitry Baryshkov	}
3075f10b46SDmitry Baryshkov
3169fc7eedSDmitry Baryshkov	if (output)
32216e3b7aSDaniel Ribeiro		rc = gpio_direction_output(gpio, level);
3369fc7eedSDmitry Baryshkov	else
3469fc7eedSDmitry Baryshkov		rc = gpio_direction_input(gpio);
3575f10b46SDmitry Baryshkov	if (rc) {
3669fc7eedSDmitry Baryshkov		printk(KERN_ERR "Can't configure reset_gpio\n");
3775f10b46SDmitry Baryshkov		gpio_free(gpio);
3875f10b46SDmitry Baryshkov		goto out;
3975f10b46SDmitry Baryshkov	}
4075f10b46SDmitry Baryshkov
4175f10b46SDmitry Baryshkovout:
4275f10b46SDmitry Baryshkov	if (!rc)
4375f10b46SDmitry Baryshkov		reset_gpio = gpio;
4475f10b46SDmitry Baryshkov
4575f10b46SDmitry Baryshkov	return rc;
4675f10b46SDmitry Baryshkov}
4775f10b46SDmitry Baryshkov
4875f10b46SDmitry Baryshkov/*
4975f10b46SDmitry Baryshkov * Trigger GPIO reset.
5075f10b46SDmitry Baryshkov * This covers various types of logic connecting gpio pin
5175f10b46SDmitry Baryshkov * to RESET pins (nRESET or GPIO_RESET):
5275f10b46SDmitry Baryshkov */
5375f10b46SDmitry Baryshkovstatic void do_gpio_reset(void)
5475f10b46SDmitry Baryshkov{
5575f10b46SDmitry Baryshkov	BUG_ON(reset_gpio == -1);
5675f10b46SDmitry Baryshkov
5775f10b46SDmitry Baryshkov	/* drive it low */
5875f10b46SDmitry Baryshkov	gpio_direction_output(reset_gpio, 0);
5975f10b46SDmitry Baryshkov	mdelay(2);
6075f10b46SDmitry Baryshkov	/* rising edge or drive high */
6175f10b46SDmitry Baryshkov	gpio_set_value(reset_gpio, 1);
6275f10b46SDmitry Baryshkov	mdelay(2);
6375f10b46SDmitry Baryshkov	/* falling edge */
6475f10b46SDmitry Baryshkov	gpio_set_value(reset_gpio, 0);
6575f10b46SDmitry Baryshkov
6675f10b46SDmitry Baryshkov	/* give it some time */
6775f10b46SDmitry Baryshkov	mdelay(10);
6875f10b46SDmitry Baryshkov
6975f10b46SDmitry Baryshkov	WARN_ON(1);
7075f10b46SDmitry Baryshkov	/* fallback */
7175f10b46SDmitry Baryshkov	do_hw_reset();
7275f10b46SDmitry Baryshkov}
7375f10b46SDmitry Baryshkov
7475f10b46SDmitry Baryshkovstatic void do_hw_reset(void)
7575f10b46SDmitry Baryshkov{
7675f10b46SDmitry Baryshkov	/* Initialize the watchdog and let it fire */
773169663aSRussell King	writel_relaxed(OWER_WME, OWER);
783169663aSRussell King	writel_relaxed(OSSR_M3, OSSR);
793169663aSRussell King	/* ... in 100 ms */
803169663aSRussell King	writel_relaxed(readl_relaxed(OSCR) + 368640, OSMR3);
81ff88b472SSergei Ianovich	/*
82ff88b472SSergei Ianovich	 * SDRAM hangs on watchdog reset on Marvell PXA270 (erratum 71)
83ff88b472SSergei Ianovich	 * we put SDRAM into self-refresh to prevent that
84ff88b472SSergei Ianovich	 */
85ff88b472SSergei Ianovich	while (1)
86ff88b472SSergei Ianovich		writel_relaxed(MDREFR_SLFRSH, MDREFR);
8775f10b46SDmitry Baryshkov}
8875f10b46SDmitry Baryshkov
897b6d864bSRobin Holtvoid pxa_restart(enum reboot_mode mode, const char *cmd)
9075f10b46SDmitry Baryshkov{
91271a74fcSRussell King	local_irq_disable();
92271a74fcSRussell King	local_fiq_disable();
93271a74fcSRussell King
9404fef228SEric Miao	clear_reset_status(RESET_STATUS_ALL);
9575f10b46SDmitry Baryshkov
9675f10b46SDmitry Baryshkov	switch (mode) {
977b6d864bSRobin Holt	case REBOOT_SOFT:
9875f10b46SDmitry Baryshkov		/* Jump into ROM at address 0 */
99e879c862SRussell King		soft_restart(0);
10075f10b46SDmitry Baryshkov		break;
1017b6d864bSRobin Holt	case REBOOT_GPIO:
10275f10b46SDmitry Baryshkov		do_gpio_reset();
10375f10b46SDmitry Baryshkov		break;
1047b6d864bSRobin Holt	case REBOOT_HARD:
10528105fdaSJaya Kumar	default:
10628105fdaSJaya Kumar		do_hw_reset();
10728105fdaSJaya Kumar		break;
10875f10b46SDmitry Baryshkov	}
10975f10b46SDmitry Baryshkov}
110