coldfire: R.I.P.

The target still uses 2.6.38. The support of that
kernel version has been removed ~9 months ago.

Signed-off-by: Gabor Juhos <juhosg@openwrt.org>

SVN-Revision: 35489
This commit is contained in:
Gabor Juhos 2013-02-04 15:23:10 +00:00
parent c41002971a
commit b97aee1ee8
59 changed files with 0 additions and 91649 deletions

View file

@ -1,23 +0,0 @@
#
# Copyright (C) 2009-2012 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
ARCH:=m68k
BOARD:=coldfire
BOARDNAME:=Freescale Coldfire v4e
FEATURES:=squashfs broken
MAINTAINER:=Imre Kaloz <kaloz@openwrt.org>
LINUX_VERSION:=2.6.38.8
include $(INCLUDE_DIR)/target.mk
define Target/Description
Build firmware images for ColdFire v4e boards
endef
$(eval $(call BuildTarget))

View file

@ -1,112 +0,0 @@
# CONFIG_8139TOO is not set
CONFIG_ADVANCED=y
# CONFIG_AMIGA is not set
# CONFIG_APOLLO is not set
# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
CONFIG_ARCH_SUPPORTS_AOUT=y
# CONFIG_ATARI is not set
# CONFIG_BINFMT_AOUT is not set
CONFIG_BITREVERSE=y
# CONFIG_BOOTPARAM is not set
CONFIG_BOUNCE=y
CONFIG_BROADCOM5222_PHY=y
CONFIG_CFDMA=y
CONFIG_CFV4E=y
CONFIG_CLASSIC_RCU=y
CONFIG_COLDFIRE=y
# CONFIG_COLDFIRE_EDMA is not set
# CONFIG_COLDFIRE_WATCHDOG is not set
CONFIG_DMADEVICES=y
CONFIG_FEC_548x=y
CONFIG_FEC_548x_AUTO_NEGOTIATION=y
CONFIG_FEC_548x_ENABLE_FEC2=y
CONFIG_FEC_548x_SHARED_PHY=y
CONFIG_FPU=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_IOMAP=y
# CONFIG_GENERIC_TIME is not set
# CONFIG_GEN_RTC is not set
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAVE_IDE=y
# CONFIG_HAVE_KPROBES is not set
# CONFIG_HAVE_KRETPROBES is not set
# CONFIG_HAVE_OPROFILE is not set
# CONFIG_HP300 is not set
CONFIG_HW_RANDOM=y
# CONFIG_IDE is not set
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_LEDS_ALIX is not set
# CONFIG_M5441X is not set
# CONFIG_M5445X is not set
# CONFIG_M5474LITE is not set
# CONFIG_M5475AFE is not set
# CONFIG_M5475BFE is not set
# CONFIG_M5475CFE is not set
# CONFIG_M5475DFE is not set
# CONFIG_M5475EFE is not set
# CONFIG_M5475FFE is not set
# CONFIG_M547X is not set
CONFIG_M547X_8X=y
CONFIG_M5484LITE=y
# CONFIG_M5485AFE is not set
# CONFIG_M5485BFE is not set
# CONFIG_M5485CFE is not set
# CONFIG_M5485DFE is not set
# CONFIG_M5485EFE is not set
# CONFIG_M5485FFE is not set
CONFIG_M548X=y
# CONFIG_M68020 is not set
# CONFIG_M68030 is not set
# CONFIG_M68040 is not set
# CONFIG_M68060 is not set
CONFIG_M68K=y
# CONFIG_M68KFPU_EMU is not set
# CONFIG_MAC is not set
CONFIG_MCD_DMA=y
CONFIG_MCFCLK=200000000
CONFIG_MCF_USER_HALT=y
# CONFIG_MEMSTICK is not set
CONFIG_MMU_CFV4E=y
CONFIG_MTD_CFI_ADV_OPTIONS=y
# CONFIG_MTD_CFI_GEOMETRY is not set
CONFIG_MTD_PHYSMAP=y
# CONFIG_NATIONAL8364x_PHY is not set
# CONFIG_NATIONAL8384x_PHY is not set
# CONFIG_NE2K_PCI is not set
CONFIG_NEED_MULTIPLE_NODES=y
# CONFIG_NETDEV_1000 is not set
# CONFIG_NET_VENDOR_3COM is not set
CONFIG_NOR_FLASH_BASE=0xE0000000
# CONFIG_NO_DMA is not set
# CONFIG_NO_IOPORT is not set
CONFIG_PCI=y
# CONFIG_PCIPCWATCHDOG is not set
CONFIG_PCI_LEGACY=y
# CONFIG_PROC_HARDWARE is not set
# CONFIG_Q40 is not set
# CONFIG_R6040 is not set
# CONFIG_RMW_INSNS is not set
# CONFIG_SCSI_DMA is not set
CONFIG_SDRAM_BASE=0x00000000
CONFIG_SDRAM_SIZE=0x04000000
# CONFIG_SERIAL_8250 is not set
CONFIG_SERIAL_COLDFIRE=y
# CONFIG_SERIAL_COLDFIRE_EDMA is not set
# CONFIG_SERIAL_COLDFIRE_IRDA is not set
# CONFIG_SERIAL_CONSOLE is not set
CONFIG_SERIAL_MCF=y
CONFIG_SERIAL_MCF_BAUDRATE=115200
CONFIG_SERIAL_MCF_CONSOLE=y
# CONFIG_SERIAL_PCH_UART is not set
CONFIG_SINGLE_MEMORY_CHUNK=y
CONFIG_SLABINFO=y
# CONFIG_SUN3 is not set
# CONFIG_SUN3X is not set
CONFIG_TIME_LOW_RES=y
CONFIG_UID16=y
# CONFIG_VDSO is not set
# CONFIG_VGASTATE is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_VME is not set

View file

@ -1,34 +0,0 @@
#
# Copyright (C) 2009-2010 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/image.mk
JFFS2_BLOCKSIZE=128k
define Image/Prepare
endef
define Image/BuildKernel
$(TARGET_CROSS)objcopy -O binary -R .bss -R .note -R .comment \
-R .note.gnu.build-id -S $(LINUX_DIR)/vmlinux $(KDIR)/vmlinux.bin
mkimage -A m68k -O linux -T kernel -a 0x00020000 -e 0x00020000 \
-C none -n 'M68K OpenWrt Linux-$(LINUX_VERSION)' \
-d $(KDIR)/vmlinux.bin $(BIN_DIR)/$(IMG_PREFIX)-uImage
endef
define Image/Build
$(call Image/Build/$(1),$(1))
endef
define Image/Build/jffs2-128k
endef
define Image/Build/squashfs
$(call prepare_generic_squashfs,$(KDIR)/root.squashfs)
endef
$(eval $(call BuildImage))

View file

@ -1,200 +0,0 @@
From 5c37079957c5e5555aa8284a879f8cc44fa8eb25 Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:39 +0800
Subject: [PATCH 05/52] Add serial driver and irda driver support for MCF5445x and MCF547x/MCF548x
Add common serial driver for MCF5445x and MCF547x/MCF548x.
Also add irda support for MCF547x/MCF548x.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
drivers/tty/serial/Kconfig | 20 ++++++++++
drivers/tty/serial/mcf.c | 87 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 107 insertions(+), 0 deletions(-)
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1027,6 +1027,26 @@ config SERIAL_68328_RTS_CTS
bool "Support RTS/CTS on 68328 serial port"
depends on SERIAL_68328
+config SERIAL_COLDFIRE_IRDA
+ bool "ColdFire IRDA support"
+ depends on SERIAL_MCF
+ help
+ This driver supports IrDA on the ColdFire platform,
+ such as MCF547x and MCF548x.
+
+ Say Y here if you want to use IrDA 1.1 SIR mode.
+
+config SERIAL_COLDFIRE_EDMA
+ bool "ColdFire serial EDMA support"
+ depends on SERIAL_MCF
+ default n
+ help
+ Enables Enhanced Direct Memory Access(eDMA) in the Coldfire
+ serial driver.
+
+ Say Y here if you want to use DMA processing of transmit
+ and receive data for the serial driver.
+
config SERIAL_MCF
bool "Coldfire serial support"
depends on COLDFIRE
--- a/drivers/tty/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
@@ -4,6 +4,10 @@
* mcf.c -- Freescale ColdFire UART driver
*
* (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
+ * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Jason Jin Jason.Jin@freescale.com
+ * Shrek Wu B16972@freescale.com
+ * Chengju Cai b22600@freescale.com
*
* 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
@@ -23,9 +27,11 @@
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/io.h>
+#include <linux/delay.h>
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
#include <asm/mcfuart.h>
+#include <asm/m5485psc.h>
#include <asm/nettel.h>
/****************************************************************************/
@@ -46,6 +52,10 @@
#define mcf_setppdtr(p, v) do { } while (0)
#endif
+#ifdef CONFIG_SERIAL_COLDFIRE_IRDA
+#define SERIAL_IRDA_LINE (2)
+#endif
+
/****************************************************************************/
/*
@@ -101,6 +111,15 @@ static void mcf_start_tx(struct uart_por
{
struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+#ifdef CONFIG_SERIAL_COLDFIRE_IRDA
+ if (port->line == SERIAL_IRDA_LINE) {
+ /* Disable IRDA receiver*/
+ writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
+ writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
+
+ writeb(MCFUART_UCR_TXENABLE, port->membase + MCFUART_UCR);
+ }
+#endif
pp->imr |= MCFUART_UIR_TXREADY;
writeb(pp->imr, port->membase + MCFUART_UIMR);
}
@@ -154,6 +173,30 @@ static int mcf_startup(struct uart_port
spin_lock_irqsave(&port->lock, flags);
+#ifdef CONFIG_SERIAL_COLDFIRE_IRDA
+ if (port->line == SERIAL_IRDA_LINE) {
+ /* Put PSC in IrDA mode */
+ MCF_PSC_SICR(port->line) = MCF_PSC_SICR_SIM_SIR;
+
+ /* Set pulse width to 1.6 uS */
+ MCF_PSC_IRSDR(port->line) = (uint8_t)
+ (16 * (CONFIG_MCFCLK / 10000000));
+ MCF_PSC_IRCR1(port->line) = MCF_PSC_IRCR1_SPUL;
+ MCF_PSC_IRCR2(port->line) = 0;
+
+ /* Enable RTS to send */
+ MCF_PSC_OPSET(port->line) = MCF_PSC_OPSET_RTS;
+
+ /* Setup FIFO Alarms */
+ MCF_PSC_RFAR(port->line) = MCF_PSC_RFAR_ALARM(248);
+ MCF_PSC_TFAR(port->line) = MCF_PSC_TFAR_ALARM(248);
+
+ MCF_PSC_RFCR(port->line) = MCF_PSC_RFCR_FRMEN
+ | MCF_PSC_RFCR_GR(4);
+ MCF_PSC_TFCR(port->line) = MCF_PSC_TFCR_FRMEN
+ | MCF_PSC_RFCR_GR(4);
+ }
+#endif
/* Reset UART, get it into known state... */
writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
@@ -177,7 +220,17 @@ static void mcf_shutdown(struct uart_por
{
struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
unsigned long flags;
+#ifdef CONFIG_SERIAL_COLDFIRE_IRDA
+ unsigned long delay_counter = 0;
+#endif
+#ifdef CONFIG_SERIAL_COLDFIRE_IRDA
+ while (!((readb(port->membase + MCFUART_USR)) & MCFUART_USR_TXEMPTY)) {
+ if (delay_counter++ > 25000)
+ break;
+ udelay(10);
+ }
+#endif
spin_lock_irqsave(&port->lock, flags);
/* Disable all interrupts now */
@@ -202,7 +255,14 @@ static void mcf_set_termios(struct uart_
unsigned int baudfr;
#endif
unsigned char mr1, mr2;
+#ifdef CONFIG_SERIAL_COLDFIRE_IRDA
+ int i = 0; /* hush GCC */
+#endif
+#ifdef CONFIG_SERIAL_COLDFIRE_IRDA
+ while (i++ < 35000)
+ udelay(1);
+#endif
baud = uart_get_baud_rate(port, termios, old, 0, 230400);
#if defined(CONFIG_M5272)
baudclk = (MCF_BUSCLK / baud) / 32;
@@ -331,6 +391,23 @@ static void mcf_tx_chars(struct mcf_uart
while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) {
if (xmit->head == xmit->tail)
break;
+#ifdef CONFIG_SERIAL_COLDFIRE_IRDA
+ if (port->line == SERIAL_IRDA_LINE) {
+ while (!((readb(port->membase + MCFUART_USR))\
+ & MCFUART_USR_TXEMPTY))
+ ;
+ /* delay for settle */
+#if defined(CONFIG_M548X)
+ udelay(1);
+#elif defined(CONFIG_M547X)
+ udelay(2);
+#else
+ int i = 0;
+ while (i++ < 25000)
+ udelay(1);
+#endif
+ }
+#endif
writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
port->icount.tx++;
@@ -340,6 +417,16 @@ static void mcf_tx_chars(struct mcf_uart
uart_write_wakeup(port);
if (xmit->head == xmit->tail) {
+#ifdef CONFIG_SERIAL_COLDFIRE_IRDA
+ if (port->line == SERIAL_IRDA_LINE) {
+ /* Enable receiver for IRDA */
+ writeb(MCFUART_UCR_CMDRESETRX,\
+ port->membase + MCFUART_UCR);
+ /* reset RX */
+ writeb(MCFUART_UCR_TXENABLE | MCFUART_UCR_RXENABLE,\
+ port->membase + MCFUART_UCR);
+ }
+#endif
pp->imr &= ~MCFUART_UIR_TXREADY;
writeb(pp->imr, port->membase + MCFUART_UIMR);
}

View file

@ -1,198 +0,0 @@
From f54ba59d355f59e4c01b5b9c7dbc2d27b47302d2 Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:41 +0800
Subject: [PATCH 10/52] Add SRAM char device driver support for MCF5445x
Created "/dev/sram" device file and implemented the sram mmap() operation to
provide interface for userspace access.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
drivers/char/Kconfig | 11 ++++
drivers/char/Makefile | 2 +
drivers/char/sram.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 164 insertions(+), 0 deletions(-)
create mode 100644 drivers/char/sram.c
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -97,6 +97,17 @@ config DEVKMEM
kind of kernel debugging operations.
When in doubt, say "N".
+config DEVSRAM
+ tristate "/dev/sram virtual device support"
+ depends on M5445X
+ default m
+ help
+ Say Y here if you want to suppot the SRAM char device. When in
+ doubt, say "N".
+
+ It implements mmap system call to provide interface for
+ user space access.
+
config BFIN_JTAG_COMM
tristate "Blackfin JTAG Communication"
depends on BLACKFIN
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -87,3 +87,5 @@ obj-$(CONFIG_RAMOOPS) += ramoops.o
obj-$(CONFIG_JS_RTC) += js-rtc.o
js-rtc-y = rtc.o
+
+obj-$(CONFIG_DEVSRAM) += sram.o
--- /dev/null
+++ b/drivers/char/sram.c
@@ -0,0 +1,151 @@
+/*
+ * linux/drivers/char/sram.c
+ *
+ * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Author: Lanttor.Guo@freescale.com
+ *
+ * SRAM char device driver, implements mmap() system call to provide
+ * interface for user space access.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/kdev_t.h>
+#include <asm/page.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+
+MODULE_LICENSE("GPL");
+
+static struct class *sram_class;
+static int sram_major;
+static int sram_minor;
+static struct cdev sram_cdev;
+
+/*
+ * Set up the cdev structure for sram.
+ */
+static void sram_setup_cdev(struct cdev *dev, int minor,
+ const struct file_operations *fops)
+{
+ int err, devno = MKDEV(sram_major, minor);
+
+ cdev_init(dev, fops);
+ dev->owner = THIS_MODULE;
+ dev->ops = fops;
+ err = cdev_add(dev, devno, 1);
+ /* Fail gracefully if need be */
+ if (err)
+ printk(KERN_NOTICE "Error %d adding sram%d", err, minor);
+}
+
+static int sram_open(struct inode *inode, struct file *filp)
+{
+ filp->f_mapping->backing_dev_info = &directly_mappable_cdev_bdi;
+ return 0;
+}
+
+static int sram_release(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+void sram_vma_open(struct vm_area_struct *vma)
+{
+ printk(KERN_DEBUG "Sram VMA open, virt %lx, phys %lx\n",
+ vma->vm_start,
+ CONFIG_SRAM_BASE + (vma->vm_pgoff << PAGE_SHIFT));
+}
+
+void sram_vma_close(struct vm_area_struct *vma)
+{
+ printk(KERN_DEBUG "Sram VMA close.\n");
+}
+
+
+static struct vm_operations_struct sram_remap_vm_ops = {
+ .open = sram_vma_open,
+ .close = sram_vma_close,
+};
+
+static int sram_remap_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ size_t size = vma->vm_end - vma->vm_start;
+
+ if (PAGE_ALIGN(size) > CONFIG_SRAM_SIZE) {
+ printk(KERN_ERR "required length exceed the size "
+ "of physical sram (%x)\n", CONFIG_SRAM_SIZE);
+ return -EAGAIN;
+ }
+
+ if ((CONFIG_SRAM_BASE + (vma->vm_pgoff << PAGE_SHIFT) + size)
+ > (CONFIG_SRAM_BASE + CONFIG_SRAM_SIZE)) {
+ printk(KERN_ERR "required sram range exceed the size "
+ "of phisical sram\n");
+ return -EAGAIN;
+ }
+
+ if (remap_pfn_range(vma, vma->vm_start,
+ (CONFIG_SRAM_BASE >> PAGE_SHIFT) + vma->vm_pgoff,
+ size,
+ vma->vm_page_prot)) {
+ printk(KERN_ERR "remap_pfn_range faile at %s()\n", __func__);
+ return -EAGAIN;
+ }
+
+ vma->vm_ops = &sram_remap_vm_ops;
+ return 0;
+}
+
+static const struct file_operations sram_ops = {
+ .owner = THIS_MODULE,
+ .open = sram_open,
+ .release = sram_release,
+ .mmap = sram_remap_mmap,
+};
+
+static int __init sram_chrdev_init(void)
+{
+ int minor_devs = 1;
+ int result;
+ dev_t dev = 0;
+ sram_minor = 0;
+
+ result = alloc_chrdev_region(&dev, sram_minor, minor_devs, "sram");
+ sram_major = MAJOR(dev);
+ if (result < 0) {
+ printk(KERN_WARNING "sram: can't get major %d\n", sram_major);
+ return result;
+ }
+
+ sram_setup_cdev(&sram_cdev, 0, &sram_ops);
+
+ sram_class = class_create(THIS_MODULE, "sram");
+ device_create(sram_class, NULL, MKDEV(sram_major, sram_minor),
+ NULL, "sram");
+
+ return 0;
+}
+
+static void sram_chrdev_cleanup(void)
+{
+ cdev_del(&sram_cdev);
+ device_destroy(sram_class, MKDEV(sram_major, sram_minor));
+ class_destroy(sram_class);
+ unregister_chrdev_region(MKDEV(sram_major, 0), 1);
+}
+
+module_init(sram_chrdev_init);
+module_exit(sram_chrdev_cleanup);

View file

@ -1,497 +0,0 @@
From 1ba9968246337836bf0acdbf7733a628da5c5e42 Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:42 +0800
Subject: [PATCH 12/52] Add vDSO support for Coldfire platform
This patch adds vDSO support for Coldfire platform.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
arch/m68k/coldfire/common/entry.S | 36 ++++++++++
arch/m68k/coldfire/vdso/Makefile | 46 +++++++++++++
arch/m68k/coldfire/vdso/vdso-bin.S | 14 ++++
arch/m68k/coldfire/vdso/vdso-lib.S | 57 ++++++++++++++++
arch/m68k/coldfire/vdso/vdso-note.S | 27 ++++++++
arch/m68k/coldfire/vdso/vdso.c | 124 +++++++++++++++++++++++++++++++++++
arch/m68k/coldfire/vdso/vdso.lds.S | 89 +++++++++++++++++++++++++
arch/m68k/include/asm/auxvec.h | 9 +++
arch/m68k/mm/init.c | 3 +
9 files changed, 405 insertions(+), 0 deletions(-)
create mode 100644 arch/m68k/coldfire/vdso/Makefile
create mode 100644 arch/m68k/coldfire/vdso/vdso-bin.S
create mode 100644 arch/m68k/coldfire/vdso/vdso-lib.S
create mode 100644 arch/m68k/coldfire/vdso/vdso-note.S
create mode 100644 arch/m68k/coldfire/vdso/vdso.c
create mode 100644 arch/m68k/coldfire/vdso/vdso.lds.S
--- a/arch/m68k/coldfire/common/entry.S
+++ b/arch/m68k/coldfire/common/entry.S
@@ -69,6 +69,9 @@ ENTRY(buserr)
movew #0x2700,%sr /* lock interrupts */
#endif
SAVE_ALL_INT
+#ifdef CONFIG_VDSO
+ jsr check_vdso_atomic_cmpxchg_32
+#endif
#ifdef CONFIG_COLDFIRE_FOO
movew PT_0FF_SR(%sp),%d3 /* get original %sr */
oril #0x2000,%d3 /* set supervisor mode in it */
@@ -82,6 +85,9 @@ ENTRY(buserr)
ENTRY(trap)
SAVE_ALL_INT
+#ifdef CONFIG_VDSO
+ jsr check_vdso_atomic_cmpxchg_32
+#endif
GET_CURRENT(%d0)
movel %sp,%sp@- /* stack frame pointer argument */
jsr trap_c
@@ -213,6 +219,9 @@ do_delayed_trace:
*/
ENTRY(inthandler)
SAVE_ALL_INT
+#ifdef CONFIG_VDSO
+ jsr check_vdso_atomic_cmpxchg_32
+#endif
GET_CURRENT(%d0)
movel %curptr@(TASK_INFO+TINFO_PREEMPT),%d0
addil #0x10000,%d0
@@ -398,8 +407,35 @@ resume:
movew %a1@(TASK_THREAD+THREAD_SR),%d0
movew %d0,%sr
+#ifdef CONFIG_VDSO
+ /* save thread pointer */
+ lea _vdso_tp,%a0
+ movel (%a0),%a0
+ movel %a1@(TASK_INFO+TINFO_TP_VALUE),(%a0)
+#endif
rts
+#ifdef CONFIG_VDSO
+/* if interrupted PC is between 0x5fffe40c to 0x5ffffe412 */
+/* then set PC back to 0x5fffe40c (start addr of __kernel_atomic_cmpxchg_32) */
+/* note: these absolute addresses depend on vdso-lib.S and vdso.lds.S */
+ENTRY(check_vdso_atomic_cmpxchg_32)
+ movel %sp@(PT_OFF_PC),%d0
+ cmpil #0x5fffe414,%d0 /* __kernel_atomic_cmpxchg_32: line 4 */
+ ble label1
+ cmpil #0x5fffe412,%d0 /* __kernel_atomic_cmpxchg_32: line 3 */
+ beql label0
+ cmpil #0x5fffe40e,%d0 /* __kernel_atomic_cmpxchg_32: line 2 */
+ beql label0
+ jra label1
+label0:
+ /* __kernel_atomic_cmpxchg_32: line 1 */
+ movel #0x5fffe40c,%d0
+ movel %d0,%sp@(PT_OFF_PC)
+label1:
+ rts
+#endif
+
.data
ALIGN
sys_call_table:
--- /dev/null
+++ b/arch/m68k/coldfire/vdso/Makefile
@@ -0,0 +1,46 @@
+#
+# Makefile for arch/m68k/coldfire/vdso with special rules
+# for building the DSO lib
+#
+# Based on arch/sh/kernel/vsyscall/Makefile
+#
+# Kurt Mahan <kmahan@freescale.com>
+#
+
+obj-y := vdso.o vdso-bin.o
+
+$(obj)/vdso-bin.o: $(obj)/vdso.lds $(obj)/vdso-lib.so
+
+#
+# The DSO Lib
+#
+
+# special linker script for building DSO images
+quiet_cmd_vdso = VDSO $@
+ cmd_vdso = $(LD) -nostdlib --eh-frame-hdr $(SYSCFLAGS_$(@F)) \
+ -T $(obj)/vdso.lds $^ -o $@
+
+vdso-flags = -shared -s -soname=linux-gate.so.1
+
+SYSCFLAGS_vdso-lib.so = $(vdso-flags)
+
+$(obj)/vdso-lib.so: $(obj)/vdso-lib.o $(obj)/vdso-note.o
+ $(call if_changed,vdso)
+
+$(obj)/vdso.lds: $(srctree)/arch/m68k/coldfire/vdso/vdso.lds.S
+ cp $< $@
+
+#
+# Create a special relocatable object that should mirror the
+# symbol table and layout of the linked DSO lib. With ld -R
+# these symbols can be refered to in the kernel code rather
+# than as hand-coded addresses
+#
+# extra-y += vdso-syms.o
+# $(obj)/built-in.o: $(obj)/vdso-syms.o
+# $(obj)/built-in.o: ld_flags += -R (obj)/vdso-syms.o
+
+# SYSCFLAGS_vdso-syms.o = -r
+# $(obj)/vdso-syms.o: $(src)/vdso.lds \
+# $(obj)/vdso-lib.o $(obj)/vdso-note.o FORCE
+# $(call if_changed,vdso)
--- /dev/null
+++ b/arch/m68k/coldfire/vdso/vdso-bin.S
@@ -0,0 +1,14 @@
+/*
+ * Setup vdso lib (.so) as binary image.
+ */
+
+#include <linux/init.h>
+
+__INITDATA
+
+ .globl vdso_bin_start, vdso_bin_end
+vdso_bin_start:
+ .incbin "arch/m68k/coldfire/vdso/vdso-lib.so"
+vdso_bin_end:
+
+__FINIT
--- /dev/null
+++ b/arch/m68k/coldfire/vdso/vdso-lib.S
@@ -0,0 +1,57 @@
+/*
+ * VDSO userspace code
+ *
+ * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Kurt Mahan <kmahan@freescale.com>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/linkage.h>
+#include <asm/unistd.h>
+
+ .text
+/*
+ * Read the thread pointer into A0 (and D0, for compatibility).
+ */
+ENTRY(__kernel_read_tp)
+ .cfi_startproc
+ lea kuser_vdso_tp,%a0
+ movel (%a0), %d0
+ movel %d0,%a0
+ rts
+ .cfi_endproc
+ .size __kernel_read_tp,.-__kernel_read_tp
+
+/*
+ * Atomic compare exchange. Can not clobber any registers
+ * other than conditional codes.
+ */
+ENTRY(__kernel_atomic_cmpxchg_32)
+ .cfi_startproc
+ cmpl (%a0),%d0
+ bne label0
+ movel %d1, (%a0)
+ jmp label1
+label0:
+ movel (%a0),%d0
+label1:
+ rts
+ .cfi_endproc
+ .size __kernel_atomic_cmpxchg_32,.-__kernel_atomic_cmpxchg_32
+
+/*
+ * Atomic memory barrier. Can not clobber any registers
+ * other than condition codes.
+ */
+ENTRY(__kernel_atomic_barrier)
+ .cfi_startproc
+ /* no code needed for uniprocs */
+ rts
+ .cfi_endproc
+ .size __kernel_atomic_barrier,.-__kernel_atomic_barrier
+
+ .previous
--- /dev/null
+++ b/arch/m68k/coldfire/vdso/vdso-note.S
@@ -0,0 +1,27 @@
+/*
+ * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
+ * Here we can supply some information useful to userland.
+ *
+ * Based on arch/sh/kernel/vsyscall/vsyscall-note.S
+ */
+
+#include <linux/uts.h>
+#include <linux/version.h>
+
+#define ASM_ELF_NOTE_BEGIN(name, flags, vendor, type) \
+ .section name, flags; \
+ .balign 4; \
+ .long 1f - 0f; /* name length */ \
+ .long 3f - 2f; /* data length */ \
+ .long type; /* note type */ \
+0: .asciz vendor; /* vendor name */ \
+1: .balign 4; \
+2:
+
+#define ASM_ELF_NOTE_END \
+3: .balign 4; /* pad out section */ \
+ .previous
+
+ ASM_ELF_NOTE_BEGIN(".note.kernel-version", "a", UTS_SYSNAME, 0)
+ .long LINUX_VERSION_CODE
+ ASM_ELF_NOTE_END
--- /dev/null
+++ b/arch/m68k/coldfire/vdso/vdso.c
@@ -0,0 +1,124 @@
+/*
+ * arch/m68k/coldfire/vdso/vdso.c
+ *
+ * Based on arch/sh/kernel/vsyscall/vsyscall.c
+ *
+ * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Kurt Mahan <kmahan@freescale.com>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gfp.h>
+#include <linux/module.h>
+#include <linux/elf.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+
+/* Mapping vDSO at the default address (what would've been returned
+ * if VDSO_MBASE was 0) makes it impossible to extend data segment
+ * (through brk()) for static binaries. The vDSO fits into one page,
+ * so map it just before TASK_UNMAPPED_BASE.
+ */
+#define VDSO_MBASE (TASK_UNMAPPED_BASE - PAGE_SIZE)
+#define VDSO_VAR_OFFSET 4096
+
+unsigned int vdso_enabled = 1;
+EXPORT_SYMBOL_GPL(vdso_enabled);
+
+static struct page *vdso_pages[1];
+
+/* _vdso_var_start: vdso_page_start + offset_4K */
+/* it's used to save key values from kernel */
+void *_vdso_var_start;
+void *_vdso_tp;
+
+extern const char vdso_bin_start, vdso_bin_end;
+
+int __init vdso_init(void)
+{
+ void *vdso_page = (void *)get_zeroed_page(GFP_ATOMIC);
+ vdso_pages[0] = virt_to_page(vdso_page);
+
+ _vdso_var_start = (void *)(vdso_page + VDSO_VAR_OFFSET);
+ _vdso_tp = _vdso_var_start;
+
+ printk(KERN_INFO "** VDSO_INIT\n");
+
+ /* copy dso bin in */
+ memcpy(vdso_page,
+ &vdso_bin_start, &vdso_bin_end - &vdso_bin_start);
+
+ return 0;
+}
+
+/* setup VMA at program startup for the vdso page */
+int arch_setup_additional_pages(struct linux_binprm *bprm,
+ int executable_stack)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long addr;
+ int ret;
+
+ current->mm->context.vdso = 0;
+
+ down_write(&mm->mmap_sem);
+ addr = get_unmapped_area(NULL, VDSO_MBASE, PAGE_SIZE, 0, 0);
+ if (IS_ERR_VALUE(addr)) {
+ ret = addr;
+ goto up_fail;
+ }
+
+ ret = install_special_mapping(mm, addr, PAGE_SIZE,
+ VM_READ | VM_EXEC |
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC |
+ VM_ALWAYSDUMP,
+ vdso_pages);
+
+ if (unlikely(ret))
+ goto up_fail;
+
+ current->mm->context.vdso = (void *)addr;
+
+up_fail:
+#ifdef DEBUG
+ printk(KERN_DEBUG "arch_setup_additional_pages: addr: %lx; ret: %d\n",
+ addr, ret);
+#endif
+
+ up_write(&mm->mmap_sem);
+ return ret;
+}
+
+/*
+ * check vma name
+ */
+const char *arch_vma_name(struct vm_area_struct *vma)
+{
+ if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
+ return "[vdso]";
+
+ return NULL;
+}
+
+struct vm_area_struct *get_gate_vma(struct task_struct *task)
+{
+ return NULL;
+}
+
+int in_gate_area(struct task_struct *task, unsigned long address)
+{
+ return 0;
+}
+
+int in_gate_area_no_task(unsigned long address)
+{
+ return 0;
+}
--- /dev/null
+++ b/arch/m68k/coldfire/vdso/vdso.lds.S
@@ -0,0 +1,89 @@
+/*
+ * Linker script for vdso DSO. The vdso page is an ELF shared
+ * object prelinked to its virtual address, and with only one read-only
+ * segment (that fits in one page). This script controls its layout.
+ *
+ * Based on arch/sh/kernel/vsyscall/vsyscall.lds.S
+ *
+ * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Kurt Mahan <kmahan@freescale.com>
+ *
+ * This 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.
+ */
+
+OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k")
+OUTPUT_ARCH(m68k)
+
+/* The ELF entry point can be used to set the AT_SYSINFO value. */
+ENTRY(__kernel_read_tp);
+ENTRY(__kernel_atomic_cmpxchg_32);
+ENTRY(__kernel_atomic_barrier);
+
+SECTIONS
+{
+ . = 0x5fffe000 + SIZEOF_HEADERS;
+
+ .hash : { *(.hash) } :text
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+
+ /*
+ * This linker script is used both with -r and with -shared.
+ * For the layouts to match, we need to skip more than enough
+ * space for the dynamic symbol table et al. If this amount
+ * is insufficient, ld -shared will barf. Just increase it here.
+ */
+ . = 0x5fffe000 + 0x400;
+
+ .text : { *(.text) } :text
+ .note : { *(.note.*) } :text :note
+ .eh_frame_hdr : { *(.eh_frame_hdr ) } :text :eh_frame_hdr
+ .eh_frame : {
+ KEEP (*(.eh_frame))
+ LONG (0)
+ } :text
+ .dynamic : { *(.dynamic) } :text :dynamic
+ .useless : {
+ *(.got.plt) *(.got)
+ *(.data .data.* .gnu.linkonce.d.*)
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ } :text
+
+ . = 0x5fffe000 + 0x1000;
+ kuser_vdso_tp = .;
+}
+
+/*
+ * We must supply the ELF program headers explicitly to get just one
+ * PT_LOAD segment, and set the flags explicitly to make segments read-only.
+ */
+PHDRS
+{
+ text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
+ dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
+ note PT_NOTE FLAGS(4); /* PF_R */
+ eh_frame_hdr PT_GNU_EH_FRAME;
+}
+
+/*
+ * This controls what symbols we export from the DSO.
+ */
+VERSION
+{
+ LINUX_2.6 {
+ global:
+ __kernel_read_tp;
+ __kernel_atomic_cmpxchg_32;
+ __kernel_atomic_barrier;
+
+ local: *;
+ };
+}
--- a/arch/m68k/include/asm/auxvec.h
+++ b/arch/m68k/include/asm/auxvec.h
@@ -1,4 +1,13 @@
#ifndef __ASMm68k_AUXVEC_H
#define __ASMm68k_AUXVEC_H
+/*
+ * Architecture-neutral AT_ values in 0-17, leave some room
+ * for more of them.
+ */
+
+#ifdef CONFIG_VDSO
+/* Entry point to the vdso page */
+#define AT_SYSINFO_EHDR 33
+#endif
#endif
--- a/arch/m68k/mm/init.c
+++ b/arch/m68k/mm/init.c
@@ -39,6 +39,9 @@
#include <asm/sections.h>
#include <asm/tlb.h>
+#ifdef CONFIG_VDSO
+int vdso_init(void);
+#endif
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);

View file

@ -1,23 +0,0 @@
From f5d90ef1f575d712c9f061dd5e4d48aa34d73bd0 Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:43 +0800
Subject: [PATCH 14/52] Add CFV4E FPU support for MCF547x/MCF548x
Add CFV4E FPU support for MCF547x/MCF548x.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
arch/m68k/include/asm/fpu.h | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
--- a/arch/m68k/include/asm/fpu.h
+++ b/arch/m68k/include/asm/fpu.h
@@ -14,6 +14,8 @@
#define FPSTATESIZE (28)
#elif defined(CONFIG_M68060)
#define FPSTATESIZE (12)
+#elif defined(CONFIG_CFV4E)
+#define FPSTATESIZE (16)
#else
#define FPSTATESIZE (0)
#endif

View file

@ -1,104 +0,0 @@
From a42f35579c21ffdda461031a5d2d210e27eb506a Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:43 +0800
Subject: [PATCH 15/52] Add driver to support ten UART devices on MCF5441x
Test CPU board: UART0(J1), UART4(J3)
Test SER2 board: UART1(J11), UART2(J31)
Signed-off-by: Alison Wang <b18965@freescale.com>
---
drivers/tty/serial/Kconfig | 70 ++++++++++++++++++++++++++++++++++++++++++++
drivers/tty/serial/mcf.c | 2 +-
2 files changed, 71 insertions(+), 1 deletions(-)
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1070,6 +1070,76 @@ config SERIAL_MCF_CONSOLE
help
Enable a ColdFire internal serial port to be the system console.
+config SERIAL_MCF_UART0
+ bool "Coldfire UART0 device support"
+ depends on SERIAL_MCF && M5441X
+ default y
+ help
+ Enable ColdFire UART0 device configuration
+
+config SERIAL_MCF_UART1
+ bool "Coldfire UART1 device support"
+ depends on SERIAL_MCF && M5441X
+ default n
+ help
+ Enable ColdFire UART1 device configuration
+
+config SERIAL_MCF_UART2
+ bool "Coldfire UART2 device support"
+ depends on SERIAL_MCF && M5441X
+ default n
+ help
+ Enable ColdFire UART2 device configuration
+
+config SERIAL_MCF_UART3
+ bool "Coldfire UART3 device support"
+ depends on SERIAL_MCF && M5441X
+ default n
+ help
+ Enable ColdFire UART3 device configuration
+
+config SERIAL_MCF_UART4
+ bool "Coldfire UART4 device support"
+ depends on SERIAL_MCF && M5441X
+ default n
+ help
+ Enable ColdFire UART4 device configuration
+
+config SERIAL_MCF_UART5
+ bool "Coldfire UART5 device support"
+ depends on SERIAL_MCF && M5441X
+ default n
+ help
+ Enable ColdFire UART5 device configuration
+
+config SERIAL_MCF_UART6
+ bool "Coldfire UART6 device support"
+ depends on SERIAL_MCF && M5441X
+ default n
+ help
+ Enable ColdFire UART6 device configuration
+
+config SERIAL_MCF_UART7
+ bool "Coldfire UART7 device support"
+ depends on SERIAL_MCF && M5441X
+ default n
+ help
+ Enable ColdFire UART7 device configuration
+
+config SERIAL_MCF_UART8
+ bool "Coldfire UART8 device support"
+ depends on SERIAL_MCF && M5441X
+ default n
+ help
+ Enable ColdFire UART8 device configuration
+
+config SERIAL_MCF_UART9
+ bool "Coldfire UART9 device support"
+ depends on SERIAL_MCF && M5441X
+ default n
+ help
+ Enable ColdFire UART9 device configuration
+
config SERIAL_68360_SMC
bool "68360 SMC uart support"
depends on M68360
--- a/drivers/tty/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
@@ -527,7 +527,7 @@ static const struct uart_ops mcf_uart_op
.verify_port = mcf_verify_port,
};
-static struct mcf_uart mcf_ports[4];
+static struct mcf_uart mcf_ports[MAX_PORT_NUM];
#define MCF_MAXPORTS ARRAY_SIZE(mcf_ports)

View file

@ -1,68 +0,0 @@
From 04491155db32bc1a9c0b367a7cac0f4a9ea9c4d2 Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:43 +0800
Subject: [PATCH 17/52] Add cpu dma sync function for coldfire platform
This patch add dma_sync_sg_for_cpu() and dma_sync_single_for_cpu()
for coldfire platform. The previous empty function do not flush the
cache for the ram used for DMA.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
arch/m68k/include/asm/dma-mapping.h | 10 ++++++++--
1 files changed, 8 insertions(+), 2 deletions(-)
--- a/arch/m68k/include/asm/dma-mapping.h
+++ b/arch/m68k/include/asm/dma-mapping.h
@@ -21,6 +21,9 @@ extern void *dma_alloc_coherent(struct d
extern void dma_free_coherent(struct device *, size_t,
void *, dma_addr_t);
+extern void dma_sync_single_for_device(struct device *, dma_addr_t, size_t,
+ enum dma_data_direction);
+
static inline void *dma_alloc_noncoherent(struct device *dev, size_t size,
dma_addr_t *handle, gfp_t flag)
{
@@ -42,6 +45,7 @@ extern dma_addr_t dma_map_single(struct
static inline void dma_unmap_single(struct device *dev, dma_addr_t addr,
size_t size, enum dma_data_direction dir)
{
+ dma_sync_single_for_device(dev, addr, size, dir);
}
extern dma_addr_t dma_map_page(struct device *, struct page *,
@@ -50,6 +54,7 @@ extern dma_addr_t dma_map_page(struct de
static inline void dma_unmap_page(struct device *dev, dma_addr_t address,
size_t size, enum dma_data_direction dir)
{
+ dma_sync_single_for_device(dev, address, size, dir);
}
extern int dma_map_sg(struct device *, struct scatterlist *, int,
@@ -57,10 +62,9 @@ extern int dma_map_sg(struct device *, s
static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
int nhwentries, enum dma_data_direction dir)
{
+ dma_map_sg(dev, sg, nhwentries, dir);
}
-extern void dma_sync_single_for_device(struct device *, dma_addr_t, size_t,
- enum dma_data_direction);
extern void dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
enum dma_data_direction);
@@ -75,11 +79,13 @@ static inline void dma_sync_single_range
static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle,
size_t size, enum dma_data_direction dir)
{
+ dma_sync_single_for_device(dev, handle, size, dir);
}
static inline void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir)
{
+ dma_sync_sg_for_device(dev, sg, nents, dir);
}
static inline void dma_sync_single_range_for_cpu(struct device *dev,

View file

@ -1,973 +0,0 @@
From c1de95e3a608c48b5576e32181480930d9106ac4 Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:44 +0800
Subject: [PATCH 18/52] Add SSD1289 TFT LCD framebuffer driver on TWR-MCF5441X
Add SSD1289 TFT LCD framebuffer driver on TWR-MCF5441X. Flexbus and spi
interfaces are both supported.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
arch/m68k/coldfire/m5441x/config.c | 1 +
arch/m68k/coldfire/m5441x/devices.c | 1 +
arch/m68k/include/asm/fsl-ssd1289-fb.h | 93 ++++
drivers/video/Kconfig | 24 +
drivers/video/Makefile | 1 +
drivers/video/fsl-ssd1289-fb.c | 791 ++++++++++++++++++++++++++++++++
6 files changed, 911 insertions(+), 0 deletions(-)
create mode 100644 arch/m68k/include/asm/fsl-ssd1289-fb.h
create mode 100644 drivers/video/fsl-ssd1289-fb.c
--- a/arch/m68k/coldfire/m5441x/config.c
+++ b/arch/m68k/coldfire/m5441x/config.c
@@ -45,6 +45,7 @@
#include <asm/mcf5441x_fbcs.h>
#include <asm/mcf5441x_dtim.h>
#include <asm/mcf5441x_xbs.h>
+#include <asm/fsl-ssd1289-fb.h>
extern int get_irq_list(struct seq_file *p, void *v);
extern char _text, _end;
--- a/arch/m68k/coldfire/m5441x/devices.c
+++ b/arch/m68k/coldfire/m5441x/devices.c
@@ -33,6 +33,7 @@
#include <asm/mcfqspi.h>
#include <asm/mcfdspi.h>
#include <asm/cf_io.h>
+#include <asm/fsl-ssd1289-fb.h>
/*
* I2C: only support i2c0 module on m5441x platform
--- /dev/null
+++ b/arch/m68k/include/asm/fsl-ssd1289-fb.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Freescale MCF54418 SSD1289 TFT LCD framebuffer driver
+ *
+ * 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.
+ */
+
+#ifndef __FSL_SSD1289_FB_H__
+#define __FSL_SSD1289_FB_H__
+
+#define SSD1289_REG_OSCILLATION 0x00
+#define SSD1289_REG_DRIVER_OUT_CTRL 0x01
+#define SSD1289_REG_LCD_DRIVE_AC 0x02
+#define SSD1289_REG_POWER_CTRL_1 0x03
+#define SSD1289_REG_COMPARE_1 0x05
+#define SSD1289_REG_COMPARE_2 0x06
+#define SSD1289_REG_DISPLAY_CTRL 0x07
+#define SSD1289_REG_FRAME_CYCLE 0x0b
+#define SSD1289_REG_POWER_CTRL_2 0x0c
+#define SSD1289_REG_POWER_CTRL_3 0x0d
+#define SSD1289_REG_POWER_CTRL_4 0x0e
+#define SSD1289_REG_GATE_SCAN_START 0x0f
+#define SSD1289_REG_SLEEP_MODE 0x10
+#define SSD1289_REG_ENTRY_MODE 0x11
+#define SSD1289_REG_OPT_SPEED_3 0x12
+#define SSD1289_REG_H_PORCH 0x16
+#define SSD1289_REG_V_PORCH 0x17
+#define SSD1289_REG_POWER_CTRL_5 0x1e
+#define SSD1289_REG_GDDRAM_DATA 0x22
+#define SSD1289_REG_WR_DATA_MASK_1 0x23
+#define SSD1289_REG_WR_DATA_MASK_2 0x24
+#define SSD1289_REG_FRAME_FREQUENCY 0x25
+#define SSD1289_REG_OPT_SPEED_1 0x28
+#define SSD1289_REG_OPT_SPEED_2 0x2f
+#define SSD1289_REG_GAMMA_CTRL_1 0x30
+#define SSD1289_REG_GAMMA_CTRL_2 0x31
+#define SSD1289_REG_GAMMA_CTRL_3 0x32
+#define SSD1289_REG_GAMMA_CTRL_4 0x33
+#define SSD1289_REG_GAMMA_CTRL_5 0x34
+#define SSD1289_REG_GAMMA_CTRL_6 0x35
+#define SSD1289_REG_GAMMA_CTRL_7 0x36
+#define SSD1289_REG_GAMMA_CTRL_8 0x37
+#define SSD1289_REG_GAMMA_CTRL_9 0x3a
+#define SSD1289_REG_GAMMA_CTRL_10 0x3b
+#define SSD1289_REG_V_SCROLL_CTRL_1 0x41
+#define SSD1289_REG_V_SCROLL_CTRL_2 0x42
+#define SSD1289_REG_H_RAM_ADR_POS 0x44
+#define SSD1289_REG_V_RAM_ADR_START 0x45
+#define SSD1289_REG_V_RAM_ADR_END 0x46
+#define SSD1289_REG_FIRST_WIN_START 0x48
+#define SSD1289_REG_FIRST_WIN_END 0x49
+#define SSD1289_REG_SECND_WIN_START 0x4a
+#define SSD1289_REG_SECND_WIN_END 0x4b
+#define SSD1289_REG_GDDRAM_X_ADDR 0x4e
+#define SSD1289_REG_GDDRAM_Y_ADDR 0x4f
+
+struct ssd1289 {
+ void __iomem *cmd;
+ void __iomem *data;
+} __packed;
+
+struct fsl_ssd1289_fb_info {
+ struct device *dev;
+ struct ssd1289 ssd1289_reg;
+ int openflag;
+ struct spi_device *spidev;
+
+ struct task_struct *task;
+ unsigned long pseudo_palette[16];
+};
+
+/* LCD description */
+struct fsl_ssd1289_fb_display {
+ /* Screen size */
+ unsigned short width;
+ unsigned short height;
+
+ /* Screen info */
+ unsigned short xres;
+ unsigned short yres;
+ unsigned short bpp;
+};
+
+#define FLEXBUS_LCD_CMD_ADDRESS 0xc0000000
+#define FLEXBUS_LCD_DATA_ADDRESS 0xc0010000
+
+#define SPI_LCD_BLOCK_SIZE 4096
+#define SPI_LCD_BLOCK_HALF_SIZE 2048
+#endif
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1980,6 +1980,30 @@ config FB_FSL_DIU
---help---
Framebuffer driver for the Freescale SoC DIU
+config FB_FSL_SSD1289
+ tristate "SSD1289 TFT LCD (Freescale MCF54418)"
+ depends on FB && M5441X
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ select FB_SYS_FOPS
+ ---help---
+ This is the framebuffer device driver for a Solomon Systech 240RGBx320
+ TFT LCD SSD1289.
+
+choice
+ prompt "SSD1289 LCD Controller Interface mode"
+ depends on FB_FSL_SSD1289
+
+config SSD1289_FLEXBUS_MODE
+ bool "SSD1289 LCD Controller Flexbus Interface mode"
+
+config SSD1289_SPI_MODE
+ bool "SSD1289 LCD Controller SPI Interface mode"
+ depends on SPI_DSPI && DSPI0
+
+endchoice
+
config FB_W100
tristate "W100 frame buffer support"
depends on FB && ARCH_PXA
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -120,6 +120,7 @@ obj-$(CONFIG_FB_IMX) += imx
obj-$(CONFIG_FB_S3C) += s3c-fb.o
obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o
+obj-$(CONFIG_FB_FSL_SSD1289) += fsl-ssd1289-fb.o
obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o
obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/
obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/
--- /dev/null
+++ b/drivers/video/fsl-ssd1289-fb.c
@@ -0,0 +1,791 @@
+/*
+ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Freescale MCF54418 SSD1289 TFT LCD framebuffer driver
+ *
+ * Author: Alison Wang <b18965@freescale.com>
+ * Jason Jin <Jason.jin@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/uaccess.h>
+#include <linux/timer.h>
+#include <linux/kthread.h>
+#include <linux/spi/spi.h>
+
+#include <asm/mcf5441x_fbcs.h>
+#include <asm/mcf5441x_dspi.h>
+#include <asm/fsl-ssd1289-fb.h>
+#include <asm/mcf5441x_gpio.h>
+#include <asm/mcf5441x_ccm.h>
+#include <asm/mcf_edma.h>
+
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+
+#if defined(CONFIG_SSD1289_SPI_MODE)
+unsigned char spi_block_buffer[SPI_LCD_BLOCK_SIZE];
+
+static int ssd1289_spi_writeblock(struct fb_info *info,
+ unsigned char *daddr, int flag)
+{
+ struct fsl_ssd1289_fb_info *fbinfo = info->par;
+ struct spi_device *devtmp;
+ int i;
+
+ for (i = 0; i < SPI_LCD_BLOCK_SIZE; i++) {
+ if (i % 2 == 0)
+ spi_block_buffer[i] = 0x01;
+ else if (flag == 1)
+ spi_block_buffer[i] = *(daddr + (i >> 1));
+ else if (flag == 0)
+ spi_block_buffer[i] = 0;
+ }
+
+ devtmp = fbinfo->spidev;
+ spi_write(devtmp, (const unsigned char *)spi_block_buffer,
+ SPI_LCD_BLOCK_SIZE);
+ return 0;
+}
+
+static int ssd1289_spi_write(struct fb_info *info,
+ unsigned short value, unsigned int flag)
+{
+ struct fsl_ssd1289_fb_info *fbinfo = info->par;
+ struct spi_device *devtmp;
+ unsigned short tmpl;
+ unsigned short tmph;
+
+ devtmp = fbinfo->spidev;
+ if (flag == 1) {
+ /* D/C = 1 */
+ tmph = ((value >> 8) & 0xff) + 0x0100;
+ tmpl = (value & 0xff) + 0x0100;
+ spi_write(devtmp, (const u8 *)&tmph, sizeof(tmph));
+ spi_write(devtmp, (const u8 *)&tmpl, sizeof(tmpl));
+ } else {
+ /* D/C = 0 */
+ tmpl = (value & 0xff);
+ spi_write(devtmp, (const u8 *)&tmpl, sizeof(tmpl));
+ }
+ return 0;
+}
+#elif defined(CONFIG_SSD1289_FLEXBUS_MODE)
+static int ssd1289_flexbus_write(struct fb_info *info, unsigned short value,
+ unsigned int flag)
+{
+ struct fsl_ssd1289_fb_info *fbinfo = info->par;
+ void __iomem *cmd_addr, *data_addr;
+
+ cmd_addr = fbinfo->ssd1289_reg.cmd;
+ data_addr = fbinfo->ssd1289_reg.data;
+
+ if (flag == 0)
+ out_be16(cmd_addr, value);
+ else
+ out_be16(data_addr, value);
+
+ return 0;
+}
+#endif
+
+static int ssd1289_write(struct fb_info *info, unsigned short value,
+ unsigned int flag)
+{
+#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
+ ssd1289_flexbus_write(info, value, flag);
+#elif defined(CONFIG_SSD1289_SPI_MODE)
+ ssd1289_spi_write(info, value, flag);
+#endif
+ return 0;
+}
+
+static void fsl_ssd1289_enable_lcd(struct fb_info *info)
+{
+ int i;
+
+#if defined(CONFIG_SSD1289_SPI_MODE)
+ int count;
+#elif defined(CONFIG_SSD1289_FLEXBUS_MODE)
+ /* GPIO configuration */
+ MCF_GPIO_PAR_BE = MCF_GPIO_PAR_BE_BE3_FB_A1 | MCF_GPIO_PAR_BE_BE2_FB_A0
+ | MCF_GPIO_PAR_BE_BE1_BE1 | MCF_GPIO_PAR_BE_BE0_BE0;
+ MCF_GPIO_PAR_CS |= MCF_GPIO_PAR_CS_CS0_CS0;
+#endif
+
+ ssd1289_write(info, SSD1289_REG_DISPLAY_CTRL, 0);
+ ssd1289_write(info, 0x0200, 1);
+
+ ssd1289_write(info, SSD1289_REG_OSCILLATION, 0);
+ ssd1289_write(info, 0x0000, 1);
+
+ mdelay(100);
+
+ /* turn on the oscillator */
+ ssd1289_write(info, SSD1289_REG_OSCILLATION, 0);
+ ssd1289_write(info, 0x0001, 1);
+
+ mdelay(100);
+ /* power control 1 */
+ ssd1289_write(info, SSD1289_REG_POWER_CTRL_1, 0);
+ ssd1289_write(info, 0xaeac, 1);
+
+ /* power control 2 */
+ ssd1289_write(info, SSD1289_REG_POWER_CTRL_2, 0);
+ ssd1289_write(info, 0x0007, 1);
+
+ /* power control 3 */
+ ssd1289_write(info, SSD1289_REG_POWER_CTRL_3, 0);
+ ssd1289_write(info, 0x000f, 1);
+
+ /* power control 4 */
+ ssd1289_write(info, SSD1289_REG_POWER_CTRL_4, 0);
+ ssd1289_write(info, 0x2900, 1);
+
+ /* power control 5 */
+ ssd1289_write(info, SSD1289_REG_POWER_CTRL_5, 0);
+ ssd1289_write(info, 0x00b3, 1);
+
+ mdelay(15);
+ /* driver output control */
+ ssd1289_write(info, SSD1289_REG_DRIVER_OUT_CTRL, 0);
+ ssd1289_write(info, 0x2b3f, 1);
+
+ /* lcd-driving-waveform control */
+ ssd1289_write(info, SSD1289_REG_LCD_DRIVE_AC, 0);
+ ssd1289_write(info, 0x0600, 1);
+
+ /* sleep mode */
+ ssd1289_write(info, SSD1289_REG_SLEEP_MODE, 0);
+ ssd1289_write(info, 0x0000, 1);
+
+ /* entry mode */
+ ssd1289_write(info, SSD1289_REG_ENTRY_MODE, 0);
+ ssd1289_write(info, 0x60a8, 1);
+
+ mdelay(15);
+ /* compare register */
+ ssd1289_write(info, SSD1289_REG_COMPARE_1, 0);
+ ssd1289_write(info, 0x0000, 1);
+
+ ssd1289_write(info, SSD1289_REG_COMPARE_2, 0);
+ ssd1289_write(info, 0x0000, 1);
+
+ /* horizontal porch */
+ ssd1289_write(info, SSD1289_REG_H_PORCH, 0);
+ ssd1289_write(info, 0xef1c, 1);
+
+ /* vertical porch */
+ ssd1289_write(info, SSD1289_REG_V_PORCH, 0);
+ ssd1289_write(info, 0x0003, 1);
+
+ /* display control */
+ ssd1289_write(info, SSD1289_REG_DISPLAY_CTRL, 0);
+ ssd1289_write(info, 0x0233, 1);
+
+ /* frame cycle control */
+ ssd1289_write(info, SSD1289_REG_FRAME_CYCLE, 0);
+ ssd1289_write(info, 0x5312, 1);
+
+ /* gate scan position */
+ ssd1289_write(info, SSD1289_REG_GATE_SCAN_START, 0);
+ ssd1289_write(info, 0x0000, 1);
+
+ mdelay(20);
+ /* vertical scroll control */
+ ssd1289_write(info, SSD1289_REG_V_SCROLL_CTRL_1, 0);
+ ssd1289_write(info, 0x0000, 1);
+
+ ssd1289_write(info, SSD1289_REG_V_SCROLL_CTRL_2, 0);
+ ssd1289_write(info, 0x0000, 1);
+
+ /* 1st screen driving position */
+ ssd1289_write(info, SSD1289_REG_FIRST_WIN_START, 0);
+ ssd1289_write(info, 0x0000, 1);
+
+ ssd1289_write(info, SSD1289_REG_FIRST_WIN_END, 0);
+ ssd1289_write(info, 0x013F, 1);
+
+ /* 2nd screen driving position */
+ ssd1289_write(info, SSD1289_REG_SECND_WIN_START, 0);
+ ssd1289_write(info, 0x0000, 1);
+
+ ssd1289_write(info, SSD1289_REG_SECND_WIN_END, 0);
+ ssd1289_write(info, 0x0000, 1);
+
+ mdelay(20);
+ /* gamma control */
+ ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_1, 0);
+ ssd1289_write(info, 0x0707, 1);
+
+ ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_2, 0);
+ ssd1289_write(info, 0x0704, 1);
+
+ ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_3, 0);
+ ssd1289_write(info, 0x0204, 1);
+
+ ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_4, 0);
+ ssd1289_write(info, 0x0201, 1);
+
+ ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_5, 0);
+ ssd1289_write(info, 0x0203, 1);
+
+ ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_6, 0);
+ ssd1289_write(info, 0x0204, 1);
+
+ ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_7, 0);
+ ssd1289_write(info, 0x0204, 1);
+
+ ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_8, 0);
+ ssd1289_write(info, 0x0502, 1);
+
+ ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_9, 0);
+ ssd1289_write(info, 0x0302, 1);
+
+ ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_10, 0);
+ ssd1289_write(info, 0x0500, 1);
+
+ /* ram write data mask */
+ ssd1289_write(info, SSD1289_REG_WR_DATA_MASK_1, 0);
+ ssd1289_write(info, 0x0000, 1);
+
+ ssd1289_write(info, SSD1289_REG_WR_DATA_MASK_2, 0);
+ ssd1289_write(info, 0x0000, 1);
+
+ /* frame frequency control */
+ ssd1289_write(info, SSD1289_REG_FRAME_FREQUENCY, 0);
+ ssd1289_write(info, 0xe000, 1);
+
+ /* optimize data access speed */
+ ssd1289_write(info, SSD1289_REG_OPT_SPEED_1, 0);
+ ssd1289_write(info, 0x0006, 1);
+
+ ssd1289_write(info, SSD1289_REG_OPT_SPEED_2, 0);
+ ssd1289_write(info, 0x12ae, 1);
+
+ ssd1289_write(info, SSD1289_REG_OPT_SPEED_3, 0);
+ ssd1289_write(info, 0x6ceb, 1);
+
+ /* horizontal ram address position */
+ ssd1289_write(info, SSD1289_REG_H_RAM_ADR_POS, 0);
+ ssd1289_write(info, 0xef00, 1);
+
+ /* vertical ram address position */
+ ssd1289_write(info, SSD1289_REG_V_RAM_ADR_START, 0);
+ ssd1289_write(info, 0x0000, 1);
+
+ ssd1289_write(info, SSD1289_REG_V_RAM_ADR_END, 0);
+ ssd1289_write(info, 0x013f, 1);
+
+ mdelay(20);
+
+ /* set start address counter */
+ ssd1289_write(info, SSD1289_REG_GDDRAM_X_ADDR, 0);
+ ssd1289_write(info, 0x00ef, 1);
+
+ ssd1289_write(info, SSD1289_REG_GDDRAM_Y_ADDR, 0);
+ ssd1289_write(info, 0x0000, 1);
+
+ ssd1289_write(info, SSD1289_REG_GDDRAM_DATA, 0);
+
+#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
+ for (i = 0; i < info->screen_size; i += 2)
+ ssd1289_write(info, 0, 1);
+#elif defined(CONFIG_SSD1289_SPI_MODE)
+ count = info->screen_size / SPI_LCD_BLOCK_HALF_SIZE;
+ for (i = 0; i < count; i++)
+ ssd1289_spi_writeblock(info, NULL, 0);
+#endif
+}
+
+static void fsl_ssd1289_disable_lcd(struct fb_info *info)
+{
+ ssd1289_write(info, SSD1289_REG_DISPLAY_CTRL, 0);
+ ssd1289_write(info, 0x0200, 1);
+
+ ssd1289_write(info, SSD1289_REG_OSCILLATION, 0);
+ ssd1289_write(info, 0x0000, 1);
+}
+
+static int ssd1289fbd(void *arg)
+{
+ struct fb_info *info = arg;
+ int i;
+ unsigned short *buf_p;
+ struct fsl_ssd1289_fb_info *fbinfo = info->par;
+#if defined(CONFIG_SSD1289_SPI_MODE)
+ unsigned char *bufspi_p;
+ int count;
+#endif
+
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (fbinfo->openflag == 1) {
+ buf_p = (unsigned short *)(info->screen_base);
+
+#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
+ for (i = 0; i < info->screen_size; i += 2) {
+ ssd1289_write(info, *buf_p, 1);
+ buf_p++;
+ }
+#elif defined(CONFIG_SSD1289_SPI_MODE)
+ bufspi_p = (unsigned char *)buf_p;
+ count = info->screen_size / SPI_LCD_BLOCK_HALF_SIZE;
+ for (i = 0; i < count; i++)
+ ssd1289_spi_writeblock(info, (bufspi_p +
+ SPI_LCD_BLOCK_HALF_SIZE * i), 1);
+#endif
+ }
+ schedule_timeout(HZ/25);
+ }
+
+ return 0;
+}
+
+static int fsl_ssd1289_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+
+ if (var->xoffset < 0)
+ var->xoffset = 0;
+
+ if (var->yoffset < 0)
+ var->yoffset = 0;
+
+ if (var->xoffset + info->var.xres > info->var.xres_virtual)
+ var->xoffset = info->var.xres_virtual - info->var.xres;
+
+ if (var->yoffset + info->var.yres > info->var.yres_virtual)
+ var->yoffset = info->var.yres_virtual - info->var.yres;
+
+ switch (var->bits_per_pixel) {
+ case 8:
+ /* 8 bpp, 332 format */
+ var->red.length = 3;
+ var->red.offset = 5;
+ var->red.msb_right = 0;
+
+ var->green.length = 3;
+ var->green.offset = 2;
+ var->green.msb_right = 0;
+
+ var->blue.length = 2;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ break;
+ case 16:
+ /* 16 bpp, 565 format */
+ var->red.length = 5;
+ var->red.offset = 11;
+ var->red.msb_right = 0;
+
+ var->green.length = 6;
+ var->green.offset = 5;
+ var->green.msb_right = 0;
+
+ var->blue.length = 5;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ break;
+ default:
+ printk(KERN_ERR "Depth not supported: %u BPP\n",
+ var->bits_per_pixel);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int fsl_ssd1289_set_par(struct fb_info *info)
+{
+ struct fb_var_screeninfo *var = &info->var;
+
+ switch (var->bits_per_pixel) {
+ case 16:
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ break;
+ case 8:
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ break;
+ default:
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ break;
+ }
+
+ return 0;
+}
+
+static inline __u32 CNVT_TOHW(__u32 val, __u32 width)
+{
+ return ((val<<width) + 0x7FFF - val)>>16;
+}
+
+static int fsl_ssd1289_setcolreg(unsigned regno,
+ unsigned red, unsigned green, unsigned blue,
+ unsigned transp, struct fb_info *info)
+{
+ int ret = 1;
+
+ /*
+ * If greyscale is true, then we convert the RGB value
+ * to greyscale no matter what visual we are using.
+ */
+ if (info->var.grayscale)
+ red = green = blue = (19595 * red + 38470 * green +
+ 7471 * blue) >> 16;
+ switch (info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ if (regno < 16) {
+ u32 *pal = info->pseudo_palette;
+ u32 value;
+
+ red = CNVT_TOHW(red, info->var.red.length);
+ green = CNVT_TOHW(green, info->var.green.length);
+ blue = CNVT_TOHW(blue, info->var.blue.length);
+ transp = CNVT_TOHW(transp, info->var.transp.length);
+
+ value = (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset) |
+ (transp << info->var.transp.offset);
+
+ pal[regno] = value;
+ ret = 0;
+ }
+ break;
+ case FB_VISUAL_STATIC_PSEUDOCOLOR:
+ case FB_VISUAL_PSEUDOCOLOR:
+ break;
+ }
+ return ret;
+}
+
+static int fsl_ssd1289_blank(int blank_mode, struct fb_info *info)
+{
+ if (blank_mode == FB_BLANK_POWERDOWN)
+ fsl_ssd1289_disable_lcd(info);
+ else
+ fsl_ssd1289_enable_lcd(info);
+
+ return 0;
+}
+
+static int fsl_ssd1289_open(struct fb_info *info, int user)
+{
+ struct fsl_ssd1289_fb_info *fbinfo = info->par;
+ struct task_struct *task;
+ int ret;
+
+ if (fbinfo->openflag == 0) {
+ memset(info->screen_base, 0, info->screen_size);
+ fsl_ssd1289_enable_lcd(info);
+
+ task = kthread_run(ssd1289fbd, info, "SSD1289 LCD");
+ if (IS_ERR(task)) {
+ ret = PTR_ERR(task);
+ return ret;
+ }
+ fbinfo->task = task;
+ }
+
+ fbinfo->openflag = 1;
+ return 0;
+}
+
+static int fsl_ssd1289_release(struct fb_info *info, int user)
+{
+ struct fsl_ssd1289_fb_info *fbinfo = info->par;
+
+ fbinfo->openflag = 0;
+ if (fbinfo->task) {
+ struct task_struct *task = fbinfo->task;
+ fbinfo->task = NULL;
+ kthread_stop(task);
+ }
+
+ memset(info->screen_base, 0, info->screen_size);
+ fsl_ssd1289_disable_lcd(info);
+ return 0;
+}
+
+static struct fb_ops fsl_ssd1289_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = fsl_ssd1289_check_var,
+ .fb_set_par = fsl_ssd1289_set_par,
+ .fb_setcolreg = fsl_ssd1289_setcolreg,
+ .fb_blank = fsl_ssd1289_blank,
+ .fb_open = fsl_ssd1289_open,
+ .fb_release = fsl_ssd1289_release,
+ .fb_copyarea = cfb_copyarea,
+ .fb_fillrect = cfb_fillrect,
+ .fb_imageblit = cfb_imageblit,
+};
+
+static int fsl_ssd1289_map_video_memory(struct fb_info *info)
+{
+ unsigned int map_size = info->fix.smem_len;
+
+#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
+ struct fsl_ssd1289_fb_info *fbinfo = info->par;
+
+ fbinfo->ssd1289_reg.cmd =
+ ioremap_nocache(FLEXBUS_LCD_CMD_ADDRESS, 2);
+ fbinfo->ssd1289_reg.data =
+ ioremap_nocache(FLEXBUS_LCD_DATA_ADDRESS, 2);
+#endif
+
+ info->screen_base = kmalloc(map_size, GFP_KERNEL);
+ info->fix.smem_start = virt_to_phys(info->screen_base);
+ info->screen_size = info->fix.smem_len;
+
+ if (info->screen_base)
+ memset(info->screen_base, 0, map_size);
+
+ return info->screen_base ? 0 : -ENOMEM;
+}
+
+static inline void fsl_ssd1289_unmap_video_memory(struct fb_info *info)
+{
+#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
+ struct fsl_ssd1289_fb_info *fbinfo = info->par;
+
+ iounmap(fbinfo->ssd1289_reg.cmd);
+ iounmap(fbinfo->ssd1289_reg.data);
+#endif
+ kfree(info->screen_base);
+}
+
+
+#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
+static int fsl_ssd1289_probe(struct platform_device *pdev)
+#elif defined(CONFIG_SSD1289_SPI_MODE)
+static int fsl_ssd1289_probe(struct spi_device *spi)
+#endif
+{
+ struct fsl_ssd1289_fb_info *fbinfo;
+ struct fb_info *info;
+ struct fsl_ssd1289_fb_display *display;
+ int ret;
+ unsigned long smem_len;
+
+#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
+ info = framebuffer_alloc(sizeof(struct fsl_ssd1289_fb_info),
+ &pdev->dev);
+ if (!info)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, info);
+
+ fbinfo = info->par;
+ fbinfo->dev = &pdev->dev;
+ display = pdev->dev.platform_data;
+#elif defined(CONFIG_SSD1289_SPI_MODE)
+ info = framebuffer_alloc(sizeof(struct fsl_ssd1289_fb_info),
+ &spi->dev);
+ if (!info)
+ return -ENOMEM;
+
+ dev_set_drvdata(&spi->dev, info);
+
+ fbinfo = info->par;
+ fbinfo->dev = &spi->dev;
+ fbinfo->spidev = spi;
+ display = spi->dev.platform_data;
+#endif
+
+ fbinfo->openflag = 0;
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.type_aux = 0;
+ info->fix.xpanstep = 0;
+ info->fix.ypanstep = 0;
+ info->fix.ywrapstep = 0;
+ info->fix.accel = FB_ACCEL_NONE;
+
+ info->var.nonstd = 0;
+ info->var.activate = FB_ACTIVATE_NOW;
+ info->var.accel_flags = 0;
+ info->var.vmode = FB_VMODE_NONINTERLACED;
+
+ info->fbops = &fsl_ssd1289_ops;
+ info->flags = FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT
+ | FBINFO_HWACCEL_COPYAREA;
+ info->pseudo_palette = &fbinfo->pseudo_palette;
+
+ /* find maximum required memory size for display */
+ smem_len = display->xres;
+ smem_len *= display->yres;
+ smem_len *= display->bpp;
+ smem_len >>= 3;
+ if (info->fix.smem_len < smem_len)
+ info->fix.smem_len = smem_len;
+
+ /* Intialize video memory */
+ ret = fsl_ssd1289_map_video_memory(info);
+ if (ret) {
+ printk(KERN_ERR "Failed to allocate video RAM: %d\n", ret);
+ ret = -ENOMEM;
+ goto dealloc_fb;
+ }
+
+ info->var.xres = display->xres;
+ info->var.yres = display->yres;
+ info->var.bits_per_pixel = display->bpp;
+ info->fix.line_length = (info->var.xres * info->var.bits_per_pixel) / 8;
+
+ fsl_ssd1289_check_var(&info->var, info);
+
+ ret = register_framebuffer(info);
+ if (ret < 0) {
+ printk(KERN_ERR "Failed to register framebuffer device: %d\n",
+ ret);
+ goto free_video_memory;
+ }
+
+ printk(KERN_INFO "fb: SSD1289 TFT LCD Framebuffer Driver\n");
+ return 0;
+
+free_video_memory:
+ fsl_ssd1289_unmap_video_memory(info);
+dealloc_fb:
+#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
+ platform_set_drvdata(pdev, NULL);
+#elif defined(CONFIG_SSD1289_SPI_MODE)
+ dev_set_drvdata(&spi->dev, NULL);
+#endif
+ framebuffer_release(info);
+ return ret;
+}
+
+#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
+static int fsl_ssd1289_remove(struct platform_device *pdev)
+{
+ struct fb_info *info = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+#elif defined(CONFIG_SSD1289_SPI_MODE)
+static int fsl_ssd1289_remove(struct spi_device *spi)
+{
+ struct fb_info *info = dev_get_drvdata(&spi->dev);
+
+ dev_set_drvdata(&spi->dev, NULL);
+#endif
+ unregister_framebuffer(info);
+ fsl_ssd1289_unmap_video_memory(info);
+ framebuffer_release(info);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
+static int fsl_ssd1289_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct fb_info *info = platform_get_drvdata(dev);
+#elif defined(CONFIG_SSD1289_SPI_MODE)
+static int fsl_ssd1289_suspend(struct spi_device *spi, pm_message_t state)
+{
+ struct fb_info *info = dev_get_drvdata(&spi->dev);
+#endif
+ /* enter into sleep mode */
+ ssd1289_write(info, SSD1289_REG_SLEEP_MODE, 0);
+ ssd1289_write(info, 0x0001, 1);
+ return 0;
+}
+
+#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
+static int fsl_ssd1289_resume(struct platform_device *dev)
+{
+ struct fb_info *info = platform_get_drvdata(dev);
+#elif defined(CONFIG_SSD1289_SPI_MODE)
+static int fsl_ssd1289_resume(struct spi_device *spi)
+{
+ struct fb_info *info = dev_get_drvdata(&spi->dev);
+#endif
+ /* leave sleep mode */
+ ssd1289_write(info, SSD1289_REG_SLEEP_MODE, 0);
+ ssd1289_write(info, 0x0000, 1);
+ return 0;
+}
+#else
+#define fsl_ssd1289_suspend NULL
+#define fsl_ssd1289_resume NULL
+#endif
+
+#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
+static struct platform_driver fsl_ssd1289_driver = {
+ .probe = fsl_ssd1289_probe,
+ .remove = fsl_ssd1289_remove,
+ .suspend = fsl_ssd1289_suspend,
+ .resume = fsl_ssd1289_resume,
+ .driver = {
+ .name = "fsl-ssd1289",
+ .owner = THIS_MODULE,
+ },
+};
+#elif defined(CONFIG_SSD1289_SPI_MODE)
+static struct spi_driver spi_ssd1289_driver = {
+ .driver = {
+ .name = "spi-ssd1289",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = fsl_ssd1289_probe,
+ .remove = fsl_ssd1289_remove,
+ .suspend = fsl_ssd1289_suspend,
+ .resume = fsl_ssd1289_resume,
+};
+#endif
+
+static int __devinit fsl_ssd1289_init(void)
+{
+#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
+ return platform_driver_register(&fsl_ssd1289_driver);
+#elif defined(CONFIG_SSD1289_SPI_MODE)
+ return spi_register_driver(&spi_ssd1289_driver);
+#endif
+}
+
+static void __exit fsl_ssd1289_exit(void)
+{
+#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
+ return platform_driver_unregister(&fsl_ssd1289_driver);
+#elif defined(CONFIG_SSD1289_SPI_MODE)
+ return spi_unregister_driver(&spi_ssd1289_driver);
+#endif
+}
+
+module_init(fsl_ssd1289_init);
+module_exit(fsl_ssd1289_exit);
+
+MODULE_AUTHOR("Alison Wang <b18965@freescale.com>");
+MODULE_DESCRIPTION("Freescale MCF54418 SSD1289 TFT LCD Framebuffer Driver");
+MODULE_LICENSE("GPL");

View file

@ -1,27 +0,0 @@
From 53cfdf92d9b68f5dac006853dd6727d7bf666b17 Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:44 +0800
Subject: [PATCH 19/52] Fix the format field for the Coldfire exception frame
Different with M68K, the correct format field encoding
for ColdFire should be 4, 5, 6 or 7.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
arch/m68k/mm/fault.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
--- a/arch/m68k/mm/fault.c
+++ b/arch/m68k/mm/fault.c
@@ -45,7 +45,11 @@ int send_fault_sig(struct pt_regs *regs)
regs->stkadj = frame_extra_sizes[regs->format];
tregs = (struct pt_regs *)((ulong)regs + regs->stkadj);
tregs->vector = regs->vector;
+#ifdef CONFIG_COLDFIRE
+ tregs->format = regs->stkadj + 4;
+#else
tregs->format = 0;
+#endif
tregs->pc = fixup->fixup;
tregs->sr = regs->sr;
return -1;

View file

@ -1,32 +0,0 @@
From f8dab3ef2c0da1c50dee07142c0b8088da61bc82 Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:45 +0800
Subject: [PATCH 22/52] Redefine I/O read and write functions
Redefine readb(), writeb(), readw(), writew(), readl(), write()
functions.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
arch/m68k/include/asm/cf_io.h | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)
--- a/arch/m68k/include/asm/cf_io.h
+++ b/arch/m68k/include/asm/cf_io.h
@@ -20,6 +20,16 @@
#include <asm-generic/iomap.h>
+/*
+ * These should be valid on any ioremap()ed region
+ */
+#define readb(addr) in_8(addr)
+#define writeb(val, addr) out_8((addr), (val))
+#define readw(addr) in_le16(addr)
+#define writew(val, addr) out_le16((addr), (val))
+#define readl(addr) in_le32(addr)
+#define writel(val, addr) out_le32((addr), (val))
+
#define readb_relaxed(addr) readb(addr)
#define readw_relaxed(addr) readw(addr)
#define readl_relaxed(addr) readl(addr)

View file

@ -1,357 +0,0 @@
From f7df9a8f3ce3a600ceeb7302bf0de899f321c818 Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:45 +0800
Subject: [PATCH 23/52] Replace readl and writel for FEC driver
Replace readl and writel by fec_readl and fec_writel
for FEC driver.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
drivers/net/fec.c | 129 ++++++++++++++++++++++++++++-------------------------
1 files changed, 68 insertions(+), 61 deletions(-)
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -244,6 +244,11 @@ static void fec_stop(struct net_device *
/* Transmitter timeout */
#define TX_TIMEOUT (2 * HZ)
+#define fec_readl(addr) \
+ ({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; })
+#define fec_writel(b, addr) \
+ (void)((*(volatile unsigned int *) (addr)) = (b))
+
static void *swap_buffer(void *bufaddr, int len)
{
int i;
@@ -347,7 +352,7 @@ fec_enet_start_xmit(struct sk_buff *skb,
bdp->cbd_sc = status;
/* Trigger transmission start */
- writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+ fec_writel(0, fep->hwp + FEC_X_DES_ACTIVE);
/* If this was the last BD in the ring, start at the beginning again. */
if (status & BD_ENET_TX_WRAP)
@@ -390,8 +395,8 @@ fec_enet_interrupt(int irq, void * dev_i
irqreturn_t ret = IRQ_NONE;
do {
- int_events = readl(fep->hwp + FEC_IEVENT);
- writel(int_events, fep->hwp + FEC_IEVENT);
+ int_events = fec_readl(fep->hwp + FEC_IEVENT);
+ fec_writel(int_events, fep->hwp + FEC_IEVENT);
#ifdef CONFIG_FEC_1588
if (__raw_readb(MCF_DTIM1_DTER) & MCF_DTIM_DTER_REF)
@@ -646,7 +651,7 @@ rx_processing_done:
* incoming frames. On a heavily loaded network, we should be
* able to keep up at the expense of system resources.
*/
- writel(0, fep->hwp + FEC_R_DES_ACTIVE);
+ fec_writel(0, fep->hwp + FEC_R_DES_ACTIVE);
}
fep->cur_rx = bdp;
@@ -686,9 +691,9 @@ static void __inline__ fec_get_mac(struc
*/
if (!is_valid_ether_addr(iap)) {
*((unsigned long *) &tmpaddr[0]) =
- be32_to_cpu(readl(fep->hwp + FEC_ADDR_LOW));
+ be32_to_cpu(fec_readl(fep->hwp + FEC_ADDR_LOW));
*((unsigned short *) &tmpaddr[4]) =
- be16_to_cpu(readl(fep->hwp + FEC_ADDR_HIGH) >> 16);
+ be16_to_cpu(fec_readl(fep->hwp + FEC_ADDR_HIGH) >> 16);
iap = &tmpaddr[0];
}
@@ -740,9 +745,9 @@ static void fec_enet_adjust_link(struct
if (id_entry->driver_data & FEC_QUIRK_ENET_MAC)
#ifdef CONFIG_FEC_1588
- writel(0x00000012, fep->hwp + FEC_ECNTRL);
+ fec_writel(0x00000012, fep->hwp + FEC_ECNTRL);
#else
- writel(0x00000002, fep->hwp + FEC_ECNTRL);
+ fec_writel(0x00000002, fep->hwp + FEC_ECNTRL);
#endif
status_change = 1;
}
@@ -763,7 +768,7 @@ static int fec_enet_mdio_read(struct mii
init_completion(&fep->mdio_done);
/* start a read op */
- writel(FEC_MMFR_ST | FEC_MMFR_OP_READ |
+ fec_writel(FEC_MMFR_ST | FEC_MMFR_OP_READ |
FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) |
FEC_MMFR_TA, fep->hwp + FEC_MII_DATA);
@@ -777,7 +782,7 @@ static int fec_enet_mdio_read(struct mii
}
/* return value */
- return FEC_MMFR_DATA(readl(fep->hwp + FEC_MII_DATA));
+ return FEC_MMFR_DATA(fec_readl(fep->hwp + FEC_MII_DATA));
}
static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
@@ -790,7 +795,7 @@ static int fec_enet_mdio_write(struct mi
init_completion(&fep->mdio_done);
/* start a write op */
- writel(FEC_MMFR_ST | FEC_MMFR_OP_WRITE |
+ fec_writel(FEC_MMFR_ST | FEC_MMFR_OP_WRITE |
FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) |
FEC_MMFR_TA | FEC_MMFR_DATA(value),
fep->hwp + FEC_MII_DATA);
@@ -905,7 +910,7 @@ static int fec_enet_mii_init(struct plat
* Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed)
*/
fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000) << 1;
- writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
+ fec_writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
fep->mii_bus = mdiobus_alloc();
if (fep->mii_bus == NULL) {
@@ -1151,30 +1156,30 @@ static void set_multicast_list(struct ne
unsigned char hash;
if (dev->flags & IFF_PROMISC) {
- tmp = readl(fep->hwp + FEC_R_CNTRL);
+ tmp = fec_readl(fep->hwp + FEC_R_CNTRL);
tmp |= 0x8;
- writel(tmp, fep->hwp + FEC_R_CNTRL);
+ fec_writel(tmp, fep->hwp + FEC_R_CNTRL);
return;
}
- tmp = readl(fep->hwp + FEC_R_CNTRL);
+ tmp = fec_readl(fep->hwp + FEC_R_CNTRL);
tmp &= ~0x8;
- writel(tmp, fep->hwp + FEC_R_CNTRL);
+ fec_writel(tmp, fep->hwp + FEC_R_CNTRL);
if (dev->flags & IFF_ALLMULTI) {
/* Catch all multicast addresses, so set the
* filter to all 1's
*/
- writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
- writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
+ fec_writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
+ fec_writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
return;
}
/* Clear filter and add the addresses in hash register
*/
- writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
- writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
+ fec_writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
+ fec_writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
netdev_for_each_mc_addr(ha, dev) {
/* Only support group multicast for now */
@@ -1198,13 +1203,13 @@ static void set_multicast_list(struct ne
hash = (crc >> (32 - HASH_BITS)) & 0x3f;
if (hash > 31) {
- tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
+ tmp = fec_readl(fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
tmp |= 1 << (hash - 32);
- writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
+ fec_writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
} else {
- tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_LOW);
+ tmp = fec_readl(fep->hwp + FEC_GRP_HASH_TABLE_LOW);
tmp |= 1 << hash;
- writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
+ fec_writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
}
}
}
@@ -1221,10 +1226,10 @@ fec_set_mac_address(struct net_device *d
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
- writel(dev->dev_addr[3] | (dev->dev_addr[2] << 8) |
+ fec_writel(dev->dev_addr[3] | (dev->dev_addr[2] << 8) |
(dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24),
fep->hwp + FEC_ADDR_LOW);
- writel((dev->dev_addr[5] << 16) | (dev->dev_addr[4] << 24),
+ fec_writel((dev->dev_addr[5] << 16) | (dev->dev_addr[4] << 24),
fep->hwp + FEC_ADDR_HIGH);
return 0;
}
@@ -1323,7 +1328,7 @@ fec_restart(struct net_device *dev, int
u32 val, temp_mac[2];
/* Whack a reset. We should wait for this. */
- writel(1, fep->hwp + FEC_ECNTRL);
+ fec_writel(1, fep->hwp + FEC_ECNTRL);
udelay(10);
/*
@@ -1332,31 +1337,32 @@ fec_restart(struct net_device *dev, int
*/
if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
memcpy(&temp_mac, dev->dev_addr, ETH_ALEN);
- writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW);
- writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH);
+ fec_writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW);
+ fec_writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH);
}
#ifdef CONFIG_FEC_1588
- writel(0x7fff8000, fep->hwp + FEC_IEVENT);
+ fec_writel(0x7fff8000, fep->hwp + FEC_IEVENT);
#else
/* Clear any outstanding interrupt. */
- writel(0xffc00000, fep->hwp + FEC_IEVENT);
+ fec_writel(0xffc00000, fep->hwp + FEC_IEVENT);
#endif
/* Reset all multicast. */
- writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
- writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
+ fec_writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
+ fec_writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
#ifndef CONFIG_M5272
- writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
- writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
+ fec_writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
+ fec_writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
#endif
/* Set maximum receive buffer size. */
- writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE);
+ fec_writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE);
/* Set receive and transmit descriptor base. */
- writel(fep->bd_dma, fep->hwp + FEC_R_DES_START);
- writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) * RX_RING_SIZE,
+ fec_writel(fep->bd_dma, fep->hwp + FEC_R_DES_START);
+ fec_writel((unsigned long)fep->bd_dma +
+ sizeof(struct bufdesc) * RX_RING_SIZE,
fep->hwp + FEC_X_DES_START);
fep->dirty_tx = fep->cur_tx = fep->tx_bd_base;
@@ -1374,24 +1380,24 @@ fec_restart(struct net_device *dev, int
/* Enable MII mode */
if (duplex) {
/* MII enable / FD enable */
- writel(OPT_FRAME_SIZE | 0x04, fep->hwp + FEC_R_CNTRL);
- writel(0x04, fep->hwp + FEC_X_CNTRL);
+ fec_writel(OPT_FRAME_SIZE | 0x04, fep->hwp + FEC_R_CNTRL);
+ fec_writel(0x04, fep->hwp + FEC_X_CNTRL);
} else {
/* MII enable / No Rcv on Xmit */
- writel(OPT_FRAME_SIZE | 0x06, fep->hwp + FEC_R_CNTRL);
- writel(0x0, fep->hwp + FEC_X_CNTRL);
+ fec_writel(OPT_FRAME_SIZE | 0x06, fep->hwp + FEC_R_CNTRL);
+ fec_writel(0x0, fep->hwp + FEC_X_CNTRL);
}
fep->full_duplex = duplex;
/* Set MII speed */
- writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
+ fec_writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
/*
* The phy interface and speed need to get configured
* differently on enet-mac.
*/
if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
- val = readl(fep->hwp + FEC_R_CNTRL);
+ val = fec_readl(fep->hwp + FEC_R_CNTRL);
/* MII or RMII */
if (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
@@ -1405,23 +1411,23 @@ fec_restart(struct net_device *dev, int
else
val |= (1 << 9);
- writel(val, fep->hwp + FEC_R_CNTRL);
+ fec_writel(val, fep->hwp + FEC_R_CNTRL);
} else {
#ifdef FEC_MIIGSK_ENR
if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) {
/* disable the gasket and wait */
- writel(0, fep->hwp + FEC_MIIGSK_ENR);
- while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4)
+ fec_writel(0, fep->hwp + FEC_MIIGSK_ENR);
+ while (fec_readl(fep->hwp + FEC_MIIGSK_ENR) & 4)
udelay(1);
/*
* configure the gasket:
* RMII, 50 MHz, no loopback, no echo
*/
- writel(1, fep->hwp + FEC_MIIGSK_CFGR);
+ fec_writel(1, fep->hwp + FEC_MIIGSK_CFGR);
/* re-enable the gasket */
- writel(2, fep->hwp + FEC_MIIGSK_ENR);
+ fec_writel(2, fep->hwp + FEC_MIIGSK_ENR);
}
#endif
}
@@ -1433,22 +1439,22 @@ fec_restart(struct net_device *dev, int
ret = fec_ptp_start(fep->ptp_priv);
if (ret) {
fep->ptimer_present = 0;
- writel(2, fep->hwp + FEC_ECNTRL);
+ fec_writel(2, fep->hwp + FEC_ECNTRL);
} else {
- val = readl(fep->hwp + FEC_ECNTRL);
+ val = fec_readl(fep->hwp + FEC_ECNTRL);
val |= 0x00000012;
- writel(val, fep->hwp + FEC_ECNTRL);
+ fec_writel(val, fep->hwp + FEC_ECNTRL);
}
} else
- writel(2, fep->hwp + FEC_ECNTRL);
+ fec_writel(2, fep->hwp + FEC_ECNTRL);
#else
/* And last, enable the transmit and receive processing */
- writel(2, fep->hwp + FEC_ECNTRL);
+ fec_writel(2, fep->hwp + FEC_ECNTRL);
#endif
- writel(0, fep->hwp + FEC_R_DES_ACTIVE);
+ fec_writel(0, fep->hwp + FEC_R_DES_ACTIVE);
/* Enable interrupts we wish to service */
- writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+ fec_writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
}
static void
@@ -1458,21 +1464,22 @@ fec_stop(struct net_device *dev)
/* We cannot expect a graceful transmit stop without link !!! */
if (fep->link) {
- writel(1, fep->hwp + FEC_X_CNTRL); /* Graceful transmit stop */
+ /* Graceful transmit stop */
+ fec_writel(1, fep->hwp + FEC_X_CNTRL);
udelay(10);
- if (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_GRA))
+ if (!(fec_readl(fep->hwp + FEC_IEVENT) & FEC_ENET_GRA))
printk("fec_stop : Graceful transmit stop did not complete !\n");
}
/* Whack a reset. We should wait for this. */
- writel(1, fep->hwp + FEC_ECNTRL);
+ fec_writel(1, fep->hwp + FEC_ECNTRL);
udelay(10);
- writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
+ fec_writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
#ifdef CONFIG_FEC_1588
if (fep->ptimer_present)
fec_ptp_stop(fep->ptp_priv);
#endif
- writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+ fec_writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
}
static int __devinit

View file

@ -1,627 +0,0 @@
From 40563ab5aa698191dbd8a05fe6053aa790eee2a1 Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:46 +0800
Subject: [PATCH 26/52] Add RTC driver support for MCF5445x
On-chip RTC module support for MCF54451 and MCF54455.
Using internal 32K clock to drive the rtc module.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
drivers/rtc/Kconfig | 9 +
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-mcf.c | 583 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 593 insertions(+), 0 deletions(-)
create mode 100644 drivers/rtc/rtc-mcf.c
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -919,6 +919,15 @@ config RTC_DRV_MV
This driver can also be built as a module. If so, the module
will be called rtc-mv.
+config RTC_MCF
+ tristate "Freescale Coldfire Real Time Clock"
+ depends on COLDFIRE
+ help
+ If you say yes here you will get support for the on-chip Coldfire
+ Real-Time Clock.
+
+ If you build it as a module it will be call mcf-rtc.
+
config RTC_DRV_PS3
tristate "PS3 RTC"
depends on PPC_PS3
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -102,3 +102,4 @@ obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41
obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o
obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
+obj-$(CONFIG_RTC_MCF) += rtc-mcf.o
--- /dev/null
+++ b/drivers/rtc/rtc-mcf.c
@@ -0,0 +1,583 @@
+/*
+ * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Implementation based on rtc-mxc.c
+ * This file contains Real Time Clock interface for Linux.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/rtc.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/uaccess.h>
+#include <asm/mcfsim.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#ifdef readl
+#undef readl
+#endif
+
+#ifdef writel
+#undef writel
+#endif
+
+#define readl(addr) in_be32(addr)
+#define writel(val, addr) out_be32((addr), (val))
+
+#define RTC_INPUT_CLK_32768HZ 0x8000
+#define RTC_INPUT_CLK_32000HZ 0x7D00
+#define RTC_INPUT_CLK_38400HZ 0x9600
+#define RTC_INPUT_CLK_48000HZ 0xBB80
+
+#define PIT_ALL_ON (MCF_RTC_ISR_2HZ | MCF_RTC_ISR_SAM0 | MCF_RTC_ISR_SAM1 | \
+ MCF_RTC_ISR_SAM2 | MCF_RTC_ISR_SAM3 | MCF_RTC_ISR_SAM4 | \
+ MCF_RTC_ISR_SAM5 | MCF_RTC_ISR_SAM6 | MCF_RTC_ISR_SAM7)
+
+#define MAX_PIE_NUM 9
+#define MAX_PIE_FREQ 512
+const u32 PIE_BIT_DEF[MAX_PIE_NUM][2] = {
+ {2, MCF_RTC_ISR_2HZ},
+ {4, MCF_RTC_ISR_SAM0},
+ {8, MCF_RTC_ISR_SAM1},
+ {16, MCF_RTC_ISR_SAM2},
+ {32, MCF_RTC_ISR_SAM3},
+ {64, MCF_RTC_ISR_SAM4},
+ {128, MCF_RTC_ISR_SAM5},
+ {256, MCF_RTC_ISR_SAM6},
+ {MAX_PIE_FREQ, MCF_RTC_ISR_SAM7},
+};
+
+/* Those are the bits from a classic RTC we want to mimic */
+#define RTC_IRQF 0x80 /* any of the following 3 is active */
+#define RTC_PF 0x40 /* Periodic interrupt */
+#define RTC_AF 0x20 /* Alarm interrupt */
+#define RTC_UF 0x10 /* Update interrupt for 1Hz RTC */
+
+#define MCF_RTC_TIME 0
+#define MCF_RTC_ALARM 1
+
+struct rtc_plat_data {
+ struct rtc_device *rtc;
+ int irq;
+ unsigned int irqen;
+ int alrm_sec;
+ int alrm_min;
+ int alrm_hour;
+ int alrm_mday;
+};
+
+/*!
+ * @defgroup RTC Real Time Clock (RTC) Driver
+ */
+/*!
+ * @file rtc-mcf.c
+ * @brief Real Time Clock interface
+ *
+ * This file contains Real Time Clock interface for Linux.
+ *
+ * @ingroup RTC
+ */
+
+#define RTC_VERSION "0.1"
+
+static u32 rtc_freq = 2; /* minimun value for PIE */
+static unsigned long rtc_status;
+
+static struct rtc_time g_rtc_alarm = {
+ .tm_year = 0,
+ .tm_mon = 0,
+ .tm_mday = 0,
+ .tm_hour = 0,
+ .tm_mon = 0,
+ .tm_sec = 0,
+};
+
+static DEFINE_SPINLOCK(rtc_lock);
+
+/*!
+ * This function is used to obtain the RTC time or the alarm value in
+ * second.
+ *
+ * @param time_alarm use MCF_RTC_TIME for RTC time value;
+ * MCF_RTC_ALARM for alarm value
+ *
+ * @return The RTC time or alarm time in second.
+ */
+static u32 get_alarm_or_time(struct device *dev, int time_alarm)
+{
+ u32 day, hr, min, sec, hr_min;
+
+ if (time_alarm == MCF_RTC_TIME) {
+ day = MCF_RTC_DAYS_DAYS(readl(MCF_RTC_DAYS));
+ hr_min = readl(MCF_RTC_HOURMIN);
+ sec = MCF_RTC_SECONDS_SECONDS(readl(MCF_RTC_SECONDS));
+ } else if (time_alarm == MCF_RTC_ALARM) {
+ day = MCF_RTC_ALRM_DAY_DAYS(readl(MCF_RTC_ALRM_DAY));
+ hr_min = readl(MCF_RTC_ALRM_HM);
+ sec = MCF_RTC_ALRM_SEC_SECONDS(readl(MCF_RTC_ALRM_SEC));
+ } else {
+ panic("wrong value for time_alarm=%d\n", time_alarm);
+ }
+
+ hr = (hr_min >> 8) & 0x001F;
+ min = hr_min & 0x003F;
+
+ return (((day * 24 + hr) * 60) + min) * 60 + sec;
+}
+
+/*!
+ * This function sets the RTC alarm value or the time value.
+ *
+ * @param time_alarm the new alarm value to be updated in the RTC
+ * @param time use MCF_RTC_TIME for RTC time value;
+ * MCF_RTC_ALARM for alarm value
+ */
+static void set_alarm_or_time(struct device *dev, int time_alarm, u32 time)
+{
+ u32 day, hr, min, sec, temp;
+
+ day = time / 86400;
+ time -= day * 86400;
+ /* time is within a day now */
+ hr = time / 3600;
+ time -= hr * 3600;
+ /* time is within an hour now */
+ min = time / 60;
+ sec = time - min * 60;
+
+ temp = (hr << 8) + min;
+
+ if (time_alarm == MCF_RTC_TIME) {
+ writel(day, MCF_RTC_DAYS);
+ writel(sec, MCF_RTC_SECONDS);
+ writel(temp, MCF_RTC_HOURMIN);
+ } else if (time_alarm == MCF_RTC_ALARM) {
+ writel(day, MCF_RTC_ALRM_DAY);
+ writel(sec, MCF_RTC_ALRM_SEC);
+ writel(temp, MCF_RTC_ALRM_HM);
+ } else {
+ panic("wrong value for time_alarm=%d\n", time_alarm);
+ }
+}
+
+/*!
+ * This function updates the RTC alarm registers and then clears all the
+ * interrupt status bits.
+ *
+ * @param alrm the new alarm value to be updated in the RTC
+ *
+ * @return 0 if successful; non-zero otherwise.
+ */
+static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
+{
+ struct rtc_time alarm_tm, now_tm;
+ unsigned long now, time;
+ int ret;
+
+ now = get_alarm_or_time(dev, MCF_RTC_TIME);
+ rtc_time_to_tm(now, &now_tm);
+ alarm_tm.tm_year = now_tm.tm_year;
+ alarm_tm.tm_mon = now_tm.tm_mon;
+ alarm_tm.tm_mday = now_tm.tm_mday;
+ alarm_tm.tm_hour = alrm->tm_hour;
+ alarm_tm.tm_min = alrm->tm_min;
+ alarm_tm.tm_sec = alrm->tm_sec;
+ rtc_tm_to_time(&now_tm, &now);
+ rtc_tm_to_time(&alarm_tm, &time);
+ if (time < now) {
+ time += 60 * 60 * 24;
+ rtc_time_to_tm(time, &alarm_tm);
+ }
+ ret = rtc_tm_to_time(&alarm_tm, &time);
+
+ /* clear all the interrupt status bits */
+ writel(readl(MCF_RTC_ISR), MCF_RTC_ISR);
+
+ set_alarm_or_time(dev, MCF_RTC_ALARM, time);
+
+ return ret;
+}
+
+/*!
+ * This function is the RTC interrupt service routine.
+ *
+ * @param irq RTC IRQ number
+ * @param dev_id device ID which is not used
+ *
+ * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
+ */
+static irqreturn_t mcf_rtc_interrupt(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ u32 status, events = 0;
+
+ spin_lock(&rtc_lock);
+
+ /* clear interrupt sources */
+ status = readl(MCF_RTC_ISR) & readl(MCF_RTC_IER);
+ writel(status, MCF_RTC_ISR);
+
+ /* clear alarm interrupt if it has occurred */
+ if (status & MCF_RTC_ISR_ALM)
+ status &= ~MCF_RTC_ISR_ALM;
+
+ /* update irq data & counter */
+ if (status & MCF_RTC_ISR_ALM)
+ events |= (RTC_AF | RTC_IRQF);
+ if (status & MCF_RTC_ISR_1HZ)
+ events |= (RTC_UF | RTC_IRQF);
+ if (status & PIT_ALL_ON)
+ events |= (RTC_PF | RTC_IRQF);
+
+ if ((status & MCF_RTC_ISR_ALM) && rtc_valid_tm(&g_rtc_alarm))
+ rtc_update_alarm(&pdev->dev, &g_rtc_alarm);
+
+ spin_unlock(&rtc_lock);
+ rtc_update_irq(pdata->rtc, 1, events);
+ return IRQ_HANDLED;
+}
+
+/*!
+ * clear all interrupts and release the IRQ
+ */
+static void mcf_rtc_release(struct device *dev)
+{
+ spin_lock_irq(&rtc_lock);
+ writel(0, MCF_RTC_IER); /* Disable all rtc interrupts */
+ writel(0x0000FFBF, MCF_RTC_ISR); /* Clear all interrupt status */
+ spin_unlock_irq(&rtc_lock);
+ rtc_status = 0;
+}
+
+/*!
+ * This function is used to support some ioctl calls directly.
+ * Other ioctl calls are supported indirectly through the
+ * arm/common/rtctime.c file.
+ *
+ * @param cmd ioctl command as defined in include/linux/rtc.h
+ * @param arg value for the ioctl command
+ *
+ * @return 0 if successful or negative value otherwise.
+ */
+static int mcf_rtc_ioctl(struct device *dev, unsigned int cmd,
+ unsigned long arg)
+{
+ int i;
+
+ switch (cmd) {
+ case RTC_PIE_OFF:
+ writel((readl(MCF_RTC_IER) & ~PIT_ALL_ON), MCF_RTC_IER);
+ return 0;
+ case RTC_IRQP_SET:
+ if (arg < 2 || arg > MAX_PIE_FREQ || (arg % 2) != 0)
+ return -EINVAL; /* Also make sure a power of 2Hz */
+ if ((arg > 64) && (!capable(CAP_SYS_RESOURCE)))
+ return -EACCES;
+ rtc_freq = arg;
+ return 0;
+ case RTC_IRQP_READ:
+ return put_user(rtc_freq, (u32 *) arg);
+ case RTC_PIE_ON:
+ for (i = 0; i < MAX_PIE_NUM; i++) {
+ if (PIE_BIT_DEF[i][0] == rtc_freq)
+ break;
+ }
+ if (i == MAX_PIE_NUM)
+ return -EACCES;
+ spin_lock_irq(&rtc_lock);
+ writel((readl(MCF_RTC_IER) | PIE_BIT_DEF[i][1]), MCF_RTC_IER);
+ spin_unlock_irq(&rtc_lock);
+ return 0;
+ case RTC_AIE_OFF:
+ spin_lock_irq(&rtc_lock);
+ writel((readl(MCF_RTC_IER) & ~MCF_RTC_ISR_ALM), MCF_RTC_IER);
+ spin_unlock_irq(&rtc_lock);
+ return 0;
+
+ case RTC_AIE_ON:
+ spin_lock_irq(&rtc_lock);
+ writel((readl(MCF_RTC_IER) | MCF_RTC_ISR_ALM), MCF_RTC_IER);
+ spin_unlock_irq(&rtc_lock);
+ return 0;
+
+ case RTC_UIE_OFF: /* UIE is for the 1Hz interrupt */
+ spin_lock_irq(&rtc_lock);
+ writel((readl(MCF_RTC_IER) & ~MCF_RTC_ISR_1HZ), MCF_RTC_IER);
+ spin_unlock_irq(&rtc_lock);
+ return 0;
+
+ case RTC_UIE_ON:
+ spin_lock_irq(&rtc_lock);
+ writel((readl(MCF_RTC_IER) | MCF_RTC_ISR_1HZ), MCF_RTC_IER);
+ spin_unlock_irq(&rtc_lock);
+ return 0;
+ }
+ return -ENOIOCTLCMD;
+}
+
+/*!
+ * This function reads the current RTC time into tm in Gregorian date.
+ *
+ * @param tm contains the RTC time value upon return
+ *
+ * @return 0 if successful; non-zero otherwise.
+ */
+static int mcf_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ u32 val;
+
+ /* Avoid roll-over from reading the different registers */
+ do {
+ val = get_alarm_or_time(dev, MCF_RTC_TIME);
+ } while (val != get_alarm_or_time(dev, MCF_RTC_TIME));
+
+ rtc_time_to_tm(val, tm);
+ return 0;
+}
+
+/*!
+ * This function sets the internal RTC time based on tm in Gregorian date.
+ *
+ * @param tm the time value to be set in the RTC
+ *
+ * @return 0 if successful; non-zero otherwise.
+ */
+static int mcf_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ unsigned long time;
+ int ret;
+
+ ret = rtc_tm_to_time(tm, &time);
+ if (ret != 0)
+ return ret;
+
+ /* Avoid roll-over from reading the different registers */
+ do {
+ set_alarm_or_time(dev, MCF_RTC_TIME, time);
+ } while (time != get_alarm_or_time(dev, MCF_RTC_TIME));
+
+ return ret;
+}
+
+/*!
+ * This function reads the current alarm value into the passed in \b alrm
+ * argument. It updates the \b alrm's pending field value based on the whether
+ * an alarm interrupt occurs or not.
+ *
+ * @param alrm contains the RTC alarm value upon return
+ *
+ * @return 0 if successful; non-zero otherwise.
+ */
+static int mcf_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ rtc_time_to_tm(get_alarm_or_time(dev, MCF_RTC_ALARM), &alrm->time);
+ alrm->pending = ((readl(MCF_RTC_ISR) & MCF_RTC_ISR_ALM) != 0) ? 1 : 0;
+
+ return 0;
+}
+
+/*!
+ * This function sets the RTC alarm based on passed in alrm.
+ *
+ * @param alrm the alarm value to be set in the RTC
+ *
+ * @return 0 if successful; non-zero otherwise.
+ */
+static int mcf_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ int ret;
+
+ spin_lock_irq(&rtc_lock);
+ if (rtc_valid_tm(&alrm->time)) {
+ if (alrm->time.tm_sec > 59 ||
+ alrm->time.tm_hour > 23 || alrm->time.tm_min > 59) {
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = rtc_update_alarm(dev, &alrm->time);
+ } else {
+ ret = rtc_valid_tm(&alrm->time);
+ if (ret)
+ goto out;
+ ret = rtc_update_alarm(dev, &alrm->time);
+ }
+
+ if (ret == 0) {
+ memcpy(&g_rtc_alarm, &alrm->time, sizeof(struct rtc_time));
+
+ if (alrm->enabled) {
+ writel((readl(MCF_RTC_IER) | MCF_RTC_ISR_ALM),
+ MCF_RTC_IER);
+ } else {
+ writel((readl(MCF_RTC_IER) & ~MCF_RTC_ISR_ALM),
+ MCF_RTC_IER);
+ }
+ }
+out:
+ spin_unlock_irq(&rtc_lock);
+
+ return ret;
+}
+
+/*!
+ * This function is used to provide the content for the /proc/driver/rtc
+ * file.
+ *
+ * @param buf the buffer to hold the information that the driver
+ * wants to write
+ *
+ * @return The number of bytes written into the rtc file.
+ */
+static int mcf_rtc_proc(struct device *dev, struct seq_file *sq)
+{
+ char *p = sq->buf;
+
+ p += sprintf(p, "alarm_IRQ\t: %s\n",
+ (((readl(MCF_RTC_IER)) & MCF_RTC_ISR_ALM) !=
+ 0) ? "yes" : "no");
+ p += sprintf(p, "update_IRQ\t: %s\n",
+ (((readl(MCF_RTC_IER)) & MCF_RTC_ISR_1HZ) !=
+ 0) ? "yes" : "no");
+ p += sprintf(p, "periodic_IRQ\t: %s\n",
+ (((readl(MCF_RTC_IER)) & PIT_ALL_ON) !=
+ 0) ? "yes" : "no");
+ p += sprintf(p, "periodic_freq\t: %d\n", rtc_freq);
+
+ return p - (sq->buf);
+}
+
+/*!
+ * The RTC driver structure
+ */
+static struct rtc_class_ops mcf_rtc_ops = {
+ .ioctl = mcf_rtc_ioctl,
+ .read_time = mcf_rtc_read_time,
+ .set_time = mcf_rtc_set_time,
+ .read_alarm = mcf_rtc_read_alarm,
+ .set_alarm = mcf_rtc_set_alarm,
+ .proc = mcf_rtc_proc,
+};
+
+static int __devinit mcf_rtc_probe(struct platform_device *pdev)
+{
+ struct timespec tv;
+ struct rtc_device *rtc;
+ struct rtc_plat_data *pdata = NULL;
+ u32 ret = 0;
+
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+ /* External clock is hard wired to 32768Hz.
+ * Clock settings 32K, 38.4K and 48K are defined above. */
+#if defined(CONFIG_M5227x) | defined(CONFIG_M5445X)
+ writel(0, MCF_RTC_GOCU);
+ writel(RTC_INPUT_CLK_32768HZ, MCF_RTC_GOCL);
+#endif
+ /* Configure and enable the RTC */
+ pdata->irq = MCFINT_VECBASE + MCFINT_RTC;
+ if (request_irq(pdata->irq, mcf_rtc_interrupt, IRQF_DISABLED,
+ pdev->name, pdev) < 0) {
+ dev_warn(&pdev->dev, "interrupt not available.\n");
+ pdata->irq = -1;
+ }
+
+ if (test_and_set_bit(1, &rtc_status))
+ return -EBUSY;
+
+ rtc = rtc_device_register(pdev->name, &pdev->dev, &mcf_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ ret = PTR_ERR(rtc);
+ if (pdata->irq >= 0)
+ free_irq(pdata->irq, pdev);
+ kfree(pdata);
+ return ret;
+ }
+ pdata->rtc = rtc;
+ platform_set_drvdata(pdev, pdata);
+
+ tv.tv_nsec = 0;
+ tv.tv_sec = get_alarm_or_time(&pdev->dev, MCF_RTC_TIME);
+
+#ifdef CONFIG_M5301x
+ writel(RTC_INPUT_CLK_32768HZ, MCF_RTC_GOC);
+ writel(0x08, MCF_RTC_OCEN);
+#endif
+ writeb(4, MCFSIM_ICR_RTC);
+
+ writel(MCF_RTC_IER_1HZ, MCF_RTC_IER); /* Unmask the 1Hz timer */
+
+ writel(MCF_RTC_CR_EN, MCF_RTC_CR);
+ if ((readl(MCF_RTC_CR) & MCF_RTC_CR_EN) == 0) {
+ printk(KERN_ALERT "RTC Hardware couldn't be enabled!\n");
+ return -EPERM;
+ }
+
+ printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION);
+ return ret;
+}
+
+static int __devexit mcf_rtc_remove(struct platform_device *pdev)
+{
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ rtc_device_unregister(pdata->rtc);
+ if (pdata->irq >= 0)
+ free_irq(pdata->irq, pdev);
+ kfree(pdata);
+ mcf_rtc_release(NULL);
+ return 0;
+}
+
+/*!
+ * Contains pointers to the power management callback functions.
+ */
+MODULE_ALIAS("mcf-rtc");
+static struct platform_driver mcf_rtc_driver = {
+ .driver = {
+ .name = "mcf-rtc",
+ .owner = THIS_MODULE,
+ },
+ .probe = mcf_rtc_probe,
+ .remove = __devexit_p(mcf_rtc_remove),
+};
+
+/*!
+ * This function creates the /proc/driver/rtc file and registers the device RTC
+ * in the /dev/misc directory. It also reads the RTC value from external source
+ * and setup the internal RTC properly.
+ *
+ * @return -1 if RTC is failed to initialize; 0 is successful.
+ */
+static int __init mcf_rtc_init(void)
+{
+ return platform_driver_register(&mcf_rtc_driver);
+}
+
+/*!
+ * This function removes the /proc/driver/rtc file and un-registers the
+ * device RTC from the /dev/misc directory.
+ */
+static void __exit mcf_rtc_exit(void)
+{
+ platform_driver_unregister(&mcf_rtc_driver);
+
+}
+
+module_init(mcf_rtc_init);
+module_exit(mcf_rtc_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Real Time Clock Driver (MCF)");
+MODULE_LICENSE("GPL");

View file

@ -1,681 +0,0 @@
From 6462d09dad154b69ea6180c0acb2d009627ff1be Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:46 +0800
Subject: [PATCH 27/52] Add RTC driver support on MCF5441x platform
Support on-chip robust-RTC module on MCF5441x platform.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
drivers/rtc/Kconfig | 9 +
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-m5441x.c | 638 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 648 insertions(+), 0 deletions(-)
create mode 100644 drivers/rtc/rtc-m5441x.c
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -928,6 +928,15 @@ config RTC_MCF
If you build it as a module it will be call mcf-rtc.
+config RTC_M5441X
+ tristate "Freescale Coldfire M5441X platform Real Time Clock"
+ depends on COLDFIRE
+ help
+ If you say yes here you will get support for the on-chip Coldfire
+ Real-Time Clock for mcf5441x platform.
+
+ If you build it as a module it will be call rtc-m5441x.
+
config RTC_DRV_PS3
tristate "PS3 RTC"
depends on PPC_PS3
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -103,3 +103,4 @@ obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm83
obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
obj-$(CONFIG_RTC_MCF) += rtc-mcf.o
+obj-$(CONFIG_RTC_M5441X) += rtc-m5441x.o
--- /dev/null
+++ b/drivers/rtc/rtc-m5441x.c
@@ -0,0 +1,638 @@
+/*
+ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Lanttor.Guo@freescale.com
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ * Implementation based on rtc-mcf.c
+ */
+
+/*
+ * RTC Real Time Clock (RTC) Driver
+ *
+ * @file rtc-m5441x.c
+ * @brief Real Time Clock interface
+ *
+ * This file contains Real Time Clock interface for Linux.
+ *
+ */
+#include <linux/rtc.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/uaccess.h>
+#include <asm/mcfsim.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#ifdef readw
+#undef readw
+#endif
+
+#ifdef writew
+#undef writew
+#endif
+
+#define readw(addr) in_be16(addr)
+#define writew(val, addr) out_be16((addr), (val))
+
+
+#define PIT_ALL_ON (MCF_RTC_ISR_2HZ | MCF_RTC_ISR_SAM0 | MCF_RTC_ISR_SAM1 | \
+ MCF_RTC_ISR_SAM2 | MCF_RTC_ISR_SAM3 | MCF_RTC_ISR_SAM4 | \
+ MCF_RTC_ISR_SAM5 | MCF_RTC_ISR_SAM6 | MCF_RTC_ISR_SAM7)
+
+#define MAX_PIE_NUM 9
+#define MAX_PIE_FREQ 512
+const u32 PIE_BIT_DEF[MAX_PIE_NUM][2] = {
+ {2, MCF_RTC_ISR_2HZ},
+ {4, MCF_RTC_ISR_SAM0},
+ {8, MCF_RTC_ISR_SAM1},
+ {16, MCF_RTC_ISR_SAM2},
+ {32, MCF_RTC_ISR_SAM3},
+ {64, MCF_RTC_ISR_SAM4},
+ {128, MCF_RTC_ISR_SAM5},
+ {256, MCF_RTC_ISR_SAM6},
+ {MAX_PIE_FREQ, MCF_RTC_ISR_SAM7},
+};
+
+/* Those are the bits from a classic RTC we want to mimic */
+#define RTC_IRQF 0x80 /* any of the following 3 is active */
+#define RTC_PF 0x40 /* Periodic interrupt */
+#define RTC_AF 0x20 /* Alarm interrupt */
+#define RTC_UF 0x10 /* Update interrupt for 1Hz RTC */
+
+#define MCF_RTC_TIME 0
+#define MCF_RTC_ALARM 1
+
+struct rtc_plat_data {
+ struct rtc_device *rtc;
+ int irq;
+ unsigned int irqen;
+ int alrm_sec;
+ int alrm_min;
+ int alrm_hour;
+ int alrm_mday;
+};
+
+static const int year_cal_basic = 2112;
+
+#define RTC_VERSION "0.1"
+
+static u32 rtc_freq = 2; /* minimun value for PIE */
+static unsigned long rtc_status;
+
+static struct rtc_time g_rtc_alarm = {
+ .tm_year = 0,
+ .tm_mon = 0,
+ .tm_mday = 0,
+ .tm_hour = 0,
+ .tm_mon = 0,
+ .tm_sec = 0,
+};
+
+static DEFINE_SPINLOCK(rtc_lock);
+
+
+/*
+ * This funciton is used to disable RTC register write protection
+ */
+static void disable_register_write_protection(void)
+{
+ if (readw(MCF_RTC_SR) & MCF_RTC_SR_WPE) {
+ writew(0x0000, MCF_RTC_CR);
+ writew(0x0001, MCF_RTC_CR);
+ writew(0x0003, MCF_RTC_CR);
+ writew(0x0002, MCF_RTC_CR);
+ }
+
+}
+
+/*
+ * This function is used to obtain the RTC time or the alarm value in
+ * second.
+ *
+ * @param time_alarm use MCF_RTC_TIME for RTC time value;
+ * MCF_RTC_ALARM for alarm value
+ *
+ * @return The RTC time or alarm time in second.
+ */
+static u32 get_alarm_or_time(struct device *dev, int time_alarm,
+ struct rtc_time *tm)
+{
+ dev_dbg(dev, "debug function %s()!\n", __func__);
+
+ if (time_alarm == MCF_RTC_TIME) {
+ /*check register information */
+ dev_dbg(dev, "RTC_YEARMON:0x%x,RTC_DAYS:0x%x,RTC_HOURMIN:0x%x,"
+ "RTC_SECONDS:0x%x\n", readw(MCF_RTC_YEARMON),
+ readw(MCF_RTC_DAYS), readw(MCF_RTC_HOURMIN),
+ readw(MCF_RTC_SECONDS));
+
+ /* get year */
+ tm->tm_year = year_cal_basic +
+ (char)(MCF_RTC_YEARMON_YEAR_RD(readw(MCF_RTC_YEARMON)));
+ /* get month */
+ tm->tm_mon =
+ MCF_RTC_YEARMON_MON_RD(readw(MCF_RTC_YEARMON)) - 1;
+ /* get month day */
+ tm->tm_mday = MCF_RTC_DAYS_DAY_RD(readw(MCF_RTC_DAYS));
+ /* get year day */
+ tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon,
+ tm->tm_year);
+ /* year minus 1900 */
+ tm->tm_year = tm->tm_year - 1900;
+ /* get week day */
+ tm->tm_wday = MCF_RTC_DAYS_DAYWEEK_RD(readw(MCF_RTC_DAYS));
+ /* get hours */
+ tm->tm_hour =
+ MCF_RTC_HOURMIN_HOURS_RD(readw(MCF_RTC_HOURMIN));
+ /* get minutes */
+ tm->tm_min =
+ MCF_RTC_HOURMIN_MINUTES_RD(readw(MCF_RTC_HOURMIN));
+ /* get seconds */
+ tm->tm_sec =
+ MCF_RTC_SECONDS_SECONDS_RD(readw(MCF_RTC_SECONDS));
+ /* no day saving time */
+ tm->tm_isdst = -1;
+
+ /* check rtc_tm fileds information */
+ dev_dbg(dev, "RTC TIME --> year:%d,yday:%d,mon:%d,mday:%d,"
+ "wday:%d,hour:%d,min:%d,sec:%d\n", tm->tm_year,
+ tm->tm_yday, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ } else if (time_alarm == MCF_RTC_ALARM) {
+ tm->tm_year = year_cal_basic +
+ (char)MCF_RTC_YEARMON_YEAR_RD
+ (readw(MCF_RTC_ALRM_YRMON));
+ tm->tm_mon =
+ MCF_RTC_YEARMON_MON_RD(readw(MCF_RTC_ALRM_YRMON)) - 1;
+ tm->tm_mday = MCF_RTC_DAYS_DAY_RD(readw(MCF_RTC_ALRM_DAYS));
+ tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon,
+ tm->tm_year);
+ tm->tm_year = tm->tm_year - 1900;
+ tm->tm_wday =
+ MCF_RTC_DAYS_DAYWEEK_RD(readw(MCF_RTC_ALRM_DAYS));
+ tm->tm_hour =
+ MCF_RTC_HOURMIN_HOURS_RD(readw(MCF_RTC_ALRM_HM));
+ tm->tm_min =
+ MCF_RTC_HOURMIN_MINUTES_RD(readw(MCF_RTC_ALRM_HM));
+ tm->tm_sec =
+ MCF_RTC_SECONDS_SECONDS_RD(readw(MCF_RTC_ALRM_SEC));
+ tm->tm_isdst = -1;
+
+ /* debug information */
+ dev_dbg(dev, "RTC ALARM --> year:%d,yday:%d,mon:%d,mday:%d,"
+ "wday:%d,hour:%d,min:%d,sec:%d\n", tm->tm_year,
+ tm->tm_yday, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ } else {
+ panic("wrong value for time_alarm=%d\n", time_alarm);
+ }
+
+ return 0;
+}
+
+/*
+ * This function sets the RTC alarm value or the time value.
+ *
+ * @param time_alarm the new alarm value to be updated in the RTC
+ * @param time use MCF_RTC_TIME for RTC time value;
+ * MCF_RTC_ALARM for alarm value
+ */
+static void set_alarm_or_time(struct device *dev, int time_alarm,
+ struct rtc_time *tm)
+{
+ char year;
+
+ dev_dbg(dev, "debug function %s()!\n", __func__);
+
+ /* wirte enable setting */
+ disable_register_write_protection();
+
+ if (time_alarm == MCF_RTC_TIME) {
+ /* check rtc_time fields information */
+ dev_dbg(dev, "RTC TIME --> year:%d,yday:%d,mon:%d,mday:%d,"
+ "wday:%d,hour:%d,min:%d,sec:%d\n", tm->tm_year,
+ tm->tm_yday, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ year = ((tm->tm_year + 1900) - year_cal_basic);
+ /* write RTC_YEARMON register */
+ writew((year << 8) | (tm->tm_mon + 1), MCF_RTC_YEARMON);
+
+ /* write RTC_DAYS register */
+ writew(MCF_RTC_DAYS_DAYWEEK_SET(tm->tm_wday) |
+ MCF_RTC_DAYS_DAY_SET(tm->tm_mday), MCF_RTC_DAYS);
+
+ /* write RTC_HOURMIN register */
+ writew(MCF_RTC_HOURMIN_HOURS_SET(tm->tm_hour) |
+ MCF_RTC_HOURMIN_MINUTES_SET(tm->tm_min),
+ MCF_RTC_HOURMIN);
+
+ /* write RTC_SECONDS register */
+ writew(MCF_RTC_SECONDS_SECONDS_SET
+ (tm->tm_sec), MCF_RTC_SECONDS);
+
+ /* debug information */
+ dev_dbg(dev, "RTC_YEARMON:0x%x, RTC_DAYS:0x%x, "
+ "RTC_HOURMIN:0x%x, RTC_SECONDS:0x%x\n",
+ readw(MCF_RTC_YEARMON), readw(MCF_RTC_DAYS),
+ readw(MCF_RTC_HOURMIN), readw(MCF_RTC_SECONDS));
+ } else if (time_alarm == MCF_RTC_ALARM) {
+
+ year = ((tm->tm_year + 1900) - year_cal_basic);
+ /* write RTC_YEARMON register */
+ writew((year << 8) | (tm->tm_mon + 1), MCF_RTC_ALRM_YRMON);
+
+ /* write RTC_DAYS register */
+ writew(MCF_RTC_DAYS_DAYWEEK_SET(tm->tm_wday) |
+ MCF_RTC_DAYS_DAY_SET(tm->tm_mday), MCF_RTC_ALRM_DAYS);
+
+ /* write RTC_HOURMIN register */
+ writew(MCF_RTC_HOURMIN_HOURS_SET(tm->tm_hour) |
+ MCF_RTC_HOURMIN_MINUTES_SET(tm->tm_min),
+ MCF_RTC_ALRM_HM);
+
+ /* write RTC_SECONDS register */
+ writew(MCF_RTC_SECONDS_SECONDS_SET
+ (tm->tm_sec), MCF_RTC_ALRM_SEC);
+
+ /* debug information */
+ dev_dbg(dev, "ALRM_YRMON:0x%x,ALRM_DAYS:0x%x,ALRM_HM:0x%x,"
+ "ALRM_SEC:0x%x\n", readw(MCF_RTC_ALRM_YRMON),
+ readw(MCF_RTC_ALRM_DAYS), readw(MCF_RTC_ALRM_HM),
+ readw(MCF_RTC_ALRM_SEC));
+ } else {
+ panic("wrong value for time_alarm=%d\n", time_alarm);
+ }
+}
+
+/*!
+ * This function updates the RTC alarm registers and then clears all the
+ * interrupt status bits.
+ *
+ * @param alrm the new alarm value to be updated in the RTC
+ *
+ * @return 0 if successful; non-zero otherwise.
+ */
+static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
+{
+ /* clear all the interrupt status bits */
+ disable_register_write_protection();
+
+ writew(readw(MCF_RTC_ISR), MCF_RTC_ISR);
+
+ set_alarm_or_time(dev, MCF_RTC_ALARM, alrm);
+
+ return 0;
+}
+
+/*!
+ * This function is the RTC interrupt service routine.
+ *
+ * @param irq RTC IRQ number
+ * @param dev_id device ID which is not used
+ *
+ * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
+ */
+static irqreturn_t mcf_rtc_interrupt(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ u16 status = 0;
+ u32 events = 0;
+
+ spin_lock(&rtc_lock);
+
+ /* clear interrupt sources */
+ status = readw(MCF_RTC_ISR) & readw(MCF_RTC_IER);
+
+ disable_register_write_protection();
+
+ writew(status, MCF_RTC_ISR);
+
+ /* clear alarm interrupt if it has occurred */
+ if (status & MCF_RTC_ISR_ALM)
+ status &= ~MCF_RTC_ISR_ALM;
+
+ /* update irq data & counter */
+ if (status & MCF_RTC_ISR_ALM)
+ events |= (RTC_AF | RTC_IRQF);
+ if (status & MCF_RTC_ISR_1HZ)
+ events |= (RTC_UF | RTC_IRQF);
+ if (status & PIT_ALL_ON)
+ events |= (RTC_PF | RTC_IRQF);
+
+ if ((status & MCF_RTC_ISR_ALM) && rtc_valid_tm(&g_rtc_alarm))
+ rtc_update_alarm(&pdev->dev, &g_rtc_alarm);
+
+ spin_unlock(&rtc_lock);
+ rtc_update_irq(pdata->rtc, 1, events);
+ return IRQ_HANDLED;
+}
+
+/*!
+ * clear all interrupts and release the IRQ
+ */
+static void mcf_rtc_release(struct device *dev)
+{
+ spin_lock_irq(&rtc_lock);
+
+ disable_register_write_protection();
+
+ writew(0, MCF_RTC_IER); /* Disable all rtc interrupts */
+ writew(readw(MCF_RTC_ISR), MCF_RTC_ISR);
+ spin_unlock_irq(&rtc_lock);
+ rtc_status = 0;
+}
+
+/*!
+ * This function is used to support some ioctl calls directly.
+ * Other ioctl calls are supported indirectly through the
+ * arm/common/rtctime.c file.
+ *
+ * @param cmd ioctl command as defined in include/linux/rtc.h
+ * @param arg value for the ioctl command
+ *
+ * @return 0 if successful or negative value otherwise.
+ */
+static int mcf_rtc_ioctl(struct device *dev, unsigned int cmd,
+ unsigned long arg)
+{
+ int i;
+
+ disable_register_write_protection();
+
+ switch (cmd) {
+ case RTC_PIE_OFF:
+ writew((readw(MCF_RTC_IER) & ~PIT_ALL_ON), MCF_RTC_IER);
+ return 0;
+ case RTC_IRQP_SET:
+ if (arg < 2 || arg > MAX_PIE_FREQ || (arg % 2) != 0)
+ return -EINVAL; /* Also make sure a power of 2Hz */
+ if ((arg > 64) && (!capable(CAP_SYS_RESOURCE)))
+ return -EACCES;
+ rtc_freq = arg;
+ return 0;
+ case RTC_IRQP_READ:
+ return put_user(rtc_freq, (u32 *) arg);
+ case RTC_PIE_ON:
+ for (i = 0; i < MAX_PIE_NUM; i++) {
+ if (PIE_BIT_DEF[i][0] == rtc_freq)
+ break;
+ }
+ if (i == MAX_PIE_NUM)
+ return -EACCES;
+ spin_lock_irq(&rtc_lock);
+ writew((readw(MCF_RTC_IER) | PIE_BIT_DEF[i][1]), MCF_RTC_IER);
+ spin_unlock_irq(&rtc_lock);
+ return 0;
+ case RTC_AIE_OFF:
+ spin_lock_irq(&rtc_lock);
+ writew((readw(MCF_RTC_IER) & ~MCF_RTC_ISR_ALM), MCF_RTC_IER);
+ spin_unlock_irq(&rtc_lock);
+ return 0;
+
+ case RTC_AIE_ON:
+ spin_lock_irq(&rtc_lock);
+ writew((readw(MCF_RTC_IER) | MCF_RTC_ISR_ALM), MCF_RTC_IER);
+ spin_unlock_irq(&rtc_lock);
+ return 0;
+
+ case RTC_UIE_OFF: /* UIE is for the 1Hz interrupt */
+ spin_lock_irq(&rtc_lock);
+ writew((readw(MCF_RTC_IER) & ~MCF_RTC_ISR_1HZ), MCF_RTC_IER);
+ spin_unlock_irq(&rtc_lock);
+ return 0;
+
+ case RTC_UIE_ON:
+ spin_lock_irq(&rtc_lock);
+ writew((readw(MCF_RTC_IER) | MCF_RTC_ISR_1HZ), MCF_RTC_IER);
+ spin_unlock_irq(&rtc_lock);
+ return 0;
+ }
+ return -ENOIOCTLCMD;
+}
+
+/*!
+ * This function reads the current RTC time into tm in Gregorian date.
+ *
+ * @param tm contains the RTC time value upon return
+ *
+ * @return 0 if successful; non-zero otherwise.
+ */
+static int mcf_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ do {
+ get_alarm_or_time(dev, MCF_RTC_TIME, tm);
+ } while (0);
+
+ return 0;
+}
+
+/*!
+ * This function sets the internal RTC time based on tm in Gregorian date.
+ *
+ * @param tm the time value to be set in the RTC
+ *
+ * @return 0 if successful; non-zero otherwise.
+ */
+static int mcf_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ do {
+ set_alarm_or_time(dev, MCF_RTC_TIME, tm);
+ } while (0);
+
+ return 0;
+}
+
+/*!
+ * This function reads the current alarm value into the passed in \b alrm
+ * argument. It updates the \b alrm's pending field value based on the whether
+ * an alarm interrupt occurs or not.
+ *
+ * @param alrm contains the RTC alarm value upon return
+ *
+ * @return 0 if successful; non-zero otherwise.
+ */
+static int mcf_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ do {
+ get_alarm_or_time(dev, MCF_RTC_ALARM, &alrm->time);
+ } while (0);
+
+ alrm->pending = ((readw(MCF_RTC_ISR) & MCF_RTC_ISR_ALM) != 0) ? 1 : 0;
+
+ return 0;
+}
+
+/*!
+ * This function sets the RTC alarm based on passed in alrm.
+ *
+ * @param alrm the alarm value to be set in the RTC
+ *
+ * @return 0 if successful; non-zero otherwise.
+ */
+static int mcf_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ int ret;
+
+ spin_lock_irq(&rtc_lock);
+
+ disable_register_write_protection();
+
+ if (rtc_valid_tm(&alrm->time)) {
+ if (alrm->time.tm_sec > 59 ||
+ alrm->time.tm_hour > 23 || alrm->time.tm_min > 59) {
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = rtc_update_alarm(dev, &alrm->time);
+ } else {
+ ret = rtc_valid_tm(&alrm->time);
+ if (ret)
+ goto out;
+ ret = rtc_update_alarm(dev, &alrm->time);
+ }
+
+ if (ret == 0) {
+ memcpy(&g_rtc_alarm, &alrm->time, sizeof(struct rtc_time));
+
+ if (alrm->enabled) {
+ writew((readw(MCF_RTC_IER) | MCF_RTC_ISR_ALM),
+ MCF_RTC_IER);
+ } else {
+ writew((readw(MCF_RTC_IER) & ~MCF_RTC_ISR_ALM),
+ MCF_RTC_IER);
+ }
+ }
+out:
+ spin_unlock_irq(&rtc_lock);
+
+ return ret;
+}
+
+/*!
+ * The RTC driver structure
+ */
+static struct rtc_class_ops mcf_rtc_ops = {
+ .ioctl = mcf_rtc_ioctl,
+ .read_time = mcf_rtc_read_time,
+ .set_time = mcf_rtc_set_time,
+ .read_alarm = mcf_rtc_read_alarm,
+ .set_alarm = mcf_rtc_set_alarm,
+};
+
+static int __devinit mcf_rtc_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc;
+ struct rtc_plat_data *pdata = NULL;
+ u32 ret = 0;
+
+ disable_register_write_protection();
+ /* Clear interrupt before request irq */
+ writew(0x0100, MCF_RTC_CR);
+ writew(0x0001, MCF_RTC_IER);
+
+ if (!(readw(MCF_RTC_CFG_DATA) & MCF_RTC_CFG_DATA_OSCEN))
+ writew(MCF_RTC_CFG_DATA_OSCEN, MCF_RTC_CFG_DATA);
+
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ pdata->irq = MCFINT_VECBASE + MCFINT_RTC;
+ if (request_irq(pdata->irq, mcf_rtc_interrupt, IRQF_DISABLED,
+ pdev->name, pdev) < 0) {
+ dev_warn(&pdev->dev, "interrupt not available.\n");
+ pdata->irq = -1;
+ }
+
+ if (test_and_set_bit(1, &rtc_status))
+ return -EBUSY;
+
+ rtc = rtc_device_register(pdev->name, &pdev->dev, &mcf_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ ret = PTR_ERR(rtc);
+ if (pdata->irq >= 0)
+ free_irq(pdata->irq, pdev);
+ kfree(pdata);
+ return ret;
+ }
+ pdata->rtc = rtc;
+ platform_set_drvdata(pdev, pdata);
+
+ dev_dbg(&pdev->dev, "RTC_CR:0x%x, RTC_SR:0x%x\n", readw(MCF_RTC_CR),
+ readw(MCF_RTC_SR));
+
+ printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION);
+ return ret;
+}
+
+static int __devexit mcf_rtc_remove(struct platform_device *pdev)
+{
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ rtc_device_unregister(pdata->rtc);
+ if (pdata->irq >= 0)
+ free_irq(pdata->irq, pdev);
+ kfree(pdata);
+ mcf_rtc_release(NULL);
+ return 0;
+}
+
+/*!
+ * Contains pointers to the power management callback functions.
+ */
+MODULE_ALIAS("rtc-m5441x");
+static struct platform_driver mcf_rtc_driver = {
+ .driver = {
+ .name = "rtc-m5441x",
+ .owner = THIS_MODULE,
+ },
+ .probe = mcf_rtc_probe,
+ .remove = __devexit_p(mcf_rtc_remove),
+};
+
+/*!
+ * This function creates the /proc/driver/rtc file and registers the device RTC
+ * in the /dev/misc directory. It also reads the RTC value from external source
+ * and setup the internal RTC properly.
+ *
+ * @return -1 if RTC is failed to initialize; 0 is successful.
+ */
+static int __init mcf_rtc_init(void)
+{
+ return platform_driver_register(&mcf_rtc_driver);
+}
+
+/*!
+ * This function removes the /proc/driver/rtc file and un-registers the
+ * device RTC from the /dev/misc directory.
+ */
+static void __exit mcf_rtc_exit(void)
+{
+ platform_driver_unregister(&mcf_rtc_driver);
+
+}
+
+module_init(mcf_rtc_init);
+module_exit(mcf_rtc_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Real Time Clock Driver (MCF)");
+MODULE_LICENSE("GPL V2");

View file

@ -1,195 +0,0 @@
From d1b6aa1480c937e326bef99746299cd004a51f28 Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:46 +0800
Subject: [PATCH 28/52] Add SD/MMC/SDIO over SPI support for MCF54451 and MCF54418
Add SD/MMC/SDIO over SPI support for MCF54451 and MCF54418.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
drivers/mmc/core/sdio.c | 9 +++++-
drivers/mmc/host/Kconfig | 35 +++++++++++++++++++++
drivers/mmc/host/mmc_spi.c | 73 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 116 insertions(+), 1 deletions(-)
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -566,8 +566,15 @@ static void mmc_sdio_detect(struct mmc_h
/*
* Just check if our card has been removed.
*/
+#if defined(M54451_SD_HW_DETECT)
+ {
+ unsigned char x;
+ err = mmc_io_rw_direct(host->card, 0, 0,
+ SDIO_FBR_BASE(0) + SDIO_FBR_CIS + 0, 0, &x);
+ }
+#else
err = mmc_select_card(host->card);
-
+#endif
mmc_release_host(host);
/*
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -368,6 +368,41 @@ config MMC_SPI
If unsure, or if your system has no SPI master driver, say N.
+config M54451_SD_HW_DETECT
+ tristate "use extern IRQ7 to detect SD/MMC card"
+ depends on MMC_SPI && M54451
+ default y
+ help
+ MMC/SD interface on 54551evb was over SPI. Enable this option will
+ use irq7 to dectect the card inserting/removing.
+
+config M5441X_SD_HW_DETECT
+ tristate "use extern IRQ to detect SD/MMC card"
+ depends on MMC_SPI && M5441X
+ help
+ MMC/SD interface on 54418evb was over SPI. Enable this option will
+ use irq7 or irq1 to dectect the card inserting/removing.
+
+choice
+ prompt "MMC/SD card detect "
+ depends on M5441X_SD_HW_DETECT
+
+config DETECT_USE_EXTERN_IRQ7
+ tristate "based extern IRQ7"
+ depends on M5441X_SD_HW_DETECT
+ help
+ MMC/SD cards using spi controller,
+ we use the extern irq7 to detect card.
+
+config DETECT_USE_EXTERN_IRQ1
+ tristate "based extern IRQ1"
+ depends on M5441X_SD_HW_DETECT
+ help
+ MMC/SD cards using spi controller,
+ we use the extern irq1 to detect card.
+
+endchoice
+
config MMC_S3C
tristate "Samsung S3C SD/MMC Card Interface support"
depends on ARCH_S3C2410
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -9,6 +9,10 @@
* (C) Copyright 2007, ATRON electronic GmbH,
* Jan Nikitenko <jan.nikitenko@gmail.com>
*
+ * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Modified for M54451EVB/M54418TWR boards.
+ * Shrek Wu <b16972@freescale.com>
+ * Jingchang Lu <b22599@freescale.com>
*
* 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
@@ -32,6 +36,14 @@
#include <linux/crc7.h>
#include <linux/crc-itu-t.h>
#include <linux/scatterlist.h>
+#if defined(CONFIG_M54451_SD_HW_DETECT)
+#include <asm/mcf5445x_eport.h>
+#include <asm/mcf5445x_intc.h>
+#include <asm/mcfsim.h>
+#elif defined(CONFIG_M5441X_SD_HW_DETECT)
+#include <asm/mcf5441x_eport.h>
+#include <asm/mcfsim.h>
+#endif
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h> /* for R1_SPI_* bit values */
@@ -268,6 +280,9 @@ static int mmc_spi_response_get(struct m
unsigned short rotator;
int i;
char tag[32];
+#if defined(CONFIG_M54451_SD_HW_DETECT) || defined(CONFIG_M5441X_SD_HW_DETECT)
+ u8 oldcp_value = 0;
+#endif
snprintf(tag, sizeof(tag), " ... CMD%d response SPI_%s",
cmd->opcode, maptype(cmd));
@@ -278,6 +293,9 @@ static int mmc_spi_response_get(struct m
* first byte. After STOP_TRANSMISSION command it may include
* two data bits, but otherwise it's all ones.
*/
+#if defined(CONFIG_M54451_SD_HW_DETECT) || defined(CONFIG_M5441X_SD_HW_DETECT)
+ oldcp_value = *cp;
+#endif
cp += 8;
while (cp < end && *cp == 0xff)
cp++;
@@ -310,6 +328,15 @@ static int mmc_spi_response_get(struct m
}
checkstatus:
+#if defined(CONFIG_M54451_SD_HW_DETECT) || defined(CONFIG_M5441X_SD_HW_DETECT)
+ if ((*cp == 0) && (oldcp_value == 0)) {
+ dev_dbg(&host->spi->dev, "NO CARD in the SD SOCKET, "
+ "new status %02x, old status %02x\n",
+ *cp, oldcp_value);
+ value = -EBADR;
+ goto done;
+ }
+#endif
bitshift = 0;
if (*cp & 0x80) {
/* Houston, we have an ugly card with a bit-shifted response */
@@ -1313,7 +1340,53 @@ mmc_spi_detect_irq(int irq, void *mmc)
struct mmc_spi_host *host = mmc_priv(mmc);
u16 delay_msec = max(host->pdata->detect_delay, (u16)100);
+#if defined(CONFIG_M54451_SD_HW_DETECT)
+ dev_dbg(&host->spi->dev, "mmc_spi_detect_irq "
+ "MCF_EPORT_EPPAR %x, MCF_EPORT_EPIER %x,"
+ "MCF_INTC0_ICR7 %x, MCF_GPIO_PAR_IRQ %x,"
+ "MCF_EPORT_EPDDR %x, MCF_EPORT_EPFR %x\n",
+ MCF_EPORT_EPPAR, MCF_EPORT_EPIER,
+ MCF_INTC0_ICR7, MCF_GPIO_PAR_IRQ,
+ MCF_EPORT_EPDDR, MCF_EPORT_EPFR);
+
+ MCF_EPORT_EPIER &= (~MCF_EPORT_EPIER_EPIE7);
+#elif defined(CONFIG_M5441X_SD_HW_DETECT)
+#if defined(CONFIG_DETECT_USE_EXTERN_IRQ1)
+ MCF_EPORT_EPIER = MCF_EPORT_EPIER & (~MCF_EPORT_EPIER_EPIE1);
+#elif defined(CONFIG_DETECT_USE_EXTERN_IRQ7)
+ MCF_EPORT_EPIER = MCF_EPORT_EPIER & (~MCF_EPORT_EPIER_EPIE7);
+#else
+ MCF_EPORT_EPIER = MCF_EPORT_EPIER & (~MCF_EPORT_EPIER_EPIE7);
+#endif
+#endif
mmc_detect_change(mmc, msecs_to_jiffies(delay_msec));
+#if defined(CONFIG_M54451_SD_HW_DETECT)
+ MCF_EPORT_EPPAR |= MCF_EPORT_EPPAR_EPPA7_BOTH;
+ MCF_EPORT_EPIER = MCF_EPORT_EPIER | MCF_EPORT_EPIER_EPIE7;
+ MCF_EPORT_EPFR |= MCF_EPORT_EPFR_EPF7;
+ dev_dbg(&host->spi->dev, "mmc_spi_detect_irq "
+ "MCF_EPORT_EPPAR %x, MCF_EPORT_EPIER %x,"
+ "MCF_INTC0_ICR7 %x, MCF_GPIO_PAR_IRQ %x,"
+ "MCF_EPORT_EPDDR %x, MCF_EPORT_EPFR %x\n",
+ MCF_EPORT_EPPAR, MCF_EPORT_EPIER,
+ MCF_INTC0_ICR7, MCF_GPIO_PAR_IRQ,
+ MCF_EPORT_EPDDR, MCF_EPORT_EPFR);
+
+#elif defined(CONFIG_M5441X_SD_HW_DETECT)
+#if defined(CONFIG_DETECT_USE_EXTERN_IRQ1)
+ MCF_EPORT_EPPAR = MCF_EPORT_EPPAR | MCF_EPORT_EPPAR_EPPA1_BOTH;
+ MCF_EPORT_EPIER = MCF_EPORT_EPIER | MCF_EPORT_EPIER_EPIE1;
+ MCF_EPORT_EPFR = MCF_EPORT_EPFR | MCF_EPORT_EPFR_EPF1;
+#elif defined(CONFIG_DETECT_USE_EXTERN_IRQ7)
+ MCF_EPORT_EPPAR = MCF_EPORT_EPPAR | MCF_EPORT_EPPAR_EPPA7_BOTH;
+ MCF_EPORT_EPIER = MCF_EPORT_EPIER | MCF_EPORT_EPIER_EPIE7;
+ MCF_EPORT_EPFR = MCF_EPORT_EPFR | MCF_EPORT_EPFR_EPF7;
+#else
+ MCF_EPORT_EPPAR = MCF_EPORT_EPPAR | MCF_EPORT_EPPAR_EPPA7_BOTH;
+ MCF_EPORT_EPIER = MCF_EPORT_EPIER | MCF_EPORT_EPIER_EPIE7;
+ MCF_EPORT_EPFR = MCF_EPORT_EPFR | MCF_EPORT_EPFR_EPF7;
+#endif
+#endif
return IRQ_HANDLED;
}

View file

@ -1,38 +0,0 @@
From 2a73218ebe0bdca04cc9299da50d7f079ca46a7d Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:47 +0800
Subject: [PATCH 30/52] Add SPI device configuration for FXS and FXO on MCF54451 platform
Add SPI device configuration for FXS and FXO on MCF54451 platform.
So FXS and FXO drivers can use SPI subsystem interfaces for the SPI
read and write operations. So as to fix the confliction between FXO/FXS
with other SPI devices.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
drivers/spi/Kconfig | 14 ++++++++++++++
1 files changed, 14 insertions(+), 0 deletions(-)
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -189,6 +189,20 @@ config SPI_COLDFIRE_DSPI_EDMA
help
Say "yes" if you want DSPI master driver to use eDMA for transfers.
+config VOIP_FXS
+ boolean "Coldfire VoIP FXS driver"
+ depends on M54451 && SPI_MASTER && SPI_DSPI
+ default n
+ help
+ Say "yes" if you want VoIP FXS driver to use DSPI for transfers.
+
+config VOIP_FXO
+ boolean "Coldfire VoIP FXO driver"
+ depends on M54451 && SPI_MASTER && SPI_DSPI
+ default n
+ help
+ Say "yes" if you want VoIP FXO driver to use DSPI for transfers.
+
config SPI_IMX_VER_IMX1
def_bool y if SOC_IMX1

View file

@ -1,338 +0,0 @@
From 42bf8a598049f6cb3c90b1f28a2f1b8daebe3de8 Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:47 +0800
Subject: [PATCH 31/52] Add watchdog driver support for MCF5445x and MCF547x/MCF548x
Add watchdog driver support for MCF5445x and MCF547x/MCF548x.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
drivers/watchdog/Kconfig | 9 ++
drivers/watchdog/Makefile | 1 +
drivers/watchdog/mcf_wdt.c | 292 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 302 insertions(+), 0 deletions(-)
create mode 100644 drivers/watchdog/mcf_wdt.c
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -974,6 +974,15 @@ config BCM63XX_WDT
# PARISC Architecture
+# ColdFire Architecture
+
+config COLDFIRE_WATCHDOG
+ tristate "ColdFire watchdog support"
+ depends on M547X_8X || M5445X || M5441X
+ help
+ To compile this driver as a module, choose M here: the
+ module will be called softdog.
+
# POWERPC Architecture
config GEF_WDT
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -107,6 +107,7 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc
# M68K Architecture
obj-$(CONFIG_M54xx_WATCHDOG) += m54xx_wdt.o
+obj-$(CONFIG_COLDFIRE_WATCHDOG) += mcf_wdt.o
# MIPS Architecture
obj-$(CONFIG_ATH79_WDT) += ath79_wdt.o
--- /dev/null
+++ b/drivers/watchdog/mcf_wdt.c
@@ -0,0 +1,292 @@
+/*
+ * drivers/watchdog/mcf_wdt.c
+ *
+ * Watchdog driver for ColdFire processors
+ *
+ * Copyright (C) 2006-2007, 2009-2011 Freescale Semiconductor, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Shrek Wu<B16972@freesale.com>
+ * ChengJu Cai<B22600@freesale.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+
+#include <linux/uaccess.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+static int nowayout;
+static unsigned int heartbeat = MCF_GPT_MAX_TIMEOUT;
+static unsigned long wdt_status;
+
+#define WDT_IN_USE 0
+#define WDT_OK_TO_CLOSE 1
+
+static unsigned long wdt_tick_rate;
+
+#ifdef CONFIG_M547X_8X
+static int
+wdt_enable(int time)
+{
+ if (time > 30 || time < 1)
+ return -EINVAL;
+
+ heartbeat = time;
+
+ MCF_GPT_GMS0 = 0;
+ MCF_GPT_GCIR0 = MCF_GPT_GCIR_PRE(heartbeat * wdt_tick_rate) |
+ MCF_GPT_GCIR_CNT(0xffff);
+ MCF_GPT_GMS0 = MCF_GPT_GMS_OCPW(0xA5) | MCF_GPT_GMS_WDEN |
+ MCF_GPT_GMS_CE | MCF_GPT_GMS_TMS_GPIO;
+
+ return 0;
+}
+
+static void
+wdt_disable(void)
+{
+ MCF_GPT_GMS0 = 0;
+}
+
+static void
+wdt_keepalive(void)
+{
+ MCF_GPT_GMS0 = MCF_GPT_GMS_OCPW(0xA5) | MCF_GPT_GMS0;
+}
+
+#elif defined(CONFIG_M5445X) || defined(CONFIG_M5441X)
+
+/* Enable watchdog and set time-out */
+static int
+wdt_enable(int time)
+{
+ unsigned int sign = 0x01 << 31;
+ int i = 0, timeout_n = 31;
+ int max_timeout = sign / MCF_BUSCLK;
+ unsigned int count;
+
+ if (time > max_timeout || time < 1)
+ return -EINVAL;
+
+ count = time * MCF_BUSCLK;
+
+ for (i = 0; i < 31; i++) {
+ if (count & (sign >> i)) {
+ if ((count & (~(sign >> i))) == 0)
+ timeout_n = 31 - i;
+ else
+ timeout_n = 31 - i + 1;
+ break;
+ }
+ }
+
+ heartbeat = (unsigned int)(0x01 << timeout_n) / MCF_BUSCLK;
+
+ MCF_SCM_CWCR = MCF_SCM_CWCR_CWE
+ | MCF_SCM_CWCR_CWRI(0x02)
+ | MCF_SCM_CWCR_CWT(timeout_n);
+
+ return 0;
+}
+
+/* Disable the watchdog */
+static void
+wdt_disable(void)
+{
+ MCF_SCM_CWCR = 0x00;
+}
+
+/* Reset the watchdog timer counter */
+static void
+wdt_keepalive(void)
+{
+ MCF_SCM_CWSR = 0x55;
+ MCF_SCM_CWSR = 0xAA;
+}
+#endif
+
+static int
+mcf_wdt_open(struct inode *inode, struct file *file)
+{
+ int ret;
+ if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+ return -EBUSY;
+
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+ ret = wdt_enable(heartbeat);
+ if (ret)
+ return ret;
+
+ return nonseekable_open(inode, file);
+}
+
+static ssize_t
+mcf_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+ for (i = 0; i != len; i++) {
+ char c;
+
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+ }
+ }
+ wdt_keepalive();
+ }
+
+ return len;
+}
+
+
+static struct watchdog_info ident = {
+ .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
+ WDIOF_KEEPALIVEPING,
+ .identity = "Coldfire Watchdog",
+};
+
+static long
+mcf_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long __user arg)
+{
+ long ret = -ENOIOCTLCMD;
+ int time = 0;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ ret = copy_to_user((struct watchdog_info *)arg, &ident,
+ sizeof(ident)) ? -EFAULT : 0;
+ break;
+
+ case WDIOC_GETSTATUS:
+ ret = put_user(0, (int *)arg);
+ break;
+
+ case WDIOC_GETBOOTSTATUS:
+ ret = put_user(0, (int *)arg);
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ ret = get_user(time, (int *)arg);
+ if (ret)
+ break;
+
+ ret = wdt_enable(time);
+ if (ret)
+ break;
+ ret = put_user(heartbeat, (int *)arg);
+ break;
+
+ case WDIOC_GETTIMEOUT:
+ ret = put_user(heartbeat, (int *)arg);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ wdt_keepalive();
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static int
+mcf_wdt_release(struct inode *inode, struct file *file)
+{
+ if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) {
+#ifdef CONFIG_M547X_8X
+ MCF_GPT_GCIR0 = (0x0A << 16) | 0x09;
+ MCF_GPT_GMS0 = MCF_GPT_GMS_OCPW(0xA5) | MCF_GPT_GMS0;
+#else
+ wdt_keepalive();
+#endif
+ } else {
+ printk(KERN_CRIT "WATCHDOG: Device closed unexpectdly\n");
+ wdt_disable();
+ }
+
+ clear_bit(WDT_IN_USE, &wdt_status);
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+#ifdef CONFIG_M547X_8X
+ /*disable the XLB priority, otherwise the watchdog reset may fail*/
+ MCF_XARB_PRIEN = 0;
+ /* Also disable the PCI, Ugly! But there is issue between PCI and
+ * watchdog. Otherwise the watchdog reset may fail, only valuable
+ * for testing!
+ */
+ MCF_SPCR &= ~0x02;
+ asm("tpf");
+#endif
+
+ return 0;
+}
+
+
+static const struct file_operations mcf_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = mcf_wdt_write,
+ .unlocked_ioctl = mcf_wdt_ioctl,
+ .open = mcf_wdt_open,
+ .release = mcf_wdt_release,
+};
+
+static struct miscdevice mcf_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &mcf_wdt_fops,
+};
+
+static int __init mcf_wdt_init(void)
+{
+ wdt_tick_rate = MCF_BUSCLK/0xffff;
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+ nowayout = 1;
+#else
+ nowayout = 0;
+#endif
+ printk(KERN_INFO "ColdFire watchdog driver is loaded.\n");
+
+ return misc_register(&mcf_wdt_miscdev);
+}
+
+static void __exit mcf_wdt_exit(void)
+{
+ misc_deregister(&mcf_wdt_miscdev);
+}
+
+module_init(mcf_wdt_init);
+module_exit(mcf_wdt_exit);
+
+MODULE_AUTHOR("Deepak Saxena");
+MODULE_DESCRIPTION("ColdFire Watchdog");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+

View file

@ -1,33 +0,0 @@
From 8834b24adf7efc8a50fcbc153910276b355fb4e9 Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:47 +0800
Subject: [PATCH 32/52] Change some jffs2 warning to debug info
As the NFC issue, the jffs2 verify buf may fail sometimes.
This patch move this kind of warning to debug information.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
fs/jffs2/wbuf.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -246,13 +246,13 @@ static int jffs2_verify_write(struct jff
else
eccstr = "OK or unused";
- printk(KERN_WARNING "Write verify error (ECC %s) at %08x. Wrote:\n",
+ printk(KERN_DEBUG "Write verify error (ECC %s) at %08x. Wrote:\n",
eccstr, c->wbuf_ofs);
- print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 1,
c->wbuf, c->wbuf_pagesize, 0);
- printk(KERN_WARNING "Read back:\n");
- print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
+ printk(KERN_DEBUG "Read back:\n");
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 1,
c->wbuf_verify, c->wbuf_pagesize, 0);
return -EIO;

View file

@ -1,49 +0,0 @@
From 1ebacc69cb9b9c2508b1e75cb23ef572cda51eec Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:47 +0800
Subject: [PATCH 33/52] Fix structure fsl_ssd1289_data definition bug for SSD1289 FB driver
Fix the bug that structure fsl_ssd1289_data definition depends on
DSPI enabled for SSD1289 framebuffer driver.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
arch/m68k/coldfire/m5441x/devices.c | 20 ++++++++++----------
1 files changed, 10 insertions(+), 10 deletions(-)
--- a/arch/m68k/coldfire/m5441x/devices.c
+++ b/arch/m68k/coldfire/m5441x/devices.c
@@ -138,6 +138,16 @@ static struct platform_device nfc_device
};
#endif
+#if defined(CONFIG_FB_FSL_SSD1289) || defined(CONFIG_FB_FSL_SSD1289_MODULE)
+static struct fsl_ssd1289_fb_display fsl_ssd1289_data = {
+ .width = 320,
+ .height = 240,
+ .xres = 320,
+ .yres = 240,
+ .bpp = 16,
+};
+#endif
+
/*
* DSPI
*/
@@ -197,16 +207,6 @@ static struct coldfire_dspi_chip at26df0
};
#endif
-#if defined(CONFIG_FB_FSL_SSD1289) || defined(CONFIG_FB_FSL_SSD1289_MODULE)
-static struct fsl_ssd1289_fb_display fsl_ssd1289_data = {
- .width = 320,
- .height = 240,
- .xres = 320,
- .yres = 240,
- .bpp = 16,
-};
-#endif
-
#if defined(CONFIG_SSD1289_SPI_MODE)
static struct coldfire_dspi_chip ssd1289_chip_info = {
.mode = SPI_MODE_0,

View file

@ -1,50 +0,0 @@
From 25ebef8c87221774de01d1f1de4fb615fcfc6b54 Mon Sep 17 00:00:00 2001
From: Jason Jin <Jason.jin@freescale.com>
Date: Thu, 4 Aug 2011 09:59:47 +0800
Subject: [PATCH 34/52] Enable the NFC driver for soft_ecc.
If enabled YAFFS2 support, soft ecc should be used for the
nand flash driver.
Signed-off-by: Jason Jin <Jason.jin@freescale.com>
---
drivers/mtd/nand/Kconfig | 6 ++++++
drivers/mtd/nand/fsl_nfc.c | 12 +++++++++---
2 files changed, 15 insertions(+), 3 deletions(-)
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -481,6 +481,12 @@ config MTD_NAND_FSL_NFC
Enables support for NAND Flash chips wired onto Freescale PowerPC
processor localbus with User-Programmable Machine support.
+config MTD_NAND_FSL_NFC_SWECC
+ bool "Software ECC"
+ depends on MTD_NAND_FSL_NFC
+ help
+ Use software ECC.
+
config MTD_NAND_MXC
tristate "MXC NAND support"
depends on ARCH_MX2 || ARCH_MX25 || ARCH_MX3 || ARCH_MX51
--- a/drivers/mtd/nand/fsl_nfc.c
+++ b/drivers/mtd/nand/fsl_nfc.c
@@ -403,9 +403,15 @@ fsl_nfc_command(struct mtd_info *mtd, un
if (page != -1)
prv->page = page;
- nfc_set_field(mtd, NFC_FLASH_CONFIG,
- CONFIG_ECC_MODE_MASK,
- CONFIG_ECC_MODE_SHIFT, ECC_45_BYTE);
+ if(hardware_ecc)
+ nfc_set_field(mtd, NFC_FLASH_CONFIG,
+ CONFIG_ECC_MODE_MASK,
+ CONFIG_ECC_MODE_SHIFT, ECC_45_BYTE);
+ else
+ /* set ECC BY_PASS */
+ nfc_set_field(mtd, NFC_FLASH_CONFIG,
+ CONFIG_ECC_MODE_MASK,
+ CONFIG_ECC_MODE_SHIFT, ECC_BYPASS);
if (!(page%0x40)) {
nfc_set_field(mtd, NFC_FLASH_CONFIG,

View file

@ -1,764 +0,0 @@
From c3b97e08b06be76ee9f2b410b13c045425fc7f3e Mon Sep 17 00:00:00 2001
From: Jingchang Lu <b35083@freescale.com>
Date: Thu, 4 Aug 2011 09:59:48 +0800
Subject: [PATCH 36/52] Add FlexCAN support on ColdFire M548X, M54418 platform
Each cpu core has two FlexCAN interface, and the M54418's FlexCAN
also support Rx message buffer FIFO mode but M548X not.
Signed-off-by: Jingchang Lu <b35083@freescale.com>
---
arch/m68k/Kconfig | 2 +
arch/m68k/coldfire/m5441x/Makefile | 4 +
arch/m68k/coldfire/m5441x/mcf-flexcan.c | 121 ++++++++++++++++
arch/m68k/coldfire/m547x/Makefile | 3 +
arch/m68k/coldfire/m547x/mcf-flexcan.c | 117 +++++++++++++++
drivers/net/can/Kconfig | 9 ++
drivers/net/can/flexcan.c | 239 ++++++++++++++++++++++++++++++-
7 files changed, 489 insertions(+), 6 deletions(-)
create mode 100644 arch/m68k/coldfire/m5441x/mcf-flexcan.c
create mode 100644 arch/m68k/coldfire/m547x/mcf-flexcan.c
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -372,6 +372,7 @@ config M547X
config M548X
bool
depends on M547X_8X
+ select HAVE_CAN_FLEXCAN
default n
choice
@@ -430,6 +431,7 @@ config M5441X
select GENERIC_TIME
select USB_EHCI_FSL
select HAVE_FSL_USB_DR
+ select HAVE_CAN_FLEXCAN
help
This option will add support for the MCF5441x processor with mmu.
--- a/arch/m68k/coldfire/m5441x/Makefile
+++ b/arch/m68k/coldfire/m5441x/Makefile
@@ -36,3 +36,7 @@ endif
ifneq ($(CONFIG_MODELO_SWITCH),)
obj-y += l2switch.o
endif
+
+ifneq ($(CONFIG_CAN_FLEXCAN),)
+obj-y += mcf-flexcan.o
+endif
--- /dev/null
+++ b/arch/m68k/coldfire/m5441x/mcf-flexcan.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Huan Wang, b18965@freescale.com, Fri Aug 08 2008
+ *
+ * Description:
+ * CAN bus driver for Freescale Coldfire embedded CPU
+ *
+ * Changelog:
+ * Fri Aug 08 2008 Huan Wang <b18965@freescale.com>
+ * - create, support for MCF548x
+ *
+ * Tue Dec 08 2009 ChengJu Cai <b22600@freescale.com>
+ * - support for MCF532x MCF5253 MCF5227x
+ *
+ * July 2011 Jingchang.Lu <b35083@freescale.com>
+ * - Add into kernel CAN driver layer
+ *
+ * This file is part of the Linux kernel
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <asm/mcfsim.h>
+
+
+static struct resource mcf5441x_can0_resources[] = {
+ [0] = {
+ .start = 0xFC020000,
+ .end = 0xFC0208C0,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 0 + 64 + 64,
+ .end = 0 + 64 + 64,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource mcf5441x_can1_resources[] = {
+ [0] = {
+ .start = 0xFC024000,
+ .end = 0xFC0248C0,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 4 + 64 + 64,
+ .end = 4 + 64 + 64,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device mcf_flexcan[PDEV_MAX] = {
+ [0] = {
+ .name = "flexcan",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(mcf5441x_can0_resources),
+ .resource = mcf5441x_can0_resources,
+ },
+ [1] = {
+ .name = "flexcan",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(mcf5441x_can1_resources),
+ .resource = mcf5441x_can1_resources,
+ },
+
+};
+
+
+static void __init mcf_flexcan_config(void)
+{
+ MCF_PM_PPMCR0 = 8; /* enable FlexCAN0 clock */
+ MCF_PM_PPMCR0 = 9; /* enable FlexCAN1 clock */
+
+ /* CAN0 */
+ MCF_GPIO_PAR_CANI2C =
+ (MCF_GPIO_PAR_CANI2C & MCF_GPIO_PAR_CANI2C_I2C0SCL_MASK) |
+ MCF_GPIO_PAR_CANI2C_I2C0SCL_CAN0TX;
+ MCF_GPIO_PAR_CANI2C =
+ (MCF_GPIO_PAR_CANI2C & MCF_GPIO_PAR_CANI2C_I2C0SDA_MASK) |
+ MCF_GPIO_PAR_CANI2C_I2C0SDA_CAN0RX;
+ /* CAN1 */
+ MCF_GPIO_PAR_CANI2C =
+ (MCF_GPIO_PAR_CANI2C & MCF_GPIO_PAR_CANI2C_CAN1TX_MASK) |
+ MCF_GPIO_PAR_CANI2C_CAN1TX_CAN1TX;
+ MCF_GPIO_PAR_CANI2C =
+ (MCF_GPIO_PAR_CANI2C & MCF_GPIO_PAR_CANI2C_CAN1RX_MASK) |
+ MCF_GPIO_PAR_CANI2C_CAN1RX_CAN1RX;
+
+
+}
+
+static int __init flexcan_of_to_pdev(void)
+{
+ int i, err = -ENODEV;
+ for (i = 0; i < PDEV_MAX; i++) {
+ err = platform_device_register(&mcf_flexcan[i]);
+ if (err)
+ return err;
+ printk(KERN_INFO "ColdFire FlexCAN devices loaded\n");
+ }
+ return err;
+}
+
+static int __init mcf_flexcan_init(void)
+{
+ int err;
+ mcf_flexcan_config();
+ err = flexcan_of_to_pdev();
+
+ return 0;
+}
+
+arch_initcall(mcf_flexcan_init);
--- a/arch/m68k/coldfire/m547x/Makefile
+++ b/arch/m68k/coldfire/m547x/Makefile
@@ -5,3 +5,6 @@
obj-$(CONFIG_M547X_8X) += config.o mcf548x-devices.o devices.o
obj-$(CONFIG_PCI) += pci.o pci_dummy.o
obj-$(CONFIG_MCD_DMA) += dma.o
+ifneq ($(CONFIG_CAN_FLEXCAN),)
+obj-y += mcf-flexcan.o
+endif
--- /dev/null
+++ b/arch/m68k/coldfire/m547x/mcf-flexcan.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Huan Wang, b18965@freescale.com, Fri Aug 08 2008
+ *
+ * Description:
+ * CAN bus driver for Freescale Coldfire embedded CPU
+ *
+ * Changelog:
+ * Fri Aug 08 2008 Huan Wang <b18965@freescale.com>
+ * - create, support for MCF548x
+ *
+ * Tue Dec 08 2009 ChengJu Cai <b22600@freescale.com>
+ * - support for MCF532x MCF5253 MCF5227x
+ *
+ * July 2011 Jingchang.Lu <b35083@freescale.com>
+ * - Add into kernel CAN driver layer
+ *
+ * This file is part of the Linux kernel
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <asm/mcfsim.h>
+
+
+static struct resource mcf548x_can0_resources[] = {
+ [0] = {
+ .start = MCF_MBAR + 0x0000A000,
+ .end = MCF_MBAR + 0x0000A7FF,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 49 + 64,
+ .end = 49 + 64,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource mcf548x_can1_resources[] = {
+ [0] = {
+ .start = MCF_MBAR + 0x0000A800,
+ .end = MCF_MBAR + 0x0000AFFF,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 55 + 64,
+ .end = 55 + 64,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device mcf_flexcan[PDEV_MAX] = {
+ [0] = {
+ .name = "flexcan",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(mcf548x_can1_resources),
+ .resource = mcf548x_can0_resources,
+ },
+ [1] = {
+ .name = "flexcan",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(mcf548x_can1_resources),
+ .resource = mcf548x_can1_resources,
+ },
+
+};
+
+
+static void __init mcf_flexcan_config(void)
+{
+ int i;
+ MCF_PAR_TIMER = MCF_PAR_TIMER | 0x28;
+ MCF_PAR_TIMER = MCF_PAR_TIMER & 0xf8;
+ MCF_PAR_DSPI = MCF_PAR_DSPI | 0x0a00;
+ MCF_PAR_FECI2CIRQ = MCF_PAR_FECI2CIRQ | 0x0283;
+ MCF_PAR_PSCn(2) = MCF_PAR_PSCn(2) & 0x0f;
+ MCF_PAR_PSCn(2) = MCF_PAR_PSCn(2) | 0x50;
+
+ for (i = 0; i < 2; i++) {
+ MCF_ICR(ISC_CANn_MBOR(i)) = 0x33 + 0x01 * i;
+ MCF_ICR(ISC_CANn_ERR(i)) = 0x33 + 0x01 * i;
+ MCF_ICR(ISC_CANn_BUSOFF(i)) = 0x33 + 0x01 * i;
+ }
+
+
+}
+
+static int __init flexcan_of_to_pdev(void)
+{
+ int i, err = -ENODEV;
+ for (i = 0; i < PDEV_MAX; i++) {
+ err = platform_device_register(&mcf_flexcan[i]);
+ if (err)
+ return err;
+ printk(KERN_INFO "ColdFire FlexCAN devices loaded\n");
+ }
+ return err;
+}
+
+static int __init mcf_flexcan_init(void)
+{
+ int err;
+ mcf_flexcan_config();
+ err = flexcan_of_to_pdev();
+
+ return 0;
+}
+
+arch_initcall(mcf_flexcan_init);
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -103,6 +103,15 @@ config CAN_FLEXCAN
---help---
Say Y here if you want to support for Freescale FlexCAN.
+config FLEXCAN_NORXFIFO
+ bool "FlexCAN message buffer without Rx FIFO mode"
+ depends on CAN_FLEXCAN && COLDFIRE
+ default n
+ ---help---
+ Say Y here if you FlexCAN message buffer has no Rx FIFO mode.
+ Freescale Coldfire series have different FlexCAN core version,
+ MCF54418's support Rx FIFO mode while others such as MCF5485 not.
+
config PCH_CAN
tristate "PCH CAN"
depends on CAN_DEV && PCI
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -4,6 +4,7 @@
* Copyright (c) 2005-2006 Varma Electronics Oy
* Copyright (c) 2009 Sascha Hauer, Pengutronix
* Copyright (c) 2010 Marc Kleine-Budde, Pengutronix
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
*
* Based on code originally by Andrey Volkov <avolkov@varma-el.com>
*
@@ -35,8 +36,28 @@
#include <linux/module.h>
#include <linux/platform_device.h>
+#ifndef CONFIG_COLDFIRE
#include <mach/clock.h>
+#else
+#include <asm/mcfsim.h>
+
+#undef readb
+#undef readw
+#undef readl
+#define readb(addr) __raw_readb(addr)
+#define readw(addr) __raw_readw(addr)
+#define readl(addr) __raw_readl(addr)
+
+#undef writeb
+#undef writew
+#undef writel
+#define writeb(b, addr) __raw_writeb(b, addr)
+#define writew(b, addr) __raw_writew(b, addr)
+#define writel(b, addr) __raw_writel(b, addr)
+
+#endif
+
#define DRV_NAME "flexcan"
/* 8 for RX fifo and 2 error handling */
@@ -85,12 +106,34 @@
#define FLEXCAN_CTRL_LOM BIT(3)
#define FLEXCAN_CTRL_PROPSEG(x) ((x) & 0x07)
#define FLEXCAN_CTRL_ERR_BUS (FLEXCAN_CTRL_ERR_MSK)
+
+#ifdef CONFIG_COLDFIRE
+
+# if defined(CONFIG_M548X)
+
+#define FLEXCAN_CTRL_ERR_STATE FLEXCAN_CTRL_BOFF_MSK
+#define FLEXCAN_CTRL_ERR_ALL \
+ (FLEXCAN_CTRL_BOFF_MSK | FLEXCAN_CTRL_ERR_MSK)
+
+# elif defined(CONFIG_M5441X)
+
#define FLEXCAN_CTRL_ERR_STATE \
(FLEXCAN_CTRL_TWRN_MSK | FLEXCAN_CTRL_RWRN_MSK | \
FLEXCAN_CTRL_BOFF_MSK)
#define FLEXCAN_CTRL_ERR_ALL \
(FLEXCAN_CTRL_ERR_BUS | FLEXCAN_CTRL_ERR_STATE)
+# endif
+
+#else /* !CONFIG_COLDFIRE */
+
+#define FLEXCAN_CTRL_ERR_STATE \
+ (FLEXCAN_CTRL_TWRN_MSK | FLEXCAN_CTRL_RWRN_MSK | \
+ FLEXCAN_CTRL_BOFF_MSK)
+#define FLEXCAN_CTRL_ERR_ALL \
+ (FLEXCAN_CTRL_ERR_BUS | FLEXCAN_CTRL_ERR_STATE)
+
+#endif
/* FLEXCAN error and status register (ESR) bits */
#define FLEXCAN_ESR_TWRN_INT BIT(17)
#define FLEXCAN_ESR_RWRN_INT BIT(16)
@@ -121,6 +164,18 @@
(FLEXCAN_ESR_ERR_BUS | FLEXCAN_ESR_ERR_STATE)
/* FLEXCAN interrupt flag register (IFLAG) bits */
+
+#ifdef CONFIG_FLEXCAN_NORXFIFO
+
+/* MB assignment for no Rx FIFO mode module */
+#define FLEXCAN_TX_BUF_ID 0
+#define FLEXCAN_RX_EXT_ID 15
+#define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE 0xfffe
+#define FLEXCAN_IFLAG_DEFAULT \
+ (FLEXCAN_IFLAG_RX_FIFO_AVAILABLE | (0x01 << FLEXCAN_TX_BUF_ID))
+
+#else
+
#define FLEXCAN_TX_BUF_ID 8
#define FLEXCAN_IFLAG_BUF(x) BIT(x)
#define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7)
@@ -130,6 +185,7 @@
(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | FLEXCAN_IFLAG_RX_FIFO_AVAILABLE | \
FLEXCAN_IFLAG_BUF(FLEXCAN_TX_BUF_ID))
+#endif
/* FLEXCAN message buffers */
#define FLEXCAN_MB_CNT_CODE(x) (((x) & 0xf) << 24)
#define FLEXCAN_MB_CNT_SRR BIT(22)
@@ -163,7 +219,11 @@ struct flexcan_regs {
u32 iflag2; /* 0x2c */
u32 iflag1; /* 0x30 */
u32 _reserved2[19];
+#ifdef CONFIG_COLDFIRE
+ struct flexcan_mb cantxfg[CAN_MB];
+#else
struct flexcan_mb cantxfg[64];
+#endif
};
struct flexcan_priv {
@@ -181,8 +241,13 @@ struct flexcan_priv {
static struct can_bittiming_const flexcan_bittiming_const = {
.name = DRV_NAME,
+#ifdef CONFIG_COLDFIRE
+ .tseg1_min = 1,
+ .tseg1_max = 8,
+#else
.tseg1_min = 4,
.tseg1_max = 16,
+#endif
.tseg2_min = 2,
.tseg2_max = 8,
.sjw_max = 4,
@@ -248,7 +313,7 @@ static int flexcan_start_xmit(struct sk_
struct net_device_stats *stats = &dev->stats;
struct flexcan_regs __iomem *regs = priv->base;
struct can_frame *cf = (struct can_frame *)skb->data;
- u32 can_id;
+ u32 can_id, tmp, tmp1;
u32 ctrl = FLEXCAN_MB_CNT_CODE(0xc) | (cf->can_dlc << 16);
if (can_dropped_invalid_skb(dev, skb))
@@ -259,6 +324,11 @@ static int flexcan_start_xmit(struct sk_
if (cf->can_id & CAN_EFF_FLAG) {
can_id = cf->can_id & CAN_EFF_MASK;
ctrl |= FLEXCAN_MB_CNT_IDE | FLEXCAN_MB_CNT_SRR;
+#ifdef CONFIG_COLDFIRE
+ tmp = (can_id & CAN_SFF_MASK) << 18;
+ tmp1 = can_id >> 11;
+ can_id = tmp | tmp1;
+#endif
} else {
can_id = (cf->can_id & CAN_SFF_MASK) << 18;
}
@@ -456,6 +526,87 @@ static int flexcan_poll_state(struct net
return 1;
}
+#ifdef CONFIG_FLEXCAN_NORXFIFO
+/* Get one frame from receive message buffer */
+static int flexcan_read_frame(struct net_device *dev)
+{
+ const struct flexcan_priv *priv = netdev_priv(dev);
+ struct flexcan_regs __iomem *regs = priv->base;
+ struct net_device_stats *stats = &dev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ struct flexcan_mb __iomem *mb;
+ u32 reg_iflag1, reg_ctrl, reg_id, i;
+
+ reg_iflag1 = readl(&regs->iflag1);
+
+ /* buf[0] if for TX */
+ for (i = 0; i < CAN_MB; i++) {
+ if (i == FLEXCAN_TX_BUF_ID)
+ continue;
+ /* find one received message slot */
+ if (reg_iflag1 & (0x01 << i))
+ break;
+ }
+ if (i >= CAN_MB)
+ return 0;
+
+ mb = &regs->cantxfg[i];
+
+ skb = alloc_can_skb(dev, &cf);
+ if (unlikely(!skb)) {
+ stats->rx_dropped++;
+ return 0;
+ }
+
+ reg_ctrl = readl(&mb->can_ctrl);
+ reg_id = readl(&mb->can_id);
+
+ /* deactive RX buff */
+ writel(0, &mb->can_ctrl);
+
+ if (reg_ctrl & FLEXCAN_MB_CNT_IDE) {
+#ifdef CONFIG_COLDFIRE
+ /* Coldfire can_id order */
+ cf->can_id = (reg_id & CAN_EFF_MASK) >> 18;
+ cf->can_id |= (reg_id & 0x3ffff) << 11;
+ cf->can_id |= CAN_EFF_FLAG;
+#else
+ cf->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG;
+#endif
+ } else
+ cf->can_id = (reg_id >> 18) & CAN_SFF_MASK;
+
+ if (reg_ctrl & FLEXCAN_MB_CNT_RTR)
+ cf->can_id |= CAN_RTR_FLAG;
+ cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf);
+
+ *(__be32 *)(cf->data + 0) = cpu_to_be32(readl(&mb->data[0]));
+ *(__be32 *)(cf->data + 4) = cpu_to_be32(readl(&mb->data[1]));
+
+ /* reactive RX buffer */
+ if (i == FLEXCAN_RX_EXT_ID)
+ writel(FLEXCAN_MB_CNT_CODE(0x4)|0x600000,
+ &regs->cantxfg[i].can_ctrl);
+ else
+ writel(FLEXCAN_MB_CNT_CODE(0x4),
+ &regs->cantxfg[i].can_ctrl);
+
+ /* mark as read */
+ writel((0x01 << i), &regs->iflag1);
+ /* release MB lock */
+ readl(&regs->timer);
+
+ netif_receive_skb(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+
+ return 1;
+
+}
+#else
+
static void flexcan_read_fifo(const struct net_device *dev,
struct can_frame *cf)
{
@@ -466,9 +617,16 @@ static void flexcan_read_fifo(const stru
reg_ctrl = readl(&mb->can_ctrl);
reg_id = readl(&mb->can_id);
- if (reg_ctrl & FLEXCAN_MB_CNT_IDE)
+ if (reg_ctrl & FLEXCAN_MB_CNT_IDE) {
+#ifdef CONFIG_COLDFIRE
+ /* ColdFire can_id order as follow */
+ cf->can_id = (reg_id & CAN_EFF_MASK) >> 18;
+ cf->can_id |= (reg_id & 0x3ffff) << 11;
+ cf->can_id |= CAN_EFF_FLAG;
+#else
cf->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG;
- else
+#endif
+ } else
cf->can_id = (reg_id >> 18) & CAN_SFF_MASK;
if (reg_ctrl & FLEXCAN_MB_CNT_RTR)
@@ -503,6 +661,7 @@ static int flexcan_read_frame(struct net
return 1;
}
+#endif
static int flexcan_poll(struct napi_struct *napi, int quota)
{
@@ -554,6 +713,14 @@ static irqreturn_t flexcan_irq(int irq,
reg_iflag1 = readl(&regs->iflag1);
reg_esr = readl(&regs->esr);
writel(FLEXCAN_ESR_ERR_INT, &regs->esr); /* ACK err IRQ */
+#ifdef CONFIG_COLDFIRE
+#ifdef CONFIG_FLEXCAN_NORXFIFO
+ writel(FLEXCAN_ESR_BOFF_INT, &regs->esr);
+#else
+ /* ACK TWRN and RWRN error, and bus-off interrupt*/
+ writel(FLEXCAN_ESR_ERR_STATE, &regs->esr);
+#endif
+#endif
/*
* schedule NAPI in case of:
@@ -575,13 +742,14 @@ static irqreturn_t flexcan_irq(int irq,
&regs->ctrl);
napi_schedule(&priv->napi);
}
-
+#ifndef CONFIG_FLEXCAN_NORXFIFO
/* FIFO overflow */
if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_OVERFLOW) {
writel(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW, &regs->iflag1);
dev->stats.rx_over_errors++;
dev->stats.rx_errors++;
}
+#endif
/* transmission complete interrupt */
if (reg_iflag1 & (1 << FLEXCAN_TX_BUF_ID)) {
@@ -676,9 +844,14 @@ static int flexcan_chip_start(struct net
*
*/
reg_mcr = readl(&regs->mcr);
+#ifdef CONFIG_FLEXCAN_NORXFIFO
+ reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
+ FLEXCAN_MCR_SUPV;
+#else
reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_FEN | FLEXCAN_MCR_HALT |
FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN |
FLEXCAN_MCR_IDAM_C;
+#endif
dev_dbg(dev->dev.parent, "%s: writing mcr=0x%08x", __func__, reg_mcr);
writel(reg_mcr, &regs->mcr);
@@ -713,9 +886,19 @@ static int flexcan_chip_start(struct net
writel(0, &regs->cantxfg[i].can_id);
writel(0, &regs->cantxfg[i].data[0]);
writel(0, &regs->cantxfg[i].data[1]);
-
+#ifdef CONFIG_FLEXCAN_NORXFIFO
+ if (i == FLEXCAN_TX_BUF_ID)
+ continue;
+ if (i == FLEXCAN_RX_EXT_ID) /* enable receive extend message */
+ writel(FLEXCAN_MB_CNT_CODE(0x4)|0x600000,
+ &regs->cantxfg[i].can_ctrl);
+ else
+ writel(FLEXCAN_MB_CNT_CODE(0x4),
+ &regs->cantxfg[i].can_ctrl);
+#else
/* put MB into rx queue */
writel(FLEXCAN_MB_CNT_CODE(0x4), &regs->cantxfg[i].can_ctrl);
+#endif
}
/* acceptance mask/acceptance code (accept everything) */
@@ -772,6 +955,7 @@ static void flexcan_chip_stop(struct net
return;
}
+
static int flexcan_open(struct net_device *dev)
{
struct flexcan_priv *priv = netdev_priv(dev);
@@ -786,6 +970,24 @@ static int flexcan_open(struct net_devic
err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev);
if (err)
goto out_close;
+ err = request_irq(dev->irq + 1, flexcan_irq, \
+ IRQF_DISABLED, dev->name, dev);
+ if (err) {
+ free_irq(dev->irq, dev);
+ goto out_close;
+ }
+#if defined(CONFIG_M548X)
+ err = request_irq(dev->irq + 2, flexcan_irq, \
+ IRQF_DISABLED, dev->name, dev);
+#elif defined(CONFIG_M5441X)
+ err = request_irq(dev->irq + 3, flexcan_irq, \
+ IRQF_DISABLED, dev->name, dev);
+#endif
+ if (err) {
+ free_irq(dev->irq, dev);
+ free_irq(dev->irq + 1, dev);
+ goto out_close;
+ }
/* start chip and queuing */
err = flexcan_chip_start(dev);
@@ -813,6 +1015,14 @@ static int flexcan_close(struct net_devi
flexcan_chip_stop(dev);
free_irq(dev->irq, dev);
+#ifdef CONFIG_COLDFIRE
+ free_irq(dev->irq + 1, dev);
+#if defined(CONFIG_M548X)
+ free_irq(dev->irq + 2, dev);
+#elif defined(CONFIG_M5441X)
+ free_irq(dev->irq + 3, dev);
+#endif
+#endif
clk_disable(priv->clk);
close_candev(dev);
@@ -854,14 +1064,23 @@ static int __devinit register_flexcandev
clk_enable(priv->clk);
+#if !defined(CONFIG_M548X)
/* select "bus clock", chip must be disabled */
flexcan_chip_disable(priv);
reg = readl(&regs->ctrl);
reg |= FLEXCAN_CTRL_CLK_SRC;
writel(reg, &regs->ctrl);
+#endif
flexcan_chip_enable(priv);
+#ifdef CONFIG_FLEXCAN_NORXFIFO
+ /* set freeze, halt and restrict register access */
+ reg = readl(&regs->mcr);
+ reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
+ FLEXCAN_MCR_SUPV;
+ writel(reg, &regs->mcr);
+#else
/* set freeze, halt and activate FIFO, restrict register access */
reg = readl(&regs->mcr);
reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
@@ -880,6 +1099,7 @@ static int __devinit register_flexcandev
err = -ENODEV;
goto out;
}
+#endif
err = register_candev(dev);
@@ -901,17 +1121,19 @@ static int __devinit flexcan_probe(struc
struct net_device *dev;
struct flexcan_priv *priv;
struct resource *mem;
- struct clk *clk;
+ struct clk *clk = NULL;
void __iomem *base;
resource_size_t mem_size;
int err, irq;
+#ifndef CONFIG_COLDFIRE
clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "no clock defined\n");
err = PTR_ERR(clk);
goto failed_clock;
}
+#endif
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
@@ -943,7 +1165,12 @@ static int __devinit flexcan_probe(struc
dev->flags |= IFF_ECHO; /* we support local echo in hardware */
priv = netdev_priv(dev);
+#ifdef CONFIG_COLDFIRE
+ /* return value is core clock but we need bus clock */
+ priv->can.clock.freq = (clk_get_rate(clk)/2);
+#else
priv->can.clock.freq = clk_get_rate(clk);
+#endif
priv->can.bittiming_const = &flexcan_bittiming_const;
priv->can.do_set_mode = flexcan_set_mode;
priv->can.do_get_berr_counter = flexcan_get_berr_counter;

View file

@ -1,934 +0,0 @@
From 8e46c06091fd87904205a977be3c784e3ac61e95 Mon Sep 17 00:00:00 2001
From: Jingchang Lu <b35083@freescale.com>
Date: Thu, 4 Aug 2011 09:59:48 +0800
Subject: [PATCH 37/52] Add ColdFire MCF54455 PATA interface support
ColdFire MCF54455 parallel ATA controller support
both uDMA and PIO mode, this driver implements all.
Signed-off-by: Jingchang Lu <b35083@freescale.com>
---
arch/m68k/include/asm/pata_fsl.h | 17 +
drivers/ata/Kconfig | 23 +-
drivers/ata/Makefile | 1 +
drivers/ata/pata_fsl.c | 844 ++++++++++++++++++++++++++++++++++++++
4 files changed, 884 insertions(+), 1 deletions(-)
create mode 100644 arch/m68k/include/asm/pata_fsl.h
create mode 100644 drivers/ata/pata_fsl.c
--- /dev/null
+++ b/arch/m68k/include/asm/pata_fsl.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_M68K_PATA_FSL_H
+#define _ASM_M68K_PATA_FSL_H
+
+/* ATA mapped IO address translate function */
+extern unsigned int io_ata_virt2phys(void *x);
+extern void *io_ata_phys2virt(unsigned int x);
+
+
+#endif
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -14,7 +14,7 @@ menuconfig ATA
tristate "Serial ATA and Parallel ATA drivers"
depends on HAS_IOMEM
depends on BLOCK
- depends on !(M32R || M68K) || BROKEN
+ depends on !(M32R) || BROKEN
select SCSI
---help---
If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or
@@ -687,6 +687,27 @@ config PATA_WINBOND
If unsure, say N.
+config PATA_FSL
+ tristate "Freescale on-chip PATA support"
+ depends on (ARCH_MX3 || ARCH_MX27 || PPC_512x || M54455)
+ help
+ Some Freescale processors SOC have parallel ATA controller,
+ such as ColdFire MCF54455.
+
+ Say Y here if you wish to use the on-chip ATA interface.
+
+ If you are unsure, say N to this.
+
+config FSL_PATA_USE_DMA
+ bool "Freescale PATA eDMA support"
+ depends on PATA_FSL && COLDFIRE_EDMA
+ default y
+ help
+ This option enables the uDMA support over PATA interface
+ which can improve performance than PIO mode for read and write.
+
+ If unsure, say Y.
+
endif # ATA_BMDMA
comment "PIO-only SFF controllers"
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -72,6 +72,7 @@ obj-$(CONFIG_PATA_TOSHIBA) += pata_picco
obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o
obj-$(CONFIG_PATA_VIA) += pata_via.o
obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o
+obj-$(CONFIG_PATA_FSL) += pata_fsl.o
# SFF PIO only
obj-$(CONFIG_PATA_AT32) += pata_at32.o
--- /dev/null
+++ b/drivers/ata/pata_fsl.c
@@ -0,0 +1,844 @@
+/*
+ * Freescale integrated PATA driver
+ *
+ * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Description:
+ * This driver is for Coldfire MCF54455 on-chip ATA module.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+#ifdef CONFIG_FSL_PATA_USE_DMA
+#include <asm/mcf_edma.h>
+#endif
+#include <asm/pata_fsl.h>
+
+#define DRV_NAME "pata_fsl"
+#define DRV_VERSION "1.0"
+
+#ifdef CONFIG_M54455
+#define WRITE_ATA8(val, reg) \
+ __raw_writeb(val, (ata_regs + reg));
+#define WRITE_ATA16(val, reg) \
+ __raw_writew(val, (ata_regs + reg));
+#else
+#define WRITE_ATA8(val, reg) \
+ __raw_writel(val, (ata_regs + reg));
+#define WRITE_ATA16(val, reg) \
+ __raw_writel(val, (ata_regs + reg));
+#endif
+
+#define MAX_FSL_SG 256 /* MCF_EDMA_TCD_PER_CHAN */
+
+struct pata_fsl_priv {
+#ifdef CONFIG_FSL_PATA_USE_DMA
+ int ultra;
+#endif
+ u8 *fsl_ata_regs;
+#ifdef CONFIG_FSL_PATA_USE_DMA
+ int dma_rchan;
+ int dma_wchan;
+ int dma_done;
+ int dma_dir;
+#if 0
+ int nsg;
+ struct fsl_edma_requestbuf reqbuf[MAX_FSL_SG];
+#endif
+#endif
+};
+
+enum {
+ /* various constants */
+
+#ifdef CONFIG_FSL_PATA_USE_DMA
+ FSL_ATA_MAX_SG_LEN = 65534,
+#endif
+
+ /* offsets to registers */
+
+ FSL_ATA_TIMING_REGS = 0x00,
+ FSL_ATA_FIFO_FILL = 0x20,
+ FSL_ATA_CONTROL = 0x24,
+ FSL_ATA_INT_PEND = 0x28,
+ FSL_ATA_INT_EN = 0x2C,
+ FSL_ATA_INT_CLEAR = 0x30,
+ FSL_ATA_FIFO_ALARM = 0x34,
+ FSL_ATA_DRIVE_DATA = 0xA0,
+ FSL_ATA_DRIVE_CONTROL = 0xD8,
+
+ /* bits within FSL_ATA_CONTROL */
+
+ FSL_ATA_CTRL_FIFO_RST_B = 0x80,
+ FSL_ATA_CTRL_ATA_RST_B = 0x40,
+ FSL_ATA_CTRL_FIFO_TX_EN = 0x20,
+ FSL_ATA_CTRL_FIFO_RCV_EN = 0x10,
+ FSL_ATA_CTRL_DMA_PENDING = 0x08,
+ FSL_ATA_CTRL_DMA_ULTRA = 0x04,
+ FSL_ATA_CTRL_DMA_WRITE = 0x02,
+ FSL_ATA_CTRL_IORDY_EN = 0x01,
+
+ /* bits within the interrupt control registers */
+
+ FSL_ATA_INTR_ATA_INTRQ1 = 0x80,
+ FSL_ATA_INTR_FIFO_UNDERFLOW = 0x40,
+ FSL_ATA_INTR_FIFO_OVERFLOW = 0x20,
+ FSL_ATA_INTR_CTRL_IDLE = 0x10,
+ FSL_ATA_INTR_ATA_INTRQ2 = 0x08,
+};
+
+/*
+ * This structure contains the timing parameters for
+ * ATA bus timing in the 5 PIO modes. The timings
+ * are in nanoseconds, and are converted to clock
+ * cycles before being stored in the ATA controller
+ * timing registers.
+ */
+static struct {
+ short t0, t1, t2_8, t2_16, t2i, t4, t9, tA;
+} pio_specs[] = {
+ [0] = {
+ .t0 = 600, .t1 = 70, .t2_8 = 290, .t2_16 = 165, .t2i = 0,
+ .t4 = 30, .t9 = 20, .tA = 50
+ },
+ [1] = {
+ .t0 = 383, .t1 = 50, .t2_8 = 290, .t2_16 = 125, .t2i = 0,
+ .t4 = 20, .t9 = 15, .tA = 50
+ },
+ [2] = {
+ .t0 = 240, .t1 = 30, .t2_8 = 290, .t2_16 = 100, .t2i = 0,
+ .t4 = 15, .t9 = 10, .tA = 50
+ },
+ [3] = {
+ .t0 = 180, .t1 = 30, .t2_8 = 80, .t2_16 = 80, .t2i = 0,
+ .t4 = 10, .t9 = 10, .tA = 50
+ },
+ [4] = {
+ .t0 = 120, .t1 = 25, .t2_8 = 70, .t2_16 = 70, .t2i = 0,
+ .t4 = 10, .t9 = 10, .tA = 50
+ },
+};
+
+#define NR_PIO_SPECS (sizeof pio_specs / sizeof pio_specs[0])
+
+/*
+ * This structure contains the timing parameters for
+ * ATA bus timing in the 3 MDMA modes. The timings
+ * are in nanoseconds, and are converted to clock
+ * cycles before being stored in the ATA controller
+ * timing registers.
+ */
+static struct {
+ short t0M, tD, tH, tJ, tKW, tM, tN, tJNH;
+} mdma_specs[] = {
+ [0] = {
+ .t0M = 480, .tD = 215, .tH = 20, .tJ = 20, .tKW = 215,
+ .tM = 50, .tN = 15, .tJNH = 20
+ },
+ [1] = {
+ .t0M = 150, .tD = 80, .tH = 15, .tJ = 5, .tKW = 50,
+ .tM = 30, .tN = 10, .tJNH = 15
+ },
+ [2] = {
+ .t0M = 120, .tD = 70, .tH = 10, .tJ = 5, .tKW = 25,
+ .tM = 25, .tN = 10, .tJNH = 10
+ },
+};
+
+#define NR_MDMA_SPECS (sizeof mdma_specs / sizeof mdma_specs[0])
+
+/*
+ * This structure contains the timing parameters for
+ * ATA bus timing in the 6 UDMA modes. The timings
+ * are in nanoseconds, and are converted to clock
+ * cycles before being stored in the ATA controller
+ * timing registers.
+ */
+static struct {
+ short t2CYC, tCYC, tDS, tDH, tDVS, tDVH, tCVS, tCVH, tFS_min, tLI_max,
+ tMLI, tAZ, tZAH, tENV_min, tSR, tRFS, tRP, tACK, tSS, tDZFS;
+} udma_specs[] = {
+ [0] = {
+ .t2CYC = 235, .tCYC = 114, .tDS = 15, .tDH = 5, .tDVS = 70,
+ .tDVH = 6, .tCVS = 70, .tCVH = 6, .tFS_min = 0,
+ .tLI_max = 100, .tMLI = 20, .tAZ = 10, .tZAH = 20,
+ .tENV_min = 20, .tSR = 50, .tRFS = 75, .tRP = 160,
+ .tACK = 20, .tSS = 50, .tDZFS = 80
+ },
+ [1] = {
+ .t2CYC = 156, .tCYC = 75, .tDS = 10, .tDH = 5, .tDVS = 48,
+ .tDVH = 6, .tCVS = 48, .tCVH = 6, .tFS_min = 0,
+ .tLI_max = 100, .tMLI = 20, .tAZ = 10, .tZAH = 20,
+ .tENV_min = 20, .tSR = 30, .tRFS = 70, .tRP = 125,
+ .tACK = 20, .tSS = 50, .tDZFS = 63
+ },
+ [2] = {
+ .t2CYC = 117, .tCYC = 55, .tDS = 7, .tDH = 5, .tDVS = 34,
+ .tDVH = 6, .tCVS = 34, .tCVH = 6, .tFS_min = 0,
+ .tLI_max = 100, .tMLI = 20, .tAZ = 10, .tZAH = 20,
+ .tENV_min = 20, .tSR = 20, .tRFS = 60, .tRP = 100,
+ .tACK = 20, .tSS = 50, .tDZFS = 47
+ },
+ [3] = {
+ .t2CYC = 86, .tCYC = 39, .tDS = 7, .tDH = 5, .tDVS = 20,
+ .tDVH = 6, .tCVS = 20, .tCVH = 6, .tFS_min = 0,
+ .tLI_max = 100, .tMLI = 20, .tAZ = 10, .tZAH = 20,
+ .tENV_min = 20, .tSR = 20, .tRFS = 60, .tRP = 100,
+ .tACK = 20, .tSS = 50, .tDZFS = 35
+ },
+ [4] = {
+ .t2CYC = 57, .tCYC = 25, .tDS = 5, .tDH = 5, .tDVS = 7,
+ .tDVH = 6, .tCVS = 7, .tCVH = 6, .tFS_min = 0,
+ .tLI_max = 100, .tMLI = 20, .tAZ = 10, .tZAH = 20,
+ .tENV_min = 20, .tSR = 50, .tRFS = 60, .tRP = 100,
+ .tACK = 20, .tSS = 50, .tDZFS = 25
+ },
+ [5] = {
+ .t2CYC = 38, .tCYC = 17, .tDS = 4, .tDH = 5, .tDVS = 5,
+ .tDVH = 6, .tCVS = 10, .tCVH = 10, .tFS_min = 0,
+ .tLI_max = 75, .tMLI = 20, .tAZ = 10, .tZAH = 20,
+ .tENV_min = 20, .tSR = 20, .tRFS = 50, .tRP = 85,
+ .tACK = 20, .tSS = 50, .tDZFS = 40
+ },
+};
+
+#define NR_UDMA_SPECS (sizeof udma_specs / sizeof udma_specs[0])
+
+struct fsl_ata_time_regs {
+ u8 time_off, time_on, time_1, time_2w;
+ u8 time_2r, time_ax, time_pio_rdx, time_4;
+ u8 time_9, time_m, time_jn, time_d;
+ u8 time_k, time_ack, time_env, time_rpx;
+ u8 time_zah, time_mlix, time_dvh, time_dzfs;
+ u8 time_dvs, time_cvh, time_ss, time_cyc;
+} __packed;
+
+
+static void update_timing_config(struct fsl_ata_time_regs *tp,
+ struct ata_host *host)
+{
+ u32 __iomem *lp = (u32 __iomem *)tp;
+ struct pata_fsl_priv *priv = host->private_data;
+ u32 __iomem *ctlp = (u32 __iomem *)priv->fsl_ata_regs;
+ int i;
+
+ /*
+ * JKM - this could have endianess issues on BE depending
+ * on how the controller is glued to the bus -- probably
+ * should rewrite this to write byte at a time.
+ */
+ for (i = 0; i < 6; i++) {
+ __raw_writel(*lp, ctlp);
+ lp++;
+ ctlp++;
+ }
+}
+
+/*!
+ * Calculate values for the ATA bus timing registers and store
+ * them into the hardware.
+ *
+ * @param xfer_mode specifies XFER xfer_mode
+ * @param pdev specifies platform_device
+ *
+ * @return EINVAL speed out of range, or illegal mode
+ */
+static int set_ata_bus_timing(u8 xfer_mode, struct platform_device *pdev)
+{
+ struct fsl_ata_platform_data *plat = (struct fsl_ata_platform_data *)
+ pdev->dev.platform_data;
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+
+ /* get the bus clock cycle time, in ns */
+ int T = 1 * 1000 * 1000 * 1000 / plat->get_clk_rate();
+ struct fsl_ata_time_regs tr = {0};
+ DPRINTK("clk_rate = %d T = %d\n", plat->get_clk_rate(), T);
+
+ /*
+ * every mode gets the same t_off and t_on
+ */
+ tr.time_off = 3;
+ tr.time_on = 3;
+
+ if (xfer_mode >= XFER_UDMA_0) {
+ int speed = xfer_mode - XFER_UDMA_0;
+ if (speed >= NR_UDMA_SPECS)
+ return -EINVAL;
+
+ tr.time_ack = (udma_specs[speed].tACK + T) / T;
+ tr.time_env = (udma_specs[speed].tENV_min + T) / T;
+ tr.time_rpx = (udma_specs[speed].tRP + T) / T + 2;
+
+ tr.time_zah = (udma_specs[speed].tZAH + T) / T;
+ tr.time_mlix = (udma_specs[speed].tMLI + T) / T;
+ tr.time_dvh = (udma_specs[speed].tDVH + T) / T + 1;
+ tr.time_dzfs = (udma_specs[speed].tDZFS + T) / T;
+
+ tr.time_dvs = (udma_specs[speed].tDVS + T) / T;
+ tr.time_cvh = (udma_specs[speed].tCVH + T) / T;
+ tr.time_ss = (udma_specs[speed].tSS + T) / T;
+ tr.time_cyc = (udma_specs[speed].tCYC + T) / T;
+ } else if (xfer_mode >= XFER_MW_DMA_0) {
+ int speed = xfer_mode - XFER_MW_DMA_0;
+ if (speed >= NR_MDMA_SPECS)
+ return -EINVAL;
+
+ tr.time_m = (mdma_specs[speed].tM + T) / T;
+ tr.time_jn = (mdma_specs[speed].tJNH + T) / T;
+ tr.time_d = (mdma_specs[speed].tD + T) / T;
+
+ tr.time_k = (mdma_specs[speed].tKW + T) / T;
+ } else {
+ int speed = xfer_mode - XFER_PIO_0;
+ if (speed >= NR_PIO_SPECS)
+ return -EINVAL;
+
+ tr.time_1 = (pio_specs[speed].t1 + T) / T;
+ tr.time_2w = (pio_specs[speed].t2_8 + T) / T;
+
+ tr.time_2r = (pio_specs[speed].t2_8 + T) / T;
+ tr.time_ax = (pio_specs[speed].tA + T) / T + 2;
+ tr.time_pio_rdx = 1;
+ tr.time_4 = (pio_specs[speed].t4 + T) / T;
+
+ tr.time_9 = (pio_specs[speed].t9 + T) / T;
+ }
+
+ update_timing_config(&tr, host);
+
+ return 0;
+}
+
+static void pata_fsl_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ set_ata_bus_timing(adev->pio_mode, to_platform_device(ap->dev));
+}
+
+#ifdef CONFIG_FSL_PATA_USE_DMA
+static void pata_fsl_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pata_fsl_priv *priv = ap->host->private_data;
+
+ priv->ultra = adev->dma_mode >= XFER_UDMA_0;
+
+ set_ata_bus_timing(adev->dma_mode, to_platform_device(ap->dev));
+}
+#endif
+
+static int pata_fsl_port_start(struct ata_port *ap)
+{
+ return 0;
+}
+
+#ifdef CONFIG_FSL_PATA_USE_DMA
+
+static irqreturn_t dma_callback(int channel, void *arg)
+{
+ struct ata_port *ap = arg;
+ struct pata_fsl_priv *priv = ap->host->private_data;
+ u8 __iomem *ata_regs = priv->fsl_ata_regs;
+
+ mcf_edma_stop_transfer(channel);
+ priv->dma_done = 1;
+ /*
+ * DMA is finished, so unmask INTRQ from the drive to allow the
+ * normal ISR to fire.
+ */
+#if 0
+ __raw_writel(FSL_ATA_INTR_ATA_INTRQ2, ata_regs + FSL_ATA_INT_EN);
+#else
+ WRITE_ATA8(FSL_ATA_INTR_ATA_INTRQ2, FSL_ATA_INT_EN);
+ WRITE_ATA8(FSL_ATA_CTRL_ATA_RST_B, FSL_ATA_CONTROL);
+#endif
+
+ return IRQ_HANDLED;
+}
+
+static void pata_fsl_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ int chan;
+ int dma_ultra;
+ u8 ata_control;
+ struct ata_port *ap = qc->ap;
+ struct pata_fsl_priv *priv = ap->host->private_data;
+ u8 __iomem *ata_regs = priv->fsl_ata_regs;
+#if 0
+ struct scatterlist *sg;
+ struct fsl_edma_requestbuf *pbuf;
+ unsigned int si;
+#endif
+ DPRINTK("ENTER\n");
+
+ /* reset the ATA FIFO first */
+ /*
+ WRITE_ATA8(FSL_ATA_CTRL_ATA_RST_B,FSL_ATA_CONTROL);
+ */
+ priv->dma_dir = qc->dma_dir;
+
+ /*
+ * Configure the on-chip ATA interface hardware.
+ */
+ dma_ultra = priv->ultra ?
+ FSL_ATA_CTRL_DMA_ULTRA : 0;
+
+ ata_control = FSL_ATA_CTRL_FIFO_RST_B |
+ FSL_ATA_CTRL_ATA_RST_B |
+ FSL_ATA_CTRL_DMA_PENDING |
+ dma_ultra;
+
+ if (qc->dma_dir == DMA_TO_DEVICE) {
+ chan = priv->dma_wchan;
+ ata_control |= FSL_ATA_CTRL_FIFO_TX_EN |
+ FSL_ATA_CTRL_DMA_WRITE;
+ } else {
+ chan = priv->dma_rchan;
+ ata_control |= FSL_ATA_CTRL_FIFO_RCV_EN;
+ }
+#if 0
+ __raw_writel(ata_control, ata_regs + FSL_ATA_CONTROL);
+ __raw_writel(plat->fifo_alarm, ata_regs + FSL_ATA_FIFO_ALARM);
+ __raw_writel(FSL_ATA_INTR_ATA_INTRQ1, ata_regs + FSL_ATA_INT_EN);
+#else
+ WRITE_ATA8(ata_control, FSL_ATA_CONTROL);
+ WRITE_ATA8(16/*plat->fifo_alarm*/, FSL_ATA_FIFO_ALARM);
+ WRITE_ATA8(FSL_ATA_INTR_ATA_INTRQ1, FSL_ATA_INT_EN);
+#endif
+ /*mb();*/
+
+ /*
+ * Set up the DMA completion callback.
+ */
+ /*
+ * Copy the sg list to an array.
+ */
+#if 0
+ priv->nsg = 0;
+ pbuf = priv->reqbuf;
+
+ for_each_sg(qc->sg, sg, qc->n_elem, si) {
+
+ /*dma_map_sg(NULL, sg, 1, priv->dma_dir); */
+
+ if (priv->dma_dir == DMA_TO_DEVICE) { /* WRITE */
+ pbuf->saddr = sg->dma_address;
+ pbuf->daddr = (dma_addr_t)(priv->fsl_ata_regs + 0x18);
+ pbuf->soff = 4;
+ pbuf->doff = 0;
+ } else { /* Read */
+ pbuf->daddr = sg->dma_address;
+ pbuf->saddr = (dma_addr_t)(priv->fsl_ata_regs + 0x18);
+ pbuf->doff = 4;
+ pbuf->soff = 0;
+ }
+ pbuf->attr = MCF_EDMA_TCD_ATTR_SSIZE_32BIT
+ |MCF_EDMA_TCD_ATTR_DSIZE_32BIT;
+ pbuf->minor_loop = 16*4; /* 16 longwords per request*/
+ pbuf->len = sg_dma_len(sg);
+
+ pbuf++;
+ priv->nsg++;
+ }
+
+ BUG_ON(*(unsigned char *)(ata_regs + FSL_ATA_FIFO_FILL));
+ mcf_edma_sg_config(chan, priv->reqbuf, priv->nsg);
+#else
+ if (priv->dma_dir == DMA_TO_DEVICE) {
+ mcf_edma_sglist_config(chan, qc->sg, qc->n_elem, priv->dma_dir,
+ (dma_addr_t)
+ ((io_ata_virt2phys((void *)priv->fsl_ata_regs)) + 0x18),
+ MCF_EDMA_TCD_ATTR_SSIZE_32BIT
+ | MCF_EDMA_TCD_ATTR_DSIZE_32BIT,
+ 4, 0, 8*4);
+ } else {
+
+ mcf_edma_sglist_config(chan, qc->sg, qc->n_elem, priv->dma_dir,
+ (dma_addr_t)
+ ((io_ata_virt2phys((void *)priv->fsl_ata_regs)) + 0x18),
+ MCF_EDMA_TCD_ATTR_SSIZE_32BIT
+ | MCF_EDMA_TCD_ATTR_DSIZE_32BIT,
+ 0, 4, 8*4);
+ }
+
+#endif
+ priv->dma_done = 0;
+
+ DPRINTK("EXIT\n");
+
+}
+
+static void pata_fsl_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pata_fsl_priv *priv = ap->host->private_data;
+ int chan;
+
+ /*
+ * Start the channel.
+ */
+ chan = qc->dma_dir == DMA_TO_DEVICE ? priv->dma_wchan : priv->dma_rchan;
+
+ mcf_edma_enable_transfer(chan);
+
+ ap->ops->sff_exec_command(ap, &qc->tf);
+}
+
+static void pata_fsl_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+/*
+ int chan;
+
+ chan = qc->dma_dir == DMA_TO_DEVICE ? priv->dma_wchan : priv->dma_rchan;
+ mcf_edma_stop_transfer(chan);
+*/
+/* do a dummy read as in ata_bmdma_stop */
+ ata_sff_dma_pause(ap);
+}
+
+static u8 pata_fsl_bmdma_status(struct ata_port *ap)
+{
+ struct pata_fsl_priv *priv = ap->host->private_data;
+
+ return priv->dma_done ? ATA_DMA_INTR : 0;
+}
+
+static void pata_fsl_dma_init(struct ata_port *ap)
+{
+ struct pata_fsl_priv *priv = ap->host->private_data;
+
+ priv->dma_rchan = -1;
+ priv->dma_wchan = -1;
+
+ priv->dma_rchan = mcf_edma_request_channel(MCF_EDMA_CHAN_ATA_RX,
+ dma_callback,
+ NULL, 0x6,
+ (void *)ap,
+ NULL,
+ "MCF ATA RX");
+ if (priv->dma_rchan < 0) {
+ dev_printk(KERN_ERR, ap->dev, "couldn't get RX DMA channel\n");
+ goto err_out;
+ }
+
+ priv->dma_wchan = mcf_edma_request_channel(MCF_EDMA_CHAN_ATA_TX,
+ dma_callback,
+ NULL, 0x6,
+ (void *)ap,
+ NULL,
+ "MCF ATA TX");
+ if (priv->dma_wchan < 0) {
+ dev_printk(KERN_ERR, ap->dev, "couldn't get TX DMA channel\n");
+ goto err_out;
+ }
+
+ dev_printk(KERN_ERR, ap->dev, "rchan=%d wchan=%d\n", priv->dma_rchan,
+ priv->dma_wchan);
+ return;
+
+err_out:
+ ap->mwdma_mask = 0;
+ ap->udma_mask = 0;
+ mcf_edma_free_channel(priv->dma_rchan, ap);
+ mcf_edma_free_channel(priv->dma_wchan, ap);
+ kfree(priv);
+}
+#endif /* CONFIG_FSL_PATA_USE_DMA */
+
+static void ata_dummy_noret(struct ata_port *ap) { return; }
+
+static struct scsi_host_template pata_fsl_sht = {
+ ATA_BMDMA_SHT(DRV_NAME),
+
+#ifdef CONFIG_FSL_PATA_USE_DMA
+ .sg_tablesize = MAX_FSL_SG,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+#endif
+};
+
+static struct ata_port_operations pata_fsl_port_ops = {
+#ifdef CONFIG_FSL_PATA_USE_DMA
+ .inherits = &ata_bmdma_port_ops,
+#else
+ .inherits = &ata_sff_port_ops,
+#endif
+ .set_piomode = pata_fsl_set_piomode,
+#ifdef CONFIG_FSL_PATA_USE_DMA
+ .set_dmamode = pata_fsl_set_dmamode,
+#endif
+ .cable_detect = ata_cable_40wire,
+
+#ifdef CONFIG_FSL_PATA_USE_DMA
+ .bmdma_setup = pata_fsl_bmdma_setup,
+ .bmdma_start = pata_fsl_bmdma_start,
+#endif
+
+ .sff_data_xfer = ata_sff_data_xfer_noirq,
+ .qc_prep = ata_noop_qc_prep,
+
+ .port_start = pata_fsl_port_start,
+
+#ifdef CONFIG_FSL_PATA_USE_DMA
+ .bmdma_stop = pata_fsl_bmdma_stop,
+ .bmdma_status = pata_fsl_bmdma_status,
+#endif
+};
+
+static void fsl_setup_port(struct ata_ioports *ioaddr)
+{
+ unsigned int shift = 2;
+
+ ioaddr->data_addr = ioaddr->cmd_addr + (ATA_REG_DATA << shift);
+ ioaddr->error_addr = ioaddr->cmd_addr + (ATA_REG_ERR << shift);
+ ioaddr->feature_addr = ioaddr->cmd_addr + (ATA_REG_FEATURE << shift);
+ ioaddr->nsect_addr = ioaddr->cmd_addr + (ATA_REG_NSECT << shift);
+ ioaddr->lbal_addr = ioaddr->cmd_addr + (ATA_REG_LBAL << shift);
+ ioaddr->lbam_addr = ioaddr->cmd_addr + (ATA_REG_LBAM << shift);
+ ioaddr->lbah_addr = ioaddr->cmd_addr + (ATA_REG_LBAH << shift);
+ ioaddr->device_addr = ioaddr->cmd_addr + (ATA_REG_DEVICE << shift);
+ ioaddr->status_addr = ioaddr->cmd_addr + (ATA_REG_STATUS << shift);
+ ioaddr->command_addr = ioaddr->cmd_addr + (ATA_REG_CMD << shift);
+}
+
+/**
+ * pata_fsl_probe - attach a platform interface
+ * @pdev: platform device
+ *
+ * Register a platform bus integrated ATA host controller
+ *
+ * The 3 platform device resources are used as follows:
+ *
+ * - I/O Base (IORESOURCE_MEM) virt. addr. of ATA controller regs
+ * - CTL Base (IORESOURCE_MEM) unused
+ * - IRQ (IORESOURCE_IRQ) platform IRQ assigned to ATA
+ *
+ */
+static int __devinit pata_fsl_probe(struct platform_device *pdev)
+{
+ struct resource *io_res;
+ struct ata_host *host;
+ struct ata_port *ap;
+ struct fsl_ata_platform_data *plat = (struct fsl_ata_platform_data *)
+ pdev->dev.platform_data;
+ struct pata_fsl_priv *priv;
+ u8 *ata_regs;
+ int ret;
+
+ DPRINTK("ENTER\n");
+ /*
+ * Get an ata_host structure for this device
+ */
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host)
+ return -ENOMEM;
+ ap = host->ports[0];
+ /*
+ * Allocate private data
+ */
+ priv = kzalloc(sizeof(struct pata_fsl_priv), GFP_KERNEL);
+ if (priv == NULL) {
+ /* free(host); */
+ return -ENOMEM;
+ }
+ host->private_data = priv;
+
+ /*
+ * Set up resources
+ */
+ if (unlikely(pdev->num_resources != 3)) {
+ dev_err(&pdev->dev, "invalid number of resources\n");
+ return -EINVAL;
+ }
+
+ io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ata_regs = (u8 *)io_res->start;
+ priv->fsl_ata_regs = ata_regs;
+ ap->ioaddr.cmd_addr = (void *)(ata_regs + FSL_ATA_DRIVE_DATA);
+ ap->ioaddr.ctl_addr = (void *)(ata_regs + FSL_ATA_DRIVE_CONTROL);
+ ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr;
+ ap->ops = &pata_fsl_port_ops;
+ ap->pio_mask = 0x3F;
+#ifdef CONFIG_FSL_PATA_USE_DMA
+ ap->mwdma_mask = 0x07;
+ ap->udma_mask = 0x1F;
+/* ap->udma_mask = plat->udma_mask; */
+/* pata_fsl_sht.sg_tablesize = plat->max_sg; */
+#else
+ ap->mwdma_mask = 0x00;
+ ap->udma_mask = 0x00;
+#endif
+ fsl_setup_port(&ap->ioaddr);
+
+ /*
+ * Do platform-specific initialization (e.g. allocate pins,
+ * turn on clock). After this call it is assumed that
+ * plat->get_clk_rate() can be called to calculate
+ * timing.
+ */
+ if (plat->init && plat->init(pdev)) {
+ /* REVISIT: don't leak what ata_host_alloc() allocated */
+ return -ENODEV;
+ }
+
+ /* Deassert the reset bit to enable the interface */
+ WRITE_ATA8(FSL_ATA_CTRL_ATA_RST_B, FSL_ATA_CONTROL);
+
+ /* Set initial timing and mode */
+ set_ata_bus_timing(XFER_PIO_4, pdev);
+
+#ifdef CONFIG_FSL_PATA_USE_DMA
+ /* get DMA ready */
+ pata_fsl_dma_init(ap);
+#endif
+
+ /*
+ * Enable the ATA INTRQ interrupt from the bus, but
+ * only allow the CPU to see it (INTRQ2) at this point.
+ * INTRQ1, which goes to the DMA, will be enabled later.
+ */
+#if 0
+ __raw_writel(FSL_ATA_INTR_ATA_INTRQ2, ata_regs + FSL_ATA_INT_EN);
+#else
+ WRITE_ATA8(FSL_ATA_INTR_ATA_INTRQ2, FSL_ATA_INT_EN);
+#endif
+
+ /* activate */
+ ret = ata_host_activate(host, platform_get_irq(pdev, 0),
+ ata_sff_interrupt, 0, &pata_fsl_sht);
+ DPRINTK("EXIT ret=%d\n", ret);
+ return ret;
+}
+
+/**
+ * pata_fsl_remove - unplug a platform interface
+ * @pdev: platform device
+ *
+ * A platform bus ATA device has been unplugged. Perform the needed
+ * cleanup. Also called on module unload for any active devices.
+ */
+static int __devexit pata_fsl_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct pata_fsl_priv *priv = host->private_data;
+ struct fsl_ata_platform_data *plat = (struct fsl_ata_platform_data *)
+ pdev->dev.platform_data;
+ u8 *ata_regs = priv->fsl_ata_regs;
+
+#if 0
+ __raw_writel(0, ata_regs + FSL_ATA_INT_EN); /* Disable interrupts */
+#else
+ WRITE_ATA8(0, FSL_ATA_INT_EN); /* Disable interrupts */
+#endif
+
+ ata_host_detach(host);
+
+ if (plat->exit)
+ plat->exit();
+
+ kfree(priv);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int pata_fsl_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct pata_fsl_priv *priv = host->private_data;
+ struct fsl_ata_platform_data *plat = (struct fsl_ata_platform_data *)
+ pdev->dev.platform_data;
+ u8 *ata_regs = priv->fsl_ata_regs;
+
+ /* Disable interrupts. */
+#if 0
+ __raw_writel(0, ata_regs + FSL_ATA_INT_EN);
+#else
+ WRITE_ATA8(0, FSL_ATA_INT_EN);
+#endif
+
+ if (plat->exit)
+ plat->exit();
+
+ return 0;
+}
+
+static int pata_fsl_resume(struct platform_device *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct pata_fsl_priv *priv = host->private_data;
+ struct fsl_ata_platform_data *plat = (struct fsl_ata_platform_data *)
+ pdev->dev.platform_data;
+ u8 *ata_regs = priv->fsl_ata_regs;
+
+ if (plat->init && plat->init(pdev))
+ return -ENODEV;
+ /* Deassert the reset bit to enable the interface */
+#if 0
+ __raw_writel(FSL_ATA_CTRL_ATA_RST_B, ata_regs + FSL_ATA_CONTROL);
+#else
+ WRITE_ATA8(FSL_ATA_CTRL_ATA_RST_B, FSL_ATA_CONTROL);
+#endif
+
+ /* Set initial timing and mode */
+ set_ata_bus_timing(XFER_PIO_4, pdev);
+
+ /*
+ * Enable hardware interrupts.
+ */
+#if 0
+ __raw_writel(FSL_ATA_INTR_ATA_INTRQ2, ata_regs + FSL_ATA_INT_EN);
+#else
+ WRITE_ATA8(FSL_ATA_INTR_ATA_INTRQ2, FSL_ATA_INT_EN);
+#endif
+
+ return 0;
+}
+#endif
+
+static struct platform_driver pata_fsl_driver = {
+ .probe = pata_fsl_probe,
+ .remove = __devexit_p(pata_fsl_remove),
+#ifdef CONFIG_PM
+ .suspend = pata_fsl_suspend,
+ .resume = pata_fsl_resume,
+#endif
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pata_fsl_init(void)
+{
+ int ret;
+
+ DPRINTK("ENTER\n");
+ ret = platform_driver_register(&pata_fsl_driver);
+ DPRINTK("EXIT ret=%d\n", ret);
+ return ret;
+}
+
+static void __exit pata_fsl_exit(void)
+{
+ platform_driver_unregister(&pata_fsl_driver);
+}
+module_init(pata_fsl_init);
+module_exit(pata_fsl_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("low-level driver for Freescale ATA");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);

View file

@ -1,25 +0,0 @@
From da0df827fa9600b3104d4b8d8cc3edbdd5a0849b Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:53 +0800
Subject: [PATCH 41/52] Fix CAU driver bug for SHA1 digest algorithm
Make the compiler to never inline a particular member
function.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
drivers/crypto/mcfcau-sha1.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
--- a/drivers/crypto/mcfcau-sha1.c
+++ b/drivers/crypto/mcfcau-sha1.c
@@ -60,7 +60,8 @@ struct mcfcau_sha1_ctx {
u8 buffer[64];
};
-static void mcfcau_sha1_transform(__u32 *digest, const char *in, __u32 *W)
+static noinline void mcfcau_sha1_transform(__u32 *digest,
+ const char *in, __u32 *W)
{
int i;
u32 *tmp_p;

View file

@ -1,24 +0,0 @@
From 77910a929baaf0ecba893e6e54857315384dc374 Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:54 +0800
Subject: [PATCH 42/52] Fix NEED_MULTIPLE_NODES unmet direct dependencies warning
Fix the warning that "(SINGLE_MEMORY_CHUNK) selects NEED_MULTIPLE_NODES
which has unmet direct dependencies (DISCONTIGMEM || NUMA)".
Signed-off-by: Alison Wang <b18965@freescale.com>
---
mm/Kconfig | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -84,7 +84,7 @@ config FLAT_NODE_MEM_MAP
#
config NEED_MULTIPLE_NODES
def_bool y
- depends on DISCONTIGMEM || NUMA
+ depends on DISCONTIGMEM || NUMA || COLDFIRE
config HAVE_MEMORY_PRESENT
def_bool y

View file

@ -1,33 +0,0 @@
From fa27f3e27863e3f4376864b144dc7506de124cf6 Mon Sep 17 00:00:00 2001
From: Jason Jin <Jason.jin@freescale.com>
Date: Thu, 4 Aug 2011 09:59:54 +0800
Subject: [PATCH 43/52] workaround for zero page used on ColdFire platform.
There is some issue for Coldfire platform to use the
zero page for read when there is memory fault. This is
a workaround for this, try to make kernel to use normal
memory instead.
Signed-off-by: Jason Jin <Jason.jin@freescale.com>
---
mm/memory.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2937,6 +2937,7 @@ static int do_anonymous_page(struct mm_s
if (check_stack_guard_page(vma, address) < 0)
return VM_FAULT_SIGBUS;
+#ifndef CONFIG_COLDFIRE
/* Use the zero-page for reads */
if (!(flags & FAULT_FLAG_WRITE)) {
entry = pte_mkspecial(pfn_pte(my_zero_pfn(address),
@@ -2946,6 +2947,7 @@ static int do_anonymous_page(struct mm_s
goto unlock;
goto setpte;
}
+#endif
/* Allocate our own private page. */
if (unlikely(anon_vma_prepare(vma)))

View file

@ -1,26 +0,0 @@
From ff4fb46407f3aee09432a897822e4934d5c6b3ff Mon Sep 17 00:00:00 2001
From: Jingchang Lu <b35083@freescale.com>
Date: Thu, 4 Aug 2011 09:59:54 +0800
Subject: [PATCH 44/52] Fix Max3353 otg toggle bug
The max3353 charge pump work with SOC FS/LS transceiver,
during dual role toggle, the root hub port should be powered
off to disable port status detection when suspend host mode,
otherwise it won't work properly when switch to host mode.
Signed-off-by: Jingchang Lu <b35083@freescale.com>
---
drivers/usb/host/ehci-fsl.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -528,7 +528,7 @@ static int ehci_fsl_suspend(struct devic
pdata->pm_portsc &= cpu_to_hc32(ehci, ~PORT_RWC_BITS);
pdata->suspended = 1;
-#if 0
+#if defined(CONFIG_USB_M5441X_MAX3353_FSLS)
/* clear PP to cut power to the port */
tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
tmp &= ~PORT_POWER;

View file

@ -1,24 +0,0 @@
From aedec75c772919fa77c33854d3389d8ca73c25bf Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:54 +0800
Subject: [PATCH 45/52] Add high-resolution kernel timer support
This patch fixed the bug that high-resolution kernel timer
could not be enabled. ARCH_USES_GETTIMEOFFSET is disabled.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
arch/m68k/Kconfig | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -64,7 +64,7 @@ config HZ
default 100
config ARCH_USES_GETTIMEOFFSET
- def_bool y
+ def_bool n
source "init/Kconfig"

View file

@ -1,109 +0,0 @@
From ab2284cd4730b9ea29937ee3a0ef1bcdc6b3159d Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:54 +0800
Subject: [PATCH 46/52] Convert rtc drivers to use the alarm_irq_enable method
Old rtc drivers use the ioctl method instead of the alarm_irq_enable
method for enabling alarm interupts. With the new virtualized RTC
rework, its important for drivers to use the alarm_irq_enable instead.
This patch converts the drivers that use the AIE ioctl method to
use the alarm_irq_enable method.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
drivers/rtc/rtc-m5441x.c | 22 +++++++++++-----------
drivers/rtc/rtc-mcf.c | 23 +++++++++++------------
2 files changed, 22 insertions(+), 23 deletions(-)
--- a/drivers/rtc/rtc-m5441x.c
+++ b/drivers/rtc/rtc-m5441x.c
@@ -400,17 +400,6 @@ static int mcf_rtc_ioctl(struct device *
writew((readw(MCF_RTC_IER) | PIE_BIT_DEF[i][1]), MCF_RTC_IER);
spin_unlock_irq(&rtc_lock);
return 0;
- case RTC_AIE_OFF:
- spin_lock_irq(&rtc_lock);
- writew((readw(MCF_RTC_IER) & ~MCF_RTC_ISR_ALM), MCF_RTC_IER);
- spin_unlock_irq(&rtc_lock);
- return 0;
-
- case RTC_AIE_ON:
- spin_lock_irq(&rtc_lock);
- writew((readw(MCF_RTC_IER) | MCF_RTC_ISR_ALM), MCF_RTC_IER);
- spin_unlock_irq(&rtc_lock);
- return 0;
case RTC_UIE_OFF: /* UIE is for the 1Hz interrupt */
spin_lock_irq(&rtc_lock);
@@ -427,6 +416,16 @@ static int mcf_rtc_ioctl(struct device *
return -ENOIOCTLCMD;
}
+static int mcf_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ if (enabled)
+ writew((readw(MCF_RTC_IER) | MCF_RTC_ISR_ALM), MCF_RTC_IER);
+ else
+ writew((readw(MCF_RTC_IER) & ~MCF_RTC_ISR_ALM), MCF_RTC_IER);
+
+ return 0;
+}
+
/*!
* This function reads the current RTC time into tm in Gregorian date.
*
@@ -534,6 +533,7 @@ static struct rtc_class_ops mcf_rtc_ops
.set_time = mcf_rtc_set_time,
.read_alarm = mcf_rtc_read_alarm,
.set_alarm = mcf_rtc_set_alarm,
+ .alarm_irq_enable = mcf_rtc_alarm_irq_enable,
};
static int __devinit mcf_rtc_probe(struct platform_device *pdev)
--- a/drivers/rtc/rtc-mcf.c
+++ b/drivers/rtc/rtc-mcf.c
@@ -298,18 +298,6 @@ static int mcf_rtc_ioctl(struct device *
writel((readl(MCF_RTC_IER) | PIE_BIT_DEF[i][1]), MCF_RTC_IER);
spin_unlock_irq(&rtc_lock);
return 0;
- case RTC_AIE_OFF:
- spin_lock_irq(&rtc_lock);
- writel((readl(MCF_RTC_IER) & ~MCF_RTC_ISR_ALM), MCF_RTC_IER);
- spin_unlock_irq(&rtc_lock);
- return 0;
-
- case RTC_AIE_ON:
- spin_lock_irq(&rtc_lock);
- writel((readl(MCF_RTC_IER) | MCF_RTC_ISR_ALM), MCF_RTC_IER);
- spin_unlock_irq(&rtc_lock);
- return 0;
-
case RTC_UIE_OFF: /* UIE is for the 1Hz interrupt */
spin_lock_irq(&rtc_lock);
writel((readl(MCF_RTC_IER) & ~MCF_RTC_ISR_1HZ), MCF_RTC_IER);
@@ -325,6 +313,16 @@ static int mcf_rtc_ioctl(struct device *
return -ENOIOCTLCMD;
}
+static int mcf_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ if (enabled)
+ writel((readl(MCF_RTC_IER) | MCF_RTC_ISR_ALM), MCF_RTC_IER);
+ else
+ writel((readl(MCF_RTC_IER) & ~MCF_RTC_ISR_ALM), MCF_RTC_IER);
+
+ return 0;
+}
+
/*!
* This function reads the current RTC time into tm in Gregorian date.
*
@@ -466,6 +464,7 @@ static struct rtc_class_ops mcf_rtc_ops
.read_alarm = mcf_rtc_read_alarm,
.set_alarm = mcf_rtc_set_alarm,
.proc = mcf_rtc_proc,
+ .alarm_irq_enable = mcf_rtc_alarm_irq_enable,
};
static int __devinit mcf_rtc_probe(struct platform_device *pdev)

View file

@ -1,37 +0,0 @@
From 7751684dc81d357bc9a226f12b9f12b14c824c54 Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:54 +0800
Subject: [PATCH 47/52] Fix DSPI compile error for MCF547x/MCF548x
Signed-off-by: Alison Wang <b18965@freescale.com>
---
arch/m68k/coldfire/m547x/devices.c | 2 +-
arch/m68k/include/asm/mcfdspi.h | 8 ++++++++
2 files changed, 9 insertions(+), 1 deletions(-)
--- a/arch/m68k/coldfire/m547x/devices.c
+++ b/arch/m68k/coldfire/m547x/devices.c
@@ -17,7 +17,7 @@
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
-#include <asm/mcfqspi.h>
+#include <asm/mcfdspi.h>
#ifdef CONFIG_SPI
--- a/arch/m68k/include/asm/mcfdspi.h
+++ b/arch/m68k/include/asm/mcfdspi.h
@@ -56,4 +56,12 @@ struct coldfire_spi_master {
u32 *irq_list;
void (*cs_control)(u8 cs, u8 command);
};
+
+struct coldfire_spi_chip {
+ u8 mode;
+ u8 bits_per_word;
+ u8 del_cs_to_clk;
+ u8 del_after_trans;
+ u16 void_write_data;
+};
#endif /*MCFDSPI_H_*/

View file

@ -1,75 +0,0 @@
From 2c83888b2170d3883c9316c4d94dddc4b7f9ec68 Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:55 +0800
Subject: [PATCH 48/52] Fix i2c driver bug when reinserting as module
Signed-off-by: Alison Wang <b18965@freescale.com>
---
drivers/i2c/busses/i2c-mcf-slave.c | 14 ++++++++++++++
drivers/i2c/busses/i2c-mcf.c | 14 ++++++++++++++
2 files changed, 28 insertions(+), 0 deletions(-)
--- a/drivers/i2c/busses/i2c-mcf-slave.c
+++ b/drivers/i2c/busses/i2c-mcf-slave.c
@@ -273,8 +273,15 @@ static int __init gen_i2c_proc_init(void
return -ENOMEM;
return 0;
}
+
+static int gen_i2c_proc_deinit(void)
+{
+ remove_proc_entry("driver/i2c-adaptor-register", NULL);
+ return 0;
+}
#else
static inline int gen_i2c_proc_init(void) { return 0; }
+static inline int gen_i2c_proc_deinit(void) { return 0; }
#endif /* CONFIG_PROC_FS */
/*
@@ -345,6 +352,13 @@ static int __init i2c_coldfire_init(void
static void __exit i2c_coldfire_exit(void)
{
+ int retval;
+
+ retval = gen_i2c_proc_deinit();
+ if (retval < 0)
+ printk(KERN_INFO "remove /proc/i2c-adaptor-register "
+ "for i2c slave mode failed!\n");
+
/* disable I2C and Interrupt */
MCF_I2CR &= ~(MCF_I2CR_IEN | MCF_I2CR_IIEN);
free_irq(IRQ, NULL);
--- a/drivers/i2c/busses/i2c-mcf.c
+++ b/drivers/i2c/busses/i2c-mcf.c
@@ -669,8 +669,15 @@ static int __init gen_i2c_proc_init(void
return -ENOMEM;
return 0;
}
+
+static int gen_i2c_proc_deinit(void)
+{
+ remove_proc_entry("driver/i2c-adaptor-register", NULL);
+ return 0;
+}
#else
static inline int gen_i2c_proc_init(void) { return 0; }
+static inline int gen_i2c_proc_deinit(void) { return 0; }
#endif /* CONFIG_PROC_FS */
static int __init coldfire_i2c_init(void)
@@ -687,6 +694,13 @@ static int __init coldfire_i2c_init(void
static void __exit coldfire_i2c_exit(void)
{
+ int retval;
+
+ retval = gen_i2c_proc_deinit();
+ if (retval < 0)
+ printk(KERN_INFO "remove /proc/i2c-adaptor-register "
+ "for i2c master mode failed!\n");
+
platform_driver_unregister(&mcf_i2c_driver);
}

View file

@ -1,113 +0,0 @@
From bb6fd2eef9359aff90f78b8791967a37e3284784 Mon Sep 17 00:00:00 2001
From: Jason Jin <jason.jin@freescale.com>
Date: Thu, 4 Aug 2011 09:59:55 +0800
Subject: [PATCH 49/52] Update FEC driver for MCF5445x and MCF54418
This patch fixed the bug that FEC could not support 10Mbps
for MCF5445x.
This patch also improved FEC performance.
Signed-off-by: Alison Wang <b18965@freescale.com>
Signed-off-by: Jason Jin <jason.jin@freescale.com>
---
arch/m68k/coldfire/m5441x/fec.c | 4 ++--
arch/m68k/coldfire/m5445x/fec.c | 17 +++++++++++++++--
drivers/net/fec.c | 9 +++++----
3 files changed, 22 insertions(+), 8 deletions(-)
--- a/arch/m68k/coldfire/m5441x/fec.c
+++ b/arch/m68k/coldfire/m5441x/fec.c
@@ -98,7 +98,7 @@ static struct fec_platform_data m54418_f
};
static struct platform_device fec0_coldfire_device = {
- .name = "m54418-fec",
+ .name = "coldfire-fec",
.id = 0,
.resource = fec0_resources,
.num_resources = ARRAY_SIZE(fec0_resources),
@@ -109,7 +109,7 @@ static struct platform_device fec0_coldf
#if defined(CONFIG_FEC2)
static struct platform_device fec1_coldfire_device = {
- .name = "m54418-fec",
+ .name = "coldfire-fec",
.id = 1,
.resource = fec1_resources,
.num_resources = ARRAY_SIZE(fec1_resources),
--- a/arch/m68k/coldfire/m5445x/fec.c
+++ b/arch/m68k/coldfire/m5445x/fec.c
@@ -34,6 +34,10 @@
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/fec.h>
+#include <linux/io.h>
+
#include <asm/pgtable.h>
#include <asm/traps.h>
@@ -89,19 +93,28 @@ static struct resource fec1_resources[]
};
#endif
+static struct fec_platform_data m5445x_fec_pdata = {
+ .phy = PHY_INTERFACE_MODE_RMII,
+};
static struct platform_device fec0_coldfire_device = {
- .name = "fec",
+ .name = "coldfire-fec",
.id = 0,
.resource = fec0_resources,
.num_resources = ARRAY_SIZE(fec0_resources),
+ .dev = {
+ .platform_data = &m5445x_fec_pdata,
+ }
};
#if defined(CONFIG_FEC2)
static struct platform_device fec1_coldfire_device = {
- .name = "fec",
+ .name = "coldfire-fec",
.id = 1,
.resource = fec1_resources,
.num_resources = ARRAY_SIZE(fec1_resources),
+ .dev = {
+ .platform_data = &m5445x_fec_pdata,
+ }
};
#endif
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -76,7 +76,7 @@ static struct platform_device_id fec_dev
.name = "imx28-fec",
.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME,
}, {
- .name = "m54418-fec",
+ .name = "coldfire-fec",
.driver_data = FEC_QUIRK_ENET_MAC,
},
{ }
@@ -341,8 +341,9 @@ fec_enet_start_xmit(struct sk_buff *skb,
/* Push the data cache so the CPM does not get stale memory
* data.
*/
- bdp->cbd_bufaddr = dma_map_single(&dev->dev, bufaddr,
- FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE);
+ bdp->cbd_bufaddr = __pa(bufaddr);
+ flush_dcache_range((unsigned long)skb->data,
+ (unsigned long)skb->data + skb->len);
/* Send it on its way. Tell FEC it's ready, interrupt when done,
* it's the last BD of the frame, and to put the CRC on the end.
@@ -1074,7 +1075,7 @@ static int fec_enet_alloc_buffers(struct
bdp = fep->tx_bd_base;
for (i = 0; i < TX_RING_SIZE; i++) {
- fep->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL);
+ fep->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_DMA);
bdp->cbd_sc = 0;
bdp->cbd_bufaddr = 0;

View file

@ -1,37 +0,0 @@
From 2411a3e2b5dfa4784bbe2548f8ef0ce1aea0379e Mon Sep 17 00:00:00 2001
From: Jason Jin <Jason.jin@freescale.com>
Date: Thu, 4 Aug 2011 09:59:55 +0800
Subject: [PATCH 50/52] Update the DMA map function for CF platform
In the DMA map, only the dcache need to be flushed.
Flush both dcache and icache will decrease the system
performance.
Signed-off-by: Jason Jin <Jason.jin@freescale.com>
---
arch/m68k/kernel/dma.c | 12 ++++++++++--
1 files changed, 10 insertions(+), 2 deletions(-)
--- a/arch/m68k/kernel/dma.c
+++ b/arch/m68k/kernel/dma.c
@@ -94,10 +94,18 @@ void dma_sync_single_for_device(struct d
{
switch (dir) {
case DMA_TO_DEVICE:
- cache_push(handle, size);
+#if defined(CONFIG_M5445X) || defined(CONFIG_M5441X)
+ flush_dcache_range(handle, handle + size);
+#else
+ flush_dcache();
+#endif
break;
case DMA_FROM_DEVICE:
- cache_clear(handle, size);
+#if defined(CONFIG_M5445X) || defined(CONFIG_M5441X)
+ cf_dcache_inv_range(handle, handle + size);
+#else
+ flush_dcache();
+#endif
break;
case PCI_DMA_BIDIRECTIONAL:
flush_dcache();

View file

@ -1,105 +0,0 @@
From 44d4e083f1527e0acc6d25eadd5258565c3b8a3a Mon Sep 17 00:00:00 2001
From: Alison Wang <b18965@freescale.com>
Date: Thu, 4 Aug 2011 09:59:55 +0800
Subject: [PATCH 51/52] Update SD/MMC over SPI driver for MCF54451 and MCF54418
This patch fixed the errors in initialization and module mode.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
arch/m68k/coldfire/m5445x/devices.c | 6 +++---
drivers/mmc/host/Kconfig | 8 ++++----
drivers/spi/spi.c | 4 ++++
3 files changed, 11 insertions(+), 7 deletions(-)
--- a/arch/m68k/coldfire/m5445x/devices.c
+++ b/arch/m68k/coldfire/m5445x/devices.c
@@ -20,7 +20,7 @@
#include <linux/interrupt.h>
#include <linux/init.h>
-#ifdef CONFIG_MMC_SPI
+#if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
#include <linux/mmc/host.h>
#include <linux/spi/mmc_spi.h>
#endif
@@ -107,7 +107,7 @@ static struct coldfire_dspi_chip codec_s
};
#endif
-#if defined(CONFIG_MMC_SPI)
+#if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
int mmc_spi_init(struct device *mmc_spi_device,
irqreturn_t mmc_spi_irq_handler(int irq, void *private),
void *irq_privatedata)
@@ -234,7 +234,7 @@ static struct spi_board_info spi_board_i
},
#endif
-#if defined(CONFIG_MMC_SPI)
+#if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
{
.modalias = "mmc_spi",
.max_speed_hz = 25000000,
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -369,7 +369,7 @@ config MMC_SPI
If unsure, or if your system has no SPI master driver, say N.
config M54451_SD_HW_DETECT
- tristate "use extern IRQ7 to detect SD/MMC card"
+ bool "use extern IRQ7 to detect SD/MMC card"
depends on MMC_SPI && M54451
default y
help
@@ -377,7 +377,7 @@ config M54451_SD_HW_DETECT
use irq7 to dectect the card inserting/removing.
config M5441X_SD_HW_DETECT
- tristate "use extern IRQ to detect SD/MMC card"
+ bool "use extern IRQ to detect SD/MMC card"
depends on MMC_SPI && M5441X
help
MMC/SD interface on 54418evb was over SPI. Enable this option will
@@ -388,14 +388,14 @@ choice
depends on M5441X_SD_HW_DETECT
config DETECT_USE_EXTERN_IRQ7
- tristate "based extern IRQ7"
+ bool "based extern IRQ7"
depends on M5441X_SD_HW_DETECT
help
MMC/SD cards using spi controller,
we use the extern irq7 to detect card.
config DETECT_USE_EXTERN_IRQ1
- tristate "based extern IRQ1"
+ bool "based extern IRQ1"
depends on M5441X_SD_HW_DETECT
help
MMC/SD cards using spi controller,
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -725,18 +725,22 @@ EXPORT_SYMBOL_GPL(spi_busnum_to_master);
*/
int spi_setup(struct spi_device *spi)
{
+#ifndef CONFIG_COLDFIRE
unsigned bad_bits;
+#endif
int status;
/* help drivers fail *cleanly* when they need options
* that aren't supported with their current master
*/
+#ifndef CONFIG_COLDFIRE
bad_bits = spi->mode & ~spi->master->mode_bits;
if (bad_bits) {
dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
bad_bits);
return -EINVAL;
}
+#endif
if (!spi->bits_per_word)
spi->bits_per_word = 8;

View file

@ -1,180 +0,0 @@
From 92b8d976e58fe5e6eb97aedcaa46e80c924fbc04 Mon Sep 17 00:00:00 2001
From: Wang Huan <wanghuan@zch06.freescale.net>
Date: Mon, 5 Sep 2011 08:59:46 +0800
Subject: [PATCH] Fix FEC driver bugs for MCF547x/MCF548x
This patch fixed kernel panic during flood ping with huge packets.
It also fixed the data integrity errors when running iozone on an
NFSv3-mounted file system.
Signed-off-by: Jason Jin <jason.jin@freescale.com>
---
arch/m68k/include/asm/cf_548x_cacheflush.h | 45 ++++++++++++++++++++++++---
drivers/net/fec_m547x.c | 18 +++++-----
2 files changed, 49 insertions(+), 14 deletions(-)
--- a/arch/m68k/include/asm/cf_548x_cacheflush.h
+++ b/arch/m68k/include/asm/cf_548x_cacheflush.h
@@ -27,8 +27,8 @@
unsigned long end_set; \
\
start_set = 0; \
- end_set = (unsigned long)LAST_DCACHE_ADDR; \
- \
+ end_set = (unsigned long)LAST_ICACHE_ADDR; \
+ asm("nop"); \
for (set = start_set; set <= end_set; set += (0x10 - 3)) {\
asm volatile("cpushl %%ic,(%0)\n" \
"\taddq%.l #1,%0\n" \
@@ -48,7 +48,7 @@
\
start_set = 0; \
end_set = (unsigned long)LAST_DCACHE_ADDR; \
- \
+ asm("nop"); \
for (set = start_set; set <= end_set; set += (0x10 - 3)) { \
asm volatile("cpushl %%dc,(%0)\n" \
"\taddq%.l #1,%0\n" \
@@ -68,7 +68,7 @@
\
start_set = 0; \
end_set = (unsigned long)LAST_DCACHE_ADDR; \
- \
+ asm("nop"); \
for (set = start_set; set <= end_set; set += (0x10 - 3)) { \
asm volatile("cpushl %%bc,(%0)\n" \
"\taddq%.l #1,%0\n" \
@@ -240,12 +240,47 @@ extern inline void flush_icache_range(un
}
}
+static inline void flush_dcache_range(unsigned long address,
+ unsigned long endaddr)
+{
+ unsigned long set;
+ unsigned long start_set;
+ unsigned long end_set;
+
+ start_set = address & _DCACHE_SET_MASK;
+ end_set = endaddr & _DCACHE_SET_MASK;
+
+ if (start_set > end_set) {
+ /* from the begining to the lowest address */
+ for (set = 0; set <= end_set; set += (0x10 - 3)) {
+ asm volatile("cpushl %%dc,(%0)\n"
+ "\taddq%.l #1,%0\n"
+ "\tcpushl %%dc,(%0)\n"
+ "\taddq%.l #1,%0\n"
+ "\tcpushl %%dc,(%0)\n"
+ "\taddq%.l #1,%0\n"
+ "\tcpushl %%dc,(%0)" : "=a" (set) : "a" (set));
+ }
+ /* next loop will finish the cache ie pass the hole */
+ end_set = LAST_ICACHE_ADDR;
+ }
+ for (set = start_set; set <= end_set; set += (0x10 - 3)) {
+ asm volatile("cpushl %%dc,(%0)\n"
+ "\taddq%.l #1,%0\n"
+ "\tcpushl %%dc,(%0)\n"
+ "\taddq%.l #1,%0\n"
+ "\tcpushl %%dc,(%0)\n"
+ "\taddq%.l #1,%0\n"
+ "\tcpushl %%dc,(%0)" : "=a" (set) : "a" (set));
+ }
+}
+
static inline void copy_to_user_page(struct vm_area_struct *vma,
struct page *page, unsigned long vaddr,
void *dst, void *src, int len)
{
memcpy(dst, src, len);
- flush_icache_user_page(vma, page, vaddr, len);
+ flush_dcache();
}
static inline void copy_from_user_page(struct vm_area_struct *vma,
struct page *page, unsigned long vaddr,
--- a/drivers/net/fec_m547x.c
+++ b/drivers/net/fec_m547x.c
@@ -34,7 +34,7 @@
#include <asm/m5485sram.h>
#include <asm/virtconvert.h>
#include <asm/irq.h>
-
+#include <asm/cf_cacheflush.h>
#include "fec_m547x.h"
#ifdef CONFIG_FEC_548x_ENABLE_FEC2
@@ -97,7 +97,7 @@ static void fec_interrupt_fec_rx_handler
static irqreturn_t fec_interrupt_handler(int irq, void *dev_id);
static void fec_interrupt_fec_tx_handler_fec0(void);
static void fec_interrupt_fec_rx_handler_fec0(void);
-static void fec_interrupt_fec_reinit(unsigned long data);
+static void fec_interrupt_fec_reinit(struct net_device *dev);
/* default fec0 address */
unsigned char fec_mac_addr_fec0[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x50 };
@@ -145,6 +145,7 @@ static int coldfire_fec_mdio_read(struct
#ifdef CONFIG_FEC_548x_SHARED_PHY
unsigned long base_addr = (unsigned long)FEC_BASE_ADDR_FEC0;
#else
+ struct net_device *dev = bus->priv;
unsigned long base_addr = (unsigned long) dev->base_addr;
#endif
int tries = 100;
@@ -179,6 +180,7 @@ static int coldfire_fec_mdio_write(struc
#ifdef CONFIG_FEC_548x_SHARED_PHY
unsigned long base_addr = (unsigned long)FEC_BASE_ADDR_FEC0;
#else
+ struct net_device *dev = bus->priv;
unsigned long base_addr = (unsigned long) dev->base_addr;
#endif
int tries = 100;
@@ -394,9 +396,6 @@ static int mcf547x_fec_open(struct net_d
dma_connect(channel, (int) fp->fecpriv_interrupt_fec_tx_handler);
- /* init tasklet for controller reinitialization */
- tasklet_init(&fp->fecpriv_tasklet_reinit,
- fec_interrupt_fec_reinit, (unsigned long) dev);
/* Reset FIFOs */
FEC_FECFRST(base_addr) |= FEC_SW_RST | FEC_RST_CTL;
@@ -790,6 +789,8 @@ static int mcf547x_fec_start_xmit(struct
/* flush data cache before initializing
* the descriptor and starting DMA */
+ flush_dcache_range(virt_to_phys(data_aligned),
+ virt_to_phys(data_aligned) + skb->len);
spin_lock_irq(&fp->fecpriv_lock);
@@ -1308,7 +1309,7 @@ irqreturn_t fec_interrupt_handler(int ir
netif_stop_queue(dev);
/* execute reinitialization as tasklet */
- tasklet_schedule(&fp->fecpriv_tasklet_reinit);
+ fec_interrupt_fec_reinit(dev);
fp->fecpriv_stat.rx_dropped++;
}
@@ -1343,10 +1344,9 @@ irqreturn_t fec_interrupt_handler(int ir
* when controller must be reinitialized.
*
*************************************************************************/
-void fec_interrupt_fec_reinit(unsigned long data)
+void fec_interrupt_fec_reinit(struct net_device *dev)
{
int i;
- struct net_device *dev = (struct net_device *)data;
struct fec_priv *fp = netdev_priv(dev);
unsigned long base_addr = (unsigned long) dev->base_addr;
@@ -1385,7 +1385,7 @@ void fec_interrupt_fec_reinit(unsigned l
fp->fecpriv_current_tx = fp->fecpriv_next_tx = 0;
/* flush entire data cache before restarting the DMA */
-
+ flush_dcache();
/* restart DMA from beginning */
MCD_startDma(fp->fecpriv_fec_rx_channel,
(char *) fp->fecpriv_rxdesc, 0,

View file

@ -1,49 +0,0 @@
From 633531cdbaa3ed70a364db78fd7f8ae11da3e394 Mon Sep 17 00:00:00 2001
From: Wang Huan <wanghuan@zch06.freescale.net>
Date: Wed, 14 Sep 2011 17:40:41 +0800
Subject: [PATCH] Fix LCD framebuffer driver data swap bug for MCF54418
This patch fixed LCD framebuffer driver data swap bug
for MCF54418.
Signed-off-by: Alison Wang <b18965@freescale.com>
---
drivers/video/fsl-ssd1289-fb.c | 13 ++++++++++---
1 files changed, 10 insertions(+), 3 deletions(-)
--- a/drivers/video/fsl-ssd1289-fb.c
+++ b/drivers/video/fsl-ssd1289-fb.c
@@ -54,8 +54,10 @@ static int ssd1289_spi_writeblock(struct
for (i = 0; i < SPI_LCD_BLOCK_SIZE; i++) {
if (i % 2 == 0)
spi_block_buffer[i] = 0x01;
- else if (flag == 1)
- spi_block_buffer[i] = *(daddr + (i >> 1));
+ else if ((flag == 1) && (i % 4 == 1))
+ spi_block_buffer[i] = *(daddr + (i >> 1) + 1);
+ else if ((flag == 1) && (i % 4 == 3))
+ spi_block_buffer[i] = *(daddr + (i >> 1) - 1);
else if (flag == 0)
spi_block_buffer[i] = 0;
}
@@ -331,6 +333,9 @@ static int ssd1289fbd(void *arg)
int i;
unsigned short *buf_p;
struct fsl_ssd1289_fb_info *fbinfo = info->par;
+#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
+ unsigned short tmp;
+#endif
#if defined(CONFIG_SSD1289_SPI_MODE)
unsigned char *bufspi_p;
int count;
@@ -344,7 +349,9 @@ static int ssd1289fbd(void *arg)
#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
for (i = 0; i < info->screen_size; i += 2) {
- ssd1289_write(info, *buf_p, 1);
+ tmp = ((((*buf_p) & 0x00ff) << 8) |
+ (((*buf_p) & 0xff00) >> 8));
+ ssd1289_write(info, tmp, 1);
buf_p++;
}
#elif defined(CONFIG_SSD1289_SPI_MODE)

View file

@ -1,34 +0,0 @@
From 78f4df7dfe913c68b8329dd84a24325b8f34217b Mon Sep 17 00:00:00 2001
From: Wang Huan <wanghuan@zch06.freescale.net>
Date: Mon, 8 Aug 2011 09:14:45 +0800
Subject: [PATCH] Fix SD/MMC/SDIO over SPI driver bug when reinserting as module
Signed-off-by: Alison Wang <b18965@freescale.com>
---
arch/m68k/coldfire/m5445x/devices.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
--- a/arch/m68k/coldfire/m5445x/devices.c
+++ b/arch/m68k/coldfire/m5445x/devices.c
@@ -136,6 +136,13 @@ int mmc_spi_init(struct device *mmc_spi_
return 0;
}
+void mmc_spi_exit(struct device *mmc_spi_device, void *irq_privatedata)
+{
+#if defined(CONFIG_M54451_SD_HW_DETECT)
+ free_irq(64 + 7, irq_privatedata);
+#endif
+}
+
static struct coldfire_dspi_chip dspi_sd_chip_info = {
.mode = SPI_MODE_0,
.bits_per_word = 8,
@@ -154,6 +161,7 @@ static struct coldfire_dspi_chip dspi_sd
static struct mmc_spi_platform_data mcf54451_mmc_pdata = {
.ocr_mask = MMC_VDD_33_34,
.init = mmc_spi_init,
+ .exit = mmc_spi_exit,
};
#endif

View file

@ -1,30 +0,0 @@
From 358154a6d0dd87305c6af92810220f8a17641c07 Mon Sep 17 00:00:00 2001
From: Wang Huan <wanghuan@zch06.freescale.net>
Date: Mon, 8 Aug 2011 10:49:53 +0800
Subject: [PATCH] Fix i2c driver could not work as module
Signed-off-by: Alison Wang <b18965@freescale.com>
---
arch/m68k/coldfire/m5445x/devices.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
--- a/arch/m68k/coldfire/m5445x/devices.c
+++ b/arch/m68k/coldfire/m5445x/devices.c
@@ -426,7 +426,7 @@ static inline void mcf5445x_init_pata(vo
/*
* I2C
*/
-#if defined(CONFIG_I2C)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static struct resource coldfire_i2c_resources[] = {
{ /* I/O */
.start = 0xFC058000,
@@ -464,7 +464,7 @@ static int __init mcf5445x_init_devices(
mcf5445x_init_pata();
#endif
-#if defined(CONFIG_I2C)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
mcf5445x_init_i2c();
#endif
return 0;

View file

@ -1,10 +0,0 @@
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1975,6 +1975,7 @@
config FEC_548x
tristate "MCF547x/MCF548x Fast Ethernet Controller support"
depends on M547X_8X
+ select PHYLIB
help
The MCF547x and MCF548x have a built-in Fast Ethernet Controller.
Saying Y here will include support for this device in the kernel.