LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ppc32/64: Map prefetchable PCI without guarded bit
From: Benjamin Herrenschmidt @ 2005-03-24  6:24 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linuxppc-dev list, Linux Kernel list

Hi !

While experimenting with framebuffer access performances, we noticed a
very significant improvement in write access to it when not setting
the "guarded" bit on the MMU mappings. This bit basically says that
reads and writes won't have side effects (it allows speculation). It
appears that it also disables write combining.

This patch implements a new phys_mem_access_prot() arch callback for
use by /dev/mem and fbdev when available, implements it for ppc32 and
ppc64, and modifies /dev/mem and fbdev to use it, respectively when
available or on ppc. I didn't change fbdev to use it on all archs
when available because there is already a whole lot of arch specific
mess in there (more than in /dev/mem !) that I didn't feel like messing
with, but archs maintainers are welcome to give it a go).

The old mecanism in /dev/mem is still there, but arch maintainers should
probably switch to this once which is more consistent imho.

Finally, the ppc32 and ppc64 implementation of this and of the PCI mmap
calls (used by /proc and /sys) are modified to check if the mapping
happens in a prefetchable PCI resource, in which case, the guarded bit
is not set for the pgprot. In fact, ppc32 implementation of this code is
updated to be identical to ppc64.

This improves framebuffer write performance on a simple test paul wrote
from about 50Mb/sec to 200Mb/sec on my M9 based laptop and on a G5. The
new hook will automatically catch up Xfree mmap's from /dev/mem, so it
will work out of the box with existing X servers. Kernel fbdev accesses
aren't improved yet as ioremap doesn't use that mecanism.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

Index: linux-work/drivers/char/mem.c
===================================================================
--- linux-work.orig/drivers/char/mem.c	2005-03-24 16:25:43.000000000 +1100
+++ linux-work/drivers/char/mem.c	2005-03-24 16:26:05.000000000 +1100
@@ -76,14 +76,6 @@
 	 * On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases.
 	 */
 	return !(efi_mem_attributes(addr) & EFI_MEMORY_WB);
-#elif defined(CONFIG_PPC64)
-	/* On PPC64, we always do non-cacheable access to the IO hole and
-	 * cacheable elsewhere. Cache paradox can checkstop the CPU and
-	 * the high_memory heuristic below is wrong on machines with memory
-	 * above the IO hole... Ah, and of course, XFree86 doesn't pass
-	 * O_SYNC when mapping us to tap IO space. Surprised ?
-	 */
-	return !page_is_ram(addr >> PAGE_SHIFT);
 #else
 	/*
 	 * Accessing memory above the top the kernel knows about or through a file pointer
@@ -238,7 +230,13 @@
 
 static int mmap_mem(struct file * file, struct vm_area_struct * vma)
 {
-#ifdef pgprot_noncached
+#if defined(__HAVE_PHYS_MEM_ACCESS_PROT)
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+	vma->vm_page_prot = phys_mem_access_prot(file, offset,
+						 vma->vm_end - vma->vm_start,
+						 vma->vm_page_prot);
+#elif defined(pgprot_noncached)
 	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
 	int uncached;
 
Index: linux-work/include/asm-ppc64/machdep.h
===================================================================
--- linux-work.orig/include/asm-ppc64/machdep.h	2005-03-24 16:25:43.000000000 +1100
+++ linux-work/include/asm-ppc64/machdep.h	2005-03-24 16:26:05.000000000 +1100
@@ -21,6 +21,7 @@
 struct device_node;
 struct iommu_table;
 struct rtc_time;
+struct file;
 
 #ifdef CONFIG_SMP
 struct smp_ops_t {
@@ -131,6 +132,12 @@
 	/* Get legacy PCI/IDE interrupt mapping */ 
 	int		(*pci_get_legacy_ide_irq)(struct pci_dev *dev, int channel);
 	
+	/* Get access protection for /dev/mem */
+	pgprot_t	(*phys_mem_access_prot)(struct file *file,
+						unsigned long offset,
+						unsigned long size,
+						pgprot_t vma_prot);
+
 };
 
 extern struct machdep_calls ppc_md;
Index: linux-work/drivers/video/fbmem.c
===================================================================
--- linux-work.orig/drivers/video/fbmem.c	2005-03-24 16:25:43.000000000 +1100
+++ linux-work/drivers/video/fbmem.c	2005-03-24 16:26:05.000000000 +1100
@@ -957,7 +957,9 @@
 	}
 #endif
 #elif defined(__powerpc__)
-	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;
+	vma->vm_page_prot = phys_mem_access_prot(file, off,
+						 vma->vm_end - vma->vm_start,
+						 vma->vm_page_prot);
 #elif defined(__alpha__)
 	/* Caching is off in the I/O space quadrant by design.  */
 #elif defined(__i386__) || defined(__x86_64__)
Index: linux-work/include/asm-ppc64/pgtable.h
===================================================================
--- linux-work.orig/include/asm-ppc64/pgtable.h	2005-03-24 16:25:43.000000000 +1100
+++ linux-work/include/asm-ppc64/pgtable.h	2005-03-24 16:26:05.000000000 +1100
@@ -472,6 +472,11 @@
  */
 #define pgprot_noncached(prot)	(__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED))
 
+struct file;
+extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
+				     unsigned long size, pgprot_t vma_prot);
+#define __HAVE_PHYS_MEM_ACCESS_PROT
+
 #define __HAVE_ARCH_PTE_SAME
 #define pte_same(A,B)	(((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0)
 
Index: linux-work/arch/ppc64/kernel/pci.c
===================================================================
--- linux-work.orig/arch/ppc64/kernel/pci.c	2005-03-24 16:25:43.000000000 +1100
+++ linux-work/arch/ppc64/kernel/pci.c	2005-03-24 17:10:21.000000000 +1100
@@ -210,6 +210,11 @@
 	struct pci_controller *hose, *tmp;
 	struct pci_bus *bus;
 
+	/* For now, override phys_mem_access_prot. If we need it,
+	 * later, we may move that initialization to each ppc_md
+	 */
+	ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
+
 #ifdef CONFIG_PPC_ISERIES
 	iSeries_pcibios_init(); 
 #endif
@@ -330,25 +335,24 @@
  *
  * Returns negative error code on failure, zero on success.
  */
-static __inline__ int __pci_mmap_make_offset(struct pci_dev *dev,
-					     struct vm_area_struct *vma,
-					     enum pci_mmap_state mmap_state)
+static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
+					       unsigned long *offset,
+					       enum pci_mmap_state mmap_state)
 {
 	struct pci_controller *hose = pci_bus_to_host(dev->bus);
-	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
 	unsigned long io_offset = 0;
 	int i, res_bit;
 
 	if (hose == 0)
-		return -EINVAL;		/* should never happen */
+		return NULL;		/* should never happen */
 
 	/* If memory, add on the PCI bridge address offset */
 	if (mmap_state == pci_mmap_mem) {
-		offset += hose->pci_mem_offset;
+		*offset += hose->pci_mem_offset;
 		res_bit = IORESOURCE_MEM;
 	} else {
 		io_offset = (unsigned long)hose->io_base_virt;
-		offset += io_offset;
+		*offset += io_offset;
 		res_bit = IORESOURCE_IO;
 	}
 
@@ -369,50 +373,106 @@
 			continue;
 
 		/* In the range of this resource? */
-		if (offset < (rp->start & PAGE_MASK) || offset > rp->end)
+		if (*offset < (rp->start & PAGE_MASK) || *offset > rp->end)
 			continue;
 
 		/* found it! construct the final physical address */
 		if (mmap_state == pci_mmap_io)
-			offset += hose->io_base_phys - io_offset;
-
-		vma->vm_pgoff = offset >> PAGE_SHIFT;
-		return 0;
+			*offset += hose->io_base_phys - io_offset;
+		return rp;
 	}
 
-	return -EINVAL;
-}
-
-/*
- * Set vm_flags of VMA, as appropriate for this architecture, for a pci device
- * mapping.
- */
-static __inline__ void __pci_mmap_set_flags(struct pci_dev *dev,
-					    struct vm_area_struct *vma,
-					    enum pci_mmap_state mmap_state)
-{
-	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
+	return NULL;
 }
 
 /*
  * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
  * device mapping.
  */
-static __inline__ void __pci_mmap_set_pgprot(struct pci_dev *dev,
-					     struct vm_area_struct *vma,
-					     enum pci_mmap_state mmap_state,
-					     int write_combine)
-{
-	long prot = pgprot_val(vma->vm_page_prot);
+static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
+				      pgprot_t protection,
+				      enum pci_mmap_state mmap_state,
+				      int write_combine)
+{
+	unsigned long prot = pgprot_val(protection);
+
+	/* Write combine is always 0 on non-memory space mappings. On
+	 * memory space, if the user didn't pass 1, we check for a
+	 * "prefetchable" resource. This is a bit hackish, but we use
+	 * this to workaround the inability of /sysfs to provide a write
+	 * combine bit
+	 */
+	if (mmap_state != pci_mmap_mem)
+		write_combine = 0;
+	else if (write_combine == 0) {
+		if (rp->flags & IORESOURCE_PREFETCH)
+			write_combine = 1;
+	}
 
 	/* XXX would be nice to have a way to ask for write-through */
 	prot |= _PAGE_NO_CACHE;
-	if (!write_combine)
+	if (write_combine)
+		prot &= ~_PAGE_GUARDED;
+	else
 		prot |= _PAGE_GUARDED;
-	vma->vm_page_prot = __pgprot(prot);
+
+	printk("PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start,
+	       prot);
+
+	return __pgprot(prot);
 }
 
 /*
+ * This one is used by /dev/mem and fbdev who have no clue about the
+ * PCI device, it tries to find the PCI device first and calls the
+ * above routine
+ */
+pgprot_t pci_phys_mem_access_prot(struct file *file,
+				  unsigned long offset,
+				  unsigned long size,
+				  pgprot_t protection)
+{
+	struct pci_dev *pdev = NULL;
+	struct resource *found = NULL;
+	unsigned long prot = pgprot_val(protection);
+	int i;
+
+	if (page_is_ram(offset >> PAGE_SHIFT))
+		return prot;
+
+	prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+
+	for_each_pci_dev(pdev) {
+		for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+			struct resource *rp = &pdev->resource[i];
+			int flags = rp->flags;
+
+			/* Active and same type? */
+			if ((flags & IORESOURCE_MEM) == 0)
+				continue;
+			/* In the range of this resource? */
+			if (offset < (rp->start & PAGE_MASK) ||
+			    offset > rp->end)
+				continue;
+			found = rp;
+			break;
+		}
+		if (found)
+			break;
+	}
+	if (found) {
+		if (found->flags & IORESOURCE_PREFETCH)
+			prot &= ~_PAGE_GUARDED;
+		pci_dev_put(pdev);
+	}
+
+	DBG("non-PCI map for %lx, prot: %lx\n", offset, prot);
+
+	return __pgprot(prot);
+}
+
+
+/*
  * Perform the actual remap of the pages for a PCI device mapping, as
  * appropriate for this architecture.  The region in the process to map
  * is described by vm_start and vm_end members of VMA, the base physical
@@ -426,14 +486,19 @@
 			enum pci_mmap_state mmap_state,
 			int write_combine)
 {
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	struct resource *rp;
 	int ret;
 
-	ret = __pci_mmap_make_offset(dev, vma, mmap_state);
-	if (ret < 0)
-		return ret;
+	rp = __pci_mmap_make_offset(dev, &offset, mmap_state);
+	if (rp == NULL)
+		return -EINVAL;
 
-	__pci_mmap_set_flags(dev, vma, mmap_state);
-	__pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine);
+	vma->vm_pgoff = offset >> PAGE_SHIFT;
+	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
+	vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
+						  vma->vm_page_prot,
+						  mmap_state, write_combine);
 
 	ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
 			       vma->vm_end - vma->vm_start, vma->vm_page_prot);
Index: linux-work/arch/ppc64/mm/init.c
===================================================================
--- linux-work.orig/arch/ppc64/mm/init.c	2005-03-24 16:25:43.000000000 +1100
+++ linux-work/arch/ppc64/mm/init.c	2005-03-24 16:26:05.000000000 +1100
@@ -912,3 +912,16 @@
 	if (!zero_cache)
 		panic("pgtable_cache_init(): could not create zero_cache!\n");
 }
+
+pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
+			      unsigned long size, pgprot_t vma_prot)
+{
+	if (ppc_md.phys_mem_access_prot)
+		return ppc_md.phys_mem_access_prot(file, addr, size, vma_prot);
+	
+	if (!page_is_ram(addr >> PAGE_SHIFT))
+		vma_prot = __pgprot(pgprot_val(vma_prot)
+				    | _PAGE_GUARDED | _PAGE_NO_CACHE);
+	return vma_prot;
+}
+EXPORT_SYMBOL(phys_mem_access_prot);
Index: linux-work/include/asm-ppc64/pci.h
===================================================================
--- linux-work.orig/include/asm-ppc64/pci.h	2005-03-24 16:25:43.000000000 +1100
+++ linux-work/include/asm-ppc64/pci.h	2005-03-24 16:26:05.000000000 +1100
@@ -130,6 +130,13 @@
 
 extern void pcibios_add_platform_entries(struct pci_dev *dev);
 
+struct file;
+extern pgprot_t	pci_phys_mem_access_prot(struct file *file,
+					 unsigned long offset,
+					 unsigned long size,
+					 pgprot_t prot);
+
+
 #endif	/* __KERNEL__ */
 
 #endif /* __PPC64_PCI_H */
Index: linux-work/include/asm-ppc/pci.h
===================================================================
--- linux-work.orig/include/asm-ppc/pci.h	2005-03-24 16:25:14.000000000 +1100
+++ linux-work/include/asm-ppc/pci.h	2005-03-24 16:26:05.000000000 +1100
@@ -97,6 +97,12 @@
 
 extern void pcibios_add_platform_entries(struct pci_dev *dev);
 
+struct file;
+extern pgprot_t	pci_phys_mem_access_prot(struct file *file,
+					 unsigned long offset,
+					 unsigned long size,
+					 pgprot_t prot);
+
 #endif	/* __KERNEL__ */
 
 #endif /* __PPC_PCI_H */
Index: linux-work/arch/ppc/kernel/pci.c
===================================================================
--- linux-work.orig/arch/ppc/kernel/pci.c	2005-03-24 16:25:14.000000000 +1100
+++ linux-work/arch/ppc/kernel/pci.c	2005-03-24 17:10:08.000000000 +1100
@@ -1478,97 +1478,145 @@
 	return res->start;
 }
 
-/*
- * Platform support for /proc/bus/pci/X/Y mmap()s,
- * modelled on the sparc64 implementation by Dave Miller.
- *  -- paulus.
- */
 
