* [PATCH 2.6.11.6] CPM2 Timers API
@ 2005-03-31 19:54 Jason McMullan
2005-03-31 20:33 ` Jason McMullan
0 siblings, 1 reply; 3+ messages in thread
From: Jason McMullan @ 2005-03-31 19:54 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1.1: Type: text/plain, Size: 207 bytes --]
Two patches:
cpm-timer.patch:
The base timers API for CPM2 timers
cpm-timer.mpc85xx-devices.patch:
MPC85xx support
--
Jason McMullan <jason.mcmullan@timesys.com>
TimeSys Corporation
[-- Attachment #1.2: cpm-timer.mpc85xx-devices.patch --]
[-- Type: text/x-patch, Size: 4739 bytes --]
Description: MPC85xx support for CPM2 timers
Date: Thu Mar 31 14:49:49 EST 2005
Patches: linux-2.6.12-rc1.bk
Signed-Off-By: Jason McMullan <jason.mcmullan@timesys.com>
Difference summary:
arch/ppc/syslib/mpc85xx_devices.c | 25 +++++++++++++++++++++++++
arch/ppc/syslib/mpc85xx_sys.c | 17 ++++++++++-------
include/asm-ppc/mpc85xx.h | 1 +
3 files changed, 36 insertions(+), 7 deletions(-)
diff -urN -X /home/jmcmullan/dontdiff linux-2.6/arch/ppc/syslib/mpc85xx_devices.c linux-2.6.patch/arch/ppc/syslib/mpc85xx_devices.c
--- linux-2.6/arch/ppc/syslib/mpc85xx_devices.c 2005-03-31 14:06:04.000000000 -0500
+++ linux-2.6.patch/arch/ppc/syslib/mpc85xx_devices.c 2005-03-31 14:42:42.000000000 -0500
@@ -19,6 +19,8 @@
#include <linux/serial_8250.h>
#include <linux/fsl_devices.h>
#include <asm/mpc85xx.h>
+#include <asm/cpm2.h>
+#include <asm/immap_cpm2.h>
#include <asm/irq.h>
#include <asm/ppc_sys.h>
@@ -61,8 +63,14 @@
.iotype = UPIO_MEM,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ,
},
+ [2] = {
+ .flags = 0
+ }
};
+#define CPM2_OFFSET(t) ((void *)(&((cpm2_map_t *)NULL)->t)-NULL)
+#define CPM2_END(t) (CPM2_OFFSET(t)+(sizeof(((cpm2_map_t *)NULL)->t))-1)
+
struct platform_device ppc_sys_platform_devices[] = {
[MPC85xx_TSEC1] = {
.name = "fsl-gianfar",
@@ -534,6 +542,23 @@
},
},
},
+ [MPC85xx_CPM_TIMER] = {
+ .name = "fsl-cpm-timer",
+ .id = 0,
+ .num_resources = 2,
+ .resource = (struct resource[]) {
+ {
+ .start = CPM2_OFFSET(im_cpmtimer),
+ .end = CPM2_END(im_cpmtimer),
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = SIU_INT_TIMER1,
+ .end = SIU_INT_TIMER4,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+ },
#endif /* CONFIG_CPM2 */
};
diff -urN -X /home/jmcmullan/dontdiff linux-2.6/arch/ppc/syslib/mpc85xx_sys.c linux-2.6.patch/arch/ppc/syslib/mpc85xx_sys.c
--- linux-2.6/arch/ppc/syslib/mpc85xx_sys.c 2005-03-31 14:06:04.000000000 -0500
+++ linux-2.6.patch/arch/ppc/syslib/mpc85xx_sys.c 2005-03-31 14:46:53.768274801 -0500
@@ -36,7 +36,7 @@
.ppc_sys_name = "8560",
.mask = 0xFFFF0000,
.value = 0x80700000,
- .num_devices = 19,
+ .num_devices = 20,
.device_list = (enum ppc_sys_devices[])
{
MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1,
@@ -46,13 +46,14 @@
MPC85xx_CPM_SCC2, MPC85xx_CPM_SCC3, MPC85xx_CPM_SCC4,
MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2, MPC85xx_CPM_FCC3,
MPC85xx_CPM_MCC1, MPC85xx_CPM_MCC2,
+ MPC85xx_CPM_TIMER,
},
},
{
.ppc_sys_name = "8541",
.mask = 0xFFFF0000,
.value = 0x80720000,
- .num_devices = 13,
+ .num_devices = 14,
.device_list = (enum ppc_sys_devices[])
{
MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1,
@@ -60,13 +61,14 @@
MPC85xx_PERFMON, MPC85xx_DUART,
MPC85xx_CPM_SPI, MPC85xx_CPM_I2C,
MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2,
+ MPC85xx_CPM_TIMER,
},
},
{
.ppc_sys_name = "8541E",
.mask = 0xFFFF0000,
.value = 0x807A0000,
- .num_devices = 14,
+ .num_devices = 15,
.device_list = (enum ppc_sys_devices[])
{
MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1,
@@ -74,13 +76,14 @@
MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_SEC2,
MPC85xx_CPM_SPI, MPC85xx_CPM_I2C,
MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2,
+ MPC85xx_CPM_TIMER,
},
},
{
.ppc_sys_name = "8555",
.mask = 0xFFFF0000,
.value = 0x80710000,
- .num_devices = 19,
+ .num_devices = 20,
.device_list = (enum ppc_sys_devices[])
{
MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1,
@@ -90,14 +93,14 @@
MPC85xx_CPM_SCC2, MPC85xx_CPM_SCC3,
MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2,
MPC85xx_CPM_SMC1, MPC85xx_CPM_SMC2,
- MPC85xx_CPM_USB,
+ MPC85xx_CPM_USB, MPC85xx_CPM_TIMER,
},
},
{
.ppc_sys_name = "8555E",
.mask = 0xFFFF0000,
.value = 0x80790000,
- .num_devices = 20,
+ .num_devices = 21,
.device_list = (enum ppc_sys_devices[])
{
MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1,
@@ -107,7 +110,7 @@
MPC85xx_CPM_SCC2, MPC85xx_CPM_SCC3,
MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2,
MPC85xx_CPM_SMC1, MPC85xx_CPM_SMC2,
- MPC85xx_CPM_USB,
+ MPC85xx_CPM_USB, MPC85xx_CPM_TIMER,
},
},
{ /* default match */
diff -urN -X /home/jmcmullan/dontdiff linux-2.6/include/asm-ppc/mpc85xx.h linux-2.6.patch/include/asm-ppc/mpc85xx.h
--- linux-2.6/include/asm-ppc/mpc85xx.h 2005-03-31 14:17:00.000000000 -0500
+++ linux-2.6.patch/include/asm-ppc/mpc85xx.h 2005-03-31 14:36:06.000000000 -0500
@@ -127,6 +127,7 @@
MPC85xx_CPM_MCC2,
MPC85xx_CPM_SMC1,
MPC85xx_CPM_SMC2,
+ MPC85xx_CPM_TIMER,
};
#endif /* CONFIG_85xx */
[-- Attachment #1.3: cpm-timer.patch --]
[-- Type: text/x-patch, Size: 16394 bytes --]
Description: CPM2 Timers API
Date: Thu Mar 31 14:49:49 EST 2005
Patches: linux-2.6.12-rc1.bk
Signed-Off-By: Jason McMullan <jason.mcmullan@timesys.com>
Difference summary:
arch/ppc/Kconfig | 6
arch/ppc/syslib/Makefile | 1
arch/ppc/syslib/cpm_timer.c | 522 ++++++++++++++++++++++++++++++++++++++++++++
include/asm-ppc/cpm_timer.h | 74 ++++++
4 files changed, 603 insertions(+)
diff -urN -X /home/jmcmullan/dontdiff linux-2.6/arch/ppc/Kconfig linux-2.6.patch/arch/ppc/Kconfig
--- linux-2.6/arch/ppc/Kconfig 2005-03-31 14:05:48.000000000 -0500
+++ linux-2.6.patch/arch/ppc/Kconfig 2005-03-31 14:50:29.192469198 -0500
@@ -713,6 +713,12 @@
you wish to build a kernel for a machine with a CPM2 coprocessor
on it (826x, 827x, 8560).
+config CPM_TIMER
+ tristate "CPM2 Timers"
+ depends on 8260 || 85xx
+ help
+ Includes kernel support for CPM2 timers
+
config PPC_CHRP
bool
depends on PPC_MULTIPLATFORM
diff -urN -X /home/jmcmullan/dontdiff linux-2.6/arch/ppc/syslib/cpm_timer.c linux-2.6.patch/arch/ppc/syslib/cpm_timer.c
--- linux-2.6/arch/ppc/syslib/cpm_timer.c 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.patch/arch/ppc/syslib/cpm_timer.c 2005-03-31 14:50:29.217463534 -0500
@@ -0,0 +1,522 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#include <asm/io.h>
+#include <asm/cpm2.h>
+#include <asm/cpm_timer.h>
+#include <asm/delay.h>
+#include <asm/ppcboot.h>
+
+#define TGCR_CAS 0x8
+#define TGCR_GM 0x8
+#define TGCR_STP 0x2
+#define TGCR_RST 0x1
+
+#define TMR_PS_MASK 0xff00
+#define TMR_CE_MASK 0xffc0
+#define TMR_CE_DISABLE 0x0000
+#define TMR_CE_RISING 0x0040
+#define TMR_CE_FALLING 0x0080
+#define TMR_CE_BOTH 0x00c0
+#define TMR_OM 0x0020
+#define TMR_ORI 0x0010
+#define TMR_FRR 0x0008
+#define TMR_ICLK_MASK 0x0006
+#define TMR_ICLK_CASCADED 0x0000
+#define TMR_ICLK_INTERNAL 0x0002
+#define TMR_ICLK_INT_DIV_16 0x0004
+#define TMR_ICLK_TIN 0x0006
+#define TMR_GE 0x0001
+
+#define TER_REF 0x0002
+#define TER_CAP 0x0001
+
+/* Timer functions
+ */
+static struct resource cpm_timer_resource = {
+ .name = "CPM Timers",
+ .start = 0,
+ .end = 3,
+};
+
+static struct cpm_timer_s {
+ char name[16];
+ int irq;
+ struct {
+ volatile uint16_t *tmr;
+ volatile uint16_t *ter;
+ } ctrl;
+ union {
+ struct {
+ volatile uint16_t *trr;
+ volatile uint16_t *tcr;
+ volatile uint16_t *tcn;
+ } r16;
+ struct {
+ volatile uint32_t *trr;
+ volatile uint32_t *tcr;
+ volatile uint32_t *tcn;
+ } r32;
+ } data;
+ cpm_timer_f func;
+ void *func_data;
+ int one_shot;
+ cpm_timer_t tm;
+} cpm_timer[4];
+
+static cpmtimer_cpm2_t *timer_base = NULL;
+
+static irqreturn_t cpm_timer_irq(int irq, void *data, struct pt_regs *regs)
+{
+ struct cpm_timer_s *info = data;
+ cpm_timer_f func;
+ uint16_t events = *info->ctrl.ter;
+ void *func_data;
+
+ func_data = info->func_data; /* Order is important here! */
+ func = info->func;
+ if (info->func) {
+ func(info->tm, func_data);
+ }
+
+ if (info->one_shot) {
+ *info->ctrl.tmr &= ~TMR_ORI; /* Disable interrupt */
+ info->func = NULL;
+ info->func_data = NULL;
+ }
+
+ *info->ctrl.ter = events; /* Clear events */
+
+ return IRQ_HANDLED;
+}
+
+/* Allocate a timer.
+ * Pass a timer id, and a reference to a NULL struct resource *
+ * Returns 0 on success, -errno on error
+ */
+EXPORT_SYMBOL(cpm_timer_alloc);
+int cpm_timer_alloc(int timer_id, cpm_timer_t *ptm)
+{
+ struct resource *tm;
+ int err;
+ uint16_t mask;
+
+ tm = kmalloc(sizeof(struct resource)+16, GFP_KERNEL);
+ memset(tm,0,sizeof(struct resource)+16);
+ if (tm == NULL)
+ return -ENOMEM;
+
+ tm->start = (timer_id>>4)&0xf;
+ tm->end = timer_id & 0xf;
+ if (tm->start > 3)
+ return -EINVAL;
+
+ if ((tm->end != tm->start) &&
+ ((tm->start & 1) || (tm->end != (tm->start+1))))
+ return -EINVAL;
+
+ err = request_resource(&cpm_timer_resource,tm);
+ if (err < 0) {
+ kfree(tm);
+ return err;
+ }
+
+ *ptm = (cpm_timer_t)(tm);
+
+ tm->name = ((void *)tm) + sizeof(struct resource);
+ if (tm->start == tm->end) {
+ sprintf((char *)tm->name,"timer%ld",tm->start+1);
+ } else {
+ sprintf((char *)tm->name,"timer%ld-%ld",tm->start+1,tm->end+1);
+ }
+
+ err = request_irq(cpm_timer[tm->end].irq,cpm_timer_irq,SA_INTERRUPT,tm->name,&cpm_timer[tm->end]);
+ if (err < 0) {
+ printk(KERN_ERR "CPM Timer %s: Can't allocate IRQ %d.\n",tm->name,cpm_timer[tm->end].irq);
+ }
+
+ /* Step 1 - enable and stop the timer */
+ mask = (TGCR_RST|TGCR_STP) << (4*((tm->end)&1));
+ if (tm->start < 2) {
+ timer_base->cpmt_tgcr1 |= mask;
+ } else {
+ timer_base->cpmt_tgcr2 |= mask;
+ }
+
+ cpm_timer[tm->end].func = NULL;
+
+ *cpm_timer[tm->end].ctrl.tmr = TMR_FRR | TMR_ICLK_INT_DIV_16;
+ if (tm->start != tm->end) {
+ if (tm->start == 0) {
+ timer_base->cpmt_tgcr1 |= (TGCR_CAS << 4);
+ } else if (tm->start == 2) {
+ timer_base->cpmt_tgcr2 |= (TGCR_CAS << 4);
+ }
+ *cpm_timer[tm->start].ctrl.tmr = TMR_FRR | TMR_ICLK_INT_DIV_16;
+ } else {
+ if (tm->start < 2) {
+ timer_base->cpmt_tgcr1 &= ~(TGCR_CAS << 4);
+ } else {
+ timer_base->cpmt_tgcr2 &= ~(TGCR_CAS << 4);
+ }
+ }
+
+ cpm_timer[tm->end].tm = tm;
+
+ cpm_timer_reset(tm);
+
+ return 0;
+}
+
+/* Free timer, using cpm_timer_t from cpm_timer_alloc
+ * cpm_timer_free() will stop the timer, and any cycle or one-shot functions
+ * pending.
+ */
+EXPORT_SYMBOL(cpm_timer_free);
+void cpm_timer_free(cpm_timer_t tm)
+{
+ uint16_t mask;
+
+ cpm_timer_stop(tm);
+ free_irq(cpm_timer[tm->end].irq,&cpm_timer[tm->end]);
+ if (tm->start != tm->end) {
+ if (tm->start == 0) {
+ timer_base->cpmt_tgcr1 &= ~(TGCR_CAS << 4);
+ } else if (tm->start == 2) {
+ timer_base->cpmt_tgcr2 &= ~(TGCR_CAS << 4);
+ }
+ }
+ wmb();
+
+ /* Disable the timer */
+ mask = (TGCR_RST << (4*((tm->start)&1))) |
+ (TGCR_RST << (4*((tm->end)&1)));
+ if (tm->start < 2) {
+ timer_base->cpmt_tgcr1 &= ~mask;
+ } else {
+ timer_base->cpmt_tgcr2 &= ~mask;
+ }
+ wmb();
+
+ release_resource(tm);
+ kfree(tm);
+}
+
+/* Stop the timer
+ */
+EXPORT_SYMBOL(cpm_timer_stop);
+void cpm_timer_stop(cpm_timer_t tm)
+{
+ uint8_t mask;
+
+ mask = (TGCR_STP << (4*((tm->end)&1)));
+ if (tm->start < 2) {
+ timer_base->cpmt_tgcr1 |= mask;
+ } else {
+ timer_base->cpmt_tgcr2 |= mask;
+ }
+ wmb();
+
+}
+
+/* Start the timer
+ */
+EXPORT_SYMBOL(cpm_timer_start);
+void cpm_timer_start(cpm_timer_t tm)
+{
+ uint8_t mask;
+
+ mask = (TGCR_STP << (4*((tm->end)&1)));
+ if (tm->start < 2) {
+ timer_base->cpmt_tgcr1 &= ~mask;
+ } else {
+ timer_base->cpmt_tgcr2 &= ~mask;
+ }
+ wmb();
+}
+
+/* Reset the timer to 0
+ *
+ * Yes, this code looks rather hokey, but evidently tcn is a write-once
+ * register.
+ */
+EXPORT_SYMBOL(cpm_timer_reset);
+void cpm_timer_reset(cpm_timer_t tm)
+{
+ int mask;
+ int tmr;
+
+ mask = ((TGCR_STP|TGCR_RST) << (4*((tm->end)&1)));
+ tmr = *cpm_timer[tm->end].ctrl.tmr;
+
+ if (tm->start < 2) {
+ timer_base->cpmt_tgcr1 &= ~mask;
+ } else {
+ timer_base->cpmt_tgcr2 &= ~mask;
+ }
+ wmb();
+
+ if (tm->start == tm->end) {
+ *cpm_timer[tm->start].data.r16.tcn = 0;
+ } else {
+ *cpm_timer[tm->start].data.r32.tcn = 0;
+ }
+ wmb();
+
+ if (tm->start < 2) {
+ timer_base->cpmt_tgcr1 |= mask;
+ } else {
+ timer_base->cpmt_tgcr2 |= mask;
+ }
+ wmb();
+ *cpm_timer[tm->end].ctrl.tmr = tmr;
+}
+
+/* Get the timer resolution, in nanoseconds/tick
+ */
+EXPORT_SYMBOL(cpm_timer_get_resolution);
+unsigned long cpm_timer_get_resolution(cpm_timer_t tm)
+{
+ /* For the mpc85xx, we're just using core frequency/16
+ */
+ extern unsigned char __res[];
+ bd_t *bd = (bd_t *)__res;
+
+ return bd->bi_busfreq/1000000*16;
+}
+
+/* Get the timer value, in ticks
+ */
+EXPORT_SYMBOL(cpm_timer_get_ticks);
+unsigned long cpm_timer_get_ticks(cpm_timer_t tm)
+{
+ unsigned long ticks;
+
+ rmb();
+ if (tm->end != tm->start)
+ ticks = *cpm_timer[tm->start].data.r32.tcn;
+ else
+ ticks = *cpm_timer[tm->start].data.r16.tcn;
+
+ return ticks;
+}
+
+/* Call a function after so many ticks
+ * The function will be called in interrupt context.
+ *
+ * You cannot call cpm_timer_free() within that context.
+ */
+
+static int cpm_timer_call_common(cpm_timer_t tm, unsigned long ticks, cpm_timer_f func, void *func_data)
+{
+ if (cpm_timer[tm->start].func != NULL)
+ return -EBUSY;
+
+ cpm_timer_reset(tm);
+
+ if (tm->start != tm->end) {
+ *cpm_timer[tm->start].data.r32.trr = ticks;
+ } else {
+ *cpm_timer[tm->start].data.r16.trr = ticks & 0xffff;
+ }
+ wmb();
+
+ cpm_timer[tm->end].func = func;
+ cpm_timer[tm->end].func_data = func_data;
+ wmb();
+
+ *cpm_timer[tm->end].ctrl.tmr |= TMR_ORI;
+ if (tm->start != tm->end) {
+ *cpm_timer[tm->start].ctrl.tmr |= TMR_ORI;
+ *cpm_timer[tm->start].ctrl.ter = 0xffff;
+ }
+ *cpm_timer[tm->end].ctrl.ter = 0xffff;
+
+ wmb();
+
+ return 0;
+}
+
+
+/* This is the one-shot timer.
+ */
+EXPORT_SYMBOL(cpm_timer_call_once);
+int cpm_timer_call_once(cpm_timer_t tm, unsigned long ticks, cpm_timer_f func, void *func_data)
+{
+ int err;
+
+ err = cpm_timer_call_common(tm,ticks,func,func_data);
+ if (err < 0)
+ return err;
+
+ cpm_timer[tm->end].one_shot = 1;
+
+ return 0;
+}
+
+
+/* This is the repeat-timer function
+ */
+EXPORT_SYMBOL(cpm_timer_call_every);
+int cpm_timer_call_every(cpm_timer_t tm, unsigned long ticks, cpm_timer_f func, void *func_data)
+{
+ int err;
+
+ err = cpm_timer_call_common(tm,ticks,func,func_data);
+ if (err < 0)
+ return err;
+
+ cpm_timer[tm->end].one_shot = 0;
+
+ return 0;
+}
+
+/* Cancel any pending timer functions
+ */
+EXPORT_SYMBOL(cpm_timer_call_none);
+int cpm_timer_call_none(cpm_timer_t tm)
+{
+ cpm_timer[tm->end].one_shot = 1;
+ wmb();
+ cpm_timer[tm->end].func = NULL;
+ wmb();
+ cpm_timer[tm->end].func_data = NULL;
+ wmb();
+
+ return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+
+extern struct seq_operations resource_op;
+
+static int cpm_timer_open(struct inode *inode, struct file *file)
+{
+ int res = seq_open(file, &resource_op);
+ if (!res) {
+ struct seq_file *m = file->private_data;
+ m->private = &cpm_timer_resource;
+ }
+ return res;
+}
+
+static struct file_operations proc_cpm_timer_operations = {
+ .open = cpm_timer_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static int __init cpm_timer_proc_init(void)
+{
+ struct proc_dir_entry *entry;
+
+ entry = create_proc_entry("cpm-timer", 0, NULL);
+ if (entry)
+ entry->proc_fops = &proc_cpm_timer_operations;
+ return 0;
+}
+
+static void __exit cpm_timer_proc_exit(void)
+{
+ remove_proc_entry("cpm-timer", NULL);
+}
+
+#endif /* CONFIG_PROC_FS */
+
+static int __devinit cpm_timer_probe(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ int i;
+ struct resource *res,*irqs;
+
+ if (timer_base != NULL)
+ return -EBUSY;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL)
+ return -EINVAL;
+
+ irqs = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL || ((irqs->end+1)-irqs->start) != 4)
+ return -EINVAL;
+
+ timer_base = ioremap(res->start,sizeof(cpmtimer_cpm2_t));
+ if (timer_base == NULL)
+ return -ENOMEM;
+
+#define CPM_TIMER_C_SETUP(field) do {\
+ cpm_timer[0].ctrl.field = &timer_base->cpmt_##field##1; \
+ cpm_timer[1].ctrl.field = &timer_base->cpmt_##field##2; \
+ cpm_timer[2].ctrl.field = &timer_base->cpmt_##field##3; \
+ cpm_timer[3].ctrl.field = &timer_base->cpmt_##field##4; \
+ } while (0)
+
+#define CPM_TIMER_D_SETUP(field) do {\
+ cpm_timer[0].data.r16.field = &timer_base->cpmt_##field##1; \
+ cpm_timer[1].data.r16.field = &timer_base->cpmt_##field##2; \
+ cpm_timer[2].data.r16.field = &timer_base->cpmt_##field##3; \
+ cpm_timer[3].data.r16.field = &timer_base->cpmt_##field##4; \
+ } while (0)
+
+ CPM_TIMER_C_SETUP(tmr);
+ CPM_TIMER_C_SETUP(ter);
+
+ CPM_TIMER_D_SETUP(trr);
+ CPM_TIMER_D_SETUP(tcr);
+ CPM_TIMER_D_SETUP(tcn);
+
+ for (i = 0; i < 4; i++) {
+ sprintf(cpm_timer[i].name,"CPM Timer %d",i+1);
+ cpm_timer[i].irq = irqs->start+i;
+ }
+
+#ifdef CONFIG_PROC_FS
+ cpm_timer_proc_init();
+#endif
+
+ return 0;
+}
+
+static void __devexit cpm_timer_remove(struct device *dev)
+{
+ iounmap(timer_base);
+#ifdef CONFIG_PROC_FS
+ cpm_timer_proc_exit();
+#endif
+}
+
+static struct device_driver cpm_timer_driver = {
+ .name = "fsl-cpm-timer",
+ .bus = &platform_bus_type,
+ .probe = cpm_timer_probe,
+ .remove = __devexit_p(cpm_timer_remove),
+};
+
+static __init int cpm_timer_init(void)
+{
+ printk(KERN_INFO "cpm-timer: CPM2 Timers\n");
+
+ return driver_register(&cpm_timer_driver);
+}
+
+static __exit void cpm_timer_exit(void)
+{
+ driver_unregister(&cpm_timer_driver);
+}
+
+MODULE_LICENSE("GPL");
+
+MODULE_AUTHOR("Jason McMullan <jason.mcmullan@timesys.com>");
+MODULE_DESCRIPTION("CPM2 timer driver");
+
+module_init(cpm_timer_init);
+module_exit(cpm_timer_exit);
+
+
diff -urN -X /home/jmcmullan/dontdiff linux-2.6/arch/ppc/syslib/Makefile linux-2.6.patch/arch/ppc/syslib/Makefile
--- linux-2.6/arch/ppc/syslib/Makefile 2005-03-31 14:06:03.000000000 -0500
+++ linux-2.6.patch/arch/ppc/syslib/Makefile 2005-03-31 14:50:29.211464894 -0500
@@ -84,6 +84,7 @@
obj-$(CONFIG_PCI_8260) += m8260_pci.o indirect_pci.o
obj-$(CONFIG_8260_PCI9) += m8260_pci_erratum9.o
obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o
+obj-$(CONFIG_CPM_TIMER) += cpm_timer.o
ifeq ($(CONFIG_PPC_GEN550),y)
obj-$(CONFIG_KGDB) += gen550_kgdb.o gen550_dbg.o
obj-$(CONFIG_SERIAL_TEXT_DEBUG) += gen550_dbg.o
diff -urN -X /home/jmcmullan/dontdiff linux-2.6/include/asm-ppc/cpm_timer.h linux-2.6.patch/include/asm-ppc/cpm_timer.h
--- linux-2.6/include/asm-ppc/cpm_timer.h 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.patch/include/asm-ppc/cpm_timer.h 2005-03-31 14:50:29.239458550 -0500
@@ -0,0 +1,74 @@
+/* Generic include file for all CPM timer definitions.
+ */
+#ifndef __ASM_CPM_TIMER_H
+#define __ASM_CPM_TIMER_H
+
+#include <linux/config.h>
+#include <linux/ioport.h>
+
+/* Allocate/utilize timers
+ * There are four 16-bit timers, which can be chained as two 32-bit timers.
+ */
+#define CPM2_TIMER16_1 0x00
+#define CPM2_TIMER16_2 0x11
+#define CPM2_TIMER16_3 0x22
+#define CPM2_TIMER16_4 0x33
+#define CPM2_TIMER32_1 0x01
+#define CPM2_TIMER32_2 0x23
+
+typedef struct resource *cpm_timer_t;
+typedef void (*cpm_timer_f)(cpm_timer_t tm, void *data);
+
+/* Allocate a timer.
+ * Pass a timer id, and a reference to a NULL struct resource *
+ * Returns 0 on success, -errno on error
+ */
+int cpm_timer_alloc(int timer_id, cpm_timer_t *tm);
+
+/* Free timer, using cpm_timer_t from cpm_timer_alloc
+ * cpm_timer_free() will stop the timer, and any cycle or one-shot functions
+ * pending.
+ */
+void cpm_timer_free(cpm_timer_t tm);
+
+/* Stop the timer
+ */
+void cpm_timer_stop(cpm_timer_t tm);
+
+/* Start the timer
+ */
+void cpm_timer_start(cpm_timer_t tm);
+
+/* Reset the timer to 0
+ */
+void cpm_timer_reset(cpm_timer_t tm);
+
+/* Get the timer resolution, in nanoseconds/tick
+ */
+unsigned long cpm_timer_get_resolution(cpm_timer_t tm);
+
+/* Get the timer value, in ticks
+ */
+unsigned long cpm_timer_get_ticks(cpm_timer_t tm);
+
+/* Call a function after so many ticks
+ * The function will be called in interrupt context.
+ *
+ * You cannot call cpm_timer_free() within that context.
+ */
+
+
+/* This is the one-shot timer.
+ */
+int cpm_timer_call_once(cpm_timer_t tm, unsigned long ticks, cpm_timer_f func, void *data);
+
+/* This is the repeat-timer function
+ */
+int cpm_timer_call_every(cpm_timer_t tm, unsigned long ticks, cpm_timer_f func, void *data);
+
+/* Cancel any pending timer functions
+ */
+int cpm_timer_call_none(cpm_timer_t tm);
+
+
+#endif /* __ASM_CPM_TIMER_H */
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH 2.6.11.6] CPM2 Timers API
2005-03-31 19:54 [PATCH 2.6.11.6] CPM2 Timers API Jason McMullan
@ 2005-03-31 20:33 ` Jason McMullan
2005-04-01 13:50 ` Jason McMullan
0 siblings, 1 reply; 3+ messages in thread
From: Jason McMullan @ 2005-03-31 20:33 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1.1: Type: text/plain, Size: 187 bytes --]
A brown bag error handling and Lindent patch, to be applied in that
order, to my previous CPM timers patch.
--
Jason McMullan <jason.mcmullan@timesys.com>
TimeSys Corporation
[-- Attachment #1.2: cpm-timer.brown-bag.patch --]
[-- Type: text/x-patch, Size: 638 bytes --]
--- linux-2.6.patch/arch/ppc/syslib/cpm_timer.c.orig 2005-03-31 14:50:29.000000000 -0500
+++ linux-2.6.patch/arch/ppc/syslib/cpm_timer.c 2005-03-31 15:01:39.417496033 -0500
@@ -114,12 +114,16 @@
tm->start = (timer_id>>4)&0xf;
tm->end = timer_id & 0xf;
- if (tm->start > 3)
+ if (tm->start > 3) {
+ kfree(tm);
return -EINVAL;
+ }
if ((tm->end != tm->start) &&
- ((tm->start & 1) || (tm->end != (tm->start+1))))
- return -EINVAL;
+ ((tm->start & 1) || (tm->end != (tm->start+1)))) {
+ kfree(tm);
+ return -EINVAL;
+ }
err = request_resource(&cpm_timer_resource,tm);
if (err < 0) {
[-- Attachment #1.3: cpm-timer.lindent.patch --]
[-- Type: text/x-patch, Size: 7152 bytes --]
--- linux-2.6/arch/ppc/syslib/cpm_timer.c 2005-03-31 15:15:59.100629916 -0500
+++ linux-2.6.patch/arch/ppc/syslib/cpm_timer.c 2005-03-31 15:15:38.838272681 -0500
@@ -42,7 +42,7 @@
static struct resource cpm_timer_resource = {
.name = "CPM Timers",
.start = 0,
- .end = 3,
+ .end = 3,
};
static struct cpm_timer_s {
@@ -101,52 +101,56 @@
* Returns 0 on success, -errno on error
*/
EXPORT_SYMBOL(cpm_timer_alloc);
-int cpm_timer_alloc(int timer_id, cpm_timer_t *ptm)
+int cpm_timer_alloc(int timer_id, cpm_timer_t * ptm)
{
struct resource *tm;
int err;
uint16_t mask;
-
- tm = kmalloc(sizeof(struct resource)+16, GFP_KERNEL);
- memset(tm,0,sizeof(struct resource)+16);
+
+ tm = kmalloc(sizeof(struct resource) + 16, GFP_KERNEL);
+ memset(tm, 0, sizeof(struct resource) + 16);
if (tm == NULL)
return -ENOMEM;
- tm->start = (timer_id>>4)&0xf;
- tm->end = timer_id & 0xf;
+ tm->start = (timer_id >> 4) & 0xf;
+ tm->end = timer_id & 0xf;
if (tm->start > 3) {
kfree(tm);
return -EINVAL;
}
- if ((tm->end != tm->start) &&
- ((tm->start & 1) || (tm->end != (tm->start+1)))) {
+ if ((tm->end != tm->start) &&
+ ((tm->start & 1) || (tm->end != (tm->start + 1)))) {
kfree(tm);
return -EINVAL;
}
- err = request_resource(&cpm_timer_resource,tm);
+ err = request_resource(&cpm_timer_resource, tm);
if (err < 0) {
kfree(tm);
return err;
}
- *ptm = (cpm_timer_t)(tm);
+ *ptm = (cpm_timer_t) (tm);
tm->name = ((void *)tm) + sizeof(struct resource);
if (tm->start == tm->end) {
- sprintf((char *)tm->name,"timer%ld",tm->start+1);
+ sprintf((char *)tm->name, "timer%ld", tm->start + 1);
} else {
- sprintf((char *)tm->name,"timer%ld-%ld",tm->start+1,tm->end+1);
+ sprintf((char *)tm->name, "timer%ld-%ld", tm->start + 1,
+ tm->end + 1);
}
- err = request_irq(cpm_timer[tm->end].irq,cpm_timer_irq,SA_INTERRUPT,tm->name,&cpm_timer[tm->end]);
+ err =
+ request_irq(cpm_timer[tm->end].irq, cpm_timer_irq, SA_INTERRUPT,
+ tm->name, &cpm_timer[tm->end]);
if (err < 0) {
- printk(KERN_ERR "CPM Timer %s: Can't allocate IRQ %d.\n",tm->name,cpm_timer[tm->end].irq);
+ printk(KERN_ERR "CPM Timer %s: Can't allocate IRQ %d.\n",
+ tm->name, cpm_timer[tm->end].irq);
}
/* Step 1 - enable and stop the timer */
- mask = (TGCR_RST|TGCR_STP) << (4*((tm->end)&1));
+ mask = (TGCR_RST | TGCR_STP) << (4 * ((tm->end) & 1));
if (tm->start < 2) {
timer_base->cpmt_tgcr1 |= mask;
} else {
@@ -188,7 +192,7 @@
uint16_t mask;
cpm_timer_stop(tm);
- free_irq(cpm_timer[tm->end].irq,&cpm_timer[tm->end]);
+ free_irq(cpm_timer[tm->end].irq, &cpm_timer[tm->end]);
if (tm->start != tm->end) {
if (tm->start == 0) {
timer_base->cpmt_tgcr1 &= ~(TGCR_CAS << 4);
@@ -199,8 +203,8 @@
wmb();
/* Disable the timer */
- mask = (TGCR_RST << (4*((tm->start)&1))) |
- (TGCR_RST << (4*((tm->end)&1)));
+ mask = (TGCR_RST << (4 * ((tm->start) & 1))) |
+ (TGCR_RST << (4 * ((tm->end) & 1)));
if (tm->start < 2) {
timer_base->cpmt_tgcr1 &= ~mask;
} else {
@@ -219,7 +223,7 @@
{
uint8_t mask;
- mask = (TGCR_STP << (4*((tm->end)&1)));
+ mask = (TGCR_STP << (4 * ((tm->end) & 1)));
if (tm->start < 2) {
timer_base->cpmt_tgcr1 |= mask;
} else {
@@ -236,7 +240,7 @@
{
uint8_t mask;
- mask = (TGCR_STP << (4*((tm->end)&1)));
+ mask = (TGCR_STP << (4 * ((tm->end) & 1)));
if (tm->start < 2) {
timer_base->cpmt_tgcr1 &= ~mask;
} else {
@@ -256,7 +260,7 @@
int mask;
int tmr;
- mask = ((TGCR_STP|TGCR_RST) << (4*((tm->end)&1)));
+ mask = ((TGCR_STP | TGCR_RST) << (4 * ((tm->end) & 1)));
tmr = *cpm_timer[tm->end].ctrl.tmr;
if (tm->start < 2) {
@@ -290,9 +294,9 @@
/* For the mpc85xx, we're just using core frequency/16
*/
extern unsigned char __res[];
- bd_t *bd = (bd_t *)__res;
+ bd_t *bd = (bd_t *) __res;
- return bd->bi_busfreq/1000000*16;
+ return bd->bi_busfreq / 1000000 * 16;
}
/* Get the timer value, in ticks
@@ -317,7 +321,8 @@
* You cannot call cpm_timer_free() within that context.
*/
-static int cpm_timer_call_common(cpm_timer_t tm, unsigned long ticks, cpm_timer_f func, void *func_data)
+static int cpm_timer_call_common(cpm_timer_t tm, unsigned long ticks,
+ cpm_timer_f func, void *func_data)
{
if (cpm_timer[tm->start].func != NULL)
return -EBUSY;
@@ -347,15 +352,15 @@
return 0;
}
-
/* This is the one-shot timer.
*/
EXPORT_SYMBOL(cpm_timer_call_once);
-int cpm_timer_call_once(cpm_timer_t tm, unsigned long ticks, cpm_timer_f func, void *func_data)
+int cpm_timer_call_once(cpm_timer_t tm, unsigned long ticks, cpm_timer_f func,
+ void *func_data)
{
int err;
- err = cpm_timer_call_common(tm,ticks,func,func_data);
+ err = cpm_timer_call_common(tm, ticks, func, func_data);
if (err < 0)
return err;
@@ -363,16 +368,16 @@
return 0;
}
-
/* This is the repeat-timer function
*/
EXPORT_SYMBOL(cpm_timer_call_every);
-int cpm_timer_call_every(cpm_timer_t tm, unsigned long ticks, cpm_timer_f func, void *func_data)
+int cpm_timer_call_every(cpm_timer_t tm, unsigned long ticks, cpm_timer_f func,
+ void *func_data)
{
int err;
- err = cpm_timer_call_common(tm,ticks,func,func_data);
+ err = cpm_timer_call_common(tm, ticks, func, func_data);
if (err < 0)
return err;
@@ -380,7 +385,7 @@
return 0;
}
-
+
/* Cancel any pending timer functions
*/
EXPORT_SYMBOL(cpm_timer_call_none);
@@ -411,10 +416,10 @@
}
static struct file_operations proc_cpm_timer_operations = {
- .open = cpm_timer_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
+ .open = cpm_timer_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
};
static int __init cpm_timer_proc_init(void)
@@ -432,13 +437,13 @@
remove_proc_entry("cpm-timer", NULL);
}
-#endif /* CONFIG_PROC_FS */
+#endif /* CONFIG_PROC_FS */
static int __devinit cpm_timer_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
int i;
- struct resource *res,*irqs;
+ struct resource *res, *irqs;
if (timer_base != NULL)
return -EBUSY;
@@ -448,10 +453,10 @@
return -EINVAL;
irqs = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (res == NULL || ((irqs->end+1)-irqs->start) != 4)
+ if (res == NULL || ((irqs->end + 1) - irqs->start) != 4)
return -EINVAL;
- timer_base = ioremap(res->start,sizeof(cpmtimer_cpm2_t));
+ timer_base = ioremap(res->start, sizeof(cpmtimer_cpm2_t));
if (timer_base == NULL)
return -ENOMEM;
@@ -477,8 +482,8 @@
CPM_TIMER_D_SETUP(tcn);
for (i = 0; i < 4; i++) {
- sprintf(cpm_timer[i].name,"CPM Timer %d",i+1);
- cpm_timer[i].irq = irqs->start+i;
+ sprintf(cpm_timer[i].name, "CPM Timer %d", i + 1);
+ cpm_timer[i].irq = irqs->start + i;
}
#ifdef CONFIG_PROC_FS
@@ -522,5 +527,3 @@
module_init(cpm_timer_init);
module_exit(cpm_timer_exit);
-
-
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH 2.6.11.6] CPM2 Timers API
2005-03-31 20:33 ` Jason McMullan
@ 2005-04-01 13:50 ` Jason McMullan
0 siblings, 0 replies; 3+ messages in thread
From: Jason McMullan @ 2005-04-01 13:50 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1.1: Type: text/plain, Size: 123 bytes --]
And here's the test-case kernel module....
--
Jason McMullan <jason.mcmullan@timesys.com>
TimeSys Corporation
[-- Attachment #1.2: cpm_timer_test.c --]
[-- Type: text/x-csrc, Size: 3852 bytes --]
/*
* CPM Timers test
*
* Copyright 2004, Timesys Corp.
* Jason McMullan <jason.mcmullan@timesys.com>
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/wait.h>
#include <asm/cpm_timer.h>
static int failed = 0;
static volatile int once, every;
static wait_queue_head_t queue;
#define FAILED(x, args...) do { failed++; printk(KERN_INFO "cpm_timer_test: " x , ## args ); if (tm != NULL) { cpm_timer_stop(tm); cpm_timer_free(tm); } return -EINVAL; } while (0)
static void cpm_timer_test_callback(cpm_timer_t tm, void *data)
{
if (data == &once) {
unsigned long val = cpm_timer_get_ticks(tm);
printk(KERN_INFO "cpm_timer_test: Called once at tick %ld.\n",
val);
once++;
wmb();
}
if (data == &every) {
unsigned long val = cpm_timer_get_ticks(tm);
printk(KERN_INFO
"cpm_timer_test: Called every(%d), tick %ld.\n", every,
val);
every++;
if (every > 5)
cpm_timer_call_none(tm);
wmb();
}
wake_up_interruptible(&queue);
}
static int test_timer(int timer_id)
{
cpm_timer_t tm = NULL;
int err;
unsigned long res, val;
printk(KERN_INFO "cpm_timer_test: Test timer ID 0x%.2x\n", timer_id);
err = cpm_timer_alloc(timer_id, &tm);
if (err < 0)
FAILED("Can't allocate timer 0x%.2x\n", timer_id);
res = cpm_timer_get_resolution(tm);
printk(KERN_INFO "cpm_timer_test: nanoseconds/tick = %ld\n", res);
val = cpm_timer_get_ticks(tm);
printk(KERN_INFO "cpm_timer_test: current value = %ld\n", val);
cpm_timer_stop(tm);
cpm_timer_reset(tm);
val = cpm_timer_get_ticks(tm);
printk(KERN_INFO "cpm_timer_test: value after stop/reset= %ld\n", val);
if (val != 0)
FAILED("Timer 0x%.2x didn't stop!\n", timer_id);
cpm_timer_start(tm);
udelay(5);
val = cpm_timer_get_ticks(tm);
udelay(5);
res = cpm_timer_get_ticks(tm);
printk(KERN_INFO "cpm_timer_test: value after 5 us= %ld\n", val);
printk(KERN_INFO "cpm_timer_test: value after 10 us= %ld\n", res);
if (val == 0 || res == 0)
FAILED("Timer 0x%.2x didn't increment!\n", timer_id);
init_waitqueue_head(&queue);
once = 0;
err =
cpm_timer_call_once(tm, 50000, cpm_timer_test_callback,
(void *)&once);
if (err < 0)
FAILED("Can't call cpm_timer_call_once for 0x%.2x\n", timer_id);
printk(KERN_INFO "cpm_timer_test: Waiting for one-shot...\n");
cpm_timer_start(tm);
err = wait_event_interruptible(queue, once != 0);
if (err < 0)
FAILED("Interrupted sleep for 0x%.2x\n", timer_id);
every = 0;
err =
cpm_timer_call_every(tm, 50000, cpm_timer_test_callback,
(void *)&every);
if (err < 0)
FAILED("Can't call cpm_timer_call_every for 0x%.2x\n",
timer_id);
printk(KERN_INFO "cpm_timer_test: Waiting for multi-shot x5...\n");
cpm_timer_start(tm);
err = wait_event_interruptible(queue, every > 5);
if (err < 0)
FAILED("Interrupted sleep for 0x%.2x\n", timer_id);
cpm_timer_call_none(tm);
printk(KERN_INFO "cpm_timer_test: Counted up to %d.\n", every);
cpm_timer_stop(tm);
cpm_timer_free(tm);
return 0;
}
static int cpm_timer_test_init(void)
{
int err;
printk(KERN_INFO "CPM2 Timer Test Module.\n");
#define TEST(x) do { err=test_timer(x); if (err != 0) goto bad; } while (0)
TEST(CPM2_TIMER16_1);
TEST(CPM2_TIMER16_2);
TEST(CPM2_TIMER16_3);
TEST(CPM2_TIMER16_4);
TEST(CPM2_TIMER32_1);
TEST(CPM2_TIMER32_2);
bad:
if (failed) {
printk(KERN_INFO "cpm_timer_test: FAILED %d tests\n", failed);
} else {
printk(KERN_INFO "cpm_timer_test: PASSED\n");
}
return 0;
}
static void cpm_timer_test_exit(void)
{
printk(KERN_INFO "CPM2 Timer Test Module unloaded.\n");
return;
}
MODULE_LICENSE("GPL");
module_init(cpm_timer_test_init);
module_exit(cpm_timer_test_exit);
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2005-04-01 13:50 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-03-31 19:54 [PATCH 2.6.11.6] CPM2 Timers API Jason McMullan
2005-03-31 20:33 ` Jason McMullan
2005-04-01 13:50 ` Jason McMullan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).