From patchwork Mon Jan 6 18:38:38 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Heiko_St=C3=BCbner?= X-Patchwork-Id: 3440181 Return-Path: X-Original-To: patchwork-linux-samsung-soc@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id ACBA6C02DC for ; Mon, 6 Jan 2014 18:38:58 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 4FD522016D for ; Mon, 6 Jan 2014 18:38:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C6A5920109 for ; Mon, 6 Jan 2014 18:38:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753592AbaAFSiz (ORCPT ); Mon, 6 Jan 2014 13:38:55 -0500 Received: from gloria.sntech.de ([95.129.55.99]:56021 "EHLO gloria.sntech.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753298AbaAFSiy (ORCPT ); Mon, 6 Jan 2014 13:38:54 -0500 Received: from ip545477c2.speed.planet.nl ([84.84.119.194] helo=phil.localnet) by gloria.sntech.de with esmtpsa (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.80) (envelope-from ) id 1W0F4b-0002et-To; Mon, 06 Jan 2014 19:38:49 +0100 From: Heiko =?ISO-8859-1?Q?St=FCbner?= To: kgene.kim@samsung.com Cc: linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org Subject: [PATCH 2/5] ARM: S3C24XX: add generic handler for swrst resets Date: Mon, 06 Jan 2014 19:38:38 +0100 Message-ID: <1569032.VYgrksRbsn@phil> User-Agent: KMail/4.11.3 (Linux/3.11-2-amd64; KDE/4.11.3; x86_64; ; ) In-Reply-To: <3105326.uFdOVLyXH8@phil> References: <3105326.uFdOVLyXH8@phil> MIME-Version: 1.0 Sender: linux-samsung-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-samsung-soc@vger.kernel.org X-Spam-Status: No, score=-7.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Previously the s3c24xx socs using the swrst machnism simply wrote the needed value to a statically mapped register. To generalize and make it usable in the dt case create a reset handler similar to the already existing watchdog-reset used by different samsung architectures. Signed-off-by: Heiko Stuebner --- arch/arm/mach-s3c24xx/Kconfig | 5 ++ arch/arm/mach-s3c24xx/Makefile | 1 + arch/arm/mach-s3c24xx/common.h | 16 ++++ arch/arm/mach-s3c24xx/swrst-reset.c | 160 +++++++++++++++++++++++++++++++++++ 4 files changed, 182 insertions(+) create mode 100644 arch/arm/mach-s3c24xx/swrst-reset.c diff --git a/arch/arm/mach-s3c24xx/Kconfig b/arch/arm/mach-s3c24xx/Kconfig index e19e314..bb0f653 100644 --- a/arch/arm/mach-s3c24xx/Kconfig +++ b/arch/arm/mach-s3c24xx/Kconfig @@ -30,6 +30,11 @@ config S3C2410_COMMON_DCLK Temporary symbol to build the dclk driver based on the common clock framework. +config S3C24XX_SWRST + bool + help + Handle resets using the swrst register available on some s3c24xx SoCs. + menu "SAMSUNG S3C24XX SoCs Support" comment "S3C24XX SoCs" diff --git a/arch/arm/mach-s3c24xx/Makefile b/arch/arm/mach-s3c24xx/Makefile index 2235d0d..9cc1d58 100644 --- a/arch/arm/mach-s3c24xx/Makefile +++ b/arch/arm/mach-s3c24xx/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_CPU_S3C2443) += s3c2443.o # PM obj-$(CONFIG_PM) += pm.o irq-pm.o sleep.o +obj-$(CONFIG_S3C24XX_SWRST) += swrst-reset.o # common code diff --git a/arch/arm/mach-s3c24xx/common.h b/arch/arm/mach-s3c24xx/common.h index 0f548c5..caf1534 100644 --- a/arch/arm/mach-s3c24xx/common.h +++ b/arch/arm/mach-s3c24xx/common.h @@ -131,4 +131,20 @@ void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f, void __iomem *reg_base); #endif +#ifdef CONFIG_S3C24XX_SWRST +void s3c24xx_swrst_reset(void); +bool s3c24xx_swrst_reset_available(void); +void s3c24xx_swrst_reset_of_init(void); +void s3c24xx_swrst_reset_init(void __iomem *base, bool is_s3c2412); +#else +static inline void s3c24xx_swrst_reset(void) {} +static inline bool s3c24xx_swrst_reset_available(void) +{ + return false; +} +static inline void s3c24xx_swrst_reset_of_init(void) {} +static inline void s3c24xx_swrst_reset_init(void __iomem *base, + bool is_s3c2412) {} +#endif + #endif /* __ARCH_ARM_MACH_S3C24XX_COMMON_H */ diff --git a/arch/arm/mach-s3c24xx/swrst-reset.c b/arch/arm/mach-s3c24xx/swrst-reset.c new file mode 100644 index 0000000..d027c4a --- /dev/null +++ b/arch/arm/mach-s3c24xx/swrst-reset.c @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include +#include + +/* + * Although the manuals state that the string to write to the register + * is soc-specific, at least the s3c2416 and s3c2450 do not seem to care + * what gets written to the register and have been using the s3c2443 + * string all along. + */ +#define S3C2412_SWRST_RESET (0x533C2412) +#define S3C2443_SWRST_RESET (0x533C2443) + +enum s3c_cpu_type { + TYPE_S3C2412, + TYPE_S3C2443, +}; + +struct s3c24xx_swrst_drv_data { + int cpu_type; +}; + +struct s3c2412_rst_clocks { + const char *clk; + const char *new_parent; +}; + +/* S3C2412 errata "Watch-dog/Software Reset Problem" specifies + * that this reset must be done with the SYSCLK sourced from + * EXTCLK instead of FOUT to avoid a glitch in the reset + * mechanism. + * + * See the watchdog section of the S3C2412 manual for more + * information on this fix. + * + * The proposed fix is to write "0" to the clksrc register, + * to reset the sysclk "which generates the ARMCLK, HCLK, PCLK". + * Translated to the clock implementation, this looks like: + */ +struct s3c2412_rst_clocks s3c2412_clocks[] = { + { "mdivclk", "xti" }, + { "msysclk", "mdivclk" }, +}; + +static void __iomem *swrst_base; +static int swrst_type; + +void s3c24xx_swrst_reset(void) +{ + int i; + bool has_faults = true; + + if (!swrst_base) { + pr_err("%s: swrst reset not initialized\n", __func__); + /* delay to allow the serial port to show the message */ + mdelay(50); + return; + } + + switch (swrst_type) { + case TYPE_S3C2412: + /* handle the needed clock changes */ + for (i = 0; i < ARRAY_SIZE(s3c2412_clocks); i++) { + struct s3c2412_rst_clocks *entry = &s3c2412_clocks[i]; + struct clk *clk, *new_parent; + int ret; + + clk = clk_get(NULL, entry->clk); + if (IS_ERR(clk)) { + pr_err("s3c24xx-swrst: could not get clock %s, err %ld\n", + entry->clk, PTR_ERR(clk)); + has_faults = true; + continue; + } + + new_parent = clk_get(NULL, entry->new_parent); + if (IS_ERR(new_parent)) { + pr_err("s3c24xx-swrst: could not get clock %s, err %ld\n", + entry->new_parent, PTR_ERR(new_parent)); + has_faults = true; + clk_put(clk); + continue; + } + + ret = clk_set_parent(clk, new_parent); + if (ret) { + pr_err("s3c24xx-swrst: could not set the parent clock of %s to %s, err %d\n", + entry->clk, entry->new_parent, ret); + has_faults = true; + } + + clk_put(new_parent); + clk_put(clk); + } + + if (has_faults) { + pr_warn("s3c24xx-swrst: some clocks could not be set to the needed parent.\n"); + pr_warn("s3c24xx-swrst: this can trigger a glitch in the s3c2412 soc\n"); + } + + writel(S3C2412_SWRST_RESET, swrst_base); + break; + case TYPE_S3C2443: + writel(S3C2443_SWRST_RESET, swrst_base); + break; + } +} + +bool s3c24xx_swrst_reset_available(void) +{ + return !!swrst_base; +} + +#ifdef CONFIG_OF +static struct s3c24xx_swrst_drv_data s3c24xx_swrst_drv_data_array[] = { + [TYPE_S3C2412] = { TYPE_S3C2412 }, + [TYPE_S3C2443] = { TYPE_S3C2443 }, +}; + +static const struct of_device_id s3c24xx_swrst_match[] = { + { + .compatible = "samsung,s3c2412-swrst", + .data = &s3c24xx_swrst_drv_data_array[TYPE_S3C2412], + }, { + .compatible = "samsung,s3c2443-swrst", + .data = &s3c24xx_swrst_drv_data_array[TYPE_S3C2443], + }, + {}, +}; + +void __init s3c24xx_swrst_reset_of_init(void) +{ + struct device_node *np; + const struct of_device_id *match; + struct s3c24xx_swrst_drv_data *data; + + np = of_find_matching_node_and_match(NULL, s3c24xx_swrst_match, &match); + if (!np) + return; + + data = (struct s3c24xx_swrst_drv_data *)match->data; + swrst_type = data->cpu_type; + + swrst_base = of_iomap(np, 0); + if (!swrst_base) { + pr_err("%s: failed to map swrst register\n", __func__); + return; + } + +} +#endif + +void __init s3c24xx_swrst_reset_init(void __iomem *base, bool is_s3c2412) +{ + swrst_base = base; + swrst_type = (is_s3c2412) ? TYPE_S3C2412 : TYPE_S3C2443; +}