-/*
- * Adjust vm_pgoff of VMA such that it is the physical page offset
- * corresponding to the 32-bit pci bus offset for DEV requested by the user.
- *
- * Basically, the user finds the base address for his device which he wishes
- * to mmap.  They read the 32-bit value from the config space base register,
- * add whatever PAGE_SIZE multiple offset they wish, and feed this into the
- * offset parameter of mmap on /proc/bus/pci/XXX for that device.
- *
- * Returns negative error code on failure, zero on success.
- */
-static __inline__ int
-__pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma,
-		       enum pci_mmap_state mmap_state)
-{
-	struct pci_controller *hose = (struct pci_controller *) dev->sysdata;
-	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-	unsigned long size = vma->vm_end - vma->vm_start;
-	unsigned long base;
-	struct resource *res;
-	int i;
-	int ret = -EINVAL;
+static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
+					       unsigned long *offset,
+					       enum pci_mmap_state mmap_state)
+{
+	struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
+	unsigned long io_offset = 0;
+	int i, res_bit;
 
 	if (hose == 0)
-		return -EINVAL;		/* should never happen */
-	if (offset + size <= offset)
-		return -EINVAL;
+		return NULL;		/* should never happen */
 
+	/* If memory, add on the PCI bridge address offset */
 	if (mmap_state == pci_mmap_mem) {
-		/* PCI memory space */
-		base = hose->pci_mem_offset;
-		for (i = 0; i < 3; ++i) {
-			res = &hose->mem_resources[i];
-			if (res->flags == 0)
-				continue;
-			if (offset >= res->start - base
-			    && offset + size - 1 <= res->end - base) {
-				ret = 0;
-				break;
-			}
-		}
-		offset += hose->pci_mem_offset;
+		*offset += hose->pci_mem_offset;
+		res_bit = IORESOURCE_MEM;
 	} else {
-		/* PCI I/O space */
-		base = (unsigned long)hose->io_base_virt - isa_io_base;
-		res = &hose->io_resource;
-		if (offset >= res->start - base
-		    && offset + size - 1 <= res->end - base)
-			ret = 0;
-		offset += hose->io_base_phys;
+		io_offset = (unsigned long)hose->io_base_virt;
+		*offset += io_offset;
+		res_bit = IORESOURCE_IO;
 	}
 
-	vma->vm_pgoff = offset >> PAGE_SHIFT;
-	return ret;
-}
+	/*
+	 * Check that the offset requested corresponds to one of the
+	 * resources of the device.
+	 */
+	for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+		struct resource *rp = &dev->resource[i];
+		int flags = rp->flags;
+
+		/* treat ROM as memory (should be already) */
+		if (i == PCI_ROM_RESOURCE)
+			flags |= IORESOURCE_MEM;
+
+		/* Active and same type? */
+		if ((flags & res_bit) == 0)
+			continue;
+
+		/* In the range of this resource? */
+		if (*offset < (rp->start & PAGE_MASK) || *offset > rp->end)
+			continue;
+
+		/* found it! construct the final physical address */
+		if (mmap_state == pci_mmap_io)
+			*offset += hose->io_base_phys - _IO_BASE;
+		return rp;
+	}
 
-/*
- * Set vm_flags of VMA, as appropriate for this architecture, for a pci device
- * mapping.
- */
-static __inline__ void
-__pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma,
-		     enum pci_mmap_state mmap_state)
-{
-	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
+	return NULL;
 }
 
 /*
  * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
  * device mapping.
  */
-static __inline__ void
-__pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,
-		      enum pci_mmap_state mmap_state, int write_combine)
-{
-	int prot = pgprot_val(vma->vm_page_prot);
+static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
+				      pgprot_t protection,
+				      enum pci_mmap_state mmap_state,
+				      int write_combine)
+{
+	unsigned long prot = pgprot_val(protection);
+
+	/* Write combine is always 0 on non-memory space mappings. On
+	 * memory space, if the user didn't pass 1, we check for a
+	 * "prefetchable" resource. This is a bit hackish, but we use
+	 * this to workaround the inability of /sysfs to provide a write
+	 * combine bit
+	 */
+	if (mmap_state != pci_mmap_mem)
+		write_combine = 0;
+	else if (write_combine == 0) {
+		if (rp->flags & IORESOURCE_PREFETCH)
+			write_combine = 1;
+	}
 
 	/* XXX would be nice to have a way to ask for write-through */
 	prot |= _PAGE_NO_CACHE;
-	if (!write_combine)
+	if (write_combine)
+		prot &= ~_PAGE_GUARDED;
+	else
 		prot |= _PAGE_GUARDED;
-	vma->vm_page_prot = __pgprot(prot);
+
+	printk("PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start,
+	       prot);
+
+	return __pgprot(prot);
 }
 
 /*
+ * This one is used by /dev/mem and fbdev who have no clue about the
+ * PCI device, it tries to find the PCI device first and calls the
+ * above routine
+ */
+pgprot_t pci_phys_mem_access_prot(struct file *file,
+				  unsigned long offset,
+				  unsigned long size,
+				  pgprot_t protection)
+{
+	struct pci_dev *pdev = NULL;
+	struct resource *found = NULL;
+	unsigned long prot = pgprot_val(protection);
+	int i;
+
+	if (page_is_ram(offset >> PAGE_SHIFT))
+		return prot;
+
+	prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+
+	for_each_pci_dev(pdev) {
+		for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+			struct resource *rp = &pdev->resource[i];
+			int flags = rp->flags;
+
+			/* Active and same type? */
+			if ((flags & IORESOURCE_MEM) == 0)
+				continue;
+			/* In the range of this resource? */
+			if (offset < (rp->start & PAGE_MASK) ||
+			    offset > rp->end)
+				continue;
+			found = rp;
+			break;
+		}
+		if (found)
+			break;
+	}
+	if (found) {
+		if (found->flags & IORESOURCE_PREFETCH)
+			prot &= ~_PAGE_GUARDED;
+		pci_dev_put(pdev);
+	}
+
+	DBG("non-PCI map for %lx, prot: %lx\n", offset, prot);
+
+	return __pgprot(prot);
+}
+
+
+/*
  * Perform the actual remap of the pages for a PCI device mapping, as
  * appropriate for this architecture.  The region in the process to map
  * is described by vm_start and vm_end members of VMA, the base physical
@@ -1582,14 +1630,19 @@
 			enum pci_mmap_state mmap_state,
 			int write_combine)
 {
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	struct resource *rp;
 	int ret;
 
-	ret = __pci_mmap_make_offset(dev, vma, mmap_state);
-	if (ret < 0)
-		return ret;
+	rp = __pci_mmap_make_offset(dev, &offset, mmap_state);
+	if (rp == NULL)
+		return -EINVAL;
 
-	__pci_mmap_set_flags(dev, vma, mmap_state);
-	__pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine);
+	vma->vm_pgoff = offset >> PAGE_SHIFT;
+	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
+	vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
+						  vma->vm_page_prot,
+						  mmap_state, write_combine);
 
 	ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
 			       vma->vm_end - vma->vm_start, vma->vm_page_prot);
Index: linux-work/include/asm-ppc/pgtable.h
===================================================================
--- linux-work.orig/include/asm-ppc/pgtable.h	2005-03-24 16:25:14.000000000 +1100
+++ linux-work/include/asm-ppc/pgtable.h	2005-03-24 16:26:05.000000000 +1100
@@ -623,6 +623,11 @@
  */
 #define pgprot_noncached(prot)	(__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED))
 
+struct file;
+extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
+				     unsigned long size, pgprot_t vma_prot);
+#define __HAVE_PHYS_MEM_ACCESS_PROT
+
 #define __HAVE_ARCH_PTE_SAME
 #define pte_same(A,B)	(((pte_val(A) ^ pte_val(B)) & ~_PAGE_HASHPTE) == 0)
 
Index: linux-work/arch/ppc/platforms/chrp_setup.c
===================================================================
--- linux-work.orig/arch/ppc/platforms/chrp_setup.c	2005-03-24 16:25:14.000000000 +1100
+++ linux-work/arch/ppc/platforms/chrp_setup.c	2005-03-24 16:26:05.000000000 +1100
@@ -527,6 +527,8 @@
 
 	ppc_md.init           = chrp_init2;
 
+	ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
+
 	ppc_md.restart        = chrp_restart;
 	ppc_md.power_off      = chrp_power_off;
 	ppc_md.halt           = chrp_halt;
Index: linux-work/include/asm-ppc/page.h
===================================================================
--- linux-work.orig/include/asm-ppc/page.h	2005-03-24 16:25:14.000000000 +1100
+++ linux-work/include/asm-ppc/page.h	2005-03-24 16:26:05.000000000 +1100
@@ -137,6 +137,8 @@
 #define ___va(paddr) ((paddr)+PPC_MEMOFFSET)
 #endif
 
+extern int page_is_ram(unsigned long pfn);
+
 #define __pa(x) ___pa((unsigned long)(x))
 #define __va(x) ((void *)(___va((unsigned long)(x))))
 
Index: linux-work/include/asm-ppc/machdep.h
===================================================================
--- linux-work.orig/include/asm-ppc/machdep.h	2005-03-24 16:25:14.000000000 +1100
+++ linux-work/include/asm-ppc/machdep.h	2005-03-24 16:26:05.000000000 +1100
@@ -6,6 +6,7 @@
 #include <linux/init.h>
 
 #include <asm/setup.h>
+#include <asm/page.h>
 
 #ifdef CONFIG_APUS
 #include <asm-m68k/machdep.h>
@@ -15,6 +16,7 @@
 struct pci_bus;	
 struct pci_dev;
 struct seq_file;
+struct file;
 
 /* We export this macro for external modules like Alsa to know if
  * ppc_md.feature_call is implemented or not
@@ -93,6 +95,12 @@
 	/* Called at then very end of pcibios_init() */
 	void (*pcibios_after_init)(void);
 
+	/* Get access protection for /dev/mem */
+	pgprot_t	(*phys_mem_access_prot)(struct file *file,
+						unsigned long offset,
+						unsigned long size,
+						pgprot_t vma_prot);
+
 	/* this is for modules, since _machine can be a define -- Cort */
 	int ppc_machine;
 
Index: linux-work/arch/ppc/platforms/prep_setup.c
===================================================================
--- linux-work.orig/arch/ppc/platforms/prep_setup.c	2005-03-24 16:25:14.000000000 +1100
+++ linux-work/arch/ppc/platforms/prep_setup.c	2005-03-24 16:26:05.000000000 +1100
@@ -1144,6 +1144,8 @@
 	/* this gets changed later on if we have an OpenPIC -- Cort */
 	ppc_md.get_irq        = i8259_irq;
 
+	ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
+
 	ppc_md.restart        = prep_restart;
 	ppc_md.power_off      = NULL; /* set in prep_setup_arch() */
 	ppc_md.halt           = prep_halt;
Index: linux-work/arch/ppc/platforms/pmac_setup.c
===================================================================
--- linux-work.orig/arch/ppc/platforms/pmac_setup.c	2005-03-24 16:25:14.000000000 +1100
+++ linux-work/arch/ppc/platforms/pmac_setup.c	2005-03-24 16:26:05.000000000 +1100
@@ -669,6 +669,7 @@
 	ppc_md.pcibios_fixup  = pmac_pcibios_fixup;
 	ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook;
 	ppc_md.pcibios_after_init = pmac_pcibios_after_init;
+	ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
 
 	ppc_md.restart        = pmac_restart;
 	ppc_md.power_off      = pmac_power_off;
Index: linux-work/arch/ppc/mm/init.c
===================================================================
--- linux-work.orig/arch/ppc/mm/init.c	2005-03-24 16:25:14.000000000 +1100
+++ linux-work/arch/ppc/mm/init.c	2005-03-24 16:44:42.000000000 +1100
@@ -641,3 +641,27 @@
 	}
 #endif
 }
+
+/*
+ * This is called by /dev/mem to know if a given address has to
+ * be mapped non-cacheable or not
+ */
+int page_is_ram(unsigned long pfn)
+{
+	unsigned long paddr = (pfn << PAGE_SHIFT);
+
+	return paddr < __pa(high_memory);
+}
+
+pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
+			      unsigned long size, pgprot_t vma_prot)
+{
+	if (ppc_md.phys_mem_access_prot)
+		return ppc_md.phys_mem_access_prot(file, addr, size, vma_prot);
+	
+	if (!page_is_ram(addr >> PAGE_SHIFT))
+		vma_prot = __pgprot(pgprot_val(vma_prot)
+				    | _PAGE_GUARDED | _PAGE_NO_CACHE);
+	return vma_prot;
+}
+EXPORT_SYMBOL(phys_mem_access_prot);

^ permalink raw reply

* [PATCH 2.6.12] ppc32: Fix Sandpoint Soft Reboot
From: Mark A. Greer @ 2005-03-23 21:17 UTC (permalink / raw)
  To: akpm; +Cc: rvinson, Embedded PPC Linux list

