[Armadeus-commitlog] armadeus branch, master, updated. armadeus-4.0-2556-g6972059
Brought to you by:
sszy
|
From: Julien B a. A. <ar...@us...> - 2011-10-20 20:57:24
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "armadeus".
The branch, master has been updated
via 69720594364daab6be7d80551cd4bcec240d48cb (commit)
via e841f0981bd118c248c6fdb35a28a4a86f252c3c (commit)
via f4e7fb2b418027b961de456439e4356fe630d6bb (commit)
from 3238df0e1e749342a1e474937a2ace2d4e32a450 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 69720594364daab6be7d80551cd4bcec240d48cb
Merge: e841f09 3238df0
Author: Julien Boibessot <jul...@ar...>
Date: Thu Oct 20 22:56:27 2011 +0200
Merge branch 'master' of ssh://armadeus.git.sourceforge.net/gitroot/armadeus/armadeus
commit e841f0981bd118c248c6fdb35a28a4a86f252c3c
Author: Julien Boibessot <jul...@ar...>
Date: Thu Oct 20 22:54:14 2011 +0200
[LINUX] 2.6.38: Add SCC and SAHARA to APF51 default config
commit f4e7fb2b418027b961de456439e4356fe630d6bb
Author: Julien Boibessot <jul...@ar...>
Date: Thu Oct 20 22:07:12 2011 +0200
[LINUX] Fixes 442-* patches
-----------------------------------------------------------------------
Summary of changes:
.../armadeus/apf51/apf51-linux-2.6.38.config | 5 +
...NGR00126692-3-1-add_drivers_mxc_directory.patch | 38 +
...00126692-3-add_hw-events_vpu_srtc_drivers.patch | 2264 ++++++++++++++++++++
...26692-3-add_mx23_mx25_mx28_security_stuff.patch | 806 -------
...0-add_scc2_and_sahara_drivers_without_rng.patch | 159 +-
5 files changed, 2374 insertions(+), 898 deletions(-)
create mode 100644 patches/linux/2.6.38/442-freescale-0034-ENGR00126692-3-1-add_drivers_mxc_directory.patch
create mode 100644 patches/linux/2.6.38/442-freescale-0034-ENGR00126692-3-add_hw-events_vpu_srtc_drivers.patch
diff --git a/buildroot/target/device/armadeus/apf51/apf51-linux-2.6.38.config b/buildroot/target/device/armadeus/apf51/apf51-linux-2.6.38.config
index 27f854a..f1f46e0 100644
--- a/buildroot/target/device/armadeus/apf51/apf51-linux-2.6.38.config
+++ b/buildroot/target/device/armadeus/apf51/apf51-linux-2.6.38.config
@@ -241,6 +241,11 @@ CONFIG_STAGING=y
# CONFIG_STAGING_EXCLUDE_BUILD is not set
CONFIG_IIO=m
CONFIG_MCP49x2=m
+# CONFIG_MXC_HWEVENT is not set
+# CONFIG_MXC_VPU is not set
+# CONFIG_MXC_VPU_IRAM is not set
+CONFIG_MXC_SECURITY_SCC2=m
+CONFIG_MXC_SAHARA=m
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_POSIX_ACL=y
diff --git a/patches/linux/2.6.38/442-freescale-0034-ENGR00126692-3-1-add_drivers_mxc_directory.patch b/patches/linux/2.6.38/442-freescale-0034-ENGR00126692-3-1-add_drivers_mxc_directory.patch
new file mode 100644
index 0000000..ed81f65
--- /dev/null
+++ b/patches/linux/2.6.38/442-freescale-0034-ENGR00126692-3-1-add_drivers_mxc_directory.patch
@@ -0,0 +1,38 @@
+Index: linux-2.6.38.8/drivers/Kconfig
+===================================================================
+--- linux-2.6.38.8.orig/drivers/Kconfig 2011-10-20 18:47:06.000000000 +0200
++++ linux-2.6.38.8/drivers/Kconfig 2011-10-20 18:47:40.000000000 +0200
+@@ -117,4 +117,7 @@
+ source "drivers/platform/Kconfig"
+
+ source "drivers/clk/Kconfig"
++
++source "drivers/mxc/Kconfig"
++
+ endmenu
+Index: linux-2.6.38.8/drivers/Makefile
+===================================================================
+--- linux-2.6.38.8.orig/drivers/Makefile 2011-10-20 18:48:13.000000000 +0200
++++ linux-2.6.38.8/drivers/Makefile 2011-10-20 18:49:22.000000000 +0200
+@@ -93,6 +93,7 @@
+ obj-$(CONFIG_CPU_FREQ) += cpufreq/
+ obj-$(CONFIG_CPU_IDLE) += cpuidle/
+ obj-$(CONFIG_DMA_ENGINE) += dma/
++obj-$(CONFIG_ARCH_MXC) += mxc/
+ obj-$(CONFIG_MMC) += mmc/
+ obj-$(CONFIG_MEMSTICK) += memstick/
+ obj-$(CONFIG_NEW_LEDS) += leds/
+Index: linux-2.6.38.8/drivers/mxc/Kconfig
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.38.8/drivers/mxc/Kconfig 2011-10-20 18:51:18.000000000 +0200
+@@ -0,0 +1,9 @@
++# drivers/video/Kconfig
++
++if ARCH_MXC
++
++menu "MXC support drivers"
++
++endmenu
++
++endif
diff --git a/patches/linux/2.6.38/442-freescale-0034-ENGR00126692-3-add_hw-events_vpu_srtc_drivers.patch b/patches/linux/2.6.38/442-freescale-0034-ENGR00126692-3-add_hw-events_vpu_srtc_drivers.patch
new file mode 100644
index 0000000..f90b18e
--- /dev/null
+++ b/patches/linux/2.6.38/442-freescale-0034-ENGR00126692-3-add_hw-events_vpu_srtc_drivers.patch
@@ -0,0 +1,2264 @@
+From 3eb9039c5392abaabd96d08c0006ea4066346a60 Mon Sep 17 00:00:00 2001
+From: Dinh Nguyen <Din...@fr...>
+Date: Tue, 17 Aug 2010 16:46:40 -0500
+Subject: [PATCH] ENGR00126692-3: Upgrade kernel to 2.6.35
+
+This patch contains changes to /drivers files
+Contains all checkpatch and copyright fixes.
+
+Acked-by: Rob Herring <r.h...@fr...>
+Signed-off-by: Dinh Nguyen <Din...@fr...>
+---
+ Changes by Armadeus systems:
+ - extracted from original patch
+
+ drivers/mxc/Kconfig | 39 +
+ drivers/mxc/Makefile | 17 +
+ drivers/mxc/hw_event/Kconfig | 11 +
+ drivers/mxc/hw_event/Makefile | 1 +
+ drivers/mxc/hw_event/mxc_hw_event.c | 266 +
+ drivers/mxc/vpu/Kconfig | 30 +
+ drivers/mxc/vpu/Makefile | 10 +
+ drivers/mxc/vpu/mxc_vl2cc.c | 124 +
+ drivers/mxc/vpu/mxc_vpu.c | 862 ++
+ drivers/rtc/Kconfig | 46 +
+ drivers/rtc/Makefile | 5 +
+ drivers/rtc/rtc-mxc_v2.c | 766 ++
+ arch/arm/plat-mxc/include/mach/hw_events.h
+
+Index: linux-2.6.38.8/drivers/mxc/hw_event/Kconfig
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.38.8/drivers/mxc/hw_event/Kconfig 2011-10-20 19:28:29.000000000 +0200
+@@ -0,0 +1,11 @@
++menu "MXC HARDWARE EVENT"
++
++config MXC_HWEVENT
++ bool "MXC Hardware Event Handler"
++ default y
++ depends on ARCH_MXC
++ help
++ If you plan to use the Hardware Event Handler in the MXC, say
++ Y here. If unsure, select Y.
++
++endmenu
+Index: linux-2.6.38.8/drivers/mxc/hw_event/Makefile
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.38.8/drivers/mxc/hw_event/Makefile 2011-10-20 19:28:29.000000000 +0200
+@@ -0,0 +1 @@
++obj-$(CONFIG_MXC_HWEVENT) += mxc_hw_event.o
+Index: linux-2.6.38.8/drivers/mxc/hw_event/mxc_hw_event.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.38.8/drivers/mxc/hw_event/mxc_hw_event.c 2011-10-20 19:28:29.000000000 +0200
+@@ -0,0 +1,266 @@
++/*
++ * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * 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
++ */
++
++/*!
++ * mxc_hw_event.c
++ * Collect the hardware events, send to user by netlink
++ */
++
++#include <linux/slab.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/netlink.h>
++#include <linux/sched.h>
++#include <linux/list.h>
++#include <linux/signal.h>
++#include <linux/freezer.h>
++#include <linux/kthread.h>
++#include <net/sock.h>
++
++#include <mach/hw_events.h>
++
++#define EVENT_POOL_SIZE 10
++
++struct hw_event_elem {
++ struct mxc_hw_event event;
++ struct list_head list;
++};
++
++static struct sock *nl_event_sock; /* netlink socket */
++static struct list_head event_head;
++static struct list_head free_head;
++static struct hw_event_elem events_pool[EVENT_POOL_SIZE]; /* event pool */
++static DEFINE_SPINLOCK(list_lock);
++static DECLARE_WAIT_QUEUE_HEAD(event_wq);
++static unsigned int seq; /* send seq */
++static int initialized;
++static struct task_struct *hwevent_kthread;
++
++/*!
++ * main HW event handler thread
++ */
++static int hw_event_thread(void *data)
++{
++ struct sk_buff *skb = NULL;
++ struct nlmsghdr *nlh = NULL;
++ unsigned int size;
++ struct hw_event_elem *event, *n;
++ LIST_HEAD(tmp_head);
++ DEFINE_WAIT(wait);
++
++ while (1) {
++
++ prepare_to_wait(&event_wq, &wait, TASK_INTERRUPTIBLE);
++ /* wait for event coming */
++ if (!freezing(current) && !kthread_should_stop() &&
++ list_empty(&event_head))
++ schedule();
++ finish_wait(&event_wq, &wait);
++
++ try_to_freeze();
++
++ if (kthread_should_stop())
++ break;
++
++ /* fetch event from list */
++ spin_lock_irq(&list_lock);
++ tmp_head = event_head;
++ tmp_head.prev->next = &tmp_head;
++ tmp_head.next->prev = &tmp_head;
++ /* clear the event list head */
++ INIT_LIST_HEAD(&event_head);
++ spin_unlock_irq(&list_lock);
++
++ list_for_each_entry_safe(event, n, &tmp_head, list) {
++
++ size = NLMSG_SPACE(sizeof(struct mxc_hw_event));
++ skb = alloc_skb(size, GFP_KERNEL);
++ if (!skb) {
++ /* if failed alloc skb, we drop this event */
++ printk(KERN_WARNING
++ "mxc_hw_event: skb_alloc() failed\n");
++ goto alloc_failure;
++ }
++
++ /* put the netlink header struct to skb */
++ nlh =
++ NLMSG_PUT(skb, 0, seq++, NLMSG_DONE,
++ size - sizeof(*nlh));
++
++ /* fill the netlink data */
++ memcpy((struct mxc_hw_event *)NLMSG_DATA(nlh),
++ &event->event, sizeof(struct mxc_hw_event));
++
++ /* free the event node, set to unused */
++ spin_lock_irq(&list_lock);
++ list_move(&event->list, &free_head);
++ spin_unlock_irq(&list_lock);
++
++ /* send to all process that create this socket */
++ NETLINK_CB(skb).pid = 0; /* sender pid */
++ NETLINK_CB(skb).dst_group = HW_EVENT_GROUP;
++ /* broadcast the event */
++ netlink_broadcast(nl_event_sock, skb, 0, HW_EVENT_GROUP,
++ GFP_KERNEL);
++
++ continue;
++ nlmsg_failure:
++ printk(KERN_WARNING
++ "mxc_hw_event: No tailroom for NLMSG in skb\n");
++ alloc_failure:
++ /* free the event node, set to unused */
++ spin_lock_irq(&list_lock);
++ list_del(&event->list);
++ list_add_tail(&event->list, &free_head);
++ spin_unlock_irq(&list_lock);
++ }
++ }
++
++ return 0;
++}
++
++/*!
++ *
++ * @priority the event priority, REALTIME, EMERENCY, NORMAL
++ * @new_event event id to be send
++ */
++int hw_event_send(int priority, struct mxc_hw_event *new_event)
++{
++ unsigned int size;
++ struct sk_buff *skb = NULL;
++ struct nlmsghdr *nlh = NULL;
++ struct mxc_hw_event *event;
++ struct hw_event_elem *event_elem;
++ int ret;
++ unsigned long flag;
++ struct list_head *list_node;
++
++ if (!initialized) {
++ pr_info("HW Event module has not been initialized\n");
++ return -1;
++ }
++
++ if (priority == HWE_HIGH_PRIORITY) {
++ /**
++ * the most high priority event,
++ * we send it immediatly.
++ */
++
++ size = NLMSG_SPACE(sizeof(struct mxc_hw_event));
++
++ /* alloc skb */
++ if (in_interrupt()) {
++ skb = alloc_skb(size, GFP_ATOMIC);
++ } else {
++ skb = alloc_skb(size, GFP_KERNEL);
++ }
++ if (!skb) {
++ /* if failed alloc skb, we drop this event */
++ printk(KERN_WARNING
++ "hw_event send: skb_alloc() failed\n");
++ goto send_later;
++ }
++
++ /* put the netlink header struct to skb */
++ nlh = NLMSG_PUT(skb, 0, seq++, NLMSG_DONE, size - sizeof(*nlh));
++
++ /* fill the netlink data */
++ event = (struct mxc_hw_event *)NLMSG_DATA(nlh);
++ memcpy(event, new_event, sizeof(struct mxc_hw_event));
++
++ /* send to all process that create this socket */
++ NETLINK_CB(skb).pid = 0; /* sender pid */
++ NETLINK_CB(skb).dst_group = HW_EVENT_GROUP;
++ /* broadcast the event */
++ ret = netlink_broadcast(nl_event_sock, skb, 0, HW_EVENT_GROUP,
++ in_interrupt() ? GFP_ATOMIC :
++ GFP_KERNEL);
++ if (ret) {
++
++ nlmsg_failure:
++ /* send failed */
++ kfree_skb(skb);
++ goto send_later;
++ }
++
++ return 0;
++ }
++
++ send_later:
++ spin_lock_irqsave(&list_lock, flag);
++ if (list_empty(&free_head)) {
++ spin_unlock_irqrestore(&list_lock, flag);
++ /* no more free event node */
++ printk(KERN_WARNING "mxc_event send: no more free node\n");
++ return -1;
++ }
++
++ /* get a free node from free list, and added to event list */
++ list_node = free_head.next;
++ /* fill event */
++ event_elem = list_entry(list_node, struct hw_event_elem, list);
++ event_elem->event = *new_event;
++ list_move(list_node, &event_head);
++ spin_unlock_irqrestore(&list_lock, flag);
++
++ wake_up(&event_wq);
++
++ return 0;
++}
++
++static int __init mxc_hw_event_init(void)
++{
++ int i;
++
++ /* initial the list head for event and free */
++ INIT_LIST_HEAD(&free_head);
++ INIT_LIST_HEAD(&event_head);
++
++ /* initial the free list */
++ for (i = 0; i < EVENT_POOL_SIZE; i++)
++ list_add_tail(&events_pool[i].list, &free_head);
++
++ /* create netlink kernel sock */
++ nl_event_sock =
++ netlink_kernel_create(&init_net, NETLINK_USERSOCK, 0, NULL, NULL,
++ THIS_MODULE);
++ if (!nl_event_sock) {
++ printk(KERN_WARNING
++ "mxc_hw_event: Fail to create netlink socket.\n");
++ return 1;
++ }
++
++ hwevent_kthread = kthread_run(hw_event_thread, NULL, "hwevent");
++ if (IS_ERR(hwevent_kthread)) {
++ printk(KERN_WARNING
++ "mxc_hw_event: Fail to create hwevent thread.\n");
++ return 1;
++ }
++
++ initialized = 1;
++
++ return 0;
++}
++
++static void __exit mxc_hw_event_exit(void)
++{
++ kthread_stop(hwevent_kthread);
++ /* wait for thread completion */
++ sock_release(nl_event_sock->sk_socket);
++}
++
++module_init(mxc_hw_event_init);
++module_exit(mxc_hw_event_exit);
++
++EXPORT_SYMBOL(hw_event_send);
++MODULE_LICENSE("GPL");
+Index: linux-2.6.38.8/drivers/mxc/vpu/Kconfig
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.38.8/drivers/mxc/vpu/Kconfig 2011-10-20 19:28:29.000000000 +0200
+@@ -0,0 +1,30 @@
++#
++# Codec configuration
++#
++
++menu "MXC VPU(Video Processing Unit) support"
++
++config MXC_VPU
++ tristate "Support for MXC VPU(Video Processing Unit)"
++ depends on (ARCH_MX3 || ARCH_MX27 || ARCH_MX37 || ARCH_MX5)
++ default y
++ ---help---
++ The VPU codec device provides codec function for H.264/MPEG4/H.263,
++ as well as MPEG2/VC-1/DivX on some platforms.
++
++config MXC_VPU_IRAM
++ tristate "Use IRAM as temporary buffer for VPU to enhance performace"
++ depends on (ARCH_MX37 || ARCH_MX5)
++ default y
++ ---help---
++ The VPU can use internal RAM as temporary buffer to save external
++ memroy bandwith, thus to enhance video performance.
++
++config MXC_VPU_DEBUG
++ bool "MXC VPU debugging"
++ depends on MXC_VPU != n
++ help
++ This is an option for the developers; most people should
++ say N here. This enables MXC VPU driver debugging.
++
++endmenu
+Index: linux-2.6.38.8/drivers/mxc/vpu/Makefile
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.38.8/drivers/mxc/vpu/Makefile 2011-10-20 19:28:29.000000000 +0200
+@@ -0,0 +1,10 @@
++#
++# Makefile for the VPU drivers.
++#
++
++obj-$(CONFIG_MXC_VPU) += vpu.o
++vpu-objs := mxc_vpu.o mxc_vl2cc.o
++
++ifeq ($(CONFIG_MXC_VPU_DEBUG),y)
++EXTRA_CFLAGS += -DDEBUG
++endif
+Index: linux-2.6.38.8/drivers/mxc/vpu/mxc_vl2cc.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.38.8/drivers/mxc/vpu/mxc_vl2cc.c 2011-10-20 19:28:29.000000000 +0200
+@@ -0,0 +1,124 @@
++/*
++ * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * 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
++ */
++
++/*!
++ * @file mxc_vl2cc.c
++ *
++ * @brief VL2CC initialization and flush operation implementation
++ *
++ * @ingroup VL2CC
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/io.h>
++
++#define VL2CC_CTRL_OFFSET (0x100)
++#define VL2CC_AUXCTRL_OFFSET (0x104)
++#define VL2CC_INVWAY_OFFSET (0x77C)
++#define VL2CC_CLEANWAY_OFFSET (0x7BC)
++
++/*! VL2CC clock handle. */
++static struct clk *vl2cc_clk;
++static u32 *vl2cc_base;
++
++/*!
++ * Initialization function of VL2CC. Remap the VL2CC base address.
++ *
++ * @return status 0 success.
++ */
++int vl2cc_init(u32 vl2cc_hw_base)
++{
++ vl2cc_base = ioremap(vl2cc_hw_base, SZ_8K - 1);
++ if (vl2cc_base == NULL) {
++ printk(KERN_INFO "vl2cc: Unable to ioremap\n");
++ return -ENOMEM;
++ }
++
++ vl2cc_clk = clk_get(NULL, "vl2cc_clk");
++ if (IS_ERR(vl2cc_clk)) {
++ printk(KERN_INFO "vl2cc: Unable to get clock\n");
++ iounmap(vl2cc_base);
++ return -EIO;
++ }
++
++ printk(KERN_INFO "VL2CC initialized\n");
++ return 0;
++}
++
++/*!
++ * Enable VL2CC hardware
++ */
++void vl2cc_enable(void)
++{
++ volatile u32 reg;
++
++ clk_enable(vl2cc_clk);
++
++ /* Disable VL2CC */
++ reg = __raw_readl(vl2cc_base + VL2CC_CTRL_OFFSET);
++ reg &= 0xFFFFFFFE;
++ __raw_writel(reg, vl2cc_base + VL2CC_CTRL_OFFSET);
++
++ /* Set the latency for data RAM reads, data RAM writes, tag RAM and
++ * dirty RAM to 1 cycle - write 0x0 to AUX CTRL [11:0] and also
++ * configure the number of ways to 8 - write 8 to AUX CTRL [16:13]
++ */
++ reg = __raw_readl(vl2cc_base + VL2CC_AUXCTRL_OFFSET);
++ reg &= 0xFFFE1000; /* Clear [16:13] too */
++ reg |= (0x8 << 13); /* [16:13] = 8; */
++ __raw_writel(reg, vl2cc_base + VL2CC_AUXCTRL_OFFSET);
++
++ /* Invalidate the VL2CC ways - write 0xff to INV BY WAY and poll the
++ * register until its value is 0x0
++ */
++ __raw_writel(0xff, vl2cc_base + VL2CC_INVWAY_OFFSET);
++ while (__raw_readl(vl2cc_base + VL2CC_INVWAY_OFFSET) != 0x0)
++ ;
++
++ /* Enable VL2CC */
++ reg = __raw_readl(vl2cc_base + VL2CC_CTRL_OFFSET);
++ reg |= 0x1;
++ __raw_writel(reg, vl2cc_base + VL2CC_CTRL_OFFSET);
++}
++
++/*!
++ * Flush VL2CC
++ */
++void vl2cc_flush(void)
++{
++ __raw_writel(0xff, vl2cc_base + VL2CC_CLEANWAY_OFFSET);
++ while (__raw_readl(vl2cc_base + VL2CC_CLEANWAY_OFFSET) != 0x0)
++ ;
++}
++
++/*!
++ * Disable VL2CC
++ */
++void vl2cc_disable(void)
++{
++ __raw_writel(0, vl2cc_base + VL2CC_CTRL_OFFSET);
++ clk_disable(vl2cc_clk);
++}
++
++/*!
++ * Cleanup VL2CC
++ */
++void vl2cc_cleanup(void)
++{
++ clk_put(vl2cc_clk);
++ iounmap(vl2cc_base);
++}
+Index: linux-2.6.38.8/drivers/mxc/vpu/mxc_vpu.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.38.8/drivers/mxc/vpu/mxc_vpu.c 2011-10-20 19:28:29.000000000 +0200
+@@ -0,0 +1,862 @@
++/*
++ * Copyright 2006-2010 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * 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
++ */
++
++/*!
++ * @file mxc_vpu.c
++ *
++ * @brief VPU system initialization and file operation implementation
++ *
++ * @ingroup VPU
++ */
++
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <linux/stat.h>
++#include <linux/platform_device.h>
++#include <linux/kdev_t.h>
++#include <linux/dma-mapping.h>
++#include <linux/iram_alloc.h>
++#include <linux/wait.h>
++#include <linux/list.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/fsl_devices.h>
++#include <linux/uaccess.h>
++#include <linux/io.h>
++#include <linux/slab.h>
++
++#include <asm/sizes.h>
++#include <mach/clock.h>
++#include <mach/hardware.h>
++
++#include <mach/mxc_vpu.h>
++
++struct vpu_priv {
++ struct fasync_struct *async_queue;
++};
++
++/* To track the allocated memory buffer */
++typedef struct memalloc_record {
++ struct list_head list;
++ struct vpu_mem_desc mem;
++} memalloc_record;
++
++struct iram_setting {
++ u32 start;
++ u32 end;
++};
++
++static DEFINE_SPINLOCK(vpu_lock);
++static LIST_HEAD(head);
++
++static int vpu_major;
++static int vpu_clk_usercount;
++static struct class *vpu_class;
++static struct vpu_priv vpu_data;
++static u8 open_count;
++static struct clk *vpu_clk;
++static struct vpu_mem_desc bitwork_mem = { 0 };
++static struct vpu_mem_desc pic_para_mem = { 0 };
++static struct vpu_mem_desc user_data_mem = { 0 };
++static struct vpu_mem_desc share_mem = { 0 };
++
++static void __iomem *vpu_base;
++static int vpu_irq;
++static u32 phy_vpu_base_addr;
++static struct mxc_vpu_platform_data *vpu_plat;
++
++/* IRAM setting */
++static struct iram_setting iram;
++
++/* implement the blocking ioctl */
++static int codec_done;
++static wait_queue_head_t vpu_queue;
++
++static u32 workctrl_regsave[6];
++static u32 rd_ptr_regsave[4];
++static u32 wr_ptr_regsave[4];
++static u32 dis_flag_regsave[4];
++
++#define READ_REG(x) __raw_readl(vpu_base + x)
++#define WRITE_REG(val, x) __raw_writel(val, vpu_base + x)
++#define SAVE_WORK_REGS do { \
++ int i; \
++ for (i = 0; i < ARRAY_SIZE(workctrl_regsave)/2; i++) \
++ workctrl_regsave[i] = READ_REG(BIT_WORK_CTRL_BUF_REG(i));\
++} while (0)
++#define RESTORE_WORK_REGS do { \
++ int i; \
++ for (i = 0; i < ARRAY_SIZE(workctrl_regsave)/2; i++) \
++ WRITE_REG(workctrl_regsave[i], BIT_WORK_CTRL_BUF_REG(i));\
++} while (0)
++#define SAVE_CTRL_REGS do { \
++ int i; \
++ for (i = ARRAY_SIZE(workctrl_regsave)/2; \
++ i < ARRAY_SIZE(workctrl_regsave); i++) \
++ workctrl_regsave[i] = READ_REG(BIT_WORK_CTRL_BUF_REG(i));\
++} while (0)
++#define RESTORE_CTRL_REGS do { \
++ int i; \
++ for (i = ARRAY_SIZE(workctrl_regsave)/2; \
++ i < ARRAY_SIZE(workctrl_regsave); i++) \
++ WRITE_REG(workctrl_regsave[i], BIT_WORK_CTRL_BUF_REG(i));\
++} while (0)
++#define SAVE_RDWR_PTR_REGS do { \
++ int i; \
++ for (i = 0; i < ARRAY_SIZE(rd_ptr_regsave); i++) \
++ rd_ptr_regsave[i] = READ_REG(BIT_RD_PTR_REG(i)); \
++ for (i = 0; i < ARRAY_SIZE(wr_ptr_regsave); i++) \
++ wr_ptr_regsave[i] = READ_REG(BIT_WR_PTR_REG(i)); \
++} while (0)
++#define RESTORE_RDWR_PTR_REGS do { \
++ int i; \
++ for (i = 0; i < ARRAY_SIZE(rd_ptr_regsave); i++) \
++ WRITE_REG(rd_ptr_regsave[i], BIT_RD_PTR_REG(i)); \
++ for (i = 0; i < ARRAY_SIZE(wr_ptr_regsave); i++) \
++ WRITE_REG(wr_ptr_regsave[i], BIT_WR_PTR_REG(i)); \
++} while (0)
++#define SAVE_DIS_FLAG_REGS do { \
++ int i; \
++ for (i = 0; i < ARRAY_SIZE(dis_flag_regsave); i++) \
++ dis_flag_regsave[i] = READ_REG(BIT_FRM_DIS_FLG_REG(i)); \
++} while (0)
++#define RESTORE_DIS_FLAG_REGS do { \
++ int i; \
++ for (i = 0; i < ARRAY_SIZE(dis_flag_regsave); i++) \
++ WRITE_REG(dis_flag_regsave[i], BIT_FRM_DIS_FLG_REG(i)); \
++} while (0)
++
++/*!
++ * Private function to alloc dma buffer
++ * @return status 0 success.
++ */
++static int vpu_alloc_dma_buffer(struct vpu_mem_desc *mem)
++{
++ mem->cpu_addr = (unsigned long)
++ dma_alloc_coherent(NULL, PAGE_ALIGN(mem->size),
++ (dma_addr_t *) (&mem->phy_addr),
++ GFP_DMA | GFP_KERNEL);
++ pr_debug("[ALLOC] mem alloc cpu_addr = 0x%x\n", mem->cpu_addr);
++ if ((void *)(mem->cpu_addr) == NULL) {
++ printk(KERN_ERR "Physical memory allocation error!\n");
++ return -1;
++ }
++ return 0;
++}
++
++/*!
++ * Private function to free dma buffer
++ */
++static void vpu_free_dma_buffer(struct vpu_mem_desc *mem)
++{
++ if (mem->cpu_addr != 0) {
++ dma_free_coherent(0, PAGE_ALIGN(mem->size),
++ (void *)mem->cpu_addr, mem->phy_addr);
++ }
++}
++
++/*!
++ * Private function to free buffers
++ * @return status 0 success.
++ */
++static int vpu_free_buffers(void)
++{
++ struct memalloc_record *rec, *n;
++ struct vpu_mem_desc mem;
++
++ list_for_each_entry_safe(rec, n, &head, list) {
++ mem = rec->mem;
++ if (mem.cpu_addr != 0) {
++ vpu_free_dma_buffer(&mem);
++ pr_debug("[FREE] freed paddr=0x%08X\n", mem.phy_addr);
++ /* delete from list */
++ list_del(&rec->list);
++ kfree(rec);
++ }
++ }
++
++ return 0;
++}
++
++/*!
++ * @brief vpu interrupt handler
++ */
++static irqreturn_t vpu_irq_handler(int irq, void *dev_id)
++{
++ struct vpu_priv *dev = dev_id;
++
++ READ_REG(BIT_INT_STATUS);
++ WRITE_REG(0x1, BIT_INT_CLEAR);
++
++ if (dev->async_queue)
++ kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
++
++ /*
++ * Clock is gated on when dec/enc started, gate it off when
++ * interrupt is received.
++ */
++ clk_disable(vpu_clk);
++
++ codec_done = 1;
++ wake_up_interruptible(&vpu_queue);
++
++ return IRQ_HANDLED;
++}
++
++/*!
++ * @brief open function for vpu file operation
++ *
++ * @return 0 on success or negative error code on error
++ */
++static int vpu_open(struct inode *inode, struct file *filp)
++{
++ spin_lock(&vpu_lock);
++ if ((open_count++ == 0) && cpu_is_mx32())
++ vl2cc_enable();
++ filp->private_data = (void *)(&vpu_data);
++ spin_unlock(&vpu_lock);
++ return 0;
++}
++
++/*!
++ * @brief IO ctrl function for vpu file operation
++ * @param cmd IO ctrl command
++ * @return 0 on success or negative error code on error
++ */
++static int vpu_ioctl(struct inode *inode, struct file *filp, u_int cmd,
++ u_long arg)
++{
++ int ret = 0;
++
++ switch (cmd) {
++ case VPU_IOC_PHYMEM_ALLOC:
++ {
++ struct memalloc_record *rec;
++
++ rec = kzalloc(sizeof(*rec), GFP_KERNEL);
++ if (!rec)
++ return -ENOMEM;
++
++ ret = copy_from_user(&(rec->mem),
++ (struct vpu_mem_desc *)arg,
++ sizeof(struct vpu_mem_desc));
++ if (ret) {
++ kfree(rec);
++ return -EFAULT;
++ }
++
++ pr_debug("[ALLOC] mem alloc size = 0x%x\n",
++ rec->mem.size);
++
++ ret = vpu_alloc_dma_buffer(&(rec->mem));
++ if (ret == -1) {
++ kfree(rec);
++ printk(KERN_ERR
++ "Physical memory allocation error!\n");
++ break;
++ }
++ ret = copy_to_user((void __user *)arg, &(rec->mem),
++ sizeof(struct vpu_mem_desc));
++ if (ret) {
++ kfree(rec);
++ ret = -EFAULT;
++ break;
++ }
++
++ spin_lock(&vpu_lock);
++ list_add(&rec->list, &head);
++ spin_unlock(&vpu_lock);
++
++ break;
++ }
++ case VPU_IOC_PHYMEM_FREE:
++ {
++ struct memalloc_record *rec, *n;
++ struct vpu_mem_desc vpu_mem;
++
++ ret = copy_from_user(&vpu_mem,
++ (struct vpu_mem_desc *)arg,
++ sizeof(struct vpu_mem_desc));
++ if (ret)
++ return -EACCES;
++
++ pr_debug("[FREE] mem freed cpu_addr = 0x%x\n",
++ vpu_mem.cpu_addr);
++ if ((void *)vpu_mem.cpu_addr != NULL) {
++ vpu_free_dma_buffer(&vpu_mem);
++ }
++
++ spin_lock(&vpu_lock);
++ list_for_each_entry_safe(rec, n, &head, list) {
++ if (rec->mem.cpu_addr == vpu_mem.cpu_addr) {
++ /* delete from list */
++ list_del(&rec->list);
++ kfree(rec);
++ break;
++ }
++ }
++ spin_unlock(&vpu_lock);
++
++ break;
++ }
++ case VPU_IOC_WAIT4INT:
++ {
++ u_long timeout = (u_long) arg;
++ if (!wait_event_interruptible_timeout
++ (vpu_queue, codec_done != 0,
++ msecs_to_jiffies(timeout))) {
++ printk(KERN_WARNING "VPU blocking: timeout.\n");
++ ret = -ETIME;
++ } else if (signal_pending(current)) {
++ printk(KERN_WARNING
++ "VPU interrupt received.\n");
++ ret = -ERESTARTSYS;
++ } else
++ codec_done = 0;
++ break;
++ }
++ case VPU_IOC_VL2CC_FLUSH:
++ if (cpu_is_mx32()) {
++ vl2cc_flush();
++ }
++ break;
++ case VPU_IOC_IRAM_SETTING:
++ {
++ ret = copy_to_user((void __user *)arg, &iram,
++ sizeof(struct iram_setting));
++ if (ret)
++ ret = -EFAULT;
++
++ break;
++ }
++ case VPU_IOC_CLKGATE_SETTING:
++ {
++ u32 clkgate_en;
++
++ if (get_user(clkgate_en, (u32 __user *) arg))
++ return -EFAULT;
++
++ if (clkgate_en) {
++ clk_enable(vpu_clk);
++ } else {
++ clk_disable(vpu_clk);
++ }
++
++ break;
++ }
++ case VPU_IOC_GET_SHARE_MEM:
++ {
++ spin_lock(&vpu_lock);
++ if (share_mem.cpu_addr != 0) {
++ ret = copy_to_user((void __user *)arg,
++ &share_mem,
++ sizeof(struct vpu_mem_desc));
++ spin_unlock(&vpu_lock);
++ break;
++ } else {
++ if (copy_from_user(&share_mem,
++ (struct vpu_mem_desc *)arg,
++ sizeof(struct vpu_mem_desc))) {
++ spin_unlock(&vpu_lock);
++ return -EFAULT;
++ }
++ if (vpu_alloc_dma_buffer(&share_mem) == -1)
++ ret = -EFAULT;
++ else {
++ if (copy_to_user((void __user *)arg,
++ &share_mem,
++ sizeof(struct
++ vpu_mem_desc)))
++ ret = -EFAULT;
++ }
++ }
++ spin_unlock(&vpu_lock);
++ break;
++ }
++ case VPU_IOC_GET_WORK_ADDR:
++ {
++ if (bitwork_mem.cpu_addr != 0) {
++ ret =
++ copy_to_user((void __user *)arg,
++ &bitwork_mem,
++ sizeof(struct vpu_mem_desc));
++ break;
++ } else {
++ if (copy_from_user(&bitwork_mem,
++ (struct vpu_mem_desc *)arg,
++ sizeof(struct vpu_mem_desc)))
++ return -EFAULT;
++
++ if (vpu_alloc_dma_buffer(&bitwork_mem) == -1)
++ ret = -EFAULT;
++ else if (copy_to_user((void __user *)arg,
++ &bitwork_mem,
++ sizeof(struct
++ vpu_mem_desc)))
++ ret = -EFAULT;
++ }
++ break;
++ }
++ case VPU_IOC_GET_PIC_PARA_ADDR:
++ {
++ if (pic_para_mem.cpu_addr != 0) {
++ ret =
++ copy_to_user((void __user *)arg,
++ &pic_para_mem,
++ sizeof(struct vpu_mem_desc));
++ break;
++ } else {
++ if (copy_from_user(&pic_para_mem,
++ (struct vpu_mem_desc *)arg,
++ sizeof(struct vpu_mem_desc)))
++ return -EFAULT;
++
++ if (vpu_alloc_dma_buffer(&pic_para_mem) == -1)
++ ret = -EFAULT;
++ else if (copy_to_user((void __user *)arg,
++ &pic_para_mem,
++ sizeof(struct
++ vpu_mem_desc)))
++ ret = -EFAULT;
++ }
++ break;
++ }
++ case VPU_IOC_GET_USER_DATA_ADDR:
++ {
++ if (user_data_mem.cpu_addr != 0) {
++ ret =
++ copy_to_user((void __user *)arg,
++ &user_data_mem,
++ sizeof(struct vpu_mem_desc));
++ break;
++ } else {
++ if (copy_from_user(&user_data_mem,
++ (struct vpu_mem_desc *)arg,
++ sizeof(struct vpu_mem_desc)))
++ return -EFAULT;
++
++ if (vpu_alloc_dma_buffer(&user_data_mem) == -1)
++ ret = -EFAULT;
++ else if (copy_to_user((void __user *)arg,
++ &user_data_mem,
++ sizeof(struct
++ vpu_mem_desc)))
++ ret = -EFAULT;
++ }
++ break;
++ }
++ case VPU_IOC_SYS_SW_RESET:
++ {
++ if (vpu_plat->reset)
++ vpu_plat->reset();
++
++ break;
++ }
++ case VPU_IOC_REG_DUMP:
++ break;
++ case VPU_IOC_PHYMEM_DUMP:
++ break;
++ default:
++ {
++ printk(KERN_ERR "No such IOCTL, cmd is %d\n", cmd);
++ break;
++ }
++ }
++ return ret;
++}
++
++/*!
++ * @brief Release function for vpu file operation
++ * @return 0 on success or negative error code on error
++ */
++static int vpu_release(struct inode *inode, struct file *filp)
++{
++ spin_lock(&vpu_lock);
++ if (open_count > 0 && !(--open_count)) {
++ vpu_free_buffers();
++
++ if (cpu_is_mx32())
++ vl2cc_disable();
++
++ /* Free shared memory when vpu device is idle */
++ vpu_free_dma_buffer(&share_mem);
++ share_mem.cpu_addr = 0;
++ }
++ spin_unlock(&vpu_lock);
++
++ return 0;
++}
++
++/*!
++ * @brief fasync function for vpu file operation
++ * @return 0 on success or negative error code on error
++ */
++static int vpu_fasync(int fd, struct file *filp, int mode)
++{
++ struct vpu_priv *dev = (struct vpu_priv *)filp->private_data;
++ return fasync_helper(fd, filp, mode, &dev->async_queue);
++}
++
++/*!
++ * @brief memory map function of harware registers for vpu file operation
++ * @return 0 on success or negative error code on error
++ */
++static int vpu_map_hwregs(struct file *fp, struct vm_area_struct *vm)
++{
++ unsigned long pfn;
++
++ vm->vm_flags |= VM_IO | VM_RESERVED;
++ vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot);
++ pfn = phy_vpu_base_addr >> PAGE_SHIFT;
++ pr_debug("size=0x%x, page no.=0x%x\n",
++ (int)(vm->vm_end - vm->vm_start), (int)pfn);
++ return remap_pfn_range(vm, vm->vm_start, pfn, vm->vm_end - vm->vm_start,
++ vm->vm_page_prot) ? -EAGAIN : 0;
++}
++
++/*!
++ * @brief memory map function of memory for vpu file operation
++ * @return 0 on success or negative error code on error
++ */
++static int vpu_map_mem(struct file *fp, struct vm_area_struct *vm)
++{
++ int request_size;
++ request_size = vm->vm_end - vm->vm_start;
++
++ pr_debug(" start=0x%x, pgoff=0x%x, size=0x%x\n",
++ (unsigned int)(vm->vm_start), (unsigned int)(vm->vm_pgoff),
++ request_size);
++
++ vm->vm_flags |= VM_IO | VM_RESERVED;
++ vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot);
++
++ return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff,
++ request_size, vm->vm_page_prot) ? -EAGAIN : 0;
++
++}
++
++/*!
++ * @brief memory map interface for vpu file operation
++ * @return 0 on success or negative error code on error
++ */
++static int vpu_mmap(struct file *fp, struct vm_area_struct *vm)
++{
++ if (vm->vm_pgoff)
++ return vpu_map_mem(fp, vm);
++ else
++ return vpu_map_hwregs(fp, vm);
++}
++
++struct file_operations vpu_fops = {
++ .owner = THIS_MODULE,
++ .open = vpu_open,
++ .ioctl = vpu_ioctl,
++ .release = vpu_release,
++ .fasync = vpu_fasync,
++ .mmap = vpu_mmap,
++};
++
++/*!
++ * This function is called by the driver framework to initialize the vpu device.
++ * @param dev The device structure for the vpu passed in by the framework.
++ * @return 0 on success or negative error code on error
++ */
++static int vpu_dev_probe(struct platform_device *pdev)
++{
++ int err = 0;
++ struct device *temp_class;
++ struct resource *res;
++ unsigned long addr = 0;
++
++ vpu_plat = pdev->dev.platform_data;
++
++ iram_alloc(VPU_IRAM_SIZE, &addr);
++ if (addr == 0)
++ iram.start = iram.end = 0;
++ else {
++ iram.start = addr;
++ iram.end = addr + VPU_IRAM_SIZE - 1;
++ }
++
++ if (cpu_is_mx32()) {
++ err = vl2cc_init(iram.start);
++ if (err != 0)
++ return err;
++ }
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ printk(KERN_ERR "vpu: unable to get vpu base addr\n");
++ return -ENODEV;
++ }
++ phy_vpu_base_addr = res->start;
++ vpu_base = ioremap(res->start, res->end - res->start);
++
++ vpu_major = register_chrdev(vpu_major, "mxc_vpu", &vpu_fops);
++ if (vpu_major < 0) {
++ printk(KERN_ERR "vpu: unable to get a major for VPU\n");
++ err = -EBUSY;
++ goto error;
++ }
++
++ vpu_class = class_create(THIS_MODULE, "mxc_vpu");
++ if (IS_ERR(vpu_class)) {
++ err = PTR_ERR(vpu_class);
++ goto err_out_chrdev;
++ }
++
++ temp_class = device_create(vpu_class, NULL, MKDEV(vpu_major, 0),
++ NULL, "mxc_vpu");
++ if (IS_ERR(temp_class)) {
++ err = PTR_ERR(temp_class);
++ goto err_out_class;
++ }
++
++ vpu_clk = clk_get(&pdev->dev, "vpu_clk");
++ if (IS_ERR(vpu_clk)) {
++ err = -ENOENT;
++ goto err_out_class;
++ }
++
++ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++ if (!res) {
++ printk(KERN_ERR "vpu: unable to get vpu interrupt\n");
++ err = -ENXIO;
++ goto err_out_class;
++ }
++ vpu_irq = res->start;
++
++ err = request_irq(vpu_irq, vpu_irq_handler, 0, "VPU_CODEC_IRQ",
++ (void *)(&vpu_data));
++ if (err)
++ goto err_out_class;
++
++ printk(KERN_INFO "VPU initialized\n");
++ goto out;
++
++ err_out_class:
++ device_destroy(vpu_class, MKDEV(vpu_major, 0));
++ class_destroy(vpu_class);
++ err_out_chrdev:
++ unregister_chrdev(vpu_major, "mxc_vpu");
++ error:
++ iounmap(vpu_base);
++ if (cpu_is_mx32()) {
++ vl2cc_cleanup();
++ }
++ out:
++ return err;
++}
++
++static int vpu_dev_remove(struct platform_device *pdev)
++{
++ free_irq(vpu_irq, &vpu_data);
++ iounmap(vpu_base);
++ iram_free(iram.start, VPU_IRAM_SIZE);
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static int vpu_suspend(struct platform_device *pdev, pm_message_t state)
++{
++ int i;
++ unsigned long timeout;
++
++ /* Wait for vpu go to idle state, suspect vpu cannot be changed
++ to idle state after about 1 sec */
++ if (open_count > 0) {
++ timeout = jiffies + HZ;
++ clk_enable(vpu_clk);
++ while (READ_REG(BIT_BUSY_FLAG)) {
++ msleep(1);
++ if (time_after(jiffies, timeout))
++ goto out;
++ }
++ clk_disable(vpu_clk);
++ }
++
++ /* Make sure clock is disabled before suspend */
++ vpu_clk_usercount = clk_get_usecount(vpu_clk);
++ for (i = 0; i < vpu_clk_usercount; i++)
++ clk_disable(vpu_clk);
++
++ if (!cpu_is_mx53()) {
++ clk_enable(vpu_clk);
++ if (bitwork_mem.cpu_addr != 0) {
++ SAVE_WORK_REGS;
++ SAVE_CTRL_REGS;
++ SAVE_RDWR_PTR_REGS;
++ SAVE_DIS_FLAG_REGS;
++
++ WRITE_REG(0x1, BIT_BUSY_FLAG);
++ WRITE_REG(VPU_SLEEP_REG_VALUE, BIT_RUN_COMMAND);
++ while (READ_REG(BIT_BUSY_FLAG))
++ ;
++ }
++ clk_disable(vpu_clk);
++ }
++
++ if (cpu_is_mx37() || cpu_is_mx51())
++ mxc_pg_enable(pdev);
++
++ return 0;
++
++out:
++ clk_disable(vpu_clk);
++ return -EAGAIN;
++
++}
++
++static int vpu_resume(struct platform_device *pdev)
++{
++ int i;
++
++ if (cpu_is_mx37() || cpu_is_mx51())
++ mxc_pg_disable(pdev);
++
++ if (cpu_is_mx53())
++ goto recover_clk;
++
++ clk_enable(vpu_clk);
++ if (bitwork_mem.cpu_addr != 0) {
++ u32 *p = (u32 *) bitwork_mem.cpu_addr;
++ u32 data;
++ u16 data_hi;
++ u16 data_lo;
++
++ RESTORE_WORK_REGS;
++
++ WRITE_REG(0x0, BIT_RESET_CTRL);
++ WRITE_REG(0x0, BIT_CODE_RUN);
++
++ /*
++ * Re-load boot code, from the codebuffer in external RAM.
++ * Thankfully, we only need 4096 bytes, same for all platforms.
++ */
++ if (cpu_is_mx51()) {
++ for (i = 0; i < 2048; i += 4) {
++ data = p[(i / 2) + 1];
++ data_hi = (data >> 16) & 0xFFFF;
++ data_lo = data & 0xFFFF;
++ WRITE_REG((i << 16) | data_hi, BIT_CODE_DOWN);
++ WRITE_REG(((i + 1) << 16) | data_lo,
++ BIT_CODE_DOWN);
++
++ data = p[i / 2];
++ data_hi = (data >> 16) & 0xFFFF;
++ data_lo = data & 0xFFFF;
++ WRITE_REG(((i + 2) << 16) | data_hi,
++ BIT_CODE_DOWN);
++ WRITE_REG(((i + 3) << 16) | data_lo,
++ BIT_CODE_DOWN);
++ }
++ } else {
++ for (i = 0; i < 2048; i += 2) {
++ if (cpu_is_mx37())
++ data = swab32(p[i / 2]);
++ else
++ data = p[i / 2];
++ data_hi = (data >> 16) & 0xFFFF;
++ data_lo = data & 0xFFFF;
++
++ WRITE_REG((i << 16) | data_hi, BIT_CODE_DOWN);
++ WRITE_REG(((i + 1) << 16) | data_lo,
++ BIT_CODE_DOWN);
++ }
++ }
++
++ RESTORE_CTRL_REGS;
++
++ WRITE_REG(BITVAL_PIC_RUN, BIT_INT_ENABLE);
++
++ WRITE_REG(0x1, BIT_BUSY_FLAG);
++ WRITE_REG(0x1, BIT_CODE_RUN);
++ while (READ_REG(BIT_BUSY_FLAG))
++ ;
++
++ RESTORE_RDWR_PTR_REGS;
++ RESTORE_DIS_FLAG_REGS;
++
++ WRITE_REG(0x1, BIT_BUSY_FLAG);
++ WRITE_REG(VPU_WAKE_REG_VALUE, BIT_RUN_COMMAND);
++ while (READ_REG(BIT_BUSY_FLAG))
++ ;
++ }
++ clk_disable(vpu_clk);
++
++recover_clk:
++ /* Recover vpu clock */
++ for (i = 0; i < vpu_clk_usercount; i++)
++ clk_enable(vpu_clk);
++
++ return 0;
++}
++#else
++#define vpu_suspend NULL
++#define vpu_resume NULL
++#endif /* !CONFIG_PM */
++
++/*! Driver definition
++ *
++ */
++static struct platform_driver mxcvpu_driver = {
++ .driver = {
++ .name = "mxc_vpu",
++ },
++ .probe = vpu_dev_probe,
++ .remove = vpu_dev_remove,
++ .suspend = vpu_suspend,
++ .resume = vpu_resume,
++};
++
++static int __init vpu_init(void)
++{
++ int ret = platform_driver_register(&mxcvpu_driver);
++
++ init_waitqueue_head(&vpu_queue);
++
++ return ret;
++}
++
++static void __exit vpu_exit(void)
++{
++ if (vpu_major > 0) {
++ device_destroy(vpu_class, MKDEV(vpu_major, 0));
++ class_destroy(vpu_class);
++ unregister_chrdev(vpu_major, "mxc_vpu");
++ vpu_major = 0;
++ }
++
++ if (cpu_is_mx32()) {
++ vl2cc_cleanup();
++ }
++
++ vpu_free_dma_buffer(&bitwork_mem);
++ vpu_free_dma_buffer(&pic_para_mem);
++ vpu_free_dma_buffer(&user_data_mem);
++
++ clk_put(vpu_clk);
++
++ platform_driver_unregister(&mxcvpu_driver);
++ return;
++}
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("Linux VPU driver for Freescale i.MX/MXC");
++MODULE_LICENSE("GPL");
++
++module_init(vpu_init);
++module_exit(vpu_exit);
+Index: linux-2.6.38.8/drivers/rtc/Kconfig
+===================================================================
+--- linux-2.6.38.8.orig/drivers/rtc/Kconfig 2011-06-03 03:35:11.000000000 +0200
++++ linux-2.6.38.8/drivers/rtc/Kconfig 2011-10-20 19:28:29.000000000 +0200
+@@ -600,6 +600,13 @@
+ This driver can also be built as a module, if so, the module
+ will be called "rtc-mxc".
+
++config RTC_DRV_MXC_V2
++ tristate "Freescale MXC Secure Real Time Clock"
++ depends on ARCH_MXC
++ depends on RTC_CLASS
++ help
++ Support for Freescale SRTC MXC
++
+ config RTC_DRV_BQ4802
+ tristate "TI BQ4802"
+ help
+@@ -877,7 +884,6 @@
+ This RTC driver uses PXA RTC registers available since pxa27x
+ series (RDxR, RYxR) instead of legacy RCNR, RTAR.
+
+-
+ config RTC_DRV_SUN4V
+ bool "SUN4V Hypervisor RTC"
+ depends on SPARC64
+Index: linux-2.6.38.8/drivers/rtc/Makefile
+===================================================================
+--- linux-2.6.38.8.orig/drivers/rtc/Makefile 2011-06-03 03:35:11.000000000 +0200
++++ linux-2.6.38.8/drivers/rtc/Makefile 2011-10-20 19:28:29.000000000 +0200
+@@ -101,3 +101,4 @@
+ 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_DRV_MXC_V2) += rtc-mxc_v2.o
+Index: linux-2.6.38.8/drivers/rtc/rtc-mxc_v2.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.38.8/drivers/rtc/rtc-mxc_v2.c 2011-10-20 19:28:29.000000000 +0200
+@@ -0,0 +1,766 @@
++/*
++ * Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * 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-ds1553.c
++ */
++
++/*!
++ * @defgroup RTC Real Time Clock (RTC) Driver
++ */
++/*!
++ * @file rtc-mxc_v2.c
++ * @brief Real Time Clock interface
++ *
++ * This file contains Real Time Clock interface for Linux.
++ *
++ * @ingroup RTC
++ */
++
++#include <linux/slab.h>
++#include <linux/delay.h>
++#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 <linux/io.h>
++#include <linux/mxc_srtc.h>
++
++#define SRTC_LPSCLR_LLPSC_LSH 17 /* start bit for LSB time value */
++
++#define SRTC_LPPDR_INIT 0x41736166 /* init for glitch detect */
++
++#define SRTC_LPCR_SWR_LP (1 << 0) /* lp software reset */
++#define SRTC_LPCR_EN_LP (1 << 3) /* lp enable */
++#define SRTC_LPCR_WAE (1 << 4) /* lp wakeup alarm enable */
++#define SRTC_LPCR_SAE (1 << 5) /* lp security alarm enable */
++#define SRTC_LPCR_SI (1 << 6) /* lp security interrupt enable */
++#define SRTC_LPCR_ALP (1 << 7) /* lp alarm flag */
++#define SRTC_LPCR_LTC (1 << 8) /* lp lock time counter */
++#define SRTC_LPCR_LMC (1 << 9) /* lp lock monotonic counter */
++#define SRTC_LPCR_SV (1 << 10) /* lp security violation */
++#define SRTC_LPCR_NSA (1 << 11) /* lp non secure access */
++#define SRTC_LPCR_NVEIE (1 << 12) /* lp non valid state exit int en */
++#define SRTC_LPCR_IEIE (1 << 13) /* lp init state exit int enable */
++#define SRTC_LPCR_NVE (1 << 14) /* lp non valid state exit bit */
++#define SRTC_LPCR_IE (1 << 15) /* lp init state exit bit */
++
++#define SRTC_LPCR_ALL_INT_EN (SRTC_LPCR_WAE | SRTC_LPCR_SAE | \
++ SRTC_LPCR_SI | SRTC_LPCR_ALP | \
++ SRTC_LPCR_NVEIE | SRTC_LPCR_IEIE)
++
++#define SRTC_LPSR_TRI (1 << 0) /* lp time read invalidate */
++#define SRTC_LPSR_PGD (1 << 1) /* lp power supply glitc detected */
++#define SRTC_LPSR_CTD (1 << 2) /* lp clock tampering detected */
++#define SRTC_LPSR_ALP (1 << 3) /* lp alarm flag */
++#define SRTC_LPSR_MR (1 << 4) /* lp monotonic counter rollover */
++#define SRTC_LPSR_TR (1 << 5) /* lp time rollover */
++#define SRTC_LPSR_EAD (1 << 6) /* lp external alarm detected */
++#define SRTC_LPSR_IT0 (1 << 7) /* lp IIM throttle */
++#define SRTC_LPSR_IT1 (1 << 8)
++#define SRTC_LPSR_IT2 (1 << 9)
++#define SRTC_LPSR_SM0 (1 << 10) /* lp security mode */
++#define SRTC_LPSR_SM1 (1 << 11)
++#define SRTC_LPSR_STATE_LP0 (1 << 12) /* lp state */
++#define SRTC_LPSR_STATE_LP1 (1 << 13)
++#define SRTC_LPSR_NVES (1 << 14) /* lp non-valid state exit status */
++#define SRTC_LPSR_IES (1 << 15) /* lp init state exit status */
++
++#define MAX_PIE_NUM 15
++#define MAX_PIE_FREQ 32768
++#define MIN_PIE_FREQ 1
++
++#define SRTC_PI0 (1 << 0)
++#define SRTC_PI1 (1 << 1)
++#define SRTC_PI2 (1 << 2)
++#define SRTC_PI3 (1 << 3)
++#define SRTC_PI4 (1 << 4)
++#define SRTC_PI5 (1 << 5)
++#define SRTC_PI6 (1 << 6)
++#define SRTC_PI7 (1 << 7)
++#define SRTC_PI8 (1 << 8)
++#define SRTC_PI9 (1 << 9)
++#define SRTC_PI10 (1 << 10)
++#define SRTC_PI11 (1 << 11)
++#define SRTC_PI12 (1 << 12)
++#define SRTC_PI13 (1 << 13)
++#define SRTC_PI14 (1 << 14)
++#define SRTC_PI15 (1 << 15)
++
++#define PIT_ALL_ON (SRTC_PI1 | SRTC_PI2 | SRTC_PI3 | \
++ SRTC_PI4 | SRTC_PI5 | SRTC_PI6 | SRTC_PI7 | \
++ SRTC_PI8 | SRTC_PI9 | SRTC_PI10 | SRTC_PI11 | \
++ SRTC_PI12 | SRTC_PI13 | SRTC_PI14 | SRTC_PI15)
++
++#define SRTC_SWR_HP (1 << 0) /* hp software reset */
++#define SRTC_EN_HP (1 << 3) /* hp enable */
++#define SRTC_TS (1 << 4) /* time syncronize hp with lp */
++
++#define SRTC_IE_AHP (1 << 16) /* Alarm HP Interrupt Enable bit */
++#define SRTC_IE_WDHP (1 << 18) /* Write Done HP Interrupt Enable bit */
++#define SRTC_IE_WDLP (1 << 19) /* Write Done LP Interrupt Enable bit */
++
++#define SRTC_ISR_AHP (1 << 16) /* interrupt status: alarm hp */
++#define SRTC_ISR_WDHP (1 << 18) /* interrupt status: write done hp */
++#define SRTC_ISR_WDLP (1 << 19) /* interrupt status: write done lp */
++#define SRTC_ISR_WPHP (1 << 20) /* interrupt status: write pending hp */
++#define SRTC_ISR_WPLP (1 << 21) /* interrupt status: write pending lp */
++
++#define SRTC_LPSCMR 0x00 /* LP Secure Counter MSB Reg */
++#define SRTC_LPSCLR 0x04 /* LP Secure Counter LSB Reg */
++#define SRTC_LPSAR 0x08 /* LP Secure Alarm Reg */
++#define SRTC_LPSMCR 0x0C /* LP Secure Monotonic Counter Reg */
++#define SRTC_LPCR 0x10 /* LP Control Reg */
++#define SRTC_LPSR 0x14 /* LP Status Reg */
++#define SRTC_LPPDR 0x18 /* LP Power Supply Glitch Detector Reg */
++#define SRTC_LPGR 0x1C /* LP General Purpose Reg */
++#define SRTC_HPCMR 0x20 /* HP Counter MSB Reg */
++#define SRTC_HPCLR 0x24 /* HP Counter LSB Reg */
++#define SRTC_HPAMR 0x28 /* HP Alarm MSB Reg */
++#define SRTC_HPALR 0x2C /* HP Alarm LSB Reg */
++#define SRTC_HPCR 0x30 /* HP Control Reg */
++#define SRTC_HPISR 0x34 /* HP Interrupt Status Reg */
++#define SRTC_HPIENR 0x38 /* HP Interrupt Enable Reg */
++
++#define SRTC_SECMODE_MASK 0x3 /* the mask of SRTC security mode */
++#define SRTC_SECMODE_LOW 0x0 /* Low Security */
++#define SRTC_SECMODE_MED 0x1 /* Medium Security */
++#define SRTC_SECMODE_HIGH 0x2 /* High Security */
++#define SRTC_SECMODE_RESERVED 0x3 /* Reserved */
++
++struct rtc_drv_data {
++ struct rtc_device *rtc;
++ void __iomem *ioaddr;
++ unsigned long baseaddr;
++ int irq;
++ struct clk *clk;
++ bool irq_enable;
++};
++
++
++/* completion event for implementing RTC_WAIT_FOR_TIME_SET ioctl */
++DECLARE_COMPLETION(srtc_completion);
++/* global to save difference of 47-bit counter value */
++static int64_t time_diff;
++
++/*!
++ * @defgroup RTC Real Time Clock (RTC) Driver
++ */
++/*!
++ * @file rtc-mxc.c
++ * @brief Real Time Clock interface
++ *
++ * This file contains Real Time Clock interface for Linux.
++ *
++ * @ingroup RTC
++ */
++
++static unsigned long rtc_status;
++
++static DEFINE_SPINLOCK(rtc_lock);
++
++/*!
++ * This function does write synchronization for writes to the lp srtc block.
++ * To take care of the asynchronous CKIL clock, all writes from the IP domain
++ * will be synchronized to the CKIL domain.
++ */
++static inline void rtc_write_sync_lp(void __iomem *ioaddr)
++{
++ unsigned int i, count;
++ /* Wait for 3 CKIL cycles */
++ for (i = 0; i < 3; i++) {
++ count = __raw_readl(ioaddr + SRTC_LPSCLR);
++ while
++ ((__raw_readl(ioaddr + SRTC_LPSCLR)) == count);
++ }
++}
++
++/*!
++ * 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_drv_data *pdata = dev_get_drvdata(dev);
++ void __iomem *ioaddr = pdata->ioaddr;
++ struct rtc_time alarm_tm, now_tm;
++ unsigned long now, time;
++ int ret;
++
++ now = __raw_readl(ioaddr + SRTC_LPSCMR);
++ 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);
++
++ __raw_writel(time, ioaddr + SRTC_LPSAR);
++
++ /* clear alarm interrupt status bit */
++ __raw_writel(SRTC_LPSR_ALP, ioaddr + SRTC_LPSR);
++
++ 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 mxc_rtc_interrupt(int irq, void *dev_id)
++{
++ struct platform_device *pdev = dev_id;
++ struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
++ void __iomem *ioaddr = pdata->ioaddr;
++ u32 lp_status, lp_cr;
++ u32 events = 0;
++
++ clk_enable(pdata->clk);
++ lp_status = __raw_readl(ioaddr + SRTC_LPSR);
++ lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
++
++ /* update irq data & counter */
++ if (lp_status & SRTC_LPSR_ALP) {
++ if (lp_cr & SRTC_LPCR_ALP)
++ events |= (RTC_AF | RTC_IRQF);
++
++ /* disable further lp alarm interrupts */
++ lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
++ }
++
++ /* Update interrupt enables */
++ __raw_writel(lp_cr, ioaddr + SRTC_LPCR);
++
++ /* If no interrupts are enabled, turn off interrupts in kernel */
++ if (((lp_cr & SRTC_LPCR_ALL_INT_EN) == 0) && (pdata->irq_enable)) {
++ disable_irq_nosync(pdata->irq);
++ pdata->irq_enable = false;
++ }
++
++ /* clear interrupt status */
++ __raw_writel(lp_status, ioaddr + SRTC_LPSR);
++ clk_disable(pdata->clk);
++
++ rtc_update_irq(pdata->rtc, 1, events);
++ return IRQ_HANDLED;
++}
++
++/*!
++ * This function is used to open the RTC driver.
++ *
++ * @return 0 if successful; non-zero otherwise.
++ */
++static int mxc_rtc_open(struct device *dev)
++{
++ struct rtc_drv_data *pdata = dev_get_drvdata(dev);
++ clk_enable(pdata->clk);
++
++ if (test_and_set_bit(1, &rtc_status))
++ return -EBUSY;
++ return 0;
++}
++
++/*!
++ * clear all interrupts and release the IRQ
++ */
++static void mxc_rtc_release(struct device *dev)
++{
++ struct rtc_drv_data *pdata = dev_get_drvdata(dev);
++
++ clk_disable(pdata->clk);
++
++ 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 mxc_rtc_ioctl(struct device *dev, unsigned int cmd,
++ unsigned long arg)
++{
++ struct rtc_drv_data *pdata = dev_get_drvdata(dev);
++ void __iomem *ioaddr = pdata->ioaddr;
++ unsigned long lock_flags = 0;
++ u32 lp_cr;
++ u64 time_47bit;
++ int retVal;
++
++ switch (cmd) {
++ case RTC_AIE_OFF:
++ spin_lock_irqsave(&rtc_lock, lock_flags);
++ lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
++ lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
++ if (((lp_cr & SRTC_LPCR_ALL_INT_EN) == 0)
++ && (pdata->irq_enable)) {
++ disable_irq(pdata->irq);
++ pdata->irq_enable = false;
++ }
++ __raw_writel(lp_cr, ioaddr + SRTC_LPCR);
++ spin_unlock_irqrestore(&rtc_lock, lock_flags);
++ return 0;
++
++ case RTC_AIE_ON:
++ spin_lock_irqsave(&rtc_lock, lock_flags);
++ if (!pdata->irq_enable) {
++ enable_irq(pdata->irq);
++ pdata->irq_enable = true;
++ }
++ lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
++ lp_cr |= SRTC_LPCR_ALP | SRTC_LPCR_WAE;
++ __raw_writel(lp_cr, ioaddr + SRTC_LPCR);
++ spin_unlock_irqrestore(&rtc_lock, lock_flags);
++ return 0;
++
++ case RTC_READ_TIME_47BIT:
++ time_47bit = (((u64) __raw_readl(ioaddr + SRTC_LPSCMR)) << 32 |
++ ((u64) __raw_readl(ioaddr + SRTC_LPSCLR)));
++ time_47bit >>= SRTC_LPSCLR_LLPSC_LSH;
++
++ if (arg && copy_to_user((u64 *) arg, &time_47bit, sizeof(u64)))
++ return -EFAULT;
++
++ return 0;
++
++ case RTC_WAIT_TIME_SET:
++
++ /* don't block without releasing mutex first */
++ mutex_unlock(&pdata->rtc->ops_lock);
++
++ /* sleep until awakened by SRTC driver when LPSCMR is changed */
++ wait_for_completion(&srtc_completion);
++
++ /* relock mutex because rtc_dev_ioctl will unlock again */
++ retVal = mutex_lock_interruptible(&pdata->rtc->ops_lock);
++
++ /* copy the new time difference = new time - previous time
++ * to the user param. The difference is a signed value */
++ if (arg && copy_to_user((int64_t *) arg, &time_diff,
++ sizeof(int64_t)))
++ return -EFAULT;
++
++ return retVal;
++
++ }
++
++ 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 mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
++{
++ struct rtc_drv_data *pdata = dev_get_drvdata(dev);
++ void __iomem *ioaddr = pdata->ioaddr;
++
++ rtc_time_to_tm(__raw_readl(ioaddr + SRTC_LPSCMR), 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 mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
++{
++ struct rtc_drv_data *pdata = dev_get_drvdata(dev);
++ void __iomem *ioaddr = pdata->ioaddr;
++ unsigned long time;
++ u64 old_time_47bit, new_time_47bit;
++ int ret;
++ ret = rtc_tm_to_time(tm, &time);
++ if (ret != 0)
++ return ret;
++
++ old_time_47bit = (((u64) __raw_readl(ioaddr + SRTC_LPSCMR)) << 32 |
++ ((u64) __raw_readl(ioaddr + SRTC_LPSCLR)));
++ old_time_47bit >>= SRTC_LPSCLR_LLPSC_LSH;
++
++ __raw_writel(time, ioaddr + SRTC_LPSCMR);
++ rtc_write_sync_lp(ioaddr);
++
++ new_time_47bit = (((u64) __raw_readl(ioaddr + SRTC_LPSCMR)) << 32 |
++ ((u64) __raw_readl(ioaddr + SRTC_LPSCLR)));
++ new_time_47bit >>= SRTC_LPSCLR_LLPSC_LSH;
++
++ /* update the difference between previous time and new time */
++ time_diff = new_time_47bit - old_time_47bit;
++
++ /* signal all waiting threads that time changed */
++ complete_all(&srtc_completion);
++ /* reinitialize completion variable */
++ INIT_COMPLETION(srtc_completion);
++
++ 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 mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
++{
++ struct rtc_drv_data *pdata = dev_get_drvdata(dev);
++ void __iomem *ioaddr = pdata->ioaddr;
++
++ rtc_time_to_tm(__raw_readl(ioaddr + SRTC_LPSAR), &alrm->time);
++ alrm->pending =
++ ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_ALP) != 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 mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
++{
++ struct rtc_drv_data *pdata = dev_get_drvdata(dev);
++ void __iomem *ioaddr = pdata->ioaddr;
++ unsigned long lock_flags = 0;
++ u32 lp_cr;
++ int ret;
++
++ if (rtc_valid_tm(&alrm->time)) {
++ if (alrm->time.tm_sec > 59 ||
++ alrm->time.tm_hour > 23 || alrm->time.tm_min > 59) {
++ return -EINVAL;
++ }
++ }
++
++ spin_lock_irqsave(&rtc_lock, lock_flags);
++ lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
++
++ ret = rtc_update_alarm(dev, &alrm->time);
++ if (ret)
++ goto out;
++
++ if (alrm->enabled)
++ lp_cr |= (SRTC_LPCR_ALP | SRTC_LPCR_WAE);
++ else
++ lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
++
++ if (lp_cr & SRTC_LPCR_ALL_INT_EN) {
++ if (!pdata->irq_enable) {
++ enable_irq(pdata->irq);
++ pdata->irq_enable = true;
++ }
++ } else {
++ if (pdata->irq_enable) {
++ disable_irq(pdata->irq);
++ pdata->irq_enable = false;
++ }
++ }
++
++ __raw_writel(lp_cr, ioaddr + SRTC_LPCR);
++
++out:
++ spin_unlock_irqrestore(&rtc_lock, lock_flags);
++ rtc_write_sync_lp(ioaddr);
++ return ret;
++}
++
++/*!
++ * This function is used to provide the content for the /proc/driver/rtc
++ * file.
++ *
++ * @param seq buffer to hold the information that the driver wants to write
++ *
++ * @return The number of bytes written into the rtc file.
++ */
++static int mxc_rtc_proc(struct device *dev, struct seq_file *seq)
++{
++ struct rtc_drv_data *pdata = dev_get_drvdata(dev);
++ void __iomem *ioaddr = pdata->ioaddr;
++
++ clk_enable(pdata->clk);
++ seq_printf(seq, "alarm_IRQ\t: %s\n",
++ (((__raw_readl(ioaddr + SRTC_LPCR)) & SRTC_LPCR_ALP) !=
++ 0) ? "yes" : "no");
++ clk_disable(pdata->clk);
++
++ return 0;
++}
++
++/*!
++ * The RTC driver structure
++ */
++static struct rtc_class_ops mxc_rtc_ops = {
++ .open = mxc_rtc_open,
++ .release = mxc_rtc_release,
++ .ioctl = mxc_rtc_ioctl,
++ .read_time = mxc_rtc_read_time,
++ .set_time = mxc_rtc_set_time,
++ .read_alarm = mxc_rtc_read_alarm,
++ .set_alarm = mxc_rtc_set_alarm,
++ .proc = mxc_rtc_proc,
++};
++
++/*! MXC RTC Power management control */
++static int mxc_rtc_probe(struct platform_device *pdev)
++{
++ struct clk *clk;
++ struct timespec tv;
++ struct resource *res;
++ struct rtc_device *rtc;
++ struct rtc_drv_data *pdata = NULL;
++ struct mxc_srtc_platform_data *plat_data = NULL;
++ void __iomem *ioaddr;
++ void __iomem *srtc_secmode_addr;
++ int ret = 0;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res)
++ return -ENODEV;
++
++ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
++ if (!pdata)
++ return -ENOMEM;
++
++ pdata->clk = clk_get(&pdev->dev, "rtc_clk");
++ clk_enable(pdata->clk);
++ pdata->baseaddr = res->start;
++ pdata->ioaddr = ioremap(pdata->baseaddr, 0x40);
++ ioaddr ...
[truncated message content] |