public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Mark Salter <msalter@redhat.com>
To: linux-kernel@vger.kernel.org
Subject: [PATCH 13/16] C6X: add drivers/platform/c6x files
Date: Wed, 11 May 2011 16:14:00 -0400	[thread overview]
Message-ID: <1305144843-5058-14-git-send-email-msalter@redhat.com> (raw)
In-Reply-To: <1305144843-5058-13-git-send-email-msalter@redhat.com>

This patch adds driver support for miscellaneous drivers for hardware found
on C64x DSP chips but not really part of the CPU core. These could have been
put under arch/c6x/kernel, but that would get cluttered pretty quickly as
new SoC parts are supported.

Signed-off-by: Mark Salter <msalter@redhat.com>
---
 drivers/platform/Kconfig             |    4 +
 drivers/platform/Makefile            |    1 +
 drivers/platform/c6x/Kconfig         |   27 ++
 drivers/platform/c6x/Makefile        |    8 +
 drivers/platform/c6x/irq-c64xplus.c  |  583 ++++++++++++++++++++++++++++++++++
 drivers/platform/c6x/pll-tci648x.c   |  433 +++++++++++++++++++++++++
 drivers/platform/c6x/timer-tci648x.c |  121 +++++++
 drivers/platform/c6x/tsc-c64xplus.c  |   53 +++
 8 files changed, 1230 insertions(+), 0 deletions(-)
 create mode 100644 drivers/platform/c6x/Kconfig
 create mode 100644 drivers/platform/c6x/Makefile
 create mode 100644 drivers/platform/c6x/irq-c64xplus.c
 create mode 100644 drivers/platform/c6x/pll-tci648x.c
 create mode 100644 drivers/platform/c6x/timer-tci648x.c
 create mode 100644 drivers/platform/c6x/tsc-c64xplus.c

diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
index 8390dca..df334ed 100644
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -1,3 +1,7 @@
 if X86
 source "drivers/platform/x86/Kconfig"
 endif