[-- Attachment #1: Type: text/plain, Size: 797 bytes --]

ppc32: Fix Sandpoint Soft Reboot

This patch allows the Freescale Sandpoint to perform soft reboots. A 
write of 0x00 to the Winbond's Chip Select Control Register was clearing 
the Upper BIOS Chip Select Enable bit which unmaps the boot flash. The 
comment associated with the write noted that it was enabling the RTC and 
Keyboard address locations, but the bits in question (1 and 0) are 
reserved when the Winbond chip is in PowerPC mode. Also, the bits are 1 
for enable, 0 for disable, therefore the original code was actually 
disabling the address locations. The patch also corrects errors in the 
definitions of 2 configuration bits in the Tundra Tsi107 bridge's MAPB 
Options register.

Signed-off-by Randy Vinson <rvinson@mvista.com>
Signed-off-by Mark A. Greer <mgreer@mvista.com>
-- 

[-- Attachment #2: sandpoint.patch --]
[-- Type: text/plain, Size: 1321 bytes --]

===== arch/ppc/platforms/sandpoint.c 1.26 vs edited =====
--- 1.26/arch/ppc/platforms/sandpoint.c	2005-03-04 23:41:15 -07:00
+++ edited/arch/ppc/platforms/sandpoint.c	2005-03-17 14:06:15 -07:00
@@ -202,13 +202,6 @@
 				0x48, /* ISA-to-PCI Addr Decoder Control */
 				0xf0);
 
-	/* Enable RTC and Keyboard address locations.  */
-	early_write_config_byte(hose,
-				0,
-				devfn,
-				0x4d,	/* Chip Select Control Register */
-				0x00);
-
 	/* Enable Port 92.  */
 	early_write_config_byte(hose,
 				0,
===== include/asm-ppc/mpc10x.h 1.10 vs edited =====
--- 1.10/include/asm-ppc/mpc10x.h	2005-01-30 23:22:39 -07:00
+++ edited/include/asm-ppc/mpc10x.h	2005-03-16 16:52:34 -07:00
@@ -115,8 +115,8 @@
 #define	MPC10X_CFG_MAPB_OPTIONS_CFAE	0x80	/* CPU_FD_ALIAS_EN */
 #define	MPC10X_CFG_MAPB_OPTIONS_PFAE	0x40	/* PCI_FD_ALIAS_EN */
 #define	MPC10X_CFG_MAPB_OPTIONS_DR	0x20	/* DLL_RESET */
-#define	MPC10X_CFG_MAPB_OPTIONS_PCICH	0x80	/* PCI_COMPATIBILITY_HOLE */
-#define	MPC10X_CFG_MAPB_OPTIONS_PROCCH	0x40	/* PROC_COMPATIBILITY_HOLE */
+#define	MPC10X_CFG_MAPB_OPTIONS_PCICH	0x08	/* PCI_COMPATIBILITY_HOLE */
+#define	MPC10X_CFG_MAPB_OPTIONS_PROCCH	0x04	/* PROC_COMPATIBILITY_HOLE */
 
 /* Define offsets for the memory controller registers in the config space */
 #define MPC10X_MCTLR_MEM_START_1	0x80	/* Banks 0-3 */

^ permalink raw reply

* Re: Linux 2.6.x on 8xx status
From: Marcelo Tosatti @ 2005-03-23 16:05 UTC (permalink / raw)
  To: Dan Malek; +Cc: Smith, Craig, paulus, linux-ppc-embedded
In-Reply-To: <f8d4fefc4fc282e699ee279e92c3c2ef@embeddededge.com>

On Wed, Mar 23, 2005 at 11:12:11AM -0500, Dan Malek wrote:
> 
> On Mar 23, 2005, at 5:25 AM, Marcelo Tosatti wrote:
> 
> >You misunderstood: get_mmu_context() _wont_ be called if the mm 
> >structures
> >are the same.
> 
> I understood.  At most, get_mmu_context() will only do a 'tlbia'
> instruction, I didn't see your reason for thinking this would have
> an effect on the tlbie usage.

OK. That is not a good reason, indeed.

> >>Well, that's interesting.  It's likely to only happen on an 860 
> >>variant
> >>that
> >>has the large TLB.
> >
> >For what reasoning?
> 
> My initial debugging seemed to indicate a stale TLB entry.  With
> the larger TLB this is more likely to happen.  The bug was never
> seen on the 823/850 with smaller TLBs.
> 
> I have a new 8xx board now, so I'll have to start working on these
> issues as well.

OK!

^ permalink raw reply

* Kernel panic: Attempted to kill init!
From: jagadeesh reddy @ 2005-03-23 20:37 UTC (permalink / raw)
  To: linuxppc-embedded

[-- Attachment #1: Type: text/plain, Size: 1398 bytes --]

Hi Linuxppc-embedded , 

Iam trying to run powerpc linux on xilinx ML310 FPGA board, everything is fine..am using montavista preview kit and recently I have added gigabyte ethernet driver(XGemac) to the kernel and when I try to run new image on target I get following error. My experience is not sufficient enough to predict why such error is happened. 

XGemac: Device instance 0 found 
Instruction machine check in kernel mode. 
Oops: machine check, sig: 7 
NIP: C00D0D58 XER: 20000000 LR: C00D0D4C SP: C0335F20 REGS: c0335e70 
TRAP: 0200 Not tainted 
MSR: 00009030 EE: 1 PR: 0 FP: 0 ME: 1 IR/DR: 11 
TASK = c0334000[1] 'swapper' Last syscall: 120 
last math 00000000 last altivec 00000000 
GPR00: 0000000A C0335F20 C0334000 00000006 00000170 C9011100 C08E0B0C 
C9011000 
GPR08: 11111111 C900F000 00000000 00000006 44000042 00000000 00000000 00000000 
GPR16: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
GPR24: 00000000 00000000 00000000 C01636E4 C08E0960 00000000 C0180000 C08E0A08 
Call backtrace: 
C00D0D4C C00D0960 C0175904 C0175C84 C016C634 C000244C C0006C9C 
Kernel panic: Attempted to kill init! 
<0>Rebooting in 180 seconds.. 

what does " Oops: machine check, sig: 7 " mean .does any one worked with xilinx gigabyte ethernet. thanks a lot...... 

jaggu

		
---------------------------------
Do you Yahoo!?
 Yahoo! Small Business - Try our new resources site! 

[-- Attachment #2: Type: text/html, Size: 1629 bytes --]

^ permalink raw reply

* Update: Booting Linux on a Custom PPC Board
From: Don Russell @ 2005-03-23 19:45 UTC (permalink / raw)
  To: linuxppc-embedded

To:  Bob Beck

Did you ever resolve the Linux on PPC boot problem?
Im attempting a similar thing.

Thanks
Don Russell
Lucent Technologies

-----Original Message-----
Ok. Now its making it to start_ in boot/simple/head.S.

It jumps to relocate in relocate.S after doing some 6xx
specific code. In util.S, it enters but never finishes
the flush_data_cache. ????????

Bob



-----Forwarded Message-----

From: Bob Beck <beck at assurtech.com>
To: linuxppc-embedded at lists.linuxppc.org
Subject: Booting Linux on a Custom PPC Board
Date: 02 Mar 2004 12:58:54 +1400


I am booting Linux on a custom board and having many
problems.  The board contains a PPC603E, flash, an
ethernet controller, and a serial chip.

Here is what I have done so far.

o Configured the kernel to support 6xx/7xx boards
o Introduced a new defined named "CONFIG_ATCNVMS"
o Modified kernel/setup.c so that early_init() would
  skip the last 3 things it does that do not make
  sense for my board.
o Added a new embed_config() function in arch/ppc/boot/simple
  that populates a bd_t structure (from ppcboot.h)
o Added code to save registers r3-r7 at the beginning
  of start_ in simple/head.S. Restored these registers
  in relocate.S before the jump to 0.
o Updated the makefiles so that the zImage.embedded
would be created in the arch/ppc/boot/images directory.


We are writing our own boot loader code for a couple of reasons.

o U-Boot does not support our ethernet chip or serial chip.
o VxWorks is in flash and we cannot change that in the near future.
o The VxWorks boot loader initializes the hardware and
  we run our custom boot loader from its shell.


Here are the steps taken by our custom boot loader.

o Malloc a piece of memory and copy the ram disk from a file
  to the malloc'd memory.
o Malloc a piece of memory and copy the zImage.bin contents from
  a file to memory.
  powerpc-linux-objcopy -O binary zImage.embedded zImage.bin
o Prepare the registers
  r3 = ptr to bd_t
  r4 = ptr to initial ram disk bin in memory
  r5 = ptr to end of initial ram disk
  r6 = ptr to start of command line string
  r7 = ptr to end of command line string
o Jump to the start address where the zImage.bin has been loaded
  into memory.

In arch/ppc/boot/simple/head.S, I call a routine that blinks a light
(start_), but this light never blinks. I also call this routine
at __start in arch/ppc/kernel/head.S but the light never blinks.


I don't understand what to do at this point. In the past I
loaded the ram disk and vmlinux into memory and jumped to 0x10000.
Somebody on this list said that was guaranteed not to work.
However, the light did blink before the code had problems in
mmu initialization.

Regards,
Bob Beck
beck at assurtech.com


** Sent via the linuxppc-embedded mail list. See http://lists.linuxppc.org/

^ permalink raw reply

* Re: question about writing to memory directly from user space in Linux
From: Eugene Surovegin @ 2005-03-23 17:10 UTC (permalink / raw)
  To: Stefan Nickl; +Cc: Vijay Padiyar, LinuxPPC Support
In-Reply-To: <1111571205.13392.3.camel@lucy.pep-kaufbeuren.de>

On Wed, Mar 23, 2005 at 10:46:45AM +0100, Stefan Nickl wrote:
> On Wed, 2005-03-23 at 14:25 +0530, Vijay Padiyar wrote:
> > Can you suggest some kind of a "synchronization" function which I can call
> > from *user space* which will ensure that all values written to mmaped memory
> > locations from user space are actually flushed to their physical locations?
> > I think this might be a potential problem with my code.
> 
> Have a look at linux/include/asm-ppc/{io.h,system.h} and
> http://www.xml.com/ldd/chapter/book/ch08.html
> 
> The eieio instruction doesn't need supervisor rights.

eieio is a nop on 603e core.

--
Eugene

^ permalink raw reply

* Re: Linux 2.6.x on 8xx status
From: Dan Malek @ 2005-03-23 16:12 UTC (permalink / raw)
  To: Marcelo Tosatti; +Cc: Smith, Craig, paulus, linux-ppc-embedded
In-Reply-To: <20050323102501.GF7846@logos.cnet>


On Mar 23, 2005, at 5:25 AM, Marcelo Tosatti wrote:

> You misunderstood: get_mmu_context() _wont_ be called if the mm 
> structures
> are the same.

I understood.  At most, get_mmu_context() will only do a 'tlbia'
instruction, I didn't see your reason for thinking this would have
an effect on the tlbie usage.

>> Well, that's interesting.  It's likely to only happen on an 860 
>> variant
>> that
>> has the large TLB.
>
> For what reasoning?

My initial debugging seemed to indicate a stale TLB entry.  With
the larger TLB this is more likely to happen.  The bug was never
seen on the 823/850 with smaller TLBs.

I have a new 8xx board now, so I'll have to start working on these
issues as well.

Thanks.


	-- Dan

^ permalink raw reply

* Re: Linux 2.6.x on 8xx status
From: Marcelo Tosatti @ 2005-03-23 10:25 UTC (permalink / raw)
  To: Dan Malek; +Cc: Smith, Craig, paulus, linux-ppc-embedded
In-Reply-To: <ab78e7b7625e4293bf29fded17f589c2@embeddededge.com>

On Tue, Mar 22, 2005 at 05:53:40PM -0500, Dan Malek wrote:
> 
> On Mar 22, 2005, at 12:58 PM, Marcelo Tosatti wrote:
> 
> >Newbie question: What prevents the initial kernel map (tuple of 8Mbyte 
> >I/D-TLB entries)
> >and the IMMR 8Mbyte D-TLB entry from getting unmapped by translation 
> >pressure,
> >in case CONFIG_PIN_TLB is disabled ?
> 
> Nothing.  In fact, they are likely invalidated shortly after the kernel
> page tables are set up.  This was only done to ensure we could get the
> kernel initialized without taking page faults.

OK.

> >By a counter at the end of _tlbie function, similar to other counters 
> >which
> >you suggested.
> 
> OK.
> 
> >Dont think thats the case given that v2.4 calls tlbia through 
> >flush_tlb_mm() at exit_mmap()
> >only. And at vmalloc_free which shouldnt be called at all.
> 
> Hmmm ...  Then, the 2.6 looks to be much less efficient with the MMU
> resources than 2.4 was.  This is going to affect everyone, it's just 
> easier
> to measure on this processor.

Many codepaths are longer (eg. but the difference 

> 
> >I just noticed this conditional at switch_mm() (v2.6), which _can_ 
> >partly
> >explain the reduced tlbie's  (its just a guess for now, though):
> 
> What is your guess?  I don't know how this would reduce the number
> of tlbie instructions, since stealing a context (as part of 
> get_context())
> will simply whack the whole TLB with a tlbia.  On 8xx, both instructions
> could be simply implemented as macros.

You misunderstood: get_mmu_context() _wont_ be called if the mm structures 
are the same.

v2.4 didnt had this optimization. 

> >Spent part of the day reading the MMU section of 860 manual, I think I 
> >have kind
> >of a clue how things are supposed to work at the lowlevel now.
> 
> :-)
> 
> >PS: I can't reproduce the invalid TLB crash anymore. i.e. even by 
> >removing
> >the _tlbie() at update_mmu_cache() everything is working as expected.
> 
> Well, that's interesting.  It's likely to only happen on an 860 variant 
> that
> has the large TLB.

For what reasoning? 

> >How can I reproduce it again? Guillaume, what kernel version are you 
> >using?
> 
> It used to happen on early 2.6 versions as soon as you entered user
> space programs.

Will let you know of any findings...

^ permalink raw reply

* Re: Linux 2.6.x on 8xx status
From: Guillaume Autran @ 2005-03-23 14:06 UTC (permalink / raw)
  To: Marcelo Tosatti; +Cc: Smith, Craig, paulus, linux-ppc-embedded
In-Reply-To: <20050322175815.GB7846@logos.cnet>

[-- Attachment #1: Type: text/plain, Size: 3299 bytes --]



Marcelo Tosatti wrote:

>On Tue, Mar 22, 2005 at 03:57:08PM -0500, Dan Malek wrote:
>  
>
>>On Mar 22, 2005, at 8:04 AM, Marcelo Tosatti wrote:
>>
>>    
>>
>>>I'm quite puzzled. Why v2.6 calls the "tlbie" instruction 100-or-so
>>>less times than v2.4 ?
>>>      
>>>
>
>That was rather a _factor_ of "100-or-so" less.
>
>  
>
>>Oh my ...  I'm more worried about the high number of TLB misses
>>in 2.6 compared to 2.4.  That's really bad.  
>>    
>>
>
>Newbie question: What prevents the initial kernel map (tuple of 8Mbyte I/D-TLB entries) 
>and the IMMR 8Mbyte D-TLB entry from getting unmapped by translation pressure,
>in case CONFIG_PIN_TLB is disabled ? 
>
>  
>
>>How did you instrument the tlbie measurement? 
>>    
>>
>
>By a counter at the end of _tlbie function, similar to other counters which 
>you suggested.
>
>  
>
>>It could be that 2.4 used lots more 'tlbia' which were replaced by tlbie in 2.6.
>>    
>>
>
>Dont think thats the case given that v2.4 calls tlbia through flush_tlb_mm() at exit_mmap() 
>only. And at vmalloc_free which shouldnt be called at all.
>
>I just noticed this conditional at switch_mm() (v2.6), which _can_ partly 
>explain the reduced tlbie's  (its just a guess for now, though):
>
>static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
>                             struct task_struct *tsk)
>{
>#ifdef CONFIG_ALTIVEC
>        asm volatile (
> BEGIN_FTR_SECTION
>        "dssall;\n"
>#ifndef CONFIG_POWER4
>         "sync;\n" /* G4 needs a sync here, G5 apparently not */
>#endif
> END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
>         : : );
>#endif /* CONFIG_ALTIVEC */
>                                                                                            
>        tsk->thread.pgdir = next->pgd;
>                                                                                            
>        /* No need to flush userspace segments if the mm doesnt change */
>	if (prev == next) 				<--------------
>		return;   				<--------------
>                                                                                            
>        /* Setup new userspace context */
>        get_mmu_context(next);
>        set_context(next->context, next->pgd);
>}
>
>I'm about to disable it and retry.
>
>Spent part of the day reading the MMU section of 860 manual, I think I have kind 
>of a clue how things are supposed to work at the lowlevel now. 
>
>I'll continue tracking it down - any help is appreciated.
>
>PS: I can't reproduce the invalid TLB crash anymore. i.e. even by removing
>the _tlbie() at update_mmu_cache() everything is working as expected.
>
>How can I reproduce it again? Guillaume, what kernel version are you using?
>
>  
>
It is very timing dependant. Running 2.6.11, ldconfig crashes in 
__flush_dcache_icache(...) just after boot time (first time called). 
Unfortunatly, it only happens every now and then. And of course, never 
when my BDI2000 is plugged in. :(

I also noticed that with kernel preemption disable, oops are less 
frequent. Probably does not mean anything anyway...

Guillaume.


-- 
=======================================
Guillaume Autran
Senior Software Engineer
MRV Communications, Inc.
Tel: (978) 952-4932 office
E-mail: gautran@mrv.com
======================================= 


[-- Attachment #2: Type: text/html, Size: 4130 bytes --]

^ permalink raw reply

* [PATCH] Updated: CPM2 Cleanup
From: Jason McMullan @ 2005-03-23 13:49 UTC (permalink / raw)
  To: linuxppc-embedded


[-- Attachment #1.1: Type: text/plain, Size: 190 bytes --]

Here is the CPM2 cleanup patch again, with galak's recommended fixes.

This is versus kernel 2.6.11.4 vanilla


-- 
Jason McMullan <jason.mcmullan@timesys.com>
TimeSys Corporation


[-- Attachment #1.2: cpu-ppc-cpm2.patch --]
[-- Type: text/x-patch, Size: 12294 bytes --]

#### Auto-generated patch ####
Date:        Wed, 23 Mar 2005 08:47:19 -0500
Maintainer:  Jason McMullan <jmcmullan@timesys.com>
Summary:     Freescale CPM2 device I/O processor, on MPC8xx and MPC8xxx CPUs
Signed-Off-By: Jason McMullan <jmcmullan@timesys.com>
###############################

Index of changes:

 arch/ppc/platforms/85xx/mpc8560_ads.c |    4 -
 arch/ppc/syslib/cpm2_common.c         |    4 -
 arch/ppc/syslib/cpm2_pic.c            |   66 +++++++++++++++++----
 arch/ppc/syslib/cpm2_pic.h            |    3 
 arch/ppc/syslib/m8260_setup.c         |    5 -
 include/asm-ppc/cpm2.h                |   23 ++++++-
 include/asm-ppc/irq.h                 |  105 +++++++++++++++++-----------------
 7 files changed, 135 insertions(+), 75 deletions(-)


--- linux-orig/arch/ppc/platforms/85xx/mpc8560_ads.c
+++ linux/arch/ppc/platforms/85xx/mpc8560_ads.c
@@ -135,7 +135,6 @@
 static void __init
 mpc8560_ads_init_IRQ(void)
 {
-	int i;
 	volatile cpm2_map_t *immap = cpm2_immr;
 
 	/* Setup OpenPIC */
@@ -145,8 +144,7 @@
 	immap->im_intctl.ic_simrh = 0x0;
 	immap->im_intctl.ic_simrl = 0x0;
 
-	for (i = CPM_IRQ_OFFSET; i < (NR_CPM_INTS + CPM_IRQ_OFFSET); i++)
-		irq_desc[i].handler = &cpm2_pic;
+        cpm2_init_IRQ();
 
 	/* Initialize the default interrupt mapping priorities,
 	 * in case the boot rom changed something on us.
--- linux-orig/arch/ppc/syslib/cpm2_common.c
+++ linux/arch/ppc/syslib/cpm2_common.c
@@ -32,12 +32,12 @@
 #include <asm/rheap.h>
 
 static void cpm2_dpinit(void);
-cpm_cpm2_t	*cpmp;		/* Pointer to comm processor space */
+volatile cpm_cpm2_t     *cpmp;          /* Pointer to comm processor space */
 
 /* We allocate this here because it is used almost exclusively for
  * the communication processor devices.
  */
-cpm2_map_t *cpm2_immr;
+volatile cpm2_map_t *cpm2_immr;
 
 #define CPM_MAP_SIZE	(0x40000)	/* 256k - the PQ3 reserve this amount
 					   of space for CPM as it is larger
--- linux-orig/arch/ppc/syslib/cpm2_pic.c
+++ linux/arch/ppc/syslib/cpm2_pic.c
@@ -47,6 +47,8 @@
 	int	bit, word;
 	volatile uint	*simr;
 
+	irq_nr -= CPM_IRQ_OFFSET;
+
 	bit = irq_to_siubit[irq_nr];
 	word = irq_to_siureg[irq_nr];
 
@@ -60,6 +62,8 @@
 	int	bit, word;
 	volatile uint	*simr;
 
+	irq_nr -= CPM_IRQ_OFFSET;
+
 	bit = irq_to_siubit[irq_nr];
 	word = irq_to_siureg[irq_nr];
 
@@ -73,6 +77,8 @@
 	int	bit, word;
 	volatile uint	*simr, *sipnr;
 
+	irq_nr -= CPM_IRQ_OFFSET;
+
 	bit = irq_to_siubit[irq_nr];
 	word = irq_to_siureg[irq_nr];
 
@@ -91,6 +97,7 @@
 	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
 			&& irq_desc[irq_nr].action) {
 
+		irq_nr -= CPM_IRQ_OFFSET;
 		bit = irq_to_siubit[irq_nr];
 		word = irq_to_siureg[irq_nr];
 
@@ -100,20 +107,23 @@
 	}
 }
 
-struct hw_interrupt_type cpm2_pic = {
-	" CPM2 SIU  ",
-	NULL,
-	NULL,
-	cpm2_unmask_irq,
-	cpm2_mask_irq,
-	cpm2_mask_and_ack,
-	cpm2_end_irq,
-	0
+static unsigned int cpm2_startup_irq(unsigned int irq)
+{
+	cpm2_unmask_irq(irq);
+	return 0;
+}
+
+static struct hw_interrupt_type cpm2_pic = {
+	.typename = "CPM2 SIU",
+	.startup = cpm2_startup_irq,
+	.shutdown = cpm2_mask_irq,
+	.enable = cpm2_unmask_irq,
+	.disable = cpm2_mask_irq,
+	.ack = cpm2_mask_and_ack,
+	.end = cpm2_end_irq,
 };
 
-
-int
-cpm2_get_irq(struct pt_regs *regs)
+int cpm2_get_irq(struct pt_regs *regs)
 {
 	int irq;
         unsigned long bits;
@@ -125,5 +135,35 @@
 
 	if (irq == 0)
 		return(-1);
-	return irq;
+	return irq+CPM_IRQ_OFFSET;
+}
+
+void cpm2_init_IRQ(void)
+{
+	int i;
+
+	/* Clear the CPM IRQ controller, in case it has any bits set
+	 * from the bootloader
+	 */
+
+	/* Mask out everything */
+	cpm2_immr->im_intctl.ic_simrh = 0x00000000;
+	cpm2_immr->im_intctl.ic_simrl = 0x00000000;
+	wmb();
+
+	/* Ack everything */
+	cpm2_immr->im_intctl.ic_sipnrh = 0xffffffff;
+	cpm2_immr->im_intctl.ic_sipnrl = 0xffffffff;
+	wmb();
+
+	/* Dummy read of the vector */
+	i = cpm2_immr->im_intctl.ic_sivec;
+	rmb();
+
+	/* Enable chaining to OpenPIC, and make everything level
+	 */
+	for (i = 0; i < NR_CPM_INTS; i++) {
+		irq_desc[i+CPM_IRQ_OFFSET].handler = &cpm2_pic;
+		irq_desc[i+CPM_IRQ_OFFSET].status |= IRQ_LEVEL;
+	}
 }
--- linux-orig/arch/ppc/syslib/cpm2_pic.h
+++ linux/arch/ppc/syslib/cpm2_pic.h
@@ -1,7 +1,8 @@
 #ifndef _PPC_KERNEL_CPM2_H
 #define _PPC_KERNEL_CPM2_H
 
-extern struct hw_interrupt_type cpm2_pic;
 extern int cpm2_get_irq(struct pt_regs *regs);
 
+extern void cpm2_init_IRQ(void);
+
 #endif /* _PPC_KERNEL_CPM2_H */
--- linux-orig/arch/ppc/syslib/m8260_setup.c
+++ linux/arch/ppc/syslib/m8260_setup.c
@@ -168,10 +168,7 @@
 static void __init
 m8260_init_IRQ(void)
 {
-	int i;
-
-        for ( i = 0 ; i < NR_SIU_INTS ; i++ )
-                irq_desc[i].handler = &cpm2_pic;
+	cpm2_init_IRQ();
 
 	/* Initialize the default interrupt mapping priorities,
 	 * in case the boot rom changed something on us.
--- linux-orig/include/asm-ppc/cpm2.h
+++ linux/include/asm-ppc/cpm2.h
@@ -69,13 +69,14 @@
 #define CPM_CR_INIT_TX		((ushort)0x0002)
 #define CPM_CR_HUNT_MODE	((ushort)0x0003)
 #define CPM_CR_STOP_TX		((ushort)0x0004)
+#define CPM_CR_GRA_STOP_TX      ((ushort)0x0005)
 #define CPM_CR_RESTART_TX	((ushort)0x0006)
 #define CPM_CR_SET_GADDR	((ushort)0x0008)
 #define CPM_CR_START_IDMA	((ushort)0x0009)
 #define CPM_CR_STOP_IDMA	((ushort)0x000b)
 
 #define mk_cr_cmd(PG, SBC, MCN, OP) \
-	((PG << 26) | (SBC << 21) | (MCN << 6) | OP)
+	(((PG) << 26) | ((SBC) << 21) | ((MCN) << 6) | (OP))
 
 /* Dual Port RAM addresses.  The first 16K is available for almost
  * any CPM use, so we put the BDs there.  The first 128 bytes are
@@ -107,7 +108,7 @@
 /* Export the base address of the communication processor registers
  * and dual port ram.
  */
-extern		cpm_cpm2_t	*cpmp;	 /* Pointer to comm processor */
+extern volatile	cpm_cpm2_t	*cpmp;	 /* Pointer to comm processor */
 extern uint cpm_dpalloc(uint size, uint align);
 extern int cpm_dpfree(uint offset);
 extern uint cpm_dpalloc_fixed(uint offset, uint size, uint align);
@@ -115,7 +116,24 @@
 extern void *cpm_dpram_addr(uint offset);
 extern void cpm_setbrg(uint brg, uint rate);
 extern void cpm2_fastbrg(uint brg, uint rate, int div16);
+extern void cpm2_reset(void);
+
+#ifdef CONFIG_CPM2
+#define CPM_CP_FCC(line, mcn)	mk_cr_cmd(CPM_CR_FCC1_PAGE+(line),CPM_CR_FCC1_SBLOCK+(line), mcn, 0)
+#define CPM_CP_SCC(line)	mk_cr_cmd(CPM_CR_SCC1_PAGE+(line),CPM_CR_SCC1_SBLOCK+(line), 0, 0)
+#define CPM_CP_SMC(line)	mk_cr_cmd(CPM_CR_SMC1_PAGE+(line),CPM_CR_SMC1_SBLOCK+(line), 0, 0)
+#define CPM_CP_I2C		mk_cr_cmd(CPM_CR_I2C_PAGE,CPM_CR_I2C_SBLOCK, 0, 0)
 
+static inline void cpm_cp_command(uint32_t id, int op)
+{
+	cpmp->cp_cpcr = id | op | CPM_CR_FLG;
+
+	while (cpmp->cp_cpcr & CPM_CR_FLG);
+}
+#else
+#error Please define cpm_cp_command and the CPM_CP_* ids you will need.
+#endif
+
 /* Buffer descriptors used by many of the CPM protocols.
 */
 typedef struct cpm_buf_desc {
@@ -135,6 +153,7 @@
 #define BD_SC_BR	((ushort)0x0020)	/* Break received */
 #define BD_SC_FR	((ushort)0x0010)	/* Framing error */
 #define BD_SC_PR	((ushort)0x0008)	/* Parity error */
+#define BD_SC_NAK	((ushort)0x0004)	/* NAK - did not respond */
 #define BD_SC_OV	((ushort)0x0002)	/* Overrun */
 #define BD_SC_CD	((ushort)0x0001)	/* ?? */
 
--- linux-orig/include/asm-ppc/irq.h
+++ linux/include/asm-ppc/irq.h
@@ -257,57 +257,62 @@
  * (Document errata updates have fixed this...make sure you have up to
  * date processor documentation -- Dan).
  */
-#define NR_SIU_INTS	64
+
+#ifndef CPM_IRQ_OFFSET
+#define CPM_IRQ_OFFSET	0
+#endif
+
+#define NR_CPM_INTS	64
 
-#define	SIU_INT_ERROR		((uint)0x00)
-#define	SIU_INT_I2C		((uint)0x01)
-#define	SIU_INT_SPI		((uint)0x02)
-#define	SIU_INT_RISC		((uint)0x03)
-#define	SIU_INT_SMC1		((uint)0x04)
-#define	SIU_INT_SMC2		((uint)0x05)
-#define	SIU_INT_IDMA1		((uint)0x06)
-#define	SIU_INT_IDMA2		((uint)0x07)
-#define	SIU_INT_IDMA3		((uint)0x08)
-#define	SIU_INT_IDMA4		((uint)0x09)
-#define	SIU_INT_SDMA		((uint)0x0a)
-#define	SIU_INT_TIMER1		((uint)0x0c)
-#define	SIU_INT_TIMER2		((uint)0x0d)
-#define	SIU_INT_TIMER3		((uint)0x0e)
-#define	SIU_INT_TIMER4		((uint)0x0f)
-#define	SIU_INT_TMCNT		((uint)0x10)
-#define	SIU_INT_PIT		((uint)0x11)
-#define	SIU_INT_IRQ1		((uint)0x13)
-#define	SIU_INT_IRQ2		((uint)0x14)
-#define	SIU_INT_IRQ3		((uint)0x15)
-#define	SIU_INT_IRQ4		((uint)0x16)
-#define	SIU_INT_IRQ5		((uint)0x17)
-#define	SIU_INT_IRQ6		((uint)0x18)
-#define	SIU_INT_IRQ7		((uint)0x19)
-#define	SIU_INT_FCC1		((uint)0x20)
-#define	SIU_INT_FCC2		((uint)0x21)
-#define	SIU_INT_FCC3		((uint)0x22)
-#define	SIU_INT_MCC1		((uint)0x24)
-#define	SIU_INT_MCC2		((uint)0x25)
-#define	SIU_INT_SCC1		((uint)0x28)
-#define	SIU_INT_SCC2		((uint)0x29)
-#define	SIU_INT_SCC3		((uint)0x2a)
-#define	SIU_INT_SCC4		((uint)0x2b)
-#define	SIU_INT_PC15		((uint)0x30)
-#define	SIU_INT_PC14		((uint)0x31)
-#define	SIU_INT_PC13		((uint)0x32)
-#define	SIU_INT_PC12		((uint)0x33)
-#define	SIU_INT_PC11		((uint)0x34)
-#define	SIU_INT_PC10		((uint)0x35)
-#define	SIU_INT_PC9		((uint)0x36)
-#define	SIU_INT_PC8		((uint)0x37)
-#define	SIU_INT_PC7		((uint)0x38)
-#define	SIU_INT_PC6		((uint)0x39)
-#define	SIU_INT_PC5		((uint)0x3a)
-#define	SIU_INT_PC4		((uint)0x3b)
-#define	SIU_INT_PC3		((uint)0x3c)
-#define	SIU_INT_PC2		((uint)0x3d)
-#define	SIU_INT_PC1		((uint)0x3e)
-#define	SIU_INT_PC0		((uint)0x3f)
+#define	SIU_INT_ERROR		((uint)0x00 + CPM_IRQ_OFFSET)
+#define	SIU_INT_I2C		((uint)0x01 + CPM_IRQ_OFFSET)
+#define	SIU_INT_SPI		((uint)0x02 + CPM_IRQ_OFFSET)
+#define	SIU_INT_RISC		((uint)0x03 + CPM_IRQ_OFFSET)
+#define	SIU_INT_SMC1		((uint)0x04 + CPM_IRQ_OFFSET)
+#define	SIU_INT_SMC2		((uint)0x05 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IDMA1		((uint)0x06 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IDMA2		((uint)0x07 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IDMA3		((uint)0x08 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IDMA4		((uint)0x09 + CPM_IRQ_OFFSET)
+#define	SIU_INT_SDMA		((uint)0x0a + CPM_IRQ_OFFSET)
+#define	SIU_INT_TIMER1		((uint)0x0c + CPM_IRQ_OFFSET)
+#define	SIU_INT_TIMER2		((uint)0x0d + CPM_IRQ_OFFSET)
+#define	SIU_INT_TIMER3		((uint)0x0e + CPM_IRQ_OFFSET)
+#define	SIU_INT_TIMER4		((uint)0x0f + CPM_IRQ_OFFSET)
+#define	SIU_INT_TMCNT		((uint)0x10 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PIT		((uint)0x11 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IRQ1		((uint)0x13 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IRQ2		((uint)0x14 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IRQ3		((uint)0x15 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IRQ4		((uint)0x16 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IRQ5		((uint)0x17 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IRQ6		((uint)0x18 + CPM_IRQ_OFFSET)
+#define	SIU_INT_IRQ7		((uint)0x19 + CPM_IRQ_OFFSET)
+#define	SIU_INT_FCC1		((uint)0x20 + CPM_IRQ_OFFSET)
+#define	SIU_INT_FCC2		((uint)0x21 + CPM_IRQ_OFFSET)
+#define	SIU_INT_FCC3		((uint)0x22 + CPM_IRQ_OFFSET)
+#define	SIU_INT_MCC1		((uint)0x24 + CPM_IRQ_OFFSET)
+#define	SIU_INT_MCC2		((uint)0x25 + CPM_IRQ_OFFSET)
+#define	SIU_INT_SCC1		((uint)0x28 + CPM_IRQ_OFFSET)
+#define	SIU_INT_SCC2		((uint)0x29 + CPM_IRQ_OFFSET)
+#define	SIU_INT_SCC3		((uint)0x2a + CPM_IRQ_OFFSET)
+#define	SIU_INT_SCC4		((uint)0x2b + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC15		((uint)0x30 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC14		((uint)0x31 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC13		((uint)0x32 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC12		((uint)0x33 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC11		((uint)0x34 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC10		((uint)0x35 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC9		((uint)0x36 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC8		((uint)0x37 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC7		((uint)0x38 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC6		((uint)0x39 + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC5		((uint)0x3a + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC4		((uint)0x3b + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC3		((uint)0x3c + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC2		((uint)0x3d + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC1		((uint)0x3e + CPM_IRQ_OFFSET)
+#define	SIU_INT_PC0		((uint)0x3f + CPM_IRQ_OFFSET)
 
 #endif /* CONFIG_8260 */
 

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: [PATCH] CPM2 cleanups
From: Jason McMullan @ 2005-03-23 13:46 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-embedded linuxppc-embedded
In-Reply-To: <ba2549a1f7b9f73004d8d6e52415aee4@freescale.com>

[-- Attachment #1: Type: text/plain, Size: 441 bytes --]

On Tue, 2005-03-22 at 23:46 -0600, Kumar Gala wrote:
> Jason, why did you bother to implement these functions, they dont 
> provide any value for us?
> 
> It looks like startup() & shutdown() are only used in IRQ probing code 
> or code in which enable/disable will be used instead.

startup/shutdown is used in the 'IRQ threads' patch we use at
TimeSys.


-- 
Jason McMullan <jason.mcmullan@timesys.com>
TimeSys Corporation


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: [PATCH] CPM2 cleanups
From: Jason McMullan @ 2005-03-23 13:44 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-embedded
In-Reply-To: <9b9c4447ceb975b7b6dd1498ec686e41@freescale.com>

[-- Attachment #1: Type: text/plain, Size: 551 bytes --]

On Tue, 2005-03-22 at 23:53 -0600, Kumar Gala wrote:
> Some additional comments:
> 
> * Did you actually try setting CPM_IRQ_OFFSET to a non-zero value?  I'm 
> guessing this doesnt work since you are not offset the irq passed into 
> the other functions.  For example, if CPM_IRQ_OFFSET is 64, will 
> cpm2_mask_irq() work?

  YAA! Good catch! (fix fix fix fix....)

> * what is SA_NOTHREAD all about?

  Stale debugging code. Will be removed on the next patch.

-- 
Jason McMullan <jason.mcmullan@timesys.com>
TimeSys Corporation


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* RE: question about writing to memory directly from user space in Linux
From: Fillod Stephane @ 2005-03-23 10:36 UTC (permalink / raw)
  To: Vijay Padiyar, LinuxPPC Support

Vijay Padiyar wrote:
>I am running Linux 2.6.10 on an MPC8260 target. We have an I2C
controller
>that is part of our application code. In VxWorks, we could address the
>MPC8260 I2C memory registers directly from application space and so
this was
>not a problem.

The I2C abstraction layer of Linux is very good, and user-land support
quite comfortable. Why bother port/develop a new driver? Besides,=20
interrupt handling in user-space can be troublesome..

>Can you suggest some kind of a "synchronization" function which I can
call
>from *user space* which will ensure that all values written to mmaped
memory
>locations from user space are actually flushed to their physical
locations?
>I think this might be a potential problem with my code.

Please have a look at Denx's FAQ for accessing memory bus:

=20
http://www.denx.de/twiki/bin/view/PPCEmbedded/DeviceDrivers#Section_Acce
ssingPeripheralsFromUserSpace
or shorter: http://tinyurl.com/6c7th

Depending on the O_SYNC flag passed to open, the mmap'ed memory will be
accessed through non guarded cache or not. See linux/drivers/char/mem.c.
The ppc instruction "eieio" deals with I/O ordering.


Regards,
--=20
Stephane

^ permalink raw reply

* Re: question about writing to memory directly from user space in Linux
From: Stefan Nickl @ 2005-03-23  9:46 UTC (permalink / raw)
  To: Vijay Padiyar; +Cc: LinuxPPC Support
In-Reply-To: <BAY1-DAV1357D81F947F1A31523FE48B4F0@phx.gbl>

On Wed, 2005-03-23 at 14:25 +0530, Vijay Padiyar wrote:
> Can you suggest some kind of a "synchronization" function which I can call
> from *user space* which will ensure that all values written to mmaped memory
> locations from user space are actually flushed to their physical locations?
> I think this might be a potential problem with my code.

Have a look at linux/include/asm-ppc/{io.h,system.h} and
http://www.xml.com/ldd/chapter/book/ch08.html

The eieio instruction doesn't need supervisor rights.

Greetings,

-- 
Stefan Nickl
Kontron Modular Computers

^ permalink raw reply

* question about writing to memory directly from user space in Linux
From: Vijay Padiyar @ 2005-03-23  8:55 UTC (permalink / raw)
  To: LinuxPPC Support

Hi

I am running Linux 2.6.10 on an MPC8260 target. We have an I2C controller
that is part of our application code. In VxWorks, we could address the
MPC8260 I2C memory registers directly from application space and so this was
not a problem.

To port this same code to Linux, I am opening '/dev/mem' and mmapping the
internal memory map of 128 KB to user space. I am writing directly to the
I2C_BASE, I2C PRAM and I2C RxBD/TxBD registers, all of which are in DPRAM,
from my application code through suitable macros.

All of this is fine. I can see that the values have been written to memory
if I do a memory dump of those registers with an external dump tool that
uses '/dev/mem' too.

Now, I have kept my Tx and Rx buffers in DPRAM as well, and have programmed
those addresses in the buffer pointers of my TxBD and RxBDs. However, I am
not sure if the values I'm writing to those locations from user space are
actually being written to the actual memory locations.

This is because I print the value of the first byte of my transmit buffer
pointer BEFORE and AFTER I write the I2C address (0xA0 for us) to it. Before
the address is written, the contents shown are 0x90. After it's written, the
contents are shown rightly as 0xA0, but I don't think this value is actually
written to DPRAM.

This is because when I start I2C transmission by setting the start transfer
bit in I2COM register, the address byte outputted on the I2C SDA bus is
0x90. This means it outputs the original value and not the value which I
wrote to it.

Can you suggest some kind of a "synchronization" function which I can call
from *user space* which will ensure that all values written to mmaped memory
locations from user space are actually flushed to their physical locations?
I think this might be a potential problem with my code.

Regards

Vijay Padiyar

http://www.vijaypadiyar.eu.tf

^ permalink raw reply

* Re: [PATCH] CPM2 cleanups
From: Kumar Gala @ 2005-03-23  5:53 UTC (permalink / raw)
  To: Jason McMullan; +Cc: linuxppc-embedded
In-Reply-To: <1111523269.2987.58.camel@ad.doubleclick.net>

Some additional comments:

* Did you actually try setting CPM_IRQ_OFFSET to a non-zero value?  I'm 
guessing this doesnt work since you are not offset the irq passed into 
the other functions.  For example, if CPM_IRQ_OFFSET is 64, will 
cpm2_mask_irq() work?

* what is SA_NOTHREAD all about?

- kumar

On Mar 22, 2005, at 2:27 PM, Jason McMullan wrote:

> _______________________________________________
> Linuxppc-embedded mailing list
>  Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>
> Date: March 22, 2005 2:28:51 PM CST
> Subject:
>
>
>
> Date: March 22, 2005 2:28:51 PM CST
> Subject:
>
>
> <ATT128341.txt><cpu-ppc-cpm2.patch>
>
> <signature.asc>
>

^ permalink raw reply

* Re: [PATCH] CPM2 cleanups
From: Kumar Gala @ 2005-03-23  5:46 UTC (permalink / raw)
  To: Jason McMullan; +Cc: linuxppc-embedded linuxppc-embedded
In-Reply-To: <20050322211839.6A3DCC1510@atlas.denx.de>

Jason, why did you bother to implement these functions, they dont=20
provide any value for us?

It looks like startup() & shutdown() are only used in IRQ probing code=20=

or code in which enable/disable will be used instead.

- kumar

On Mar 22, 2005, at 3:18 PM, Wolfgang Denk wrote:

> In message <1111523269.2987.58.camel@ad.doubleclick.net> you wrote:
>  >
> ...
>  > +static unsigned int cpm2_startup_irq(unsigned int irq)
>  > +{=A0
> > +=A0=A0=A0=A0=A0=A0 cpm2_unmask_irq(irq);
> > +=A0=A0=A0=A0=A0=A0 return 0;
>  > +}
>  > +
>  > +static void cpm2_shutdown_irq(unsigned int irq)
>  > +{
>  > +=A0=A0=A0=A0=A0=A0 cpm2_mask_irq(irq);
> > +}
>
> Why is cpm2_startup_irq() not void like cpm2_shutdown_irq() ?
>
> Best regards,
>
> Wolfgang Denk
>
> --=20
> Software Engineering:=A0 Embedded and Realtime Systems,=A0 Embedded =
Linux
>  Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
>  Overflow on /dev/null, please empty the bit bucket.
>  _______________________________________________
> Linuxppc-embedded mailing list
>  Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded

^ permalink raw reply

* Re: [PATCH] MPC85xx CDS - Time Of Day, Cache settings, CPM IRQs
From: Kumar Gala @ 2005-03-22 22:56 UTC (permalink / raw)
  To: Jason McMullan; +Cc: linuxppc-embedded
In-Reply-To: <1111524464.2987.69.camel@ad.doubleclick.net>

Some feedback on the patches:

* I'm not going to accept the printing of caches enabled, etc.  If you 
want to do this add sysfs attributes to the CPU.  That is more useful 
going forward and we dont have to do it for every board then.  (Plus we 
can add other attributes)

* TODC should already exist in 2.6.12-rc1

* I'll take a look at the CPM changes

- kumar

On Mar 22, 2005, at 2:47 PM, Jason McMullan wrote:

> _______________________________________________
> Linuxppc-embedded mailing list
>  Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>
> Date: March 22, 2005 2:49:12 PM CST
> Subject:
>
>
>
> Date: March 22, 2005 2:49:12 PM CST
> Subject:
>
>
> <ATT118674.txt><board-ppc-mpc85xx-cds.patch>
>
> <signature.asc>
>

^ permalink raw reply

* Re: Linux 2.6.x on 8xx status
From: Dan Malek @ 2005-03-22 22:53 UTC (permalink / raw)
  To: Marcelo Tosatti; +Cc: Smith, Craig, paulus, linux-ppc-embedded
In-Reply-To: <20050322175815.GB7846@logos.cnet>


On Mar 22, 2005, at 12:58 PM, Marcelo Tosatti wrote:

> Newbie question: What prevents the initial kernel map (tuple of 8Mbyte 
> I/D-TLB entries)
> and the IMMR 8Mbyte D-TLB entry from getting unmapped by translation 
> pressure,
> in case CONFIG_PIN_TLB is disabled ?

Nothing.  In fact, they are likely invalidated shortly after the kernel
page tables are set up.  This was only done to ensure we could get the
kernel initialized without taking page faults.

> By a counter at the end of _tlbie function, similar to other counters 
> which
> you suggested.

OK.

> Dont think thats the case given that v2.4 calls tlbia through 
> flush_tlb_mm() at exit_mmap()
> only. And at vmalloc_free which shouldnt be called at all.

Hmmm ...  Then, the 2.6 looks to be much less efficient with the MMU
resources than 2.4 was.  This is going to affect everyone, it's just 
easier
to measure on this processor.

> I just noticed this conditional at switch_mm() (v2.6), which _can_ 
> partly
> explain the reduced tlbie's  (its just a guess for now, though):

What is your guess?  I don't know how this would reduce the number
of tlbie instructions, since stealing a context (as part of 
get_context())
will simply whack the whole TLB with a tlbia.  On 8xx, both instructions
could be simply implemented as macros.

> Spent part of the day reading the MMU section of 860 manual, I think I 
> have kind
> of a clue how things are supposed to work at the lowlevel now.

:-)

> PS: I can't reproduce the invalid TLB crash anymore. i.e. even by 
> removing
> the _tlbie() at update_mmu_cache() everything is working as expected.

Well, that's interesting.  It's likely to only happen on an 860 variant 
that
has the large TLB.

> How can I reproduce it again? Guillaume, what kernel version are you 
> using?

It used to happen on early 2.6 versions as soon as you entered user
space programs.


	-- Dan

^ permalink raw reply

* Re: Linux 2.6.x on 8xx status
From: Marcelo Tosatti @ 2005-03-22 17:58 UTC (permalink / raw)
  To: Dan Malek; +Cc: Smith, Craig, paulus, linux-ppc-embedded
In-Reply-To: <f4f476b5e54e9f005dd28082bd5f16fe@embeddededge.com>

On Tue, Mar 22, 2005 at 03:57:08PM -0500, Dan Malek wrote:
> 
> On Mar 22, 2005, at 8:04 AM, Marcelo Tosatti wrote:
> 
> >I'm quite puzzled. Why v2.6 calls the "tlbie" instruction 100-or-so
> >less times than v2.4 ?

That was rather a _factor_ of "100-or-so" less.

> Oh my ...  I'm more worried about the high number of TLB misses
> in 2.6 compared to 2.4.  That's really bad.  

Newbie question: What prevents the initial kernel map (tuple of 8Mbyte I/D-TLB entries) 
and the IMMR 8Mbyte D-TLB entry from getting unmapped by translation pressure,
in case CONFIG_PIN_TLB is disabled ? 

> How did you instrument the tlbie measurement? 

By a counter at the end of _tlbie function, similar to other counters which 
you suggested.

> It could be that 2.4 used lots more 'tlbia' which were replaced by tlbie in 2.6.

Dont think thats the case given that v2.4 calls tlbia through flush_tlb_mm() at exit_mmap() 
only. And at vmalloc_free which shouldnt be called at all.

I just noticed this conditional at switch_mm() (v2.6), which _can_ partly 
explain the reduced tlbie's  (its just a guess for now, though):

static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
                             struct task_struct *tsk)
{
#ifdef CONFIG_ALTIVEC
        asm volatile (
 BEGIN_FTR_SECTION
        "dssall;\n"
#ifndef CONFIG_POWER4
         "sync;\n" /* G4 needs a sync here, G5 apparently not */
#endif
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
         : : );
#endif /* CONFIG_ALTIVEC */
                                                                                            
        tsk->thread.pgdir = next->pgd;
                                                                                            
        /* No need to flush userspace segments if the mm doesnt change */
	if (prev == next) 				<--------------
		return;   				<--------------
                                                                                            
        /* Setup new userspace context */
        get_mmu_context(next);
        set_context(next->context, next->pgd);
}

I'm about to disable it and retry.

Spent part of the day reading the MMU section of 860 manual, I think I have kind 
of a clue how things are supposed to work at the lowlevel now. 

I'll continue tracking it down - any help is appreciated.

PS: I can't reproduce the invalid TLB crash anymore. i.e. even by removing
the _tlbie() at update_mmu_cache() everything is working as expected.

How can I reproduce it again? Guillaume, what kernel version are you using?

^ permalink raw reply

* Re: Linux 2.6.x on 8xx status
From: Dan Malek @ 2005-03-22 20:57 UTC (permalink / raw)
  To: Marcelo Tosatti; +Cc: Smith, Craig, paulus, linux-ppc-embedded
In-Reply-To: <20050322130426.GE2498@logos.cnet>


On Mar 22, 2005, at 8:04 AM, Marcelo Tosatti wrote:

> I'm quite puzzled. Why v2.6 calls the "tlbie" instruction 100-or-so
> less times than v2.4 ?

Oh my ...  I'm more worried about the high number of TLB misses
in 2.6 compared to 2.4.  That's really bad.  How did you instrument
the tlbie measurement?  It could be that 2.4 used lots more 'tlbia'
which were replaced by tlbie in 2.6.

Thanks.


	-- Dan

^ permalink raw reply

* Re: Need help.
From: Kumar Gala @ 2005-03-22 21:36 UTC (permalink / raw)
  To: Naveen Kumar Atmakuri; +Cc: linuxppc-embedded
In-Reply-To: <000601c52e9e$3b9de080$870da8c0@anaveen>

While I can specify a place for you to get precompiled binaries for=20
MPC7448, I can suggest grabbing crosstool from:
    http://www.kegel.com/crosstool/

There is a 7450 config which will work for MPC7448.

- kumar


On Mar 21, 2005, at 11:15 PM, Naveen Kumar Atmakuri wrote:

> Hi everybody,
> =A0
> Could any one suggest the toolchain and kernel versions that are=20
> compatible with the MPC7448 processor ( It's a motorola processor=20
> based on power PC architecture ). Is there any site from where we can=20=

> download the precompiled binaries for the same processor.
> =A0
> With Regards& Thanks,
> A.Naveen Kumar,
> Design Engineer,
> Mistral Software Pvt Ltd.
> <ATT92461.txt>=

^ permalink raw reply

* Re: [PATCH] CPM2 cleanups
From: Wolfgang Denk @ 2005-03-22 21:18 UTC (permalink / raw)
  To: Jason McMullan; +Cc: linuxppc-embedded
In-Reply-To: <1111523269.2987.58.camel@ad.doubleclick.net>

In message <1111523269.2987.58.camel@ad.doubleclick.net> you wrote:
> 
...
> +static unsigned int cpm2_startup_irq(unsigned int irq)
> +{  
> +       cpm2_unmask_irq(irq);
> +       return 0;
> +}
> +
> +static void cpm2_shutdown_irq(unsigned int irq)
> +{
> +       cpm2_mask_irq(irq);
> +}

Why is cpm2_startup_irq() not void like cpm2_shutdown_irq() ?

Best regards,

Wolfgang Denk

-- 
Software Engineering:  Embedded and Realtime Systems,  Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
Overflow on /dev/null, please empty the bit bucket.

^ permalink raw reply

* [PATCH] Updated: CPM2 I2C (SDMA and BitBang)
From: Jason McMullan @ 2005-03-22 21:12 UTC (permalink / raw)
  To: linuxppc-embedded


[-- Attachment #1.1: Type: text/plain, Size: 267 bytes --]

Updated (thanks to a quick eye by ebs) patch to add 
CPM2 SDMA and BitBang I2C support to the MPC85xx

This patch gets rid of some really stupid cut & paste errors
during initialization.

-- 
Jason McMullan <jason.mcmullan@timesys.com>
TimeSys Corporation


[-- Attachment #1.2: driver-i2c-cpm.patch --]
[-- Type: text/x-patch, Size: 24409 bytes --]

#### Auto-generated patch ####
Date:        Tue, 22 Mar 2005 15:59:01 -0500
Maintainer:  Jason McMullan <jmcmullan@timesys.com>
Summary:     CPM/CPM2 I2C driver for Freescale SoC devices
Description: CPM/CPM2 I2C driver for Freescale SoC devices
Depends:
	
###############################

Index of changes:

 drivers/i2c/algos/Kconfig              |    4 
 drivers/i2c/algos/Makefile             |    1 
 drivers/i2c/busses/Kconfig             |   25 +
 drivers/i2c/busses/Makefile            |    1 
 include/linux/i2c-id.h                 |    4 
 linux/drivers/i2c/algos/i2c-algo-cpm.c |  477 +++++++++++++++++++++++++++++++++
 linux/drivers/i2c/busses/i2c-cpm.c     |  219 +++++++++++++++
 linux/include/linux/i2c-algo-cpm.h     |   64 ++++
 8 files changed, 791 insertions(+), 4 deletions(-)


--- linux-orig/drivers/i2c/algos/Kconfig
+++ linux/drivers/i2c/algos/Kconfig
@@ -16,6 +16,10 @@
 	  This support is also available as a module.  If so, the module 
 	  will be called i2c-algo-bit.
 
+config I2C_ALGO_CPM
+	tristate "MPC (8xx and 8xxx) CPM I2C interface"
+	depends on (8xx || 85xx ) && I2C
+
 config I2C_ALGOPCF
 	tristate "I2C PCF 8584 interfaces"
 	depends on I2C
--- linux-orig/drivers/i2c/algos/Makefile
+++ linux/drivers/i2c/algos/Makefile
@@ -3,6 +3,7 @@
 #
 
 obj-$(CONFIG_I2C_ALGOBIT)	+= i2c-algo-bit.o
+obj-$(CONFIG_I2C_ALGO_CPM)	+= i2c-algo-cpm.o
 obj-$(CONFIG_I2C_ALGOPCF)	+= i2c-algo-pcf.o
 obj-$(CONFIG_I2C_ALGOPCA)	+= i2c-algo-pca.o
 obj-$(CONFIG_I2C_ALGOITE)	+= i2c-algo-ite.o
--- /dev/null
+++ linux/drivers/i2c/algos/i2c-algo-cpm.c
@@ -0,0 +1,477 @@
+/*
+ * i2c-algo-cpm.c i2x driver algorithms for Motorola MPC CPM
+ * Copyright (c) 2004 Jason McMullan (jason.mcmullan@timesys.com)
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * based on i2c-algo-cpm.c
+ */
+
+/* $Id$ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-cpm.h>
+
+#include <asm/io.h>
+
+#define I2C_VERSION	"0.1"
+#define I2C_DATE	"Mar 22, 2005"
+
+#define CPM_MAX_READ	513
+/* #define I2C_CHIP_ERRATA */ /* Try uncomment this if you have an older CPU(earlier than rev D4) */
+
+#undef DEBUG
+
+#ifdef DEBUG
+int cpm_debug = 0;
+MODULE_PARM(cpm_debug, "i");
+#define static /**/
+#define DPRINTK(fmt, args...) printk(KERN_INFO fmt ,##args)
+#else
+#define DPRINTK(args...) do { } while (0)
+#endif
+
+static void cpm_i2c_param_reset(struct i2c_algo_cpm_data *cpm_adap)
+{
+	volatile cpm_iic_t	*iip = cpm_adap->iip;
+
+	/* Set up the IIC parameters in the parameter ram.
+	*/
+	iip->iic_rbase = cpm_adap->dp_offset;
+	iip->iic_tbase = cpm_adap->dp_offset + sizeof(cbd_t)*2;
+
+	/* Initialize the parameter ram.
+	 * We need to make sure many things are initialized to zero,
+	 * especially in the case of a microcode patch.
+	 */
+	iip->iic_rstate = 0;
+	iip->iic_rdp = 0;
+	iip->iic_rbptr = 0;
+	iip->iic_rbc = 0;
+	iip->iic_rxtmp = 0;
+	iip->iic_tstate = 0;
+	iip->iic_tdp = 0;
+	iip->iic_tbptr = 0;
+	iip->iic_tbc = 0;
+	iip->iic_txtmp = 0;
+
+	iip->iic_tfcr = CPMFCR_EB | CPMFCR_GBL;
+	iip->iic_rfcr = CPMFCR_EB | CPMFCR_GBL;
+
+	/* Set maximum receive size.
+	*/
+	iip->iic_mrblr = CPM_MAX_READ;
+
+}
+
+static int i2c_cpm_start(struct i2c_algo_cpm_data *cpm)
+{
+	volatile cpm_i2c_t *i2c = cpm->i2c;
+
+	DPRINTK("i2c_cpm_start: Ready (i2cmr=%.2x, i2cer=%.2x, i2com=%.2x, i2mod=%.2x)\n", i2c->i2c_i2cmr,i2c->i2c_i2cer,i2c->i2c_i2com,i2c->i2c_i2mod);
+
+	/* Wait for IIC transfer */
+	cpm->status = -EBUSY;
+	i2c->i2c_i2mod &= ~I2MOD_EN;
+
+	/* Chip bug, set enable here */
+	i2c->i2c_i2cmr = I2CER_MASK;	/* Enable interupts */
+	i2c->i2c_i2cer = I2CER_MASK;
+	i2c->i2c_i2mod = I2MOD_EN;		/* Enable */
+	i2c->i2c_i2com = I2COM_STR | I2COM_MS;	/* Begin transmission */
+	interruptible_sleep_on(&cpm->wait);
+
+	DPRINTK("i2c_cpm_start: Done  (i2cmr=%.2x, i2cer=%.2x, i2com=%.2x, i2mod=%.2x)\n", i2c->i2c_i2cmr,i2c->i2c_i2cer,i2c->i2c_i2com,i2c->i2c_i2mod);
+
+	DPRINTK("i2c_cpm_start: result=%d\n",cpm->status);
+	return cpm->status;
+}
+
+static irqreturn_t i2c_cpm_interrupt(int unused, void *dev_id, struct pt_regs *regs)
+ {
+	struct i2c_algo_cpm_data *cpm_adap = dev_id;
+	uint8_t events;
+
+#ifdef I2C_CHIP_ERRATA
+	/* Chip errata, clear enable.
+	 * This seems to not be needed on rev D4 or newer CPUs.
+	 * Someone with an older CPU needs to verify this.
+	 */
+	cpm_adap->i2c->i2c_i2mod &= ~I2MOD_EN; wmb();
+#endif
+
+	events = cpm_adap->i2c->i2c_i2cer;
+	DPRINTK("i2c_cpm_interrupt: dev_id=0x%p, i2cer=0x%.2x\n", dev_id,events);
+
+
+	if (events & I2CER_TXE) {
+		cpm_adap->status = -ENODEV;
+	} else if (events & I2CER_BSY) {
+		cpm_adap->status = -EAGAIN;
+	} else if (events & (I2CER_RXB | I2CER_TXB)) {
+		cpm_adap->status = 0;
+	}
+
+	/* Clear interrupt.
+	*/
+	cpm_adap->i2c->i2c_i2cer = events; wmb();
+
+	/* Get 'em going again.
+	*/
+	wake_up_interruptible(&cpm_adap->wait);
+
+	return IRQ_HANDLED;
+}
+
+/* Read from IIC...
+ * abyte = address byte, with r/w flag already set
+ */
+static int i2c_cpm_read(struct i2c_algo_cpm_data *cpm, uint8_t abyte, char *buf, int count)
+{
+	volatile cbd_t	*tbdf, *rbdf;
+	uint8_t *tb;
+	dma_addr_t tb_dma[2];
+	int err;
+
+	DPRINTK("i2c_cpm_read: abyte=0x%x(%c)\n", abyte>>1, "wr"[abyte&1]);
+
+	if (count >= CPM_MAX_READ)
+		return -EINVAL;
+
+	/* If we are relocated, we must reset the params */
+	if (cpm->reloc)
+		cpm_i2c_param_reset(cpm);
+
+	rbdf = (void *)cpm_dpram_addr(cpm->iip->iic_rbase);
+	tbdf = (void *)cpm_dpram_addr(cpm->iip->iic_tbase);
+
+	/* To read, we need an empty buffer of the proper length.
+	 * All that is used is the first byte for address, the remainder
+	 * is just used for timing (and doesn't really have to exist).
+	 */
+	tb = cpm->temp;
+	tb[0] = abyte;		/* Device address byte w/rw flag */
+
+
+	tb_dma[0] = dma_map_single(cpm->device, tb, 1, DMA_TO_DEVICE);
+	tbdf->cbd_bufaddr = tb_dma[0];
+	tbdf->cbd_datlen = 1;
+	tbdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START;
+
+	cpm->iip->iic_mrblr = count + 1;
+
+	tb_dma[1] = dma_map_single(cpm->device, buf, count, DMA_FROM_DEVICE);
+	rbdf->cbd_datlen = 0;
+	rbdf->cbd_bufaddr = tb_dma[1];
+	rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP| BD_SC_INTRPT;
+
+	DPRINTK("tbdf->cbd_sc(0x%p) = 0x%.4x\n",&tbdf->cbd_sc,tbdf->cbd_sc);
+	DPRINTK("rbdf->cbd_sc(0x%p) = 0x%.4x\n",&rbdf->cbd_sc,rbdf->cbd_sc);
+	err = i2c_cpm_start(cpm);
+	dma_unmap_single(cpm->device, tb_dma[1], count, DMA_FROM_DEVICE);
+	dma_unmap_single(cpm->device, tb_dma[0], 1, DMA_TO_DEVICE);
+	DPRINTK("tbdf->cbd_sc(0x%p) = 0x%.4x\n",&tbdf->cbd_sc,tbdf->cbd_sc);
+	DPRINTK("rbdf->cbd_sc(0x%p) = 0x%.4x\n",&rbdf->cbd_sc,rbdf->cbd_sc);
+	if (err)
+		return err;
+
+	if (tbdf->cbd_sc & BD_SC_READY) {
+		DPRINTK("i2c_cpm_read: complete but tbuf ready\n");
+		DPRINTK("\ttx sc %04x, rx sc %04x\n", tbdf->cbd_sc, rbdf->cbd_sc);
+		return -EREMOTEIO;
+	}
+
+	if (tbdf->cbd_sc & BD_SC_NAK) {
+		DPRINTK("i2c_cpm_read: no ack\n");
+		return -EREMOTEIO;
+ 	}
+
+	if (rbdf->cbd_sc & BD_SC_EMPTY) {
+		DPRINTK("i2c_cpm_read: complete but rbuf empty\n");
+		DPRINTK("\ttx sc %04x, rx sc %04x\n", tbdf->cbd_sc, rbdf->cbd_sc);
+		return -EREMOTEIO;
+	}
+
+	if (rbdf->cbd_sc & BD_SC_OV) {
+		DPRINTK("i2c_cpm_read: Overrun\n");
+		return -EREMOTEIO;
+ 	}
+
+	DPRINTK("i2c_cpm_read: read %d bytes\n", rbdf->cbd_datlen);
+
+	if (rbdf->cbd_datlen < count) {
+		DPRINTK("i2c_cpm_read: short, wanted %d got %d\n", count, rbdf->cbd_datlen);
+	}
+
+	return count;
+}
+
+/* Write to IIC...
+ * addr = address byte, with r/w flag already set
+ */
+static int
+i2c_cpm_write(struct i2c_algo_cpm_data *cpm, uint8_t abyte, char *buf,int count)
+{
+	volatile cbd_t *tbdf, *rbdf;
+	uint8_t *tb;
+	dma_addr_t tb_dma[2];
+	int err;
+
+	DPRINTK("i2c_cpm_write: abyte=0x%x(%c)\n", abyte>>1, "wr"[abyte&1]);
+
+	/* If we are relocated, we must reset the params */
+	if (cpm->reloc)
+		cpm_i2c_param_reset(cpm);
+
+	tb = cpm->temp;
+	tb[0] = abyte;		/* Device address byte w/rw flag */
+
+	/* set up 2 descriptors */
+	tbdf = (void *)cpm_dpram_addr(cpm->iip->iic_tbase);
+	rbdf = (void *)cpm_dpram_addr(cpm->iip->iic_rbase);
+
+	tb_dma[0] = dma_map_single(cpm->device, tb, 1, DMA_TO_DEVICE);
+	tbdf[0].cbd_bufaddr = tb_dma[0];
+	tbdf[0].cbd_datlen = 1;
+	tbdf[0].cbd_sc = BD_SC_READY | BD_SC_INTRPT | BD_IIC_START;
+
+	if (count > 0) {
+		tb_dma[1] = dma_map_single(cpm->device, buf, count, DMA_TO_DEVICE);
+		tbdf[1].cbd_bufaddr = tb_dma[1];
+		tbdf[1].cbd_datlen = count;
+		tbdf[1].cbd_sc = BD_SC_READY | BD_SC_INTRPT | BD_SC_LAST | BD_SC_WRAP;
+	} else {
+		tbdf[0].cbd_sc |= BD_SC_INTRPT | BD_SC_LAST | BD_SC_WRAP;
+		tb_dma[1] = 0;
+	}
+
+	rbdf[0].cbd_sc = BD_SC_WRAP;
+
+	DPRINTK("tbdf->cbd_sc(0x%p) = 0x%.4x(%d),0x%.4x(%d)\n",&tbdf->cbd_sc,tbdf[0].cbd_sc,tbdf[0].cbd_datlen,tbdf[1].cbd_sc,tbdf[1].cbd_datlen);
+	err = i2c_cpm_start(cpm);
+
+	if (tb_dma[1])
+		dma_unmap_single(cpm->device, tb_dma[1], count, DMA_TO_DEVICE);
+	dma_unmap_single(cpm->device, tb_dma[0], 1, DMA_TO_DEVICE);
+
+	DPRINTK("tbdf->cbd_sc(0x%p) = 0x%.4x(%d),0x%.4x(%d)\n",&tbdf->cbd_sc,tbdf[0].cbd_sc,tbdf[0].cbd_datlen,tbdf[1].cbd_sc,tbdf[1].cbd_datlen);
+	if (err < 0)
+		return err;
+
+
+	if (tbdf->cbd_sc & BD_SC_NAK) {
+		DPRINTK("i2c_cpm_write; no ack\n");
+		return -ENODEV;
+	}
+
+	if (tbdf->cbd_sc & BD_SC_READY) {
+		DPRINTK("i2c_cpm_write: complete but tbuf ready\n");
+		return -EREMOTEIO;
+	}
+
+	return count;
+}
+
+static int cpm_xfer(struct i2c_adapter *i2c_adap,
+		    struct i2c_msg msgs[],
+		    int num)
+{
+	struct i2c_algo_cpm_data *adap = i2c_adap->algo_data;
+	struct i2c_msg *pmsg;
+	int i, ret;
+	uint8_t addr;
+
+	for (i = 0; i < num; i++) {
+		pmsg = &msgs[i];
+
+		DPRINTK("i2c-algo-cpm: #%d addr=0x%x flags=0x%x len=%d\n buf=%lx\n", i, pmsg->addr, pmsg->flags, pmsg->len, (unsigned long)pmsg->buf);
+
+		addr = pmsg->addr << 1;
+		if (pmsg->flags & I2C_M_RD )
+			addr |= 1;
+		if (pmsg->flags & I2C_M_REV_DIR_ADDR )
+			addr ^= 1;
+
+		if (!(pmsg->flags & I2C_M_NOSTART)) {
+		}
+		if (pmsg->flags & I2C_M_RD ) {
+			/* read bytes into buffer*/
+			ret = i2c_cpm_read(adap, addr, pmsg->buf, pmsg->len);
+			DPRINTK("i2c-algo-cpm: read %d bytes\n", ret);
+			if (ret < pmsg->len ) {
+				return (ret<0)? ret : -EREMOTEIO;
+			}
+		} else {
+			/* write bytes from buffer */
+			ret = i2c_cpm_write(adap, addr, pmsg->buf, pmsg->len);
+			DPRINTK("i2c-algo-cpm: wrote %d\n", ret);
+			if (ret < pmsg->len ) {
+				return (ret<0) ? ret : -EREMOTEIO;
+			}
+		}
+	}
+	return (num);
+}
+
+static int algo_control(struct i2c_adapter *adapter,
+	unsigned int cmd, unsigned long arg)
+{
+	return 0;
+}
+
+static u32 cpm_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+/* -----exported algorithm data: -------------------------------------	*/
+
+static struct i2c_algorithm cpm_algo = {
+	"CPM2 algorithm",
+	I2C_ALGO_CPM2,
+	cpm_xfer,
+	NULL,
+	NULL,				/* slave_xmit		*/
+	NULL,				/* slave_recv		*/
+	algo_control,			/* ioctl		*/
+	cpm_func,			/* functionality	*/
+};
+
+static int i2c_cpm_init(struct i2c_algo_cpm_data *cpm_adap)
+{
+	volatile cpm_i2c_t	*i2c = cpm_adap->i2c;
+	unsigned char brg;
+
+	DPRINTK("i2c_cpm_init() - iip=%p\n",cpm_adap->iip);
+
+	cpm_adap->dp_offset = cpm_dpalloc(sizeof(cbd_t)*4+1, 16);
+	cpm_adap->temp = cpm_dpram_addr(cpm_adap->dp_offset+sizeof(cbd_t)*4);
+
+	cpm_i2c_param_reset(cpm_adap);
+
+	/* Initialize Tx/Rx parameters.
+	*/
+	if (! cpm_adap->reloc)
+		cpm_cp_command(CPM_CP_I2C, CPM_CR_INIT_TRX);
+
+	/* Select an arbitrary address.  Just make sure it is unique.
+	*/
+	i2c->i2c_i2add = 0xfc; wmb();
+
+	/* Make clock run at 60 KHz.
+	*/
+	brg = (unsigned char) (cpm_adap->intfreq/(32*2*60000) -3);
+	i2c->i2c_i2brg = brg;
+
+	i2c->i2c_i2mod = I2MOD_FLT; /* Enable filter */
+
+	/* Disable interrupts.
+	*/
+	i2c->i2c_i2cmr = 0;
+	i2c->i2c_i2cer = 0xff;
+
+	init_waitqueue_head(&cpm_adap->wait);
+
+	/* Install interrupt handler.
+	*/
+	DPRINTK("%s[%d] Install ISR for IRQ %d\n", __func__,__LINE__, cpm_adap->irq);
+	return request_irq(cpm_adap->irq, i2c_cpm_interrupt, 0, "i2c-algo-cpm", cpm_adap);
+}
+
+
+static int
+i2c_cpm_shutdown(struct i2c_algo_cpm_data *cpm_adap)
+{
+	volatile cpm_i2c_t *i2c = cpm_adap->i2c;
+
+	/* Shut down IIC.
+	*/
+	i2c->i2c_i2mod &= ~I2MOD_EN;
+	i2c->i2c_i2cmr = 0;
+	i2c->i2c_i2cer = I2CER_MASK;
+	free_irq(cpm_adap->irq,cpm_adap);
+	cpm_dpfree(cpm_adap->dp_offset);
+
+	return(0);
+}
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_cpm_add_bus(struct i2c_adapter *adap)
+{
+	struct i2c_algo_cpm_data *cpm_adap = adap->algo_data;
+
+	DPRINTK("i2c-algo-cpm: hw routines for %s registered.\n", adap->name);
+
+	/* register new adapter to i2c module... */
+
+	adap->id |= cpm_algo.id;
+	adap->algo = &cpm_algo;
+
+	i2c_add_adapter(adap);
+	i2c_cpm_init(cpm_adap);
+
+	return 0;
+}
+
+int i2c_cpm_del_bus(struct i2c_adapter *adap)
+{
+	int res;
+	struct i2c_algo_cpm_data *cpm_adap = adap->algo_data;
+
+	i2c_cpm_shutdown(cpm_adap);
+
+	if ((res = i2c_del_adapter(adap)) < 0)
+		return res;
+
+	printk("i2c-algo-cpm: adapter unregistered: %s\n",adap->name);
+
+	return 0;
+}
+
+MODULE_LICENSE("GPL");
+EXPORT_SYMBOL(i2c_cpm_add_bus);
+EXPORT_SYMBOL(i2c_cpm_del_bus);
+
+int __init i2c_algo_cpm_init (void)
+{
+	printk("i2c-algo-cpm: CPM2 I2C algorithm module version %s (%s)\n", I2C_VERSION, I2C_DATE);
+	return 0;
+}
+
+
+MODULE_AUTHOR("Jason McMullan <jason.mcmullan@timesys.com>");
+MODULE_DESCRIPTION("I2C-Bus CPM2 algorithm");
+
+static void i2c_algo_cpm_exit(void)
+{
+}
+
+module_init(i2c_algo_cpm_init);
+module_exit(i2c_algo_cpm_exit);

--- linux-orig/drivers/i2c/busses/Kconfig
+++ linux/drivers/i2c/busses/Kconfig
@@ -229,6 +229,21 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-mpc.
 
+config I2C_CPM
+	tristate "Motorola MPC8xx and MPC85xx CPM I2C"
+	depends on (8xx || 85xx) && I2C
+	help
+	  This supports the use of the I2C interface in the Motorola
+	  MPC8xx and MPC85xx series embedded processors on the CPM
+	  I2C macrocell.
+
+config I2C_CPM_BIT
+	bool "Bit-Bang only?"
+	depends on I2C_CPM
+	help
+	  Only use the CPM parallel port bit-banging interface, not the
+	  SDMA CPM device.
+
 config I2C_NFORCE2
 	tristate "Nvidia Nforce2"
 	depends on I2C && PCI && EXPERIMENTAL
@@ -317,10 +332,12 @@
 	  This support is also available as a module.  If so, the module 
 	  will be called i2c-prosavage.
 
-config I2C_RPXLITE
-	tristate "Embedded Planet RPX Lite/Classic support"
-	depends on (RPXLITE || RPXCLASSIC) && I2C
-	select I2C_ALGO8XX
+# This appears to be broken...
+#
+#config I2C_RPXLITE
+#	tristate "Embedded Planet RPX Lite/Classic support"
+#	depends on (RPXLITE || RPXCLASSIC) && I2C
+#	select I2C_ALGO8XX
 
 config I2C_S3C2410
 	tristate "S3C2410 I2C Driver"
--- linux-orig/drivers/i2c/busses/Makefile
+++ linux/drivers/i2c/busses/Makefile
@@ -8,6 +8,7 @@
 obj-$(CONFIG_I2C_AMD756)	+= i2c-amd756.o
 obj-$(CONFIG_I2C_AMD756_S4882)	+= i2c-amd756-s4882.o
 obj-$(CONFIG_I2C_AMD8111)	+= i2c-amd8111.o
+obj-$(CONFIG_I2C_CPM)		+= i2c-cpm.o
 obj-$(CONFIG_I2C_AU1550)	+= i2c-au1550.o
 obj-$(CONFIG_I2C_ELEKTOR)	+= i2c-elektor.o
 obj-$(CONFIG_I2C_HYDRA)		+= i2c-hydra.o
--- /dev/null
+++ linux/drivers/i2c/busses/i2c-cpm.c
@@ -0,0 +1,219 @@
+/*
+ * CPM I2C interface.
+ * Copyright (c) 2004 Jason McMullan (jason.mcmullan@timesys.com)
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
+ *
+ * On-Chip Peripheral version of the Motorola CPM I2C macrocell driver,
+ * used on the MPC8xx and MPC85xx series processors.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/stddef.h>
+#include <linux/device.h>
+
+#include <linux/i2c.h>
+
+#include <asm/io.h>
+#ifdef CONFIG_CPM2
+#include <asm/cpm2.h>
+#else
+#include <asm/commproc.h>
+#endif
+
+#ifdef CONFIG_I2C_CPM_BIT
+#include <linux/i2c-algo-bit.h>
+
+#define CYCLE_DELAY	10
+#define TIMEOUT		(HZ / 2)
+#endif /* CONFIG_I2C_CPM_BIT */
+
+#ifdef CONFIG_CPM2
+/* SDA and SCL bits on port D */
+#define BIT_SDA (1<<16)
+#define BIT_SCL (1<<17)
+#endif /* CONFIG_CPM2 */
+
+#ifdef CONFIG_I2C_CPM_BIT
+static void bit_cpm_setsda(void *data, int state)
+{
+	if (state)
+		cpm2_immr->im_ioport.iop_pdatd |= BIT_SDA;
+	else
+		cpm2_immr->im_ioport.iop_pdatd &= ~BIT_SDA;
+}
+
+static void bit_cpm_setscl(void *data, int state)
+{
+	if (state)
+		cpm2_immr->im_ioport.iop_pdatd |= BIT_SCL;
+	else
+		cpm2_immr->im_ioport.iop_pdatd &= ~BIT_SCL;
+}
+
+static int bit_cpm_getsda(void *data)
+{
+	return (cpm2_immr->im_ioport.iop_pdatd & BIT_SDA) ? 1 : 0;
+}
+
+static int bit_cpm_getscl(void *data)
+{
+	return (cpm2_immr->im_ioport.iop_pdatd & BIT_SCL) ? 1 : 0;
+}
+
+
+static struct i2c_algo_bit_data cpm_data = {
+	.setsda = bit_cpm_setsda,
+	.setscl = bit_cpm_setscl,
+	.getsda = bit_cpm_getsda,
+	.getscl = bit_cpm_getscl,
+	.udelay = CYCLE_DELAY,
+	.mdelay = CYCLE_DELAY,
+	.timeout = TIMEOUT
+};
+#else /* !CONFIG_I2C_CPM_BIT */
+#include <linux/i2c-algo-cpm.h>
+
+static struct i2c_algo_cpm_data cpm_data = { .irq = -1 };
+#endif /* !CONFIG_I2C_CPM_BIT */
+
+static struct i2c_adapter cpm_ops = {
+	.owner		= THIS_MODULE,
+	.name		= "cpm-i2c",
+	.id		= I2C_HW_CPM2,
+	.algo_data	= &cpm_data,
+};
+
+#ifdef CONFIG_I2C_CPM_BIT
+static int __devinit cpm_i2c_probe_bitbang(struct device *dev)
+{
+#ifdef CONFIG_CPM2
+	if (cpm2_immr->im_ioport.iop_ppard & (BIT_SCL | BIT_SDA)) {
+		printk(KERN_INFO "%s: CPM I/O Port D is not configured for I2C bit-bang mode.\n", pdev->bus_id);
+		return -ENODEV;
+	}
+
+	/* Configure as open drain... */
+	cpm2_immr->im_ioport.iop_podrd |= (BIT_SCL | BIT_SDA);
+
+	/* Inputs... */
+	cpm2_immr->im_ioport.iop_pdird &= ~(BIT_SCL | BIT_SDA);
+#endif
+
+	return i2c_bit_add_bus(&cpm_ops);
+}
+#else
+static int __devinit cpm_i2c_probe_cpm(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct resource *res;
+	int err;
+	struct i2c_algo_cpm_data *data = &cpm_data;
+	bd_t *binfo = (bd_t *)__res;
+
+	if (data->irq != -1)
+		return -EBUSY;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL)
+		return -EINVAL;
+
+	data->i2c = (cpm_i2c_t *)ioremap(res->start,sizeof(cpm_i2c_t));
+	if (data->i2c == NULL)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (res == NULL) {
+		iounmap((void *)data->i2c);
+		return -EINVAL;
+	}
+
+	data->iip = (iic_t *)ioremap(res->start,sizeof(iic_t));
+	if (data->iip == NULL) {
+		iounmap((void *)data->i2c);
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (res == NULL) {
+		iounmap((void *)data->iip);
+		iounmap((void *)data->i2c);
+		return -EINVAL;
+	}
+
+	data->irq = res->start;
+
+	data->device = dev;
+	data->intfreq = binfo->bi_intfreq;
+
+#ifdef CONFIG_CPM2
+	/* Configure as peripheral... */
+	cpm2_immr->im_ioport.iop_ppard |= (BIT_SCL | BIT_SDA);
+	cpm2_immr->im_ioport.iop_psord |= (BIT_SCL | BIT_SDA);
+
+	/* Inputs... */
+	cpm2_immr->im_ioport.iop_pdird &= ~(BIT_SCL | BIT_SDA);
+#endif
+
+	err = i2c_cpm_add_bus(&cpm_ops);
+	if (err < 0) {
+		data->irq=-1;
+		iounmap((void *)data->iip);
+		iounmap((void *)data->i2c);
+		return err;
+	}
+
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_I2C_CPM_BIT
+static void __devexit cpm_i2c_remove_bitbang(struct device *dev)
+{
+	i2c_bit_del_bus(&cpm_ops);
+}
+#else
+static void __devexit cpm_i2c_remove_cpm(struct device *dev)
+{
+	struct i2c_algo_cpm_data *data = &cpm_data;
+
+	i2c_cpm_del_bus(&cpm_ops);
+
+	iounmap((void *)data->iip);
+	iounmap((void *)data->i2c);
+}
+#endif
+
+static struct device_driver cpm_i2c_driver = {
+	.name	= "fsl-cpm-i2c",
+	.bus	= &platform_bus_type,
+#ifdef CONFIG_I2C_CPM_BIT
+	.probe	= cpm_i2c_probe_bitbang,
+	.remove	= __devexit_p(cpm_i2c_remove_bitbang),
+#else
+	.probe	= cpm_i2c_probe_cpm,
+	.remove	= __devexit_p(cpm_i2c_remove_cpm),
+#endif
+};
+
+int __init cpm_i2c_init(void)
+{
+	printk(KERN_INFO "%s: CPM2 i2c driver\n",cpm_i2c_driver.name);
+
+	return driver_register(&cpm_i2c_driver);
+}
+
+void __exit cpm_i2c_exit(void)
+{
+	driver_unregister(&cpm_i2c_driver);
+}
+
+MODULE_LICENSE("GPL");
+
+MODULE_AUTHOR("Jason McMullan <jason.mcmullan@timesys.com>");
+MODULE_DESCRIPTION("I2C-Bus (on CPM) adapter routines for MPC8xx and MPC85xx boards");
+
+module_init(cpm_i2c_init);
+module_exit(cpm_i2c_exit);

--- /dev/null
+++ linux/include/linux/i2c-algo-cpm.h
@@ -0,0 +1,64 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-algo-mpc.h i2c driver algorithms for MPC CPMs			     */
+/* ------------------------------------------------------------------------- */
+
+/* $Id$ */
+
+#ifndef I2C_ALGO_MPC_H
+#define I2C_ALGO_MPC_H 1
+
+#include <linux/i2c.h>
+
+#ifdef CONFIG_85xx
+#include <asm/mpc85xx.h>
+#include <asm/cpm2.h>
+#include <asm/immap_85xx.h>
+
+typedef i2c_cpm2_t cpm_i2c_t;
+typedef iic_t cpm_iic_t;
+
+#elif defined(CONFIG_8xx)
+#include <asm/mpc8xx.h>
+#include <asm/commproc.h>
+
+typedef i2c8xx_t cpm_i2c_t;
+typedef iic_t cpm_iic_t;
+#endif
+
+#define I2MOD_EN	0x01
+#define I2MOD_PDIV_MASK	0x06
+#define   I2MOD_PDIV_4	0x06
+#define   I2MOD_PDIV_8	0x04
+#define   I2MOD_PDIV_16	0x02
+#define   I2MOD_PDIV_32	0x00
+#define I2MOD_FLT	0x08
+#define I2MOD_GCD	0x10
+#define I2MOD_REVD	0x20
+
+#define I2COM_MS	0x01
+#define I2COM_STR	0x80
+
+#define I2CER_MASK	0x17
+#define I2CER_TXE	0x10
+#define I2CER_BSY	0x04
+#define I2CER_TXB	0x02
+#define I2CER_RXB	0x01
+
+struct i2c_algo_cpm_data {
+	struct device		*device;
+        dma_addr_t		dp_offset;
+        int 			reloc;
+        volatile cpm_i2c_t	*i2c;
+        volatile cpm_iic_t	*iip;
+	int			irq;
+	int			intfreq;
+        uint8_t			*temp;
+
+	wait_queue_head_t	wait;
+	int			status;
+};
+
+int i2c_cpm_add_bus(struct i2c_adapter *);
+int i2c_cpm_del_bus(struct i2c_adapter *);
+
+#endif /* I2C_ALGO_CPM_H */

--- linux-orig/include/linux/i2c-id.h
+++ linux/include/linux/i2c-id.h
@@ -201,6 +201,7 @@
 #define I2C_ALGO_SIBYTE 0x150000	/* Broadcom SiByte SOCs		*/
 #define I2C_ALGO_SGI	0x160000        /* SGI algorithm                */
 #define I2C_ALGO_AU1550	0x170000        /* Au1550 PSC algorithm		*/
+#define I2C_ALGO_CPM2	0x180000	/* MPC8xxx and MPC8xx CPM I2C */
 
 #define I2C_ALGO_EXP	0x800000	/* experimental			*/
 
@@ -253,6 +254,9 @@
 /* --- ACPI Embedded controller algorithms                              */
 #define I2C_HW_ACPI_EC          0x00
 
+/* --- Motorola MPC CPM2 I2C adapters -- */
+#define I2C_HW_CPM2	0x00
+
 /* --- MPC824x PowerPC adapters						*/
 #define I2C_HW_MPC824X 0x00	/* Motorola 8240 / 8245                 */
 

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* [PATCH] MPC85xx CDS - Time Of Day, Cache settings, CPM IRQs
From: Jason McMullan @ 2005-03-22 20:47 UTC (permalink / raw)
  To: linuxppc-embedded


[-- Attachment #1.1: Type: text/plain, Size: 223 bytes --]


Some minor fixes for:

	MPC85xx CDS Time of Day Clock

		    /proc/cpuinfo shows cache settings

		    CPM IRQs are allocated more sanely.

-- 
Jason McMullan <jason.mcmullan@timesys.com>
TimeSys Corporation


[-- Attachment #1.2: board-ppc-mpc85xx-cds.patch --]
[-- Type: text/x-patch, Size: 7872 bytes --]

#### Auto-generated patch ####
Date:        Tue, 22 Mar 2005 15:44:01 -0500
Maintainer:  Jason McMullan <jmcmullan@timesys.com>
Summary:     Freescale MPC85xx CDS series eval boards
###############################

--- linux-orig/arch/ppc/platforms/85xx/Kconfig
+++ linux/arch/ppc/platforms/85xx/Kconfig
@@ -22,9 +22,10 @@
 	  This option enables support for the MPC 8540 ADS evaluation board.
 
 config MPC8555_CDS
-	bool "Freescale MPC8555 CDS"
+	bool "Freescale MPC8555/MPC8541 CDS"
 	help
-	  This option enablese support for the MPC8555 CDS evaluation board.
+	  This option enables support for the MPC8555/MPC8541 CDS 
+          evaluation boards.
 
 config MPC8560_ADS
 	bool "Freescale MPC8560 ADS"
--- linux-orig/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
+++ linux/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
@@ -39,6 +39,7 @@
 #include <asm/page.h>
 #include <asm/atomic.h>
 #include <asm/time.h>
+#include <asm/todc.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
 #include <asm/prom.h>
@@ -63,6 +64,10 @@
 unsigned long isa_mem_base = 0;
 #endif
 
+#ifdef CONFIG_CPM2
+extern void cpm2_reset(void);
+#endif
+
 extern unsigned long total_memory;      /* in mm/init */
 
 unsigned char __res[sizeof (bd_t)];
@@ -158,31 +163,27 @@
         /* Display the amount of memory */
         seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
 
+	/* Display the cache settings */
+	seq_printf(m, "L1 D-cache\t: %s\n",(mfspr(SPRN_L1CSR0)&1) ? "on" : "off");
+	seq_printf(m, "L1 I-cache\t: %s\n",(mfspr(SPRN_L1CSR1)&1) ? "on" : "off");
+	{
+		struct ccsr_l2cache *l2cache;
+		l2cache = ioremap(CCSRBAR+0x20000, sizeof(struct ccsr_l2cache));
+
+		seq_printf(m, "L2 cache\t: %s\n",(l2cache->l2ctl & 0x80000000) ? "on" : "off");
+		iounmap(l2cache);
+	}
+	seq_printf(m, "BPU cache\t: %s\n",(mfspr(SPRN_BUCSR)&1) ? "on" : "off");
+
         return 0;
 }
 
-#ifdef CONFIG_CPM2
-static void cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs)
-{
-	while((irq = cpm2_get_irq(regs)) >= 0)
-		__do_IRQ(irq, regs);
-}
-
-static struct irqaction cpm2_irqaction = {
-	.handler = cpm2_cascade,
-	.flags = SA_INTERRUPT,
-	.mask = CPU_MASK_NONE,
-	.name = "cpm2_cascade",
-};
-#endif /* CONFIG_CPM2 */
-
 void __init
 mpc85xx_cds_init_IRQ(void)
 {
 	bd_t *binfo = (bd_t *) __res;
 #ifdef CONFIG_CPM2
 	volatile cpm2_map_t *immap = cpm2_immr;
-	int i;
 #endif
 
         /* Determine the Physical Address of the OpenPIC regs */
@@ -202,12 +203,7 @@
         openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET);
 
 #ifdef CONFIG_CPM2
-	/* disable all CPM interupts */
-	immap->im_intctl.ic_simrh = 0x0;
-	immap->im_intctl.ic_simrl = 0x0;
-
-	for (i = CPM_IRQ_OFFSET; i < (NR_CPM_INTS + CPM_IRQ_OFFSET); i++)
-		irq_desc[i].handler = &cpm2_pic;
+	cpm2_init_IRQ();
 
 	/* Initialize the default interrupt mapping priorities,
 	 * in case the boot rom changed something on us.
@@ -216,7 +212,7 @@
 	immap->im_intctl.ic_scprrh = 0x05309770;
 	immap->im_intctl.ic_scprrl = 0x05309770;
 
-	setup_irq(MPC85xx_IRQ_CPM, &cpm2_irqaction);
+	openpic_hookup_cascade(MPC85xx_IRQ_CPM, "CPM Cascade", cpm2_get_irq);
 #endif
 
         return;
@@ -303,6 +299,8 @@
 }
 #endif /* CONFIG_PCI */
 
+TODC_ALLOC();
+
 /* ************************************************************************
  *
  * Setup the architecture
@@ -328,6 +326,13 @@
 	cds_pci_slot = ((cadmus[CM_CSR] >> 6) & 0x3) + 1;
 	printk("CDS Version = %x in PCI slot %d\n", cadmus[CM_VER], cds_pci_slot);
 
+	/* Setup TODC access */
+	TODC_INIT(TODC_TYPE_DS1743,
+			0,
+			0,
+			ioremap(CDS_RTC_ADDR, CDS_RTC_SIZE),
+			8);
+
         /* Set loops_per_jiffy to a half-way reasonable value,
            for use until calibrate_delay gets called. */
         loops_per_jiffy = freq / HZ;
@@ -364,7 +369,6 @@
 	pdata->phy_reg_addr += binfo->bi_immr_base;
 	memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
 
-
 #ifdef CONFIG_BLK_DEV_INITRD
         if (initrd_start)
                 ROOT_DEV = Root_RAM0;
@@ -452,11 +456,15 @@
 
         ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory;
 
-        ppc_md.time_init = NULL;
-        ppc_md.set_rtc_time = NULL;
-        ppc_md.get_rtc_time = NULL;
         ppc_md.calibrate_decr = mpc85xx_calibrate_decr;
 
+        ppc_md.time_init = todc_time_init;
+        ppc_md.set_rtc_time = todc_set_rtc_time;
+        ppc_md.get_rtc_time = todc_get_rtc_time;
+
+	ppc_md.nvram_read_val = todc_direct_read_val;
+	ppc_md.nvram_write_val = todc_direct_write_val;
+
 #if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
         ppc_md.progress = gen550_progress;
 #endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */
--- linux-orig/arch/ppc/platforms/85xx/mpc85xx_cds_common.h
+++ linux/arch/ppc/platforms/85xx/mpc85xx_cds_common.h
@@ -33,6 +33,10 @@
 #define CM_CSR	(1)
 #define CM_RST	(2)
 
+/* CDS NVRAM/RTC */
+#define CDS_RTC_ADDR	(0xf8000000)
+#define CDS_RTC_SIZE	(8 * 1024)
+
 /* PCI config */
 #define PCI1_CFG_ADDR_OFFSET	(0x8000)
 #define PCI1_CFG_DATA_OFFSET	(0x8004)
--- linux-orig/arch/ppc/syslib/Makefile
+++ linux/arch/ppc/syslib/Makefile
@@ -98,5 +98,6 @@
 					ppc_sys.o
 ifeq ($(CONFIG_85xx),y)
 obj-$(CONFIG_PCI)		+= indirect_pci.o pci_auto.o
+obj-$(CONFIG_MPC8555_CDS)	+= todc_time.o
 endif
 obj-$(CONFIG_PPC_MPC52xx)	+= mpc52xx_setup.o mpc52xx_pic.o
--- linux-orig/include/asm-ppc/immap_85xx.h
+++ linux/include/asm-ppc/immap_85xx.h
@@ -122,5 +122,49 @@
 	char	res13[61916];
 } ccsr_guts_t;
 
+/* L2 Cache Registers(0x2_0000-0x2_1000) */
+
+typedef struct ccsr_l2cache {
+	uint32_t	l2ctl;		/* 0x.0000 - L2 configuration register 0 */
+	uint8_t		res1[12];
+	uint32_t	l2cewar0;	/* 0x.0010 - L2 cache external write address register 0 */
+	uint8_t		res2[4];
+	uint32_t	l2cewcr0;	/* 0x.0018 - L2 cache external write control register 0 */
+	uint8_t		res3[4];
+	uint32_t	l2cewar1;	/* 0x.0020 - L2 cache external write address register 1 */
+	uint8_t		res4[4];
+	uint32_t	l2cewcr1;	/* 0x.0028 - L2 cache external write control register 1 */
+	uint8_t		res5[4];
+	uint32_t	l2cewar2;	/* 0x.0030 - L2 cache external write address register 2 */
+	uint8_t		res6[4];
+	uint32_t	l2cewcr2;	/* 0x.0038 - L2 cache external write control register 2 */
+	uint8_t		res7[4];
+	uint32_t	l2cewar3;	/* 0x.0040 - L2 cache external write address register 3 */
+	uint8_t		res8[4];
+	uint32_t	l2cewcr3;	/* 0x.0048 - L2 cache external write control register 3 */
+	uint8_t		res9[180];
+	uint32_t	l2srbar0;	/* 0x.0100 - L2 memory-mapped SRAM base address register 0 */
+	uint8_t		res10[4];
+	uint32_t	l2srbar1;	/* 0x.0108 - L2 memory-mapped SRAM base address register 1 */
+	uint8_t		res11[3316];
+	uint32_t	l2errinjhi;	/* 0x.0e00 - L2 error injection mask high register */
+	uint32_t	l2errinjlo;	/* 0x.0e04 - L2 error injection mask low register */
+	uint32_t	l2errinjctl;	/* 0x.0e08 - L2 error injection tag/ECC control register */
+	uint8_t		res12[20];
+	uint32_t	l2captdatahi;	/* 0x.0e20 - L2 error data high capture register */
+	uint32_t	l2captdatalo;	/* 0x.0e24 - L2 error data low capture register */
+	uint32_t	l2captecc;	/* 0x.0e28 - L2 error ECC capture register */
+	uint8_t		res13[20];
+	uint32_t	l2errdet;	/* 0x.0e40 - L2 error detect register */
+	uint32_t	l2errdis;	/* 0x.0e44 - L2 error disable register */
+	uint32_t	l2errinten;	/* 0x.0e48 - L2 error interrupt enable register */
+	uint32_t	l2errattr;	/* 0x.0e4c - L2 error attributes capture register */
+	uint32_t	l2erraddr;	/* 0x.0e50 - L2 error address capture register */
+	uint8_t		res14[4];
+	uint32_t	l2errctl;	/* 0x.0e58 - L2 error control register */
+	uint8_t		res15[420];
+} ccsr_l2cache_t;
+
+
 #endif /* __ASM_IMMAP_85XX_H__ */
 #endif /* __KERNEL__ */

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox