1ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler/*
2ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler * Copyright (C) 1999 ARM Limited
3ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler * Copyright (C) 2000 Deep Blue Solutions Ltd
4ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler * Copyright 2006-2007,2010 Freescale Semiconductor, Inc. All Rights Reserved.
5ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
6ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler * Copyright 2009 Ilya Yanok, Emcraft Systems Ltd, yanok@emcraft.com
7ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler *
8ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler * This program is free software; you can redistribute it and/or modify
9ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler * it under the terms of the GNU General Public License as published by
10ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler * the Free Software Foundation; either version 2 of the License, or
11ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler * (at your option) any later version.
12ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler *
13ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler * This program is distributed in the hope that it will be useful,
14ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler * but WITHOUT ANY WARRANTY; without even the implied warranty of
15ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler * GNU General Public License for more details.
17ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler */
18ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
19ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler#include <linux/kernel.h>
20ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler#include <linux/clk.h>
21ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler#include <linux/io.h>
22ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler#include <linux/err.h>
23ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler#include <linux/delay.h>
24ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler#include <linux/init.h>
25ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler#include <linux/module.h>
26ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
27ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler#include <asm/proc-fns.h>
285a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <asm/system_misc.h>
29ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
30ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler#include <mach/mxs.h>
31ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler#include <mach/common.h>
32ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
33ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler#define MX23_CLKCTRL_RESET_OFFSET	0x120
34ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler#define MX28_CLKCTRL_RESET_OFFSET	0x1e0
35ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler#define MXS_CLKCTRL_RESET_CHIP		(1 << 1)
36ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
37ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler#define MXS_MODULE_CLKGATE		(1 << 30)
38ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler#define MXS_MODULE_SFTRST		(1 << 31)
39ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
40ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler#define CLKCTRL_TIMEOUT		10	/* 10 ms */
41ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
42ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winklerstatic void __iomem *mxs_clkctrl_reset_addr;
43ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
44ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler/*
45cb43e23435a66d5ed90f804af9efe9096503979fTomas Winkler * Reset the system. It is called by machine_restart().
46ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler */
47ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winklervoid mxs_restart(char mode, const char *cmd)
48ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler{
49ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	/* reset the chip */
50ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	__mxs_setl(MXS_CLKCTRL_RESET_CHIP, mxs_clkctrl_reset_addr);
510e4817470be8d233fb58b5af7b938185dae94d67Tomas Winkler
52ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	pr_err("Failed to assert the chip reset\n");
53fe45332ed289d91e57eca11bfd1ca75d6e420ab4Tomas Winkler
54fe45332ed289d91e57eca11bfd1ca75d6e420ab4Tomas Winkler	/* Delay to allow the serial port to show the message */
55fe45332ed289d91e57eca11bfd1ca75d6e420ab4Tomas Winkler	mdelay(50);
56fe45332ed289d91e57eca11bfd1ca75d6e420ab4Tomas Winkler
57fe45332ed289d91e57eca11bfd1ca75d6e420ab4Tomas Winkler	/* We'll take a jump through zero as a poor second */
58fe45332ed289d91e57eca11bfd1ca75d6e420ab4Tomas Winkler	soft_restart(0);
59fe45332ed289d91e57eca11bfd1ca75d6e420ab4Tomas Winkler}
60fe45332ed289d91e57eca11bfd1ca75d6e420ab4Tomas Winkler
61fe45332ed289d91e57eca11bfd1ca75d6e420ab4Tomas Winklerstatic int __init mxs_arch_reset_init(void)
62fe45332ed289d91e57eca11bfd1ca75d6e420ab4Tomas Winkler{
63fe45332ed289d91e57eca11bfd1ca75d6e420ab4Tomas Winkler	struct clk *clk;
64fe45332ed289d91e57eca11bfd1ca75d6e420ab4Tomas Winkler
65fe45332ed289d91e57eca11bfd1ca75d6e420ab4Tomas Winkler	mxs_clkctrl_reset_addr = MXS_IO_ADDRESS(MXS_CLKCTRL_BASE_ADDR) +
66fe45332ed289d91e57eca11bfd1ca75d6e420ab4Tomas Winkler				(cpu_is_mx23() ? MX23_CLKCTRL_RESET_OFFSET :
67ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler						 MX28_CLKCTRL_RESET_OFFSET);
68ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
69ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	clk = clk_get_sys("rtc", NULL);
70ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	if (!IS_ERR(clk))
71ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler		clk_prepare_enable(clk);
72ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
73ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	return 0;
74ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler}
75ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winklercore_initcall(mxs_arch_reset_init);
76ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
77ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler/*
78ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler * Clear the bit and poll it cleared.  This is usually called with
79ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler * a reset address and mask being either SFTRST(bit 31) or CLKGATE
80ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler * (bit 30).
81ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler */
82ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winklerstatic int clear_poll_bit(void __iomem *addr, u32 mask)
83ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler{
840df828f670b1fd8c469f3d60472ddca0d0f51fcfTomas Winkler	int timeout = 0x400;
85ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
86ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	/* clear the bit */
87ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	__mxs_clrl(mask, addr);
88ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
89ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	/*
90ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	 * SFTRST needs 3 GPMI clocks to settle, the reference manual
91ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	 * recommends to wait 1us.
9251f50f815778b91c699fbcc3aac0dda891a7b795Tejun Heo	 */
93ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	udelay(1);
94ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
95ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	/* poll the bit becoming clear */
96ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	while ((__raw_readl(addr) & mask) && --timeout)
97ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler		/* nothing */;
98ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
99ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	return !timeout;
100ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler}
101ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
102ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winklerint mxs_reset_block(void __iomem *reset_addr)
103ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler{
104ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	int ret;
105ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	int timeout = 0x400;
106ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
107ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	/* clear and poll SFTRST */
108ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	ret = clear_poll_bit(reset_addr, MXS_MODULE_SFTRST);
109ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	if (unlikely(ret))
110ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler		goto error;
111ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
112ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	/* clear CLKGATE */
113ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	__mxs_clrl(MXS_MODULE_CLKGATE, reset_addr);
114ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
115ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	/* set SFTRST to reset the block */
116ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	__mxs_setl(MXS_MODULE_SFTRST, reset_addr);
117ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	udelay(1);
118ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
119ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	/* poll CLKGATE becoming set */
120ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	while ((!(__raw_readl(reset_addr) & MXS_MODULE_CLKGATE)) && --timeout)
121ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler		/* nothing */;
122ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	if (unlikely(!timeout))
123ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler		goto error;
124ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
125ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	/* clear and poll SFTRST */
126ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	ret = clear_poll_bit(reset_addr, MXS_MODULE_SFTRST);
127ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	if (unlikely(ret))
128ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler		goto error;
129ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
130ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	/* clear and poll CLKGATE */
131ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	ret = clear_poll_bit(reset_addr, MXS_MODULE_CLKGATE);
132ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	if (unlikely(ret))
133ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler		goto error;
134ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
135ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	return 0;
136ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
137ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winklererror:
138ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	pr_err("%s(%p): module reset timeout\n", __func__, reset_addr);
139ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	return -ETIMEDOUT;
140ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler}
141ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas WinklerEXPORT_SYMBOL(mxs_reset_block);
142ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
143ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winklerint mxs_clkctrl_timeout(unsigned int reg_offset, unsigned int mask)
144ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler{
145ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	unsigned long timeout = jiffies + msecs_to_jiffies(CLKCTRL_TIMEOUT);
146ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	while (readl_relaxed(MXS_IO_ADDRESS(MXS_CLKCTRL_BASE_ADDR)
147ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler						+ reg_offset) & mask) {
148ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler		if (time_after(jiffies, timeout)) {
149ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler			pr_err("Timeout at CLKCTRL + 0x%x\n", reg_offset);
150ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler			return -ETIMEDOUT;
151ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler		}
152ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	}
153ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler
154ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler	return 0;
1550df828f670b1fd8c469f3d60472ddca0d0f51fcfTomas Winkler}
156ab69a5ae2bdc0b5e20e935a7b75f30aa3f4c3baeTomas Winkler