+
+if TMS320C6X
+source "drivers/platform/c6x/Kconfig"
+endif
diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile
index 782953a..bd9e0e3 100644
--- a/drivers/platform/Makefile
+++ b/drivers/platform/Makefile
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_X86)		+= x86/
+obj-$(CONFIG_TMS320C6X)		+= c6x/
diff --git a/drivers/platform/c6x/Kconfig b/drivers/platform/c6x/Kconfig
new file mode 100644
index 0000000..a950fb8
--- /dev/null
+++ b/drivers/platform/c6x/Kconfig
@@ -0,0 +1,27 @@
+#
+# C6X Platform Specific Drivers
+#
+
+menuconfig C6X_PLATFORM_DEVICES
+	bool "C6X Platform Specific Device Drivers"
+	default y
+	depends on TMS320C6X
+	---help---
+	  Say Y here to get to see options for device drivers for various
+	  c64x platforms. This option alone does not add any kernel code.
+
+	  If you say N, all options in this submenu will be skipped and disabled.
+
+if C6X_PLATFORM_DEVICES
+
+config PLL_TCI648X
+	bool "PLL_TCI648X"
+	depends on COMMON_CLKDEV
+
+config TIMER_TCI648X
+	bool "TIMER_TCI648X"
+
+config PIC_C64XPLUS
+	bool "C64X+ Megamodule Interrupt Controller"
+
+endif # C6X_PLATFORM_DEVICES
diff --git a/drivers/platform/c6x/Makefile b/drivers/platform/c6x/Makefile
new file mode 100644
index 0000000..2f9be75
--- /dev/null
+++ b/drivers/platform/c6x/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for drivers/platform/c6x
+#
+
+obj-$(CONFIG_PLL_TCI648X)      += pll-tci648x.o
+obj-$(CONFIG_TMS320C64XPLUS)   += tsc-c64xplus.o
+obj-$(CONFIG_TIMER_TCI648X)    += timer-tci648x.o
+obj-$(CONFIG_PIC_C64XPLUS)     += irq-c64xplus.o
diff --git a/drivers/platform/c6x/irq-c64xplus.c b/drivers/platform/c6x/irq-c64xplus.c
new file mode 100644
index 0000000..4eff863
--- /dev/null
+++ b/drivers/platform/c6x/irq-c64xplus.c
@@ -0,0 +1,583 @@
+/*
+ *  Support for C64x+ Megamodule Interrupt Controller
+ *
+ *  Copyright (C) 2010, 2011 Texas Instruments Incorporated
+ *  Contributed by: Mark Salter <msalter@redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/hardirq.h>
+#include <linux/seq_file.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/hardirq.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/page.h>
+#include <asm/hardware.h>
+
+#define IRQ_UNMAPPED 0xffff
+
+#define NR_MEGAMOD_COMBINERS 4
+
+#ifdef CONFIG_SOC_TMS320C6474
+#define NR_CIC_COMBINERS 2
+#define NR_CIC_OUTPUTS	 16
+#else
+#define NR_CIC_COMBINERS 0
+#endif
+
+#define NR_COMBINERS (NR_MEGAMOD_COMBINERS + NR_CIC_COMBINERS)
+
+struct combiner_handler_info {
+	volatile uint32_t *mevtflag;
+	volatile uint32_t *evtclr;
+	uint16_t irqmap[32];
+};
+
+struct combiner_mask_info {
+	int irq_base;
+	volatile uint32_t *evtmask;
+};
+
+struct c6x_irq_chip {
+	struct irq_chip chip;
+	struct combiner_mask_info *minfo;
+};
+
+static struct combiner_mask_info    megamod_mask_info[NR_MEGAMOD_COMBINERS];
+static struct combiner_handler_info megamod_handler_info[NR_MEGAMOD_COMBINERS];
+
+uint16_t prio_to_irq[NR_SYS_IRQS];
+
+static uint8_t	irq_to_prio[NR_IRQS];
+
+/* The 16 SoC GPIOs can span more than one megamodule */
+#define NR_GPIO_CHIPS 2
+
+static struct c6x_irq_chip direct_chips[(INT15 - INT4) + 1];
+static struct c6x_irq_chip gpio_chips[NR_GPIO_CHIPS];
+static struct c6x_irq_chip *prio_saved_chips[NR_SYS_IRQS];
+
+#if NR_CIC_COMBINERS > 0
+static struct combiner_mask_info    cic_mask_info[NR_CIC_COMBINERS];
+static struct combiner_handler_info cic_handler_info[NR_CIC_COMBINERS];
+
+static uint8_t	cic_output_to_evt[NR_CIC_OUTPUTS];
+static uint8_t	cic_evt_to_output[NR_CIC_IRQS];
+static struct c6x_irq_chip cic_mapped_chips[CIC_MAPLEN - NR_CIC_COMBINERS];
+static struct c6x_irq_chip *cic_saved_chips[CIC_MAPLEN - NR_CIC_COMBINERS];
+#endif
+
+/* lock protecting irq mappings */
+static spinlock_t map_lock;
+
+static void mask_direct(struct irq_data *data)
+{
+	uint16_t prio;
+
+	BUG_ON(data->irq >= NR_IRQS);
+	prio = irq_to_prio[data->irq];
+	BUG_ON(prio >= NR_SYS_IRQS);
+	and_creg(IER, ~(1 << prio));
+}
+
+static void unmask_direct(struct irq_data *data)
+{
+	uint16_t prio;
+
+	BUG_ON(data->irq >= NR_IRQS);
+	prio = irq_to_prio[data->irq];
+	BUG_ON(prio >= NR_SYS_IRQS);
+	or_creg(IER, 1 << prio);
+}
+
+static const char * const direct_chip_names[] = {
+	"direct-4",
+	"direct-5",
+	"direct-6",
+	"direct-7",
+	"direct-8",
+	"direct-9",
+	"direct-10",
+	"direct-11",
+	"direct-12",
+	"direct-13",
+	"direct-14",
+	"direct-15",
+};
+
+#if NR_CIC_COMBINERS > 0
+/*
+ * CIC IRQs mapped directly to megamodule use chip data from the megamodule
+ * combiner since the megamodule combiner will controlling masking. All other
+ * CIC IRQs use CIC combiner chip data.
+ */
+static inline int cic_mapped_irq(uint16_t irq)
+{
+	uint8_t output;
+
+	if (irq < IRQ_CIC_START || irq >= (IRQ_CIC_START + NR_CIC_IRQS))
+		return irq;
+
+	/* the CIC combined IRQs are hardwired */
+	if (irq < (IRQ_CIC_START + NR_CIC_COMBINERS))
+		return CIC_MAPBASE + (irq - IRQ_CIC_START);
+
+	/* the other CIC events may or may not be mapped to megamodule */
+	output = cic_evt_to_output[irq - IRQ_CIC_START];
+	if (output)
+		return CIC_MAPBASE + output;
+
+	return irq;
+}
+#else
+#define cic_mapped_irq(i) (i)
+#endif
+
+#define c6x_irq_to_chip(i) ((struct c6x_irq_chip *)irq_to_desc((i))->chip)
+
+static void mask_combined(struct irq_data *data)
+{
+	struct c6x_irq_chip *chip = (struct c6x_irq_chip *)data->chip;
+	int irq = data->irq;
+
+	irq = cic_mapped_irq(irq);
+	*chip->minfo->evtmask |= (1 << (irq - chip->minfo->irq_base));
+}
+
+static void unmask_combined(struct irq_data *data)
+{
+	struct c6x_irq_chip *chip = (struct c6x_irq_chip *)data->chip;
+	int irq = data->irq;
+
+	irq = cic_mapped_irq(irq);
+	*chip->minfo->evtmask &= ~(1 << (irq - chip->minfo->irq_base));
+}
+
+#define __CHIP(namestr, i, m, u)	\
+	{				\
+		.chip = { .name = namestr #i,	\
+			  .irq_mask = m,	\
+			  .irq_unmask = u,	\
+		},				\
+	}
+
+/* Combiner chips */
+#define MEGAMOD_CHIP(i)	\
+	__CHIP("combiner-", i, mask_combined, unmask_combined)
+
+static struct c6x_irq_chip megamod_chips[] = {
+	MEGAMOD_CHIP(0),
+	MEGAMOD_CHIP(1),
+	MEGAMOD_CHIP(2),
+	MEGAMOD_CHIP(3),
+};
+
+#if NR_CIC_COMBINERS > 0
+
+#define CIC_CHIP(i)	\
+	__CHIP("cicombiner-", i, mask_combined, unmask_combined)
+
+static struct c6x_irq_chip cic_chips[] = {
+	CIC_CHIP(0),
+#if NR_CIC_COMBINERS > 1
+	CIC_CHIP(1),
+#endif
+#if NR_CIC_COMBINERS > 2
+	CIC_CHIP(2),
+#endif
+#if NR_CIC_COMBINERS > 3
+	CIC_CHIP(3),
+#endif
+};
+#endif /* NR_CIC_COMBINERS > 0 */
+
+/*
+ * When handling IRQs through the CIC, ack after the handler runs.
+ * For IRQs through the megamodule, ack before handler runs.
+ */
+#if NR_CIC_COMBINERS
+#define PRE_ACK (irq < IRQ_CIC_START || \
+		 irq >= (IRQ_CIC_START + NR_CIC_COMBINERS))
+#else
+#define PRE_ACK 1
+#endif
+
+static void handle_combined_irq(unsigned int irq, struct irq_desc *desc)
+{
+	struct combiner_handler_info *info = irq_desc_get_handler_data(desc);
+	unsigned long events;
+	int n;
+
+	while ((events = *info->mevtflag) != 0) {
+		n = __ffs(events);
+		irq = info->irqmap[n]; /* irq to handle */
+
+		if (PRE_ACK)
+			*info->evtclr = (1 << n);
+
+		generic_handle_irq(irq);
+
+		if (!PRE_ACK)
+			*info->evtclr = (1 << n);
+	}
+}
+
+/*
+ * Setup megamodule event mappings.
+ */
+static inline void __irq_megamod_map(unsigned int src, unsigned int dst)
+{
+	uint32_t val;
+	int offset, nr_srcs;
+
+	nr_srcs = (NR_MEGAMOD_COMBINERS * 32);
+
+	BUG_ON(dst < INT4 || dst > INT15);
+	BUG_ON(src >= nr_srcs);
+
+	/* each mux register controls four outputs */
+	offset = (dst & 3) << 3;
+	val = IC_INTMUX[dst >> 2];
+	val &= ~((nr_srcs - 1) << offset);
+	val |= ((src & (nr_srcs - 1)) << offset);
+	IC_INTMUX[dst >> 2] = val;
+}
+
+/*
+ * Map a C64x+ megamodule event to a CPU core priority interrupt.
+ */
+void irq_map(unsigned int irq_src, unsigned int prio)
+{
+	struct irq_desc *desc;
+	struct c6x_irq_chip *chip, *direct;
+	unsigned long flags;
+	unsigned int prio_idx = prio - INT4;
+
+	if (prio < INT4 || prio > INT15)
+		return;
+
+	/* only map megamodule event sources here */
+	if (irq_src >= (NR_MEGAMOD_COMBINERS * 32))
+		return;
+
+	spin_lock_irqsave(&map_lock, flags);
+
+	/* make sure this IRQ is not mapped to another core IRQ */
+	if (irq_to_prio[irq_src])
+		goto out_unlock;
+
+	/* make sure no other IRQ is mapped to the requested priority */
+	if (prio_to_irq[prio] != IRQ_UNMAPPED)
+		goto out_unlock;
+
+#if NR_CIC_COMBINERS > 0
+	/* handle mapping for IRQs coming from CIC */
+	if (irq_src >= CIC_MAPBASE &&
+	    irq_src < (CIC_MAPBASE + CIC_MAPLEN)) {
+		uint8_t cic_src, output = (irq_src - CIC_MAPBASE);
+		uint16_t cic_irq;
+		struct irq_data *data;
+
+		if (output >= NR_CIC_COMBINERS) {
+			cic_src = cic_output_to_evt[output];
+			if (cic_src < NR_CIC_COMBINERS)
+				goto out_unlock;
+			cic_irq = IRQ_CIC_START + cic_src;
+		} else
+			cic_irq = IRQ_CIC_START + output;
+
+		desc = irq_to_desc(cic_irq);
+		data = &desc->irq_data;
+		chip = (struct c6x_irq_chip *)data->chip;
+
+		/* mask combined CIC irq in megamodule combiner */
+		if (output < NR_CIC_COMBINERS)
+			mask_combined(data);
+
+		direct = &direct_chips[prio_idx];
+		*direct = *chip;
+		direct->chip.name = direct_chip_names[prio_idx];
+		direct->chip.irq_mask = mask_direct;
+		direct->chip.irq_unmask = unmask_direct;
+
+		prio_saved_chips[prio] = chip;
+		data->chip = (struct irq_chip *)direct;
+		irq_to_prio[cic_irq] = prio;
+		prio_to_irq[prio] = cic_irq;
+
+		__irq_megamod_map(irq_src, prio);
+
+		if (output < NR_CIC_COMBINERS)
+			irq_set_chained_handler(irq_src, handle_combined_irq);
+
+		goto out_unlock;
+	}
+#endif
+	desc = irq_to_desc(irq_src);
+	chip = (struct c6x_irq_chip *)desc->irq_data.chip;
+
+	direct = &direct_chips[prio_idx];
+	if (irq_src < NR_MEGAMOD_COMBINERS)
+		memset(&direct->chip, 0, sizeof(direct->chip));
+	else
+		*direct = *(struct c6x_irq_chip *)chip;
+	direct->chip.name = direct_chip_names[prio_idx];
+	direct->chip.irq_mask = mask_direct;
+	direct->chip.irq_unmask = unmask_direct;
+
+	prio_saved_chips[prio] = chip;
+	irq_set_chip(irq_src, (struct irq_chip *)direct);
+	irq_to_prio[irq_src] = prio;
+	prio_to_irq[prio] = irq_src;
+
+	__irq_megamod_map(irq_src, prio);
+
+	if (irq_src < NR_MEGAMOD_COMBINERS) {
+		irq_set_handler_data(irq_src, &megamod_handler_info[irq_src]);
+		irq_set_chained_handler(irq_src, handle_combined_irq);
+	}
+
+out_unlock:
+	spin_unlock_irqrestore(&map_lock, flags);
+}
+EXPORT_SYMBOL(irq_map);
+
+
+#if NR_CIC_COMBINERS > 0
+/*
+ * Setup CIC event mappings on given core.
+ */
+static inline void __irq_cic_map(int core, unsigned int src, unsigned int dst)
+{
+	uint32_t val;
+	int offset, nr_srcs;
+
+	nr_srcs = (NR_CIC_COMBINERS * 32);
+
+	/* output0 and output1 are hardwired */
+	BUG_ON(dst < 2 || dst > 15);
+	BUG_ON(src >= nr_srcs);
+
+	offset = (dst & 3) << 3;
+	val = CIC_MUX(core)[dst >> 2];
+	val &= ~(0x7f << offset);
+	val |= ((src & 0x7f) << offset);
+	CIC_MUX(core)[dst >> 2] = val;
+}
+
+/*
+ * Map a C64x+ CIC IRQ to a megamodule event
+ *
+ * Do nothing for CIC combined IRQs. They are always mapped.
+ */
+void irq_cic_map(unsigned int irq_src, unsigned int irq_dst)
+{
+	struct irq_desc *desc;
+	struct c6x_irq_chip *chip, *mmchip;
+	unsigned long flags;
+	int src, output;
+	struct combiner_handler_info *info;
+	unsigned int idx = irq_dst - (CIC_MAPBASE + NR_CIC_COMBINERS);
+
+	if (irq_dst < (CIC_MAPBASE + NR_CIC_COMBINERS) ||
+	    irq_dst >= (CIC_MAPBASE + CIC_MAPLEN))
+		return;
+
+	/* only map CIC event sources */
+	if (irq_src < (IRQ_CIC_START + NR_CIC_COMBINERS) ||
+	    irq_src >= (IRQ_CIC_START + NR_CIC_IRQS))
+		return;
+
+	src = irq_src - IRQ_CIC_START;
+	output = irq_dst - CIC_MAPBASE;
+
+	spin_lock_irqsave(&map_lock, flags);
+
+	/* make sure this IRQ is not already mapped */
+	if (cic_evt_to_output[src])
+		goto out_unlock;
+
+	/* make sure the requested output is not in use */
+	if (cic_output_to_evt[output])
+		goto out_unlock;
+
+	/* record the mapping */
+	cic_evt_to_output[src] = output;
+	cic_output_to_evt[output] = src;
+
+	mmchip = &megamod_chips[(CIC_MAPBASE + output) / 32];
+	info = &megamod_handler_info[(CIC_MAPBASE + output) / 32];
+	info->irqmap[(CIC_MAPBASE + output) & 31] = irq_src;
+
+	desc = irq_to_desc(irq_src);
+	cic_saved_chips[idx] = (struct c6x_irq_chip *)desc->irq_data.chip;
+
+	chip = &cic_mapped_chips[idx];
+	*chip = *(struct c6x_irq_chip *)desc->irq_data.chip;
+	chip->chip.name = mmchip->chip.name;
+	chip->minfo = mmchip->minfo;
+
+	desc->irq_data.chip = (struct irq_chip *)chip;
+
+	__irq_cic_map(get_coreid(), src, output);
+out_unlock:
+	spin_unlock_irqrestore(&map_lock, flags);
+}
+EXPORT_SYMBOL(irq_cic_map);
+
+/*
+ * Map a CIC source to a give CIC output event for a given core or TPCC
+ */
+void cic_raw_map(unsigned int src, unsigned int dst, int core)
+{
+	__irq_cic_map(core, src, dst);
+}
+EXPORT_SYMBOL(cic_raw_map);
+
+#endif  /* NR_CIC_COMBINERS > 0 */
+
+void __init init_pic_c64xplus(void)
+{
+	int i, j, idx;
+	struct irq_desc *desc;
+	struct c6x_irq_chip *c6x_chip, *last_chip;
+	struct irq_chip *chip;
+	struct combiner_mask_info *minfo;
+	struct combiner_handler_info *hinfo;
+#if NR_CIC_COMBINERS > 0
+	unsigned core = get_coreid();
+#endif
+
+	spin_lock_init(&map_lock);
+
+	/* initialize chip info */
+	minfo = &megamod_mask_info[0];
+	hinfo = &megamod_handler_info[0];
+	for (i = 0; i < NR_MEGAMOD_COMBINERS; i++) {
+		minfo->irq_base = IRQ_EVT0 + (i * 32);
+		minfo->evtmask  = &IC_EVTMASK[i];
+		hinfo->mevtflag = &IC_MEVTFLAG[i];
+		hinfo->evtclr   = &IC_EVTCLR[i];
+		for (j = 0; j < 32; j++)
+			hinfo->irqmap[j] = minfo->irq_base + j;
+		minfo++;
+		hinfo++;
+	}
+#if NR_CIC_COMBINERS > 0
+	minfo = &cic_mask_info[0];
+	hinfo = &cic_handler_info[0];
+	for (i = 0; i < NR_CIC_COMBINERS; i++) {
+		minfo->irq_base = IRQ_CIC_START + (i * 32);
+		minfo->evtmask  = &CIC_EVTMASK(core)[i];
+		hinfo->mevtflag = &CIC_MEVTFLAG(core)[i];
+		hinfo->evtclr   = &CIC_EVTCLR(core)[i];
+		for (j = 0; j < 32; j++)
+			hinfo->irqmap[j] = minfo->irq_base + j;
+		minfo++;
+		hinfo++;
+	}
+#endif
+
+	/* initialize mapping arrays */
+	for (i = 0; i < NR_SYS_IRQS; i++)
+		prio_to_irq[i] = IRQ_UNMAPPED;
+	memset(&irq_to_prio[0], 0, sizeof(irq_to_prio));
+#if NR_CIC_COMBINERS > 0
+	memset(&cic_output_to_evt[0], 0, sizeof(cic_output_to_evt));
+	memset(&cic_evt_to_output[0], 0, sizeof(cic_evt_to_output));
+#endif
+
+	/* initialize megamodule combined IRQs */
+	for (i = 0; i < NR_MEGAMOD_COMBINERS; i++) {
+		desc = irq_to_desc(i);
+
+		IC_EVTMASK[i] = ~0;	/* mask all events */
+		IC_EVTCLR[i] = ~0;	/* clear all events */
+
+		irq_set_chip_and_handler(i, &dummy_irq_chip, handle_bad_irq);
+
+		megamod_chips[i].minfo = &megamod_mask_info[i];
+		irq_set_handler_data(i, &megamod_handler_info[i]);
+	}
+
+	/* initialize individual megamodule IRQs */
+	for (i = NR_MEGAMOD_COMBINERS; i < (NR_MEGAMOD_COMBINERS * 32); i++) {
+		chip = (struct irq_chip *)&megamod_chips[i / 32];
+		irq_set_chip_and_handler(i, chip, handle_level_irq);
+	}
+
+#if NR_CIC_COMBINERS > 0
+	/* megamodule IRQs coming from CIC cannot be used directly */
+	for (i = CIC_MAPBASE; i < (CIC_MAPBASE + CIC_MAPLEN); i++)
+		irq_set_chip_and_handler(i, &dummy_irq_chip, handle_bad_irq);
+
+	/* CIC combined IRQs are hardwired to CIC_MAPBASE in megamodule */
+	for (i = 0; i < NR_CIC_COMBINERS; i++) {
+		int irq = IRQ_CIC_START + i;
+
+		CIC_EVTMASK(core)[i] = ~0;	/* mask all events */
+		CIC_EVTCLR(core)[i] = ~0;	/* clear all events */
+
+		cic_chips[i].minfo = &cic_mask_info[i];
+
+		/* chip info for megamodule combiner we are wired through */
+		chip = (struct irq_chip *)&megamod_chips[(CIC_MAPBASE + i)/32];
+		hinfo = &megamod_handler_info[(CIC_MAPBASE + i) / 32];
+
+		/* redirect megamodule irq to right place */
+		hinfo->irqmap[(CIC_MAPBASE + i) & 31] = irq;
+
+		irq_set_chip(irq, chip);
+		irq_set_handler_data(irq, &cic_handler_info[i]);
+		irq_set_chained_handler(irq, handle_combined_irq);
+	}
+
+	/* initialize individual CIC IRQs */
+	for (i = NR_CIC_COMBINERS; i < (NR_CIC_COMBINERS * 32); i++) {
+		int irq = IRQ_CIC_START + i;
+
+		irq_set_chip(irq, (struct irq_chip *)&cic_chips[i / 32]);
+		irq_set_handler(irq, handle_level_irq);
+	}
+
+	/*
+	 * clear again megamodule combined IRQs because spurious CIC interrupts
+	 * may have occur after the CIC initialization.
+	 */
+	for (i = 0; i < NR_MEGAMOD_COMBINERS; i++)
+		IC_EVTCLR[i] = ~0;	/* clear all events */
+#endif
+
+	/*
+	 * GPIO interrupts need separate copies of megamodule chips
+	 * so gpio code can add edge triggering support.
+	 */
+	last_chip = NULL;
+	idx = 0;
+	for (i = IRQ_GPIO_START; i <= IRQ_GPIO15; i++) {
+		c6x_chip = (struct c6x_irq_chip *)irq_to_desc(i)->irq_data.chip;
+		if (c6x_chip != last_chip) {
+			last_chip = c6x_chip;
+			gpio_chips[idx++] = *c6x_chip;
+		}
+		irq_to_desc(i)->irq_data.chip = &gpio_chips[idx - 1].chip;
+	}
+
+	/* map megamodule combined IRQs to low-priority core IRQs */
+	irq_map(IRQ_EVT0, INT12);
+	irq_map(IRQ_EVT1, INT13);
+	irq_map(IRQ_EVT2, INT14);
+	irq_map(IRQ_EVT3, INT15);
+}
diff --git a/drivers/platform/c6x/pll-tci648x.c b/drivers/platform/c6x/pll-tci648x.c
new file mode 100644
index 0000000..ae15659
--- /dev/null
+++ b/drivers/platform/c6x/pll-tci648x.c
@@ -0,0 +1,433 @@
+/*
+ * Clock and PLL control for TCI648x devices
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ * Contributed by: Mark Salter <msalter@redhat.com>
+ *
+ * Copied heavily from arm/mach-davinci/clock.c, so:
+ *
+ * Copyright (C) 2006-2007 Texas Instruments.
+ * Copyright (C) 2008-2009 Deep Root Systems, LLC
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include <asm/clock.h>
+
+static LIST_HEAD(clocks);
+static DEFINE_MUTEX(clocks_mutex);
+static DEFINE_SPINLOCK(clockfw_lock);
+
+static void __clk_enable(struct clk *clk)
+{
+	if (clk->parent)
+		__clk_enable(clk->parent);
+	clk->usecount++;
+}
+
+static void __clk_disable(struct clk *clk)
+{
+	if (WARN_ON(clk->usecount == 0))
+		return;
+	--clk->usecount;
+
+	if (clk->parent)
+		__clk_disable(clk->parent);
+}
+
+int clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+
+	if (clk == NULL || IS_ERR(clk))
+		return -EINVAL;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	__clk_enable(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+
+	if (clk == NULL || IS_ERR(clk))
+		return;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	__clk_disable(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk == NULL || IS_ERR(clk))
+		return -EINVAL;
+
+	return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk == NULL || IS_ERR(clk))
+		return -EINVAL;
+
+	if (clk->round_rate)
+		return clk->round_rate(clk, rate);
+
+	return clk->rate;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+/* Propagate rate to children */
+static void propagate_rate(struct clk *root)
+{
+	struct clk *clk;
+
+	list_for_each_entry(clk, &root->children, childnode) {
+		if (clk->recalc)
+			clk->rate = clk->recalc(clk);
+		propagate_rate(clk);
+	}
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long flags;
+	int ret = -EINVAL;
+
+	if (clk == NULL || IS_ERR(clk))
+		return ret;
+
+	if (clk->set_rate)
+		ret = clk->set_rate(clk, rate);
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (ret == 0) {
+		if (clk->recalc)
+			clk->rate = clk->recalc(clk);
+		propagate_rate(clk);
+	}
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	unsigned long flags;
+
+	if (clk == NULL || IS_ERR(clk))
+		return -EINVAL;
+
+	/* Cannot change parent on enabled clock */
+	if (WARN_ON(clk->usecount))
+		return -EINVAL;
+
+	mutex_lock(&clocks_mutex);
+	clk->parent = parent;
+	list_del_init(&clk->childnode);
+	list_add(&clk->childnode, &clk->parent->children);
+	mutex_unlock(&clocks_mutex);
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (clk->recalc)
+		clk->rate = clk->recalc(clk);
+	propagate_rate(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(clk_set_parent);
+
+int clk_register(struct clk *clk)
+{
+	if (clk == NULL || IS_ERR(clk))
+		return -EINVAL;
+
+	if (WARN(clk->parent && !clk->parent->rate,
+		 "CLK: %s parent %s has no rate!\n",
+		 clk->name, clk->parent->name))
+		return -EINVAL;
+
+	mutex_lock(&clocks_mutex);
+	list_add_tail(&clk->node, &clocks);
+	if (clk->parent)
+		list_add_tail(&clk->childnode, &clk->parent->children);
+	mutex_unlock(&clocks_mutex);
+
+	/* If rate is already set, use it */
+	if (clk->rate)
+		return 0;
+
+	/* Else, see if there is a way to calculate it */
+	if (clk->recalc)
+		clk->rate = clk->recalc(clk);
+
+	/* Otherwise, default to parent rate */
+	else if (clk->parent)
+		clk->rate = clk->parent->rate;
+
+	return 0;
+}
+EXPORT_SYMBOL(clk_register);
+
+void clk_unregister(struct clk *clk)
+{
+	if (clk == NULL || IS_ERR(clk))
+		return;
+
+	mutex_lock(&clocks_mutex);
+	list_del(&clk->node);
+	list_del(&clk->childnode);
+	mutex_unlock(&clocks_mutex);
+}
+EXPORT_SYMBOL(clk_unregister);
+
+static unsigned long clk_sysclk_recalc(struct clk *clk)
+{
+	u32 v, plldiv = 0;
+	struct pll_data *pll;
+	unsigned long rate = clk->rate;
+
+	if (WARN_ON(!clk->parent))
+		return rate;
+
+	rate = clk->parent->rate;
+
+	/* the parent must be a PLL */
+	if (WARN_ON(!clk->parent->pll_data))
+		return rate;
+
+	pll = clk->parent->pll_data;
+
+	/* If pre-PLL, source clock is before the multiplier and divider(s) */
+	if (clk->flags & PRE_PLL)
+		rate = pll->input_rate;
+
+	if (!clk->div) {
+		pr_debug("%s: (no divider) rate = %lu KHz\n",
+			 clk->name, rate / 1000);
+		return rate;
+	}
+
+	if (clk->flags & FIXED_DIV_PLL) {
+		rate /= clk->div;
+		pr_debug("%s: (fixed divide by %d) rate = %lu KHz\n",
+			 clk->name, clk->div, rate / 1000);
+		return rate;
+	}
+
+	v = __raw_readl(pll->base + clk->div);
+	if (v & PLLDIV_EN)
+		plldiv = (v & PLLDIV_RATIO_MASK) + 1;
+
+	if (plldiv == 0)
+		plldiv = 1;
+
+	rate /= plldiv;
+
+	pr_debug("%s: (divide by %d) rate = %lu KHz\n",
+		 clk->name, plldiv, rate / 1000);
+
+	return rate;
+}
+
+static unsigned long clk_leafclk_recalc(struct clk *clk)
+{
+	if (WARN_ON(!clk->parent))
+		return clk->rate;
+
+	pr_debug("%s: (parent %s) rate = %lu KHz\n",
+		 clk->name, clk->parent->name,	clk->parent->rate / 1000);
+
+	return clk->parent->rate;
+}
+
+static unsigned long clk_pllclk_recalc(struct clk *clk)
+{
+	u32 ctrl, mult = 1, prediv = 1;
+	u8 bypass;
+	struct pll_data *pll = clk->pll_data;
+	unsigned long rate = clk->rate;
+
+	if (clk->flags & FIXED_RATE_PLL)
+		return rate;
+
+	pll->base = ioremap(pll->phys_base, 1024);
+	ctrl = __raw_readl(pll->base + PLLCTL);
+	rate = pll->input_rate = clk->parent->rate;
+
+	if (ctrl & PLLCTL_PLLEN) {
+		bypass = 0;
+		mult = __raw_readl(pll->base + PLLM);
+		mult = (mult & PLLM_PLLM_MASK) + 1;
+	} else
+		bypass = 1;
+
+	if (pll->flags & PLL_HAS_PREDIV) {
+		prediv = __raw_readl(pll->base + PREDIV);
+		if (prediv & PLLDIV_EN)
+			prediv = (prediv & PLLDIV_RATIO_MASK) + 1;
+		else
+			prediv = 1;
+	}
+
+	if (!bypass) {
+		rate /= prediv;
+		rate *= mult;
+	}
+
+	pr_debug("PLL%d: input = %lu MHz [ ",
+		 pll->num, clk->parent->rate / 1000000);
+	if (bypass)
+		pr_debug("bypass ");
+	if (prediv > 1)
+		pr_debug("/ %d ", prediv);
+	if (mult > 1)
+		pr_debug("* %d ", mult);
+	pr_debug("] --> %lu MHz output.\n", rate / 1000000);
+
+	return rate;
+}
+
+
+int __init c6x_clk_init(struct clk_lookup *clocks)
+{
+	struct clk_lookup *c;
+	struct clk *clk;
+	size_t num_clocks = 0;
+
+	for (c = clocks; c->clk; c++) {
+		clk = c->clk;
+
+		INIT_LIST_HEAD(&clk->node);
+		INIT_LIST_HEAD(&clk->children);
+		INIT_LIST_HEAD(&clk->childnode);
+
+		if (!clk->recalc) {
+
+			/* Check if clock is a PLL */
+			if (clk->pll_data)
+				clk->recalc = clk_pllclk_recalc;
+
+			/* Else, if it is a PLL-derived clock */
+			else if (clk->flags & CLK_PLL)
+				clk->recalc = clk_sysclk_recalc;
+
+			/* Otherwise, it is a leaf clock (PSC clock) */
+			else if (clk->parent)
+				clk->recalc = clk_leafclk_recalc;
+		}
+
+		if (clk->recalc)
+			clk->rate = clk->recalc(clk);
+
+		clk_register(clk);
+		num_clocks++;
+
+		/* Turn on clocks that Linux doesn't otherwise manage */
+		if (clk->flags & ALWAYS_ENABLED)
+			clk_enable(clk);
+	}
+
+	clkdev_add_table(clocks, num_clocks);
+
+	return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#define CLKNAME_MAX	10		/* longest clock name */
+#define NEST_DELTA	2
+#define NEST_MAX	4
+
+static void
+dump_clock(struct seq_file *s, unsigned nest, struct clk *parent)
+{
+	char		*state;
+	char		buf[CLKNAME_MAX + NEST_DELTA * NEST_MAX];
+	struct clk	*clk;
+	unsigned	i;
+
+	if (parent->flags & CLK_PLL)
+		state = "pll";
+	else
+		state = "";
+
+	/* <nest spaces> name <pad to end> */
+	memset(buf, ' ', sizeof(buf) - 1);
+	buf[sizeof(buf) - 1] = 0;
+	i = strlen(parent->name);
+	memcpy(buf + nest, parent->name,
+	       min(i, (unsigned)(sizeof(buf) - 1 - nest)));
+
+	seq_printf(s, "%s users=%2d %-3s %9ld Hz\n",
+		   buf, parent->usecount, state, clk_get_rate(parent));
+	/* REVISIT show device associations too */
+
+	/* cost is now small, but not linear... */
+	list_for_each_entry(clk, &parent->children, childnode) {
+		dump_clock(s, nest + NEST_DELTA, clk);
+	}
+}
+
+static int c6x_ck_show(struct seq_file *m, void *v)
+{
+	struct clk *clk;
+
+	/*
+	 * Show clock tree; We trust nonzero usecounts equate to PSC enables...
+	 */
+	mutex_lock(&clocks_mutex);
+	list_for_each_entry(clk, &clocks, node)
+		if (!clk->parent)
+			dump_clock(m, 0, clk);
+	mutex_unlock(&clocks_mutex);
+
+	return 0;
+}
+
+static int c6x_ck_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, c6x_ck_show, NULL);
+}
+
+static const struct file_operations c6x_ck_operations = {
+	.open		= c6x_ck_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int __init c6x_clk_debugfs_init(void)
+{
+	debugfs_create_file("c6x_clocks", S_IFREG | S_IRUGO, NULL, NULL,
+			    &c6x_ck_operations);
+
+	return 0;
+}
+device_initcall(c6x_clk_debugfs_init);
+#endif /* CONFIG_DEBUG_FS */
diff --git a/drivers/platform/c6x/timer-tci648x.c b/drivers/platform/c6x/timer-tci648x.c
new file mode 100644
index 0000000..79cda27
--- /dev/null
+++ b/drivers/platform/c6x/timer-tci648x.c
@@ -0,0 +1,121 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2010, 2011 Texas Instruments Incorporated
+ *  Contributed by: Mark Salter (msalter@redhat.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/percpu.h>
+#include <linux/smp.h>
+#include <linux/io.h>
+#include <linux/bug.h>
+
+#include <asm/irq.h>
+#include <asm/timer.h>
+#include <asm/system.h>
+
+#include <mach/board.h>
+
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+
+static int next_event(unsigned long delta,
+		      struct clock_event_device *evt)
+{
+	u32 timer_CNTLO = TIMER_CNTLO_REG(LINUX_TIMER_SRC);
+	u32 timer_PRDLO = TIMER_PRDLO_REG(LINUX_TIMER_SRC);
+	u32 timer_TCR	= TIMER_TCR_REG(LINUX_TIMER_SRC);
+
+	TIMER_REG(timer_TCR)  &= ~TIMER_B_TCR_ENAMODELO_MASK;
+	TIMER_REG(timer_PRDLO) = delta - 1;
+	TIMER_REG(timer_CNTLO) = 0;
+	TIMER_REG(timer_TCR) |= TIMER_B_TCR_ENAMODELO_ONCE;
+
+	return 0;
+}
+
+static void set_clock_mode(enum clock_event_mode mode,
+			   struct clock_event_device *evt)
+{
+}
+
+static void event_handler(struct clock_event_device *dev)
+{
+}
+
+static struct clock_event_device t64_clockevent_device;
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *cd = &t64_clockevent_device;
+
+	cd->event_handler(cd);
+
+	return IRQ_HANDLED;
+}
+
+int __init c6x_arch_init_clockevents(void)
+{
+	struct clock_event_device *cd = &t64_clockevent_device;
+	u64 temp;
+	u32 shift, timer_TCR, timer_TGCR;
+	u32 timer_PRDLO, timer_CNTLO, timer_EMUMGTCLKSPD;
+
+	timer_TCR	   = TIMER_TCR_REG(LINUX_TIMER_SRC);
+	timer_TGCR	   = TIMER_TGCR_REG(LINUX_TIMER_SRC);
+	timer_CNTLO	   = TIMER_CNTLO_REG(LINUX_TIMER_SRC);
+	timer_PRDLO	   = TIMER_PRDLO_REG(LINUX_TIMER_SRC);
+	timer_EMUMGTCLKSPD = TIMER_EMUMGTCLKSPD_REG(LINUX_TIMER_SRC);
+
+	/* disable timer, reset count */
+	TIMER_REG(timer_TCR)  &= ~TIMER_B_TCR_ENAMODELO_MASK;
+	TIMER_REG(timer_PRDLO) = 0;
+
+	/* use internal clock and 1 cycle pulse width */
+	TIMER_REG(timer_TCR)  &= ~(TIMER_B_TCR_CLKSRCLO | TIMER_B_TCR_PWIDLO_MASK);
+
+	/* dual 32-bit unchained mode */
+	TIMER_REG(timer_TGCR) &= ~TIMER_B_TGCR_TIMMODE_MASK;
+	TIMER_REG(timer_TGCR) |= (TIMER_B_TGCR_TIMLORS | TIMER_B_TGCR_TIMMODE_UD32);
+
+	cd->irq		= LINUX_TIMER_IRQ;
+	cd->name	= "TIMER64_EVT32_TIMER";
+	cd->features	= CLOCK_EVT_FEAT_ONESHOT;
+
+	/* Calculate the min / max delta */
+	/* Find a shift value */
+	for (shift = 32; shift > 0; shift--) {
+		temp = (u64)(c6x_core_freq / TIMER_DIVISOR(LINUX_TIMER_SRC));
+		temp <<=  shift;
+
+		do_div(temp, NSEC_PER_SEC);
+		if ((temp >> 32) == 0)
+			break;
+	}
+	cd->shift = shift;
+	cd->mult = (u32) temp;
+
+	cd->max_delta_ns	= clockevent_delta2ns(0x7fffffff, cd);
+	cd->min_delta_ns	= clockevent_delta2ns(250, cd);
+
+	cd->rating		= 200;
+	cd->set_mode		= set_clock_mode;
+	cd->event_handler	= event_handler;
+	cd->set_next_event	= next_event;
+	cd->cpumask		= cpumask_of(smp_processor_id());
+
+	clockevents_register_device(cd);
+
+	/* Set handler */
+	request_irq(cd->irq, timer_interrupt, IRQF_DISABLED | IRQF_TIMER,
+		    "timer", NULL);
+
+	return 0;
+}
+
+#endif /* CONFIG_GENERIC_CLOCKEVENTS */
+
diff --git a/drivers/platform/c6x/tsc-c64xplus.c b/drivers/platform/c6x/tsc-c64xplus.c
new file mode 100644
index 0000000..437bf25
--- /dev/null
+++ b/drivers/platform/c6x/tsc-c64xplus.c
@@ -0,0 +1,53 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2010 Texas Instruments Incorporated
+ *  Contributed by: Mark Salter <msalter@redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#include <linux/clocksource.h>
+#include <asm/timer.h>
+
+
+#ifdef CONFIG_GENERIC_TIME
+static cycle_t tsc_read(struct clocksource *cs)
+{
+	return get_cycles();
+}
+
+static struct clocksource clocksource_tsc = {
+	.name		= "TSC64",
+	.rating		= 300,
+	.read		= tsc_read,
+	.mask		= CLOCKSOURCE_MASK(64),
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+int __init c6x_arch_init_clocksource(void)
+{
+	struct clocksource *cs = &clocksource_tsc;
+	u64 temp;
+	u32 shift;
+
+	/* Find a shift value */
+	for (shift = 32; shift > 0; shift--) {
+		temp = (u64) NSEC_PER_SEC << shift;
+		do_div(temp, c6x_core_freq);
+		if ((temp >> 32) == 0)
+			break;
+	}
+	cs->shift = shift;
+	cs->mult = (u32) temp;
+
+	/* write anything into TSCL to enable counting */
+	set_creg(TSCL, 0);
+
+	clocksource_register(cs);
+
+	return 0;
+}
+#endif /* CONFIG_GENERIC_TIME */
+
-- 
1.6.2.5


  reply	other threads:[~2011-05-11 21:06 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-05-11 20:13 [PATCH] arch/c6x: new architecture port for linux Mark Salter
2011-05-11 20:13 ` [PATCH 01/16] fix default __strnlen_user macro Mark Salter
2011-05-11 20:13   ` [PATCH 02/16] fixed generic page.h for non-zero PAGE_OFFSET Mark Salter
2011-05-11 20:13     ` [PATCH 03/16] add driver for C64x+ ethernet driver Mark Salter
2011-05-11 20:13       ` [PATCH 04/16] add support for C64x+ debugger based console Mark Salter
2011-05-11 20:13         ` [PATCH 05/16] add ELF machine define for TI C6X DSPs Mark Salter
2011-05-11 20:13           ` [PATCH 06/16] add maintainers entry for C6X arch Mark Salter
2011-05-11 20:13             ` [PATCH 07/16] C6X: add toplevel configury and makefile Mark Salter
2011-05-11 20:13               ` [PATCH 08/16] C6X: add include files Mark Salter
2011-05-11 20:13                 ` [PATCH 09/16] C6X: add kernel files Mark Salter
2011-05-11 20:13                   ` [PATCH 10/16] C6X: add mm files Mark Salter
2011-05-11 20:13                     ` [PATCH 11/16] C6X: add lib files Mark Salter
2011-05-11 20:13                       ` [PATCH 12/16] C6X: add platform files Mark Salter
2011-05-11 20:14                         ` Mark Salter [this message]
2011-05-11 20:14                           ` [PATCH 14/16] C6X: add default configs Mark Salter
2011-05-11 20:14                             ` [PATCH 15/16] Add new elf binfmt support for DSBT Mark Salter
2011-05-11 20:14                               ` [PATCH 16/16] C6X: add support for DSBT binary format Mark Salter
2011-05-12  2:41         ` [04/16] add support for C64x+ debugger based console Milton Miller
2011-05-12 12:55           ` Mark Salter
2011-05-12  0:49       ` [PATCH 03/16] add driver for C64x+ ethernet driver Joe Perches
2011-05-13 15:30       ` Ben Hutchings
2011-05-13 13:55   ` [PATCH 01/16] fix default __strnlen_user macro Pavel Machek
2011-05-13 14:40     ` Mark Salter
2011-05-11 20:13 ` [PATCH] arch/c6x: new architecture port for linux Milton Miller
2011-05-12 12:34   ` Mark Salter
2011-05-11 21:34 ` Randy Dunlap
2011-05-12  0:57   ` Mark Salter
2011-05-12  1:07     ` Randy Dunlap
2011-05-12  1:16       ` Mark Salter
2011-05-21 17:10 ` Arnd Bergmann
2011-05-21 17:46   ` Geert Uytterhoeven
2011-06-16 12:54   ` Mark Salter
2011-06-16 14:02     ` Arnd Bergmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1305144843-5058-14-git-send-email-msalter@redhat.com \
    --to=msalter@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox