/* * (C) Copyright 2002 * Sysgo Real-Time Solutions, GmbH * Marius Groeger * * (C) Copyright 2002 * Sysgo Real-Time Solutions, GmbH * Alex Zuepke * * (C) Copyright 2002 * Gary Jennejohn, DENX Software Engineering, * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include #include #include #include #include #include #include #include /* Part 1: Registers */ # define GPT_TCTL 0x00 # define GPT_TPRER 0x04 /* Part 2: Bitfields */ #define TCTL_SWR (1 << 15) /* Software reset */ #define IMX1_TCTL_FRR (1 << 8) /* Freerun / restart */ #define IMX31_TCTL_FRR (1 << 9) /* Freerun / restart */ #define IMX1_TCTL_CLKSOURCE_IPG (1 << 1) /* Clock source bit position */ #define IMX31_TCTL_CLKSOURCE_IPG (1 << 6) /* Clock source bit position */ #define TCTL_TEN (1 << 0) /* Timer enable */ struct imx_gpt_regs { unsigned int tcn; uint32_t tctl_val; }; static struct imx_gpt_regs regs_imx1 = { .tcn = 0x10, .tctl_val = IMX1_TCTL_FRR | IMX1_TCTL_CLKSOURCE_IPG | TCTL_TEN, }; static struct imx_gpt_regs regs_imx31 = { .tcn = 0x24, .tctl_val = IMX31_TCTL_FRR | IMX31_TCTL_CLKSOURCE_IPG | TCTL_TEN, }; static struct imx_gpt_regs *regs; static void __iomem *timer_base; static uint64_t imx_clocksource_read(void) { return readl(timer_base + regs->tcn); } static struct clocksource cs = { .read = imx_clocksource_read, .mask = CLOCKSOURCE_MASK(32), .shift = 10, }; static int imx_clocksource_clock_change(struct notifier_block *nb, unsigned long event, void *data) { cs.mult = clocksource_hz2mult(imx_get_gptclk(), cs.shift); return 0; } static struct notifier_block imx_clock_notifier = { .notifier_call = imx_clocksource_clock_change, }; static int imx_gpt_probe(struct device_d *dev) { int i; int ret; /* one timer is enough */ if (timer_base) return -EBUSY; ret = dev_get_drvdata(dev, (unsigned long *)®s); if (ret) return ret; timer_base = dev_request_mem_region(dev, 0); /* setup GP Timer 1 */ writel(TCTL_SWR, timer_base + GPT_TCTL); #ifdef CONFIG_ARCH_IMX21 PCCR1 |= PCCR1_GPT1_EN; #endif #ifdef CONFIG_ARCH_IMX27 PCCR0 |= PCCR0_GPT1_EN; PCCR1 |= PCCR1_PERCLK1_EN; #endif #ifdef CONFIG_ARCH_IMX25 writel(readl(IMX_CCM_BASE + CCM_CGCR1) | (1 << 19), IMX_CCM_BASE + CCM_CGCR1); #endif for (i = 0; i < 100; i++) writel(0, timer_base + GPT_TCTL); /* We have no udelay by now */ writel(0, timer_base + GPT_TPRER); writel(regs->tctl_val, timer_base + GPT_TCTL); cs.mult = clocksource_hz2mult(imx_get_gptclk(), cs.shift); init_clock(&cs); clock_register_client(&imx_clock_notifier); return 0; } static __maybe_unused struct of_device_id imx_gpt_dt_ids[] = { { .compatible = "fsl,imx1-gpt", .data = (unsigned long)®s_imx1, }, { .compatible = "fsl,imx31-gpt", .data = (unsigned long)®s_imx31, }, { /* sentinel */ } }; static struct platform_device_id imx_gpt_ids[] = { { .name = "imx1-gpt", .driver_data = (unsigned long)®s_imx1, }, { .name = "imx31-gpt", .driver_data = (unsigned long)®s_imx31, }, { /* sentinel */ }, }; static struct driver_d imx_gpt_driver = { .name = "imx-gpt", .probe = imx_gpt_probe, .of_compatible = DRV_OF_COMPAT(imx_gpt_dt_ids), .id_table = imx_gpt_ids, }; static int imx_gpt_init(void) { return register_driver(&imx_gpt_driver); } coredevice_initcall(imx_gpt_init); /* * Watchdog Registers */ #ifdef CONFIG_ARCH_IMX1 #define WDOG_WCR 0x00 /* Watchdog Control Register */ #define WDOG_WSR 0x04 /* Watchdog Service Register */ #define WDOG_WSTR 0x08 /* Watchdog Status Register */ #define WDOG_WCR_WDE (1 << 0) #else #define WDOG_WCR 0x00 /* Watchdog Control Register */ #define WDOG_WSR 0x02 /* Watchdog Service Register */ #define WDOG_WSTR 0x04 /* Watchdog Status Register */ #define WDOG_WCR_WDE (1 << 2) #endif /* * Reset the cpu by setting up the watchdog timer and let it time out */ void __noreturn reset_cpu (unsigned long addr) { void __iomem *wdt = IOMEM(IMX_WDT_BASE); /* Disable watchdog and set Time-Out field to 0 */ writew(0x0, wdt + WDOG_WCR); /* Write Service Sequence */ writew(0x5555, wdt + WDOG_WSR); writew(0xaaaa, wdt + WDOG_WSR); /* Enable watchdog */ writew(WDOG_WCR_WDE, wdt + WDOG_WCR); while (1); /*NOTREACHED*/ } EXPORT_SYMBOL(reset_cpu);