From f5e70d0fe3ea990cfb3fc8d7f76a719adcb1e0b5 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 13 Jul 2009 11:35:12 +0100 Subject: [PATCH 0001/5312] md: Factor out RAID6 algorithms into lib/ We'll want to use these in btrfs too. Signed-off-by: David Woodhouse --- drivers/md/Kconfig | 7 +- drivers/md/Makefile | 76 ------------------- lib/Kconfig | 3 + lib/Makefile | 1 + lib/raid6/Makefile | 78 ++++++++++++++++++++ {drivers/md => lib/raid6}/mktables.c | 0 {drivers/md => lib/raid6}/raid6algos.c | 0 {drivers/md => lib/raid6}/raid6altivec.uc | 0 {drivers/md => lib/raid6}/raid6int.uc | 0 {drivers/md => lib/raid6}/raid6mmx.c | 0 {drivers/md => lib/raid6}/raid6recov.c | 0 {drivers/md => lib/raid6}/raid6sse1.c | 0 {drivers/md => lib/raid6}/raid6sse2.c | 0 {drivers/md => lib/raid6}/raid6test/Makefile | 0 {drivers/md => lib/raid6}/raid6test/test.c | 0 {drivers/md => lib/raid6}/raid6x86.h | 0 {drivers/md => lib/raid6}/unroll.pl | 0 17 files changed, 84 insertions(+), 81 deletions(-) create mode 100644 lib/raid6/Makefile rename {drivers/md => lib/raid6}/mktables.c (100%) rename {drivers/md => lib/raid6}/raid6algos.c (100%) rename {drivers/md => lib/raid6}/raid6altivec.uc (100%) rename {drivers/md => lib/raid6}/raid6int.uc (100%) rename {drivers/md => lib/raid6}/raid6mmx.c (100%) rename {drivers/md => lib/raid6}/raid6recov.c (100%) rename {drivers/md => lib/raid6}/raid6sse1.c (100%) rename {drivers/md => lib/raid6}/raid6sse2.c (100%) rename {drivers/md => lib/raid6}/raid6test/Makefile (100%) rename {drivers/md => lib/raid6}/raid6test/test.c (100%) rename {drivers/md => lib/raid6}/raid6x86.h (100%) rename {drivers/md => lib/raid6}/unroll.pl (100%) diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 2158377a1359..891f7c8490d3 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -121,7 +121,7 @@ config MD_RAID10 config MD_RAID456 tristate "RAID-4/RAID-5/RAID-6 mode" depends on BLK_DEV_MD - select MD_RAID6_PQ + select RAID6_PQ select ASYNC_MEMCPY select ASYNC_XOR select ASYNC_PQ @@ -165,12 +165,9 @@ config MULTICORE_RAID456 If unsure, say N. -config MD_RAID6_PQ - tristate - config ASYNC_RAID6_TEST tristate "Self test for hardware accelerated raid6 recovery" - depends on MD_RAID6_PQ + depends on RAID6_PQ select ASYNC_RAID6_RECOV ---help--- This is a one-shot self test that permutes through the diff --git a/drivers/md/Makefile b/drivers/md/Makefile index 1dc4185bd781..c9b3a7843d83 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile @@ -12,13 +12,6 @@ dm-log-userspace-y \ += dm-log-userspace-base.o dm-log-userspace-transfer.o md-mod-y += md.o bitmap.o raid456-y += raid5.o -raid6_pq-y += raid6algos.o raid6recov.o raid6tables.o \ - raid6int1.o raid6int2.o raid6int4.o \ - raid6int8.o raid6int16.o raid6int32.o \ - raid6altivec1.o raid6altivec2.o raid6altivec4.o \ - raid6altivec8.o \ - raid6mmx.o raid6sse1.o raid6sse2.o -hostprogs-y += mktables # Note: link order is important. All raid personalities # and must come before md.o, as they each initialise @@ -29,7 +22,6 @@ obj-$(CONFIG_MD_LINEAR) += linear.o obj-$(CONFIG_MD_RAID0) += raid0.o obj-$(CONFIG_MD_RAID1) += raid1.o obj-$(CONFIG_MD_RAID10) += raid10.o -obj-$(CONFIG_MD_RAID6_PQ) += raid6_pq.o obj-$(CONFIG_MD_RAID456) += raid456.o obj-$(CONFIG_MD_MULTIPATH) += multipath.o obj-$(CONFIG_MD_FAULTY) += faulty.o @@ -45,75 +37,7 @@ obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-log.o dm-region-hash.o obj-$(CONFIG_DM_LOG_USERSPACE) += dm-log-userspace.o obj-$(CONFIG_DM_ZERO) += dm-zero.o -quiet_cmd_unroll = UNROLL $@ - cmd_unroll = $(PERL) $(srctree)/$(src)/unroll.pl $(UNROLL) \ - < $< > $@ || ( rm -f $@ && exit 1 ) - -ifeq ($(CONFIG_ALTIVEC),y) -altivec_flags := -maltivec -mabi=altivec -endif - ifeq ($(CONFIG_DM_UEVENT),y) dm-mod-objs += dm-uevent.o endif -targets += raid6int1.c -$(obj)/raid6int1.c: UNROLL := 1 -$(obj)/raid6int1.c: $(src)/raid6int.uc $(src)/unroll.pl FORCE - $(call if_changed,unroll) - -targets += raid6int2.c -$(obj)/raid6int2.c: UNROLL := 2 -$(obj)/raid6int2.c: $(src)/raid6int.uc $(src)/unroll.pl FORCE - $(call if_changed,unroll) - -targets += raid6int4.c -$(obj)/raid6int4.c: UNROLL := 4 -$(obj)/raid6int4.c: $(src)/raid6int.uc $(src)/unroll.pl FORCE - $(call if_changed,unroll) - -targets += raid6int8.c -$(obj)/raid6int8.c: UNROLL := 8 -$(obj)/raid6int8.c: $(src)/raid6int.uc $(src)/unroll.pl FORCE - $(call if_changed,unroll) - -targets += raid6int16.c -$(obj)/raid6int16.c: UNROLL := 16 -$(obj)/raid6int16.c: $(src)/raid6int.uc $(src)/unroll.pl FORCE - $(call if_changed,unroll) - -targets += raid6int32.c -$(obj)/raid6int32.c: UNROLL := 32 -$(obj)/raid6int32.c: $(src)/raid6int.uc $(src)/unroll.pl FORCE - $(call if_changed,unroll) - -CFLAGS_raid6altivec1.o += $(altivec_flags) -targets += raid6altivec1.c -$(obj)/raid6altivec1.c: UNROLL := 1 -$(obj)/raid6altivec1.c: $(src)/raid6altivec.uc $(src)/unroll.pl FORCE - $(call if_changed,unroll) - -CFLAGS_raid6altivec2.o += $(altivec_flags) -targets += raid6altivec2.c -$(obj)/raid6altivec2.c: UNROLL := 2 -$(obj)/raid6altivec2.c: $(src)/raid6altivec.uc $(src)/unroll.pl FORCE - $(call if_changed,unroll) - -CFLAGS_raid6altivec4.o += $(altivec_flags) -targets += raid6altivec4.c -$(obj)/raid6altivec4.c: UNROLL := 4 -$(obj)/raid6altivec4.c: $(src)/raid6altivec.uc $(src)/unroll.pl FORCE - $(call if_changed,unroll) - -CFLAGS_raid6altivec8.o += $(altivec_flags) -targets += raid6altivec8.c -$(obj)/raid6altivec8.c: UNROLL := 8 -$(obj)/raid6altivec8.c: $(src)/raid6altivec.uc $(src)/unroll.pl FORCE - $(call if_changed,unroll) - -quiet_cmd_mktable = TABLE $@ - cmd_mktable = $(obj)/mktables > $@ || ( rm -f $@ && exit 1 ) - -targets += raid6tables.c -$(obj)/raid6tables.c: $(obj)/mktables FORCE - $(call if_changed,mktable) diff --git a/lib/Kconfig b/lib/Kconfig index bb1326d3839c..1cc756c4c78c 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -7,6 +7,9 @@ config BINARY_PRINTF menu "Library routines" +config RAID6_PQ + tristate + config BITREVERSE tristate diff --git a/lib/Makefile b/lib/Makefile index 2e78277eff9d..b25faf0d1d5c 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/ obj-$(CONFIG_REED_SOLOMON) += reed_solomon/ obj-$(CONFIG_LZO_COMPRESS) += lzo/ obj-$(CONFIG_LZO_DECOMPRESS) += lzo/ +obj-$(CONFIG_RAID6_PQ) += raid6/ lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o diff --git a/lib/raid6/Makefile b/lib/raid6/Makefile new file mode 100644 index 000000000000..b2fe4baa90e0 --- /dev/null +++ b/lib/raid6/Makefile @@ -0,0 +1,78 @@ +obj-$(CONFIG_RAID6_PQ) += raid6_pq.o + +raid6_pq-y += raid6algos.o raid6recov.o raid6tables.o \ + raid6int1.o raid6int2.o raid6int4.o \ + raid6int8.o raid6int16.o raid6int32.o \ + raid6altivec1.o raid6altivec2.o raid6altivec4.o \ + raid6altivec8.o \ + raid6mmx.o raid6sse1.o raid6sse2.o +hostprogs-y += mktables + +quiet_cmd_unroll = UNROLL $@ + cmd_unroll = $(PERL) $(srctree)/$(src)/unroll.pl $(UNROLL) \ + < $< > $@ || ( rm -f $@ && exit 1 ) + +ifeq ($(CONFIG_ALTIVEC),y) +altivec_flags := -maltivec -mabi=altivec +endif + +targets += raid6int1.c +$(obj)/raid6int1.c: UNROLL := 1 +$(obj)/raid6int1.c: $(src)/raid6int.uc $(src)/unroll.pl FORCE + $(call if_changed,unroll) + +targets += raid6int2.c +$(obj)/raid6int2.c: UNROLL := 2 +$(obj)/raid6int2.c: $(src)/raid6int.uc $(src)/unroll.pl FORCE + $(call if_changed,unroll) + +targets += raid6int4.c +$(obj)/raid6int4.c: UNROLL := 4 +$(obj)/raid6int4.c: $(src)/raid6int.uc $(src)/unroll.pl FORCE + $(call if_changed,unroll) + +targets += raid6int8.c +$(obj)/raid6int8.c: UNROLL := 8 +$(obj)/raid6int8.c: $(src)/raid6int.uc $(src)/unroll.pl FORCE + $(call if_changed,unroll) + +targets += raid6int16.c +$(obj)/raid6int16.c: UNROLL := 16 +$(obj)/raid6int16.c: $(src)/raid6int.uc $(src)/unroll.pl FORCE + $(call if_changed,unroll) + +targets += raid6int32.c +$(obj)/raid6int32.c: UNROLL := 32 +$(obj)/raid6int32.c: $(src)/raid6int.uc $(src)/unroll.pl FORCE + $(call if_changed,unroll) + +CFLAGS_raid6altivec1.o += $(altivec_flags) +targets += raid6altivec1.c +$(obj)/raid6altivec1.c: UNROLL := 1 +$(obj)/raid6altivec1.c: $(src)/raid6altivec.uc $(src)/unroll.pl FORCE + $(call if_changed,unroll) + +CFLAGS_raid6altivec2.o += $(altivec_flags) +targets += raid6altivec2.c +$(obj)/raid6altivec2.c: UNROLL := 2 +$(obj)/raid6altivec2.c: $(src)/raid6altivec.uc $(src)/unroll.pl FORCE + $(call if_changed,unroll) + +CFLAGS_raid6altivec4.o += $(altivec_flags) +targets += raid6altivec4.c +$(obj)/raid6altivec4.c: UNROLL := 4 +$(obj)/raid6altivec4.c: $(src)/raid6altivec.uc $(src)/unroll.pl FORCE + $(call if_changed,unroll) + +CFLAGS_raid6altivec8.o += $(altivec_flags) +targets += raid6altivec8.c +$(obj)/raid6altivec8.c: UNROLL := 8 +$(obj)/raid6altivec8.c: $(src)/raid6altivec.uc $(src)/unroll.pl FORCE + $(call if_changed,unroll) + +quiet_cmd_mktable = TABLE $@ + cmd_mktable = $(obj)/mktables > $@ || ( rm -f $@ && exit 1 ) + +targets += raid6tables.c +$(obj)/raid6tables.c: $(obj)/mktables FORCE + $(call if_changed,mktable) diff --git a/drivers/md/mktables.c b/lib/raid6/mktables.c similarity index 100% rename from drivers/md/mktables.c rename to lib/raid6/mktables.c diff --git a/drivers/md/raid6algos.c b/lib/raid6/raid6algos.c similarity index 100% rename from drivers/md/raid6algos.c rename to lib/raid6/raid6algos.c diff --git a/drivers/md/raid6altivec.uc b/lib/raid6/raid6altivec.uc similarity index 100% rename from drivers/md/raid6altivec.uc rename to lib/raid6/raid6altivec.uc diff --git a/drivers/md/raid6int.uc b/lib/raid6/raid6int.uc similarity index 100% rename from drivers/md/raid6int.uc rename to lib/raid6/raid6int.uc diff --git a/drivers/md/raid6mmx.c b/lib/raid6/raid6mmx.c similarity index 100% rename from drivers/md/raid6mmx.c rename to lib/raid6/raid6mmx.c diff --git a/drivers/md/raid6recov.c b/lib/raid6/raid6recov.c similarity index 100% rename from drivers/md/raid6recov.c rename to lib/raid6/raid6recov.c diff --git a/drivers/md/raid6sse1.c b/lib/raid6/raid6sse1.c similarity index 100% rename from drivers/md/raid6sse1.c rename to lib/raid6/raid6sse1.c diff --git a/drivers/md/raid6sse2.c b/lib/raid6/raid6sse2.c similarity index 100% rename from drivers/md/raid6sse2.c rename to lib/raid6/raid6sse2.c diff --git a/drivers/md/raid6test/Makefile b/lib/raid6/raid6test/Makefile similarity index 100% rename from drivers/md/raid6test/Makefile rename to lib/raid6/raid6test/Makefile diff --git a/drivers/md/raid6test/test.c b/lib/raid6/raid6test/test.c similarity index 100% rename from drivers/md/raid6test/test.c rename to lib/raid6/raid6test/test.c diff --git a/drivers/md/raid6x86.h b/lib/raid6/raid6x86.h similarity index 100% rename from drivers/md/raid6x86.h rename to lib/raid6/raid6x86.h diff --git a/drivers/md/unroll.pl b/lib/raid6/unroll.pl similarity index 100% rename from drivers/md/unroll.pl rename to lib/raid6/unroll.pl -- GitLab From e5d84970a554d5c0072043a7b9f0f5b88b5fdfe1 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 29 Oct 2009 16:41:49 +0000 Subject: [PATCH 0002/5312] async_tx: Move ASYNC_RAID6_TEST option to crypto/async_tx/, fix dependencies Signed-off-by: David Woodhouse --- crypto/async_tx/Kconfig | 14 ++++++++++++++ drivers/md/Kconfig | 13 ------------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/crypto/async_tx/Kconfig b/crypto/async_tx/Kconfig index e5aeb2b79e6f..e24aa80087ad 100644 --- a/crypto/async_tx/Kconfig +++ b/crypto/async_tx/Kconfig @@ -22,4 +22,18 @@ config ASYNC_RAID6_RECOV tristate select ASYNC_CORE select ASYNC_PQ + select ASYNC_XOR + +config ASYNC_RAID6_TEST + tristate "Self test for hardware accelerated raid6 recovery" + depends on ASYNC_RAID6_RECOV + select ASYNC_MEMCPY + ---help--- + This is a one-shot self test that permutes through the + recovery of all the possible two disk failure scenarios for a + N-disk array. Recovery is performed with the asynchronous + raid6 recovery routines, and will optionally use an offload + engine if one is available. + + If unsure, say N. diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 891f7c8490d3..e27ae4604cef 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -165,19 +165,6 @@ config MULTICORE_RAID456 If unsure, say N. -config ASYNC_RAID6_TEST - tristate "Self test for hardware accelerated raid6 recovery" - depends on RAID6_PQ - select ASYNC_RAID6_RECOV - ---help--- - This is a one-shot self test that permutes through the - recovery of all the possible two disk failure scenarios for a - N-disk array. Recovery is performed with the asynchronous - raid6 recovery routines, and will optionally use an offload - engine if one is available. - - If unsure, say N. - config MD_MULTIPATH tristate "Multipath I/O support" depends on BLK_DEV_MD -- GitLab From 4c31a781144c1f556dfcda3277dafecd4e107d95 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Tue, 3 Nov 2009 15:58:40 +0000 Subject: [PATCH 0003/5312] xenbus: do not hold transaction_mutex when returning to userspace ================================================ [ BUG: lock held when returning to user space! ] ------------------------------------------------ xenstore-list/3522 is leaving the kernel with locks still held! 1 lock held by xenstore-list/3522: #0: (&xs_state.transaction_mutex){......}, at: [] xenbus_dev_request_and_reply+0x8f/0xa0 The canonical fix for this type of issue appears to be to maintain a count manually rather than using an rwsem so do that here. Signed-off-by: Ian Campbell Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/xenbus/xenbus_xs.c | 57 ++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c index eab33f1dbdf7..6f91e8c8b932 100644 --- a/drivers/xen/xenbus/xenbus_xs.c +++ b/drivers/xen/xenbus/xenbus_xs.c @@ -76,6 +76,14 @@ struct xs_handle { /* * Mutex ordering: transaction_mutex -> watch_mutex -> request_mutex. * response_mutex is never taken simultaneously with the other three. + * + * transaction_mutex must be held before incrementing + * transaction_count. The mutex is held when a suspend is in + * progress to prevent new transactions starting. + * + * When decrementing transaction_count to zero the wait queue + * should be woken up, the suspend code waits for count to + * reach zero. */ /* One request at a time. */ @@ -85,7 +93,9 @@ struct xs_handle { struct mutex response_mutex; /* Protect transactions against save/restore. */ - struct rw_semaphore transaction_mutex; + struct mutex transaction_mutex; + atomic_t transaction_count; + wait_queue_head_t transaction_wq; /* Protect watch (de)register against save/restore. */ struct rw_semaphore watch_mutex; @@ -157,6 +167,31 @@ static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len) return body; } +static void transaction_start(void) +{ + mutex_lock(&xs_state.transaction_mutex); + atomic_inc(&xs_state.transaction_count); + mutex_unlock(&xs_state.transaction_mutex); +} + +static void transaction_end(void) +{ + if (atomic_dec_and_test(&xs_state.transaction_count)) + wake_up(&xs_state.transaction_wq); +} + +static void transaction_suspend(void) +{ + mutex_lock(&xs_state.transaction_mutex); + wait_event(xs_state.transaction_wq, + atomic_read(&xs_state.transaction_count) == 0); +} + +static void transaction_resume(void) +{ + mutex_unlock(&xs_state.transaction_mutex); +} + void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) { void *ret; @@ -164,7 +199,7 @@ void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) int err; if (req_msg.type == XS_TRANSACTION_START) - down_read(&xs_state.transaction_mutex); + transaction_start(); mutex_lock(&xs_state.request_mutex); @@ -180,7 +215,7 @@ void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) if ((msg->type == XS_TRANSACTION_END) || ((req_msg.type == XS_TRANSACTION_START) && (msg->type == XS_ERROR))) - up_read(&xs_state.transaction_mutex); + transaction_end(); return ret; } @@ -432,11 +467,11 @@ int xenbus_transaction_start(struct xenbus_transaction *t) { char *id_str; - down_read(&xs_state.transaction_mutex); + transaction_start(); id_str = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL); if (IS_ERR(id_str)) { - up_read(&xs_state.transaction_mutex); + transaction_end(); return PTR_ERR(id_str); } @@ -461,7 +496,7 @@ int xenbus_transaction_end(struct xenbus_transaction t, int abort) err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL)); - up_read(&xs_state.transaction_mutex); + transaction_end(); return err; } @@ -662,7 +697,7 @@ EXPORT_SYMBOL_GPL(unregister_xenbus_watch); void xs_suspend(void) { - down_write(&xs_state.transaction_mutex); + transaction_suspend(); down_write(&xs_state.watch_mutex); mutex_lock(&xs_state.request_mutex); mutex_lock(&xs_state.response_mutex); @@ -677,7 +712,7 @@ void xs_resume(void) mutex_unlock(&xs_state.response_mutex); mutex_unlock(&xs_state.request_mutex); - up_write(&xs_state.transaction_mutex); + transaction_resume(); /* No need for watches_lock: the watch_mutex is sufficient. */ list_for_each_entry(watch, &watches, list) { @@ -693,7 +728,7 @@ void xs_suspend_cancel(void) mutex_unlock(&xs_state.response_mutex); mutex_unlock(&xs_state.request_mutex); up_write(&xs_state.watch_mutex); - up_write(&xs_state.transaction_mutex); + mutex_unlock(&xs_state.transaction_mutex); } static int xenwatch_thread(void *unused) @@ -843,8 +878,10 @@ int xs_init(void) mutex_init(&xs_state.request_mutex); mutex_init(&xs_state.response_mutex); - init_rwsem(&xs_state.transaction_mutex); + mutex_init(&xs_state.transaction_mutex); init_rwsem(&xs_state.watch_mutex); + atomic_set(&xs_state.transaction_count, 0); + init_waitqueue_head(&xs_state.transaction_wq); /* Initialize the shared memory rings to talk to xenstored */ err = xb_init_comms(); -- GitLab From e40b17208b6805be50ffe891878662b6076206b9 Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Fri, 5 Feb 2010 21:47:03 -0500 Subject: [PATCH 0004/5312] x86: Move notify_die from nmi.c to traps.c In order to handle a new nmi_watchdog approach, I need to move the notify_die() routine out of nmi_watchdog_tick() and into default_do_nmi(). This lets me easily swap out the old nmi_watchdog with the new one with just a config change. The change probably makes sense from a high level perspective because the nmi_watchdog shouldn't be handling notify_die routines anyway. However, this move does change the semantics a little bit. Instead of checking on every nmi interrupt if the cpus are stuck, only check them on the nmi_watchdog interrupts. v2: Move notify_die call into #idef block Signed-off-by: Don Zickus Cc: Linus Torvalds Cc: Andrew Morton Cc: gorcunov@gmail.com Cc: aris@redhat.com Cc: peterz@infradead.org LKML-Reference: <1265424425-31562-2-git-send-email-dzickus@redhat.com> Signed-off-by: Ingo Molnar --- arch/x86/kernel/apic/nmi.c | 7 ------- arch/x86/kernel/traps.c | 5 +++++ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/apic/nmi.c b/arch/x86/kernel/apic/nmi.c index 0159a69396cb..5d47682f580b 100644 --- a/arch/x86/kernel/apic/nmi.c +++ b/arch/x86/kernel/apic/nmi.c @@ -400,13 +400,6 @@ nmi_watchdog_tick(struct pt_regs *regs, unsigned reason) int cpu = smp_processor_id(); int rc = 0; - /* check for other users first */ - if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) - == NOTIFY_STOP) { - rc = 1; - touched = 1; - } - sum = get_timer_irqs(cpu); if (__get_cpu_var(nmi_touch)) { diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 1168e4454188..51ef893ffa65 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -400,7 +400,12 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs) if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT) == NOTIFY_STOP) return; + #ifdef CONFIG_X86_LOCAL_APIC + if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) + == NOTIFY_STOP) + return; + /* * Ok, so this is none of the documented NMI sources, * so it must be the NMI watchdog. -- GitLab From 1fb9d6ad2766a1dd70d167552988375049a97f21 Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Fri, 5 Feb 2010 21:47:04 -0500 Subject: [PATCH 0005/5312] nmi_watchdog: Add new, generic implementation, using perf events This is a new generic nmi_watchdog implementation using the perf events infrastructure as suggested by Ingo. The implementation is simple, just create an in-kernel perf event and register an overflow handler to check for cpu lockups. I created a generic implementation that lives in kernel/ and the hardware specific part that for now lives in arch/x86. This approach has a number of advantages: - It simplifies the x86 PMU implementation in the long run, in that it removes the hardcoded low-level PMU implementation that was the NMI watchdog before. - It allows new NMI watchdog features to be added in a central place. - It allows other architectures to enable the NMI watchdog, as long as they have perf events (that provide NMIs) implemented. - It also allows for more graceful co-existence of existing perf events apps and the NMI watchdog - before these changes the relationship was exclusive. (The NMI watchdog will 'spend' a perf event when enabled. In later iterations we might be able to piggyback from an existing NMI event without having to allocate a hardware event for the NMI watchdog - turning this into a no-hardware-cost feature.) As for compatibility, we'll keep the old NMI watchdog code as well until the new one can 100% replace it on all CPUs, old and new alike. That might take some time as the NMI watchdog has been ported to many CPU models. I have done light testing to make sure the framework works correctly and it does. v2: Set the correct timeout values based on the old nmi watchdog Signed-off-by: Don Zickus Cc: Linus Torvalds Cc: Andrew Morton Cc: gorcunov@gmail.com Cc: aris@redhat.com Cc: peterz@infradead.org LKML-Reference: <1265424425-31562-3-git-send-email-dzickus@redhat.com> Signed-off-by: Ingo Molnar --- arch/x86/kernel/apic/hw_nmi.c | 114 ++++++++++++++++++++ kernel/nmi_watchdog.c | 191 ++++++++++++++++++++++++++++++++++ 2 files changed, 305 insertions(+) create mode 100644 arch/x86/kernel/apic/hw_nmi.c create mode 100644 kernel/nmi_watchdog.c diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c new file mode 100644 index 000000000000..8c0e6a410d05 --- /dev/null +++ b/arch/x86/kernel/apic/hw_nmi.c @@ -0,0 +1,114 @@ +/* + * HW NMI watchdog support + * + * started by Don Zickus, Copyright (C) 2010 Red Hat, Inc. + * + * Arch specific calls to support NMI watchdog + * + * Bits copied from original nmi.c file + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* For reliability, we're prepared to waste bits here. */ +static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly; + +static DEFINE_PER_CPU(unsigned, last_irq_sum); + +/* + * Take the local apic timer and PIT/HPET into account. We don't + * know which one is active, when we have highres/dyntick on + */ +static inline unsigned int get_timer_irqs(int cpu) +{ + return per_cpu(irq_stat, cpu).apic_timer_irqs + + per_cpu(irq_stat, cpu).irq0_irqs; +} + +static inline int mce_in_progress(void) +{ +#if defined(CONFIG_X86_MCE) + return atomic_read(&mce_entry) > 0; +#endif + return 0; +} + +int hw_nmi_is_cpu_stuck(struct pt_regs *regs) +{ + unsigned int sum; + int cpu = smp_processor_id(); + + /* FIXME: cheap hack for this check, probably should get its own + * die_notifier handler + */ + if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) { + static DEFINE_SPINLOCK(lock); /* Serialise the printks */ + + spin_lock(&lock); + printk(KERN_WARNING "NMI backtrace for cpu %d\n", cpu); + show_regs(regs); + dump_stack(); + spin_unlock(&lock); + cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask)); + } + + /* if we are doing an mce, just assume the cpu is not stuck */ + /* Could check oops_in_progress here too, but it's safer not to */ + if (mce_in_progress()) + return 0; + + /* We determine if the cpu is stuck by checking whether any + * interrupts have happened since we last checked. Of course + * an nmi storm could create false positives, but the higher + * level logic should account for that + */ + sum = get_timer_irqs(cpu); + if (__get_cpu_var(last_irq_sum) == sum) { + return 1; + } else { + __get_cpu_var(last_irq_sum) = sum; + return 0; + } +} + +void arch_trigger_all_cpu_backtrace(void) +{ + int i; + + cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask); + + printk(KERN_INFO "sending NMI to all CPUs:\n"); + apic->send_IPI_all(NMI_VECTOR); + + /* Wait for up to 10 seconds for all CPUs to do the backtrace */ + for (i = 0; i < 10 * 1000; i++) { + if (cpumask_empty(to_cpumask(backtrace_mask))) + break; + mdelay(1); + } +} + +/* STUB calls to mimic old nmi_watchdog behaviour */ +unsigned int nmi_watchdog = NMI_NONE; +EXPORT_SYMBOL(nmi_watchdog); +atomic_t nmi_active = ATOMIC_INIT(0); /* oprofile uses this */ +EXPORT_SYMBOL(nmi_active); +int nmi_watchdog_enabled; +int unknown_nmi_panic; +void cpu_nmi_set_wd_enabled(void) { return; } +void acpi_nmi_enable(void) { return; } +void acpi_nmi_disable(void) { return; } +void stop_apic_nmi_watchdog(void *unused) { return; } +void setup_apic_nmi_watchdog(void *unused) { return; } +int __init check_nmi_watchdog(void) { return 0; } diff --git a/kernel/nmi_watchdog.c b/kernel/nmi_watchdog.c new file mode 100644 index 000000000000..36817b214d69 --- /dev/null +++ b/kernel/nmi_watchdog.c @@ -0,0 +1,191 @@ +/* + * Detect Hard Lockups using the NMI + * + * started by Don Zickus, Copyright (C) 2010 Red Hat, Inc. + * + * this code detects hard lockups: incidents in where on a CPU + * the kernel does not respond to anything except NMI. + * + * Note: Most of this code is borrowed heavily from softlockup.c, + * so thanks to Ingo for the initial implementation. + * Some chunks also taken from arch/x86/kernel/apic/nmi.c, thanks + * to those contributors as well. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static DEFINE_PER_CPU(struct perf_event *, nmi_watchdog_ev); +static DEFINE_PER_CPU(int, nmi_watchdog_touch); +static DEFINE_PER_CPU(long, alert_counter); + +void touch_nmi_watchdog(void) +{ + __raw_get_cpu_var(nmi_watchdog_touch) = 1; + touch_softlockup_watchdog(); +} +EXPORT_SYMBOL(touch_nmi_watchdog); + +void touch_all_nmi_watchdog(void) +{ + int cpu; + + for_each_online_cpu(cpu) + per_cpu(nmi_watchdog_touch, cpu) = 1; + touch_softlockup_watchdog(); +} + +#ifdef CONFIG_SYSCTL +/* + * proc handler for /proc/sys/kernel/nmi_watchdog + */ +int proc_nmi_enabled(struct ctl_table *table, int write, + void __user *buffer, size_t *length, loff_t *ppos) +{ + int cpu; + + if (per_cpu(nmi_watchdog_ev, smp_processor_id()) == NULL) + nmi_watchdog_enabled = 0; + else + nmi_watchdog_enabled = 1; + + touch_all_nmi_watchdog(); + proc_dointvec(table, write, buffer, length, ppos); + if (nmi_watchdog_enabled) + for_each_online_cpu(cpu) + perf_event_enable(per_cpu(nmi_watchdog_ev, cpu)); + else + for_each_online_cpu(cpu) + perf_event_disable(per_cpu(nmi_watchdog_ev, cpu)); + return 0; +} + +#endif /* CONFIG_SYSCTL */ + +struct perf_event_attr wd_attr = { + .type = PERF_TYPE_HARDWARE, + .config = PERF_COUNT_HW_CPU_CYCLES, + .size = sizeof(struct perf_event_attr), + .pinned = 1, + .disabled = 1, +}; + +static int panic_on_timeout; + +void wd_overflow(struct perf_event *event, int nmi, + struct perf_sample_data *data, + struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + int touched = 0; + + if (__get_cpu_var(nmi_watchdog_touch)) { + per_cpu(nmi_watchdog_touch, cpu) = 0; + touched = 1; + } + + /* check to see if the cpu is doing anything */ + if (!touched && hw_nmi_is_cpu_stuck(regs)) { + /* + * Ayiee, looks like this CPU is stuck ... + * wait a few IRQs (5 seconds) before doing the oops ... + */ + per_cpu(alert_counter,cpu) += 1; + if (per_cpu(alert_counter,cpu) == 5) { + /* + * die_nmi will return ONLY if NOTIFY_STOP happens.. + */ + die_nmi("BUG: NMI Watchdog detected LOCKUP", + regs, panic_on_timeout); + } + } else { + per_cpu(alert_counter,cpu) = 0; + } + + return; +} + +/* + * Create/destroy watchdog threads as CPUs come and go: + */ +static int __cpuinit +cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) +{ + int hotcpu = (unsigned long)hcpu; + struct perf_event *event; + + switch (action) { + case CPU_UP_PREPARE: + case CPU_UP_PREPARE_FROZEN: + per_cpu(nmi_watchdog_touch, hotcpu) = 0; + break; + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + /* originally wanted the below chunk to be in CPU_UP_PREPARE, but caps is unpriv for non-CPU0 */ + wd_attr.sample_period = cpu_khz * 1000; + event = perf_event_create_kernel_counter(&wd_attr, hotcpu, -1, wd_overflow); + if (IS_ERR(event)) { + printk(KERN_ERR "nmi watchdog failed to create perf event on %i: %p\n", hotcpu, event); + return NOTIFY_BAD; + } + per_cpu(nmi_watchdog_ev, hotcpu) = event; + perf_event_enable(per_cpu(nmi_watchdog_ev, hotcpu)); + break; +#ifdef CONFIG_HOTPLUG_CPU + case CPU_UP_CANCELED: + case CPU_UP_CANCELED_FROZEN: + perf_event_disable(per_cpu(nmi_watchdog_ev, hotcpu)); + case CPU_DEAD: + case CPU_DEAD_FROZEN: + event = per_cpu(nmi_watchdog_ev, hotcpu); + per_cpu(nmi_watchdog_ev, hotcpu) = NULL; + perf_event_release_kernel(event); + break; +#endif /* CONFIG_HOTPLUG_CPU */ + } + return NOTIFY_OK; +} + +static struct notifier_block __cpuinitdata cpu_nfb = { + .notifier_call = cpu_callback +}; + +static int __initdata nonmi_watchdog; + +static int __init nonmi_watchdog_setup(char *str) +{ + nonmi_watchdog = 1; + return 1; +} +__setup("nonmi_watchdog", nonmi_watchdog_setup); + +static int __init spawn_nmi_watchdog_task(void) +{ + void *cpu = (void *)(long)smp_processor_id(); + int err; + + if (nonmi_watchdog) + return 0; + + err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu); + if (err == NOTIFY_BAD) { + BUG(); + return 1; + } + cpu_callback(&cpu_nfb, CPU_ONLINE, cpu); + register_cpu_notifier(&cpu_nfb); + + return 0; +} +early_initcall(spawn_nmi_watchdog_task); -- GitLab From 84e478c6f1eb9c4bfa1fff2f8108e9a061b46428 Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Fri, 5 Feb 2010 21:47:05 -0500 Subject: [PATCH 0006/5312] nmi_watchdog: Config option to enable new nmi_watchdog These are the bits that enable the new nmi_watchdog and safely isolate the old nmi_watchdog. Only one or the other can run, not both at the same time. Signed-off-by: Don Zickus Cc: Linus Torvalds Cc: Andrew Morton Cc: gorcunov@gmail.com Cc: aris@redhat.com Cc: peterz@infradead.org LKML-Reference: <1265424425-31562-4-git-send-email-dzickus@redhat.com> Signed-off-by: Ingo Molnar --- arch/x86/kernel/apic/Makefile | 7 ++++++- arch/x86/kernel/traps.c | 2 ++ include/linux/nmi.h | 4 ++++ kernel/Makefile | 1 + lib/Kconfig.debug | 13 +++++++++++++ 5 files changed, 26 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/apic/Makefile b/arch/x86/kernel/apic/Makefile index 565c1bfc507d..1a4512e48d24 100644 --- a/arch/x86/kernel/apic/Makefile +++ b/arch/x86/kernel/apic/Makefile @@ -2,7 +2,12 @@ # Makefile for local APIC drivers and for the IO-APIC code # -obj-$(CONFIG_X86_LOCAL_APIC) += apic.o apic_noop.o probe_$(BITS).o ipi.o nmi.o +obj-$(CONFIG_X86_LOCAL_APIC) += apic.o apic_noop.o probe_$(BITS).o ipi.o +ifneq ($(CONFIG_NMI_WATCHDOG),y) +obj-$(CONFIG_X86_LOCAL_APIC) += nmi.o +endif +obj-$(CONFIG_NMI_WATCHDOG) += hw_nmi.o + obj-$(CONFIG_X86_IO_APIC) += io_apic.o obj-$(CONFIG_SMP) += ipi.o diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 51ef893ffa65..973cbc4f044f 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -406,6 +406,7 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs) == NOTIFY_STOP) return; +#ifndef CONFIG_NMI_WATCHDOG /* * Ok, so this is none of the documented NMI sources, * so it must be the NMI watchdog. @@ -413,6 +414,7 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs) if (nmi_watchdog_tick(regs, reason)) return; if (!do_nmi_callback(regs, cpu)) +#endif /* !CONFIG_NMI_WATCHDOG */ unknown_nmi_error(reason, regs); #else unknown_nmi_error(reason, regs); diff --git a/include/linux/nmi.h b/include/linux/nmi.h index b752e807adde..a42ff0bef708 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -47,4 +47,8 @@ static inline bool trigger_all_cpu_backtrace(void) } #endif +#ifdef CONFIG_NMI_WATCHDOG +int hw_nmi_is_cpu_stuck(struct pt_regs *); +#endif + #endif diff --git a/kernel/Makefile b/kernel/Makefile index 864ff75d65f2..8a5abe53ebad 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -76,6 +76,7 @@ obj-$(CONFIG_AUDIT_TREE) += audit_tree.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o +obj-$(CONFIG_NMI_WATCHDOG) += nmi_watchdog.o obj-$(CONFIG_DETECT_HUNG_TASK) += hung_task.o obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ obj-$(CONFIG_SECCOMP) += seccomp.o diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 25c3ed594c54..f80b67e72aa0 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -170,6 +170,19 @@ config DETECT_SOFTLOCKUP can be detected via the NMI-watchdog, on platforms that support it.) +config NMI_WATCHDOG + bool "Detect Hard Lockups with an NMI Watchdog" + depends on DEBUG_KERNEL && PERF_EVENTS + default y + help + Say Y here to enable the kernel to use the NMI as a watchdog + to detect hard lockups. This is useful when a cpu hangs for no + reason but can still respond to NMIs. A backtrace is displayed + for reviewing and reporting. + + The overhead should be minimal, just an extra NMI every few + seconds. + config BOOTPARAM_SOFTLOCKUP_PANIC bool "Panic (Reboot) On Soft Lockups" depends on DETECT_SOFTLOCKUP -- GitLab From 8e7672cdb413af859086ffceaed68f7e1e8ea4c2 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 9 Feb 2010 06:11:00 +0100 Subject: [PATCH 0007/5312] nmi_watchdog: Only enable on x86 for now It wont even build on other platforms just yet - so restrict it to x86 for now. Cc: Don Zickus Cc: gorcunov@gmail.com Cc: aris@redhat.com Cc: peterz@infradead.org LKML-Reference: <1265424425-31562-4-git-send-email-dzickus@redhat.com> Signed-off-by: Ingo Molnar --- lib/Kconfig.debug | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index f80b67e72aa0..acef88239e15 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -173,6 +173,7 @@ config DETECT_SOFTLOCKUP config NMI_WATCHDOG bool "Detect Hard Lockups with an NMI Watchdog" depends on DEBUG_KERNEL && PERF_EVENTS + depends on X86 default y help Say Y here to enable the kernel to use the NMI as a watchdog -- GitLab From c3128fb6ad39b0edda6675d20585a64846cf89ea Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Fri, 12 Feb 2010 17:19:18 -0500 Subject: [PATCH 0008/5312] nmi_watchdog: Use a boolean config flag for compiling Determines if an arch has setup arch specific perf_events and nmi_watchdog code. This should restrict compiles to only those arches ready. Signed-off-by: Don Zickus Cc: peterz@infradead.org Cc: gorcunov@gmail.com Cc: aris@redhat.com LKML-Reference: <1266013161-31197-1-git-send-email-dzickus@redhat.com> Signed-off-by: Ingo Molnar --- arch/x86/Kconfig | 1 + init/Kconfig | 5 +++++ lib/Kconfig.debug | 3 +-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index cbcbfdee3ee0..4f9685fa3a3a 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -52,6 +52,7 @@ config X86 select HAVE_KERNEL_LZO select HAVE_HW_BREAKPOINT select PERF_EVENTS + select PERF_EVENTS_NMI select ANON_INODES select HAVE_ARCH_KMEMCHECK select HAVE_USER_RETURN_NOTIFIER diff --git a/init/Kconfig b/init/Kconfig index ada48441aff8..7331a16dd82c 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -946,6 +946,11 @@ config PERF_USE_VMALLOC help See tools/perf/design.txt for details +config PERF_EVENTS_NMI + bool + help + Arch has support for nmi_watchdog + menu "Kernel Performance Events And Counters" config PERF_EVENTS diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index acef88239e15..01a4d85ee746 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -172,8 +172,7 @@ config DETECT_SOFTLOCKUP config NMI_WATCHDOG bool "Detect Hard Lockups with an NMI Watchdog" - depends on DEBUG_KERNEL && PERF_EVENTS - depends on X86 + depends on DEBUG_KERNEL && PERF_EVENTS && PERF_EVENTS_NMI default y help Say Y here to enable the kernel to use the NMI as a watchdog -- GitLab From 504d7cf10ee42bb76b9556859f23d4121dee0a77 Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Fri, 12 Feb 2010 17:19:19 -0500 Subject: [PATCH 0009/5312] nmi_watchdog: Compile and portability fixes The original patch was x86_64 centric. Changed the code to make it less so. ested by building and running on a powerpc. Signed-off-by: Don Zickus Cc: peterz@infradead.org Cc: gorcunov@gmail.com Cc: aris@redhat.com LKML-Reference: <1266013161-31197-2-git-send-email-dzickus@redhat.com> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/nmi.h | 2 ++ arch/x86/kernel/apic/hw_nmi.c | 21 ++++++++++---- include/linux/nmi.h | 9 ++++++ kernel/nmi_watchdog.c | 52 +++++++++++++++++++++++++++-------- kernel/sysctl.c | 15 +++++++++- 5 files changed, 82 insertions(+), 17 deletions(-) diff --git a/arch/x86/include/asm/nmi.h b/arch/x86/include/asm/nmi.h index 93da9c3f3341..5b41b0feb6db 100644 --- a/arch/x86/include/asm/nmi.h +++ b/arch/x86/include/asm/nmi.h @@ -17,7 +17,9 @@ int do_nmi_callback(struct pt_regs *regs, int cpu); extern void die_nmi(char *str, struct pt_regs *regs, int do_panic); extern int check_nmi_watchdog(void); +#if !defined(CONFIG_NMI_WATCHDOG) extern int nmi_watchdog_enabled; +#endif extern int avail_to_resrv_perfctr_nmi_bit(unsigned int); extern int reserve_perfctr_nmi(unsigned int); extern void release_perfctr_nmi(unsigned int); diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c index 8c0e6a410d05..312d772c5c35 100644 --- a/arch/x86/kernel/apic/hw_nmi.c +++ b/arch/x86/kernel/apic/hw_nmi.c @@ -32,8 +32,13 @@ static DEFINE_PER_CPU(unsigned, last_irq_sum); */ static inline unsigned int get_timer_irqs(int cpu) { - return per_cpu(irq_stat, cpu).apic_timer_irqs + - per_cpu(irq_stat, cpu).irq0_irqs; + unsigned int irqs = per_cpu(irq_stat, cpu).irq0_irqs; + +#if defined(CONFIG_X86_LOCAL_APIC) + irqs += per_cpu(irq_stat, cpu).apic_timer_irqs; +#endif + + return irqs; } static inline int mce_in_progress(void) @@ -82,6 +87,11 @@ int hw_nmi_is_cpu_stuck(struct pt_regs *regs) } } +u64 hw_nmi_get_sample_period(void) +{ + return cpu_khz * 1000; +} + void arch_trigger_all_cpu_backtrace(void) { int i; @@ -100,15 +110,16 @@ void arch_trigger_all_cpu_backtrace(void) } /* STUB calls to mimic old nmi_watchdog behaviour */ +#if defined(CONFIG_X86_LOCAL_APIC) unsigned int nmi_watchdog = NMI_NONE; EXPORT_SYMBOL(nmi_watchdog); +void acpi_nmi_enable(void) { return; } +void acpi_nmi_disable(void) { return; } +#endif atomic_t nmi_active = ATOMIC_INIT(0); /* oprofile uses this */ EXPORT_SYMBOL(nmi_active); -int nmi_watchdog_enabled; int unknown_nmi_panic; void cpu_nmi_set_wd_enabled(void) { return; } -void acpi_nmi_enable(void) { return; } -void acpi_nmi_disable(void) { return; } void stop_apic_nmi_watchdog(void *unused) { return; } void setup_apic_nmi_watchdog(void *unused) { return; } int __init check_nmi_watchdog(void) { return 0; } diff --git a/include/linux/nmi.h b/include/linux/nmi.h index a42ff0bef708..794e7354c5bf 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -20,10 +20,14 @@ extern void touch_nmi_watchdog(void); extern void acpi_nmi_disable(void); extern void acpi_nmi_enable(void); #else +#ifndef CONFIG_NMI_WATCHDOG static inline void touch_nmi_watchdog(void) { touch_softlockup_watchdog(); } +#else +extern void touch_nmi_watchdog(void); +#endif static inline void acpi_nmi_disable(void) { } static inline void acpi_nmi_enable(void) { } #endif @@ -49,6 +53,11 @@ static inline bool trigger_all_cpu_backtrace(void) #ifdef CONFIG_NMI_WATCHDOG int hw_nmi_is_cpu_stuck(struct pt_regs *); +u64 hw_nmi_get_sample_period(void); +extern int nmi_watchdog_enabled; +struct ctl_table; +extern int proc_nmi_enabled(struct ctl_table *, int , + void __user *, size_t *, loff_t *); #endif #endif diff --git a/kernel/nmi_watchdog.c b/kernel/nmi_watchdog.c index 36817b214d69..73c1954a97bb 100644 --- a/kernel/nmi_watchdog.c +++ b/kernel/nmi_watchdog.c @@ -30,6 +30,8 @@ static DEFINE_PER_CPU(struct perf_event *, nmi_watchdog_ev); static DEFINE_PER_CPU(int, nmi_watchdog_touch); static DEFINE_PER_CPU(long, alert_counter); +static int panic_on_timeout; + void touch_nmi_watchdog(void) { __raw_get_cpu_var(nmi_watchdog_touch) = 1; @@ -46,19 +48,49 @@ void touch_all_nmi_watchdog(void) touch_softlockup_watchdog(); } +static int __init setup_nmi_watchdog(char *str) +{ + if (!strncmp(str, "panic", 5)) { + panic_on_timeout = 1; + str = strchr(str, ','); + if (!str) + return 1; + ++str; + } + return 1; +} +__setup("nmi_watchdog=", setup_nmi_watchdog); + #ifdef CONFIG_SYSCTL /* * proc handler for /proc/sys/kernel/nmi_watchdog */ +int nmi_watchdog_enabled; + int proc_nmi_enabled(struct ctl_table *table, int write, void __user *buffer, size_t *length, loff_t *ppos) { int cpu; - if (per_cpu(nmi_watchdog_ev, smp_processor_id()) == NULL) + if (!write) { + struct perf_event *event; + for_each_online_cpu(cpu) { + event = per_cpu(nmi_watchdog_ev, cpu); + if (event->state > PERF_EVENT_STATE_OFF) { + nmi_watchdog_enabled = 1; + break; + } + } + proc_dointvec(table, write, buffer, length, ppos); + return 0; + } + + if (per_cpu(nmi_watchdog_ev, smp_processor_id()) == NULL) { nmi_watchdog_enabled = 0; - else - nmi_watchdog_enabled = 1; + proc_dointvec(table, write, buffer, length, ppos); + printk("NMI watchdog failed configuration, can not be enabled\n"); + return 0; + } touch_all_nmi_watchdog(); proc_dointvec(table, write, buffer, length, ppos); @@ -81,8 +113,6 @@ struct perf_event_attr wd_attr = { .disabled = 1, }; -static int panic_on_timeout; - void wd_overflow(struct perf_event *event, int nmi, struct perf_sample_data *data, struct pt_regs *regs) @@ -103,11 +133,11 @@ void wd_overflow(struct perf_event *event, int nmi, */ per_cpu(alert_counter,cpu) += 1; if (per_cpu(alert_counter,cpu) == 5) { - /* - * die_nmi will return ONLY if NOTIFY_STOP happens.. - */ - die_nmi("BUG: NMI Watchdog detected LOCKUP", - regs, panic_on_timeout); + if (panic_on_timeout) { + panic("NMI Watchdog detected LOCKUP on cpu %d", cpu); + } else { + WARN(1, "NMI Watchdog detected LOCKUP on cpu %d", cpu); + } } } else { per_cpu(alert_counter,cpu) = 0; @@ -133,7 +163,7 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) case CPU_ONLINE: case CPU_ONLINE_FROZEN: /* originally wanted the below chunk to be in CPU_UP_PREPARE, but caps is unpriv for non-CPU0 */ - wd_attr.sample_period = cpu_khz * 1000; + wd_attr.sample_period = hw_nmi_get_sample_period(); event = perf_event_create_kernel_counter(&wd_attr, hotcpu, -1, wd_overflow); if (IS_ERR(event)) { printk(KERN_ERR "nmi watchdog failed to create perf event on %i: %p\n", hotcpu, event); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 8a68b2448468..ac72c9e6bd9b 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -60,6 +60,10 @@ #include #endif +#ifdef CONFIG_NMI_WATCHDOG +#include +#endif + #if defined(CONFIG_SYSCTL) @@ -692,7 +696,16 @@ static struct ctl_table kern_table[] = { .mode = 0444, .proc_handler = proc_dointvec, }, -#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) +#if defined(CONFIG_NMI_WATCHDOG) + { + .procname = "nmi_watchdog", + .data = &nmi_watchdog_enabled, + .maxlen = sizeof (int), + .mode = 0644, + .proc_handler = proc_nmi_enabled, + }, +#endif +#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) && !defined(CONFIG_NMI_WATCHDOG) { .procname = "unknown_nmi_panic", .data = &unknown_nmi_panic, -- GitLab From cf454aecb31741a0438ed1201b3dd153c7c7b19a Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Fri, 12 Feb 2010 17:19:20 -0500 Subject: [PATCH 0010/5312] nmi_watchdog: Fallback to software events when no hardware pmu detected Not all arches have a PMU or have perf_event support for their PMU. The nmi_watchdog will fail in those cases. Fallback to using software events to generate nmi_watchdog traffic with local apic interrupts. Tested on a Pentium4 and it worked as expected, excepting for detecting cpu lockups. The problem with using software events as a cpu lock up detector is the nmi_watchdog uses the logic that if local apic interrupts stop incrementing then the cpu is probably locked up. But with software events we use the local apic to trigger the nmi_watchdog callback to see if local apic interrupts are still firing, which obviously they are otherwise we wouldn't have been triggered. The algorithm to detect cpu lock ups is the same as the old nmi_watchdog. Perhaps we need to find a better way to detect lock ups? Signed-off-by: Don Zickus Cc: peterz@infradead.org Cc: gorcunov@gmail.com Cc: aris@redhat.com LKML-Reference: <1266013161-31197-3-git-send-email-dzickus@redhat.com> Signed-off-by: Ingo Molnar --- kernel/nmi_watchdog.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/kernel/nmi_watchdog.c b/kernel/nmi_watchdog.c index 73c1954a97bb..4f23505d887d 100644 --- a/kernel/nmi_watchdog.c +++ b/kernel/nmi_watchdog.c @@ -166,8 +166,12 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) wd_attr.sample_period = hw_nmi_get_sample_period(); event = perf_event_create_kernel_counter(&wd_attr, hotcpu, -1, wd_overflow); if (IS_ERR(event)) { - printk(KERN_ERR "nmi watchdog failed to create perf event on %i: %p\n", hotcpu, event); - return NOTIFY_BAD; + wd_attr.type = PERF_TYPE_SOFTWARE; + event = perf_event_create_kernel_counter(&wd_attr, hotcpu, -1, wd_overflow); + if (IS_ERR(event)) { + printk(KERN_ERR "nmi watchdog failed to create perf event on %i: %p\n", hotcpu, event); + return NOTIFY_BAD; + } } per_cpu(nmi_watchdog_ev, hotcpu) = event; perf_event_enable(per_cpu(nmi_watchdog_ev, hotcpu)); -- GitLab From 6081b6cd9702967889de34fe5da1f96bb96d0ab8 Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Tue, 16 Feb 2010 17:04:52 -0500 Subject: [PATCH 0011/5312] nmi_watchdog: support for oprofile Re-arrange the code so that when someone disables nmi_watchdog with: echo 0 > /proc/sys/kernel/nmi_watchdog it releases the hardware reservation on the PMUs. This allows the oprofile module to grab those PMUs and do its thing. Otherwise oprofile fails to load because the hardware is reserved by the perf_events subsystem. Tested using: oprofile --vm-linux --start and watched it failed when nmi_watchdog is enabled and succeed when: oprofile --deinit && echo 0 > /proc/sys/kernel/nmi_watchdog is run. Note: this has the side quirk of having the nmi_watchdog latch onto the software events instead of hardware events if oprofile has already reserved the hardware first. User beware! :-) Signed-off-by: Don Zickus Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: gorcunov@gmail.com Cc: aris@redhat.com Cc: eranian@google.com LKML-Reference: <1266357892-30504-1-git-send-email-dzickus@redhat.com> Signed-off-by: Ingo Molnar --- kernel/nmi_watchdog.c | 144 ++++++++++++++++++++++++------------------ 1 file changed, 82 insertions(+), 62 deletions(-) diff --git a/kernel/nmi_watchdog.c b/kernel/nmi_watchdog.c index 4f23505d887d..633b230c2319 100644 --- a/kernel/nmi_watchdog.c +++ b/kernel/nmi_watchdog.c @@ -61,50 +61,6 @@ static int __init setup_nmi_watchdog(char *str) } __setup("nmi_watchdog=", setup_nmi_watchdog); -#ifdef CONFIG_SYSCTL -/* - * proc handler for /proc/sys/kernel/nmi_watchdog - */ -int nmi_watchdog_enabled; - -int proc_nmi_enabled(struct ctl_table *table, int write, - void __user *buffer, size_t *length, loff_t *ppos) -{ - int cpu; - - if (!write) { - struct perf_event *event; - for_each_online_cpu(cpu) { - event = per_cpu(nmi_watchdog_ev, cpu); - if (event->state > PERF_EVENT_STATE_OFF) { - nmi_watchdog_enabled = 1; - break; - } - } - proc_dointvec(table, write, buffer, length, ppos); - return 0; - } - - if (per_cpu(nmi_watchdog_ev, smp_processor_id()) == NULL) { - nmi_watchdog_enabled = 0; - proc_dointvec(table, write, buffer, length, ppos); - printk("NMI watchdog failed configuration, can not be enabled\n"); - return 0; - } - - touch_all_nmi_watchdog(); - proc_dointvec(table, write, buffer, length, ppos); - if (nmi_watchdog_enabled) - for_each_online_cpu(cpu) - perf_event_enable(per_cpu(nmi_watchdog_ev, cpu)); - else - for_each_online_cpu(cpu) - perf_event_disable(per_cpu(nmi_watchdog_ev, cpu)); - return 0; -} - -#endif /* CONFIG_SYSCTL */ - struct perf_event_attr wd_attr = { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES, @@ -146,6 +102,85 @@ void wd_overflow(struct perf_event *event, int nmi, return; } +static int enable_nmi_watchdog(int cpu) +{ + struct perf_event *event; + + event = per_cpu(nmi_watchdog_ev, cpu); + if (event && event->state > PERF_EVENT_STATE_OFF) + return 0; + + if (event == NULL) { + /* Try to register using hardware perf events first */ + wd_attr.sample_period = hw_nmi_get_sample_period(); + event = perf_event_create_kernel_counter(&wd_attr, cpu, -1, wd_overflow); + if (IS_ERR(event)) { + wd_attr.type = PERF_TYPE_SOFTWARE; + event = perf_event_create_kernel_counter(&wd_attr, cpu, -1, wd_overflow); + if (IS_ERR(event)) { + printk(KERN_ERR "nmi watchdog failed to create perf event on %i: %p\n", cpu, event); + return -1; + } + } + per_cpu(nmi_watchdog_ev, cpu) = event; + } + perf_event_enable(per_cpu(nmi_watchdog_ev, cpu)); + return 0; +} + +static void disable_nmi_watchdog(int cpu) +{ + struct perf_event *event; + + event = per_cpu(nmi_watchdog_ev, cpu); + if (event) { + perf_event_disable(per_cpu(nmi_watchdog_ev, cpu)); + per_cpu(nmi_watchdog_ev, cpu) = NULL; + perf_event_release_kernel(event); + } +} + +#ifdef CONFIG_SYSCTL +/* + * proc handler for /proc/sys/kernel/nmi_watchdog + */ +int nmi_watchdog_enabled; + +int proc_nmi_enabled(struct ctl_table *table, int write, + void __user *buffer, size_t *length, loff_t *ppos) +{ + int cpu; + + if (!write) { + struct perf_event *event; + for_each_online_cpu(cpu) { + event = per_cpu(nmi_watchdog_ev, cpu); + if (event && event->state > PERF_EVENT_STATE_OFF) { + nmi_watchdog_enabled = 1; + break; + } + } + proc_dointvec(table, write, buffer, length, ppos); + return 0; + } + + touch_all_nmi_watchdog(); + proc_dointvec(table, write, buffer, length, ppos); + if (nmi_watchdog_enabled) { + for_each_online_cpu(cpu) + if (enable_nmi_watchdog(cpu)) { + printk("NMI watchdog failed configuration, " + " can not be enabled\n"); + } + } else { + for_each_online_cpu(cpu) + disable_nmi_watchdog(cpu); + } + return 0; +} + +#endif /* CONFIG_SYSCTL */ + /* * Create/destroy watchdog threads as CPUs come and go: */ @@ -153,7 +188,6 @@ static int __cpuinit cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { int hotcpu = (unsigned long)hcpu; - struct perf_event *event; switch (action) { case CPU_UP_PREPARE: @@ -162,29 +196,15 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) break; case CPU_ONLINE: case CPU_ONLINE_FROZEN: - /* originally wanted the below chunk to be in CPU_UP_PREPARE, but caps is unpriv for non-CPU0 */ - wd_attr.sample_period = hw_nmi_get_sample_period(); - event = perf_event_create_kernel_counter(&wd_attr, hotcpu, -1, wd_overflow); - if (IS_ERR(event)) { - wd_attr.type = PERF_TYPE_SOFTWARE; - event = perf_event_create_kernel_counter(&wd_attr, hotcpu, -1, wd_overflow); - if (IS_ERR(event)) { - printk(KERN_ERR "nmi watchdog failed to create perf event on %i: %p\n", hotcpu, event); - return NOTIFY_BAD; - } - } - per_cpu(nmi_watchdog_ev, hotcpu) = event; - perf_event_enable(per_cpu(nmi_watchdog_ev, hotcpu)); + if (enable_nmi_watchdog(hotcpu)) + return NOTIFY_BAD; break; #ifdef CONFIG_HOTPLUG_CPU case CPU_UP_CANCELED: case CPU_UP_CANCELED_FROZEN: - perf_event_disable(per_cpu(nmi_watchdog_ev, hotcpu)); + disable_nmi_watchdog(hotcpu); case CPU_DEAD: case CPU_DEAD_FROZEN: - event = per_cpu(nmi_watchdog_ev, hotcpu); - per_cpu(nmi_watchdog_ev, hotcpu) = NULL; - perf_event_release_kernel(event); break; #endif /* CONFIG_HOTPLUG_CPU */ } -- GitLab From 96ca4028aca0638d0e11dcbfabc4283054072933 Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Tue, 16 Feb 2010 17:02:25 -0500 Subject: [PATCH 0012/5312] nmi_watchdog: Properly configure for software events Paul Mackerras brought up a good point that when fallbacking to software events, I may have been lucky in my configuration. Modified the code to explicit provide a new configuration for software events. Suggested-by: Paul Mackerras Signed-off-by: Don Zickus Cc: gorcunov@gmail.com Cc: aris@redhat.com Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: <1266357745-26671-1-git-send-email-dzickus@redhat.com> Signed-off-by: Ingo Molnar --- kernel/nmi_watchdog.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/kernel/nmi_watchdog.c b/kernel/nmi_watchdog.c index 633b230c2319..3c75cbf3acb8 100644 --- a/kernel/nmi_watchdog.c +++ b/kernel/nmi_watchdog.c @@ -61,7 +61,7 @@ static int __init setup_nmi_watchdog(char *str) } __setup("nmi_watchdog=", setup_nmi_watchdog); -struct perf_event_attr wd_attr = { +struct perf_event_attr wd_hw_attr = { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES, .size = sizeof(struct perf_event_attr), @@ -69,6 +69,14 @@ struct perf_event_attr wd_attr = { .disabled = 1, }; +struct perf_event_attr wd_sw_attr = { + .type = PERF_TYPE_SOFTWARE, + .config = PERF_COUNT_SW_CPU_CLOCK, + .size = sizeof(struct perf_event_attr), + .pinned = 1, + .disabled = 1, +}; + void wd_overflow(struct perf_event *event, int nmi, struct perf_sample_data *data, struct pt_regs *regs) @@ -105,6 +113,7 @@ void wd_overflow(struct perf_event *event, int nmi, static int enable_nmi_watchdog(int cpu) { struct perf_event *event; + struct perf_event_attr *wd_attr; event = per_cpu(nmi_watchdog_ev, cpu); if (event && event->state > PERF_EVENT_STATE_OFF) @@ -112,11 +121,15 @@ static int enable_nmi_watchdog(int cpu) if (event == NULL) { /* Try to register using hardware perf events first */ - wd_attr.sample_period = hw_nmi_get_sample_period(); - event = perf_event_create_kernel_counter(&wd_attr, cpu, -1, wd_overflow); + wd_attr = &wd_hw_attr; + wd_attr->sample_period = hw_nmi_get_sample_period(); + event = perf_event_create_kernel_counter(wd_attr, cpu, -1, wd_overflow); if (IS_ERR(event)) { - wd_attr.type = PERF_TYPE_SOFTWARE; - event = perf_event_create_kernel_counter(&wd_attr, cpu, -1, wd_overflow); + /* hardware doesn't exist or not supported, fallback to software events */ + printk("nmi_watchdog: hardware not available, trying software events\n"); + wd_attr = &wd_sw_attr; + wd_attr->sample_period = NSEC_PER_SEC; + event = perf_event_create_kernel_counter(wd_attr, cpu, -1, wd_overflow); if (IS_ERR(event)) { printk(KERN_ERR "nmi watchdog failed to create perf event on %i: %p\n", cpu, event); return -1; -- GitLab From 2cc4452bc31fc1cde6f0b64a4eb13269f982787d Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Thu, 18 Feb 2010 21:56:52 -0500 Subject: [PATCH 0013/5312] nmi_watchdog: Fix undefined 'apic' build bug Ingo provided me a config that fails to compile with: arch/x86/built-in.o: In function `arch_trigger_all_cpu_backtrace': (.text+0x17e78): undefined reference to `apic' make: *** [.tmp_vmlinux1] Error 1 I realized I changed the compile behaviour of the nmi code by not wrapping it with CONFIG_LOCAL_APIC. To fix this I add a compile check for ARCH_HAS_NMI_WATCHDOG around arch_trigger_all_cpu_backtrace. Signed-off-by: Don Zickus Cc: a.p.zijlstra@chello.nl Cc: gorcunov@gmail.com Cc: aris@redhat.com LKML-Reference: <1266548212-24243-1-git-send-email-dzickus@redhat.com> Signed-off-by: Ingo Molnar --- arch/x86/kernel/apic/hw_nmi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c index 312d772c5c35..0b4d205a6b8e 100644 --- a/arch/x86/kernel/apic/hw_nmi.c +++ b/arch/x86/kernel/apic/hw_nmi.c @@ -92,6 +92,7 @@ u64 hw_nmi_get_sample_period(void) return cpu_khz * 1000; } +#ifdef ARCH_HAS_NMI_WATCHDOG void arch_trigger_all_cpu_backtrace(void) { int i; @@ -108,6 +109,7 @@ void arch_trigger_all_cpu_backtrace(void) mdelay(1); } } +#endif /* STUB calls to mimic old nmi_watchdog behaviour */ #if defined(CONFIG_X86_LOCAL_APIC) -- GitLab From 47195d57636604ff6048b0d7aa3e4ed9643f6073 Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Mon, 22 Feb 2010 18:09:03 -0500 Subject: [PATCH 0014/5312] nmi_watchdog: Clean up various small details Mostly copy/paste whitespace damage with a couple of nitpicks by the checkpatch script. Fix the struct definition as requested by Ingo too. Signed-off-by: Don Zickus Cc: peterz@infradead.org Cc: gorcunov@gmail.com Cc: aris@redhat.com LKML-Reference: <1266880143-24943-1-git-send-email-dzickus@redhat.com> Signed-off-by: Ingo Molnar -- arch/x86/kernel/apic/hw_nmi.c | 14 +++++------ arch/x86/kernel/traps.c | 6 ++-- include/linux/nmi.h | 2 - kernel/nmi_watchdog.c | 51 ++++++++++++++++++++---------------------- 4 files changed, 36 insertions(+), 37 deletions(-) --- arch/x86/kernel/apic/hw_nmi.c | 14 +++++----- arch/x86/kernel/traps.c | 6 ++--- include/linux/nmi.h | 2 +- kernel/nmi_watchdog.c | 51 +++++++++++++++++------------------ 4 files changed, 36 insertions(+), 37 deletions(-) diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c index 0b4d205a6b8e..e8b78a0be5de 100644 --- a/arch/x86/kernel/apic/hw_nmi.c +++ b/arch/x86/kernel/apic/hw_nmi.c @@ -38,15 +38,15 @@ static inline unsigned int get_timer_irqs(int cpu) irqs += per_cpu(irq_stat, cpu).apic_timer_irqs; #endif - return irqs; + return irqs; } static inline int mce_in_progress(void) { #if defined(CONFIG_X86_MCE) - return atomic_read(&mce_entry) > 0; + return atomic_read(&mce_entry) > 0; #endif - return 0; + return 0; } int hw_nmi_is_cpu_stuck(struct pt_regs *regs) @@ -69,9 +69,9 @@ int hw_nmi_is_cpu_stuck(struct pt_regs *regs) } /* if we are doing an mce, just assume the cpu is not stuck */ - /* Could check oops_in_progress here too, but it's safer not to */ - if (mce_in_progress()) - return 0; + /* Could check oops_in_progress here too, but it's safer not to */ + if (mce_in_progress()) + return 0; /* We determine if the cpu is stuck by checking whether any * interrupts have happened since we last checked. Of course @@ -89,7 +89,7 @@ int hw_nmi_is_cpu_stuck(struct pt_regs *regs) u64 hw_nmi_get_sample_period(void) { - return cpu_khz * 1000; + return cpu_khz * 1000; } #ifdef ARCH_HAS_NMI_WATCHDOG diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 973cbc4f044f..bdc7fab3ef3e 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -402,9 +402,9 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs) return; #ifdef CONFIG_X86_LOCAL_APIC - if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) - == NOTIFY_STOP) - return; + if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) + == NOTIFY_STOP) + return; #ifndef CONFIG_NMI_WATCHDOG /* diff --git a/include/linux/nmi.h b/include/linux/nmi.h index 794e7354c5bf..22cc7960b649 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -57,7 +57,7 @@ u64 hw_nmi_get_sample_period(void); extern int nmi_watchdog_enabled; struct ctl_table; extern int proc_nmi_enabled(struct ctl_table *, int , - void __user *, size_t *, loff_t *); + void __user *, size_t *, loff_t *); #endif #endif diff --git a/kernel/nmi_watchdog.c b/kernel/nmi_watchdog.c index 3c75cbf3acb8..0a6f57f537a7 100644 --- a/kernel/nmi_watchdog.c +++ b/kernel/nmi_watchdog.c @@ -50,31 +50,31 @@ void touch_all_nmi_watchdog(void) static int __init setup_nmi_watchdog(char *str) { - if (!strncmp(str, "panic", 5)) { - panic_on_timeout = 1; - str = strchr(str, ','); - if (!str) - return 1; - ++str; - } - return 1; + if (!strncmp(str, "panic", 5)) { + panic_on_timeout = 1; + str = strchr(str, ','); + if (!str) + return 1; + ++str; + } + return 1; } __setup("nmi_watchdog=", setup_nmi_watchdog); struct perf_event_attr wd_hw_attr = { - .type = PERF_TYPE_HARDWARE, - .config = PERF_COUNT_HW_CPU_CYCLES, - .size = sizeof(struct perf_event_attr), - .pinned = 1, - .disabled = 1, + .type = PERF_TYPE_HARDWARE, + .config = PERF_COUNT_HW_CPU_CYCLES, + .size = sizeof(struct perf_event_attr), + .pinned = 1, + .disabled = 1, }; struct perf_event_attr wd_sw_attr = { - .type = PERF_TYPE_SOFTWARE, - .config = PERF_COUNT_SW_CPU_CLOCK, - .size = sizeof(struct perf_event_attr), - .pinned = 1, - .disabled = 1, + .type = PERF_TYPE_SOFTWARE, + .config = PERF_COUNT_SW_CPU_CLOCK, + .size = sizeof(struct perf_event_attr), + .pinned = 1, + .disabled = 1, }; void wd_overflow(struct perf_event *event, int nmi, @@ -95,16 +95,15 @@ void wd_overflow(struct perf_event *event, int nmi, * Ayiee, looks like this CPU is stuck ... * wait a few IRQs (5 seconds) before doing the oops ... */ - per_cpu(alert_counter,cpu) += 1; - if (per_cpu(alert_counter,cpu) == 5) { - if (panic_on_timeout) { + per_cpu(alert_counter, cpu) += 1; + if (per_cpu(alert_counter, cpu) == 5) { + if (panic_on_timeout) panic("NMI Watchdog detected LOCKUP on cpu %d", cpu); - } else { + else WARN(1, "NMI Watchdog detected LOCKUP on cpu %d", cpu); - } } } else { - per_cpu(alert_counter,cpu) = 0; + per_cpu(alert_counter, cpu) = 0; } return; @@ -126,7 +125,7 @@ static int enable_nmi_watchdog(int cpu) event = perf_event_create_kernel_counter(wd_attr, cpu, -1, wd_overflow); if (IS_ERR(event)) { /* hardware doesn't exist or not supported, fallback to software events */ - printk("nmi_watchdog: hardware not available, trying software events\n"); + printk(KERN_INFO "nmi_watchdog: hardware not available, trying software events\n"); wd_attr = &wd_sw_attr; wd_attr->sample_period = NSEC_PER_SEC; event = perf_event_create_kernel_counter(wd_attr, cpu, -1, wd_overflow); @@ -182,7 +181,7 @@ int proc_nmi_enabled(struct ctl_table *table, int write, if (nmi_watchdog_enabled) { for_each_online_cpu(cpu) if (enable_nmi_watchdog(cpu)) { - printk("NMI watchdog failed configuration, " + printk(KERN_ERR "NMI watchdog failed configuration, " " can not be enabled\n"); } } else { -- GitLab From c99c30feadf664ccd8590b96259cb9f3954bd246 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 28 Feb 2010 20:49:00 +0100 Subject: [PATCH 0015/5312] nmi_watchdog: Turn it off by default It was nice to enable it by default for testing - but before we push it upstream we want it to be off - so that people can opt-in gradually. Cc: Don Zickus Cc: peterz@infradead.org Cc: gorcunov@gmail.com Cc: aris@redhat.com LKML-Reference: <1266880143-24943-1-git-send-email-dzickus@redhat.com> Signed-off-by: Ingo Molnar --- lib/Kconfig.debug | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 01a4d85ee746..e2e73cc17a91 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -173,7 +173,6 @@ config DETECT_SOFTLOCKUP config NMI_WATCHDOG bool "Detect Hard Lockups with an NMI Watchdog" depends on DEBUG_KERNEL && PERF_EVENTS && PERF_EVENTS_NMI - default y help Say Y here to enable the kernel to use the NMI as a watchdog to detect hard lockups. This is useful when a cpu hangs for no -- GitLab From 5671a10e2bc7f99d9157c6044faf8be2ef302361 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 2 Mar 2010 14:20:14 +0100 Subject: [PATCH 0016/5312] nmi_watchdog: Tell the world we're active Because I was wondering why perf stat wasn't working as expected.. Signed-off-by: Peter Zijlstra Cc: Don Zickus LKML-Reference: Signed-off-by: Ingo Molnar --- kernel/nmi_watchdog.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/nmi_watchdog.c b/kernel/nmi_watchdog.c index 0a6f57f537a7..a79d211c30df 100644 --- a/kernel/nmi_watchdog.c +++ b/kernel/nmi_watchdog.c @@ -244,6 +244,8 @@ static int __init spawn_nmi_watchdog_task(void) if (nonmi_watchdog) return 0; + printk(KERN_INFO "NMI watchdog enabled, takes one hw-pmu counter.\n"); + err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu); if (err == NOTIFY_BAD) { BUG(); -- GitLab From 927a7c9c1793def3a55d60c926d3945528e6bf1b Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Fri, 19 Mar 2010 04:47:19 +0000 Subject: [PATCH 0017/5312] dmaengine: shdma: Enable on SH-Mobile ARM Enable the shdma dmaengine driver on SH-Mobile ARM. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/dma/Kconfig | 2 +- drivers/dma/shdma.c | 8 ++++---- include/linux/serial_sci.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index c27f80e5d531..9d8ca990dde6 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -128,7 +128,7 @@ config TXX9_DMAC config SH_DMAE tristate "Renesas SuperH DMAC support" - depends on SUPERH && SH_DMA + depends on (SUPERH && SH_DMA) || (ARM && ARCH_SHMOBILE) depends on !SH_DMA_API select DMA_ENGINE help diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index 7a18b580f626..bbc3dfeed9b2 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -793,7 +793,7 @@ static irqreturn_t sh_dmae_interrupt(int irq, void *data) return ret; } -#if defined(CONFIG_CPU_SH4) +#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) static irqreturn_t sh_dmae_err(int irq, void *data) { struct sh_dmae_device *shdev = (struct sh_dmae_device *)data; @@ -1034,7 +1034,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev) /* Default transfer size of 32 bytes requires 32-byte alignment */ shdev->common.copy_align = LOG2_DEFAULT_XFER_SIZE; -#if defined(CONFIG_CPU_SH4) +#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) chanirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1); if (!chanirq_res) @@ -1059,7 +1059,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev) #else chanirq_res = errirq_res; -#endif /* CONFIG_CPU_SH4 */ +#endif /* CONFIG_CPU_SH4 || CONFIG_ARCH_SHMOBILE */ if (chanirq_res->start == chanirq_res->end && !platform_get_resource(pdev, IORESOURCE_IRQ, 1)) { @@ -1106,7 +1106,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev) chan_probe_err: sh_dmae_chan_remove(shdev); eirqres: -#if defined(CONFIG_CPU_SH4) +#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) free_irq(errirq, shdev); eirq_err: #endif diff --git a/include/linux/serial_sci.h b/include/linux/serial_sci.h index f5364a1de68b..837efa4e63c2 100644 --- a/include/linux/serial_sci.h +++ b/include/linux/serial_sci.h @@ -3,7 +3,7 @@ #include #ifdef CONFIG_SERIAL_SH_SCI_DMA -#include +#include #endif /* -- GitLab From 12a55f2db71e0a1474ba56ab1c93287600b915be Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 11 Mar 2010 10:05:50 +0000 Subject: [PATCH 0018/5312] i2c: i2c-sh_mobile register access code break out Break out register access functions in the i2c-sh_mobile driver. This update should not change any driver logic. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/i2c/busses/i2c-sh_mobile.c | 90 ++++++++++++++++++------------ 1 file changed, 53 insertions(+), 37 deletions(-) diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index ffb405d7c6f2..d2fabd9dbf80 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -132,12 +132,12 @@ struct sh_mobile_i2c_data { #define NORMAL_SPEED 100000 /* FAST_SPEED 400000 */ /* Register offsets */ -#define ICDR(pd) (pd->reg + 0x00) -#define ICCR(pd) (pd->reg + 0x04) -#define ICSR(pd) (pd->reg + 0x08) -#define ICIC(pd) (pd->reg + 0x0c) -#define ICCL(pd) (pd->reg + 0x10) -#define ICCH(pd) (pd->reg + 0x14) +#define ICDR 0x00 +#define ICCR 0x04 +#define ICSR 0x08 +#define ICIC 0x0c +#define ICCL 0x10 +#define ICCH 0x14 /* Register bits */ #define ICCR_ICE 0x80 @@ -160,6 +160,22 @@ struct sh_mobile_i2c_data { #define ICIC_WAITE 0x02 #define ICIC_DTEE 0x01 +static void iic_wr(struct sh_mobile_i2c_data *pd, int offs, unsigned char data) +{ + iowrite8(data, pd->reg + offs); +} + +static unsigned char iic_rd(struct sh_mobile_i2c_data *pd, int offs) +{ + return ioread8(pd->reg + offs); +} + +static void iic_set_clr(struct sh_mobile_i2c_data *pd, int offs, + unsigned char set, unsigned char clr) +{ + iic_wr(pd, offs, (iic_rd(pd, offs) | set) & ~clr); +} + static void activate_ch(struct sh_mobile_i2c_data *pd) { unsigned long i2c_clk; @@ -197,24 +213,24 @@ static void activate_ch(struct sh_mobile_i2c_data *pd) pd->icch = (u_int8_t)(num/denom); /* Enable channel and configure rx ack */ - iowrite8(ioread8(ICCR(pd)) | ICCR_ICE, ICCR(pd)); + iic_set_clr(pd, ICCR, ICCR_ICE, 0); /* Mask all interrupts */ - iowrite8(0, ICIC(pd)); + iic_wr(pd, ICIC, 0); /* Set the clock */ - iowrite8(pd->iccl, ICCL(pd)); - iowrite8(pd->icch, ICCH(pd)); + iic_wr(pd, ICCL, pd->iccl); + iic_wr(pd, ICCH, pd->icch); } static void deactivate_ch(struct sh_mobile_i2c_data *pd) { /* Clear/disable interrupts */ - iowrite8(0, ICSR(pd)); - iowrite8(0, ICIC(pd)); + iic_wr(pd, ICSR, 0); + iic_wr(pd, ICIC, 0); /* Disable channel */ - iowrite8(ioread8(ICCR(pd)) & ~ICCR_ICE, ICCR(pd)); + iic_set_clr(pd, ICCR, 0, ICCR_ICE); /* Disable clock and mark device as idle */ clk_disable(pd->clk); @@ -233,35 +249,35 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, switch (op) { case OP_START: /* issue start and trigger DTE interrupt */ - iowrite8(0x94, ICCR(pd)); + iic_wr(pd, ICCR, 0x94); break; case OP_TX_FIRST: /* disable DTE interrupt and write data */ - iowrite8(ICIC_WAITE | ICIC_ALE | ICIC_TACKE, ICIC(pd)); - iowrite8(data, ICDR(pd)); + iic_wr(pd, ICIC, ICIC_WAITE | ICIC_ALE | ICIC_TACKE); + iic_wr(pd, ICDR, data); break; case OP_TX: /* write data */ - iowrite8(data, ICDR(pd)); + iic_wr(pd, ICDR, data); break; case OP_TX_STOP: /* write data and issue a stop afterwards */ - iowrite8(data, ICDR(pd)); - iowrite8(0x90, ICCR(pd)); + iic_wr(pd, ICDR, data); + iic_wr(pd, ICCR, 0x90); break; case OP_TX_TO_RX: /* select read mode */ - iowrite8(0x81, ICCR(pd)); + iic_wr(pd, ICCR, 0x81); break; case OP_RX: /* just read data */ - ret = ioread8(ICDR(pd)); + ret = iic_rd(pd, ICDR); break; case OP_RX_STOP: /* enable DTE interrupt, issue stop */ - iowrite8(ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE, - ICIC(pd)); - iowrite8(0xc0, ICCR(pd)); + iic_wr(pd, ICIC, + ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE); + iic_wr(pd, ICCR, 0xc0); break; case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */ - iowrite8(ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE, - ICIC(pd)); - ret = ioread8(ICDR(pd)); - iowrite8(0xc0, ICCR(pd)); + iic_wr(pd, ICIC, + ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE); + ret = iic_rd(pd, ICDR); + iic_wr(pd, ICCR, 0xc0); break; } @@ -367,7 +383,7 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) unsigned char sr; int wakeup; - sr = ioread8(ICSR(pd)); + sr = iic_rd(pd, ICSR); pd->sr |= sr; /* remember state */ dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr, @@ -376,7 +392,7 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) if (sr & (ICSR_AL | ICSR_TACK)) { /* don't interrupt transaction - continue to issue stop */ - iowrite8(sr & ~(ICSR_AL | ICSR_TACK), ICSR(pd)); + iic_wr(pd, ICSR, sr & ~(ICSR_AL | ICSR_TACK)); wakeup = 0; } else if (pd->msg->flags & I2C_M_RD) wakeup = sh_mobile_i2c_isr_rx(pd); @@ -384,7 +400,7 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) wakeup = sh_mobile_i2c_isr_tx(pd); if (sr & ICSR_WAIT) /* TODO: add delay here to support slow acks */ - iowrite8(sr & ~ICSR_WAIT, ICSR(pd)); + iic_wr(pd, ICSR, sr & ~ICSR_WAIT); if (wakeup) { pd->sr |= SW_DONE; @@ -402,21 +418,21 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg) } /* Initialize channel registers */ - iowrite8(ioread8(ICCR(pd)) & ~ICCR_ICE, ICCR(pd)); + iic_set_clr(pd, ICCR, 0, ICCR_ICE); /* Enable channel and configure rx ack */ - iowrite8(ioread8(ICCR(pd)) | ICCR_ICE, ICCR(pd)); + iic_set_clr(pd, ICCR, ICCR_ICE, 0); /* Set the clock */ - iowrite8(pd->iccl, ICCL(pd)); - iowrite8(pd->icch, ICCH(pd)); + iic_wr(pd, ICCL, pd->iccl); + iic_wr(pd, ICCH, pd->icch); pd->msg = usr_msg; pd->pos = -1; pd->sr = 0; /* Enable all interrupts to begin with */ - iowrite8(ICIC_WAITE | ICIC_ALE | ICIC_TACKE | ICIC_DTEE, ICIC(pd)); + iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE); return 0; } @@ -451,7 +467,7 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, retry_count = 1000; again: - val = ioread8(ICSR(pd)); + val = iic_rd(pd, ICSR); dev_dbg(pd->dev, "val 0x%02x pd->sr 0x%02x\n", val, pd->sr); -- GitLab From 962b6032c889ed9a5f0bdb7052d9318067a75bda Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 11 Mar 2010 10:06:02 +0000 Subject: [PATCH 0019/5312] i2c: i2c-sh_mobile support for new ICIC bits Add support for a new version of the IIC block found in the SH-Mobile ARM line of processors. Prototype patch written by Nishimoto-san. Tested on sh7377 and sh7372. Signed-off-by: NISHIMOTO Hiroki Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/i2c/busses/i2c-sh_mobile.c | 31 ++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index d2fabd9dbf80..598c49acaeb5 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -119,8 +119,10 @@ struct sh_mobile_i2c_data { struct i2c_adapter adap; struct clk *clk; + u_int8_t icic; u_int8_t iccl; u_int8_t icch; + u_int8_t flags; spinlock_t lock; wait_queue_head_t wait; @@ -129,6 +131,8 @@ struct sh_mobile_i2c_data { int sr; }; +#define IIC_FLAG_HAS_ICIC67 (1 << 0) + #define NORMAL_SPEED 100000 /* FAST_SPEED 400000 */ /* Register offsets */ @@ -155,6 +159,8 @@ struct sh_mobile_i2c_data { #define ICSR_WAIT 0x02 #define ICSR_DTE 0x01 +#define ICIC_ICCLB8 0x80 +#define ICIC_ICCHB8 0x40 #define ICIC_ALE 0x08 #define ICIC_TACKE 0x04 #define ICIC_WAITE 0x02 @@ -162,6 +168,9 @@ struct sh_mobile_i2c_data { static void iic_wr(struct sh_mobile_i2c_data *pd, int offs, unsigned char data) { + if (offs == ICIC) + data |= pd->icic; + iowrite8(data, pd->reg + offs); } @@ -203,6 +212,14 @@ static void activate_ch(struct sh_mobile_i2c_data *pd) else pd->iccl = (u_int8_t)(num/denom); + /* one more bit of ICCL in ICIC */ + if (pd->flags & IIC_FLAG_HAS_ICIC67) { + if ((num/denom) > 0xff) + pd->icic |= ICIC_ICCLB8; + else + pd->icic &= ~ICIC_ICCLB8; + } + /* Calculate the value for icch. From the data sheet: icch = (p clock / transfer rate) * (H / (L + H)) */ num = i2c_clk * 4; @@ -212,6 +229,14 @@ static void activate_ch(struct sh_mobile_i2c_data *pd) else pd->icch = (u_int8_t)(num/denom); + /* one more bit of ICCH in ICIC */ + if (pd->flags & IIC_FLAG_HAS_ICIC67) { + if ((num/denom) > 0xff) + pd->icic |= ICIC_ICCHB8; + else + pd->icic &= ~ICIC_ICCHB8; + } + /* Enable channel and configure rx ack */ iic_set_clr(pd, ICCR, ICCR_ICE, 0); @@ -592,6 +617,12 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) goto err_irq; } + /* The IIC blocks on SH-Mobile ARM processors + * come with two new bits in ICIC. + */ + if (size > 0x17) + pd->flags |= IIC_FLAG_HAS_ICIC67; + /* Enable Runtime PM for this device. * * Also tell the Runtime PM core to ignore children -- GitLab From 0924fada1e64f92dd89818cf3a15571cc515afd8 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 11 Mar 2010 10:06:15 +0000 Subject: [PATCH 0020/5312] i2c: i2c-sh_mobile kconfig update for SH-Mobile ARM Update the Kconfig entry for the i2c-sh_mobile driver to enable build on SH-Mobile ARM platforms Signed-off-by: Kuninori Morimoto Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/i2c/busses/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 9c6170cd9aac..41b0754eaf62 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -529,7 +529,7 @@ config I2C_SH7760 config I2C_SH_MOBILE tristate "SuperH Mobile I2C Controller" - depends on SUPERH + depends on SUPERH || ARCH_SHMOBILE help If you say yes to this option, support will be included for the built-in I2C interface on the Renesas SH-Mobile processor. -- GitLab From c1909cc19abdfa9f995036996603c9e969117e72 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 11 Mar 2010 10:42:47 +0000 Subject: [PATCH 0021/5312] ARM: mach-shmobile: sh7372: Add I2C0, I2C1 support sh7372 chip has 2 INTC. Then, I2C0 is connected to INTCS, and I2C1 is connected to INTCA. Both of these has no GPIO settings. Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/setup-sh7372.c | 47 +++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index 1d1153290f59..b7c5d896e01c 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c @@ -32,6 +32,7 @@ #include #include +/* SCIF */ static struct plat_sci_port scif0_platform_data = { .mapbase = 0xe6c40000, .flags = UPF_BOOT_AUTOCONF, @@ -137,6 +138,7 @@ static struct platform_device scif6_device = { }, }; +/* CMT */ static struct sh_timer_config cmt10_platform_data = { .name = "CMT10", .channel_offset = 0x10, @@ -169,6 +171,49 @@ static struct platform_device cmt10_device = { .num_resources = ARRAY_SIZE(cmt10_resources), }; +/* I2C */ +static struct resource iic0_resources[] = { + [0] = { + .name = "IIC0", + .start = 0xFFF20000, + .end = 0xFFF20425 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = intcs_evt2irq(0xe00), + .end = intcs_evt2irq(0xe60), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device iic0_device = { + .name = "i2c-sh_mobile", + .id = 0, /* "i2c0" clock */ + .num_resources = ARRAY_SIZE(iic0_resources), + .resource = iic0_resources, +}; + +static struct resource iic1_resources[] = { + [0] = { + .name = "IIC1", + .start = 0xE6C20000, + .end = 0xE6C20425 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 44, + .end = 47, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device iic1_device = { + .name = "i2c-sh_mobile", + .id = 1, /* "i2c1" clock */ + .num_resources = ARRAY_SIZE(iic1_resources), + .resource = iic1_resources, +}; + static struct platform_device *sh7372_early_devices[] __initdata = { &scif0_device, &scif1_device, @@ -178,6 +223,8 @@ static struct platform_device *sh7372_early_devices[] __initdata = { &scif5_device, &scif6_device, &cmt10_device, + &iic0_device, + &iic1_device, }; void __init sh7372_add_standard_devices(void) -- GitLab From 91cf5082292129881fbbfb6390b9544050c25619 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 11 Mar 2010 10:42:52 +0000 Subject: [PATCH 0022/5312] ARM: mach-shmobile: ap4evb: Add TouchScreen support Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ap4evb.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 1c2ec96ce261..b10431451f39 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include #include @@ -234,6 +236,23 @@ static struct platform_device *ap4evb_devices[] __initdata = { &sdhi0_device, }; +/* TouchScreen */ +#define IRQ28 396 +struct tsc2007_platform_data tsc2007_info = { + .model = 2007, + .x_plate_ohms = 180, +}; + +/* I2C */ +static struct i2c_board_info i2c1_devices[] = { + { + I2C_BOARD_INFO("tsc2007", 0x48), + .type = "tsc2007", + .platform_data = &tsc2007_info, + .irq = IRQ28, + }, +}; + static struct map_desc ap4evb_io_desc[] __initdata = { /* create a 1:1 entity map for 0xe6xxxxxx * used by CPGA, INTC and PFC. @@ -318,6 +337,13 @@ static void __init ap4evb_init(void) gpio_request(GPIO_FN_SDHID0_1, NULL); gpio_request(GPIO_FN_SDHID0_0, NULL); + /* enable TouchScreen */ + gpio_request(GPIO_FN_IRQ28_123, NULL); + set_irq_type(IRQ28, IRQ_TYPE_LEVEL_LOW); + + i2c_register_board_info(1, i2c1_devices, + ARRAY_SIZE(i2c1_devices)); + sh7372_add_standard_devices(); platform_add_devices(ap4evb_devices, ARRAY_SIZE(ap4evb_devices)); -- GitLab From dda128dcb4d85dfd6a2e11002d0c2f352aea7dc5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 12 Mar 2010 10:07:55 +0000 Subject: [PATCH 0023/5312] ARM: mach-shmobile: ap4evb: Add SW43, SW3 tiny document Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ap4evb.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index b10431451f39..0a7eb29cd7ca 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -82,12 +82,16 @@ */ /* - * KEYSC + * LCD / IRQ / KEYSC / IrDA * - * SW43 KEYSC - * ------------------------- - * ON enable - * OFF disable + * IRQ = IRQ26 (TS), IRQ27 (VIO), IRQ28 (TouchScreen) + * LCD = 2nd LCDC + * + * | SW43 | + * SW3 | ON | OFF | + * -------------+-----------------------+---------------+ + * ON | KEY / IrDA | LCD | + * OFF | KEY / IrDA / IRQ | IRQ | */ /* MTD */ @@ -236,7 +240,7 @@ static struct platform_device *ap4evb_devices[] __initdata = { &sdhi0_device, }; -/* TouchScreen */ +/* TouchScreen (Needs SW3 set to OFF) */ #define IRQ28 396 struct tsc2007_platform_data tsc2007_info = { .model = 2007, -- GitLab From 8fc883c2989c20781b001f8271d454d9b314a6ea Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 11 Mar 2010 07:34:37 +0000 Subject: [PATCH 0024/5312] ARM: mach-shmobile: ap4evb: Add R2025S RTC support Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ap4evb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 0a7eb29cd7ca..e7602945a6a5 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -249,6 +249,9 @@ struct tsc2007_platform_data tsc2007_info = { /* I2C */ static struct i2c_board_info i2c1_devices[] = { + { + I2C_BOARD_INFO("r2025sd", 0x32), + }, { I2C_BOARD_INFO("tsc2007", 0x48), .type = "tsc2007", -- GitLab From ff9170aeff93575b05474f29533ac9688891742e Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 11 Mar 2010 05:30:30 +0000 Subject: [PATCH 0025/5312] ARM: mach-shmobile: add INTCS macros Add SH-Mobile ARM INTCS macros for the INTCS controller. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/include/mach/irqs.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/mach-shmobile/include/mach/irqs.h b/arch/arm/mach-shmobile/include/mach/irqs.h index 5179b72e1ee3..51b4a6ab6c60 100644 --- a/arch/arm/mach-shmobile/include/mach/irqs.h +++ b/arch/arm/mach-shmobile/include/mach/irqs.h @@ -4,7 +4,13 @@ #define NR_IRQS 512 #define NR_IRQS_LEGACY 8 +/* INTCA */ #define evt2irq(evt) (((evt) >> 5) - 16) #define irq2evt(irq) (((irq) + 16) << 5) +/* INTCS */ +#define INTCS_VECT_BASE 0x3400 +#define INTCS_VECT(n, vect) INTC_VECT((n), INTCS_VECT_BASE + (vect)) +#define intcs_evt2irq(evt) evt2irq(INTCS_VECT_BASE + (evt)) + #endif /* __ASM_MACH_IRQS_H */ -- GitLab From 0e9131a3fa68cdc114e4c4c6270b1d6a38242c0d Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 11 Mar 2010 06:52:33 +0000 Subject: [PATCH 0026/5312] ARM: mach-shmobile: sh7367 INTCS support Add support for the sh7367 INTCS interrupt controller. INTCS is the interrupt controller for the sh7367 SuperH processor core. It is tied into the INTCA interrupt controller which interfaces to the ARM processor. INTCS support is implemented using a new INTC table together with a chained interrupt handler that ties into the already supported INTCA controller. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/intc-sh7367.c | 172 ++++++++++++++++++++++++++- 1 file changed, 171 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-shmobile/intc-sh7367.c b/arch/arm/mach-shmobile/intc-sh7367.c index 5ff70cadfc32..c13063ff311d 100644 --- a/arch/arm/mach-shmobile/intc-sh7367.c +++ b/arch/arm/mach-shmobile/intc-sh7367.c @@ -263,8 +263,178 @@ static struct intc_desc intca_desc __initdata = { intca_sense_registers, intca_ack_registers), }; +enum { + UNUSED_INTCS = 0, + + INTCS, + + /* interrupt sources INTCS */ + VIO2_VEU0, VIO2_VEU1, VIO2_VEU2, VIO2_VEU3, + VIO3_VOU, + RTDMAC_1_DEI0, RTDMAC_1_DEI1, RTDMAC_1_DEI2, RTDMAC_1_DEI3, + VIO1_CEU, VIO1_BEU0, VIO1_BEU1, VIO1_BEU2, + VPU, + SGX530, + _2DDMAC_2DDM0, _2DDMAC_2DDM1, _2DDMAC_2DDM2, _2DDMAC_2DDM3, + IIC2_ALI2, IIC2_TACKI2, IIC2_WAITI2, IIC2_DTEI2, + IPMMU_IPMMUB, IPMMU_IPMMUS, + RTDMAC_2_DEI4, RTDMAC_2_DEI5, RTDMAC_2_DADERR, + MSIOF, + IIC0_ALI0, IIC0_TACKI0, IIC0_WAITI0, IIC0_DTEI0, + TMU_TUNI0, TMU_TUNI1, TMU_TUNI2, + CMT, + TSIF, + IPMMUI, + MVI3, + ICB, + PEP, + ASA, + BEM, + VE2HO, + HQE, + JPEG, + LCDC, + + /* interrupt groups INTCS */ + _2DDMAC, RTDMAC_1, RTDMAC_2, VEU, BEU, IIC0, IPMMU, IIC2, +}; + +static struct intc_vect intcs_vectors[] = { + INTCS_VECT(VIO2_VEU0, 0x700), INTCS_VECT(VIO2_VEU1, 0x720), + INTCS_VECT(VIO2_VEU2, 0x740), INTCS_VECT(VIO2_VEU3, 0x760), + INTCS_VECT(VIO3_VOU, 0x780), + INTCS_VECT(RTDMAC_1_DEI0, 0x800), INTCS_VECT(RTDMAC_1_DEI1, 0x820), + INTCS_VECT(RTDMAC_1_DEI2, 0x840), INTCS_VECT(RTDMAC_1_DEI3, 0x860), + INTCS_VECT(VIO1_CEU, 0x880), INTCS_VECT(VIO1_BEU0, 0x8a0), + INTCS_VECT(VIO1_BEU1, 0x8c0), INTCS_VECT(VIO1_BEU2, 0x8e0), + INTCS_VECT(VPU, 0x980), + INTCS_VECT(SGX530, 0x9e0), + INTCS_VECT(_2DDMAC_2DDM0, 0xa00), INTCS_VECT(_2DDMAC_2DDM1, 0xa20), + INTCS_VECT(_2DDMAC_2DDM2, 0xa40), INTCS_VECT(_2DDMAC_2DDM3, 0xa60), + INTCS_VECT(IIC2_ALI2, 0xa80), INTCS_VECT(IIC2_TACKI2, 0xaa0), + INTCS_VECT(IIC2_WAITI2, 0xac0), INTCS_VECT(IIC2_DTEI2, 0xae0), + INTCS_VECT(IPMMU_IPMMUB, 0xb20), INTCS_VECT(IPMMU_IPMMUS, 0xb60), + INTCS_VECT(RTDMAC_2_DEI4, 0xb80), INTCS_VECT(RTDMAC_2_DEI5, 0xba0), + INTCS_VECT(RTDMAC_2_DADERR, 0xbc0), + INTCS_VECT(MSIOF, 0xd20), + INTCS_VECT(IIC0_ALI0, 0xe00), INTCS_VECT(IIC0_TACKI0, 0xe20), + INTCS_VECT(IIC0_WAITI0, 0xe40), INTCS_VECT(IIC0_DTEI0, 0xe60), + INTCS_VECT(TMU_TUNI0, 0xe80), INTCS_VECT(TMU_TUNI1, 0xea0), + INTCS_VECT(TMU_TUNI2, 0xec0), + INTCS_VECT(CMT, 0xf00), + INTCS_VECT(TSIF, 0xf20), + INTCS_VECT(IPMMUI, 0xf60), + INTCS_VECT(MVI3, 0x420), + INTCS_VECT(ICB, 0x480), + INTCS_VECT(PEP, 0x4a0), + INTCS_VECT(ASA, 0x4c0), + INTCS_VECT(BEM, 0x4e0), + INTCS_VECT(VE2HO, 0x520), + INTCS_VECT(HQE, 0x540), + INTCS_VECT(JPEG, 0x560), + INTCS_VECT(LCDC, 0x580), + + INTC_VECT(INTCS, 0xf80), +}; + +static struct intc_group intcs_groups[] __initdata = { + INTC_GROUP(_2DDMAC, _2DDMAC_2DDM0, _2DDMAC_2DDM1, + _2DDMAC_2DDM2, _2DDMAC_2DDM3), + INTC_GROUP(RTDMAC_1, RTDMAC_1_DEI0, RTDMAC_1_DEI1, + RTDMAC_1_DEI2, RTDMAC_1_DEI3), + INTC_GROUP(RTDMAC_2, RTDMAC_2_DEI4, RTDMAC_2_DEI5, RTDMAC_2_DADERR), + INTC_GROUP(VEU, VIO2_VEU0, VIO2_VEU1, VIO2_VEU2, VIO2_VEU3), + INTC_GROUP(BEU, VIO1_BEU0, VIO1_BEU1, VIO1_BEU2), + INTC_GROUP(IIC0, IIC0_ALI0, IIC0_TACKI0, IIC0_WAITI0, IIC0_DTEI0), + INTC_GROUP(IPMMU, IPMMU_IPMMUS, IPMMU_IPMMUB), + INTC_GROUP(IIC2, IIC2_ALI2, IIC2_TACKI2, IIC2_WAITI2, IIC2_DTEI2), +}; + +static struct intc_mask_reg intcs_mask_registers[] = { + { 0xffd20184, 0xffd201c4, 8, /* IMR1SA / IMCR1SA */ + { VIO1_BEU2, VIO1_BEU1, VIO1_BEU0, VIO1_CEU, + VIO2_VEU3, VIO2_VEU2, VIO2_VEU1, VIO2_VEU0 } }, + { 0xffd20188, 0xffd201c8, 8, /* IMR2SA / IMCR2SA */ + { VIO3_VOU, 0, VE2HO, VPU, + 0, 0, 0, 0 } }, + { 0xffd2018c, 0xffd201cc, 8, /* IMR3SA / IMCR3SA */ + { _2DDMAC_2DDM3, _2DDMAC_2DDM2, _2DDMAC_2DDM1, _2DDMAC_2DDM0, + BEM, ASA, PEP, ICB } }, + { 0xffd20190, 0xffd201d0, 8, /* IMR4SA / IMCR4SA */ + { 0, 0, MVI3, 0, + JPEG, HQE, 0, LCDC } }, + { 0xffd20194, 0xffd201d4, 8, /* IMR5SA / IMCR5SA */ + { 0, RTDMAC_2_DADERR, RTDMAC_2_DEI5, RTDMAC_2_DEI4, + RTDMAC_1_DEI3, RTDMAC_1_DEI2, RTDMAC_1_DEI1, RTDMAC_1_DEI0 } }, + { 0xffd20198, 0xffd201d8, 8, /* IMR6SA / IMCR6SA */ + { 0, 0, MSIOF, 0, + SGX530, 0, 0, 0 } }, + { 0xffd2019c, 0xffd201dc, 8, /* IMR7SA / IMCR7SA */ + { 0, TMU_TUNI2, TMU_TUNI1, TMU_TUNI0, + 0, 0, 0, 0 } }, + { 0xffd201a4, 0xffd201e4, 8, /* IMR9SA / IMCR9SA */ + { 0, 0, 0, CMT, + IIC2_DTEI2, IIC2_WAITI2, IIC2_TACKI2, IIC2_ALI2 } }, + { 0xffd201a8, 0xffd201e8, 8, /* IMR10SA / IMCR10SA */ + { IPMMU_IPMMUS, 0, IPMMU_IPMMUB, 0, + 0, 0, 0, 0 } }, + { 0xffd201ac, 0xffd201ec, 8, /* IMR11SA / IMCR11SA */ + { IIC0_DTEI0, IIC0_WAITI0, IIC0_TACKI0, IIC0_ALI0, + 0, 0, IPMMUI, TSIF } }, + { 0xffd20104, 0, 16, /* INTAMASK */ + { 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, INTCS } }, +}; + +/* Priority is needed for INTCA to receive the INTCS interrupt */ +static struct intc_prio_reg intcs_prio_registers[] = { + { 0xffd20000, 0, 16, 4, /* IPRAS */ { 0, MVI3, _2DDMAC, ICB } }, + { 0xffd20004, 0, 16, 4, /* IPRBS */ { JPEG, LCDC, 0, 0 } }, + { 0xffd20008, 0, 16, 4, /* IPRCS */ { BBIF2, 0, 0, 0 } }, + { 0xffd20010, 0, 16, 4, /* IPRES */ { RTDMAC_1, VIO1_CEU, 0, VPU } }, + { 0xffd20014, 0, 16, 4, /* IPRFS */ { 0, RTDMAC_2, 0, CMT } }, + { 0xffd20018, 0, 16, 4, /* IPRGS */ { TMU_TUNI0, TMU_TUNI1, + TMU_TUNI2, 0 } }, + { 0xffd2001c, 0, 16, 4, /* IPRHS */ { 0, VIO3_VOU, VEU, BEU } }, + { 0xffd20020, 0, 16, 4, /* IPRIS */ { 0, MSIOF, TSIF, IIC0 } }, + { 0xffd20024, 0, 16, 4, /* IPRJS */ { 0, SGX530, 0, 0 } }, + { 0xffd20028, 0, 16, 4, /* IPRKS */ { BEM, ASA, IPMMUI, PEP } }, + { 0xffd2002c, 0, 16, 4, /* IPRLS */ { IPMMU, 0, VE2HO, HQE } }, + { 0xffd20030, 0, 16, 4, /* IPRMS */ { IIC2, 0, 0, 0 } }, +}; + +static struct resource intcs_resources[] __initdata = { + [0] = { + .start = 0xffd20000, + .end = 0xffd2ffff, + .flags = IORESOURCE_MEM, + } +}; + +static struct intc_desc intcs_desc __initdata = { + .name = "sh7367-intcs", + .resource = intcs_resources, + .num_resources = ARRAY_SIZE(intcs_resources), + .hw = INTC_HW_DESC(intcs_vectors, intcs_groups, intcs_mask_registers, + intcs_prio_registers, NULL, NULL), +}; + +static void intcs_demux(unsigned int irq, struct irq_desc *desc) +{ + void __iomem *reg = (void *)get_irq_data(irq); + unsigned int evtcodeas = ioread32(reg); + + generic_handle_irq(intcs_evt2irq(evtcodeas)); +} + void __init sh7367_init_irq(void) { - /* INTCA */ + void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE); + register_intc_controller(&intca_desc); + register_intc_controller(&intcs_desc); + + /* demux using INTEVTSA */ + set_irq_data(evt2irq(0xf80), (void *)intevtsa); + set_irq_chained_handler(evt2irq(0xf80), intcs_demux); } -- GitLab From 7da5c86883fde778fabb1820c521410e8a678132 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 29 Mar 2010 07:58:13 +0000 Subject: [PATCH 0027/5312] ARM: mach-shmobile: intc-sh7377: Add INTCS support Add support for the sh7377 INTCS interrupt controller. INTCS is the interrupt controller for the sh7377 SuperH processor core. It is tied into the INTCA interrupt controller which interfaces to the ARM processor. INTCS support is implemented using a new INTC table together with a chained interrupt handler that ties into the already supported INTCA controller. Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/intc-sh7377.c | 294 +++++++++++++++++++++++++++ 1 file changed, 294 insertions(+) diff --git a/arch/arm/mach-shmobile/intc-sh7377.c b/arch/arm/mach-shmobile/intc-sh7377.c index 5c781e2d1897..deac5cfe3524 100644 --- a/arch/arm/mach-shmobile/intc-sh7377.c +++ b/arch/arm/mach-shmobile/intc-sh7377.c @@ -346,7 +346,301 @@ static struct intc_desc intca_desc __initdata = { intca_sense_registers, intca_ack_registers), }; +/* this macro ignore entry which is also in INTCA */ +#define __IGNORE(a...) +#define __IGNORE0(a...) 0 + +enum { + UNUSED_INTCS = 0, + + INTCS, + + /* interrupt sources INTCS */ + VEU_VEU0, VEU_VEU1, VEU_VEU2, VEU_VEU3, + RTDMAC1_1_DEI0, RTDMAC1_1_DEI1, RTDMAC1_1_DEI2, RTDMAC1_1_DEI3, + CEU, + BEU_BEU0, BEU_BEU1, BEU_BEU2, + __IGNORE(MFI) + __IGNORE(BBIF2) + VPU, + TSIF1, + __IGNORE(SGX540) + _2DDMAC, + IIC2_ALI2, IIC2_TACKI2, IIC2_WAITI2, IIC2_DTEI2, + IPMMU_IPMMUR, IPMMU_IPMMUR2, + RTDMAC1_2_DEI4, RTDMAC1_2_DEI5, RTDMAC1_2_DADERR, + __IGNORE(KEYSC) + __IGNORE(TTI20) + __IGNORE(MSIOF) + IIC0_ALI0, IIC0_TACKI0, IIC0_WAITI0, IIC0_DTEI0, + TMU_TUNI0, TMU_TUNI1, TMU_TUNI2, + CMT0, + TSIF0, + __IGNORE(CMT2) + LMB, + __IGNORE(MSUG) + __IGNORE(MSU_MSU, MSU_MSU2) + __IGNORE(CTI) + MVI3, + __IGNORE(RWDT0) + __IGNORE(RWDT1) + ICB, + PEP, + ASA, + __IGNORE(_2DG) + HQE, + JPU, + LCDC0, + __IGNORE(LCRC) + RTDMAC2_1_DEI0, RTDMAC2_1_DEI1, RTDMAC2_1_DEI2, RTDMAC2_1_DEI3, + RTDMAC2_2_DEI4, RTDMAC2_2_DEI5, RTDMAC2_2_DADERR, + FRC, + LCDC1, + CSIRX, + DSITX_DSITX0, DSITX_DSITX1, + __IGNORE(SPU2_SPU0, SPU2_SPU1) + __IGNORE(FSI) + __IGNORE(FMSI) + __IGNORE(SCUV) + TMU1_TUNI10, TMU1_TUNI11, TMU1_TUNI12, + TSIF2, + CMT4, + __IGNORE(MFIS2) + CPORTS2R, + + /* interrupt groups INTCS */ + RTDMAC1_1, RTDMAC1_2, VEU, BEU, IIC0, __IGNORE(MSU) IPMMU, + IIC2, RTDMAC2_1, RTDMAC2_2, DSITX, __IGNORE(SPU2) TMU1, +}; + +#define INTCS_INTVECT 0x0F80 +static struct intc_vect intcs_vectors[] __initdata = { + INTCS_VECT(VEU_VEU0, 0x0700), INTCS_VECT(VEU_VEU1, 0x0720), + INTCS_VECT(VEU_VEU2, 0x0740), INTCS_VECT(VEU_VEU3, 0x0760), + INTCS_VECT(RTDMAC1_1_DEI0, 0x0800), INTCS_VECT(RTDMAC1_1_DEI1, 0x0820), + INTCS_VECT(RTDMAC1_1_DEI2, 0x0840), INTCS_VECT(RTDMAC1_1_DEI3, 0x0860), + INTCS_VECT(CEU, 0x0880), + INTCS_VECT(BEU_BEU0, 0x08A0), + INTCS_VECT(BEU_BEU1, 0x08C0), + INTCS_VECT(BEU_BEU2, 0x08E0), + __IGNORE(INTCS_VECT(MFI, 0x0900)) + __IGNORE(INTCS_VECT(BBIF2, 0x0960)) + INTCS_VECT(VPU, 0x0980), + INTCS_VECT(TSIF1, 0x09A0), + __IGNORE(INTCS_VECT(SGX540, 0x09E0)) + INTCS_VECT(_2DDMAC, 0x0A00), + INTCS_VECT(IIC2_ALI2, 0x0A80), INTCS_VECT(IIC2_TACKI2, 0x0AA0), + INTCS_VECT(IIC2_WAITI2, 0x0AC0), INTCS_VECT(IIC2_DTEI2, 0x0AE0), + INTCS_VECT(IPMMU_IPMMUR, 0x0B00), INTCS_VECT(IPMMU_IPMMUR2, 0x0B20), + INTCS_VECT(RTDMAC1_2_DEI4, 0x0B80), + INTCS_VECT(RTDMAC1_2_DEI5, 0x0BA0), + INTCS_VECT(RTDMAC1_2_DADERR, 0x0BC0), + __IGNORE(INTCS_VECT(KEYSC 0x0BE0)) + __IGNORE(INTCS_VECT(TTI20, 0x0C80)) + __IGNORE(INTCS_VECT(MSIOF, 0x0D20)) + INTCS_VECT(IIC0_ALI0, 0x0E00), INTCS_VECT(IIC0_TACKI0, 0x0E20), + INTCS_VECT(IIC0_WAITI0, 0x0E40), INTCS_VECT(IIC0_DTEI0, 0x0E60), + INTCS_VECT(TMU_TUNI0, 0x0E80), + INTCS_VECT(TMU_TUNI1, 0x0EA0), + INTCS_VECT(TMU_TUNI2, 0x0EC0), + INTCS_VECT(CMT0, 0x0F00), + INTCS_VECT(TSIF0, 0x0F20), + __IGNORE(INTCS_VECT(CMT2, 0x0F40)) + INTCS_VECT(LMB, 0x0F60), + __IGNORE(INTCS_VECT(MSUG, 0x0F80)) + __IGNORE(INTCS_VECT(MSU_MSU, 0x0FA0)) + __IGNORE(INTCS_VECT(MSU_MSU2, 0x0FC0)) + __IGNORE(INTCS_VECT(CTI, 0x0400)) + INTCS_VECT(MVI3, 0x0420), + __IGNORE(INTCS_VECT(RWDT0, 0x0440)) + __IGNORE(INTCS_VECT(RWDT1, 0x0460)) + INTCS_VECT(ICB, 0x0480), + INTCS_VECT(PEP, 0x04A0), + INTCS_VECT(ASA, 0x04C0), + __IGNORE(INTCS_VECT(_2DG, 0x04E0)) + INTCS_VECT(HQE, 0x0540), + INTCS_VECT(JPU, 0x0560), + INTCS_VECT(LCDC0, 0x0580), + __IGNORE(INTCS_VECT(LCRC, 0x05A0)) + INTCS_VECT(RTDMAC2_1_DEI0, 0x1300), INTCS_VECT(RTDMAC2_1_DEI1, 0x1320), + INTCS_VECT(RTDMAC2_1_DEI2, 0x1340), INTCS_VECT(RTDMAC2_1_DEI3, 0x1360), + INTCS_VECT(RTDMAC2_2_DEI4, 0x1380), INTCS_VECT(RTDMAC2_2_DEI5, 0x13A0), + INTCS_VECT(RTDMAC2_2_DADERR, 0x13C0), + INTCS_VECT(FRC, 0x1700), + INTCS_VECT(LCDC1, 0x1780), + INTCS_VECT(CSIRX, 0x17A0), + INTCS_VECT(DSITX_DSITX0, 0x17C0), INTCS_VECT(DSITX_DSITX1, 0x17E0), + __IGNORE(INTCS_VECT(SPU2_SPU0, 0x1800)) + __IGNORE(INTCS_VECT(SPU2_SPU1, 0x1820)) + __IGNORE(INTCS_VECT(FSI, 0x1840)) + __IGNORE(INTCS_VECT(FMSI, 0x1860)) + __IGNORE(INTCS_VECT(SCUV, 0x1880)) + INTCS_VECT(TMU1_TUNI10, 0x1900), INTCS_VECT(TMU1_TUNI11, 0x1920), + INTCS_VECT(TMU1_TUNI12, 0x1940), + INTCS_VECT(TSIF2, 0x1960), + INTCS_VECT(CMT4, 0x1980), + __IGNORE(INTCS_VECT(MFIS2, 0x1A00)) + INTCS_VECT(CPORTS2R, 0x1A20), + + INTC_VECT(INTCS, INTCS_INTVECT), +}; + +static struct intc_group intcs_groups[] __initdata = { + INTC_GROUP(RTDMAC1_1, + RTDMAC1_1_DEI0, RTDMAC1_1_DEI1, + RTDMAC1_1_DEI2, RTDMAC1_1_DEI3), + INTC_GROUP(RTDMAC1_2, + RTDMAC1_2_DEI4, RTDMAC1_2_DEI5, RTDMAC1_2_DADERR), + INTC_GROUP(VEU, VEU_VEU0, VEU_VEU1, VEU_VEU2, VEU_VEU3), + INTC_GROUP(BEU, BEU_BEU0, BEU_BEU1, BEU_BEU2), + INTC_GROUP(IIC0, IIC0_ALI0, IIC0_TACKI0, IIC0_WAITI0, IIC0_DTEI0), + __IGNORE(INTC_GROUP(MSU, MSU_MSU, MSU_MSU2)) + INTC_GROUP(IPMMU, IPMMU_IPMMUR, IPMMU_IPMMUR2), + INTC_GROUP(IIC2, IIC2_ALI2, IIC2_TACKI2, IIC2_WAITI2, IIC2_DTEI2), + INTC_GROUP(RTDMAC2_1, + RTDMAC2_1_DEI0, RTDMAC2_1_DEI1, + RTDMAC2_1_DEI2, RTDMAC2_1_DEI3), + INTC_GROUP(RTDMAC2_2, RTDMAC2_2_DEI4, RTDMAC2_2_DEI5, RTDMAC2_2_DADERR), + INTC_GROUP(DSITX, DSITX_DSITX0, DSITX_DSITX1), + __IGNORE(INTC_GROUP(SPU2, SPU2_SPU0, SPU2_SPU1)) + INTC_GROUP(TMU1, TMU1_TUNI10, TMU1_TUNI11, TMU1_TUNI12), +}; + +static struct intc_mask_reg intcs_mask_registers[] __initdata = { + { 0xE6940184, 0xE69401C4, 8, /* IMR1AS / IMCR1AS */ + { BEU_BEU2, BEU_BEU1, BEU_BEU0, CEU, + VEU_VEU3, VEU_VEU2, VEU_VEU1, VEU_VEU0 } }, + { 0xE6940188, 0xE69401C8, 8, /* IMR2AS / IMCR2AS */ + { 0, 0, 0, VPU, + __IGNORE0(BBIF2), 0, 0, __IGNORE0(MFI) } }, + { 0xE694018C, 0xE69401CC, 8, /* IMR3AS / IMCR3AS */ + { 0, 0, 0, _2DDMAC, + __IGNORE0(_2DG), ASA, PEP, ICB } }, + { 0xE6940190, 0xE69401D0, 8, /* IMR4AS / IMCR4AS */ + { 0, 0, MVI3, __IGNORE0(CTI), + JPU, HQE, __IGNORE0(LCRC), LCDC0 } }, + { 0xE6940194, 0xE69401D4, 8, /* IMR5AS / IMCR5AS */ + { __IGNORE0(KEYSC), RTDMAC1_2_DADERR, RTDMAC1_2_DEI5, RTDMAC1_2_DEI4, + RTDMAC1_1_DEI3, RTDMAC1_1_DEI2, RTDMAC1_1_DEI1, RTDMAC1_1_DEI0 } }, + __IGNORE({ 0xE6940198, 0xE69401D8, 8, /* IMR6AS / IMCR6AS */ + { 0, 0, MSIOF, 0, + SGX540, 0, TTI20, 0 } }) + { 0xE694019C, 0xE69401DC, 8, /* IMR7AS / IMCR7AS */ + { 0, TMU_TUNI2, TMU_TUNI1, TMU_TUNI0, + 0, 0, 0, 0 } }, + __IGNORE({ 0xE69401A0, 0xE69401E0, 8, /* IMR8AS / IMCR8AS */ + { 0, 0, 0, 0, + 0, MSU_MSU, MSU_MSU2, MSUG } }) + { 0xE69401A4, 0xE69401E4, 8, /* IMR9AS / IMCR9AS */ + { __IGNORE0(RWDT1), __IGNORE0(RWDT0), __IGNORE0(CMT2), CMT0, + IIC2_DTEI2, IIC2_WAITI2, IIC2_TACKI2, IIC2_ALI2 } }, + { 0xE69401A8, 0xE69401E8, 8, /* IMR10AS / IMCR10AS */ + { 0, 0, IPMMU_IPMMUR, IPMMU_IPMMUR2, + 0, 0, 0, 0 } }, + { 0xE69401AC, 0xE69401EC, 8, /* IMR11AS / IMCR11AS */ + { IIC0_DTEI0, IIC0_WAITI0, IIC0_TACKI0, IIC0_ALI0, + 0, TSIF1, LMB, TSIF0 } }, + { 0xE6950180, 0xE69501C0, 8, /* IMR0AS3 / IMCR0AS3 */ + { RTDMAC2_1_DEI0, RTDMAC2_1_DEI1, RTDMAC2_1_DEI2, RTDMAC2_1_DEI3, + RTDMAC2_2_DEI4, RTDMAC2_2_DEI5, RTDMAC2_2_DADERR, 0 } }, + { 0xE6950190, 0xE69501D0, 8, /* IMR4AS3 / IMCR4AS3 */ + { FRC, 0, 0, 0, + LCDC1, CSIRX, DSITX_DSITX0, DSITX_DSITX1 } }, + __IGNORE({ 0xE6950194, 0xE69501D4, 8, /* IMR5AS3 / IMCR5AS3 */ + {SPU2_SPU0, SPU2_SPU1, FSI, FMSI, + SCUV, 0, 0, 0 } }) + { 0xE6950198, 0xE69501D8, 8, /* IMR6AS3 / IMCR6AS3 */ + { TMU1_TUNI10, TMU1_TUNI11, TMU1_TUNI12, TSIF2, + CMT4, 0, 0, 0 } }, + { 0xE695019C, 0xE69501DC, 8, /* IMR7AS3 / IMCR7AS3 */ + { __IGNORE0(MFIS2), CPORTS2R, 0, 0, + 0, 0, 0, 0 } }, + { 0xFFD20104, 0, 16, /* INTAMASK */ + { 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, INTCS } } +}; + +static struct intc_prio_reg intcs_prio_registers[] __initdata = { + /* IPRAS */ + { 0xFFD20000, 0, 16, 4, { __IGNORE0(CTI), MVI3, _2DDMAC, ICB } }, + /* IPRBS */ + { 0xFFD20004, 0, 16, 4, { JPU, LCDC0, 0, __IGNORE0(LCRC) } }, + /* IPRCS */ + __IGNORE({ 0xFFD20008, 0, 16, 4, { BBIF2, 0, 0, 0 } }) + /* IPRES */ + { 0xFFD20010, 0, 16, 4, { RTDMAC1_1, CEU, __IGNORE0(MFI), VPU } }, + /* IPRFS */ + { 0xFFD20014, 0, 16, 4, + { __IGNORE0(KEYSC), RTDMAC1_2, __IGNORE0(CMT2), CMT0 } }, + /* IPRGS */ + { 0xFFD20018, 0, 16, 4, { TMU_TUNI0, TMU_TUNI1, TMU_TUNI2, TSIF1 } }, + /* IPRHS */ + { 0xFFD2001C, 0, 16, 4, { __IGNORE0(TTI20), 0, VEU, BEU } }, + /* IPRIS */ + { 0xFFD20020, 0, 16, 4, { 0, __IGNORE0(MSIOF), TSIF0, IIC0 } }, + /* IPRJS */ + __IGNORE({ 0xFFD20024, 0, 16, 4, { 0, SGX540, MSUG, MSU } }) + /* IPRKS */ + { 0xFFD20028, 0, 16, 4, { __IGNORE0(_2DG), ASA, LMB, PEP } }, + /* IPRLS */ + { 0xFFD2002C, 0, 16, 4, { IPMMU, 0, 0, HQE } }, + /* IPRMS */ + { 0xFFD20030, 0, 16, 4, + { IIC2, 0, __IGNORE0(RWDT1), __IGNORE0(RWDT0) } }, + /* IPRAS3 */ + { 0xFFD50000, 0, 16, 4, { RTDMAC2_1, 0, 0, 0 } }, + /* IPRBS3 */ + { 0xFFD50004, 0, 16, 4, { RTDMAC2_2, 0, 0, 0 } }, + /* IPRIS3 */ + { 0xFFD50020, 0, 16, 4, { FRC, 0, 0, 0 } }, + /* IPRJS3 */ + { 0xFFD50024, 0, 16, 4, { LCDC1, CSIRX, DSITX, 0 } }, + /* IPRKS3 */ + __IGNORE({ 0xFFD50028, 0, 16, 4, { SPU2, 0, FSI, FMSI } }) + /* IPRLS3 */ + __IGNORE({ 0xFFD5002C, 0, 16, 4, { SCUV, 0, 0, 0 } }) + /* IPRMS3 */ + { 0xFFD50030, 0, 16, 4, { TMU1, 0, 0, TSIF2 } }, + /* IPRNS3 */ + { 0xFFD50034, 0, 16, 4, { CMT4, 0, 0, 0 } }, + /* IPROS3 */ + { 0xFFD50038, 0, 16, 4, { __IGNORE0(MFIS2), CPORTS2R, 0, 0 } }, +}; + +static struct resource intcs_resources[] __initdata = { + [0] = { + .start = 0xffd20000, + .end = 0xffd500ff, + .flags = IORESOURCE_MEM, + } +}; + +static struct intc_desc intcs_desc __initdata = { + .name = "sh7377-intcs", + .resource = intcs_resources, + .num_resources = ARRAY_SIZE(intcs_resources), + .hw = INTC_HW_DESC(intcs_vectors, intcs_groups, + intcs_mask_registers, intcs_prio_registers, + NULL, NULL), +}; + +static void intcs_demux(unsigned int irq, struct irq_desc *desc) +{ + void __iomem *reg = (void *)get_irq_data(irq); + unsigned int evtcodeas = ioread32(reg); + + generic_handle_irq(intcs_evt2irq(evtcodeas)); +} + +#define INTEVTSA 0xFFD20100 void __init sh7377_init_irq(void) { + void __iomem *intevtsa = ioremap_nocache(INTEVTSA, PAGE_SIZE); + register_intc_controller(&intca_desc); + register_intc_controller(&intcs_desc); + + /* demux using INTEVTSA */ + set_irq_data(evt2irq(INTCS_INTVECT), (void *)intevtsa); + set_irq_chained_handler(evt2irq(INTCS_INTVECT), intcs_demux); } -- GitLab From 4eea423a4567937dc5e0abdc72bd21b546180459 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 29 Mar 2010 06:31:46 +0000 Subject: [PATCH 0028/5312] ARM: mach-shmobile: Add missing __initdata on intcs sh7367/sh7377 Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/intc-sh7367.c | 6 +++--- arch/arm/mach-shmobile/intc-sh7377.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-shmobile/intc-sh7367.c b/arch/arm/mach-shmobile/intc-sh7367.c index c13063ff311d..1a20c489b20d 100644 --- a/arch/arm/mach-shmobile/intc-sh7367.c +++ b/arch/arm/mach-shmobile/intc-sh7367.c @@ -75,7 +75,7 @@ enum { ETM11, ARM11, USBHS, FLCTL, IIC1 }; -static struct intc_vect intca_vectors[] = { +static struct intc_vect intca_vectors[] __initdata = { INTC_VECT(IRQ0A, 0x0200), INTC_VECT(IRQ1A, 0x0220), INTC_VECT(IRQ2A, 0x0240), INTC_VECT(IRQ3A, 0x0260), INTC_VECT(IRQ4A, 0x0280), INTC_VECT(IRQ5A, 0x02a0), @@ -162,7 +162,7 @@ static struct intc_group intca_groups[] __initdata = { INTC_GROUP(IIC1, IIC1_ALI1, IIC1_TACKI1, IIC1_WAITI1, IIC1_DTEI1), }; -static struct intc_mask_reg intca_mask_registers[] = { +static struct intc_mask_reg intca_mask_registers[] __initdata = { { 0xe6900040, 0xe6900060, 8, /* INTMSK00A / INTMSKCLR00A */ { IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A } }, { 0xe6900044, 0xe6900064, 8, /* INTMSK10A / INTMSKCLR10A */ @@ -211,7 +211,7 @@ static struct intc_mask_reg intca_mask_registers[] = { MISTY, CMT3, RWDT1, RWDT0 } }, }; -static struct intc_prio_reg intca_prio_registers[] = { +static struct intc_prio_reg intca_prio_registers[] __initdata = { { 0xe6900010, 0, 32, 4, /* INTPRI00A */ { IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A } }, { 0xe6900014, 0, 32, 4, /* INTPRI10A */ diff --git a/arch/arm/mach-shmobile/intc-sh7377.c b/arch/arm/mach-shmobile/intc-sh7377.c index deac5cfe3524..2cdeb8ccd821 100644 --- a/arch/arm/mach-shmobile/intc-sh7377.c +++ b/arch/arm/mach-shmobile/intc-sh7377.c @@ -90,7 +90,7 @@ enum { ICUSB, ICUDMC }; -static struct intc_vect intca_vectors[] = { +static struct intc_vect intca_vectors[] __initdata = { INTC_VECT(IRQ0A, 0x0200), INTC_VECT(IRQ1A, 0x0220), INTC_VECT(IRQ2A, 0x0240), INTC_VECT(IRQ3A, 0x0260), INTC_VECT(IRQ4A, 0x0280), INTC_VECT(IRQ5A, 0x02a0), @@ -202,7 +202,7 @@ static struct intc_group intca_groups[] __initdata = { INTC_GROUP(ICUDMC, ICUDMC_ICUDMC1, ICUDMC_ICUDMC2), }; -static struct intc_mask_reg intca_mask_registers[] = { +static struct intc_mask_reg intca_mask_registers[] __initdata = { { 0xe6900040, 0xe6900060, 8, /* INTMSK00A / INTMSKCLR00A */ { IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A } }, { 0xe6900044, 0xe6900064, 8, /* INTMSK10A / INTMSKCLR10A */ @@ -272,7 +272,7 @@ static struct intc_mask_reg intca_mask_registers[] = { SCIFA6, 0, 0, 0 } }, }; -static struct intc_prio_reg intca_prio_registers[] = { +static struct intc_prio_reg intca_prio_registers[] __initdata = { { 0xe6900010, 0, 32, 4, /* INTPRI00A */ { IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A } }, { 0xe6900014, 0, 32, 4, /* INTPRI10A */ -- GitLab From 819ee86796ae263cd76dd734085dab70d1250cdb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 29 Mar 2010 06:31:36 +0000 Subject: [PATCH 0029/5312] ARM: mach-shmobile: Add SDHI support This patch add SDHI support for G4 board. Current gpio frame work doesn't have the method to control only pull-up/down/free. So, it have special gpio_pull_up function for SDHI. It is quick hack, so this function should be replaced by correct gpio frame work in future. Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-g4evm.c | 127 +++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/arch/arm/mach-shmobile/board-g4evm.c b/arch/arm/mach-shmobile/board-g4evm.c index 10673a90be52..33441d58cfa6 100644 --- a/arch/arm/mach-shmobile/board-g4evm.c +++ b/arch/arm/mach-shmobile/board-g4evm.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,31 @@ #include #include +/* + * SDHI + * + * SDHI0 : card detection is possible + * SDHI1 : card detection is impossible + * + * [G4-MAIN-BOARD] + * JP74 : short # DBG_2V8A for SDHI0 + * JP75 : NC # DBG_3V3A for SDHI0 + * JP76 : NC # DBG_3V3A_SD for SDHI0 + * JP77 : NC # 3V3A_SDIO for SDHI1 + * JP78 : short # DBG_2V8A for SDHI1 + * JP79 : NC # DBG_3V3A for SDHI1 + * JP80 : NC # DBG_3V3A_SD for SDHI1 + * + * [G4-CORE-BOARD] + * S32 : all off # to dissever from G3-CORE_DBG board + * S33 : all off # to dissever from G3-CORE_DBG board + * + * [G3-CORE_DBG-BOARD] + * S1 : all off # to dissever from G3-CORE_DBG board + * S3 : all off # to dissever from G3-CORE_DBG board + * S4 : all off # to dissever from G3-CORE_DBG board + */ + static struct mtd_partition nor_flash_partitions[] = { { .name = "loader", @@ -169,10 +195,53 @@ static struct platform_device keysc_device = { }, }; +/* SDHI */ +static struct resource sdhi0_resources[] = { + [0] = { + .name = "SDHI0", + .start = 0xe6d50000, + .end = 0xe6d501ff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 96, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device sdhi0_device = { + .name = "sh_mobile_sdhi", + .num_resources = ARRAY_SIZE(sdhi0_resources), + .resource = sdhi0_resources, + .id = 0, +}; + +static struct resource sdhi1_resources[] = { + [0] = { + .name = "SDHI1", + .start = 0xe6d60000, + .end = 0xe6d601ff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 100, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device sdhi1_device = { + .name = "sh_mobile_sdhi", + .num_resources = ARRAY_SIZE(sdhi1_resources), + .resource = sdhi1_resources, + .id = 1, +}; + static struct platform_device *g4evm_devices[] __initdata = { &nor_flash_device, &usb_host_device, &keysc_device, + &sdhi0_device, + &sdhi1_device, }; static struct map_desc g4evm_io_desc[] __initdata = { @@ -197,6 +266,36 @@ static void __init g4evm_map_io(void) shmobile_setup_console(); } +#define GPIO_SDHID0_D0 0xe60520fc +#define GPIO_SDHID0_D1 0xe60520fd +#define GPIO_SDHID0_D2 0xe60520fe +#define GPIO_SDHID0_D3 0xe60520ff +#define GPIO_SDHICMD0 0xe6052100 + +#define GPIO_SDHID1_D0 0xe6052103 +#define GPIO_SDHID1_D1 0xe6052104 +#define GPIO_SDHID1_D2 0xe6052105 +#define GPIO_SDHID1_D3 0xe6052106 +#define GPIO_SDHICMD1 0xe6052107 + +/* + * FIXME !! + * + * gpio_pull_up is quick_hack. + * + * current gpio frame work doesn't have + * the method to control only pull up/down/free. + * this function should be replaced by correct gpio function + */ +static void __init gpio_pull_up(u32 addr) +{ + u8 data = __raw_readb(addr); + + data &= 0x0F; + data |= 0xC0; + __raw_writeb(data, addr); +} + static void __init g4evm_init(void) { sh7377_pinmux_init(); @@ -253,6 +352,34 @@ static void __init g4evm_init(void) gpio_request(GPIO_FN_PORT71_KEYIN5_PU, NULL); gpio_request(GPIO_FN_PORT72_KEYIN6_PU, NULL); + /* SDHI0 */ + gpio_request(GPIO_FN_SDHICLK0, NULL); + gpio_request(GPIO_FN_SDHICD0, NULL); + gpio_request(GPIO_FN_SDHID0_0, NULL); + gpio_request(GPIO_FN_SDHID0_1, NULL); + gpio_request(GPIO_FN_SDHID0_2, NULL); + gpio_request(GPIO_FN_SDHID0_3, NULL); + gpio_request(GPIO_FN_SDHICMD0, NULL); + gpio_request(GPIO_FN_SDHIWP0, NULL); + gpio_pull_up(GPIO_SDHID0_D0); + gpio_pull_up(GPIO_SDHID0_D1); + gpio_pull_up(GPIO_SDHID0_D2); + gpio_pull_up(GPIO_SDHID0_D3); + gpio_pull_up(GPIO_SDHICMD0); + + /* SDHI1 */ + gpio_request(GPIO_FN_SDHICLK1, NULL); + gpio_request(GPIO_FN_SDHID1_0, NULL); + gpio_request(GPIO_FN_SDHID1_1, NULL); + gpio_request(GPIO_FN_SDHID1_2, NULL); + gpio_request(GPIO_FN_SDHID1_3, NULL); + gpio_request(GPIO_FN_SDHICMD1, NULL); + gpio_pull_up(GPIO_SDHID1_D0); + gpio_pull_up(GPIO_SDHID1_D1); + gpio_pull_up(GPIO_SDHID1_D2); + gpio_pull_up(GPIO_SDHID1_D3); + gpio_pull_up(GPIO_SDHICMD1); + sh7377_add_standard_devices(); platform_add_devices(g4evm_devices, ARRAY_SIZE(g4evm_devices)); -- GitLab From bbff48f5e9e14bea5183dd2c2408e3364f4c19e3 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 7 Apr 2010 17:17:22 +0900 Subject: [PATCH 0030/5312] MAINTAINERS: Add a patchwork entry for ARM/SH-Mobile. Since this overlaps with the sh list, we invariably end up using the same patchwork queue. Reference it explicitly to save people from having to do a reverse lookup from the SH entry. Signed-off-by: Paul Mundt --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 3d29fa389888..55727a60b3e8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -949,8 +949,9 @@ ARM/SHMOBILE ARM ARCHITECTURE M: Paul Mundt M: Magnus Damm L: linux-sh@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/genesis-2.6.git W: http://oss.renesas.com +Q: http://patchwork.kernel.org/project/linux-sh/list/ +T: git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/genesis-2.6.git S: Supported F: arch/arm/mach-shmobile/ F: drivers/sh/ -- GitLab From 0fff9ec116f2073553cd9b1d1afdc503cf10ef60 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 13 Apr 2010 06:16:25 +0000 Subject: [PATCH 0031/5312] ARM: mach-shmobile: intc-sh7372: modify wrong address Signed-off-by: Kuninori Morimoto Signed-off-by: Yoshihiro Shimoda Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/intc-sh7372.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c index 3ce9d9bd5899..cfba59f057ec 100644 --- a/arch/arm/mach-shmobile/intc-sh7372.c +++ b/arch/arm/mach-shmobile/intc-sh7372.c @@ -319,17 +319,17 @@ static struct intc_prio_reg intca_prio_registers[] __initdata = { { 0xe6950034, 0, 16, 4, /* IPRNA3 */ { AP_ARM2, 0, 0, 0 } }, { 0xe6950038, 0, 16, 4, /* IPROA3 */ { MFIS2, CPORTR2S, CMT14, CMT15 } }, - { 0xe694003c, 0, 16, 4, /* IPRPA3 */ { 0, 0, + { 0xe695003c, 0, 16, 4, /* IPRPA3 */ { 0, 0, MMC_MMC_ERR, MMC_MMC_NOR } }, - { 0xe6940040, 0, 16, 4, /* IPRQA3 */ { IIC4_ALI4, IIC4_TACKI4, + { 0xe6950040, 0, 16, 4, /* IPRQA3 */ { IIC4_ALI4, IIC4_TACKI4, IIC4_WAITI4, IIC4_DTEI4 } }, - { 0xe6940044, 0, 16, 4, /* IPRRA3 */ { IIC3_ALI3, IIC3_TACKI3, + { 0xe6950044, 0, 16, 4, /* IPRRA3 */ { IIC3_ALI3, IIC3_TACKI3, IIC3_WAITI3, IIC3_DTEI3 } }, - { 0xe6940048, 0, 16, 4, /* IPRSA3 */ { 0/*ERI*/, 0/*RXI*/, + { 0xe6950048, 0, 16, 4, /* IPRSA3 */ { 0/*ERI*/, 0/*RXI*/, 0/*TXI*/, 0/*TEI*/} }, - { 0xe694004c, 0, 16, 4, /* IPRTA3 */ { USB0_USB0I1, USB0_USB0I0, + { 0xe695004c, 0, 16, 4, /* IPRTA3 */ { USB0_USB0I1, USB0_USB0I0, USB1_USB1I1, USB1_USB1I0 } }, - { 0xe6940050, 0, 16, 4, /* IPRUA3 */ { USBHSDMAC1_USHDMI, 0, 0, 0 } }, + { 0xe6950050, 0, 16, 4, /* IPRUA3 */ { USBHSDMAC1_USHDMI, 0, 0, 0 } }, }; static struct intc_sense_reg intca_sense_registers[] __initdata = { -- GitLab From fb54d268329846aa13b2bc44a64d90e9b7131192 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 13 Apr 2010 06:16:32 +0000 Subject: [PATCH 0032/5312] ARM: mach-shmobile: ap4evb: Add USB host support Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ap4evb.c | 63 +++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index e7602945a6a5..d3b8ca5d4041 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -94,6 +95,15 @@ * OFF | KEY / IrDA / IRQ | IRQ | */ +/* + * USB + * + * J7 : 1-2 MAX3355E VBUS + * 2-3 DC 5.0V + * + * S39: bit2: off + */ + /* MTD */ static struct mtd_partition nor_flash_partitions[] = { { @@ -233,11 +243,53 @@ static struct platform_device sdhi0_device = { .id = 0, }; +/* USB1 */ +void usb1_host_port_power(int port, int power) +{ + if (!power) /* only power-on supported for now */ + return; + + /* set VBOUT/PWEN and EXTLP1 in DVSTCTR */ + __raw_writew(__raw_readw(0xE68B0008) | 0x600, 0xE68B0008); +} + +static struct r8a66597_platdata usb1_host_data = { + .on_chip = 1, + .port_power = usb1_host_port_power, +}; + +static struct resource usb1_host_resources[] = { + [0] = { + .name = "USBHS", + .start = 0xE68B0000, + .end = 0xE68B00E6 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 215, + .end = 215, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device usb1_host_device = { + .name = "r8a66597_hcd", + .id = 1, + .dev = { + .dma_mask = NULL, /* not use dma */ + .coherent_dma_mask = 0xffffffff, + .platform_data = &usb1_host_data, + }, + .num_resources = ARRAY_SIZE(usb1_host_resources), + .resource = usb1_host_resources, +}; + static struct platform_device *ap4evb_devices[] __initdata = { &nor_flash_device, &smc911x_device, &keysc_device, &sdhi0_device, + &usb1_host_device, }; /* TouchScreen (Needs SW3 set to OFF) */ @@ -351,6 +403,17 @@ static void __init ap4evb_init(void) i2c_register_board_info(1, i2c1_devices, ARRAY_SIZE(i2c1_devices)); + /* USB enable */ + gpio_request(GPIO_FN_VBUS0_1, NULL); + gpio_request(GPIO_FN_IDIN_1_18, NULL); + gpio_request(GPIO_FN_PWEN_1_115, NULL); + gpio_request(GPIO_FN_OVCN_1_114, NULL); + gpio_request(GPIO_FN_EXTLP_1, NULL); + gpio_request(GPIO_FN_OVCN2_1, NULL); + + /* setup USB phy */ + __raw_writew(0x8a0a, 0xE6058130); /* USBCR2 */ + sh7372_add_standard_devices(); platform_add_devices(ap4evb_devices, ARRAY_SIZE(ap4evb_devices)); -- GitLab From 91e080633221cadece6c1c37786ef8a18a9d1a5e Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Sat, 1 May 2010 22:55:21 -0700 Subject: [PATCH 0033/5312] xtensa: Fix FLUSH_DCACHE macro for some variants. Define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE also for processor configurations that don't have cache-aliasing. Signed-off-by: Chris Zankel --- arch/xtensa/include/asm/cacheflush.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/xtensa/include/asm/cacheflush.h b/arch/xtensa/include/asm/cacheflush.h index a508f2f73bd7..376cd9d5f455 100644 --- a/arch/xtensa/include/asm/cacheflush.h +++ b/arch/xtensa/include/asm/cacheflush.h @@ -115,6 +115,7 @@ extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned lon #define flush_cache_vmap(start,end) do { } while (0) #define flush_cache_vunmap(start,end) do { } while (0) +#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0 #define flush_dcache_page(page) do { } while (0) #define flush_cache_page(vma,addr,pfn) do { } while (0) -- GitLab From ed5010ea469baa8c0038d027c3b79a600da36811 Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Sat, 1 May 2010 23:00:07 -0700 Subject: [PATCH 0034/5312] xtensa: Fix linker script patch-up The Xtensa architecture requires to patch the generated linker script to insert precede certain sections with a .literal section. Ammend the sed script to fix-up only sequences that start with a '*': '*(.init.text)' -> '*(.init.literal .init.text)' Signed-off-by: Chris Zankel --- arch/xtensa/kernel/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/xtensa/kernel/Makefile b/arch/xtensa/kernel/Makefile index 6f56d95f2c1e..2d2728b3e862 100644 --- a/arch/xtensa/kernel/Makefile +++ b/arch/xtensa/kernel/Makefile @@ -23,8 +23,8 @@ obj-$(CONFIG_MODULES) += xtensa_ksyms.o module.o # # Replicate rules in scripts/Makefile.build -sed-y = -e 's/(\(\.[a-z]*it\|\.ref\|\)\.text)/(\1.literal \1.text)/g' \ - -e 's/(\(\.text\.[a-z]*\))/(\1.literal \1)/g' +sed-y = -e 's/\*(\(\.[a-z]*it\|\.ref\|\)\.text)/*(\1.literal \1.text)/g' \ + -e 's/\*(\(\.text\.[a-z]*\))/*(\1.literal \1)/g' quiet_cmd__cpp_lds_S = LDS $@ cmd__cpp_lds_S = $(CPP) $(cpp_flags) -P -C -Uxtensa -D__ASSEMBLY__ $< \ -- GitLab From 8b307f9c471c7d198070227be26007258b43140e Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Sat, 1 May 2010 23:05:29 -0700 Subject: [PATCH 0035/5312] xtensa: Fixes due to bss boundary symbol name changes. The bss start and end symbols have changed to __bss_start and __bss_stop. Signed-off-by: Chris Zankel --- arch/xtensa/kernel/head.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S index d215adcfd4ea..3ef91a73652d 100644 --- a/arch/xtensa/kernel/head.S +++ b/arch/xtensa/kernel/head.S @@ -184,8 +184,8 @@ _startup: * Now clear the BSS segment. */ - movi a2, _bss_start # start of BSS - movi a3, _bss_end # end of BSS + movi a2, __bss_start # start of BSS + movi a3, __bss_stop # end of BSS __loopt a2, a3, a4, 2 s32i a0, a2, 0 -- GitLab From cf1c0aaf816ecc90106d997c0af3f7cdde6c2a71 Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Sun, 2 May 2010 01:00:22 -0700 Subject: [PATCH 0036/5312] xtensa: Add -mforce-no-pic option is supported GCC is configured to always compile with PIC enabled for the Xtensa architecture. This fails when nfsroot is enabled as the code uses a non-conformant segment that mismatches in permissione with a read-only segment. A patch has been submitted to GCC to add the machine-option 'force-no-pic' that disables PIC. Signed-off-by: Chris Zankel --- arch/xtensa/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile index 4caffac3ca2e..7608559de93a 100644 --- a/arch/xtensa/Makefile +++ b/arch/xtensa/Makefile @@ -35,6 +35,8 @@ KBUILD_CFLAGS += -ffreestanding KBUILD_CFLAGS += -pipe -mlongcalls +KBUILD_CFLAGS += $(call cc-option,-mforce-no-pic,) + vardirs := $(patsubst %,arch/xtensa/variants/%/,$(variant-y)) plfdirs := $(patsubst %,arch/xtensa/platforms/%/,$(platform-y)) -- GitLab From 4573e398d591a2fe6c600908578fd31401746529 Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Sun, 2 May 2010 01:05:13 -0700 Subject: [PATCH 0037/5312] xtensa: Shuffle include statements to fix linker script The linker script was including assembly macros from the coprocessor header file that is not otherwise used by the script. Signed-off-by: Chris Zankel --- arch/xtensa/include/asm/elf.h | 1 + arch/xtensa/include/asm/pgalloc.h | 1 + arch/xtensa/include/asm/processor.h | 1 - arch/xtensa/include/asm/ptrace.h | 2 ++ arch/xtensa/kernel/asm-offsets.c | 1 + arch/xtensa/kernel/entry.S | 1 + 6 files changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/xtensa/include/asm/elf.h b/arch/xtensa/include/asm/elf.h index 5eb6d695e987..6e65eadaae14 100644 --- a/arch/xtensa/include/asm/elf.h +++ b/arch/xtensa/include/asm/elf.h @@ -14,6 +14,7 @@ #define _XTENSA_ELF_H #include +#include /* Xtensa processor ELF architecture-magic number */ diff --git a/arch/xtensa/include/asm/pgalloc.h b/arch/xtensa/include/asm/pgalloc.h index 4f4a7987eded..40cf9bceda2c 100644 --- a/arch/xtensa/include/asm/pgalloc.h +++ b/arch/xtensa/include/asm/pgalloc.h @@ -14,6 +14,7 @@ #ifdef __KERNEL__ #include +#include /* * Allocating and freeing a pmd is trivial: the 1-entry pmd is diff --git a/arch/xtensa/include/asm/processor.h b/arch/xtensa/include/asm/processor.h index 0ea4937c0b61..3acb26e8dead 100644 --- a/arch/xtensa/include/asm/processor.h +++ b/arch/xtensa/include/asm/processor.h @@ -12,7 +12,6 @@ #define _XTENSA_PROCESSOR_H #include -#include #include #include diff --git a/arch/xtensa/include/asm/ptrace.h b/arch/xtensa/include/asm/ptrace.h index 3c549f798727..0d42c934b66f 100644 --- a/arch/xtensa/include/asm/ptrace.h +++ b/arch/xtensa/include/asm/ptrace.h @@ -77,6 +77,8 @@ #ifndef __ASSEMBLY__ +#include + /* * This struct defines the way the registers are stored on the * kernel stack during a system call or other kernel entry. diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c index 070ff8af3a21..7dc3f9157185 100644 --- a/arch/xtensa/kernel/asm-offsets.c +++ b/arch/xtensa/kernel/asm-offsets.c @@ -13,6 +13,7 @@ */ #include +#include #include #include diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S index 77fc9f6dc016..5fd01f6aaf37 100644 --- a/arch/xtensa/kernel/entry.S +++ b/arch/xtensa/kernel/entry.S @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include -- GitLab From 0a972468ec3f8a5f86193a8f124f7b04cf600c3c Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Sun, 2 May 2010 08:37:20 -0700 Subject: [PATCH 0038/5312] xtensa: Fix the network driver for the simulator target Network methods have moved to the net_device_ops structure. Signed-off-by: Chris Zankel --- arch/xtensa/platforms/iss/network.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/arch/xtensa/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c index 87e218f98ef4..f717e20d961b 100644 --- a/arch/xtensa/platforms/iss/network.c +++ b/arch/xtensa/platforms/iss/network.c @@ -623,6 +623,19 @@ static struct platform_driver iss_net_driver = { static int driver_registered; +static const struct net_device_ops iss_netdev_ops = { + .ndo_open = iss_net_open, + .ndo_stop = iss_net_close, + .ndo_get_stats = iss_net_get_stats, + .ndo_start_xmit = iss_net_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = iss_net_change_mtu, + .ndo_set_mac_address = iss_net_set_mac, + //.ndo_do_ioctl = iss_net_ioctl, + .ndo_tx_timeout = iss_net_tx_timeout, + .ndo_set_multicast_list = iss_net_set_multicast_list, +}; + static int iss_net_configure(int index, char *init) { struct net_device *dev; @@ -686,15 +699,8 @@ static int iss_net_configure(int index, char *init) */ snprintf(dev->name, sizeof dev->name, "eth%d", index); + dev->netdev_ops = &iss_netdev_ops; dev->mtu = lp->mtu; - dev->open = iss_net_open; - dev->hard_start_xmit = iss_net_start_xmit; - dev->stop = iss_net_close; - dev->get_stats = iss_net_get_stats; - dev->set_multicast_list = iss_net_set_multicast_list; - dev->tx_timeout = iss_net_tx_timeout; - dev->set_mac_address = iss_net_set_mac; - dev->change_mtu = iss_net_change_mtu; dev->watchdog_timeo = (HZ >> 1); dev->irq = -1; -- GitLab From d1eca29e7adc5e50165b9856cbb00014c274c5c7 Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Mon, 3 May 2010 01:06:43 -0700 Subject: [PATCH 0039/5312] xtensa: Add missing include in coprocessor.h Coprocessor.h depends on variant settings. Signed-off-by: Chris Zankel --- arch/xtensa/include/asm/coprocessor.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/xtensa/include/asm/coprocessor.h b/arch/xtensa/include/asm/coprocessor.h index 65a285d8d3fb..75c94a1658b0 100644 --- a/arch/xtensa/include/asm/coprocessor.h +++ b/arch/xtensa/include/asm/coprocessor.h @@ -13,6 +13,7 @@ #define _XTENSA_COPROCESSOR_H #include +#include #include #include -- GitLab From 45c34e05c4e3d36e7c44e790241ea11a1d90d54e Mon Sep 17 00:00:00 2001 From: John Villalovos Date: Fri, 7 May 2010 12:41:40 -0400 Subject: [PATCH 0040/5312] Oprofile: Change CPUIDS from decimal to hex, and add some comments Back when the patch was submitted for "Add Xeon 7500 series support to oprofile", Robert Richter had asked for a followon patch that converted all the CPU ID values to hex. I have done that here for the "i386/core_i7" and "i386/atom" class processors in the ppro_init() function and also added some comments on where to find documentation on the Intel processors. Signed-off-by: John L. Villalovos Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index b28d2f1253bb..1ba67dc8006a 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -634,6 +634,18 @@ static int __init ppro_init(char **cpu_type) if (force_arch_perfmon && cpu_has_arch_perfmon) return 0; + /* + * Documentation on identifying Intel processors by CPU family + * and model can be found in the Intel Software Developer's + * Manuals (SDM): + * + * http://www.intel.com/products/processor/manuals/ + * + * As of May 2010 the documentation for this was in the: + * "Intel 64 and IA-32 Architectures Software Developer's + * Manual Volume 3B: System Programming Guide", "Table B-1 + * CPUID Signature Values of DisplayFamily_DisplayModel". + */ switch (cpu_model) { case 0 ... 2: *cpu_type = "i386/ppro"; @@ -655,12 +667,12 @@ static int __init ppro_init(char **cpu_type) case 15: case 23: *cpu_type = "i386/core_2"; break; + case 0x1a: case 0x2e: - case 26: spec = &op_arch_perfmon_spec; *cpu_type = "i386/core_i7"; break; - case 28: + case 0x1c: *cpu_type = "i386/atom"; break; default: -- GitLab From 58687acba59266735adb8ccd9b5b9aa2c7cd205b Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Fri, 7 May 2010 17:11:44 -0400 Subject: [PATCH 0041/5312] lockup_detector: Combine nmi_watchdog and softlockup detector The new nmi_watchdog (which uses the perf event subsystem) is very similar in structure to the softlockup detector. Using Ingo's suggestion, I combined the two functionalities into one file: kernel/watchdog.c. Now both the nmi_watchdog (or hardlockup detector) and softlockup detector sit on top of the perf event subsystem, which is run every 60 seconds or so to see if there are any lockups. To detect hardlockups, cpus not responding to interrupts, I implemented an hrtimer that runs 5 times for every perf event overflow event. If that stops counting on a cpu, then the cpu is most likely in trouble. To detect softlockups, tasks not yielding to the scheduler, I used the previous kthread idea that now gets kicked every time the hrtimer fires. If the kthread isn't being scheduled neither is anyone else and the warning is printed to the console. I tested this on x86_64 and both the softlockup and hardlockup paths work. V2: - cleaned up the Kconfig and softlockup combination - surrounded hardlockup cases with #ifdef CONFIG_PERF_EVENTS_NMI - seperated out the softlockup case from perf event subsystem - re-arranged the enabling/disabling nmi watchdog from proc space - added cpumasks for hardlockup failure cases - removed fallback to soft events if no PMU exists for hard events V3: - comment cleanups - drop support for older softlockup code - per_cpu cleanups - completely remove software clock base hardlockup detector - use per_cpu masking on hard/soft lockup detection - #ifdef cleanups - rename config option NMI_WATCHDOG to LOCKUP_DETECTOR - documentation additions V4: - documentation fixes - convert per_cpu to __get_cpu_var - powerpc compile fixes V5: - split apart warn flags for hard and soft lockups TODO: - figure out how to make an arch-agnostic clock2cycles call (if possible) to feed into perf events as a sample period [fweisbec: merged conflict patch] Signed-off-by: Don Zickus Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Cyrill Gorcunov Cc: Eric Paris Cc: Randy Dunlap LKML-Reference: <1273266711-18706-2-git-send-email-dzickus@redhat.com> Signed-off-by: Frederic Weisbecker --- Documentation/kernel-parameters.txt | 2 + arch/x86/include/asm/nmi.h | 2 +- arch/x86/kernel/apic/Makefile | 4 +- arch/x86/kernel/apic/hw_nmi.c | 2 +- arch/x86/kernel/traps.c | 4 +- include/linux/nmi.h | 8 +- include/linux/sched.h | 6 + init/Kconfig | 5 +- kernel/Makefile | 3 +- kernel/sysctl.c | 21 +- kernel/watchdog.c | 592 ++++++++++++++++++++++++++++ lib/Kconfig.debug | 30 +- 12 files changed, 650 insertions(+), 29 deletions(-) create mode 100644 kernel/watchdog.c diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 839b21b0699a..dfe8d1c226c6 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1777,6 +1777,8 @@ and is between 256 and 4096 characters. It is defined in the file nousb [USB] Disable the USB subsystem + nowatchdog [KNL] Disable the lockup detector. + nowb [ARM] nox2apic [X86-64,APIC] Do not enable x2APIC mode. diff --git a/arch/x86/include/asm/nmi.h b/arch/x86/include/asm/nmi.h index 5b41b0feb6db..932f0f86b4b7 100644 --- a/arch/x86/include/asm/nmi.h +++ b/arch/x86/include/asm/nmi.h @@ -17,7 +17,7 @@ int do_nmi_callback(struct pt_regs *regs, int cpu); extern void die_nmi(char *str, struct pt_regs *regs, int do_panic); extern int check_nmi_watchdog(void); -#if !defined(CONFIG_NMI_WATCHDOG) +#if !defined(CONFIG_LOCKUP_DETECTOR) extern int nmi_watchdog_enabled; #endif extern int avail_to_resrv_perfctr_nmi_bit(unsigned int); diff --git a/arch/x86/kernel/apic/Makefile b/arch/x86/kernel/apic/Makefile index 1a4512e48d24..52f32e0ea194 100644 --- a/arch/x86/kernel/apic/Makefile +++ b/arch/x86/kernel/apic/Makefile @@ -3,10 +3,10 @@ # obj-$(CONFIG_X86_LOCAL_APIC) += apic.o apic_noop.o probe_$(BITS).o ipi.o -ifneq ($(CONFIG_NMI_WATCHDOG),y) +ifneq ($(CONFIG_LOCKUP_DETECTOR),y) obj-$(CONFIG_X86_LOCAL_APIC) += nmi.o endif -obj-$(CONFIG_NMI_WATCHDOG) += hw_nmi.o +obj-$(CONFIG_LOCKUP_DETECTOR) += hw_nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o obj-$(CONFIG_SMP) += ipi.o diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c index e8b78a0be5de..79425f96fcee 100644 --- a/arch/x86/kernel/apic/hw_nmi.c +++ b/arch/x86/kernel/apic/hw_nmi.c @@ -89,7 +89,7 @@ int hw_nmi_is_cpu_stuck(struct pt_regs *regs) u64 hw_nmi_get_sample_period(void) { - return cpu_khz * 1000; + return (u64)(cpu_khz) * 1000 * 60; } #ifdef ARCH_HAS_NMI_WATCHDOG diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index bdc7fab3ef3e..bd347c2b34dc 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -406,7 +406,7 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs) == NOTIFY_STOP) return; -#ifndef CONFIG_NMI_WATCHDOG +#ifndef CONFIG_LOCKUP_DETECTOR /* * Ok, so this is none of the documented NMI sources, * so it must be the NMI watchdog. @@ -414,7 +414,7 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs) if (nmi_watchdog_tick(regs, reason)) return; if (!do_nmi_callback(regs, cpu)) -#endif /* !CONFIG_NMI_WATCHDOG */ +#endif /* !CONFIG_LOCKUP_DETECTOR */ unknown_nmi_error(reason, regs); #else unknown_nmi_error(reason, regs); diff --git a/include/linux/nmi.h b/include/linux/nmi.h index 22cc7960b649..abd48aacaf79 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -20,7 +20,7 @@ extern void touch_nmi_watchdog(void); extern void acpi_nmi_disable(void); extern void acpi_nmi_enable(void); #else -#ifndef CONFIG_NMI_WATCHDOG +#ifndef CONFIG_LOCKUP_DETECTOR static inline void touch_nmi_watchdog(void) { touch_softlockup_watchdog(); @@ -51,12 +51,12 @@ static inline bool trigger_all_cpu_backtrace(void) } #endif -#ifdef CONFIG_NMI_WATCHDOG +#ifdef CONFIG_LOCKUP_DETECTOR int hw_nmi_is_cpu_stuck(struct pt_regs *); u64 hw_nmi_get_sample_period(void); -extern int nmi_watchdog_enabled; +extern int watchdog_enabled; struct ctl_table; -extern int proc_nmi_enabled(struct ctl_table *, int , +extern int proc_dowatchdog_enabled(struct ctl_table *, int , void __user *, size_t *, loff_t *); #endif diff --git a/include/linux/sched.h b/include/linux/sched.h index dad7f668ebf7..37efe8fa5306 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -346,6 +346,12 @@ extern int proc_dohung_task_timeout_secs(struct ctl_table *table, int write, size_t *lenp, loff_t *ppos); #endif +#ifdef CONFIG_LOCKUP_DETECTOR +extern int proc_dowatchdog_thresh(struct ctl_table *table, int write, + void __user *buffer, + size_t *lenp, loff_t *ppos); +#endif + /* Attach to any functions which should be ignored in wchan output. */ #define __sched __attribute__((__section__(".sched.text"))) diff --git a/init/Kconfig b/init/Kconfig index c6c8903cb534..e44e25422f22 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -944,8 +944,11 @@ config PERF_USE_VMALLOC config PERF_EVENTS_NMI bool + depends on PERF_EVENTS help - Arch has support for nmi_watchdog + System hardware can generate an NMI using the perf event + subsystem. Also has support for calculating CPU cycle events + to determine how many clock cycles in a given period. menu "Kernel Performance Events And Counters" diff --git a/kernel/Makefile b/kernel/Makefile index d5c30060ac14..6adeafc3e259 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -76,9 +76,8 @@ obj-$(CONFIG_GCOV_KERNEL) += gcov/ obj-$(CONFIG_AUDIT_TREE) += audit_tree.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_KGDB) += kgdb.o -obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o -obj-$(CONFIG_NMI_WATCHDOG) += nmi_watchdog.o obj-$(CONFIG_DETECT_HUNG_TASK) += hung_task.o +obj-$(CONFIG_LOCKUP_DETECTOR) += watchdog.o obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ obj-$(CONFIG_SECCOMP) += seccomp.o obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o diff --git a/kernel/sysctl.c b/kernel/sysctl.c index a38af430f0d8..0f9adda85f97 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -74,7 +74,7 @@ #include #endif -#ifdef CONFIG_NMI_WATCHDOG +#ifdef CONFIG_LOCKUP_DETECTOR #include #endif @@ -686,16 +686,25 @@ static struct ctl_table kern_table[] = { .mode = 0444, .proc_handler = proc_dointvec, }, -#if defined(CONFIG_NMI_WATCHDOG) +#if defined(CONFIG_LOCKUP_DETECTOR) { - .procname = "nmi_watchdog", - .data = &nmi_watchdog_enabled, + .procname = "watchdog", + .data = &watchdog_enabled, .maxlen = sizeof (int), .mode = 0644, - .proc_handler = proc_nmi_enabled, + .proc_handler = proc_dowatchdog_enabled, + }, + { + .procname = "watchdog_thresh", + .data = &softlockup_thresh, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dowatchdog_thresh, + .extra1 = &neg_one, + .extra2 = &sixty, }, #endif -#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) && !defined(CONFIG_NMI_WATCHDOG) +#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) && !defined(CONFIG_LOCKUP_DETECTOR) { .procname = "unknown_nmi_panic", .data = &unknown_nmi_panic, diff --git a/kernel/watchdog.c b/kernel/watchdog.c new file mode 100644 index 000000000000..6b7fad8497af --- /dev/null +++ b/kernel/watchdog.c @@ -0,0 +1,592 @@ +/* + * Detect hard and soft lockups on a system + * + * started by Don Zickus, Copyright (C) 2010 Red Hat, Inc. + * + * this code detects hard lockups: incidents in where on a CPU + * the kernel does not respond to anything except NMI. + * + * Note: Most of this code is borrowed heavily from softlockup.c, + * so thanks to Ingo for the initial implementation. + * Some chunks also taken from arch/x86/kernel/apic/nmi.c, thanks + * to those contributors as well. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +int watchdog_enabled; +int __read_mostly softlockup_thresh = 60; + +static DEFINE_PER_CPU(unsigned long, watchdog_touch_ts); +static DEFINE_PER_CPU(struct task_struct *, softlockup_watchdog); +static DEFINE_PER_CPU(struct hrtimer, watchdog_hrtimer); +static DEFINE_PER_CPU(bool, softlockup_touch_sync); +static DEFINE_PER_CPU(bool, hard_watchdog_warn); +static DEFINE_PER_CPU(bool, soft_watchdog_warn); +#ifdef CONFIG_PERF_EVENTS_NMI +static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts); +static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved); +static DEFINE_PER_CPU(struct perf_event *, watchdog_ev); +#endif + +static int __read_mostly did_panic; +static int __initdata no_watchdog; + + +/* boot commands */ +/* + * Should we panic when a soft-lockup or hard-lockup occurs: + */ +#ifdef CONFIG_PERF_EVENTS_NMI +static int hardlockup_panic; + +static int __init hardlockup_panic_setup(char *str) +{ + if (!strncmp(str, "panic", 5)) + hardlockup_panic = 1; + return 1; +} +__setup("nmi_watchdog=", hardlockup_panic_setup); +#endif + +unsigned int __read_mostly softlockup_panic = + CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE; + +static int __init softlockup_panic_setup(char *str) +{ + softlockup_panic = simple_strtoul(str, NULL, 0); + + return 1; +} +__setup("softlockup_panic=", softlockup_panic_setup); + +static int __init nowatchdog_setup(char *str) +{ + no_watchdog = 1; + return 1; +} +__setup("nowatchdog", nowatchdog_setup); + +/* deprecated */ +static int __init nosoftlockup_setup(char *str) +{ + no_watchdog = 1; + return 1; +} +__setup("nosoftlockup", nosoftlockup_setup); +/* */ + + +/* + * Returns seconds, approximately. We don't need nanosecond + * resolution, and we don't need to waste time with a big divide when + * 2^30ns == 1.074s. + */ +static unsigned long get_timestamp(int this_cpu) +{ + return cpu_clock(this_cpu) >> 30LL; /* 2^30 ~= 10^9 */ +} + +static unsigned long get_sample_period(void) +{ + /* + * convert softlockup_thresh from seconds to ns + * the divide by 5 is to give hrtimer 5 chances to + * increment before the hardlockup detector generates + * a warning + */ + return softlockup_thresh / 5 * NSEC_PER_SEC; +} + +/* Commands for resetting the watchdog */ +static void __touch_watchdog(void) +{ + int this_cpu = raw_smp_processor_id(); + + __get_cpu_var(watchdog_touch_ts) = get_timestamp(this_cpu); +} + +void touch_watchdog(void) +{ + __get_cpu_var(watchdog_touch_ts) = 0; +} +EXPORT_SYMBOL(touch_watchdog); + +void touch_all_watchdog(void) +{ + int cpu; + + /* + * this is done lockless + * do we care if a 0 races with a timestamp? + * all it means is the softlock check starts one cycle later + */ + for_each_online_cpu(cpu) + per_cpu(watchdog_touch_ts, cpu) = 0; +} + +void touch_nmi_watchdog(void) +{ + touch_watchdog(); +} +EXPORT_SYMBOL(touch_nmi_watchdog); + +void touch_all_nmi_watchdog(void) +{ + touch_all_watchdog(); +} + +void touch_softlockup_watchdog(void) +{ + touch_watchdog(); +} + +void touch_all_softlockup_watchdogs(void) +{ + touch_all_watchdog(); +} + +void touch_softlockup_watchdog_sync(void) +{ + __raw_get_cpu_var(softlockup_touch_sync) = true; + __raw_get_cpu_var(watchdog_touch_ts) = 0; +} + +void softlockup_tick(void) +{ +} + +#ifdef CONFIG_PERF_EVENTS_NMI +/* watchdog detector functions */ +static int is_hardlockup(int cpu) +{ + unsigned long hrint = per_cpu(hrtimer_interrupts, cpu); + + if (per_cpu(hrtimer_interrupts_saved, cpu) == hrint) + return 1; + + per_cpu(hrtimer_interrupts_saved, cpu) = hrint; + return 0; +} +#endif + +static int is_softlockup(unsigned long touch_ts, int cpu) +{ + unsigned long now = get_timestamp(cpu); + + /* Warn about unreasonable delays: */ + if (time_after(now, touch_ts + softlockup_thresh)) + return now - touch_ts; + + return 0; +} + +static int +watchdog_panic(struct notifier_block *this, unsigned long event, void *ptr) +{ + did_panic = 1; + + return NOTIFY_DONE; +} + +static struct notifier_block panic_block = { + .notifier_call = watchdog_panic, +}; + +#ifdef CONFIG_PERF_EVENTS_NMI +static struct perf_event_attr wd_hw_attr = { + .type = PERF_TYPE_HARDWARE, + .config = PERF_COUNT_HW_CPU_CYCLES, + .size = sizeof(struct perf_event_attr), + .pinned = 1, + .disabled = 1, +}; + +/* Callback function for perf event subsystem */ +void watchdog_overflow_callback(struct perf_event *event, int nmi, + struct perf_sample_data *data, + struct pt_regs *regs) +{ + int this_cpu = smp_processor_id(); + unsigned long touch_ts = per_cpu(watchdog_touch_ts, this_cpu); + + if (touch_ts == 0) { + __touch_watchdog(); + return; + } + + /* check for a hardlockup + * This is done by making sure our timer interrupt + * is incrementing. The timer interrupt should have + * fired multiple times before we overflow'd. If it hasn't + * then this is a good indication the cpu is stuck + */ + if (is_hardlockup(this_cpu)) { + /* only print hardlockups once */ + if (__get_cpu_var(hard_watchdog_warn) == true) + return; + + if (hardlockup_panic) + panic("Watchdog detected hard LOCKUP on cpu %d", this_cpu); + else + WARN(1, "Watchdog detected hard LOCKUP on cpu %d", this_cpu); + + __get_cpu_var(hard_watchdog_warn) = true; + return; + } + + __get_cpu_var(hard_watchdog_warn) = false; + return; +} +static void watchdog_interrupt_count(void) +{ + __get_cpu_var(hrtimer_interrupts)++; +} +#else +static inline void watchdog_interrupt_count(void) { return; } +#endif /* CONFIG_PERF_EVENTS_NMI */ + +/* watchdog kicker functions */ +static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) +{ + int this_cpu = smp_processor_id(); + unsigned long touch_ts = __get_cpu_var(watchdog_touch_ts); + struct pt_regs *regs = get_irq_regs(); + int duration; + + /* kick the hardlockup detector */ + watchdog_interrupt_count(); + + /* kick the softlockup detector */ + wake_up_process(__get_cpu_var(softlockup_watchdog)); + + /* .. and repeat */ + hrtimer_forward_now(hrtimer, ns_to_ktime(get_sample_period())); + + if (touch_ts == 0) { + if (unlikely(per_cpu(softlockup_touch_sync, this_cpu))) { + /* + * If the time stamp was touched atomically + * make sure the scheduler tick is up to date. + */ + per_cpu(softlockup_touch_sync, this_cpu) = false; + sched_clock_tick(); + } + __touch_watchdog(); + return HRTIMER_RESTART; + } + + /* check for a softlockup + * This is done by making sure a high priority task is + * being scheduled. The task touches the watchdog to + * indicate it is getting cpu time. If it hasn't then + * this is a good indication some task is hogging the cpu + */ + duration = is_softlockup(touch_ts, this_cpu); + if (unlikely(duration)) { + /* only warn once */ + if (__get_cpu_var(soft_watchdog_warn) == true) + return HRTIMER_RESTART; + + printk(KERN_ERR "BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n", + this_cpu, duration, + current->comm, task_pid_nr(current)); + print_modules(); + print_irqtrace_events(current); + if (regs) + show_regs(regs); + else + dump_stack(); + + if (softlockup_panic) + panic("softlockup: hung tasks"); + __get_cpu_var(soft_watchdog_warn) = true; + } else + __get_cpu_var(soft_watchdog_warn) = false; + + return HRTIMER_RESTART; +} + + +/* + * The watchdog thread - touches the timestamp. + */ +static int watchdog(void *__bind_cpu) +{ + struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; + struct hrtimer *hrtimer = &per_cpu(watchdog_hrtimer, (unsigned long)__bind_cpu); + + sched_setscheduler(current, SCHED_FIFO, ¶m); + + /* initialize timestamp */ + __touch_watchdog(); + + /* kick off the timer for the hardlockup detector */ + /* done here because hrtimer_start can only pin to smp_processor_id() */ + hrtimer_start(hrtimer, ns_to_ktime(get_sample_period()), + HRTIMER_MODE_REL_PINNED); + + set_current_state(TASK_INTERRUPTIBLE); + /* + * Run briefly once per second to reset the softlockup timestamp. + * If this gets delayed for more than 60 seconds then the + * debug-printout triggers in softlockup_tick(). + */ + while (!kthread_should_stop()) { + __touch_watchdog(); + schedule(); + + if (kthread_should_stop()) + break; + + set_current_state(TASK_INTERRUPTIBLE); + } + __set_current_state(TASK_RUNNING); + + return 0; +} + + +#ifdef CONFIG_PERF_EVENTS_NMI +static int watchdog_nmi_enable(int cpu) +{ + struct perf_event_attr *wd_attr; + struct perf_event *event = per_cpu(watchdog_ev, cpu); + + /* is it already setup and enabled? */ + if (event && event->state > PERF_EVENT_STATE_OFF) + goto out; + + /* it is setup but not enabled */ + if (event != NULL) + goto out_enable; + + /* Try to register using hardware perf events */ + wd_attr = &wd_hw_attr; + wd_attr->sample_period = hw_nmi_get_sample_period(); + event = perf_event_create_kernel_counter(wd_attr, cpu, -1, watchdog_overflow_callback); + if (!IS_ERR(event)) { + printk(KERN_INFO "NMI watchdog enabled, takes one hw-pmu counter.\n"); + goto out_save; + } + + printk(KERN_ERR "NMI watchdog failed to create perf event on cpu%i: %p\n", cpu, event); + return -1; + + /* success path */ +out_save: + per_cpu(watchdog_ev, cpu) = event; +out_enable: + perf_event_enable(per_cpu(watchdog_ev, cpu)); +out: + return 0; +} + +static void watchdog_nmi_disable(int cpu) +{ + struct perf_event *event = per_cpu(watchdog_ev, cpu); + + if (event) { + perf_event_disable(event); + per_cpu(watchdog_ev, cpu) = NULL; + + /* should be in cleanup, but blocks oprofile */ + perf_event_release_kernel(event); + } + return; +} +#else +static int watchdog_nmi_enable(int cpu) { return 0; } +static void watchdog_nmi_disable(int cpu) { return; } +#endif /* CONFIG_PERF_EVENTS_NMI */ + +/* prepare/enable/disable routines */ +static int watchdog_prepare_cpu(int cpu) +{ + struct hrtimer *hrtimer = &per_cpu(watchdog_hrtimer, cpu); + + WARN_ON(per_cpu(softlockup_watchdog, cpu)); + hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hrtimer->function = watchdog_timer_fn; + + return 0; +} + +static int watchdog_enable(int cpu) +{ + struct task_struct *p = per_cpu(softlockup_watchdog, cpu); + + /* enable the perf event */ + if (watchdog_nmi_enable(cpu) != 0) + return -1; + + /* create the watchdog thread */ + if (!p) { + p = kthread_create(watchdog, (void *)(unsigned long)cpu, "watchdog/%d", cpu); + if (IS_ERR(p)) { + printk(KERN_ERR "softlockup watchdog for %i failed\n", cpu); + return -1; + } + kthread_bind(p, cpu); + per_cpu(watchdog_touch_ts, cpu) = 0; + per_cpu(softlockup_watchdog, cpu) = p; + wake_up_process(p); + } + + return 0; +} + +static void watchdog_disable(int cpu) +{ + struct task_struct *p = per_cpu(softlockup_watchdog, cpu); + struct hrtimer *hrtimer = &per_cpu(watchdog_hrtimer, cpu); + + /* + * cancel the timer first to stop incrementing the stats + * and waking up the kthread + */ + hrtimer_cancel(hrtimer); + + /* disable the perf event */ + watchdog_nmi_disable(cpu); + + /* stop the watchdog thread */ + if (p) { + per_cpu(softlockup_watchdog, cpu) = NULL; + kthread_stop(p); + } + + /* if any cpu succeeds, watchdog is considered enabled for the system */ + watchdog_enabled = 1; +} + +static void watchdog_enable_all_cpus(void) +{ + int cpu; + int result; + + for_each_online_cpu(cpu) + result += watchdog_enable(cpu); + + if (result) + printk(KERN_ERR "watchdog: failed to be enabled on some cpus\n"); + +} + +static void watchdog_disable_all_cpus(void) +{ + int cpu; + + for_each_online_cpu(cpu) + watchdog_disable(cpu); + + /* if all watchdogs are disabled, then they are disabled for the system */ + watchdog_enabled = 0; +} + + +/* sysctl functions */ +#ifdef CONFIG_SYSCTL +/* + * proc handler for /proc/sys/kernel/nmi_watchdog + */ + +int proc_dowatchdog_enabled(struct ctl_table *table, int write, + void __user *buffer, size_t *length, loff_t *ppos) +{ + proc_dointvec(table, write, buffer, length, ppos); + + if (watchdog_enabled) + watchdog_enable_all_cpus(); + else + watchdog_disable_all_cpus(); + return 0; +} + +int proc_dowatchdog_thresh(struct ctl_table *table, int write, + void __user *buffer, + size_t *lenp, loff_t *ppos) +{ + return proc_dointvec_minmax(table, write, buffer, lenp, ppos); +} + +/* stub functions */ +int proc_dosoftlockup_thresh(struct ctl_table *table, int write, + void __user *buffer, + size_t *lenp, loff_t *ppos) +{ + return proc_dowatchdog_thresh(table, write, buffer, lenp, ppos); +} +/* end of stub functions */ +#endif /* CONFIG_SYSCTL */ + + +/* + * Create/destroy watchdog threads as CPUs come and go: + */ +static int __cpuinit +cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) +{ + int hotcpu = (unsigned long)hcpu; + + switch (action) { + case CPU_UP_PREPARE: + case CPU_UP_PREPARE_FROZEN: + if (watchdog_prepare_cpu(hotcpu)) + return NOTIFY_BAD; + break; + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + if (watchdog_enable(hotcpu)) + return NOTIFY_BAD; + break; +#ifdef CONFIG_HOTPLUG_CPU + case CPU_UP_CANCELED: + case CPU_UP_CANCELED_FROZEN: + watchdog_disable(hotcpu); + break; + case CPU_DEAD: + case CPU_DEAD_FROZEN: + watchdog_disable(hotcpu); + break; +#endif /* CONFIG_HOTPLUG_CPU */ + } + return NOTIFY_OK; +} + +static struct notifier_block __cpuinitdata cpu_nfb = { + .notifier_call = cpu_callback +}; + +static int __init spawn_watchdog_task(void) +{ + void *cpu = (void *)(long)smp_processor_id(); + int err; + + if (no_watchdog) + return 0; + + err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu); + WARN_ON(err == NOTIFY_BAD); + + cpu_callback(&cpu_nfb, CPU_ONLINE, cpu); + register_cpu_notifier(&cpu_nfb); + + atomic_notifier_chain_register(&panic_notifier_list, &panic_block); + + return 0; +} +early_initcall(spawn_watchdog_task); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 220ae6063b6f..49e285dcaf57 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -153,7 +153,7 @@ config DEBUG_SHIRQ points; some don't and need to be caught. config DETECT_SOFTLOCKUP - bool "Detect Soft Lockups" + bool depends on DEBUG_KERNEL && !S390 default y help @@ -171,17 +171,27 @@ config DETECT_SOFTLOCKUP can be detected via the NMI-watchdog, on platforms that support it.) -config NMI_WATCHDOG - bool "Detect Hard Lockups with an NMI Watchdog" - depends on DEBUG_KERNEL && PERF_EVENTS && PERF_EVENTS_NMI +config LOCKUP_DETECTOR + bool "Detect Hard and Soft Lockups" + depends on DEBUG_KERNEL + default DETECT_SOFTLOCKUP help - Say Y here to enable the kernel to use the NMI as a watchdog - to detect hard lockups. This is useful when a cpu hangs for no - reason but can still respond to NMIs. A backtrace is displayed - for reviewing and reporting. + Say Y here to enable the kernel to act as a watchdog to detect + hard and soft lockups. + + Softlockups are bugs that cause the kernel to loop in kernel + mode for more than 60 seconds, without giving other tasks a + chance to run. The current stack trace is displayed upon + detection and the system will stay locked up. + + Hardlockups are bugs that cause the CPU to loop in kernel mode + for more than 60 seconds, without letting other interrupts have a + chance to run. The current stack trace is displayed upon detection + and the system will stay locked up. - The overhead should be minimal, just an extra NMI every few - seconds. + The overhead should be minimal. A periodic hrtimer runs to + generate interrupts and kick the watchdog task every 10-12 seconds. + An NMI is generated every 60 seconds or so to check for hardlockups. config BOOTPARAM_SOFTLOCKUP_PANIC bool "Panic (Reboot) On Soft Lockups" -- GitLab From 332fbdbca3f7716c5620970755ae054d213bcc4e Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Fri, 7 May 2010 17:11:45 -0400 Subject: [PATCH 0042/5312] lockup_detector: Touch_softlockup cleanups and softlockup_tick removal Just some code cleanup to make touch_softlockup clearer and remove the softlockup_tick function as it is no longer needed. Also remove the /proc softlockup_thres call as it has been changed to watchdog_thres. Signed-off-by: Don Zickus Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Cyrill Gorcunov Cc: Eric Paris Cc: Randy Dunlap LKML-Reference: <1273266711-18706-3-git-send-email-dzickus@redhat.com> Signed-off-by: Frederic Weisbecker --- include/linux/sched.h | 16 +++------------- kernel/sysctl.c | 9 --------- kernel/timer.c | 1 - kernel/watchdog.c | 35 +++-------------------------------- 4 files changed, 6 insertions(+), 55 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 37efe8fa5306..33f9b2ad0bbb 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -312,19 +312,15 @@ extern void scheduler_tick(void); extern void sched_show_task(struct task_struct *p); #ifdef CONFIG_DETECT_SOFTLOCKUP -extern void softlockup_tick(void); extern void touch_softlockup_watchdog(void); extern void touch_softlockup_watchdog_sync(void); extern void touch_all_softlockup_watchdogs(void); -extern int proc_dosoftlockup_thresh(struct ctl_table *table, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos); +extern int proc_dowatchdog_thresh(struct ctl_table *table, int write, + void __user *buffer, + size_t *lenp, loff_t *ppos); extern unsigned int softlockup_panic; extern int softlockup_thresh; #else -static inline void softlockup_tick(void) -{ -} static inline void touch_softlockup_watchdog(void) { } @@ -346,12 +342,6 @@ extern int proc_dohung_task_timeout_secs(struct ctl_table *table, int write, size_t *lenp, loff_t *ppos); #endif -#ifdef CONFIG_LOCKUP_DETECTOR -extern int proc_dowatchdog_thresh(struct ctl_table *table, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos); -#endif - /* Attach to any functions which should be ignored in wchan output. */ #define __sched __attribute__((__section__(".sched.text"))) diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 0f9adda85f97..999bc3fccf47 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -817,15 +817,6 @@ static struct ctl_table kern_table[] = { .extra1 = &zero, .extra2 = &one, }, - { - .procname = "softlockup_thresh", - .data = &softlockup_thresh, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dosoftlockup_thresh, - .extra1 = &neg_one, - .extra2 = &sixty, - }, #endif #ifdef CONFIG_DETECT_HUNG_TASK { diff --git a/kernel/timer.c b/kernel/timer.c index aeb6a54f2771..e8de5eb07a02 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1225,7 +1225,6 @@ void run_local_timers(void) { hrtimer_run_queues(); raise_softirq(TIMER_SOFTIRQ); - softlockup_tick(); } /* diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 6b7fad8497af..f1541b7e3244 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -119,13 +119,12 @@ static void __touch_watchdog(void) __get_cpu_var(watchdog_touch_ts) = get_timestamp(this_cpu); } -void touch_watchdog(void) +void touch_softlockup_watchdog(void) { __get_cpu_var(watchdog_touch_ts) = 0; } -EXPORT_SYMBOL(touch_watchdog); -void touch_all_watchdog(void) +void touch_all_softlockup_watchdogs(void) { int cpu; @@ -140,35 +139,16 @@ void touch_all_watchdog(void) void touch_nmi_watchdog(void) { - touch_watchdog(); + touch_softlockup_watchdog(); } EXPORT_SYMBOL(touch_nmi_watchdog); -void touch_all_nmi_watchdog(void) -{ - touch_all_watchdog(); -} - -void touch_softlockup_watchdog(void) -{ - touch_watchdog(); -} - -void touch_all_softlockup_watchdogs(void) -{ - touch_all_watchdog(); -} - void touch_softlockup_watchdog_sync(void) { __raw_get_cpu_var(softlockup_touch_sync) = true; __raw_get_cpu_var(watchdog_touch_ts) = 0; } -void softlockup_tick(void) -{ -} - #ifdef CONFIG_PERF_EVENTS_NMI /* watchdog detector functions */ static int is_hardlockup(int cpu) @@ -522,15 +502,6 @@ int proc_dowatchdog_thresh(struct ctl_table *table, int write, { return proc_dointvec_minmax(table, write, buffer, lenp, ppos); } - -/* stub functions */ -int proc_dosoftlockup_thresh(struct ctl_table *table, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos) -{ - return proc_dowatchdog_thresh(table, write, buffer, lenp, ppos); -} -/* end of stub functions */ #endif /* CONFIG_SYSCTL */ -- GitLab From 2508ce1845a3b256798532b2c6b7997c2dc6533b Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Fri, 7 May 2010 17:11:46 -0400 Subject: [PATCH 0043/5312] lockup_detector: Remove old softlockup code Now that is no longer compiled or used, just remove it. Also move some of the code wrapped with DETECT_SOFTLOCKUP to the LOCKUP_DETECTOR wrappers because that is the code that uses it now. Signed-off-by: Don Zickus Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Cyrill Gorcunov Cc: Eric Paris Cc: Randy Dunlap LKML-Reference: <1273266711-18706-4-git-send-email-dzickus@redhat.com> Signed-off-by: Frederic Weisbecker --- kernel/softlockup.c | 293 -------------------------------------------- kernel/sysctl.c | 22 ++-- 2 files changed, 10 insertions(+), 305 deletions(-) delete mode 100644 kernel/softlockup.c diff --git a/kernel/softlockup.c b/kernel/softlockup.c deleted file mode 100644 index 4b493f67dcb5..000000000000 --- a/kernel/softlockup.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Detect Soft Lockups - * - * started by Ingo Molnar, Copyright (C) 2005, 2006 Red Hat, Inc. - * - * this code detects soft lockups: incidents in where on a CPU - * the kernel does not reschedule for 10 seconds or more. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static DEFINE_SPINLOCK(print_lock); - -static DEFINE_PER_CPU(unsigned long, softlockup_touch_ts); /* touch timestamp */ -static DEFINE_PER_CPU(unsigned long, softlockup_print_ts); /* print timestamp */ -static DEFINE_PER_CPU(struct task_struct *, softlockup_watchdog); -static DEFINE_PER_CPU(bool, softlock_touch_sync); - -static int __read_mostly did_panic; -int __read_mostly softlockup_thresh = 60; - -/* - * Should we panic (and reboot, if panic_timeout= is set) when a - * soft-lockup occurs: - */ -unsigned int __read_mostly softlockup_panic = - CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE; - -static int __init softlockup_panic_setup(char *str) -{ - softlockup_panic = simple_strtoul(str, NULL, 0); - - return 1; -} -__setup("softlockup_panic=", softlockup_panic_setup); - -static int -softlock_panic(struct notifier_block *this, unsigned long event, void *ptr) -{ - did_panic = 1; - - return NOTIFY_DONE; -} - -static struct notifier_block panic_block = { - .notifier_call = softlock_panic, -}; - -/* - * Returns seconds, approximately. We don't need nanosecond - * resolution, and we don't need to waste time with a big divide when - * 2^30ns == 1.074s. - */ -static unsigned long get_timestamp(int this_cpu) -{ - return cpu_clock(this_cpu) >> 30LL; /* 2^30 ~= 10^9 */ -} - -static void __touch_softlockup_watchdog(void) -{ - int this_cpu = raw_smp_processor_id(); - - __raw_get_cpu_var(softlockup_touch_ts) = get_timestamp(this_cpu); -} - -void touch_softlockup_watchdog(void) -{ - __raw_get_cpu_var(softlockup_touch_ts) = 0; -} -EXPORT_SYMBOL(touch_softlockup_watchdog); - -void touch_softlockup_watchdog_sync(void) -{ - __raw_get_cpu_var(softlock_touch_sync) = true; - __raw_get_cpu_var(softlockup_touch_ts) = 0; -} - -void touch_all_softlockup_watchdogs(void) -{ - int cpu; - - /* Cause each CPU to re-update its timestamp rather than complain */ - for_each_online_cpu(cpu) - per_cpu(softlockup_touch_ts, cpu) = 0; -} -EXPORT_SYMBOL(touch_all_softlockup_watchdogs); - -int proc_dosoftlockup_thresh(struct ctl_table *table, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos) -{ - touch_all_softlockup_watchdogs(); - return proc_dointvec_minmax(table, write, buffer, lenp, ppos); -} - -/* - * This callback runs from the timer interrupt, and checks - * whether the watchdog thread has hung or not: - */ -void softlockup_tick(void) -{ - int this_cpu = smp_processor_id(); - unsigned long touch_ts = per_cpu(softlockup_touch_ts, this_cpu); - unsigned long print_ts; - struct pt_regs *regs = get_irq_regs(); - unsigned long now; - - /* Is detection switched off? */ - if (!per_cpu(softlockup_watchdog, this_cpu) || softlockup_thresh <= 0) { - /* Be sure we don't false trigger if switched back on */ - if (touch_ts) - per_cpu(softlockup_touch_ts, this_cpu) = 0; - return; - } - - if (touch_ts == 0) { - if (unlikely(per_cpu(softlock_touch_sync, this_cpu))) { - /* - * If the time stamp was touched atomically - * make sure the scheduler tick is up to date. - */ - per_cpu(softlock_touch_sync, this_cpu) = false; - sched_clock_tick(); - } - __touch_softlockup_watchdog(); - return; - } - - print_ts = per_cpu(softlockup_print_ts, this_cpu); - - /* report at most once a second */ - if (print_ts == touch_ts || did_panic) - return; - - /* do not print during early bootup: */ - if (unlikely(system_state != SYSTEM_RUNNING)) { - __touch_softlockup_watchdog(); - return; - } - - now = get_timestamp(this_cpu); - - /* - * Wake up the high-prio watchdog task twice per - * threshold timespan. - */ - if (time_after(now - softlockup_thresh/2, touch_ts)) - wake_up_process(per_cpu(softlockup_watchdog, this_cpu)); - - /* Warn about unreasonable delays: */ - if (time_before_eq(now - softlockup_thresh, touch_ts)) - return; - - per_cpu(softlockup_print_ts, this_cpu) = touch_ts; - - spin_lock(&print_lock); - printk(KERN_ERR "BUG: soft lockup - CPU#%d stuck for %lus! [%s:%d]\n", - this_cpu, now - touch_ts, - current->comm, task_pid_nr(current)); - print_modules(); - print_irqtrace_events(current); - if (regs) - show_regs(regs); - else - dump_stack(); - spin_unlock(&print_lock); - - if (softlockup_panic) - panic("softlockup: hung tasks"); -} - -/* - * The watchdog thread - runs every second and touches the timestamp. - */ -static int watchdog(void *__bind_cpu) -{ - struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; - - sched_setscheduler(current, SCHED_FIFO, ¶m); - - /* initialize timestamp */ - __touch_softlockup_watchdog(); - - set_current_state(TASK_INTERRUPTIBLE); - /* - * Run briefly once per second to reset the softlockup timestamp. - * If this gets delayed for more than 60 seconds then the - * debug-printout triggers in softlockup_tick(). - */ - while (!kthread_should_stop()) { - __touch_softlockup_watchdog(); - schedule(); - - if (kthread_should_stop()) - break; - - set_current_state(TASK_INTERRUPTIBLE); - } - __set_current_state(TASK_RUNNING); - - return 0; -} - -/* - * Create/destroy watchdog threads as CPUs come and go: - */ -static int __cpuinit -cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) -{ - int hotcpu = (unsigned long)hcpu; - struct task_struct *p; - - switch (action) { - case CPU_UP_PREPARE: - case CPU_UP_PREPARE_FROZEN: - BUG_ON(per_cpu(softlockup_watchdog, hotcpu)); - p = kthread_create(watchdog, hcpu, "watchdog/%d", hotcpu); - if (IS_ERR(p)) { - printk(KERN_ERR "watchdog for %i failed\n", hotcpu); - return NOTIFY_BAD; - } - per_cpu(softlockup_touch_ts, hotcpu) = 0; - per_cpu(softlockup_watchdog, hotcpu) = p; - kthread_bind(p, hotcpu); - break; - case CPU_ONLINE: - case CPU_ONLINE_FROZEN: - wake_up_process(per_cpu(softlockup_watchdog, hotcpu)); - break; -#ifdef CONFIG_HOTPLUG_CPU - case CPU_UP_CANCELED: - case CPU_UP_CANCELED_FROZEN: - if (!per_cpu(softlockup_watchdog, hotcpu)) - break; - /* Unbind so it can run. Fall thru. */ - kthread_bind(per_cpu(softlockup_watchdog, hotcpu), - cpumask_any(cpu_online_mask)); - case CPU_DEAD: - case CPU_DEAD_FROZEN: - p = per_cpu(softlockup_watchdog, hotcpu); - per_cpu(softlockup_watchdog, hotcpu) = NULL; - kthread_stop(p); - break; -#endif /* CONFIG_HOTPLUG_CPU */ - } - return NOTIFY_OK; -} - -static struct notifier_block __cpuinitdata cpu_nfb = { - .notifier_call = cpu_callback -}; - -static int __initdata nosoftlockup; - -static int __init nosoftlockup_setup(char *str) -{ - nosoftlockup = 1; - return 1; -} -__setup("nosoftlockup", nosoftlockup_setup); - -static int __init spawn_softlockup_task(void) -{ - void *cpu = (void *)(long)smp_processor_id(); - int err; - - if (nosoftlockup) - return 0; - - err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu); - if (err == NOTIFY_BAD) { - BUG(); - return 1; - } - cpu_callback(&cpu_nfb, CPU_ONLINE, cpu); - register_cpu_notifier(&cpu_nfb); - - atomic_notifier_chain_register(&panic_notifier_list, &panic_block); - - return 0; -} -early_initcall(spawn_softlockup_task); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 999bc3fccf47..04bcd8abe09c 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -108,7 +108,7 @@ extern int blk_iopoll_enabled; #endif /* Constants used for minimum and maximum */ -#ifdef CONFIG_DETECT_SOFTLOCKUP +#ifdef CONFIG_LOCKUP_DETECTOR static int sixty = 60; static int neg_one = -1; #endif @@ -703,6 +703,15 @@ static struct ctl_table kern_table[] = { .extra1 = &neg_one, .extra2 = &sixty, }, + { + .procname = "softlockup_panic", + .data = &softlockup_panic, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &one, + }, #endif #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) && !defined(CONFIG_LOCKUP_DETECTOR) { @@ -807,17 +816,6 @@ static struct ctl_table kern_table[] = { .proc_handler = proc_dointvec, }, #endif -#ifdef CONFIG_DETECT_SOFTLOCKUP - { - .procname = "softlockup_panic", - .data = &softlockup_panic, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, -#endif #ifdef CONFIG_DETECT_HUNG_TASK { .procname = "hung_task_panic", -- GitLab From f69bcf60c3f17aa367e16eef7bc6ab001ea6d58a Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Fri, 7 May 2010 17:11:47 -0400 Subject: [PATCH 0044/5312] lockup_detector: Remove nmi_watchdog.c file This file migrated to kernel/watchdog.c and then combined with kernel/softlockup.c. As a result kernel/nmi_watchdog.c is no longer needed. Just remove it. Signed-off-by: Don Zickus Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Cyrill Gorcunov Cc: Eric Paris Cc: Randy Dunlap LKML-Reference: <1273266711-18706-5-git-send-email-dzickus@redhat.com> Signed-off-by: Frederic Weisbecker --- kernel/nmi_watchdog.c | 259 ------------------------------------------ 1 file changed, 259 deletions(-) delete mode 100644 kernel/nmi_watchdog.c diff --git a/kernel/nmi_watchdog.c b/kernel/nmi_watchdog.c deleted file mode 100644 index a79d211c30df..000000000000 --- a/kernel/nmi_watchdog.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Detect Hard Lockups using the NMI - * - * started by Don Zickus, Copyright (C) 2010 Red Hat, Inc. - * - * this code detects hard lockups: incidents in where on a CPU - * the kernel does not respond to anything except NMI. - * - * Note: Most of this code is borrowed heavily from softlockup.c, - * so thanks to Ingo for the initial implementation. - * Some chunks also taken from arch/x86/kernel/apic/nmi.c, thanks - * to those contributors as well. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static DEFINE_PER_CPU(struct perf_event *, nmi_watchdog_ev); -static DEFINE_PER_CPU(int, nmi_watchdog_touch); -static DEFINE_PER_CPU(long, alert_counter); - -static int panic_on_timeout; - -void touch_nmi_watchdog(void) -{ - __raw_get_cpu_var(nmi_watchdog_touch) = 1; - touch_softlockup_watchdog(); -} -EXPORT_SYMBOL(touch_nmi_watchdog); - -void touch_all_nmi_watchdog(void) -{ - int cpu; - - for_each_online_cpu(cpu) - per_cpu(nmi_watchdog_touch, cpu) = 1; - touch_softlockup_watchdog(); -} - -static int __init setup_nmi_watchdog(char *str) -{ - if (!strncmp(str, "panic", 5)) { - panic_on_timeout = 1; - str = strchr(str, ','); - if (!str) - return 1; - ++str; - } - return 1; -} -__setup("nmi_watchdog=", setup_nmi_watchdog); - -struct perf_event_attr wd_hw_attr = { - .type = PERF_TYPE_HARDWARE, - .config = PERF_COUNT_HW_CPU_CYCLES, - .size = sizeof(struct perf_event_attr), - .pinned = 1, - .disabled = 1, -}; - -struct perf_event_attr wd_sw_attr = { - .type = PERF_TYPE_SOFTWARE, - .config = PERF_COUNT_SW_CPU_CLOCK, - .size = sizeof(struct perf_event_attr), - .pinned = 1, - .disabled = 1, -}; - -void wd_overflow(struct perf_event *event, int nmi, - struct perf_sample_data *data, - struct pt_regs *regs) -{ - int cpu = smp_processor_id(); - int touched = 0; - - if (__get_cpu_var(nmi_watchdog_touch)) { - per_cpu(nmi_watchdog_touch, cpu) = 0; - touched = 1; - } - - /* check to see if the cpu is doing anything */ - if (!touched && hw_nmi_is_cpu_stuck(regs)) { - /* - * Ayiee, looks like this CPU is stuck ... - * wait a few IRQs (5 seconds) before doing the oops ... - */ - per_cpu(alert_counter, cpu) += 1; - if (per_cpu(alert_counter, cpu) == 5) { - if (panic_on_timeout) - panic("NMI Watchdog detected LOCKUP on cpu %d", cpu); - else - WARN(1, "NMI Watchdog detected LOCKUP on cpu %d", cpu); - } - } else { - per_cpu(alert_counter, cpu) = 0; - } - - return; -} - -static int enable_nmi_watchdog(int cpu) -{ - struct perf_event *event; - struct perf_event_attr *wd_attr; - - event = per_cpu(nmi_watchdog_ev, cpu); - if (event && event->state > PERF_EVENT_STATE_OFF) - return 0; - - if (event == NULL) { - /* Try to register using hardware perf events first */ - wd_attr = &wd_hw_attr; - wd_attr->sample_period = hw_nmi_get_sample_period(); - event = perf_event_create_kernel_counter(wd_attr, cpu, -1, wd_overflow); - if (IS_ERR(event)) { - /* hardware doesn't exist or not supported, fallback to software events */ - printk(KERN_INFO "nmi_watchdog: hardware not available, trying software events\n"); - wd_attr = &wd_sw_attr; - wd_attr->sample_period = NSEC_PER_SEC; - event = perf_event_create_kernel_counter(wd_attr, cpu, -1, wd_overflow); - if (IS_ERR(event)) { - printk(KERN_ERR "nmi watchdog failed to create perf event on %i: %p\n", cpu, event); - return -1; - } - } - per_cpu(nmi_watchdog_ev, cpu) = event; - } - perf_event_enable(per_cpu(nmi_watchdog_ev, cpu)); - return 0; -} - -static void disable_nmi_watchdog(int cpu) -{ - struct perf_event *event; - - event = per_cpu(nmi_watchdog_ev, cpu); - if (event) { - perf_event_disable(per_cpu(nmi_watchdog_ev, cpu)); - per_cpu(nmi_watchdog_ev, cpu) = NULL; - perf_event_release_kernel(event); - } -} - -#ifdef CONFIG_SYSCTL -/* - * proc handler for /proc/sys/kernel/nmi_watchdog - */ -int nmi_watchdog_enabled; - -int proc_nmi_enabled(struct ctl_table *table, int write, - void __user *buffer, size_t *length, loff_t *ppos) -{ - int cpu; - - if (!write) { - struct perf_event *event; - for_each_online_cpu(cpu) { - event = per_cpu(nmi_watchdog_ev, cpu); - if (event && event->state > PERF_EVENT_STATE_OFF) { - nmi_watchdog_enabled = 1; - break; - } - } - proc_dointvec(table, write, buffer, length, ppos); - return 0; - } - - touch_all_nmi_watchdog(); - proc_dointvec(table, write, buffer, length, ppos); - if (nmi_watchdog_enabled) { - for_each_online_cpu(cpu) - if (enable_nmi_watchdog(cpu)) { - printk(KERN_ERR "NMI watchdog failed configuration, " - " can not be enabled\n"); - } - } else { - for_each_online_cpu(cpu) - disable_nmi_watchdog(cpu); - } - return 0; -} - -#endif /* CONFIG_SYSCTL */ - -/* - * Create/destroy watchdog threads as CPUs come and go: - */ -static int __cpuinit -cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) -{ - int hotcpu = (unsigned long)hcpu; - - switch (action) { - case CPU_UP_PREPARE: - case CPU_UP_PREPARE_FROZEN: - per_cpu(nmi_watchdog_touch, hotcpu) = 0; - break; - case CPU_ONLINE: - case CPU_ONLINE_FROZEN: - if (enable_nmi_watchdog(hotcpu)) - return NOTIFY_BAD; - break; -#ifdef CONFIG_HOTPLUG_CPU - case CPU_UP_CANCELED: - case CPU_UP_CANCELED_FROZEN: - disable_nmi_watchdog(hotcpu); - case CPU_DEAD: - case CPU_DEAD_FROZEN: - break; -#endif /* CONFIG_HOTPLUG_CPU */ - } - return NOTIFY_OK; -} - -static struct notifier_block __cpuinitdata cpu_nfb = { - .notifier_call = cpu_callback -}; - -static int __initdata nonmi_watchdog; - -static int __init nonmi_watchdog_setup(char *str) -{ - nonmi_watchdog = 1; - return 1; -} -__setup("nonmi_watchdog", nonmi_watchdog_setup); - -static int __init spawn_nmi_watchdog_task(void) -{ - void *cpu = (void *)(long)smp_processor_id(); - int err; - - if (nonmi_watchdog) - return 0; - - printk(KERN_INFO "NMI watchdog enabled, takes one hw-pmu counter.\n"); - - err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu); - if (err == NOTIFY_BAD) { - BUG(); - return 1; - } - cpu_callback(&cpu_nfb, CPU_ONLINE, cpu); - register_cpu_notifier(&cpu_nfb); - - return 0; -} -early_initcall(spawn_nmi_watchdog_task); -- GitLab From 7cbb7e7fa46f6e5229438ac9e4a5c72ec0d53e0b Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Fri, 7 May 2010 17:11:48 -0400 Subject: [PATCH 0045/5312] x86: Move trigger_all_cpu_backtrace to its own die_notifier As part of the transition of the nmi watchdog to something more generic, the trigger_all_cpu_backtrace code is getting left behind. Put it in its own die_notifier so it can still be used. V2: - use arch_spin_locks Signed-off-by: Don Zickus Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Cyrill Gorcunov Cc: Eric Paris Cc: Randy Dunlap LKML-Reference: <1273266711-18706-6-git-send-email-dzickus@redhat.com> Signed-off-by: Frederic Weisbecker --- arch/x86/kernel/apic/hw_nmi.c | 65 +++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c index 79425f96fcee..8c3edfb89c2b 100644 --- a/arch/x86/kernel/apic/hw_nmi.c +++ b/arch/x86/kernel/apic/hw_nmi.c @@ -17,6 +17,10 @@ #include #include #include +#include +#include +#include + #include #include @@ -54,20 +58,6 @@ int hw_nmi_is_cpu_stuck(struct pt_regs *regs) unsigned int sum; int cpu = smp_processor_id(); - /* FIXME: cheap hack for this check, probably should get its own - * die_notifier handler - */ - if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) { - static DEFINE_SPINLOCK(lock); /* Serialise the printks */ - - spin_lock(&lock); - printk(KERN_WARNING "NMI backtrace for cpu %d\n", cpu); - show_regs(regs); - dump_stack(); - spin_unlock(&lock); - cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask)); - } - /* if we are doing an mce, just assume the cpu is not stuck */ /* Could check oops_in_progress here too, but it's safer not to */ if (mce_in_progress()) @@ -109,6 +99,53 @@ void arch_trigger_all_cpu_backtrace(void) mdelay(1); } } + +static int __kprobes +arch_trigger_all_cpu_backtrace_handler(struct notifier_block *self, + unsigned long cmd, void *__args) +{ + struct die_args *args = __args; + struct pt_regs *regs; + int cpu = smp_processor_id(); + + switch (cmd) { + case DIE_NMI: + case DIE_NMI_IPI: + break; + + default: + return NOTIFY_DONE; + } + + regs = args->regs; + + if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) { + static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED; + + arch_spin_lock(&lock); + printk(KERN_WARNING "NMI backtrace for cpu %d\n", cpu); + show_regs(regs); + dump_stack(); + arch_spin_unlock(&lock); + cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask)); + return NOTIFY_STOP; + } + + return NOTIFY_DONE; +} + +static __read_mostly struct notifier_block backtrace_notifier = { + .notifier_call = arch_trigger_all_cpu_backtrace_handler, + .next = NULL, + .priority = 1 +}; + +static int __init register_trigger_all_cpu_backtrace(void) +{ + register_die_notifier(&backtrace_notifier); + return 0; +} +early_initcall(register_trigger_all_cpu_backtrace); #endif /* STUB calls to mimic old nmi_watchdog behaviour */ -- GitLab From 10f9014912a2b1cb59c39cdea777e6d9afa8f17e Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Fri, 7 May 2010 17:11:49 -0400 Subject: [PATCH 0046/5312] x86: Cleanup hw_nmi.c cruft The design of the hardlockup watchdog has changed and cruft was left behind in the hw_nmi.c file. Just remove the code that isn't used anymore. Signed-off-by: Don Zickus Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Cyrill Gorcunov Cc: Eric Paris Cc: Randy Dunlap LKML-Reference: <1273266711-18706-7-git-send-email-dzickus@redhat.com> Signed-off-by: Frederic Weisbecker --- arch/x86/kernel/apic/hw_nmi.c | 58 ----------------------------------- 1 file changed, 58 deletions(-) diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c index 8c3edfb89c2b..3b40082f0371 100644 --- a/arch/x86/kernel/apic/hw_nmi.c +++ b/arch/x86/kernel/apic/hw_nmi.c @@ -9,74 +9,16 @@ * */ -#include -#include #include -#include -#include -#include -#include -#include #include #include #include - - #include #include /* For reliability, we're prepared to waste bits here. */ static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly; -static DEFINE_PER_CPU(unsigned, last_irq_sum); - -/* - * Take the local apic timer and PIT/HPET into account. We don't - * know which one is active, when we have highres/dyntick on - */ -static inline unsigned int get_timer_irqs(int cpu) -{ - unsigned int irqs = per_cpu(irq_stat, cpu).irq0_irqs; - -#if defined(CONFIG_X86_LOCAL_APIC) - irqs += per_cpu(irq_stat, cpu).apic_timer_irqs; -#endif - - return irqs; -} - -static inline int mce_in_progress(void) -{ -#if defined(CONFIG_X86_MCE) - return atomic_read(&mce_entry) > 0; -#endif - return 0; -} - -int hw_nmi_is_cpu_stuck(struct pt_regs *regs) -{ - unsigned int sum; - int cpu = smp_processor_id(); - - /* if we are doing an mce, just assume the cpu is not stuck */ - /* Could check oops_in_progress here too, but it's safer not to */ - if (mce_in_progress()) - return 0; - - /* We determine if the cpu is stuck by checking whether any - * interrupts have happened since we last checked. Of course - * an nmi storm could create false positives, but the higher - * level logic should account for that - */ - sum = get_timer_irqs(cpu); - if (__get_cpu_var(last_irq_sum) == sum) { - return 1; - } else { - __get_cpu_var(last_irq_sum) = sum; - return 0; - } -} - u64 hw_nmi_get_sample_period(void) { return (u64)(cpu_khz) * 1000 * 60; -- GitLab From d7c547335fa6b0090fa09c46ea0e965ac273a27e Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Fri, 7 May 2010 17:11:51 -0400 Subject: [PATCH 0047/5312] lockup_detector: Separate touch_nmi_watchdog code path from touch_watchdog When I combined the nmi_watchdog (hardlockup) and softlockup code, I also combined the paths the touch_watchdog and touch_nmi_watchdog took. This may not be the best idea as pointed out by Frederic W., that the touch_watchdog case probably should not reset the hardlockup count. Therefore the patch below falls back to the previous idea of keeping the touch_nmi_watchdog a superset of the touch_watchdog case. Signed-off-by: Don Zickus Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Cyrill Gorcunov Cc: Eric Paris Cc: Randy Dunlap LKML-Reference: <1273266711-18706-9-git-send-email-dzickus@redhat.com> Signed-off-by: Frederic Weisbecker --- kernel/watchdog.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/kernel/watchdog.c b/kernel/watchdog.c index f1541b7e3244..57b8e2c25eda 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -31,6 +31,7 @@ int watchdog_enabled; int __read_mostly softlockup_thresh = 60; static DEFINE_PER_CPU(unsigned long, watchdog_touch_ts); +static DEFINE_PER_CPU(bool, watchdog_nmi_touch); static DEFINE_PER_CPU(struct task_struct *, softlockup_watchdog); static DEFINE_PER_CPU(struct hrtimer, watchdog_hrtimer); static DEFINE_PER_CPU(bool, softlockup_touch_sync); @@ -139,6 +140,7 @@ void touch_all_softlockup_watchdogs(void) void touch_nmi_watchdog(void) { + __get_cpu_var(watchdog_nmi_touch) = true; touch_softlockup_watchdog(); } EXPORT_SYMBOL(touch_nmi_watchdog); @@ -201,10 +203,9 @@ void watchdog_overflow_callback(struct perf_event *event, int nmi, struct pt_regs *regs) { int this_cpu = smp_processor_id(); - unsigned long touch_ts = per_cpu(watchdog_touch_ts, this_cpu); - if (touch_ts == 0) { - __touch_watchdog(); + if (__get_cpu_var(watchdog_nmi_touch) == true) { + __get_cpu_var(watchdog_nmi_touch) = false; return; } -- GitLab From 89d7ce2a2178e7f562f608b466a18c8c2ece87af Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 13 May 2010 00:27:20 +0200 Subject: [PATCH 0048/5312] lockup_detector: Make BOOTPARAM_SOFTLOCKUP_PANIC depend on LOCKUP_DETECTOR Panic on softlockups was still depending on the softlockup detector. But the latter has been merged into the lockup detector now. Let's update this config dependency. Signed-off-by: Frederic Weisbecker Cc: Don Zickus Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Cyrill Gorcunov Cc: Eric Paris Cc: Randy Dunlap --- lib/Kconfig.debug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 49e285dcaf57..755713a359e2 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -195,7 +195,7 @@ config LOCKUP_DETECTOR config BOOTPARAM_SOFTLOCKUP_PANIC bool "Panic (Reboot) On Soft Lockups" - depends on DETECT_SOFTLOCKUP + depends on LOCKUP_DETECTOR help Say Y here to enable the kernel to panic on "soft lockups", which are bugs that cause the kernel to loop in kernel -- GitLab From 19cc36c0f0457e5c6629ec24036fbbe8255c88ec Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 13 May 2010 02:30:49 +0200 Subject: [PATCH 0049/5312] lockup_detector: Fix forgotten config conversion Fix forgotten CONFIG_DETECT_SOFTLOCKUP -> CONFIG_LOCKUP_DETECTOR in sched.h Fixes: arch/x86/built-in.o: In function `touch_nmi_watchdog': (.text+0x1bd59): undefined reference to `touch_softlockup_watchdog' kernel/built-in.o: In function `show_state_filter': (.text+0x10d01): undefined reference to `touch_all_softlockup_watchdogs' kernel/built-in.o: In function `sched_clock_idle_wakeup_event': (.text+0x362f9): undefined reference to `touch_softlockup_watchdog' kernel/built-in.o: In function `timekeeping_resume': timekeeping.c:(.text+0x38757): undefined reference to `touch_softlockup_watchdog' kernel/built-in.o: In function `tick_nohz_handler': tick-sched.c:(.text+0x3e5b9): undefined reference to `touch_softlockup_watchdog' kernel/built-in.o: In function `tick_sched_timer': tick-sched.c:(.text+0x3e671): undefined reference to `touch_softlockup_watchdog' kernel/built-in.o: In function `tick_check_idle': (.text+0x3e90b): undefined reference to `touch_softlockup_watchdog' Signed-off-by: Frederic Weisbecker Cc: Don Zickus Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Cyrill Gorcunov Cc: Eric Paris Cc: Randy Dunlap --- include/linux/sched.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 33f9b2ad0bbb..3958e0cd24f7 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -311,7 +311,7 @@ extern void scheduler_tick(void); extern void sched_show_task(struct task_struct *p); -#ifdef CONFIG_DETECT_SOFTLOCKUP +#ifdef CONFIG_LOCKUP_DETECTOR extern void touch_softlockup_watchdog(void); extern void touch_softlockup_watchdog_sync(void); extern void touch_all_softlockup_watchdogs(void); -- GitLab From 0167c781907fcdc3e1f144ef5ce31d402c91eb94 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 13 May 2010 08:53:33 +0200 Subject: [PATCH 0050/5312] watchdog: Export touch_softlockup_watchdog There are modules that rely on it: ERROR: "touch_softlockup_watchdog" [drivers/video/nvidia/nvidiafb.ko] undefined! Cc: Frederic Weisbecker Cc: Don Zickus Cc: Peter Zijlstra Cc: Cyrill Gorcunov LKML-Reference: <1273713674-8434-1-git-send-regression-fweisbec@gmail.com> Signed-off-by: Ingo Molnar --- kernel/watchdog.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 57b8e2c25eda..be5e74e62be6 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -124,6 +124,7 @@ void touch_softlockup_watchdog(void) { __get_cpu_var(watchdog_touch_ts) = 0; } +EXPORT_SYMBOL(touch_softlockup_watchdog); void touch_all_softlockup_watchdogs(void) { -- GitLab From 5e85391b3badd3f0e50ebdd0cafe0202a979f73a Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 13 May 2010 09:12:39 +0200 Subject: [PATCH 0051/5312] x86, watchdog: Fix build error in hw_nmi.c On some configs the following build error triggers: arch/x86/kernel/apic/hw_nmi.c:35: error: 'apic' undeclared (first use in this function) arch/x86/kernel/apic/hw_nmi.c:35: error: (Each undeclared identifier is reported only once arch/x86/kernel/apic/hw_nmi.c:35: error: for each function it appears in.) Because asm/apic.h was only included implicitly. Include it explicitly. Cc: Frederic Weisbecker Cc: Don Zickus Cc: Peter Zijlstra Cc: Cyrill Gorcunov LKML-Reference: <1273713674-8434-1-git-send-regression-fweisbec@gmail.com> Signed-off-by: Ingo Molnar --- arch/x86/kernel/apic/hw_nmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c index 3b40082f0371..cefd6942f0e9 100644 --- a/arch/x86/kernel/apic/hw_nmi.c +++ b/arch/x86/kernel/apic/hw_nmi.c @@ -8,6 +8,7 @@ * Bits copied from original nmi.c file * */ +#include #include #include -- GitLab From bd0f9a3ff48ec4bc2010e74b77c9db45ccc48d0f Mon Sep 17 00:00:00 2001 From: Hans Ulli Kroll Date: Thu, 13 May 2010 06:22:40 +0100 Subject: [PATCH 0052/5312] ARM: 6128/1: Gemini: add support for Wiligear WBD-111 added base support for the Wiligear WBD-111 supported devices on SoC - GPIO with led und keys - UART - PFLASH, set fixed partition table Signed-off-by: Imre Kaloz Signed-off-by: Hans Ulli Kroll Signed-off-by: Russell King --- arch/arm/mach-gemini/Kconfig | 7 ++ arch/arm/mach-gemini/Makefile | 1 + arch/arm/mach-gemini/board-wbd111.c | 143 ++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 arch/arm/mach-gemini/board-wbd111.c diff --git a/arch/arm/mach-gemini/Kconfig b/arch/arm/mach-gemini/Kconfig index 515b75cf2e8b..4de67ce7c192 100644 --- a/arch/arm/mach-gemini/Kconfig +++ b/arch/arm/mach-gemini/Kconfig @@ -9,6 +9,13 @@ config MACH_RUT100 Say Y here if you intend to run this kernel on a Teltonika 3G Router RUT100. +config MACH_WBD111 + bool "Wiliboard WBD-111" + select GEMINI_MEM_SWAP + help + Say Y here if you intend to run this kernel on a + Wiliboard WBD-111. + endmenu config GEMINI_MEM_SWAP diff --git a/arch/arm/mach-gemini/Makefile b/arch/arm/mach-gemini/Makefile index 719505b81821..3997487f7b31 100644 --- a/arch/arm/mach-gemini/Makefile +++ b/arch/arm/mach-gemini/Makefile @@ -8,3 +8,4 @@ obj-y := irq.o mm.o time.o devices.o gpio.o # Board-specific support obj-$(CONFIG_MACH_RUT100) += board-rut1xx.o +obj-$(CONFIG_MACH_WBD111) += board-wbd111.o diff --git a/arch/arm/mach-gemini/board-wbd111.c b/arch/arm/mach-gemini/board-wbd111.c new file mode 100644 index 000000000000..36538c15b3c4 --- /dev/null +++ b/arch/arm/mach-gemini/board-wbd111.c @@ -0,0 +1,143 @@ +/* + * Support for Wiliboard WBD-111 + * + * Copyright (C) 2009 Imre Kaloz + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "common.h" + +static struct gpio_keys_button wbd111_keys[] = { + { + .code = KEY_SETUP, + .gpio = 5, + .active_low = 1, + .desc = "reset", + .type = EV_KEY, + }, +}; + +static struct gpio_keys_platform_data wbd111_keys_data = { + .buttons = wbd111_keys, + .nbuttons = ARRAY_SIZE(wbd111_keys), +}; + +static struct platform_device wbd111_keys_device = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &wbd111_keys_data, + }, +}; + +static struct gpio_led wbd111_leds[] = { + { + .name = "L3red", + .gpio = 1, + }, + { + .name = "L4green", + .gpio = 2, + }, + { + .name = "L4red", + .gpio = 3, + }, + { + .name = "L3green", + .gpio = 5, + }, +}; + +static struct gpio_led_platform_data wbd111_leds_data = { + .num_leds = ARRAY_SIZE(wbd111_leds), + .leds = wbd111_leds, +}; + +static struct platform_device wbd111_leds_device = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &wbd111_leds_data, + }, +}; + +static struct sys_timer wbd111_timer = { + .init = gemini_timer_init, +}; + +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition wbd111_partitions[] = { + { + .name = "RedBoot", + .offset = 0, + .size = 0x020000, + .mask_flags = MTD_WRITEABLE, + } , { + .name = "kernel", + .offset = 0x020000, + .size = 0x100000, + } , { + .name = "rootfs", + .offset = 0x120000, + .size = 0x6a0000, + } , { + .name = "VCTL", + .offset = 0x7c0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, + } , { + .name = "cfg", + .offset = 0x7d0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, + } , { + .name = "FIS", + .offset = 0x7e0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, + } +}; +#define wbd111_num_partitions ARRAY_SIZE(wbd111_partitions) +#else +#define wbd111_partitions NULL +#define wbd111_num_partitions 0 +#endif /* CONFIG_MTD_PARTITIONS */ + +static void __init wbd111_init(void) +{ + gemini_gpio_init(); + platform_register_uart(); + platform_register_pflash(SZ_8M, wbd111_partitions, + wbd111_num_partitions); + platform_device_register(&wbd111_leds_device); + platform_device_register(&wbd111_keys_device); +} + +MACHINE_START(WBD111, "Wiliboard WBD-111") + .phys_io = 0x7fffc000, + .io_pg_offst = ((0xffffc000) >> 18) & 0xfffc, + .boot_params = 0x100, + .map_io = gemini_map_io, + .init_irq = gemini_init_irq, + .timer = &wbd111_timer, + .init_machine = wbd111_init, +MACHINE_END -- GitLab From 6a5f0d3a7800caf74078039d66460466da487b10 Mon Sep 17 00:00:00 2001 From: Hans Ulli Kroll Date: Thu, 13 May 2010 06:34:29 +0100 Subject: [PATCH 0053/5312] ARM: 6129/1: Gemini: add support for Wiliboard WBD-222 Depends on patch # 6128 Add support for Wiliboard WBD-222. supported devices on SoC - GPIO with led und keys - UART - PFLASH, set fixed partition table Signed-off-by: Imre Kaloz Signed-off-by: Hans Ulli Kroll Signed-off-by: Russell King --- arch/arm/mach-gemini/Kconfig | 7 ++ arch/arm/mach-gemini/Makefile | 1 + arch/arm/mach-gemini/board-wbd222.c | 143 ++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 arch/arm/mach-gemini/board-wbd222.c diff --git a/arch/arm/mach-gemini/Kconfig b/arch/arm/mach-gemini/Kconfig index 4de67ce7c192..799750032ef6 100644 --- a/arch/arm/mach-gemini/Kconfig +++ b/arch/arm/mach-gemini/Kconfig @@ -16,6 +16,13 @@ config MACH_WBD111 Say Y here if you intend to run this kernel on a Wiliboard WBD-111. +config MACH_WBD222 + bool "Wiliboard WBD-222" + select GEMINI_MEM_SWAP + help + Say Y here if you intend to run this kernel on a + Wiliboard WBD-222. + endmenu config GEMINI_MEM_SWAP diff --git a/arch/arm/mach-gemini/Makefile b/arch/arm/mach-gemini/Makefile index 3997487f7b31..8e02c471acd4 100644 --- a/arch/arm/mach-gemini/Makefile +++ b/arch/arm/mach-gemini/Makefile @@ -9,3 +9,4 @@ obj-y := irq.o mm.o time.o devices.o gpio.o # Board-specific support obj-$(CONFIG_MACH_RUT100) += board-rut1xx.o obj-$(CONFIG_MACH_WBD111) += board-wbd111.o +obj-$(CONFIG_MACH_WBD222) += board-wbd222.o diff --git a/arch/arm/mach-gemini/board-wbd222.c b/arch/arm/mach-gemini/board-wbd222.c new file mode 100644 index 000000000000..ece8b4c65110 --- /dev/null +++ b/arch/arm/mach-gemini/board-wbd222.c @@ -0,0 +1,143 @@ +/* + * Support for Wiliboard WBD-222 + * + * Copyright (C) 2009 Imre Kaloz + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "common.h" + +static struct gpio_keys_button wbd222_keys[] = { + { + .code = KEY_SETUP, + .gpio = 5, + .active_low = 1, + .desc = "reset", + .type = EV_KEY, + }, +}; + +static struct gpio_keys_platform_data wbd222_keys_data = { + .buttons = wbd222_keys, + .nbuttons = ARRAY_SIZE(wbd222_keys), +}; + +static struct platform_device wbd222_keys_device = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &wbd222_keys_data, + }, +}; + +static struct gpio_led wbd222_leds[] = { + { + .name = "L3red", + .gpio = 1, + }, + { + .name = "L4green", + .gpio = 2, + }, + { + .name = "L4red", + .gpio = 3, + }, + { + .name = "L3green", + .gpio = 5, + }, +}; + +static struct gpio_led_platform_data wbd222_leds_data = { + .num_leds = ARRAY_SIZE(wbd222_leds), + .leds = wbd222_leds, +}; + +static struct platform_device wbd222_leds_device = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &wbd222_leds_data, + }, +}; + +static struct sys_timer wbd222_timer = { + .init = gemini_timer_init, +}; + +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition wbd222_partitions[] = { + { + .name = "RedBoot", + .offset = 0, + .size = 0x020000, + .mask_flags = MTD_WRITEABLE, + } , { + .name = "kernel", + .offset = 0x020000, + .size = 0x100000, + } , { + .name = "rootfs", + .offset = 0x120000, + .size = 0x6a0000, + } , { + .name = "VCTL", + .offset = 0x7c0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, + } , { + .name = "cfg", + .offset = 0x7d0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, + } , { + .name = "FIS", + .offset = 0x7e0000, + .size = 0x010000, + .mask_flags = MTD_WRITEABLE, + } +}; +#define wbd222_num_partitions ARRAY_SIZE(wbd222_partitions) +#else +#define wbd222_partitions NULL +#define wbd222_num_partitions 0 +#endif /* CONFIG_MTD_PARTITIONS */ + +static void __init wbd222_init(void) +{ + gemini_gpio_init(); + platform_register_uart(); + platform_register_pflash(SZ_8M, wbd222_partitions, + wbd222_num_partitions); + platform_device_register(&wbd222_leds_device); + platform_device_register(&wbd222_keys_device); +} + +MACHINE_START(WBD222, "Wiliboard WBD-222") + .phys_io = 0x7fffc000, + .io_pg_offst = ((0xffffc000) >> 18) & 0xfffc, + .boot_params = 0x100, + .map_io = gemini_map_io, + .init_irq = gemini_init_irq, + .timer = &wbd222_timer, + .init_machine = wbd222_init, +MACHINE_END -- GitLab From a21e0030d659476b4ae48aab7846fa01e6ee0a71 Mon Sep 17 00:00:00 2001 From: Hans Ulli Kroll Date: Thu, 13 May 2010 06:37:26 +0100 Subject: [PATCH 0054/5312] ARM: 6130/1: Gemini: add support for Raidsonic IB4220 depends on patch # 6128, 6129 Add support for Nasbox IB4220 from Raidsonic. supported devices on SoC - GPIO with led und keys - UART - PFLASH, set fixed partition table Signed-off-by: Janos Laube Signed-off-by: Hans Ulli Kroll Signed-off-by: Russell King --- arch/arm/mach-gemini/Kconfig | 7 ++ arch/arm/mach-gemini/Makefile | 1 + arch/arm/mach-gemini/board-nas4220b.c | 111 ++++++++++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 arch/arm/mach-gemini/board-nas4220b.c diff --git a/arch/arm/mach-gemini/Kconfig b/arch/arm/mach-gemini/Kconfig index 799750032ef6..6f066ee4bf24 100644 --- a/arch/arm/mach-gemini/Kconfig +++ b/arch/arm/mach-gemini/Kconfig @@ -2,6 +2,13 @@ if ARCH_GEMINI menu "Cortina Systems Gemini Implementations" +config MACH_NAS4220B + bool "Raidsonic NAS-4220-B" + select GEMINI_MEM_SWAP + help + Say Y here if you intend to run this kernel on a + Raidsonic NAS-4220-B. + config MACH_RUT100 bool "Teltonika RUT100" select GEMINI_MEM_SWAP diff --git a/arch/arm/mach-gemini/Makefile b/arch/arm/mach-gemini/Makefile index 8e02c471acd4..c5b24b95a76e 100644 --- a/arch/arm/mach-gemini/Makefile +++ b/arch/arm/mach-gemini/Makefile @@ -7,6 +7,7 @@ obj-y := irq.o mm.o time.o devices.o gpio.o # Board-specific support +obj-$(CONFIG_MACH_NAS4220B) += board-nas4220b.o obj-$(CONFIG_MACH_RUT100) += board-rut1xx.o obj-$(CONFIG_MACH_WBD111) += board-wbd111.o obj-$(CONFIG_MACH_WBD222) += board-wbd222.o diff --git a/arch/arm/mach-gemini/board-nas4220b.c b/arch/arm/mach-gemini/board-nas4220b.c new file mode 100644 index 000000000000..01f1d6daab44 --- /dev/null +++ b/arch/arm/mach-gemini/board-nas4220b.c @@ -0,0 +1,111 @@ +/* + * Support for Raidsonic NAS-4220-B + * + * Copyright (C) 2009 Janos Laube + * + * based on rut1xx.c + * Copyright (C) 2008 Paulius Zaleckas + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "common.h" + +static struct sys_timer ib4220b_timer = { + .init = gemini_timer_init, +}; + +static struct gpio_led ib4220b_leds[] = { + { + .name = "nas4220b:orange:hdd", + .default_trigger = "none", + .gpio = 60, + }, + { + .name = "nas4220b:green:os", + .default_trigger = "heartbeat", + .gpio = 62, + }, +}; + +static struct gpio_led_platform_data ib4220b_leds_data = { + .num_leds = ARRAY_SIZE(ib4220b_leds), + .leds = ib4220b_leds, +}; + +static struct platform_device ib4220b_led_device = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &ib4220b_leds_data, + }, +}; + +static struct gpio_keys_button ib4220b_keys[] = { + { + .code = KEY_SETUP, + .gpio = 61, + .active_low = 1, + .desc = "Backup Button", + .type = EV_KEY, + }, + { + .code = KEY_RESTART, + .gpio = 63, + .active_low = 1, + .desc = "Softreset Button", + .type = EV_KEY, + }, +}; + +static struct gpio_keys_platform_data ib4220b_keys_data = { + .buttons = ib4220b_keys, + .nbuttons = ARRAY_SIZE(ib4220b_keys), +}; + +static struct platform_device ib4220b_key_device = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &ib4220b_keys_data, + }, +}; + +static void __init ib4220b_init(void) +{ + gemini_gpio_init(); + platform_register_uart(); + platform_register_pflash(SZ_16M, NULL, 0); + platform_device_register(&ib4220b_led_device); + platform_device_register(&ib4220b_key_device); +} + +MACHINE_START(NAS4220B, "Raidsonic NAS IB-4220-B") + .phys_io = 0x7fffc000, + .io_pg_offst = ((0xffffc000) >> 18) & 0xfffc, + .boot_params = 0x100, + .map_io = gemini_map_io, + .init_irq = gemini_init_irq, + .timer = &ib4220b_timer, + .init_machine = ib4220b_init, +MACHINE_END -- GitLab From 162500b3a3ff39d941d29db49b41a16667ae44f0 Mon Sep 17 00:00:00 2001 From: Hans Ulli Kroll Date: Thu, 13 May 2010 06:43:59 +0100 Subject: [PATCH 0055/5312] ARM: 6131/1: MAINTAINERS: update for ARM/Gemini Patch #6128, #6129 and #6130 and this one are pullable on git://git.berlios.de/gemini-board gemini_updates Modified MAINTAINERS to set new maintainer for Gemini SoC Acked-by: Paulius Zaleckas Signed-off-by: Hans Ulli Kroll Signed-off-by: Russell King --- MAINTAINERS | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 382eaa4d0068..f3225b58369b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -620,10 +620,10 @@ M: Richard Purdie S: Maintained ARM/CORTINA SYSTEMS GEMINI ARM ARCHITECTURE -M: Paulius Zaleckas +M: Hans Ulli Kroll L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -T: git git://gitorious.org/linux-gemini/mainline.git -S: Odd Fixes +T: git git://git.berlios.de/gemini-board +S: Maintained F: arch/arm/mach-gemini/ ARM/EBSA110 MACHINE SUPPORT @@ -645,9 +645,10 @@ T: topgit git://git.openezx.org/openezx.git F: arch/arm/mach-pxa/ezx.c ARM/FARADAY FA526 PORT -M: Paulius Zaleckas +M: Hans Ulli Kroll L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Odd Fixes +S: Maintained +T: git://git.berlios.de/gemini-board F: arch/arm/mm/*-fa* ARM/FOOTBRIDGE ARCHITECTURE -- GitLab From e16bb1d7fe07609bc8b0e4c043eff2f47ada78d8 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 15 May 2010 22:30:22 +0200 Subject: [PATCH 0056/5312] lockup_detector: Update some config We kept CONFIG_DETECT_SOFTLOCKUP around for compatibility with older configs. But it was enabled by default if CONFIG_DEBUG_KERNEL. So if we want to enable CONFIG_LOCKUP_DETECTOR on configs that had CONFIG_DETECT_SOFTLOCKUP, all we need is to have the same enabling by default if CONFIG_DEBUG_KERNEL. We can then remove CONFIG_DETECT_SOFTLOCKUP directly. So tag CONFIG_LOCKUP_DETECTOR as default y. This is what we want for most serious kernel debugging anyway. And also forbid the lockup detector in S390 as it was for the previous softlockup detector, event though the true reason for that is not outlined. Signed-off-by: Frederic Weisbecker Cc: Ingo Molnar Cc: Don Zickus Cc: Peter Zijlstra Cc: Cyrill Gorcunov --- lib/Kconfig.debug | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 755713a359e2..3a18b0b856ce 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -152,29 +152,10 @@ config DEBUG_SHIRQ Drivers ought to be able to handle interrupts coming in at those points; some don't and need to be caught. -config DETECT_SOFTLOCKUP - bool - depends on DEBUG_KERNEL && !S390 - default y - help - Say Y here to enable the kernel to detect "soft lockups", - which are bugs that cause the kernel to loop in kernel - mode for more than 60 seconds, without giving other tasks a - chance to run. - - When a soft-lockup is detected, the kernel will print the - current stack trace (which you should report), but the - system will stay locked up. This feature has negligible - overhead. - - (Note that "hard lockups" are separate type of bugs that - can be detected via the NMI-watchdog, on platforms that - support it.) - config LOCKUP_DETECTOR bool "Detect Hard and Soft Lockups" - depends on DEBUG_KERNEL - default DETECT_SOFTLOCKUP + depends on DEBUG_KERNEL && !S390 + default y help Say Y here to enable the kernel to act as a watchdog to detect hard and soft lockups. @@ -212,7 +193,7 @@ config BOOTPARAM_SOFTLOCKUP_PANIC config BOOTPARAM_SOFTLOCKUP_PANIC_VALUE int - depends on DETECT_SOFTLOCKUP + depends on LOCKUP_DETECTOR range 0 1 default 0 if !BOOTPARAM_SOFTLOCKUP_PANIC default 1 if BOOTPARAM_SOFTLOCKUP_PANIC -- GitLab From c01d4323309a90a298fd81cf3a059ee1b12be2e9 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 15 May 2010 22:57:48 +0200 Subject: [PATCH 0057/5312] lockup_detector: Adapt CONFIG_PERF_EVENT_NMI to other archs CONFIG_PERF_EVENT_NMI is something that need to be enabled from the arch. This is fine on x86 as PERF_EVENTS is builtin but if other archs select it, they will need to handle the PERF_EVENTS dependency. Instead, handle the dependency in the generic layer: - archs need to tell what they support through HAVE_PERF_EVENTS_NMI - Enable magically PERF_EVENTS_NMI if we have PERF_EVENTS and HAVE_PERF_EVENTS_NMI. Signed-off-by: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Don Zickus Cc: Cyrill Gorcunov --- arch/Kconfig | 3 +++ arch/x86/Kconfig | 2 +- init/Kconfig | 3 +-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index e5eb1337a537..89b0efb50948 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -145,4 +145,7 @@ config HAVE_HW_BREAKPOINT config HAVE_USER_RETURN_NOTIFIER bool +config HAVE_PERF_EVENTS_NMI + bool + source "kernel/gcov/Kconfig" diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 3cb28cd1f551..3cb5bb02172b 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -54,7 +54,7 @@ config X86 select HAVE_KERNEL_LZO select HAVE_HW_BREAKPOINT select PERF_EVENTS - select PERF_EVENTS_NMI + select HAVE_PERF_EVENTS_NMI select ANON_INODES select HAVE_ARCH_KMEMCHECK select HAVE_USER_RETURN_NOTIFIER diff --git a/init/Kconfig b/init/Kconfig index e44e25422f22..ab733c32292c 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -943,8 +943,7 @@ config PERF_USE_VMALLOC See tools/perf/design.txt for details config PERF_EVENTS_NMI - bool - depends on PERF_EVENTS + def_bool PERF_EVENTS && HAVE_PERF_EVENTS_NMI help System hardware can generate an NMI using the perf event subsystem. Also has support for calculating CPU cycle events -- GitLab From 23637d477c1f53acbb176a02c241d60a25888fae Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 15 May 2010 23:15:20 +0200 Subject: [PATCH 0058/5312] lockup_detector: Introduce CONFIG_HARDLOCKUP_DETECTOR This new config is deemed to simplify even more the lockup detector dependencies and can make it easier to bring a smooth sorting between archs that support the new generic lockup detector and those that still have their own, especially for those that are in the middle of this migration. Instead of checking whether we have CONFIG_LOCKUP_DETECTOR + CONFIG_PERF_EVENTS_NMI each time an arch wants to know if it needs to build its own lockup detector, take a shortcut with this new config. It is enabled only if the hardlockup detection part of the whole lockup detector is on. Signed-off-by: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Don Zickus Cc: Cyrill Gorcunov --- arch/Kconfig | 4 ++++ init/Kconfig | 7 ------- kernel/watchdog.c | 14 +++++++------- lib/Kconfig.debug | 3 +++ 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index 89b0efb50948..35084f280087 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -147,5 +147,9 @@ config HAVE_USER_RETURN_NOTIFIER config HAVE_PERF_EVENTS_NMI bool + help + System hardware can generate an NMI using the perf event + subsystem. Also has support for calculating CPU cycle events + to determine how many clock cycles in a given period. source "kernel/gcov/Kconfig" diff --git a/init/Kconfig b/init/Kconfig index ab733c32292c..eb77e8ccde1c 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -942,13 +942,6 @@ config PERF_USE_VMALLOC help See tools/perf/design.txt for details -config PERF_EVENTS_NMI - def_bool PERF_EVENTS && HAVE_PERF_EVENTS_NMI - help - System hardware can generate an NMI using the perf event - subsystem. Also has support for calculating CPU cycle events - to determine how many clock cycles in a given period. - menu "Kernel Performance Events And Counters" config PERF_EVENTS diff --git a/kernel/watchdog.c b/kernel/watchdog.c index be5e74e62be6..83fb63155cbc 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -37,7 +37,7 @@ static DEFINE_PER_CPU(struct hrtimer, watchdog_hrtimer); static DEFINE_PER_CPU(bool, softlockup_touch_sync); static DEFINE_PER_CPU(bool, hard_watchdog_warn); static DEFINE_PER_CPU(bool, soft_watchdog_warn); -#ifdef CONFIG_PERF_EVENTS_NMI +#ifdef CONFIG_HARDLOCKUP_DETECTOR static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts); static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved); static DEFINE_PER_CPU(struct perf_event *, watchdog_ev); @@ -51,7 +51,7 @@ static int __initdata no_watchdog; /* * Should we panic when a soft-lockup or hard-lockup occurs: */ -#ifdef CONFIG_PERF_EVENTS_NMI +#ifdef CONFIG_HARDLOCKUP_DETECTOR static int hardlockup_panic; static int __init hardlockup_panic_setup(char *str) @@ -152,7 +152,7 @@ void touch_softlockup_watchdog_sync(void) __raw_get_cpu_var(watchdog_touch_ts) = 0; } -#ifdef CONFIG_PERF_EVENTS_NMI +#ifdef CONFIG_HARDLOCKUP_DETECTOR /* watchdog detector functions */ static int is_hardlockup(int cpu) { @@ -189,7 +189,7 @@ static struct notifier_block panic_block = { .notifier_call = watchdog_panic, }; -#ifdef CONFIG_PERF_EVENTS_NMI +#ifdef CONFIG_HARDLOCKUP_DETECTOR static struct perf_event_attr wd_hw_attr = { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES, @@ -239,7 +239,7 @@ static void watchdog_interrupt_count(void) } #else static inline void watchdog_interrupt_count(void) { return; } -#endif /* CONFIG_PERF_EVENTS_NMI */ +#endif /* CONFIG_HARDLOCKUP_DETECTOR */ /* watchdog kicker functions */ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) @@ -342,7 +342,7 @@ static int watchdog(void *__bind_cpu) } -#ifdef CONFIG_PERF_EVENTS_NMI +#ifdef CONFIG_HARDLOCKUP_DETECTOR static int watchdog_nmi_enable(int cpu) { struct perf_event_attr *wd_attr; @@ -393,7 +393,7 @@ static void watchdog_nmi_disable(int cpu) #else static int watchdog_nmi_enable(int cpu) { return 0; } static void watchdog_nmi_disable(int cpu) { return; } -#endif /* CONFIG_PERF_EVENTS_NMI */ +#endif /* CONFIG_HARDLOCKUP_DETECTOR */ /* prepare/enable/disable routines */ static int watchdog_prepare_cpu(int cpu) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 3a18b0b856ce..e65e47d5c5e6 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -174,6 +174,9 @@ config LOCKUP_DETECTOR generate interrupts and kick the watchdog task every 10-12 seconds. An NMI is generated every 60 seconds or so to check for hardlockups. +config HARDLOCKUP_DETECTOR + def_bool LOCKUP_DETECTOR && PERF_EVENTS && HAVE_PERF_EVENTS_NMI + config BOOTPARAM_SOFTLOCKUP_PANIC bool "Panic (Reboot) On Soft Lockups" depends on LOCKUP_DETECTOR -- GitLab From cafcd80d216bc2136b8edbb794327e495792c666 Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Fri, 14 May 2010 11:11:21 -0400 Subject: [PATCH 0059/5312] lockup_detector: Cross arch compile fixes Combining the softlockup and hardlockup code causes watchdog.c to build even without the hardlockup detection support. So if an arch, that has the previous and the new nmi watchdog implementations cohabiting, wants to know if the generic one is in use, CONFIG_LOCKUP_DETECTOR is not a reliable check. We need to use CONFIG_HARDLOCKUP_DETECTOR instead. Fixes: kernel/built-in.o: In function `touch_nmi_watchdog': (.text+0x449bc): multiple definition of `touch_nmi_watchdog' arch/sparc/kernel/built-in.o:(.text+0x11b28): first defined here Signed-off-by: Don Zickus Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Don Zickus Cc: Cyrill Gorcunov LKML-Reference: <20100514151121.GR15159@redhat.com> [ use CONFIG_HARDLOCKUP_DETECTOR instead of CONFIG_PERF_EVENTS_NMI] Signed-off-by: Frederic Weisbecker --- arch/x86/kernel/apic/Makefile | 4 ++-- include/linux/nmi.h | 2 +- kernel/watchdog.c | 7 +++++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/apic/Makefile b/arch/x86/kernel/apic/Makefile index 52f32e0ea194..910f20b457c4 100644 --- a/arch/x86/kernel/apic/Makefile +++ b/arch/x86/kernel/apic/Makefile @@ -3,10 +3,10 @@ # obj-$(CONFIG_X86_LOCAL_APIC) += apic.o apic_noop.o probe_$(BITS).o ipi.o -ifneq ($(CONFIG_LOCKUP_DETECTOR),y) +ifneq ($(CONFIG_HARDLOCKUP_DETECTOR),y) obj-$(CONFIG_X86_LOCAL_APIC) += nmi.o endif -obj-$(CONFIG_LOCKUP_DETECTOR) += hw_nmi.o +obj-$(CONFIG_HARDLOCKUP_DETECTOR) += hw_nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o obj-$(CONFIG_SMP) += ipi.o diff --git a/include/linux/nmi.h b/include/linux/nmi.h index abd48aacaf79..06aab5eee134 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -20,7 +20,7 @@ extern void touch_nmi_watchdog(void); extern void acpi_nmi_disable(void); extern void acpi_nmi_enable(void); #else -#ifndef CONFIG_LOCKUP_DETECTOR +#ifndef CONFIG_HARDLOCKUP_DETECTOR static inline void touch_nmi_watchdog(void) { touch_softlockup_watchdog(); diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 83fb63155cbc..e53622c1465e 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -31,13 +31,13 @@ int watchdog_enabled; int __read_mostly softlockup_thresh = 60; static DEFINE_PER_CPU(unsigned long, watchdog_touch_ts); -static DEFINE_PER_CPU(bool, watchdog_nmi_touch); static DEFINE_PER_CPU(struct task_struct *, softlockup_watchdog); static DEFINE_PER_CPU(struct hrtimer, watchdog_hrtimer); static DEFINE_PER_CPU(bool, softlockup_touch_sync); -static DEFINE_PER_CPU(bool, hard_watchdog_warn); static DEFINE_PER_CPU(bool, soft_watchdog_warn); #ifdef CONFIG_HARDLOCKUP_DETECTOR +static DEFINE_PER_CPU(bool, hard_watchdog_warn); +static DEFINE_PER_CPU(bool, watchdog_nmi_touch); static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts); static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved); static DEFINE_PER_CPU(struct perf_event *, watchdog_ev); @@ -139,6 +139,7 @@ void touch_all_softlockup_watchdogs(void) per_cpu(watchdog_touch_ts, cpu) = 0; } +#ifdef CONFIG_HARDLOCKUP_DETECTOR void touch_nmi_watchdog(void) { __get_cpu_var(watchdog_nmi_touch) = true; @@ -146,6 +147,8 @@ void touch_nmi_watchdog(void) } EXPORT_SYMBOL(touch_nmi_watchdog); +#endif + void touch_softlockup_watchdog_sync(void) { __raw_get_cpu_var(softlockup_touch_sync) = true; -- GitLab From b6f4bb383d69cac46f17e2305720f9a3d426c5ed Mon Sep 17 00:00:00 2001 From: "apatard@mandriva.com" Date: Sat, 15 May 2010 17:30:01 +0200 Subject: [PATCH 0060/5312] ASoC: Add SOC_DOUBLE_R_SX_TLV control This patch is adding a new control which has the following capabilities: - tlv - variable data size (for instance, 7 ou 8 bit) - double mixer - data range centered around 0 Signed-off-by: Arnaud Patard Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/soc.h | 21 ++++++++++ sound/soc/soc-core.c | 95 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 697e7ffe39d7..65e9d03ed4f5 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -170,6 +170,21 @@ .get = xhandler_get, .put = xhandler_put, \ .private_value = (unsigned long)&xenum } +#define SOC_DOUBLE_R_SX_TLV(xname, xreg_left, xreg_right, xshift,\ + xmin, xmax, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw_2r_sx, \ + .get = snd_soc_get_volsw_2r_sx, \ + .put = snd_soc_put_volsw_2r_sx, \ + .private_value = (unsigned long)&(struct soc_mixer_control) \ + {.reg = xreg_left, \ + .rreg = xreg_right, .shift = xshift, \ + .min = xmin, .max = xmax} } + + /* * Simplified versions of above macros, declaring a struct and calculating * ARRAY_SIZE internally @@ -329,6 +344,12 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_soc_limit_volume(struct snd_soc_codec *codec, const char *name, int max); +int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); /** * struct snd_soc_jack_pin - Describes a pin to update based on jack detection diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e1043f644730..6220bc1ee427 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2351,6 +2351,101 @@ int snd_soc_limit_volume(struct snd_soc_codec *codec, } EXPORT_SYMBOL_GPL(snd_soc_limit_volume); +/** + * snd_soc_info_volsw_2r_sx - double with tlv and variable data size + * mixer info callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Returns 0 for success. + */ +int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int max = mc->max; + int min = mc->min; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = max-min; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r_sx); + +/** + * snd_soc_get_volsw_2r_sx - double with tlv and variable data size + * mixer get callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Returns 0 for success. + */ +int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int mask = (1<shift)-1; + int min = mc->min; + int val = snd_soc_read(codec, mc->reg) & mask; + int valr = snd_soc_read(codec, mc->rreg) & mask; + + ucontrol->value.integer.value[0] = ((val & 0xff)-min); + ucontrol->value.integer.value[1] = ((valr & 0xff)-min); + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r_sx); + +/** + * snd_soc_put_volsw_2r_sx - double with tlv and variable data size + * mixer put callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Returns 0 for success. + */ +int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int mask = (1<shift)-1; + int min = mc->min; + int ret; + unsigned int val, valr, oval, ovalr; + + val = ((ucontrol->value.integer.value[0]+min) & 0xff); + val &= mask; + valr = ((ucontrol->value.integer.value[1]+min) & 0xff); + valr &= mask; + + oval = snd_soc_read(codec, mc->reg) & mask; + ovalr = snd_soc_read(codec, mc->rreg) & mask; + + ret = 0; + if (oval != val) { + ret = snd_soc_write(codec, mc->reg, val); + if (ret < 0) + return 0; + ret = 1; + } + if (ovalr != valr) { + ret = snd_soc_write(codec, mc->rreg, valr); + if (ret < 0) + return 0; + ret = 1; + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx); + /** * snd_soc_dai_set_sysclk - configure DAI system or master clock. * @dai: DAI -- GitLab From 26e09c6eee14f4827b55137ba0eedc4e77cd50ab Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Mon, 17 May 2010 18:06:04 -0400 Subject: [PATCH 0061/5312] lockup_detector: Convert per_cpu to __get_cpu_var for readability Just a bunch of conversions as suggested by Frederic W. __get_cpu_var() provides preemption disabled checks. Plus it gives more readability as it makes it obvious we are dealing locally now with these vars. Signed-off-by: Don Zickus Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Don Zickus Cc: Cyrill Gorcunov LKML-Reference: <1274133966-18415-2-git-send-email-dzickus@redhat.com> Signed-off-by: Frederic Weisbecker --- kernel/watchdog.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/kernel/watchdog.c b/kernel/watchdog.c index e53622c1465e..91b0b26adc67 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -115,7 +115,7 @@ static unsigned long get_sample_period(void) /* Commands for resetting the watchdog */ static void __touch_watchdog(void) { - int this_cpu = raw_smp_processor_id(); + int this_cpu = smp_processor_id(); __get_cpu_var(watchdog_touch_ts) = get_timestamp(this_cpu); } @@ -157,21 +157,21 @@ void touch_softlockup_watchdog_sync(void) #ifdef CONFIG_HARDLOCKUP_DETECTOR /* watchdog detector functions */ -static int is_hardlockup(int cpu) +static int is_hardlockup(void) { - unsigned long hrint = per_cpu(hrtimer_interrupts, cpu); + unsigned long hrint = __get_cpu_var(hrtimer_interrupts); - if (per_cpu(hrtimer_interrupts_saved, cpu) == hrint) + if (__get_cpu_var(hrtimer_interrupts_saved) == hrint) return 1; - per_cpu(hrtimer_interrupts_saved, cpu) = hrint; + __get_cpu_var(hrtimer_interrupts_saved) = hrint; return 0; } #endif -static int is_softlockup(unsigned long touch_ts, int cpu) +static int is_softlockup(unsigned long touch_ts) { - unsigned long now = get_timestamp(cpu); + unsigned long now = get_timestamp(smp_processor_id()); /* Warn about unreasonable delays: */ if (time_after(now, touch_ts + softlockup_thresh)) @@ -206,8 +206,6 @@ void watchdog_overflow_callback(struct perf_event *event, int nmi, struct perf_sample_data *data, struct pt_regs *regs) { - int this_cpu = smp_processor_id(); - if (__get_cpu_var(watchdog_nmi_touch) == true) { __get_cpu_var(watchdog_nmi_touch) = false; return; @@ -219,7 +217,9 @@ void watchdog_overflow_callback(struct perf_event *event, int nmi, * fired multiple times before we overflow'd. If it hasn't * then this is a good indication the cpu is stuck */ - if (is_hardlockup(this_cpu)) { + if (is_hardlockup()) { + int this_cpu = smp_processor_id(); + /* only print hardlockups once */ if (__get_cpu_var(hard_watchdog_warn) == true) return; @@ -247,7 +247,6 @@ static inline void watchdog_interrupt_count(void) { return; } /* watchdog kicker functions */ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) { - int this_cpu = smp_processor_id(); unsigned long touch_ts = __get_cpu_var(watchdog_touch_ts); struct pt_regs *regs = get_irq_regs(); int duration; @@ -262,12 +261,12 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) hrtimer_forward_now(hrtimer, ns_to_ktime(get_sample_period())); if (touch_ts == 0) { - if (unlikely(per_cpu(softlockup_touch_sync, this_cpu))) { + if (unlikely(__get_cpu_var(softlockup_touch_sync))) { /* * If the time stamp was touched atomically * make sure the scheduler tick is up to date. */ - per_cpu(softlockup_touch_sync, this_cpu) = false; + __get_cpu_var(softlockup_touch_sync) = false; sched_clock_tick(); } __touch_watchdog(); @@ -280,14 +279,14 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) * indicate it is getting cpu time. If it hasn't then * this is a good indication some task is hogging the cpu */ - duration = is_softlockup(touch_ts, this_cpu); + duration = is_softlockup(touch_ts); if (unlikely(duration)) { /* only warn once */ if (__get_cpu_var(soft_watchdog_warn) == true) return HRTIMER_RESTART; printk(KERN_ERR "BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n", - this_cpu, duration, + smp_processor_id(), duration, current->comm, task_pid_nr(current)); print_modules(); print_irqtrace_events(current); @@ -309,10 +308,10 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) /* * The watchdog thread - touches the timestamp. */ -static int watchdog(void *__bind_cpu) +static int watchdog(void *unused) { struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; - struct hrtimer *hrtimer = &per_cpu(watchdog_hrtimer, (unsigned long)__bind_cpu); + struct hrtimer *hrtimer = &__raw_get_cpu_var(watchdog_hrtimer); sched_setscheduler(current, SCHED_FIFO, ¶m); @@ -328,7 +327,7 @@ static int watchdog(void *__bind_cpu) /* * Run briefly once per second to reset the softlockup timestamp. * If this gets delayed for more than 60 seconds then the - * debug-printout triggers in softlockup_tick(). + * debug-printout triggers in watchdog_timer_fn(). */ while (!kthread_should_stop()) { __touch_watchdog(); -- GitLab From e35e7fb0e9ea557f7504ced6fe4ccf69e44b7f07 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 19 May 2010 11:36:49 +0200 Subject: [PATCH 0062/5312] lockup_detector: Don't enable the lockup detector by default The lockup detector is a new feature that now involves the nmi watchdog. Drop the default y and let the user choose. Signed-off-by: Frederic Weisbecker Cc: Don Zickus Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Cyrill Gorcunov --- lib/Kconfig.debug | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index e65e47d5c5e6..63968a968443 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -155,7 +155,6 @@ config DEBUG_SHIRQ config LOCKUP_DETECTOR bool "Detect Hard and Soft Lockups" depends on DEBUG_KERNEL && !S390 - default y help Say Y here to enable the kernel to act as a watchdog to detect hard and soft lockups. -- GitLab From 1082e2703a2d91790f9349a6155913a8aa0d0b66 Mon Sep 17 00:00:00 2001 From: Wan ZongShun Date: Tue, 18 May 2010 13:41:46 +0800 Subject: [PATCH 0063/5312] ASoC: NUC900/audio: add nuc900 audio driver support Add support for NUC900 AC97 Signed-off-by: Wan ZongShun Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/Kconfig | 1 + sound/soc/Makefile | 1 + sound/soc/nuc900/Kconfig | 27 ++ sound/soc/nuc900/Makefile | 11 + sound/soc/nuc900/nuc900-ac97.c | 442 ++++++++++++++++++++++++++++++++ sound/soc/nuc900/nuc900-audio.c | 81 ++++++ sound/soc/nuc900/nuc900-auido.h | 121 +++++++++ sound/soc/nuc900/nuc900-pcm.c | 352 +++++++++++++++++++++++++ 8 files changed, 1036 insertions(+) create mode 100644 sound/soc/nuc900/Kconfig create mode 100644 sound/soc/nuc900/Makefile create mode 100644 sound/soc/nuc900/nuc900-ac97.c create mode 100644 sound/soc/nuc900/nuc900-audio.c create mode 100644 sound/soc/nuc900/nuc900-auido.h create mode 100644 sound/soc/nuc900/nuc900-pcm.c diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index b1749bc67979..6e04fc2aae4d 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -30,6 +30,7 @@ source "sound/soc/blackfin/Kconfig" source "sound/soc/davinci/Kconfig" source "sound/soc/fsl/Kconfig" source "sound/soc/imx/Kconfig" +source "sound/soc/nuc900/Kconfig" source "sound/soc/omap/Kconfig" source "sound/soc/pxa/Kconfig" source "sound/soc/s3c24xx/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 1470141d4167..ccec241488a6 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_SND_SOC) += blackfin/ obj-$(CONFIG_SND_SOC) += davinci/ obj-$(CONFIG_SND_SOC) += fsl/ obj-$(CONFIG_SND_SOC) += imx/ +obj-$(CONFIG_SND_SOC) += nuc900/ obj-$(CONFIG_SND_SOC) += omap/ obj-$(CONFIG_SND_SOC) += pxa/ obj-$(CONFIG_SND_SOC) += s3c24xx/ diff --git a/sound/soc/nuc900/Kconfig b/sound/soc/nuc900/Kconfig new file mode 100644 index 000000000000..a0ed1c618f60 --- /dev/null +++ b/sound/soc/nuc900/Kconfig @@ -0,0 +1,27 @@ +## +## NUC900 series AC97 API +## +config SND_SOC_NUC900 + tristate "SoC Audio for NUC900 series" + depends on ARCH_W90X900 + help + This option enables support for AC97 mode on the NUC900 SoC. + +config SND_SOC_NUC900_AC97 + tristate + select AC97_BUS + select SND_AC97_CODEC + select SND_SOC_AC97_BUS + + +## +## Boards +## +config SND_SOC_NUC900EVB + tristate "NUC900 AC97 support for demo board" + depends on SND_SOC_NUC900 + select SND_SOC_NUC900_AC97 + select SND_SOC_AC97_CODEC + help + Select this option to enable audio (AC97) on the + NUC900 demoboard. diff --git a/sound/soc/nuc900/Makefile b/sound/soc/nuc900/Makefile new file mode 100644 index 000000000000..7e46c7150316 --- /dev/null +++ b/sound/soc/nuc900/Makefile @@ -0,0 +1,11 @@ +# NUC900 series audio +snd-soc-nuc900-pcm-objs := nuc900-pcm.o +snd-soc-nuc900-ac97-objs := nuc900-ac97.o + +obj-$(CONFIG_SND_SOC_NUC900) += snd-soc-nuc900-pcm.o +obj-$(CONFIG_SND_SOC_NUC900_AC97) += snd-soc-nuc900-ac97.o + +# Boards +snd-soc-nuc900-audio-objs := nuc900-audio.o + +obj-$(CONFIG_SND_SOC_NUC900EVB) += snd-soc-nuc900-audio.o diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c new file mode 100644 index 000000000000..f7b44e081420 --- /dev/null +++ b/sound/soc/nuc900/nuc900-ac97.c @@ -0,0 +1,442 @@ +/* + * Copyright (c) 2009-2010 Nuvoton technology corporation. + * + * Wan ZongShun + * + * 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;version 2 of the License. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "nuc900-auido.h" + +static DEFINE_MUTEX(ac97_mutex); +struct nuc900_audio *nuc900_ac97_data; + +static int nuc900_checkready(void) +{ + struct nuc900_audio *nuc900_audio = nuc900_ac97_data; + + if (!(AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS0) & CODEC_READY)) + return -EPERM; + + return 0; +} + +/* AC97 controller reads codec register */ +static unsigned short nuc900_ac97_read(struct snd_ac97 *ac97, + unsigned short reg) +{ + struct nuc900_audio *nuc900_audio = nuc900_ac97_data; + unsigned long timeout = 0x10000, val; + + mutex_lock(&ac97_mutex); + + val = nuc900_checkready(); + if (!!val) { + dev_err(nuc900_audio->dev, "AC97 codec is not ready\n"); + goto out; + } + + /* set the R_WB bit and write register index */ + AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS1, R_WB | reg); + + /* set the valid frame bit and valid slots */ + val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0); + val |= (VALID_FRAME | SLOT1_VALID); + AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, val); + + udelay(100); + + /* polling the AC_R_FINISH */ + val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON); + val &= AC_R_FINISH; + while (!val && timeout--) + mdelay(1); + + if (!timeout) { + dev_err(nuc900_audio->dev, "AC97 read register time out !\n"); + val = -EPERM; + goto out; + } + + val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0) ; + val &= ~SLOT1_VALID; + AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, val); + + if (AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS1) >> 2 != reg) { + dev_err(nuc900_audio->dev, + "R_INDEX of REG_ACTL_ACIS1 not match!\n"); + } + + udelay(100); + val = (AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS2) & 0xFFFF); + +out: + mutex_unlock(&ac97_mutex); + return val; +} + +/* AC97 controller writes to codec register */ +static void nuc900_ac97_write(struct snd_ac97 *ac97, unsigned short reg, + unsigned short val) +{ + struct nuc900_audio *nuc900_audio = nuc900_ac97_data; + unsigned long tmp, timeout = 0x10000; + + mutex_lock(&ac97_mutex); + + tmp = nuc900_checkready(); + if (!!tmp) + dev_err(nuc900_audio->dev, "AC97 codec is not ready\n"); + + /* clear the R_WB bit and write register index */ + AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS1, reg); + + /* write register value */ + AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS2, val); + + /* set the valid frame bit and valid slots */ + tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0); + tmp |= SLOT1_VALID | SLOT2_VALID | VALID_FRAME; + AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp); + + udelay(100); + + /* polling the AC_W_FINISH */ + tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON); + tmp &= AC_W_FINISH; + while (tmp && timeout--) + mdelay(1); + + if (!timeout) + dev_err(nuc900_audio->dev, "AC97 write register time out !\n"); + + tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0); + tmp &= ~(SLOT1_VALID | SLOT2_VALID); + AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp); + + mutex_unlock(&ac97_mutex); + +} + +static void nuc900_ac97_warm_reset(struct snd_ac97 *ac97) +{ + struct nuc900_audio *nuc900_audio = nuc900_ac97_data; + unsigned long val; + + mutex_lock(&ac97_mutex); + + /* warm reset AC 97 */ + val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON); + val |= AC_W_RES; + AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val); + + udelay(1000); + + val = nuc900_checkready(); + if (!!val) + dev_err(nuc900_audio->dev, "AC97 codec is not ready\n"); + + mutex_unlock(&ac97_mutex); +} + +static void nuc900_ac97_cold_reset(struct snd_ac97 *ac97) +{ + struct nuc900_audio *nuc900_audio = nuc900_ac97_data; + unsigned long val; + + mutex_lock(&ac97_mutex); + + /* reset Audio Controller */ + val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); + val |= ACTL_RESET_BIT; + AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); + + udelay(1000); + + val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); + val &= (~ACTL_RESET_BIT); + AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); + + udelay(1000); + + /* reset AC-link interface */ + + val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); + val |= AC_RESET; + AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); + + udelay(1000); + + val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); + val &= ~AC_RESET; + AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); + + udelay(1000); + + /* cold reset AC 97 */ + val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON); + val |= AC_C_RES; + AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val); + + udelay(1000); + + val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON); + val &= (~AC_C_RES); + AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val); + + udelay(1000); + + mutex_unlock(&ac97_mutex); + +} + +/* AC97 controller operations */ +struct snd_ac97_bus_ops soc_ac97_ops = { + .read = nuc900_ac97_read, + .write = nuc900_ac97_write, + .reset = nuc900_ac97_cold_reset, + .warm_reset = nuc900_ac97_warm_reset, +} +EXPORT_SYMBOL_GPL(soc_ac97_ops); + +static int nuc900_ac97_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct nuc900_audio *nuc900_audio = nuc900_ac97_data; + int ret, stype = SUBSTREAM_TYPE(substream); + unsigned long val, tmp; + + ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); + if (PCM_TX == stype) { + tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0); + tmp |= (SLOT3_VALID | SLOT4_VALID | VALID_FRAME); + AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp); + + tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_PSR); + tmp |= (P_DMA_END_IRQ | P_DMA_MIDDLE_IRQ); + AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, tmp); + val |= AC_PLAY; + } else { + tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_RSR); + tmp |= (R_DMA_END_IRQ | R_DMA_MIDDLE_IRQ); + + AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, tmp); + val |= AC_RECORD; + } + + AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); + + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); + if (PCM_TX == stype) { + tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0); + tmp &= ~(SLOT3_VALID | SLOT4_VALID); + AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp); + + AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, RESET_PRSR); + val &= ~AC_PLAY; + } else { + AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, RESET_PRSR); + val &= ~AC_RECORD; + } + + AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); + + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int nuc900_ac97_probe(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct nuc900_audio *nuc900_audio = nuc900_ac97_data; + unsigned long val; + + mutex_lock(&ac97_mutex); + + /* enable unit clock */ + clk_enable(nuc900_audio->clk); + + /* enable audio controller and AC-link interface */ + val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON); + val |= (IIS_AC_PIN_SEL | ACLINK_EN); + AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val); + + mutex_unlock(&ac97_mutex); + + return 0; +} + +static void nuc900_ac97_remove(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct nuc900_audio *nuc900_audio = nuc900_ac97_data; + + clk_disable(nuc900_audio->clk); +} + +static struct snd_soc_dai_ops nuc900_ac97_dai_ops = { + .trigger = nuc900_ac97_trigger, +}; + +struct snd_soc_dai nuc900_ac97_dai = { + .name = "nuc900-ac97", + .probe = nuc900_ac97_probe, + .remove = nuc900_ac97_remove, + .ac97_control = 1, + .playback = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels_min = 1, + .channels_max = 2, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &nuc900_ac97_dai_ops, +} +EXPORT_SYMBOL_GPL(nuc900_ac97_dai); + +static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev) +{ + struct nuc900_audio *nuc900_audio; + int ret; + + if (nuc900_ac97_data) + return -EBUSY; + + nuc900_audio = kzalloc(sizeof(struct nuc900_audio), GFP_KERNEL); + if (!nuc900_audio) + return -ENOMEM; + + spin_lock_init(&nuc900_audio->lock); + + nuc900_audio->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!nuc900_audio->res) { + ret = -ENODEV; + goto out0; + } + + if (!request_mem_region(nuc900_audio->res->start, + resource_size(nuc900_audio->res), pdev->name)) { + ret = -EBUSY; + goto out0; + } + + nuc900_audio->mmio = ioremap(nuc900_audio->res->start, + resource_size(nuc900_audio->res)); + if (!nuc900_audio->mmio) { + ret = -ENOMEM; + goto out1; + } + + nuc900_audio->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(nuc900_audio->clk)) { + ret = PTR_ERR(nuc900_audio->clk); + goto out2; + } + + nuc900_audio->irq_num = platform_get_irq(pdev, 0); + if (!nuc900_audio->irq_num) { + ret = -EBUSY; + goto out2; + } + + nuc900_ac97_data = nuc900_audio; + + nuc900_audio->dev = nuc900_ac97_dai.dev = &pdev->dev; + + ret = snd_soc_register_dai(&nuc900_ac97_dai); + if (ret) + goto out3; + + mfp_set_groupg(nuc900_audio->dev); /* enbale ac97 multifunction pin*/ + + return 0; + +out3: + clk_put(nuc900_audio->clk); +out2: + iounmap(nuc900_audio->mmio); +out1: + release_mem_region(nuc900_audio->res->start, + resource_size(nuc900_audio->res)); +out0: + kfree(nuc900_audio); + return ret; +} + +static int __devexit nuc900_ac97_drvremove(struct platform_device *pdev) +{ + + snd_soc_unregister_dai(&nuc900_ac97_dai); + + clk_put(nuc900_ac97_data->clk); + iounmap(nuc900_ac97_data->mmio); + release_mem_region(nuc900_ac97_data->res->start, + resource_size(nuc900_ac97_data->res)); + + nuc900_ac97_data = NULL; + + return 0; +} + +static struct platform_driver nuc900_ac97_driver = { + .driver = { + .name = "nuc900-audio", + .owner = THIS_MODULE, + }, + .probe = nuc900_ac97_drvprobe, + .remove = __devexit_p(nuc900_ac97_drvremove), +}; + +static int __init nuc900_ac97_init(void) +{ + return platform_driver_register(&nuc900_ac97_driver); +} + +static void __exit nuc900_ac97_exit(void) +{ + platform_driver_unregister(&nuc900_ac97_driver); +} + +module_init(nuc900_ac97_init); +module_exit(nuc900_ac97_exit); + +MODULE_AUTHOR("Wan ZongShun "); +MODULE_DESCRIPTION("NUC900 AC97 SoC driver!"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:nuc900-ac97"); diff --git a/sound/soc/nuc900/nuc900-audio.c b/sound/soc/nuc900/nuc900-audio.c new file mode 100644 index 000000000000..b33d5b844d71 --- /dev/null +++ b/sound/soc/nuc900/nuc900-audio.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2010 Nuvoton technology corporation. + * + * Wan ZongShun + * + * 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;version 2 of the License. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../codecs/ac97.h" +#include "nuc900-auido.h" + +static struct snd_soc_dai_link nuc900evb_ac97_dai = { + .name = "AC97", + .stream_name = "AC97 HiFi", + .cpu_dai = &nuc900_ac97_dai, + .codec_dai = &ac97_dai, +}; + +static struct snd_soc_card nuc900evb_audio_machine = { + .name = "NUC900EVB_AC97", + .dai_link = &nuc900evb_ac97_dai, + .num_links = 1, + .platform = &nuc900_soc_platform, +}; + +static struct snd_soc_device nuc900evb_ac97_devdata = { + .card = &nuc900evb_audio_machine, + .codec_dev = &soc_codec_dev_ac97, +}; + +static struct platform_device *nuc900evb_asoc_dev; + +static int __init nuc900evb_audio_init(void) +{ + int ret; + + ret = -ENOMEM; + nuc900evb_asoc_dev = platform_device_alloc("soc-audio", -1); + if (!nuc900evb_asoc_dev) + goto out; + + /* nuc900 board audio device */ + platform_set_drvdata(nuc900evb_asoc_dev, &nuc900evb_ac97_devdata); + + nuc900evb_ac97_devdata.dev = &nuc900evb_asoc_dev->dev; + ret = platform_device_add(nuc900evb_asoc_dev); + + if (ret) { + platform_device_put(nuc900evb_asoc_dev); + nuc900evb_asoc_dev = NULL; + } + +out: + return ret; +} + +static void __exit nuc900evb_audio_exit(void) +{ + platform_device_unregister(nuc900evb_asoc_dev); +} + +module_init(nuc900evb_audio_init); +module_exit(nuc900evb_audio_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("NUC900 Series ASoC audio support"); +MODULE_AUTHOR("Wan ZongShun"); diff --git a/sound/soc/nuc900/nuc900-auido.h b/sound/soc/nuc900/nuc900-auido.h new file mode 100644 index 000000000000..95ac4ef2f353 --- /dev/null +++ b/sound/soc/nuc900/nuc900-auido.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2010 Nuvoton technology corporation. + * + * Wan ZongShun + * + * 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;version 2 of the License. + * + */ + +#ifndef _NUC900_AUDIO_H +#define _NUC900_AUDIO_H + +#include + +/* Audio Control Registers */ +#define ACTL_CON 0x00 +#define ACTL_RESET 0x04 +#define ACTL_RDSTB 0x08 +#define ACTL_RDST_LENGTH 0x0C +#define ACTL_RDSTC 0x10 +#define ACTL_RSR 0x14 +#define ACTL_PDSTB 0x18 +#define ACTL_PDST_LENGTH 0x1C +#define ACTL_PDSTC 0x20 +#define ACTL_PSR 0x24 +#define ACTL_IISCON 0x28 +#define ACTL_ACCON 0x2C +#define ACTL_ACOS0 0x30 +#define ACTL_ACOS1 0x34 +#define ACTL_ACOS2 0x38 +#define ACTL_ACIS0 0x3C +#define ACTL_ACIS1 0x40 +#define ACTL_ACIS2 0x44 +#define ACTL_COUNTER 0x48 + +/* bit definition of REG_ACTL_CON register */ +#define R_DMA_IRQ 0x1000 +#define T_DMA_IRQ 0x0800 +#define IIS_AC_PIN_SEL 0x0100 +#define FIFO_TH 0x0080 +#define ADC_EN 0x0010 +#define M80_EN 0x0008 +#define ACLINK_EN 0x0004 +#define IIS_EN 0x0002 + +/* bit definition of REG_ACTL_RESET register */ +#define W5691_PLAY 0x20000 +#define ACTL_RESET_BIT 0x10000 +#define RECORD_RIGHT_CHNNEL 0x08000 +#define RECORD_LEFT_CHNNEL 0x04000 +#define PLAY_RIGHT_CHNNEL 0x02000 +#define PLAY_LEFT_CHNNEL 0x01000 +#define DAC_PLAY 0x00800 +#define ADC_RECORD 0x00400 +#define M80_PLAY 0x00200 +#define AC_RECORD 0x00100 +#define AC_PLAY 0x00080 +#define IIS_RECORD 0x00040 +#define IIS_PLAY 0x00020 +#define DAC_RESET 0x00010 +#define ADC_RESET 0x00008 +#define M80_RESET 0x00004 +#define AC_RESET 0x00002 +#define IIS_RESET 0x00001 + +/* bit definition of REG_ACTL_ACCON register */ +#define AC_BCLK_PU_EN 0x20 +#define AC_R_FINISH 0x10 +#define AC_W_FINISH 0x08 +#define AC_W_RES 0x04 +#define AC_C_RES 0x02 + +/* bit definition of ACTL_RSR register */ +#define R_FIFO_EMPTY 0x04 +#define R_DMA_END_IRQ 0x02 +#define R_DMA_MIDDLE_IRQ 0x01 + +/* bit definition of ACTL_PSR register */ +#define P_FIFO_EMPTY 0x04 +#define P_DMA_END_IRQ 0x02 +#define P_DMA_MIDDLE_IRQ 0x01 + +/* bit definition of ACTL_ACOS0 register */ +#define SLOT1_VALID 0x01 +#define SLOT2_VALID 0x02 +#define SLOT3_VALID 0x04 +#define SLOT4_VALID 0x08 +#define VALID_FRAME 0x10 + +/* bit definition of ACTL_ACOS1 register */ +#define R_WB 0x80 + +#define CODEC_READY 0x10 +#define RESET_PRSR 0x00 +#define AUDIO_WRITE(addr, val) __raw_writel(val, addr) +#define AUDIO_READ(addr) __raw_readl(addr) +#define PCM_TX 0 +#define PCM_RX 1 +#define SUBSTREAM_TYPE(substream) \ + ((substream)->stream == SNDRV_PCM_STREAM_PLAYBACK ? PCM_TX : PCM_RX) + +struct nuc900_audio { + void __iomem *mmio; + spinlock_t lock; + dma_addr_t dma_addr[2]; + unsigned long buffersize[2]; + unsigned long irq_num; + struct snd_pcm_substream *substream; + struct resource *res; + struct clk *clk; + struct device *dev; + +}; + +extern struct nuc900_audio *nuc900_ac97_data; +extern struct snd_soc_dai nuc900_ac97_dai; +extern struct snd_soc_platform nuc900_soc_platform; + +#endif /*end _NUC900_AUDIO_H */ diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c new file mode 100644 index 000000000000..32a503c1c4be --- /dev/null +++ b/sound/soc/nuc900/nuc900-pcm.c @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2010 Nuvoton technology corporation. + * + * Wan ZongShun + * + * 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;version 2 of the License. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "nuc900-auido.h" + +static const struct snd_pcm_hardware nuc900_pcm_hardware = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = 4*1024, + .period_bytes_min = 1*1024, + .period_bytes_max = 4*1024, + .periods_min = 1, + .periods_max = 1024, +}; + +static int nuc900_dma_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct nuc900_audio *nuc900_audio = runtime->private_data; + unsigned long flags, stype = SUBSTREAM_TYPE(substream); + int ret = 0; + + spin_lock_irqsave(&nuc900_audio->lock, flags); + + ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); + if (ret < 0) + return ret; + + nuc900_audio->substream = substream; + nuc900_audio->dma_addr[stype] = runtime->dma_addr; + nuc900_audio->buffersize[stype] = params_buffer_bytes(params); + + spin_unlock_irqrestore(&nuc900_audio->lock, flags); + + return ret; +} + +static void nuc900_update_dma_register(struct snd_pcm_substream *substream, + dma_addr_t dma_addr, size_t count) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct nuc900_audio *nuc900_audio = runtime->private_data; + void __iomem *mmio_addr, *mmio_len; + + if (SUBSTREAM_TYPE(substream) == PCM_TX) { + mmio_addr = nuc900_audio->mmio + ACTL_PDSTB; + mmio_len = nuc900_audio->mmio + ACTL_PDST_LENGTH; + } else { + mmio_addr = nuc900_audio->mmio + ACTL_RDSTB; + mmio_len = nuc900_audio->mmio + ACTL_RDST_LENGTH; + } + + AUDIO_WRITE(mmio_addr, dma_addr); + AUDIO_WRITE(mmio_len, count); +} + +static void nuc900_dma_start(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct nuc900_audio *nuc900_audio = runtime->private_data; + unsigned long val; + + val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON); + val |= (T_DMA_IRQ | R_DMA_IRQ); + AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val); +} + +static void nuc900_dma_stop(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct nuc900_audio *nuc900_audio = runtime->private_data; + unsigned long val; + + val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON); + val &= ~(T_DMA_IRQ | R_DMA_IRQ); + AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val); +} + +static irqreturn_t nuc900_dma_interrupt(int irq, void *dev_id) +{ + struct snd_pcm_substream *substream = dev_id; + struct nuc900_audio *nuc900_audio = substream->runtime->private_data; + unsigned long val; + + spin_lock(&nuc900_audio->lock); + + val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON); + + if (val & R_DMA_IRQ) { + AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | R_DMA_IRQ); + + val = AUDIO_READ(nuc900_audio->mmio + ACTL_RSR); + + if (val & R_DMA_MIDDLE_IRQ) { + val |= R_DMA_MIDDLE_IRQ; + AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val); + } + + if (val & R_DMA_END_IRQ) { + val |= R_DMA_END_IRQ; + AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val); + } + } else if (val & T_DMA_IRQ) { + AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | T_DMA_IRQ); + + val = AUDIO_READ(nuc900_audio->mmio + ACTL_PSR); + + if (val & P_DMA_MIDDLE_IRQ) { + val |= P_DMA_MIDDLE_IRQ; + AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val); + } + + if (val & P_DMA_END_IRQ) { + val |= P_DMA_END_IRQ; + AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val); + } + } else { + dev_err(nuc900_audio->dev, "Wrong DMA interrupt status!\n"); + spin_unlock(&nuc900_audio->lock); + return IRQ_HANDLED; + } + + spin_unlock(&nuc900_audio->lock); + + snd_pcm_period_elapsed(substream); + + return IRQ_HANDLED; +} + +static int nuc900_dma_hw_free(struct snd_pcm_substream *substream) +{ + snd_pcm_lib_free_pages(substream); + return 0; +} + +static int nuc900_dma_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct nuc900_audio *nuc900_audio = runtime->private_data; + unsigned long flags, val, stype = SUBSTREAM_TYPE(substream);; + + spin_lock_irqsave(&nuc900_audio->lock, flags); + + nuc900_update_dma_register(substream, + nuc900_audio->dma_addr[stype], nuc900_audio->buffersize[stype]); + + val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); + + switch (runtime->channels) { + case 1: + if (PCM_TX == stype) { + val &= ~(PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL); + val |= PLAY_RIGHT_CHNNEL; + } else { + val &= ~(RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL); + val |= RECORD_RIGHT_CHNNEL; + } + AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); + break; + case 2: + if (PCM_TX == stype) + val |= (PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL); + else + val |= (RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL); + AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); + break; + default: + return -EINVAL; + } + spin_unlock_irqrestore(&nuc900_audio->lock, flags); + return 0; +} + +static int nuc900_dma_trigger(struct snd_pcm_substream *substream, int cmd) +{ + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + nuc900_dma_start(substream); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + nuc900_dma_stop(substream); + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + +int nuc900_dma_getposition(struct snd_pcm_substream *substream, + dma_addr_t *src, dma_addr_t *dst) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct nuc900_audio *nuc900_audio = runtime->private_data; + + if (src != NULL) + *src = AUDIO_READ(nuc900_audio->mmio + ACTL_PDSTC); + + if (dst != NULL) + *dst = AUDIO_READ(nuc900_audio->mmio + ACTL_RDSTC); + + return 0; +} + +static snd_pcm_uframes_t nuc900_dma_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + dma_addr_t src, dst; + unsigned long res; + + nuc900_dma_getposition(substream, &src, &dst); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + res = dst - runtime->dma_addr; + else + res = src - runtime->dma_addr; + + return bytes_to_frames(substream->runtime, res); +} + +static int nuc900_dma_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct nuc900_audio *nuc900_audio; + + snd_soc_set_runtime_hwparams(substream, &nuc900_pcm_hardware); + + nuc900_audio = nuc900_ac97_data; + + if (request_irq(nuc900_audio->irq_num, nuc900_dma_interrupt, + IRQF_DISABLED, "nuc900-dma", substream)) + return -EBUSY; + + runtime->private_data = nuc900_audio; + + return 0; +} + +static int nuc900_dma_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct nuc900_audio *nuc900_audio = runtime->private_data; + + free_irq(nuc900_audio->irq_num, substream); + + return 0; +} + +static int nuc900_dma_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + return dma_mmap_writecombine(substream->pcm->card->dev, vma, + runtime->dma_area, + runtime->dma_addr, + runtime->dma_bytes); +} + +static struct snd_pcm_ops nuc900_dma_ops = { + .open = nuc900_dma_open, + .close = nuc900_dma_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = nuc900_dma_hw_params, + .hw_free = nuc900_dma_hw_free, + .prepare = nuc900_dma_prepare, + .trigger = nuc900_dma_trigger, + .pointer = nuc900_dma_pointer, + .mmap = nuc900_dma_mmap, +}; + +static void nuc900_dma_free_dma_buffers(struct snd_pcm *pcm) +{ + snd_pcm_lib_preallocate_free_for_all(pcm); +} + +static u64 nuc900_pcm_dmamask = DMA_BIT_MASK(32); +static int nuc900_dma_new(struct snd_card *card, + struct snd_soc_dai *dai, struct snd_pcm *pcm) +{ + if (!card->dev->dma_mask) + card->dev->dma_mask = &nuc900_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = DMA_BIT_MASK(32); + + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + card->dev, 4 * 1024, (4 * 1024) - 1); + + return 0; +} + +struct snd_soc_platform nuc900_soc_platform = { + .name = "nuc900-dma", + .pcm_ops = &nuc900_dma_ops, + .pcm_new = nuc900_dma_new, + .pcm_free = nuc900_dma_free_dma_buffers, +} +EXPORT_SYMBOL_GPL(nuc900_soc_platform); + +static int __init nuc900_soc_platform_init(void) +{ + return snd_soc_register_platform(&nuc900_soc_platform); +} + +static void __exit nuc900_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&nuc900_soc_platform); +} + +module_init(nuc900_soc_platform_init); +module_exit(nuc900_soc_platform_exit); + +MODULE_AUTHOR("Wan ZongShun, "); +MODULE_DESCRIPTION("nuc900 Audio DMA module"); +MODULE_LICENSE("GPL"); -- GitLab From 1dedefd1a066a795a87afca9c0236e1a94de9bf6 Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Wed, 19 May 2010 12:01:23 -0700 Subject: [PATCH 0064/5312] x86: detect scattered cpuid features earlier Some extra CPU features such as ARAT is needed in early boot so that x86_init function pointers can be set up properly. http://lkml.org/lkml/2010/5/18/519 At start_kernel() level, this patch moves init_scattered_cpuid_features() from check_bugs() to setup_arch() -> early_cpu_init() which is earlier than platform specific x86_init layer setup. Suggested by HPA. Signed-off-by: Jacob Pan LKML-Reference: <1274295685-6774-2-git-send-email-jacob.jun.pan@linux.intel.com> Acked-by: Thomas Gleixner Signed-off-by: H. Peter Anvin --- arch/x86/kernel/cpu/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index c1c00d0b1692..284bf89ddae2 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -576,6 +576,7 @@ static void __cpuinit get_cpu_cap(struct cpuinfo_x86 *c) if (c->extended_cpuid_level >= 0x80000007) c->x86_power = cpuid_edx(0x80000007); + init_scattered_cpuid_features(c); } static void __cpuinit identify_cpu_without_cpuid(struct cpuinfo_x86 *c) @@ -731,7 +732,6 @@ static void __cpuinit generic_identify(struct cpuinfo_x86 *c) get_model_name(c); /* Default name */ - init_scattered_cpuid_features(c); detect_nopl(c); } -- GitLab From a0c173bd8a3fd0541be8e4ef962170e48d8811c7 Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Wed, 19 May 2010 12:01:24 -0700 Subject: [PATCH 0065/5312] x86, mrst: add cpu type detection Medfield is the follow-up of Moorestown, it is treated under the same HW sub-architecture. However, we do need to know the CPU type in order for some of the driver to act accordingly. We also have different optimal clock configuration for each CPU type. Signed-off-by: Jacob Pan LKML-Reference: <1274295685-6774-3-git-send-email-jacob.jun.pan@linux.intel.com> Acked-by: Thomas Gleixner Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/mrst.h | 19 +++++++++++++++++++ arch/x86/kernel/mrst.c | 26 ++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/arch/x86/include/asm/mrst.h b/arch/x86/include/asm/mrst.h index 451d30e7f62d..dc5c8500bfc7 100644 --- a/arch/x86/include/asm/mrst.h +++ b/arch/x86/include/asm/mrst.h @@ -11,8 +11,27 @@ #ifndef _ASM_X86_MRST_H #define _ASM_X86_MRST_H extern int pci_mrst_init(void); +extern int mrst_identify_cpu(void); int __init sfi_parse_mrtc(struct sfi_table_header *table); +/* + * Medfield is the follow-up of Moorestown, it combines two chip solution into + * one. Other than that it also added always-on and constant tsc and lapic + * timers. Medfield is the platform name, and the chip name is called Penwell + * we treat Medfield/Penwell as a variant of Moorestown. Penwell can be + * identified via MSRs. + */ +enum mrst_cpu_type { + MRST_CPU_CHIP_LINCROFT = 1, + MRST_CPU_CHIP_PENWELL, +}; + +enum mrst_timer_options { + MRST_TIMER_DEFAULT, + MRST_TIMER_APBT_ONLY, + MRST_TIMER_LAPIC_APBT, +}; + #define SFI_MTMR_MAX_NUM 8 #define SFI_MRTC_MAX 8 diff --git a/arch/x86/kernel/mrst.c b/arch/x86/kernel/mrst.c index e796448f0eb5..ceaebeb5866f 100644 --- a/arch/x86/kernel/mrst.c +++ b/arch/x86/kernel/mrst.c @@ -27,6 +27,8 @@ static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM]; static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM]; +static int mrst_cpu_chip; + int sfi_mtimer_num; struct sfi_rtc_table_entry sfi_mrtc_array[SFI_MRTC_MAX]; @@ -216,6 +218,28 @@ static void __init mrst_setup_boot_clock(void) setup_boot_APIC_clock(); }; +int mrst_identify_cpu(void) +{ + return mrst_cpu_chip; +} +EXPORT_SYMBOL_GPL(mrst_identify_cpu); + +void __cpuinit mrst_arch_setup(void) +{ + if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x27) + mrst_cpu_chip = MRST_CPU_CHIP_PENWELL; + else if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x26) + mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT; + else { + pr_err("Unknown Moorestown CPU (%d:%d), default to Lincroft\n", + boot_cpu_data.x86, boot_cpu_data.x86_model); + mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT; + } + pr_debug("Moorestown CPU %s identified\n", + (mrst_cpu_chip == MRST_CPU_CHIP_LINCROFT) ? + "Lincroft" : "Penwell"); +} + /* * Moorestown specific x86_init function overrides and early setup * calls. @@ -230,6 +254,8 @@ void __init x86_mrst_early_setup(void) x86_init.irqs.pre_vector_init = x86_init_noop; + x86_init.oem.arch_setup = mrst_arch_setup; + x86_cpuinit.setup_percpu_clockev = mrst_setup_secondary_clock; x86_platform.calibrate_tsc = mrst_calibrate_tsc; -- GitLab From a875c01944f0d750eeb1ef3133feceb13f13c4b3 Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Wed, 19 May 2010 12:01:25 -0700 Subject: [PATCH 0066/5312] x86, mrst: add more timer config options Always-on local APIC timer (ARAT) has been introduced to Medfield, along with the platform APB timers we have more timer configuration options between Moorestown and Medfield. This patch adds run-time detection of avaiable timer features so that we can treat Medfield as a variant of Moorestown and set up the optimal timer options for each platform. i.e. Medfield: per cpu always-on local APIC timer Moorestown: per cpu APB timer Manual override is possible via cmdline option x86_mrst_timer. Signed-off-by: Jacob Pan LKML-Reference: <1274295685-6774-4-git-send-email-jacob.jun.pan@linux.intel.com> Acked-by: Thomas Gleixner Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/apb_timer.h | 1 - arch/x86/include/asm/mrst.h | 1 + arch/x86/kernel/apb_timer.c | 37 +++----------- arch/x86/kernel/mrst.c | 88 +++++++++++++++++++++++--------- 4 files changed, 72 insertions(+), 55 deletions(-) diff --git a/arch/x86/include/asm/apb_timer.h b/arch/x86/include/asm/apb_timer.h index c74a2eebe570..a69b1ac9eaf8 100644 --- a/arch/x86/include/asm/apb_timer.h +++ b/arch/x86/include/asm/apb_timer.h @@ -55,7 +55,6 @@ extern unsigned long apbt_quick_calibrate(void); extern int arch_setup_apbt_irqs(int irq, int trigger, int mask, int cpu); extern void apbt_setup_secondary_clock(void); extern unsigned int boot_cpu_id; -extern int disable_apbt_percpu; extern struct sfi_timer_table_entry *sfi_get_mtmr(int hint); extern void sfi_free_mtmr(struct sfi_timer_table_entry *mtmr); diff --git a/arch/x86/include/asm/mrst.h b/arch/x86/include/asm/mrst.h index dc5c8500bfc7..67ad31545778 100644 --- a/arch/x86/include/asm/mrst.h +++ b/arch/x86/include/asm/mrst.h @@ -12,6 +12,7 @@ #define _ASM_X86_MRST_H extern int pci_mrst_init(void); extern int mrst_identify_cpu(void); +extern int mrst_timer_options __cpuinitdata; int __init sfi_parse_mrtc(struct sfi_table_header *table); /* diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c index a35347501d36..8dd77800ff5d 100644 --- a/arch/x86/kernel/apb_timer.c +++ b/arch/x86/kernel/apb_timer.c @@ -43,10 +43,11 @@ #include #include +#include #define APBT_MASK CLOCKSOURCE_MASK(32) #define APBT_SHIFT 22 -#define APBT_CLOCKEVENT_RATING 150 +#define APBT_CLOCKEVENT_RATING 110 #define APBT_CLOCKSOURCE_RATING 250 #define APBT_MIN_DELTA_USEC 200 @@ -83,8 +84,6 @@ struct apbt_dev { char name[10]; }; -int disable_apbt_percpu __cpuinitdata; - static DEFINE_PER_CPU(struct apbt_dev, cpu_apbt_dev); #ifdef CONFIG_SMP @@ -194,29 +193,6 @@ static struct clock_event_device apbt_clockevent = { .rating = APBT_CLOCKEVENT_RATING, }; -/* - * if user does not want to use per CPU apb timer, just give it a lower rating - * than local apic timer and skip the late per cpu timer init. - */ -static inline int __init setup_x86_mrst_timer(char *arg) -{ - if (!arg) - return -EINVAL; - - if (strcmp("apbt_only", arg) == 0) - disable_apbt_percpu = 0; - else if (strcmp("lapic_and_apbt", arg) == 0) - disable_apbt_percpu = 1; - else { - pr_warning("X86 MRST timer option %s not recognised" - " use x86_mrst_timer=apbt_only or lapic_and_apbt\n", - arg); - return -EINVAL; - } - return 0; -} -__setup("x86_mrst_timer=", setup_x86_mrst_timer); - /* * start count down from 0xffff_ffff. this is done by toggling the enable bit * then load initial load count to ~0. @@ -335,7 +311,7 @@ static int __init apbt_clockevent_register(void) adev->num = smp_processor_id(); memcpy(&adev->evt, &apbt_clockevent, sizeof(struct clock_event_device)); - if (disable_apbt_percpu) { + if (mrst_timer_options == MRST_TIMER_LAPIC_APBT) { apbt_clockevent.rating = APBT_CLOCKEVENT_RATING - 100; global_clock_event = &adev->evt; printk(KERN_DEBUG "%s clockevent registered as global\n", @@ -429,7 +405,8 @@ static int apbt_cpuhp_notify(struct notifier_block *n, static __init int apbt_late_init(void) { - if (disable_apbt_percpu || !apb_timer_block_enabled) + if (mrst_timer_options == MRST_TIMER_LAPIC_APBT || + !apb_timer_block_enabled) return 0; /* This notifier should be called after workqueue is ready */ hotcpu_notifier(apbt_cpuhp_notify, -20); @@ -450,6 +427,8 @@ static void apbt_set_mode(enum clock_event_mode mode, int timer_num; struct apbt_dev *adev = EVT_TO_APBT_DEV(evt); + BUG_ON(!apbt_virt_address); + timer_num = adev->num; pr_debug("%s CPU %d timer %d mode=%d\n", __func__, first_cpu(*evt->cpumask), timer_num, mode); @@ -676,7 +655,7 @@ void __init apbt_time_init(void) } #ifdef CONFIG_SMP /* kernel cmdline disable apb timer, so we will use lapic timers */ - if (disable_apbt_percpu) { + if (mrst_timer_options == MRST_TIMER_LAPIC_APBT) { printk(KERN_INFO "apbt: disabled per cpu timer\n"); return; } diff --git a/arch/x86/kernel/mrst.c b/arch/x86/kernel/mrst.c index ceaebeb5866f..636b53bd4198 100644 --- a/arch/x86/kernel/mrst.c +++ b/arch/x86/kernel/mrst.c @@ -25,6 +25,29 @@ #include #include +/* + * the clockevent devices on Moorestown/Medfield can be APBT or LAPIC clock, + * cmdline option x86_mrst_timer can be used to override the configuration + * to prefer one or the other. + * at runtime, there are basically three timer configurations: + * 1. per cpu apbt clock only + * 2. per cpu always-on lapic clocks only, this is Penwell/Medfield only + * 3. per cpu lapic clock (C3STOP) and one apbt clock, with broadcast. + * + * by default (without cmdline option), platform code first detects cpu type + * to see if we are on lincroft or penwell, then set up both lapic or apbt + * clocks accordingly. + * i.e. by default, medfield uses configuration #2, moorestown uses #1. + * config #3 is supported but not recommended on medfield. + * + * rating and feature summary: + * lapic (with C3STOP) --------- 100 + * apbt (always-on) ------------ 110 + * lapic (always-on,ARAT) ------ 150 + */ + +int mrst_timer_options __cpuinitdata; + static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM]; static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM]; static int mrst_cpu_chip; @@ -169,18 +192,6 @@ int __init sfi_parse_mrtc(struct sfi_table_header *table) return 0; } -/* - * the secondary clock in Moorestown can be APBT or LAPIC clock, default to - * APBT but cmdline option can also override it. - */ -static void __cpuinit mrst_setup_secondary_clock(void) -{ - /* restore default lapic clock if disabled by cmdline */ - if (disable_apbt_percpu) - return setup_secondary_APIC_clock(); - apbt_setup_secondary_clock(); -} - static unsigned long __init mrst_calibrate_tsc(void) { unsigned long flags, fast_calibrate; @@ -197,6 +208,21 @@ static unsigned long __init mrst_calibrate_tsc(void) void __init mrst_time_init(void) { + switch (mrst_timer_options) { + case MRST_TIMER_APBT_ONLY: + break; + case MRST_TIMER_LAPIC_APBT: + x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock; + x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock; + break; + default: + if (!boot_cpu_has(X86_FEATURE_ARAT)) + break; + x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock; + x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock; + return; + } + /* we need at least one APB timer */ sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr); pre_init_apic_IRQ0(); apbt_time_init(); @@ -207,17 +233,6 @@ void __init mrst_rtc_init(void) sfi_table_parse(SFI_SIG_MRTC, NULL, NULL, sfi_parse_mrtc); } -/* - * if we use per cpu apb timer, the bootclock already setup. if we use lapic - * timer and one apbt timer for broadcast, we need to set up lapic boot clock. - */ -static void __init mrst_setup_boot_clock(void) -{ - pr_info("%s: per cpu apbt flag %d \n", __func__, disable_apbt_percpu); - if (disable_apbt_percpu) - setup_boot_APIC_clock(); -}; - int mrst_identify_cpu(void) { return mrst_cpu_chip; @@ -250,13 +265,13 @@ void __init x86_mrst_early_setup(void) x86_init.resources.reserve_resources = x86_init_noop; x86_init.timers.timer_init = mrst_time_init; - x86_init.timers.setup_percpu_clockev = mrst_setup_boot_clock; + x86_init.timers.setup_percpu_clockev = x86_init_noop; x86_init.irqs.pre_vector_init = x86_init_noop; x86_init.oem.arch_setup = mrst_arch_setup; - x86_cpuinit.setup_percpu_clockev = mrst_setup_secondary_clock; + x86_cpuinit.setup_percpu_clockev = apbt_setup_secondary_clock; x86_platform.calibrate_tsc = mrst_calibrate_tsc; x86_init.pci.init = pci_mrst_init; @@ -269,3 +284,26 @@ void __init x86_mrst_early_setup(void) x86_init.mpparse.get_smp_config = x86_init_uint_noop; } + +/* + * if user does not want to use per CPU apb timer, just give it a lower rating + * than local apic timer and skip the late per cpu timer init. + */ +static inline int __init setup_x86_mrst_timer(char *arg) +{ + if (!arg) + return -EINVAL; + + if (strcmp("apbt_only", arg) == 0) + mrst_timer_options = MRST_TIMER_APBT_ONLY; + else if (strcmp("lapic_and_apbt", arg) == 0) + mrst_timer_options = MRST_TIMER_LAPIC_APBT; + else { + pr_warning("X86 MRST timer option %s not recognised" + " use x86_mrst_timer=apbt_only or lapic_and_apbt\n", + arg); + return -EINVAL; + } + return 0; +} +__setup("x86_mrst_timer=", setup_x86_mrst_timer); -- GitLab From a75af580bb1fd261bf63cc00e4b324e17ceb15cf Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 19 May 2010 13:40:14 -0700 Subject: [PATCH 0067/5312] x86, mrst: make mrst_identify_cpu() an inline returning enum We have an enum, might as well use it. While we're at it, make it an inline... there is really no point in calling a function for this stuff. LKML-Reference: <1274295685-6774-3-git-send-email-jacob.jun.pan@linux.intel.com> Signed-off-by: H. Peter Anvin Acked-by: Thomas Gleixner Cc: Jacob Pan --- arch/x86/include/asm/mrst.h | 7 ++++++- arch/x86/kernel/mrst.c | 17 ++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/x86/include/asm/mrst.h b/arch/x86/include/asm/mrst.h index 67ad31545778..1869c18d15ca 100644 --- a/arch/x86/include/asm/mrst.h +++ b/arch/x86/include/asm/mrst.h @@ -11,7 +11,6 @@ #ifndef _ASM_X86_MRST_H #define _ASM_X86_MRST_H extern int pci_mrst_init(void); -extern int mrst_identify_cpu(void); extern int mrst_timer_options __cpuinitdata; int __init sfi_parse_mrtc(struct sfi_table_header *table); @@ -27,6 +26,12 @@ enum mrst_cpu_type { MRST_CPU_CHIP_PENWELL, }; +extern enum mrst_cpu_type __mrst_cpu_chip; +static enum mrst_cpu_type mrst_identify_cpu(void) +{ + return __mrst_cpu_chip; +} + enum mrst_timer_options { MRST_TIMER_DEFAULT, MRST_TIMER_APBT_ONLY, diff --git a/arch/x86/kernel/mrst.c b/arch/x86/kernel/mrst.c index 636b53bd4198..967f2686adb0 100644 --- a/arch/x86/kernel/mrst.c +++ b/arch/x86/kernel/mrst.c @@ -50,7 +50,8 @@ int mrst_timer_options __cpuinitdata; static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM]; static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM]; -static int mrst_cpu_chip; +enum mrst_cpu_type __mrst_cpu_chip; +EXPORT_SYMBOL_GPL(__mrst_cpu_chip); int sfi_mtimer_num; @@ -233,25 +234,19 @@ void __init mrst_rtc_init(void) sfi_table_parse(SFI_SIG_MRTC, NULL, NULL, sfi_parse_mrtc); } -int mrst_identify_cpu(void) -{ - return mrst_cpu_chip; -} -EXPORT_SYMBOL_GPL(mrst_identify_cpu); - void __cpuinit mrst_arch_setup(void) { if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x27) - mrst_cpu_chip = MRST_CPU_CHIP_PENWELL; + __mrst_cpu_chip = MRST_CPU_CHIP_PENWELL; else if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x26) - mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT; + __mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT; else { pr_err("Unknown Moorestown CPU (%d:%d), default to Lincroft\n", boot_cpu_data.x86, boot_cpu_data.x86_model); - mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT; + __mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT; } pr_debug("Moorestown CPU %s identified\n", - (mrst_cpu_chip == MRST_CPU_CHIP_LINCROFT) ? + (__mrst_cpu_chip == MRST_CPU_CHIP_LINCROFT) ? "Lincroft" : "Penwell"); } -- GitLab From 14671386dcbafb3086bbda3cb6f9f27d34c7bf6d Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 19 May 2010 14:37:40 -0700 Subject: [PATCH 0068/5312] x86, mrst: make mrst_timer_options an enum We have an enum mrst_timer_options, use it so that the kernel knows if we're missing something from a switch statement or equivalent. Signed-off-by: H. Peter Anvin LKML-Reference: <1274295685-6774-4-git-send-email-jacob.jun.pan@linux.intel.com> Cc: Thomas Gleixner Cc: Jacob Pan --- arch/x86/include/asm/mrst.h | 3 ++- arch/x86/kernel/mrst.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/mrst.h b/arch/x86/include/asm/mrst.h index 1869c18d15ca..16350740edf6 100644 --- a/arch/x86/include/asm/mrst.h +++ b/arch/x86/include/asm/mrst.h @@ -11,7 +11,6 @@ #ifndef _ASM_X86_MRST_H #define _ASM_X86_MRST_H extern int pci_mrst_init(void); -extern int mrst_timer_options __cpuinitdata; int __init sfi_parse_mrtc(struct sfi_table_header *table); /* @@ -38,6 +37,8 @@ enum mrst_timer_options { MRST_TIMER_LAPIC_APBT, }; +extern enum mrst_timer_options mrst_timer_options; + #define SFI_MTMR_MAX_NUM 8 #define SFI_MRTC_MAX 8 diff --git a/arch/x86/kernel/mrst.c b/arch/x86/kernel/mrst.c index 967f2686adb0..7ee4ed901baf 100644 --- a/arch/x86/kernel/mrst.c +++ b/arch/x86/kernel/mrst.c @@ -46,7 +46,7 @@ * lapic (always-on,ARAT) ------ 150 */ -int mrst_timer_options __cpuinitdata; +__cpuinitdata enum mrst_timer_options mrst_timer_options; static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM]; static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM]; -- GitLab From 9b7c23adb350a108737a993c9c781463c1439dc6 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 19 May 2010 10:29:47 +0000 Subject: [PATCH 0069/5312] ARM: mach-shmobile: Use 0x2200 as INTCS_VECT_BASE Change INTCS_VECT_BASE from 0x3400 to 0x2200. The old value 0x3400 gave the INTCA and INTCS interrupt conrollers separated spaces, but required ARM support for more than 512 NR_IRQS which is not in place at this point. The value 0x2200 will make some of the INTCA interrupts make use of empty INTCS areas. This is a bit more error prone but works fine as a workaround for G3, G3 and AP4. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/include/mach/irqs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-shmobile/include/mach/irqs.h b/arch/arm/mach-shmobile/include/mach/irqs.h index 51b4a6ab6c60..e881797648a9 100644 --- a/arch/arm/mach-shmobile/include/mach/irqs.h +++ b/arch/arm/mach-shmobile/include/mach/irqs.h @@ -9,7 +9,7 @@ #define irq2evt(irq) (((irq) + 16) << 5) /* INTCS */ -#define INTCS_VECT_BASE 0x3400 +#define INTCS_VECT_BASE 0x2200 #define INTCS_VECT(n, vect) INTC_VECT((n), INTCS_VECT_BASE + (vect)) #define intcs_evt2irq(evt) evt2irq(INTCS_VECT_BASE + (evt)) -- GitLab From f4dd61853e52251cc2661fb47cf133403ade1180 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 11 Mar 2010 05:42:21 +0000 Subject: [PATCH 0070/5312] ARM: mach-shmobile: sh7372 INTCS support Add support for the sh7372 INTCS interrupt controller. INTCS is the interrupt controller for the sh7372 SuperH processor core. It is tied into the INTCA interrupt controller which interfaces to the ARM processor. INTCS support is implemented using a new INTC table together with a chained interrupt handler that ties into the already supported INTCA controller. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/intc-sh7372.c | 220 +++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c index cfba59f057ec..e3551b56cd03 100644 --- a/arch/arm/mach-shmobile/intc-sh7372.c +++ b/arch/arm/mach-shmobile/intc-sh7372.c @@ -363,7 +363,227 @@ static struct intc_desc intca_desc __initdata = { intca_sense_registers, intca_ack_registers), }; +enum { + UNUSED_INTCS = 0, + + INTCS, + + /* interrupt sources INTCS */ + VEU_VEU0, VEU_VEU1, VEU_VEU2, VEU_VEU3, + RTDMAC_1_DEI0, RTDMAC_1_DEI1, RTDMAC_1_DEI2, RTDMAC_1_DEI3, + CEU, BEU_BEU0, BEU_BEU1, BEU_BEU2, + VPU, + TSIF1, + _3DG_SGX530, + _2DDMAC, + IIC2_ALI2, IIC2_TACKI2, IIC2_WAITI2, IIC2_DTEI2, + IPMMU_IPMMUR, IPMMU_IPMMUR2, + RTDMAC_2_DEI4, RTDMAC_2_DEI5, RTDMAC_2_DADERR, + MSIOF, + IIC0_ALI0, IIC0_TACKI0, IIC0_WAITI0, IIC0_DTEI0, + TMU_TUNI0, TMU_TUNI1, TMU_TUNI2, + CMT0, + TSIF0, + LMB, + CTI, + ICB, + JPU_JPEG, + LCDC, + LCRC, + RTDMAC2_1_DEI0, RTDMAC2_1_DEI1, RTDMAC2_1_DEI2, RTDMAC2_1_DEI3, + RTDMAC2_2_DEI4, RTDMAC2_2_DEI5, RTDMAC2_2_DADERR, + ISP, + LCDC1, + CSIRX, + DSITX_DSITX0, + DSITX_DSITX1, + TMU1_TUNI0, TMU1_TUNI1, TMU1_TUNI2, + CMT4, + DSITX1_DSITX1_0, + DSITX1_DSITX1_1, + CPORTS2R, + JPU6E, + + /* interrupt groups INTCS */ + RTDMAC_1, RTDMAC_2, VEU, BEU, IIC0, IPMMU, IIC2, + RTDMAC2_1, RTDMAC2_2, TMU1, DSITX, +}; + +static struct intc_vect intcs_vectors[] = { + INTCS_VECT(VEU_VEU0, 0x700), INTCS_VECT(VEU_VEU1, 0x720), + INTCS_VECT(VEU_VEU2, 0x740), INTCS_VECT(VEU_VEU3, 0x760), + INTCS_VECT(RTDMAC_1_DEI0, 0x800), INTCS_VECT(RTDMAC_1_DEI1, 0x820), + INTCS_VECT(RTDMAC_1_DEI2, 0x840), INTCS_VECT(RTDMAC_1_DEI3, 0x860), + INTCS_VECT(CEU, 0x880), INTCS_VECT(BEU_BEU0, 0x8a0), + INTCS_VECT(BEU_BEU1, 0x8c0), INTCS_VECT(BEU_BEU2, 0x8e0), + INTCS_VECT(VPU, 0x980), + INTCS_VECT(TSIF1, 0x9a0), + INTCS_VECT(_3DG_SGX530, 0x9e0), + INTCS_VECT(_2DDMAC, 0xa00), + INTCS_VECT(IIC2_ALI2, 0xa80), INTCS_VECT(IIC2_TACKI2, 0xaa0), + INTCS_VECT(IIC2_WAITI2, 0xac0), INTCS_VECT(IIC2_DTEI2, 0xae0), + INTCS_VECT(IPMMU_IPMMUR, 0xb00), INTCS_VECT(IPMMU_IPMMUR2, 0xb20), + INTCS_VECT(RTDMAC_2_DEI4, 0xb80), INTCS_VECT(RTDMAC_2_DEI5, 0xba0), + INTCS_VECT(RTDMAC_2_DADERR, 0xbc0), + INTCS_VECT(IIC0_ALI0, 0xe00), INTCS_VECT(IIC0_TACKI0, 0xe20), + INTCS_VECT(IIC0_WAITI0, 0xe40), INTCS_VECT(IIC0_DTEI0, 0xe60), + INTCS_VECT(TMU_TUNI0, 0xe80), INTCS_VECT(TMU_TUNI1, 0xea0), + INTCS_VECT(TMU_TUNI2, 0xec0), + INTCS_VECT(CMT0, 0xf00), + INTCS_VECT(TSIF0, 0xf20), + INTCS_VECT(LMB, 0xf60), + INTCS_VECT(CTI, 0x400), + INTCS_VECT(ICB, 0x480), + INTCS_VECT(JPU_JPEG, 0x560), + INTCS_VECT(LCDC, 0x580), + INTCS_VECT(LCRC, 0x5a0), + INTCS_VECT(RTDMAC2_1_DEI0, 0x1300), INTCS_VECT(RTDMAC2_1_DEI1, 0x1320), + INTCS_VECT(RTDMAC2_1_DEI2, 0x1340), INTCS_VECT(RTDMAC2_1_DEI3, 0x1360), + INTCS_VECT(RTDMAC2_2_DEI4, 0x1380), INTCS_VECT(RTDMAC2_2_DEI5, 0x13a0), + INTCS_VECT(RTDMAC2_2_DADERR, 0x13c0), + INTCS_VECT(ISP, 0x1720), + INTCS_VECT(LCDC1, 0x1780), + INTCS_VECT(CSIRX, 0x17a0), + INTCS_VECT(DSITX_DSITX0, 0x17c0), + INTCS_VECT(DSITX_DSITX1, 0x17e0), + INTCS_VECT(TMU1_TUNI0, 0x1900), INTCS_VECT(TMU1_TUNI1, 0x1920), + INTCS_VECT(TMU1_TUNI2, 0x1940), + INTCS_VECT(CMT4, 0x1980), + INTCS_VECT(DSITX1_DSITX1_0, 0x19a0), + INTCS_VECT(DSITX1_DSITX1_1, 0x19c0), + INTCS_VECT(CPORTS2R, 0x1a20), + INTCS_VECT(JPU6E, 0x1a80), + + INTC_VECT(INTCS, 0xf80), +}; + +static struct intc_group intcs_groups[] __initdata = { + INTC_GROUP(RTDMAC_1, RTDMAC_1_DEI0, RTDMAC_1_DEI1, + RTDMAC_1_DEI2, RTDMAC_1_DEI3), + INTC_GROUP(RTDMAC_2, RTDMAC_2_DEI4, RTDMAC_2_DEI5, RTDMAC_2_DADERR), + INTC_GROUP(VEU, VEU_VEU0, VEU_VEU1, VEU_VEU2, VEU_VEU3), + INTC_GROUP(BEU, BEU_BEU0, BEU_BEU1, BEU_BEU2), + INTC_GROUP(IIC0, IIC0_ALI0, IIC0_TACKI0, IIC0_WAITI0, IIC0_DTEI0), + INTC_GROUP(IPMMU, IPMMU_IPMMUR, IPMMU_IPMMUR2), + INTC_GROUP(IIC2, IIC2_ALI2, IIC2_TACKI2, IIC2_WAITI2, IIC2_DTEI2), + INTC_GROUP(RTDMAC2_1, RTDMAC2_1_DEI0, RTDMAC2_1_DEI1, + RTDMAC2_1_DEI2, RTDMAC2_1_DEI3), + INTC_GROUP(RTDMAC2_2, RTDMAC2_2_DEI4, + RTDMAC2_2_DEI5, RTDMAC2_2_DADERR), + INTC_GROUP(TMU1, TMU1_TUNI2, TMU1_TUNI1, TMU1_TUNI0), + INTC_GROUP(DSITX, DSITX_DSITX0, DSITX_DSITX1), +}; + +static struct intc_mask_reg intcs_mask_registers[] = { + { 0xffd20184, 0xffd201c4, 8, /* IMR1SA / IMCR1SA */ + { BEU_BEU2, BEU_BEU1, BEU_BEU0, CEU, + VEU_VEU3, VEU_VEU2, VEU_VEU1, VEU_VEU0 } }, + { 0xffd20188, 0xffd201c8, 8, /* IMR2SA / IMCR2SA */ + { 0, 0, 0, VPU, + 0, 0, 0, 0 } }, + { 0xffd2018c, 0xffd201cc, 8, /* IMR3SA / IMCR3SA */ + { 0, 0, 0, _2DDMAC, + 0, 0, 0, ICB } }, + { 0xffd20190, 0xffd201d0, 8, /* IMR4SA / IMCR4SA */ + { 0, 0, 0, CTI, + JPU_JPEG, 0, LCRC, LCDC } }, + { 0xffd20194, 0xffd201d4, 8, /* IMR5SA / IMCR5SA */ + { 0, RTDMAC_2_DADERR, RTDMAC_2_DEI5, RTDMAC_2_DEI4, + RTDMAC_1_DEI3, RTDMAC_1_DEI2, RTDMAC_1_DEI1, RTDMAC_1_DEI0 } }, + { 0xffd20198, 0xffd201d8, 8, /* IMR6SA / IMCR6SA */ + { 0, 0, MSIOF, 0, + _3DG_SGX530, 0, 0, 0 } }, + { 0xffd2019c, 0xffd201dc, 8, /* IMR7SA / IMCR7SA */ + { 0, TMU_TUNI2, TMU_TUNI1, TMU_TUNI0, + 0, 0, 0, 0 } }, + { 0xffd201a4, 0xffd201e4, 8, /* IMR9SA / IMCR9SA */ + { 0, 0, 0, CMT0, + IIC2_DTEI2, IIC2_WAITI2, IIC2_TACKI2, IIC2_ALI2 } }, + { 0xffd201a8, 0xffd201e8, 8, /* IMR10SA / IMCR10SA */ + { 0, 0, IPMMU_IPMMUR2, IPMMU_IPMMUR, + 0, 0, 0, 0 } }, + { 0xffd201ac, 0xffd201ec, 8, /* IMR11SA / IMCR11SA */ + { IIC0_DTEI0, IIC0_WAITI0, IIC0_TACKI0, IIC0_ALI0, + 0, TSIF1, LMB, TSIF0 } }, + { 0xffd50180, 0xffd501c0, 8, /* IMR0SA3 / IMCR0SA3 */ + { 0, RTDMAC2_2_DADERR, RTDMAC2_2_DEI5, RTDMAC2_2_DEI4, + RTDMAC2_1_DEI3, RTDMAC2_1_DEI2, RTDMAC2_1_DEI1, RTDMAC2_1_DEI0 } }, + { 0xffd50190, 0xffd501d0, 8, /* IMR4SA3 / IMCR4SA3 */ + { 0, ISP, 0, 0, + LCDC1, CSIRX, DSITX_DSITX0, DSITX_DSITX1 } }, + { 0xffd50198, 0xffd501d8, 8, /* IMR6SA3 / IMCR6SA3 */ + { 0, TMU1_TUNI2, TMU1_TUNI1, TMU1_TUNI0, + CMT4, DSITX1_DSITX1_0, DSITX1_DSITX1_1, 0 } }, + { 0xffd5019c, 0xffd501dc, 8, /* IMR7SA3 / IMCR7SA3 */ + { 0, CPORTS2R, 0, 0, + JPU6E, 0, 0, 0 } }, + { 0xffd20104, 0, 16, /* INTAMASK */ + { 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, INTCS } }, +}; + +/* Priority is needed for INTCA to receive the INTCS interrupt */ +static struct intc_prio_reg intcs_prio_registers[] = { + { 0xffd20000, 0, 16, 4, /* IPRAS */ { CTI, 0, _2DDMAC, ICB } }, + { 0xffd20004, 0, 16, 4, /* IPRBS */ { JPU_JPEG, LCDC, 0, LCRC } }, + { 0xffd20010, 0, 16, 4, /* IPRES */ { RTDMAC_1, CEU, 0, VPU } }, + { 0xffd20014, 0, 16, 4, /* IPRFS */ { 0, RTDMAC_2, 0, CMT0 } }, + { 0xffd20018, 0, 16, 4, /* IPRGS */ { TMU_TUNI0, TMU_TUNI1, + TMU_TUNI2, TSIF1 } }, + { 0xffd2001c, 0, 16, 4, /* IPRHS */ { 0, 0, VEU, BEU } }, + { 0xffd20020, 0, 16, 4, /* IPRIS */ { 0, MSIOF, TSIF0, IIC0 } }, + { 0xffd20024, 0, 16, 4, /* IPRJS */ { 0, _3DG_SGX530, 0, 0 } }, + { 0xffd20028, 0, 16, 4, /* IPRKS */ { 0, 0, LMB, 0 } }, + { 0xffd2002c, 0, 16, 4, /* IPRLS */ { IPMMU, 0, 0, 0 } }, + { 0xffd20030, 0, 16, 4, /* IPRMS */ { IIC2, 0, 0, 0 } }, + { 0xffd50000, 0, 16, 4, /* IPRAS3 */ { RTDMAC2_1, 0, 0, 0 } }, + { 0xffd50004, 0, 16, 4, /* IPRBS3 */ { RTDMAC2_2, 0, 0, 0 } }, + { 0xffd50020, 0, 16, 4, /* IPRIS3 */ { 0, ISP, 0, 0 } }, + { 0xffd50024, 0, 16, 4, /* IPRJS3 */ { LCDC1, CSIRX, DSITX, 0 } }, + { 0xffd50030, 0, 16, 4, /* IPRMS3 */ { TMU1, 0, 0, 0 } }, + { 0xffd50034, 0, 16, 4, /* IPRNS3 */ { CMT4, DSITX1_DSITX1_0, + DSITX1_DSITX1_1, 0 } }, + { 0xffd50038, 0, 16, 4, /* IPROS3 */ { 0, CPORTS2R, 0, 0 } }, + { 0xffd5003c, 0, 16, 4, /* IPRPS3 */ { JPU6E, 0, 0, 0 } }, +}; + +static struct resource intcs_resources[] __initdata = { + [0] = { + .start = 0xffd20000, + .end = 0xffd201ff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 0xffd50000, + .end = 0xffd501ff, + .flags = IORESOURCE_MEM, + } +}; + +static struct intc_desc intcs_desc __initdata = { + .name = "sh7372-intcs", + .resource = intcs_resources, + .num_resources = ARRAY_SIZE(intcs_resources), + .hw = INTC_HW_DESC(intcs_vectors, intcs_groups, intcs_mask_registers, + intcs_prio_registers, NULL, NULL), +}; + +static void intcs_demux(unsigned int irq, struct irq_desc *desc) +{ + void __iomem *reg = (void *)get_irq_data(irq); + unsigned int evtcodeas = ioread32(reg); + + generic_handle_irq(intcs_evt2irq(evtcodeas)); +} + void __init sh7372_init_irq(void) { + void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE); + register_intc_controller(&intca_desc); + register_intc_controller(&intcs_desc); + + /* demux using INTEVTSA */ + set_irq_data(evt2irq(0xf80), (void *)intevtsa); + set_irq_chained_handler(evt2irq(0xf80), intcs_demux); } -- GitLab From 645e522ee05f467b86f6fd2f3554fd6592418bae Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 12 May 2010 09:03:19 +0000 Subject: [PATCH 0071/5312] ARM: mach-shmobile: Enable TMU driver build Allow users to build the TMU driver on SH-Mobile ARM. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/Kconfig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index f2b88c5fe142..176135fb419a 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -76,6 +76,12 @@ config SH_TIMER_CMT help This enables build of the CMT timer driver. +config SH_TIMER_TMU + bool "TMU timer driver" + default y + help + This enables build of the TMU timer driver. + endmenu endif -- GitLab From e47bb515c57853c1f41474dae199cb033e747f66 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 12 May 2010 14:21:24 +0000 Subject: [PATCH 0072/5312] ARM: mach-shmobile: Use shared clock framework Teach SH-Mobile ARM how to make use of the shared SH clock framework. This commit is one atomic switch that dumps the local hackery and instead links in the shared clock framework code in drivers/sh. A few local functions are kept in clock.c. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/Kconfig | 3 ++ arch/arm/mach-shmobile/Makefile | 2 +- arch/arm/mach-shmobile/clock-sh7367.c | 36 +--------------- arch/arm/mach-shmobile/clock.c | 44 ++++++++++++++++++++ arch/arm/mach-shmobile/include/mach/common.h | 2 + drivers/sh/Makefile | 5 ++- 6 files changed, 54 insertions(+), 38 deletions(-) create mode 100644 arch/arm/mach-shmobile/clock.c diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 176135fb419a..698eb24ee8e8 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -84,4 +84,7 @@ config SH_TIMER_TMU endmenu +config SH_CLK_CPG + bool + endif diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index 6d385d371c33..09178f87625d 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -3,7 +3,7 @@ # # Common objects -obj-y := timer.o console.o +obj-y := timer.o console.o clock.o # CPU objects obj-$(CONFIG_ARCH_SH7367) += setup-sh7367.o clock-sh7367.o intc-sh7367.o diff --git a/arch/arm/mach-shmobile/clock-sh7367.c b/arch/arm/mach-shmobile/clock-sh7367.c index bb940c6e4e6c..f3ede5284ce3 100644 --- a/arch/arm/mach-shmobile/clock-sh7367.c +++ b/arch/arm/mach-shmobile/clock-sh7367.c @@ -21,43 +21,9 @@ #include #include #include - -struct clk { - const char *name; - unsigned long rate; -}; - +#include #include -int __clk_get(struct clk *clk) -{ - return 1; -} -EXPORT_SYMBOL(__clk_get); - -void __clk_put(struct clk *clk) -{ -} -EXPORT_SYMBOL(__clk_put); - - -int clk_enable(struct clk *clk) -{ - return 0; -} -EXPORT_SYMBOL(clk_enable); - -void clk_disable(struct clk *clk) -{ -} -EXPORT_SYMBOL(clk_disable); - -unsigned long clk_get_rate(struct clk *clk) -{ - return clk ? clk->rate : 0; -} -EXPORT_SYMBOL(clk_get_rate); - /* a static peripheral clock for now - enough to get sh-sci working */ static struct clk peripheral_clk = { .name = "peripheral_clk", diff --git a/arch/arm/mach-shmobile/clock.c b/arch/arm/mach-shmobile/clock.c new file mode 100644 index 000000000000..b7c705a213a2 --- /dev/null +++ b/arch/arm/mach-shmobile/clock.c @@ -0,0 +1,44 @@ +/* + * SH-Mobile Timer + * + * Copyright (C) 2010 Magnus Damm + * + * 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include +#include +#include + +int __init clk_init(void) +{ + /* Kick the child clocks.. */ + recalculate_root_clocks(); + + /* Enable the necessary init clocks */ + clk_enable_init_clocks(); + + return 0; +} + +int __clk_get(struct clk *clk) +{ + return 1; +} +EXPORT_SYMBOL(__clk_get); + +void __clk_put(struct clk *clk) +{ +} +EXPORT_SYMBOL(__clk_put); diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index 57903605cc51..f3d51858b9b8 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -4,6 +4,8 @@ extern struct sys_timer shmobile_timer; extern void shmobile_setup_console(void); +extern int clk_init(void); + extern void sh7367_init_irq(void); extern void sh7367_add_early_devices(void); extern void sh7367_add_standard_devices(void); diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile index 78bb5127abd0..08fc653a825c 100644 --- a/drivers/sh/Makefile +++ b/drivers/sh/Makefile @@ -1,9 +1,10 @@ # # Makefile for the SuperH specific drivers. # +obj-y := clk.o intc.o + obj-$(CONFIG_SUPERHYWAY) += superhyway/ obj-$(CONFIG_MAPLE) += maple/ + obj-$(CONFIG_GENERIC_GPIO) += pfc.o -obj-$(CONFIG_SUPERH) += clk.o obj-$(CONFIG_SH_CLK_CPG) += clk-cpg.o -obj-y += intc.o -- GitLab From 495b3cea94135a97e919bca67d7dcfdefafc7767 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 12 May 2010 14:21:34 +0000 Subject: [PATCH 0073/5312] ARM: mach-shmobile: sh7372 clock framework support V2 This patch is V2 of clock framework tables/code for sh7372. MSTP are included for KEYSC, SCIF, IIC, USB, SDHI and UIO. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/Kconfig | 1 + arch/arm/mach-shmobile/Makefile | 2 +- arch/arm/mach-shmobile/board-ap4evb.c | 16 +- arch/arm/mach-shmobile/clock-sh7372.c | 387 +++++++++++++++++++ arch/arm/mach-shmobile/include/mach/common.h | 1 + arch/arm/mach-shmobile/setup-sh7372.c | 8 +- 6 files changed, 404 insertions(+), 11 deletions(-) create mode 100644 arch/arm/mach-shmobile/clock-sh7372.c diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 698eb24ee8e8..a8bd47fca1df 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -21,6 +21,7 @@ config ARCH_SH7372 select CPU_V7 select HAVE_CLK select COMMON_CLKDEV + select SH_CLK_CPG select GENERIC_CLOCKEVENTS comment "SH-Mobile Board Type" diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index 09178f87625d..3995b3bd64b4 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -8,7 +8,7 @@ obj-y := timer.o console.o clock.o # CPU objects obj-$(CONFIG_ARCH_SH7367) += setup-sh7367.o clock-sh7367.o intc-sh7367.o obj-$(CONFIG_ARCH_SH7377) += setup-sh7377.o clock-sh7367.o intc-sh7377.o -obj-$(CONFIG_ARCH_SH7372) += setup-sh7372.o clock-sh7367.o intc-sh7372.o +obj-$(CONFIG_ARCH_SH7372) += setup-sh7372.o clock-sh7372.o intc-sh7372.o # Pinmux setup pfc-$(CONFIG_ARCH_SH7367) := pfc-sh7367.o diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index d3b8ca5d4041..4d197e36270a 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -39,6 +39,7 @@ #include #include #include +#include /* * Address Interface BusWidth note @@ -328,9 +329,8 @@ static void __init ap4evb_map_io(void) { iotable_init(ap4evb_io_desc, ARRAY_SIZE(ap4evb_io_desc)); - /* setup early devices, clocks and console here as well */ + /* setup early devices and console here as well */ sh7372_add_early_devices(); - sh7367_clock_init(); /* use g3 clocks for now */ shmobile_setup_console(); } @@ -419,11 +419,21 @@ static void __init ap4evb_init(void) platform_add_devices(ap4evb_devices, ARRAY_SIZE(ap4evb_devices)); } +static void __init ap4evb_timer_init(void) +{ + sh7372_clock_init(); + shmobile_timer.init(); +} + +static struct sys_timer ap4evb_timer = { + .init = ap4evb_timer_init, +}; + MACHINE_START(AP4EVB, "ap4evb") .phys_io = 0xe6000000, .io_pg_offst = ((0xe6000000) >> 18) & 0xfffc, .map_io = ap4evb_map_io, .init_irq = sh7372_init_irq, .init_machine = ap4evb_init, - .timer = &shmobile_timer, + .timer = &ap4evb_timer, MACHINE_END diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c new file mode 100644 index 000000000000..ac46b4bce522 --- /dev/null +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -0,0 +1,387 @@ +/* + * SH7372 clock framework support + * + * Copyright (C) 2010 Magnus Damm + * + * 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 + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include + +/* SH7372 registers */ +#define FRQCRA 0xe6150000 +#define FRQCRB 0xe6150004 +#define FRQCRC 0xe61500e0 +#define FRQCRD 0xe61500e4 +#define VCLKCR1 0xe6150008 +#define VCLKCR2 0xe615000c +#define VCLKCR3 0xe615001c +#define FMSICKCR 0xe6150010 +#define FMSOCKCR 0xe6150014 +#define FSIACKCR 0xe6150018 +#define FSIBCKCR 0xe6150090 +#define SUBCKCR 0xe6150080 +#define SPUCKCR 0xe6150084 +#define VOUCKCR 0xe6150088 +#define HDMICKCR 0xe6150094 +#define DSITCKCR 0xe6150060 +#define DSI0PCKCR 0xe6150064 +#define DSI1PCKCR 0xe6150098 +#define PLLC01CR 0xe6150028 +#define PLLC2CR 0xe615002c +#define SMSTPCR0 0xe6150130 +#define SMSTPCR1 0xe6150134 +#define SMSTPCR2 0xe6150138 +#define SMSTPCR3 0xe615013c +#define SMSTPCR4 0xe6150140 + +/* Fixed 32 KHz root clock from EXTALR pin */ +static struct clk r_clk = { + .rate = 32768, +}; + +/* + * 26MHz default rate for the EXTAL1 root input clock. + * If needed, reset this with clk_set_rate() from the platform code. + */ +struct clk extal1_clk = { + .rate = 26666666, +}; + +/* + * 48MHz default rate for the EXTAL2 root input clock. + * If needed, reset this with clk_set_rate() from the platform code. + */ +struct clk extal2_clk = { + .rate = 48000000, +}; + +/* A fixed divide-by-2 block */ +static unsigned long div2_recalc(struct clk *clk) +{ + return clk->parent->rate / 2; +} + +static struct clk_ops div2_clk_ops = { + .recalc = div2_recalc, +}; + +/* Divide extal1 by two */ +static struct clk extal1_div2_clk = { + .ops = &div2_clk_ops, + .parent = &extal1_clk, +}; + +/* Divide extal2 by two */ +static struct clk extal2_div2_clk = { + .ops = &div2_clk_ops, + .parent = &extal2_clk, +}; + +/* Divide extal2 by four */ +static struct clk extal2_div4_clk = { + .ops = &div2_clk_ops, + .parent = &extal2_div2_clk, +}; + +/* PLLC0 and PLLC1 */ +static unsigned long pllc01_recalc(struct clk *clk) +{ + unsigned long mult = 1; + + if (__raw_readl(PLLC01CR) & (1 << 14)) + mult = (((__raw_readl(clk->enable_reg) >> 24) & 0x3f) + 1) * 2; + + return clk->parent->rate * mult; +} + +static struct clk_ops pllc01_clk_ops = { + .recalc = pllc01_recalc, +}; + +static struct clk pllc0_clk = { + .ops = &pllc01_clk_ops, + .flags = CLK_ENABLE_ON_INIT, + .parent = &extal1_div2_clk, + .enable_reg = (void __iomem *)FRQCRC, +}; + +static struct clk pllc1_clk = { + .ops = &pllc01_clk_ops, + .flags = CLK_ENABLE_ON_INIT, + .parent = &extal1_div2_clk, + .enable_reg = (void __iomem *)FRQCRA, +}; + +/* Divide PLLC1 by two */ +static struct clk pllc1_div2_clk = { + .ops = &div2_clk_ops, + .parent = &pllc1_clk, +}; + +/* PLLC2 */ +static unsigned long pllc2_recalc(struct clk *clk) +{ + unsigned long mult = 1; + + if (__raw_readl(PLLC2CR) & (1 << 31)) + mult = (((__raw_readl(PLLC2CR) >> 24) & 0x3f) + 1) * 2; + + return clk->parent->rate * mult; +} + +static struct clk_ops pllc2_clk_ops = { + .recalc = pllc2_recalc, +}; + +static struct clk pllc2_clk = { + .ops = &pllc2_clk_ops, + .flags = CLK_ENABLE_ON_INIT, + .parent = &extal1_div2_clk, +}; + +struct clk *main_clks[] = { + &r_clk, + &extal1_clk, + &extal2_clk, + &extal1_div2_clk, + &extal2_div2_clk, + &extal2_div4_clk, + &pllc0_clk, + &pllc1_clk, + &pllc1_div2_clk, + &pllc2_clk, +}; + +static void div4_kick(struct clk *clk) +{ + unsigned long value; + + /* set KICK bit in FRQCRB to update hardware setting */ + value = __raw_readl(FRQCRB); + value |= (1 << 31); + __raw_writel(value, FRQCRB); +} + +static int divisors[] = { 2, 3, 4, 6, 8, 12, 16, 18, + 24, 32, 36, 48, 0, 72, 96, 0 }; + +static struct clk_div_mult_table div4_div_mult_table = { + .divisors = divisors, + .nr_divisors = ARRAY_SIZE(divisors), +}; + +static struct clk_div4_table div4_table = { + .div_mult_table = &div4_div_mult_table, + .kick = div4_kick, +}; + +enum { DIV4_I, DIV4_ZG, DIV4_B, DIV4_M1, DIV4_CSIR, + DIV4_ZTR, DIV4_ZT, DIV4_ZX, DIV4_HP, + DIV4_ISPB, DIV4_S, DIV4_ZB, DIV4_ZB3, DIV4_CP, + DIV4_DDRP, DIV4_NR }; + +#define DIV4(_reg, _bit, _mask, _flags) \ + SH_CLK_DIV4(&pllc1_clk, _reg, _bit, _mask, _flags) + +struct clk div4_clks[DIV4_NR] = { + [DIV4_I] = DIV4(FRQCRA, 20, 0x6fff, CLK_ENABLE_ON_INIT), + [DIV4_ZG] = DIV4(FRQCRA, 16, 0x6fff, CLK_ENABLE_ON_INIT), + [DIV4_B] = DIV4(FRQCRA, 8, 0x6fff, CLK_ENABLE_ON_INIT), + [DIV4_M1] = DIV4(FRQCRA, 4, 0x6fff, CLK_ENABLE_ON_INIT), + [DIV4_CSIR] = DIV4(FRQCRA, 0, 0x6fff, 0), + [DIV4_ZTR] = DIV4(FRQCRB, 20, 0x6fff, 0), + [DIV4_ZT] = DIV4(FRQCRB, 16, 0x6fff, 0), + [DIV4_ZX] = DIV4(FRQCRB, 12, 0x6fff, 0), + [DIV4_HP] = DIV4(FRQCRB, 4, 0x6fff, 0), + [DIV4_ISPB] = DIV4(FRQCRC, 20, 0x6fff, 0), + [DIV4_S] = DIV4(FRQCRC, 12, 0x6fff, 0), + [DIV4_ZB] = DIV4(FRQCRC, 8, 0x6fff, 0), + [DIV4_ZB3] = DIV4(FRQCRC, 4, 0x6fff, 0), + [DIV4_CP] = DIV4(FRQCRC, 0, 0x6fff, 0), + [DIV4_DDRP] = DIV4(FRQCRD, 0, 0x677c, 0), +}; + +enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_FMSI, DIV6_FMSO, + DIV6_FSIA, DIV6_FSIB, DIV6_SUB, DIV6_SPU, + DIV6_VOU, DIV6_HDMI, DIV6_DSIT, DIV6_DSI0P, DIV6_DSI1P, + DIV6_NR }; + +struct clk div6_clks[DIV6_NR] = { + [DIV6_VCK1] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR1, 0), + [DIV6_VCK2] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR2, 0), + [DIV6_VCK3] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR3, 0), + [DIV6_FMSI] = SH_CLK_DIV6(&pllc1_div2_clk, FMSICKCR, 0), + [DIV6_FMSO] = SH_CLK_DIV6(&pllc1_div2_clk, FMSOCKCR, 0), + [DIV6_FSIA] = SH_CLK_DIV6(&pllc1_div2_clk, FSIACKCR, 0), + [DIV6_FSIB] = SH_CLK_DIV6(&pllc1_div2_clk, FSIBCKCR, 0), + [DIV6_SUB] = SH_CLK_DIV6(&extal2_clk, SUBCKCR, 0), + [DIV6_SPU] = SH_CLK_DIV6(&pllc1_div2_clk, SPUCKCR, 0), + [DIV6_VOU] = SH_CLK_DIV6(&pllc1_div2_clk, VOUCKCR, 0), + [DIV6_HDMI] = SH_CLK_DIV6(&pllc1_div2_clk, HDMICKCR, 0), + [DIV6_DSIT] = SH_CLK_DIV6(&pllc1_div2_clk, DSITCKCR, 0), + [DIV6_DSI0P] = SH_CLK_DIV6(&pllc1_div2_clk, DSI0PCKCR, 0), + [DIV6_DSI1P] = SH_CLK_DIV6(&pllc1_div2_clk, DSI1PCKCR, 0), +}; + +enum { MSTP001, + MSTP131, MSTP130, MSTP129, MSTP128, MSTP116, MSTP106, MSTP101, + MSTP223, + MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200, + MSTP329, MSTP323, MSTP322, MSTP314, MSTP313, + MSTP415, MSTP410, MSTP411, MSTP406, MSTP403, + MSTP_NR }; + +#define MSTP(_parent, _reg, _bit, _flags) \ + SH_CLK_MSTP32(_parent, _reg, _bit, _flags) + +static struct clk mstp_clks[MSTP_NR] = { + [MSTP001] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR0, 1, 0), /* IIC2 */ + [MSTP131] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 31, 0), /* VEU3 */ + [MSTP130] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 30, 0), /* VEU2 */ + [MSTP129] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 29, 0), /* VEU1 */ + [MSTP128] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 28, 0), /* VEU0 */ + [MSTP116] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */ + [MSTP106] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 6, 0), /* JPU */ + [MSTP101] = MSTP(&div4_clks[DIV4_M1], SMSTPCR1, 1, 0), /* VPU */ + [MSTP223] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR2, 23, 0), /* SPU2 */ + [MSTP207] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 7, 0), /* SCIFA5 */ + [MSTP206] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 6, 0), /* SCIFB */ + [MSTP204] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 4, 0), /* SCIFA0 */ + [MSTP203] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 3, 0), /* SCIFA1 */ + [MSTP202] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 2, 0), /* SCIFA2 */ + [MSTP201] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 1, 0), /* SCIFA3 */ + [MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */ + [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */ + [MSTP323] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */ + [MSTP322] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 22, 0), /* USB0 */ + [MSTP314] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 14, 0), /* SDHI0 */ + [MSTP313] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 13, 0), /* SDHI1 */ + [MSTP415] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 15, 0), /* SDHI2 */ + [MSTP411] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 11, 0), /* IIC3 */ + [MSTP410] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 10, 0), /* IIC4 */ + [MSTP406] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 6, 0), /* USB1 */ + [MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */ +}; + +#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk } +#define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk } + +static struct clk_lookup lookups[] = { + /* main clocks */ + CLKDEV_CON_ID("r_clk", &r_clk), + CLKDEV_CON_ID("extal1", &extal1_clk), + CLKDEV_CON_ID("extal2", &extal2_clk), + CLKDEV_CON_ID("extal1_div2_clk", &extal1_div2_clk), + CLKDEV_CON_ID("extal2_div2_clk", &extal2_div2_clk), + CLKDEV_CON_ID("extal2_div4_clk", &extal2_div4_clk), + CLKDEV_CON_ID("pllc0_clk", &pllc0_clk), + CLKDEV_CON_ID("pllc1_clk", &pllc1_clk), + CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk), + CLKDEV_CON_ID("pllc2_clk", &pllc2_clk), + + /* DIV4 clocks */ + CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]), + CLKDEV_CON_ID("zg_clk", &div4_clks[DIV4_ZG]), + CLKDEV_CON_ID("b_clk", &div4_clks[DIV4_B]), + CLKDEV_CON_ID("m1_clk", &div4_clks[DIV4_M1]), + CLKDEV_CON_ID("csir_clk", &div4_clks[DIV4_CSIR]), + CLKDEV_CON_ID("ztr_clk", &div4_clks[DIV4_ZTR]), + CLKDEV_CON_ID("zt_clk", &div4_clks[DIV4_ZT]), + CLKDEV_CON_ID("zx_clk", &div4_clks[DIV4_ZX]), + CLKDEV_CON_ID("hp_clk", &div4_clks[DIV4_HP]), + CLKDEV_CON_ID("ispb_clk", &div4_clks[DIV4_ISPB]), + CLKDEV_CON_ID("s_clk", &div4_clks[DIV4_S]), + CLKDEV_CON_ID("zb_clk", &div4_clks[DIV4_ZB]), + CLKDEV_CON_ID("zb3_clk", &div4_clks[DIV4_ZB3]), + CLKDEV_CON_ID("cp_clk", &div4_clks[DIV4_CP]), + CLKDEV_CON_ID("ddrp_clk", &div4_clks[DIV4_DDRP]), + + /* DIV6 clocks */ + CLKDEV_CON_ID("vck1_clk", &div6_clks[DIV6_VCK1]), + CLKDEV_CON_ID("vck2_clk", &div6_clks[DIV6_VCK2]), + CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]), + CLKDEV_CON_ID("fmsi_clk", &div6_clks[DIV6_FMSI]), + CLKDEV_CON_ID("fmso_clk", &div6_clks[DIV6_FMSO]), + CLKDEV_CON_ID("fsia_clk", &div6_clks[DIV6_FSIA]), + CLKDEV_CON_ID("fsib_clk", &div6_clks[DIV6_FSIB]), + CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]), + CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]), + CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]), + CLKDEV_CON_ID("hdmi_clk", &div6_clks[DIV6_HDMI]), + CLKDEV_CON_ID("dsit_clk", &div6_clks[DIV6_DSIT]), + CLKDEV_CON_ID("dsi0p_clk", &div6_clks[DIV6_DSI0P]), + CLKDEV_CON_ID("dsi1p_clk", &div6_clks[DIV6_DSI1P]), + + /* MSTP32 clocks */ + CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* IIC2 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.3", &mstp_clks[MSTP131]), /* VEU3 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.2", &mstp_clks[MSTP130]), /* VEU2 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.1", &mstp_clks[MSTP129]), /* VEU1 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.0", &mstp_clks[MSTP128]), /* VEU0 */ + CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* IIC0 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.5", &mstp_clks[MSTP106]), /* JPU */ + CLKDEV_DEV_ID("uio_pdrv_genirq.0", &mstp_clks[MSTP101]), /* VPU */ + CLKDEV_DEV_ID("uio_pdrv_genirq.6", &mstp_clks[MSTP223]), /* SPU2DSP0 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.7", &mstp_clks[MSTP223]), /* SPU2DSP1 */ + CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), /* SCIFA5 */ + CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP206]), /* SCIFB */ + CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */ + CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP203]), /* SCIFA1 */ + CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP202]), /* SCIFA2 */ + CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), /* SCIFA3 */ + CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */ + CLKDEV_CON_ID("cmt1", &mstp_clks[MSTP329]), /* CMT10 */ + CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */ + CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP323]), /* USB0 */ + CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP323]), /* USB0 */ + CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */ + CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */ + CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP415]), /* SDHI2 */ + CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* IIC3 */ + CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* IIC4 */ + CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */ + CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */ + CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */ +}; + +void __init sh7372_clock_init(void) +{ + int k, ret = 0; + + for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++) + ret = clk_register(main_clks[k]); + + if (!ret) + ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table); + + if (!ret) + ret = sh_clk_div6_register(div6_clks, DIV6_NR); + + if (!ret) + ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); + + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); + + if (!ret) + clk_init(); + else + panic("failed to setup sh7372 clocks\n"); + +} diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index f3d51858b9b8..780bd65140da 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -20,6 +20,7 @@ extern void sh7377_pinmux_init(void); extern void sh7372_init_irq(void); extern void sh7372_add_early_devices(void); extern void sh7372_add_standard_devices(void); +extern void sh7372_clock_init(void); extern void sh7372_pinmux_init(void); #endif /* __ARCH_MACH_COMMON_H */ diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index b7c5d896e01c..885dfaa54c2a 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c @@ -143,7 +143,7 @@ static struct sh_timer_config cmt10_platform_data = { .name = "CMT10", .channel_offset = 0x10, .timer_bit = 0, - .clk = "r_clk", + .clk = "cmt1", .clockevent_rating = 125, .clocksource_rating = 125, }; @@ -233,14 +233,8 @@ void __init sh7372_add_standard_devices(void) ARRAY_SIZE(sh7372_early_devices)); } -#define SMSTPCR3 0xe615013c -#define SMSTPCR3_CMT1 (1 << 29) - void __init sh7372_add_early_devices(void) { - /* enable clock to CMT1 */ - __raw_writel(__raw_readl(SMSTPCR3) & ~SMSTPCR3_CMT1, SMSTPCR3); - early_platform_add_devices(sh7372_early_devices, ARRAY_SIZE(sh7372_early_devices)); } -- GitLab From 85f91dd082b5569b323ca261f0242c33a25d3a12 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 13 May 2010 01:07:54 +0000 Subject: [PATCH 0074/5312] ARM: mach-shmobile: g3evm: Add IrDA support Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-g3evm.c | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/arch/arm/mach-shmobile/board-g3evm.c b/arch/arm/mach-shmobile/board-g3evm.c index 9247503296c4..19b3bf3bf566 100644 --- a/arch/arm/mach-shmobile/board-g3evm.c +++ b/arch/arm/mach-shmobile/board-g3evm.c @@ -38,6 +38,14 @@ #include #include +/* + * IrDA + * + * S67: 5bit : ON power + * : 6bit : ON remote control + * OFF IrDA + */ + static struct mtd_partition nor_flash_partitions[] = { { .name = "loader", @@ -209,11 +217,30 @@ static struct platform_device nand_flash_device = { }, }; +static struct resource irda_resources[] = { + [0] = { + .start = 0xE6D00000, + .end = 0xE6D01FD4 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 20, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device irda_device = { + .name = "sh_irda", + .resource = irda_resources, + .num_resources = ARRAY_SIZE(irda_resources), +}; + static struct platform_device *g3evm_devices[] __initdata = { &nor_flash_device, &usb_host_device, &keysc_device, &nand_flash_device, + &irda_device, }; static struct map_desc g3evm_io_desc[] __initdata = { @@ -318,6 +345,12 @@ static void __init g3evm_init(void) /* FOE, FCDE, FSC on dedicated pins */ __raw_writel(__raw_readl(0xe6158048) & ~(1 << 15), 0xe6158048); + /* IrDA */ + gpio_request(GPIO_FN_IRDA_OUT, NULL); + gpio_request(GPIO_FN_IRDA_IN, NULL); + gpio_request(GPIO_FN_IRDA_FIRSEL, NULL); + set_irq_type(20, IRQ_TYPE_LEVEL_LOW); + sh7367_add_standard_devices(); platform_add_devices(g3evm_devices, ARRAY_SIZE(g3evm_devices)); -- GitLab From 4a539a2023fd2f7384916ef6e7777ad234a00dcd Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 20 May 2010 12:48:02 +0900 Subject: [PATCH 0075/5312] ARM: mach-shmobile: update defconfigs. Signed-off-by: Paul Mundt --- arch/arm/configs/ap4evb_defconfig | 71 +++++++++++++++++++++++++----- arch/arm/configs/g3evm_defconfig | 73 ++++++++++++++++++++++++++----- arch/arm/configs/g4evm_defconfig | 72 +++++++++++++++++++++++++----- 3 files changed, 181 insertions(+), 35 deletions(-) diff --git a/arch/arm/configs/ap4evb_defconfig b/arch/arm/configs/ap4evb_defconfig index e14229be7676..eb38098545d3 100644 --- a/arch/arm/configs/ap4evb_defconfig +++ b/arch/arm/configs/ap4evb_defconfig @@ -1,12 +1,15 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.33-rc7 -# Mon Feb 8 12:25:36 2010 +# Linux kernel version: 2.6.34 +# Thu May 20 12:18:56 2010 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y CONFIG_GENERIC_TIME=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_HAVE_PROC_CPU=y CONFIG_GENERIC_HARDIRQS=y CONFIG_STACKTRACE_SUPPORT=y CONFIG_HAVE_LATENCYTOP_SUPPORT=y @@ -17,6 +20,7 @@ CONFIG_GENERIC_IRQ_PROBE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y CONFIG_VECTORS_BASE=0xffff0000 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -31,6 +35,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32 CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y CONFIG_HAVE_KERNEL_LZO=y CONFIG_KERNEL_GZIP=y # CONFIG_KERNEL_BZIP2 is not set @@ -54,11 +59,6 @@ CONFIG_RCU_FANOUT=32 CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 -CONFIG_GROUP_SCHED=y -CONFIG_FAIR_GROUP_SCHED=y -# CONFIG_RT_GROUP_SCHED is not set -CONFIG_USER_SCHED=y -# CONFIG_CGROUP_SCHED is not set # CONFIG_CGROUPS is not set # CONFIG_SYSFS_DEPRECATED_V2 is not set # CONFIG_RELAY is not set @@ -94,10 +94,14 @@ CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_AIO=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y # # Kernel Performance Events And Counters # +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERF_COUNTERS is not set CONFIG_VM_EVENT_COUNTERS=y CONFIG_COMPAT_BRK=y CONFIG_SLAB=y @@ -172,8 +176,11 @@ CONFIG_MMU=y # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_REALVIEW is not set # CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set # CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCMRING is not set # CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set # CONFIG_ARCH_GEMINI is not set # CONFIG_ARCH_EBSA110 is not set # CONFIG_ARCH_EP93XX is not set @@ -182,7 +189,6 @@ CONFIG_MMU=y # CONFIG_ARCH_STMP3XXX is not set # CONFIG_ARCH_NETX is not set # CONFIG_ARCH_H720X is not set -# CONFIG_ARCH_NOMADIK is not set # CONFIG_ARCH_IOP13XX is not set # CONFIG_ARCH_IOP32X is not set # CONFIG_ARCH_IOP33X is not set @@ -199,6 +205,7 @@ CONFIG_MMU=y # CONFIG_ARCH_KS8695 is not set # CONFIG_ARCH_NS9XXX is not set # CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_NUC93X is not set # CONFIG_ARCH_PNX4008 is not set # CONFIG_ARCH_PXA is not set # CONFIG_ARCH_MSM is not set @@ -207,14 +214,18 @@ CONFIG_ARCH_SHMOBILE=y # CONFIG_ARCH_SA1100 is not set # CONFIG_ARCH_S3C2410 is not set # CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P6440 is not set +# CONFIG_ARCH_S5P6442 is not set # CONFIG_ARCH_S5PC1XX is not set +# CONFIG_ARCH_S5PV210 is not set # CONFIG_ARCH_SHARK is not set # CONFIG_ARCH_LH7A40X is not set # CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set # CONFIG_ARCH_DAVINCI is not set # CONFIG_ARCH_OMAP is not set -# CONFIG_ARCH_BCMRING is not set -# CONFIG_ARCH_U8500 is not set +# CONFIG_PLAT_SPEAR is not set # # SH-Mobile System Type @@ -242,6 +253,8 @@ CONFIG_MEMORY_SIZE=0x10000000 # Timer and clock configuration # CONFIG_SH_TIMER_CMT=y +CONFIG_SH_TIMER_TMU=y +CONFIG_SH_CLK_CPG=y # # Processor Type @@ -269,6 +282,8 @@ CONFIG_ARM_THUMB=y # CONFIG_CPU_BPREDICT_DISABLE is not set CONFIG_HAS_TLS_REG=y CONFIG_ARM_L1_CACHE_SHIFT=5 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_CPU_HAS_PMU=y # CONFIG_ARM_ERRATA_430973 is not set # CONFIG_ARM_ERRATA_458693 is not set # CONFIG_ARM_ERRATA_460075 is not set @@ -322,7 +337,7 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="console=ttySC0,115200 earlyprintk=sh-sci.0,115200" +CONFIG_CMDLINE="console=ttySC0,115200" # CONFIG_XIP_KERNEL is not set CONFIG_KEXEC=y CONFIG_ATAGS_PROC=y @@ -452,10 +467,12 @@ CONFIG_MTD_NAND=y # CONFIG_MTD_NAND_VERIFY_WRITE is not set # CONFIG_MTD_NAND_ECC_SMC is not set # CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_GPIO is not set CONFIG_MTD_NAND_IDS=y # CONFIG_MTD_NAND_DISKONCHIP is not set # CONFIG_MTD_NAND_NANDSIM is not set # CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_NAND_SH_FLCTL is not set # CONFIG_MTD_ONENAND is not set # @@ -476,6 +493,7 @@ CONFIG_HAVE_IDE=y # # SCSI device support # +CONFIG_SCSI_MOD=y # CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set # CONFIG_SCSI_DMA is not set @@ -543,6 +561,7 @@ CONFIG_SERIAL_SH_SCI_NR_UARTS=8 CONFIG_SERIAL_SH_SCI_CONSOLE=y CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_TIMBERDALE is not set CONFIG_UNIX98_PTYS=y # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set # CONFIG_LEGACY_PTYS is not set @@ -558,6 +577,31 @@ CONFIG_UNIX98_PTYS=y # PPS support # # CONFIG_PPS is not set +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +# CONFIG_GPIO_SYSFS is not set + +# +# Memory mapped GPIO expanders: +# +# CONFIG_GPIO_IT8761E is not set + +# +# I2C GPIO expanders: +# + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# + +# +# AC97 GPIO expanders: +# # CONFIG_W1 is not set # CONFIG_POWER_SUPPLY is not set # CONFIG_HWMON is not set @@ -575,10 +619,14 @@ CONFIG_SSB_POSSIBLE=y # # CONFIG_MFD_CORE is not set # CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_MFD_SH_MOBILE_SDHI is not set +# CONFIG_HTC_EGPIO is not set # CONFIG_HTC_PASIC3 is not set # CONFIG_MFD_TMIO is not set # CONFIG_MFD_T7L66XB is not set # CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set # CONFIG_REGULATOR is not set # CONFIG_MEDIA_SUPPORT is not set @@ -733,6 +781,7 @@ CONFIG_DEBUG_MEMORY_INIT=y CONFIG_HAVE_FUNCTION_TRACER=y CONFIG_TRACING_SUPPORT=y # CONFIG_FTRACE is not set +# CONFIG_ATOMIC64_SELFTEST is not set # CONFIG_SAMPLES is not set CONFIG_HAVE_ARCH_KGDB=y # CONFIG_KGDB is not set diff --git a/arch/arm/configs/g3evm_defconfig b/arch/arm/configs/g3evm_defconfig index 3c19031961db..549e46064a29 100644 --- a/arch/arm/configs/g3evm_defconfig +++ b/arch/arm/configs/g3evm_defconfig @@ -1,12 +1,15 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.33-rc7 -# Mon Feb 8 12:20:01 2010 +# Linux kernel version: 2.6.34 +# Thu May 20 12:21:19 2010 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y CONFIG_GENERIC_TIME=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_HAVE_PROC_CPU=y CONFIG_GENERIC_HARDIRQS=y CONFIG_STACKTRACE_SUPPORT=y CONFIG_HAVE_LATENCYTOP_SUPPORT=y @@ -17,6 +20,7 @@ CONFIG_GENERIC_IRQ_PROBE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y CONFIG_VECTORS_BASE=0xffff0000 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -31,6 +35,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32 CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y CONFIG_HAVE_KERNEL_LZO=y CONFIG_KERNEL_GZIP=y # CONFIG_KERNEL_BZIP2 is not set @@ -54,11 +59,6 @@ CONFIG_RCU_FANOUT=32 CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 -CONFIG_GROUP_SCHED=y -CONFIG_FAIR_GROUP_SCHED=y -# CONFIG_RT_GROUP_SCHED is not set -CONFIG_USER_SCHED=y -# CONFIG_CGROUP_SCHED is not set # CONFIG_CGROUPS is not set # CONFIG_SYSFS_DEPRECATED_V2 is not set # CONFIG_RELAY is not set @@ -94,10 +94,14 @@ CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_AIO=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y # # Kernel Performance Events And Counters # +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERF_COUNTERS is not set CONFIG_VM_EVENT_COUNTERS=y CONFIG_COMPAT_BRK=y CONFIG_SLAB=y @@ -172,8 +176,11 @@ CONFIG_MMU=y # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_REALVIEW is not set # CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set # CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCMRING is not set # CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set # CONFIG_ARCH_GEMINI is not set # CONFIG_ARCH_EBSA110 is not set # CONFIG_ARCH_EP93XX is not set @@ -182,7 +189,6 @@ CONFIG_MMU=y # CONFIG_ARCH_STMP3XXX is not set # CONFIG_ARCH_NETX is not set # CONFIG_ARCH_H720X is not set -# CONFIG_ARCH_NOMADIK is not set # CONFIG_ARCH_IOP13XX is not set # CONFIG_ARCH_IOP32X is not set # CONFIG_ARCH_IOP33X is not set @@ -199,6 +205,7 @@ CONFIG_MMU=y # CONFIG_ARCH_KS8695 is not set # CONFIG_ARCH_NS9XXX is not set # CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_NUC93X is not set # CONFIG_ARCH_PNX4008 is not set # CONFIG_ARCH_PXA is not set # CONFIG_ARCH_MSM is not set @@ -207,14 +214,18 @@ CONFIG_ARCH_SHMOBILE=y # CONFIG_ARCH_SA1100 is not set # CONFIG_ARCH_S3C2410 is not set # CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P6440 is not set +# CONFIG_ARCH_S5P6442 is not set # CONFIG_ARCH_S5PC1XX is not set +# CONFIG_ARCH_S5PV210 is not set # CONFIG_ARCH_SHARK is not set # CONFIG_ARCH_LH7A40X is not set # CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set # CONFIG_ARCH_DAVINCI is not set # CONFIG_ARCH_OMAP is not set -# CONFIG_ARCH_BCMRING is not set -# CONFIG_ARCH_U8500 is not set +# CONFIG_PLAT_SPEAR is not set # # SH-Mobile System Type @@ -242,6 +253,7 @@ CONFIG_MEMORY_SIZE=0x08000000 # Timer and clock configuration # CONFIG_SH_TIMER_CMT=y +CONFIG_SH_TIMER_TMU=y # # Processor Type @@ -267,6 +279,8 @@ CONFIG_ARM_THUMB=y # CONFIG_CPU_DCACHE_DISABLE is not set # CONFIG_CPU_BPREDICT_DISABLE is not set CONFIG_ARM_L1_CACHE_SHIFT=5 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_CPU_HAS_PMU=y # CONFIG_ARM_ERRATA_411920 is not set CONFIG_COMMON_CLKDEV=y @@ -317,7 +331,7 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="console=ttySC1,115200 earlyprintk=sh-sci.1,115200" +CONFIG_CMDLINE="console=ttySC1,115200" # CONFIG_XIP_KERNEL is not set CONFIG_KEXEC=y CONFIG_ATAGS_PROC=y @@ -447,10 +461,12 @@ CONFIG_MTD_NAND=y # CONFIG_MTD_NAND_VERIFY_WRITE is not set # CONFIG_MTD_NAND_ECC_SMC is not set # CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_GPIO is not set CONFIG_MTD_NAND_IDS=y # CONFIG_MTD_NAND_DISKONCHIP is not set # CONFIG_MTD_NAND_NANDSIM is not set # CONFIG_MTD_NAND_PLATFORM is not set +CONFIG_MTD_NAND_SH_FLCTL=y # CONFIG_MTD_ONENAND is not set # @@ -471,6 +487,7 @@ CONFIG_HAVE_IDE=y # # SCSI device support # +CONFIG_SCSI_MOD=y # CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set # CONFIG_SCSI_DMA is not set @@ -538,6 +555,7 @@ CONFIG_SERIAL_SH_SCI_NR_UARTS=8 CONFIG_SERIAL_SH_SCI_CONSOLE=y CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_TIMBERDALE is not set CONFIG_UNIX98_PTYS=y # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set # CONFIG_LEGACY_PTYS is not set @@ -553,6 +571,31 @@ CONFIG_UNIX98_PTYS=y # PPS support # # CONFIG_PPS is not set +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +# CONFIG_GPIO_SYSFS is not set + +# +# Memory mapped GPIO expanders: +# +# CONFIG_GPIO_IT8761E is not set + +# +# I2C GPIO expanders: +# + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# + +# +# AC97 GPIO expanders: +# # CONFIG_W1 is not set # CONFIG_POWER_SUPPLY is not set # CONFIG_HWMON is not set @@ -568,12 +611,16 @@ CONFIG_SSB_POSSIBLE=y # # Multifunction device drivers # -# CONFIG_MFD_CORE is not set +CONFIG_MFD_CORE=y # CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +CONFIG_MFD_SH_MOBILE_SDHI=y +# CONFIG_HTC_EGPIO is not set # CONFIG_HTC_PASIC3 is not set # CONFIG_MFD_TMIO is not set # CONFIG_MFD_T7L66XB is not set # CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set # CONFIG_REGULATOR is not set # CONFIG_MEDIA_SUPPORT is not set @@ -728,6 +775,7 @@ CONFIG_DEBUG_MEMORY_INIT=y CONFIG_HAVE_FUNCTION_TRACER=y CONFIG_TRACING_SUPPORT=y # CONFIG_FTRACE is not set +# CONFIG_ATOMIC64_SELFTEST is not set # CONFIG_SAMPLES is not set CONFIG_HAVE_ARCH_KGDB=y # CONFIG_KGDB is not set @@ -772,3 +820,4 @@ CONFIG_DECOMPRESS_LZO=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y CONFIG_HAS_DMA=y +CONFIG_GENERIC_ATOMIC64=y diff --git a/arch/arm/configs/g4evm_defconfig b/arch/arm/configs/g4evm_defconfig index 8ee79a537134..3841bc609d41 100644 --- a/arch/arm/configs/g4evm_defconfig +++ b/arch/arm/configs/g4evm_defconfig @@ -1,12 +1,15 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.33-rc7 -# Mon Feb 8 12:21:35 2010 +# Linux kernel version: 2.6.34 +# Thu May 20 12:37:38 2010 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y CONFIG_GENERIC_TIME=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_HAVE_PROC_CPU=y CONFIG_GENERIC_HARDIRQS=y CONFIG_STACKTRACE_SUPPORT=y CONFIG_HAVE_LATENCYTOP_SUPPORT=y @@ -17,6 +20,7 @@ CONFIG_GENERIC_IRQ_PROBE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y CONFIG_VECTORS_BASE=0xffff0000 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -31,6 +35,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32 CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y CONFIG_HAVE_KERNEL_LZO=y CONFIG_KERNEL_GZIP=y # CONFIG_KERNEL_BZIP2 is not set @@ -54,11 +59,6 @@ CONFIG_RCU_FANOUT=32 CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 -CONFIG_GROUP_SCHED=y -CONFIG_FAIR_GROUP_SCHED=y -# CONFIG_RT_GROUP_SCHED is not set -CONFIG_USER_SCHED=y -# CONFIG_CGROUP_SCHED is not set # CONFIG_CGROUPS is not set # CONFIG_SYSFS_DEPRECATED_V2 is not set # CONFIG_RELAY is not set @@ -94,10 +94,14 @@ CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_AIO=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y # # Kernel Performance Events And Counters # +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERF_COUNTERS is not set CONFIG_VM_EVENT_COUNTERS=y CONFIG_COMPAT_BRK=y CONFIG_SLAB=y @@ -172,8 +176,11 @@ CONFIG_MMU=y # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_REALVIEW is not set # CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set # CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCMRING is not set # CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set # CONFIG_ARCH_GEMINI is not set # CONFIG_ARCH_EBSA110 is not set # CONFIG_ARCH_EP93XX is not set @@ -182,7 +189,6 @@ CONFIG_MMU=y # CONFIG_ARCH_STMP3XXX is not set # CONFIG_ARCH_NETX is not set # CONFIG_ARCH_H720X is not set -# CONFIG_ARCH_NOMADIK is not set # CONFIG_ARCH_IOP13XX is not set # CONFIG_ARCH_IOP32X is not set # CONFIG_ARCH_IOP33X is not set @@ -199,6 +205,7 @@ CONFIG_MMU=y # CONFIG_ARCH_KS8695 is not set # CONFIG_ARCH_NS9XXX is not set # CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_NUC93X is not set # CONFIG_ARCH_PNX4008 is not set # CONFIG_ARCH_PXA is not set # CONFIG_ARCH_MSM is not set @@ -207,14 +214,18 @@ CONFIG_ARCH_SHMOBILE=y # CONFIG_ARCH_SA1100 is not set # CONFIG_ARCH_S3C2410 is not set # CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P6440 is not set +# CONFIG_ARCH_S5P6442 is not set # CONFIG_ARCH_S5PC1XX is not set +# CONFIG_ARCH_S5PV210 is not set # CONFIG_ARCH_SHARK is not set # CONFIG_ARCH_LH7A40X is not set # CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set # CONFIG_ARCH_DAVINCI is not set # CONFIG_ARCH_OMAP is not set -# CONFIG_ARCH_BCMRING is not set -# CONFIG_ARCH_U8500 is not set +# CONFIG_PLAT_SPEAR is not set # # SH-Mobile System Type @@ -242,6 +253,7 @@ CONFIG_MEMORY_SIZE=0x08000000 # Timer and clock configuration # CONFIG_SH_TIMER_CMT=y +CONFIG_SH_TIMER_TMU=y # # Processor Type @@ -269,6 +281,8 @@ CONFIG_ARM_THUMB=y # CONFIG_CPU_BPREDICT_DISABLE is not set CONFIG_HAS_TLS_REG=y CONFIG_ARM_L1_CACHE_SHIFT=5 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_CPU_HAS_PMU=y # CONFIG_ARM_ERRATA_430973 is not set # CONFIG_ARM_ERRATA_458693 is not set # CONFIG_ARM_ERRATA_460075 is not set @@ -322,7 +336,7 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="console=ttySC4,115200 earlyprintk=sh-sci.4,115200" +CONFIG_CMDLINE="console=ttySC4,115200" # CONFIG_XIP_KERNEL is not set CONFIG_KEXEC=y CONFIG_ATAGS_PROC=y @@ -452,10 +466,12 @@ CONFIG_MTD_NAND=y # CONFIG_MTD_NAND_VERIFY_WRITE is not set # CONFIG_MTD_NAND_ECC_SMC is not set # CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_GPIO is not set CONFIG_MTD_NAND_IDS=y # CONFIG_MTD_NAND_DISKONCHIP is not set # CONFIG_MTD_NAND_NANDSIM is not set # CONFIG_MTD_NAND_PLATFORM is not set +CONFIG_MTD_NAND_SH_FLCTL=y # CONFIG_MTD_ONENAND is not set # @@ -476,6 +492,7 @@ CONFIG_HAVE_IDE=y # # SCSI device support # +CONFIG_SCSI_MOD=y # CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set # CONFIG_SCSI_DMA is not set @@ -543,6 +560,7 @@ CONFIG_SERIAL_SH_SCI_NR_UARTS=8 CONFIG_SERIAL_SH_SCI_CONSOLE=y CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_TIMBERDALE is not set CONFIG_UNIX98_PTYS=y # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set # CONFIG_LEGACY_PTYS is not set @@ -558,6 +576,31 @@ CONFIG_UNIX98_PTYS=y # PPS support # # CONFIG_PPS is not set +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +# CONFIG_GPIO_SYSFS is not set + +# +# Memory mapped GPIO expanders: +# +# CONFIG_GPIO_IT8761E is not set + +# +# I2C GPIO expanders: +# + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# + +# +# AC97 GPIO expanders: +# # CONFIG_W1 is not set # CONFIG_POWER_SUPPLY is not set # CONFIG_HWMON is not set @@ -573,12 +616,16 @@ CONFIG_SSB_POSSIBLE=y # # Multifunction device drivers # -# CONFIG_MFD_CORE is not set +CONFIG_MFD_CORE=y # CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +CONFIG_MFD_SH_MOBILE_SDHI=y +# CONFIG_HTC_EGPIO is not set # CONFIG_HTC_PASIC3 is not set # CONFIG_MFD_TMIO is not set # CONFIG_MFD_T7L66XB is not set # CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set # CONFIG_REGULATOR is not set # CONFIG_MEDIA_SUPPORT is not set @@ -733,6 +780,7 @@ CONFIG_DEBUG_MEMORY_INIT=y CONFIG_HAVE_FUNCTION_TRACER=y CONFIG_TRACING_SUPPORT=y # CONFIG_FTRACE is not set +# CONFIG_ATOMIC64_SELFTEST is not set # CONFIG_SAMPLES is not set CONFIG_HAVE_ARCH_KGDB=y # CONFIG_KGDB is not set -- GitLab From 28f0721a79046056ced3b9bd79c319c5c417ec30 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 28 Apr 2010 08:25:30 +0000 Subject: [PATCH 0076/5312] ARM: mach-shmobile: Set CONSISTENT_DMA_SIZE to 158 MB This patch sets CONSISTENT_DMA_SIZE to 158 MB for all SH-Mobile ARM processors. The DMA area is mapped at 0xf6000000 - 0xffdfffff, on top of the 256 MB I/O window at 0xe6000000. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/include/mach/memory.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/mach-shmobile/include/mach/memory.h b/arch/arm/mach-shmobile/include/mach/memory.h index e188183f4dce..377584e57e03 100644 --- a/arch/arm/mach-shmobile/include/mach/memory.h +++ b/arch/arm/mach-shmobile/include/mach/memory.h @@ -4,4 +4,7 @@ #define PHYS_OFFSET UL(CONFIG_MEMORY_START) #define MEM_SIZE UL(CONFIG_MEMORY_SIZE) +/* DMA memory at 0xf6000000 - 0xffdfffff */ +#define CONSISTENT_DMA_SIZE (158 << 20) + #endif /* __ASM_MACH_MEMORY_H */ -- GitLab From e370bc22c2aa42e0bdae178d558ce83ed8d23364 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 28 Apr 2010 08:36:57 +0000 Subject: [PATCH 0077/5312] ARM: mach-shmobile: Update VMALLOC_END Extend VMALLOC_END to the I/O Window at 0xe6000000. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/include/mach/vmalloc.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-shmobile/include/mach/vmalloc.h b/arch/arm/mach-shmobile/include/mach/vmalloc.h index fb3c4f1ab252..4aecf6e3a859 100644 --- a/arch/arm/mach-shmobile/include/mach/vmalloc.h +++ b/arch/arm/mach-shmobile/include/mach/vmalloc.h @@ -1,6 +1,7 @@ #ifndef __ASM_MACH_VMALLOC_H #define __ASM_MACH_VMALLOC_H -#define VMALLOC_END (PAGE_OFFSET + 0x24000000) +/* Vmalloc at ... - 0xe5ffffff */ +#define VMALLOC_END 0xe6000000 #endif /* __ASM_MACH_VMALLOC_H */ -- GitLab From 44ebaa5de1f922965d8aa215a6da729341b3deb2 Mon Sep 17 00:00:00 2001 From: Jorge Eduardo Candelaria Date: Thu, 20 May 2010 17:53:07 -0500 Subject: [PATCH 0078/5312] ASoC: TWL6040: Fix playback with 19.2 Mhz MCLK When using MCLK is configured for 19.2 Mhz, clock slicer should be enabled and HPPLL should be bypassed in clock path. Signed-off-by: Jorge Eduardo Candelaria Signed-off-by: Margarita Olaya Cabrera Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- sound/soc/codecs/twl6040.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index af36346ff336..85dd4fb4c681 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -928,7 +928,7 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai, case 19200000: /* mclk input, pll disabled */ hppllctl |= TWL6040_MCLK_19200KHZ | - TWL6040_HPLLSQRBP | + TWL6040_HPLLSQRENA | TWL6040_HPLLBP; break; case 26000000: -- GitLab From fab90aa4cf2330f15bba5218d5d633c1044bddd3 Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Fri, 21 May 2010 11:57:01 +0800 Subject: [PATCH 0079/5312] ASoC: ad193x: add set_sysclk entry to support different clock input Signed-off-by: Barry Song <21cnbao@gmail.com> Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/ad193x.c | 41 ++++++++++++++++++++++++++++++++++++++- sound/soc/codecs/ad193x.h | 5 +++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index c8ca1142b2f4..1def75e4862f 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -24,6 +24,7 @@ /* codec private data */ struct ad193x_priv { + unsigned int sysclk; struct snd_soc_codec codec; u8 reg_cache[AD193X_NUM_REGS]; }; @@ -251,15 +252,32 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai, return 0; } +static int ad193x_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); + switch (freq) { + case 12288000: + case 18432000: + case 24576000: + case 36864000: + ad193x->sysclk = freq; + return 0; + } + return -EINVAL; +} + static int ad193x_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - int word_len = 0, reg = 0; + int word_len = 0, reg = 0, master_rate = 0; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; + struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); /* bit size */ switch (params_format(params)) { @@ -275,6 +293,25 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream, break; } + switch (ad193x->sysclk) { + case 12288000: + master_rate = AD193X_PLL_INPUT_256; + break; + case 18432000: + master_rate = AD193X_PLL_INPUT_384; + break; + case 24576000: + master_rate = AD193X_PLL_INPUT_512; + break; + case 36864000: + master_rate = AD193X_PLL_INPUT_768; + break; + } + + reg = snd_soc_read(codec, AD193X_PLL_CLK_CTRL0); + reg = (reg & AD193X_PLL_INPUT_MASK) | master_rate; + snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, reg); + reg = snd_soc_read(codec, AD193X_DAC_CTRL2); reg = (reg & (~AD193X_DAC_WORD_LEN_MASK)) | word_len; snd_soc_write(codec, AD193X_DAC_CTRL2, reg); @@ -348,6 +385,7 @@ static int ad193x_bus_probe(struct device *dev, void *ctrl_data, int bus_type) /* pll input: mclki/xi */ snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */ snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04); + ad193x->sysclk = 12288000; ret = snd_soc_register_codec(codec); if (ret != 0) { @@ -383,6 +421,7 @@ static struct snd_soc_dai_ops ad193x_dai_ops = { .hw_params = ad193x_hw_params, .digital_mute = ad193x_mute, .set_tdm_slot = ad193x_set_tdm_slot, + .set_sysclk = ad193x_set_dai_sysclk, .set_fmt = ad193x_set_dai_fmt, }; diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h index a03c880d52f9..654ba64ae04c 100644 --- a/sound/soc/codecs/ad193x.h +++ b/sound/soc/codecs/ad193x.h @@ -11,6 +11,11 @@ #define AD193X_PLL_CLK_CTRL0 0x800 #define AD193X_PLL_POWERDOWN 0x01 +#define AD193X_PLL_INPUT_MASK (~0x6) +#define AD193X_PLL_INPUT_256 (0 << 1) +#define AD193X_PLL_INPUT_384 (1 << 1) +#define AD193X_PLL_INPUT_512 (2 << 1) +#define AD193X_PLL_INPUT_768 (3 << 1) #define AD193X_PLL_CLK_CTRL1 0x801 #define AD193X_DAC_CTRL0 0x802 #define AD193X_DAC_POWERDOWN 0x01 -- GitLab From 7490509fbca3e17e3a220533ea9b686f46c1e64d Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 20 May 2010 14:35:30 +0000 Subject: [PATCH 0080/5312] ARM: mach-shmobile: sh7367/G3EVM evt2irq() update This patch updates the irq numbers on sh7367/G3EVM to make use of evt2irq() and intcs_evt2irq(). Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-g3evm.c | 8 +++---- arch/arm/mach-shmobile/setup-sh7367.c | 30 ++++++++++++++++++++------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-shmobile/board-g3evm.c b/arch/arm/mach-shmobile/board-g3evm.c index 19b3bf3bf566..16d292dc26df 100644 --- a/arch/arm/mach-shmobile/board-g3evm.c +++ b/arch/arm/mach-shmobile/board-g3evm.c @@ -121,7 +121,7 @@ static struct resource usb_host_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 65, + .start = evt2irq(0xa20), /* USBHS_USHI0 */ .flags = IORESOURCE_IRQ, }, }; @@ -161,7 +161,7 @@ static struct resource keysc_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 79, + .start = evt2irq(0xbe0), /* KEYSC_KEY */ .flags = IORESOURCE_IRQ, }, }; @@ -224,7 +224,7 @@ static struct resource irda_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 20, + .start = evt2irq(0x480), /* IRDA */ .flags = IORESOURCE_IRQ, }, }; @@ -349,7 +349,7 @@ static void __init g3evm_init(void) gpio_request(GPIO_FN_IRDA_OUT, NULL); gpio_request(GPIO_FN_IRDA_IN, NULL); gpio_request(GPIO_FN_IRDA_FIRSEL, NULL); - set_irq_type(20, IRQ_TYPE_LEVEL_LOW); + set_irq_type(evt2irq(0x480), IRQ_TYPE_LEVEL_LOW); sh7367_add_standard_devices(); diff --git a/arch/arm/mach-shmobile/setup-sh7367.c b/arch/arm/mach-shmobile/setup-sh7367.c index eca90716140e..3148c11a550e 100644 --- a/arch/arm/mach-shmobile/setup-sh7367.c +++ b/arch/arm/mach-shmobile/setup-sh7367.c @@ -31,11 +31,13 @@ #include #include +/* SCIFA0 */ static struct plat_sci_port scif0_platform_data = { .mapbase = 0xe6c40000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 80, 80, 80, 80 }, + .irqs = { evt2irq(0xc00), evt2irq(0xc00), + evt2irq(0xc00), evt2irq(0xc00) }, }; static struct platform_device scif0_device = { @@ -46,11 +48,13 @@ static struct platform_device scif0_device = { }, }; +/* SCIFA1 */ static struct plat_sci_port scif1_platform_data = { .mapbase = 0xe6c50000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 81, 81, 81, 81 }, + .irqs = { evt2irq(0xc20), evt2irq(0xc20), + evt2irq(0xc20), evt2irq(0xc20) }, }; static struct platform_device scif1_device = { @@ -61,11 +65,13 @@ static struct platform_device scif1_device = { }, }; +/* SCIFA2 */ static struct plat_sci_port scif2_platform_data = { .mapbase = 0xe6c60000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 82, 82, 82, 82 }, + .irqs = { evt2irq(0xc40), evt2irq(0xc40), + evt2irq(0xc40), evt2irq(0xc40) }, }; static struct platform_device scif2_device = { @@ -76,11 +82,13 @@ static struct platform_device scif2_device = { }, }; +/* SCIFA3 */ static struct plat_sci_port scif3_platform_data = { .mapbase = 0xe6c70000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 83, 83, 83, 83 }, + .irqs = { evt2irq(0xc60), evt2irq(0xc60), + evt2irq(0xc60), evt2irq(0xc60) }, }; static struct platform_device scif3_device = { @@ -91,11 +99,13 @@ static struct platform_device scif3_device = { }, }; +/* SCIFA4 */ static struct plat_sci_port scif4_platform_data = { .mapbase = 0xe6c80000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 89, 89, 89, 89 }, + .irqs = { evt2irq(0xd20), evt2irq(0xd20), + evt2irq(0xd20), evt2irq(0xd20) }, }; static struct platform_device scif4_device = { @@ -106,11 +116,13 @@ static struct platform_device scif4_device = { }, }; +/* SCIFA5 */ static struct plat_sci_port scif5_platform_data = { .mapbase = 0xe6cb0000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 90, 90, 90, 90 }, + .irqs = { evt2irq(0xd40), evt2irq(0xd40), + evt2irq(0xd40), evt2irq(0xd40) }, }; static struct platform_device scif5_device = { @@ -121,11 +133,13 @@ static struct platform_device scif5_device = { }, }; +/* SCIFB */ static struct plat_sci_port scif6_platform_data = { .mapbase = 0xe6c30000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 91, 91, 91, 91 }, + .irqs = { evt2irq(0xd60), evt2irq(0xd60), + evt2irq(0xd60), evt2irq(0xd60) }, }; static struct platform_device scif6_device = { @@ -153,7 +167,7 @@ static struct resource cmt10_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 72, + .start = evt2irq(0xb00), /* CMT1_CMT10 */ .flags = IORESOURCE_IRQ, }, }; -- GitLab From 043296dd430c26cab042dd75341f458c92d824b9 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 20 May 2010 14:39:21 +0000 Subject: [PATCH 0081/5312] ARM: mach-shmobile: sh7377/G4EVM evt2irq() update This patch updates the irq numbers on sh7377/G4EVM to make use of evt2irq() and intcs_evt2irq(). Makes the system cope with an updated INTCS_VECT_BASE. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-g4evm.c | 9 ++++--- arch/arm/mach-shmobile/setup-sh7377.c | 34 ++++++++++++++++++++------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/arch/arm/mach-shmobile/board-g4evm.c b/arch/arm/mach-shmobile/board-g4evm.c index 33441d58cfa6..b75372e0563f 100644 --- a/arch/arm/mach-shmobile/board-g4evm.c +++ b/arch/arm/mach-shmobile/board-g4evm.c @@ -138,8 +138,7 @@ static struct resource usb_host_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 65, - .end = 65, + .start = evt2irq(0x0a20), /* USBHS_USHI0 */ .flags = IORESOURCE_IRQ, }, }; @@ -180,7 +179,7 @@ static struct resource keysc_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 79, + .start = evt2irq(0x0be0), /* KEYSC_KEY */ .flags = IORESOURCE_IRQ, }, }; @@ -204,7 +203,7 @@ static struct resource sdhi0_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 96, + .start = evt2irq(0x0e00), /* SDHI0 */ .flags = IORESOURCE_IRQ, }, }; @@ -224,7 +223,7 @@ static struct resource sdhi1_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 100, + .start = evt2irq(0x0e80), /* SDHI1 */ .flags = IORESOURCE_IRQ, }, }; diff --git a/arch/arm/mach-shmobile/setup-sh7377.c b/arch/arm/mach-shmobile/setup-sh7377.c index 60e37774c35c..bb4adf17dbf4 100644 --- a/arch/arm/mach-shmobile/setup-sh7377.c +++ b/arch/arm/mach-shmobile/setup-sh7377.c @@ -32,11 +32,13 @@ #include #include +/* SCIFA0 */ static struct plat_sci_port scif0_platform_data = { .mapbase = 0xe6c40000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 80, 80, 80, 80 }, + .irqs = { evt2irq(0xc00), evt2irq(0xc00), + evt2irq(0xc00), evt2irq(0xc00) }, }; static struct platform_device scif0_device = { @@ -47,11 +49,13 @@ static struct platform_device scif0_device = { }, }; +/* SCIFA1 */ static struct plat_sci_port scif1_platform_data = { .mapbase = 0xe6c50000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 81, 81, 81, 81 }, + .irqs = { evt2irq(0xc20), evt2irq(0xc20), + evt2irq(0xc20), evt2irq(0xc20) }, }; static struct platform_device scif1_device = { @@ -62,11 +66,13 @@ static struct platform_device scif1_device = { }, }; +/* SCIFA2 */ static struct plat_sci_port scif2_platform_data = { .mapbase = 0xe6c60000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 82, 82, 82, 82 }, + .irqs = { evt2irq(0xc40), evt2irq(0xc40), + evt2irq(0xc40), evt2irq(0xc40) }, }; static struct platform_device scif2_device = { @@ -77,11 +83,13 @@ static struct platform_device scif2_device = { }, }; +/* SCIFA3 */ static struct plat_sci_port scif3_platform_data = { .mapbase = 0xe6c70000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 83, 83, 83, 83 }, + .irqs = { evt2irq(0xc60), evt2irq(0xc60), + evt2irq(0xc60), evt2irq(0xc60) }, }; static struct platform_device scif3_device = { @@ -92,11 +100,13 @@ static struct platform_device scif3_device = { }, }; +/* SCIFA4 */ static struct plat_sci_port scif4_platform_data = { .mapbase = 0xe6c80000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 89, 89, 89, 89 }, + .irqs = { evt2irq(0xd20), evt2irq(0xd20), + evt2irq(0xd20), evt2irq(0xd20) }, }; static struct platform_device scif4_device = { @@ -107,11 +117,13 @@ static struct platform_device scif4_device = { }, }; +/* SCIFA5 */ static struct plat_sci_port scif5_platform_data = { .mapbase = 0xe6cb0000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 90, 90, 90, 90 }, + .irqs = { evt2irq(0xd40), evt2irq(0xd40), + evt2irq(0xd40), evt2irq(0xd40) }, }; static struct platform_device scif5_device = { @@ -122,11 +134,13 @@ static struct platform_device scif5_device = { }, }; +/* SCIFA6 */ static struct plat_sci_port scif6_platform_data = { .mapbase = 0xe6cc0000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 196, 196, 196, 196 }, + .irqs = { intcs_evt2irq(0x1a80), intcs_evt2irq(0x1a80), + intcs_evt2irq(0x1a80), intcs_evt2irq(0x1a80) }, }; static struct platform_device scif6_device = { @@ -137,11 +151,13 @@ static struct platform_device scif6_device = { }, }; +/* SCIFB */ static struct plat_sci_port scif7_platform_data = { .mapbase = 0xe6c30000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 91, 91, 91, 91 }, + .irqs = { evt2irq(0xd60), evt2irq(0xd60), + evt2irq(0xd60), evt2irq(0xd60) }, }; static struct platform_device scif7_device = { @@ -169,7 +185,7 @@ static struct resource cmt10_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 72, + .start = evt2irq(0xb00), /* CMT1_CMT10 */ .flags = IORESOURCE_IRQ, }, }; -- GitLab From 33c9607acf159da986c85983e1b58b739bcb46c2 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 20 May 2010 14:41:00 +0000 Subject: [PATCH 0082/5312] ARM: mach-shmobile: sh7372/AP4EVB evt2irq() update This patch updates the irq numbers on sh7372/AP4EVB to make use of evt2irq() and intcs_evt2irq(). Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ap4evb.c | 11 ++++---- arch/arm/mach-shmobile/setup-sh7372.c | 39 ++++++++++++++++++--------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 4d197e36270a..5342306cd391 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -165,7 +165,7 @@ static struct resource smc911x_resources[] = { .end = 0x16000000 - 1, .flags = IORESOURCE_MEM, }, { - .start = 6, + .start = evt2irq(0x02c0) /* IRQ6A */, .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL, }, }; @@ -208,7 +208,7 @@ static struct resource keysc_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 79, + .start = evt2irq(0x0be0), /* KEYSC_KEY */ .flags = IORESOURCE_IRQ, }, }; @@ -232,7 +232,7 @@ static struct resource sdhi0_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 96, + .start = evt2irq(0x0e00) /* SDHI0 */, .flags = IORESOURCE_IRQ, }, }; @@ -267,8 +267,7 @@ static struct resource usb1_host_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 215, - .end = 215, + .start = evt2irq(0x1ce0) /* USB1_USB1I0 */, .flags = IORESOURCE_IRQ, }, }; @@ -294,7 +293,7 @@ static struct platform_device *ap4evb_devices[] __initdata = { }; /* TouchScreen (Needs SW3 set to OFF) */ -#define IRQ28 396 +#define IRQ28 evt2irq(0x3380) /* IRQ28A */ struct tsc2007_platform_data tsc2007_info = { .model = 2007, .x_plate_ohms = 180, diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index 885dfaa54c2a..d6b15648d8b0 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c @@ -32,12 +32,13 @@ #include #include -/* SCIF */ +/* SCIFA0 */ static struct plat_sci_port scif0_platform_data = { .mapbase = 0xe6c40000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 80, 80, 80, 80 }, + .irqs = { evt2irq(0x0c00), evt2irq(0x0c00), + evt2irq(0x0c00), evt2irq(0x0c00) }, }; static struct platform_device scif0_device = { @@ -48,11 +49,13 @@ static struct platform_device scif0_device = { }, }; +/* SCIFA1 */ static struct plat_sci_port scif1_platform_data = { .mapbase = 0xe6c50000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 81, 81, 81, 81 }, + .irqs = { evt2irq(0x0c20), evt2irq(0x0c20), + evt2irq(0x0c20), evt2irq(0x0c20) }, }; static struct platform_device scif1_device = { @@ -63,11 +66,13 @@ static struct platform_device scif1_device = { }, }; +/* SCIFA2 */ static struct plat_sci_port scif2_platform_data = { .mapbase = 0xe6c60000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 82, 82, 82, 82 }, + .irqs = { evt2irq(0x0c40), evt2irq(0x0c40), + evt2irq(0x0c40), evt2irq(0x0c40) }, }; static struct platform_device scif2_device = { @@ -78,11 +83,13 @@ static struct platform_device scif2_device = { }, }; +/* SCIFA3 */ static struct plat_sci_port scif3_platform_data = { .mapbase = 0xe6c70000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 83, 83, 83, 83 }, + .irqs = { evt2irq(0x0c60), evt2irq(0x0c60), + evt2irq(0x0c60), evt2irq(0x0c60) }, }; static struct platform_device scif3_device = { @@ -93,11 +100,13 @@ static struct platform_device scif3_device = { }, }; +/* SCIFA4 */ static struct plat_sci_port scif4_platform_data = { .mapbase = 0xe6c80000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 89, 89, 89, 89 }, + .irqs = { evt2irq(0x0d20), evt2irq(0x0d20), + evt2irq(0x0d20), evt2irq(0x0d20) }, }; static struct platform_device scif4_device = { @@ -108,11 +117,13 @@ static struct platform_device scif4_device = { }, }; +/* SCIFA5 */ static struct plat_sci_port scif5_platform_data = { .mapbase = 0xe6cb0000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 90, 90, 90, 90 }, + .irqs = { evt2irq(0x0d40), evt2irq(0x0d40), + evt2irq(0x0d40), evt2irq(0x0d40) }, }; static struct platform_device scif5_device = { @@ -123,11 +134,13 @@ static struct platform_device scif5_device = { }, }; +/* SCIFB */ static struct plat_sci_port scif6_platform_data = { .mapbase = 0xe6c30000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 91, 91, 91, 91 }, + .irqs = { evt2irq(0x0d60), evt2irq(0x0d60), + evt2irq(0x0d60), evt2irq(0x0d60) }, }; static struct platform_device scif6_device = { @@ -156,7 +169,7 @@ static struct resource cmt10_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 72, + .start = evt2irq(0x0b00), /* CMT1_CMT10 */ .flags = IORESOURCE_IRQ, }, }; @@ -180,8 +193,8 @@ static struct resource iic0_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = intcs_evt2irq(0xe00), - .end = intcs_evt2irq(0xe60), + .start = intcs_evt2irq(0xe00), /* IIC0_ALI0 */ + .end = intcs_evt2irq(0xe60), /* IIC0_DTEI0 */ .flags = IORESOURCE_IRQ, }, }; @@ -201,8 +214,8 @@ static struct resource iic1_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = 44, - .end = 47, + .start = evt2irq(0x780), /* IIC1_ALI1 */ + .end = evt2irq(0x7e0), /* IIC1_DTEI1 */ .flags = IORESOURCE_IRQ, }, }; -- GitLab From 83ca5c87cb4bac32f8e0cf7f0c640bfcf310bb5d Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 20 May 2010 14:45:03 +0000 Subject: [PATCH 0083/5312] ARM: mach-shmobile: sh7372 clock fixes Fixes for the sh7372 clock framework: - remove unused #include - add sh7372 prefix to user modifiable root clocks - put modifiable root clock prototypes in header file - fix off-by-one id error on VEU MSTP clocks - make arrays static Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/clock-sh7372.c | 33 ++++++++++---------- arch/arm/mach-shmobile/include/mach/common.h | 4 ++- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index ac46b4bce522..023de5e5a33c 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -18,7 +18,6 @@ */ #include #include -#include #include #include #include @@ -60,7 +59,7 @@ static struct clk r_clk = { * 26MHz default rate for the EXTAL1 root input clock. * If needed, reset this with clk_set_rate() from the platform code. */ -struct clk extal1_clk = { +struct clk sh7372_extal1_clk = { .rate = 26666666, }; @@ -68,7 +67,7 @@ struct clk extal1_clk = { * 48MHz default rate for the EXTAL2 root input clock. * If needed, reset this with clk_set_rate() from the platform code. */ -struct clk extal2_clk = { +struct clk sh7372_extal2_clk = { .rate = 48000000, }; @@ -85,13 +84,13 @@ static struct clk_ops div2_clk_ops = { /* Divide extal1 by two */ static struct clk extal1_div2_clk = { .ops = &div2_clk_ops, - .parent = &extal1_clk, + .parent = &sh7372_extal1_clk, }; /* Divide extal2 by two */ static struct clk extal2_div2_clk = { .ops = &div2_clk_ops, - .parent = &extal2_clk, + .parent = &sh7372_extal2_clk, }; /* Divide extal2 by four */ @@ -156,10 +155,10 @@ static struct clk pllc2_clk = { .parent = &extal1_div2_clk, }; -struct clk *main_clks[] = { +static struct clk *main_clks[] = { &r_clk, - &extal1_clk, - &extal2_clk, + &sh7372_extal1_clk, + &sh7372_extal2_clk, &extal1_div2_clk, &extal2_div2_clk, &extal2_div4_clk, @@ -200,7 +199,7 @@ enum { DIV4_I, DIV4_ZG, DIV4_B, DIV4_M1, DIV4_CSIR, #define DIV4(_reg, _bit, _mask, _flags) \ SH_CLK_DIV4(&pllc1_clk, _reg, _bit, _mask, _flags) -struct clk div4_clks[DIV4_NR] = { +static struct clk div4_clks[DIV4_NR] = { [DIV4_I] = DIV4(FRQCRA, 20, 0x6fff, CLK_ENABLE_ON_INIT), [DIV4_ZG] = DIV4(FRQCRA, 16, 0x6fff, CLK_ENABLE_ON_INIT), [DIV4_B] = DIV4(FRQCRA, 8, 0x6fff, CLK_ENABLE_ON_INIT), @@ -223,7 +222,7 @@ enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_FMSI, DIV6_FMSO, DIV6_VOU, DIV6_HDMI, DIV6_DSIT, DIV6_DSI0P, DIV6_DSI1P, DIV6_NR }; -struct clk div6_clks[DIV6_NR] = { +static struct clk div6_clks[DIV6_NR] = { [DIV6_VCK1] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR1, 0), [DIV6_VCK2] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR2, 0), [DIV6_VCK3] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR3, 0), @@ -231,7 +230,7 @@ struct clk div6_clks[DIV6_NR] = { [DIV6_FMSO] = SH_CLK_DIV6(&pllc1_div2_clk, FMSOCKCR, 0), [DIV6_FSIA] = SH_CLK_DIV6(&pllc1_div2_clk, FSIACKCR, 0), [DIV6_FSIB] = SH_CLK_DIV6(&pllc1_div2_clk, FSIBCKCR, 0), - [DIV6_SUB] = SH_CLK_DIV6(&extal2_clk, SUBCKCR, 0), + [DIV6_SUB] = SH_CLK_DIV6(&sh7372_extal2_clk, SUBCKCR, 0), [DIV6_SPU] = SH_CLK_DIV6(&pllc1_div2_clk, SPUCKCR, 0), [DIV6_VOU] = SH_CLK_DIV6(&pllc1_div2_clk, VOUCKCR, 0), [DIV6_HDMI] = SH_CLK_DIV6(&pllc1_div2_clk, HDMICKCR, 0), @@ -286,8 +285,8 @@ static struct clk mstp_clks[MSTP_NR] = { static struct clk_lookup lookups[] = { /* main clocks */ CLKDEV_CON_ID("r_clk", &r_clk), - CLKDEV_CON_ID("extal1", &extal1_clk), - CLKDEV_CON_ID("extal2", &extal2_clk), + CLKDEV_CON_ID("extal1", &sh7372_extal1_clk), + CLKDEV_CON_ID("extal2", &sh7372_extal2_clk), CLKDEV_CON_ID("extal1_div2_clk", &extal1_div2_clk), CLKDEV_CON_ID("extal2_div2_clk", &extal2_div2_clk), CLKDEV_CON_ID("extal2_div4_clk", &extal2_div4_clk), @@ -331,10 +330,10 @@ static struct clk_lookup lookups[] = { /* MSTP32 clocks */ CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* IIC2 */ - CLKDEV_DEV_ID("uio_pdrv_genirq.3", &mstp_clks[MSTP131]), /* VEU3 */ - CLKDEV_DEV_ID("uio_pdrv_genirq.2", &mstp_clks[MSTP130]), /* VEU2 */ - CLKDEV_DEV_ID("uio_pdrv_genirq.1", &mstp_clks[MSTP129]), /* VEU1 */ - CLKDEV_DEV_ID("uio_pdrv_genirq.0", &mstp_clks[MSTP128]), /* VEU0 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.4", &mstp_clks[MSTP131]), /* VEU3 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.3", &mstp_clks[MSTP130]), /* VEU2 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.2", &mstp_clks[MSTP129]), /* VEU1 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.1", &mstp_clks[MSTP128]), /* VEU0 */ CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* IIC0 */ CLKDEV_DEV_ID("uio_pdrv_genirq.5", &mstp_clks[MSTP106]), /* JPU */ CLKDEV_DEV_ID("uio_pdrv_genirq.0", &mstp_clks[MSTP101]), /* VPU */ diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index 780bd65140da..38e9a2d275f0 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -3,7 +3,7 @@ extern struct sys_timer shmobile_timer; extern void shmobile_setup_console(void); - +struct clk; extern int clk_init(void); extern void sh7367_init_irq(void); @@ -22,5 +22,7 @@ extern void sh7372_add_early_devices(void); extern void sh7372_add_standard_devices(void); extern void sh7372_clock_init(void); extern void sh7372_pinmux_init(void); +extern struct clk sh7372_extal1_clk; +extern struct clk sh7372_extal2_clk; #endif /* __ARCH_MACH_COMMON_H */ -- GitLab From 4f0836b4f9b9bf807719f203205f251a7a46ebd9 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 20 May 2010 14:49:28 +0000 Subject: [PATCH 0084/5312] ARM: mach-shmobile: sh7367 clock framework V2 This patch is V2 of clock framework tables/code for sh7367. MSTP support is included for the following hardware blocks: KEYSC, SCIF, IIC, IRDA, FLCTL, VOU, SIU, USB, SDHI and UIO. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/Kconfig | 1 + arch/arm/mach-shmobile/board-g3evm.c | 19 +- arch/arm/mach-shmobile/clock-sh7367.c | 353 +++++++++++++++++-- arch/arm/mach-shmobile/include/mach/common.h | 2 + 4 files changed, 337 insertions(+), 38 deletions(-) diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index a8bd47fca1df..a2a0734344a8 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -7,6 +7,7 @@ config ARCH_SH7367 select CPU_V6 select HAVE_CLK select COMMON_CLKDEV + select SH_CLK_CPG select GENERIC_CLOCKEVENTS config ARCH_SH7377 diff --git a/arch/arm/mach-shmobile/board-g3evm.c b/arch/arm/mach-shmobile/board-g3evm.c index 16d292dc26df..a8f20cb0b7d2 100644 --- a/arch/arm/mach-shmobile/board-g3evm.c +++ b/arch/arm/mach-shmobile/board-g3evm.c @@ -37,6 +37,7 @@ #include #include #include +#include /* * IrDA @@ -259,9 +260,8 @@ static void __init g3evm_map_io(void) { iotable_init(g3evm_io_desc, ARRAY_SIZE(g3evm_io_desc)); - /* setup early devices, clocks and console here as well */ + /* setup early devices and console here as well */ sh7367_add_early_devices(); - sh7367_clock_init(); shmobile_setup_console(); } @@ -298,9 +298,6 @@ static void __init g3evm_init(void) gpio_request(GPIO_FN_EXTLP, NULL); gpio_request(GPIO_FN_IDIN, NULL); - /* enable clock in SYMSTPCR2 */ - __raw_writel(__raw_readl(0xe6158048) & ~(1 << 22), 0xe6158048); - /* setup USB phy */ __raw_writew(0x0300, 0xe605810a); /* USBCR1 */ __raw_writew(0x00e0, 0xe60581c0); /* CPFCH */ @@ -356,11 +353,21 @@ static void __init g3evm_init(void) platform_add_devices(g3evm_devices, ARRAY_SIZE(g3evm_devices)); } +static void __init g3evm_timer_init(void) +{ + sh7367_clock_init(); + shmobile_timer.init(); +} + +static struct sys_timer g3evm_timer = { + .init = g3evm_timer_init, +}; + MACHINE_START(G3EVM, "g3evm") .phys_io = 0xe6000000, .io_pg_offst = ((0xe6000000) >> 18) & 0xfffc, .map_io = g3evm_map_io, .init_irq = sh7367_init_irq, .init_machine = g3evm_init, - .timer = &shmobile_timer, + .timer = &g3evm_timer, MACHINE_END diff --git a/arch/arm/mach-shmobile/clock-sh7367.c b/arch/arm/mach-shmobile/clock-sh7367.c index f3ede5284ce3..b6454c9f2abb 100644 --- a/arch/arm/mach-shmobile/clock-sh7367.c +++ b/arch/arm/mach-shmobile/clock-sh7367.c @@ -1,5 +1,5 @@ /* - * Preliminary clock framework support for sh7367 + * SH7367 clock framework support * * Copyright (C) 2010 Magnus Damm * @@ -17,53 +17,342 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include -#include #include -#include -#include +#include #include +#include #include -/* a static peripheral clock for now - enough to get sh-sci working */ -static struct clk peripheral_clk = { - .name = "peripheral_clk", - .rate = 48000000, -}; +/* SH7367 registers */ +#define RTFRQCR 0xe6150000 +#define SYFRQCR 0xe6150004 +#define CMFRQCR 0xe61500E0 +#define VCLKCR1 0xe6150008 +#define VCLKCR2 0xe615000C +#define VCLKCR3 0xe615001C +#define SCLKACR 0xe6150010 +#define SCLKBCR 0xe6150014 +#define SUBUSBCKCR 0xe6158080 +#define SPUCKCR 0xe6150084 +#define MSUCKCR 0xe6150088 +#define MVI3CKCR 0xe6150090 +#define VOUCKCR 0xe6150094 +#define MFCK1CR 0xe6150098 +#define MFCK2CR 0xe615009C +#define PLLC1CR 0xe6150028 +#define PLLC2CR 0xe615002C +#define RTMSTPCR0 0xe6158030 +#define RTMSTPCR2 0xe6158038 +#define SYMSTPCR0 0xe6158040 +#define SYMSTPCR2 0xe6158048 +#define CMMSTPCR0 0xe615804c -/* a static rclk for now - enough to get sh_cmt working */ +/* Fixed 32 KHz root clock from EXTALR pin */ static struct clk r_clk = { - .name = "r_clk", - .rate = 32768, + .rate = 32768, }; -/* a static usb0 for now - enough to get r8a66597 working */ -static struct clk usb0_clk = { - .name = "usb0", +/* + * 26MHz default rate for the EXTALB1 root input clock. + * If needed, reset this with clk_set_rate() from the platform code. + */ +struct clk sh7367_extalb1_clk = { + .rate = 26666666, }; -/* a static keysc0 clk for now - enough to get sh_keysc working */ -static struct clk keysc0_clk = { - .name = "keysc0", +/* + * 48MHz default rate for the EXTAL2 root input clock. + * If needed, reset this with clk_set_rate() from the platform code. + */ +struct clk sh7367_extal2_clk = { + .rate = 48000000, }; +/* A fixed divide-by-2 block */ +static unsigned long div2_recalc(struct clk *clk) +{ + return clk->parent->rate / 2; +} + +static struct clk_ops div2_clk_ops = { + .recalc = div2_recalc, +}; + +/* Divide extalb1 by two */ +static struct clk extalb1_div2_clk = { + .ops = &div2_clk_ops, + .parent = &sh7367_extalb1_clk, +}; + +/* Divide extal2 by two */ +static struct clk extal2_div2_clk = { + .ops = &div2_clk_ops, + .parent = &sh7367_extal2_clk, +}; + +/* PLLC1 */ +static unsigned long pllc1_recalc(struct clk *clk) +{ + unsigned long mult = 1; + + if (__raw_readl(PLLC1CR) & (1 << 14)) + mult = (((__raw_readl(RTFRQCR) >> 24) & 0x3f) + 1) * 2; + + return clk->parent->rate * mult; +} + +static struct clk_ops pllc1_clk_ops = { + .recalc = pllc1_recalc, +}; + +static struct clk pllc1_clk = { + .ops = &pllc1_clk_ops, + .flags = CLK_ENABLE_ON_INIT, + .parent = &extalb1_div2_clk, +}; + +/* Divide PLLC1 by two */ +static struct clk pllc1_div2_clk = { + .ops = &div2_clk_ops, + .parent = &pllc1_clk, +}; + +/* PLLC2 */ +static unsigned long pllc2_recalc(struct clk *clk) +{ + unsigned long mult = 1; + + if (__raw_readl(PLLC2CR) & (1 << 31)) + mult = (((__raw_readl(PLLC2CR) >> 24) & 0x3f) + 1) * 2; + + return clk->parent->rate * mult; +} + +static struct clk_ops pllc2_clk_ops = { + .recalc = pllc2_recalc, +}; + +static struct clk pllc2_clk = { + .ops = &pllc2_clk_ops, + .flags = CLK_ENABLE_ON_INIT, + .parent = &extalb1_div2_clk, +}; + +static struct clk *main_clks[] = { + &r_clk, + &sh7367_extalb1_clk, + &sh7367_extal2_clk, + &extalb1_div2_clk, + &extal2_div2_clk, + &pllc1_clk, + &pllc1_div2_clk, + &pllc2_clk, +}; + +static void div4_kick(struct clk *clk) +{ + unsigned long value; + + /* set KICK bit in SYFRQCR to update hardware setting */ + value = __raw_readl(SYFRQCR); + value |= (1 << 31); + __raw_writel(value, SYFRQCR); +} + +static int divisors[] = { 2, 3, 4, 6, 8, 12, 16, 18, + 24, 32, 36, 48, 0, 72, 0, 0 }; + +static struct clk_div_mult_table div4_div_mult_table = { + .divisors = divisors, + .nr_divisors = ARRAY_SIZE(divisors), +}; + +static struct clk_div4_table div4_table = { + .div_mult_table = &div4_div_mult_table, + .kick = div4_kick, +}; + +enum { DIV4_I, DIV4_G, DIV4_S, DIV4_B, + DIV4_ZX, DIV4_ZT, DIV4_Z, DIV4_ZD, DIV4_HP, + DIV4_ZS, DIV4_ZB, DIV4_ZB3, DIV4_CP, DIV4_NR }; + +#define DIV4(_reg, _bit, _mask, _flags) \ + SH_CLK_DIV4(&pllc1_clk, _reg, _bit, _mask, _flags) + +static struct clk div4_clks[DIV4_NR] = { + [DIV4_I] = DIV4(RTFRQCR, 20, 0x6fff, CLK_ENABLE_ON_INIT), + [DIV4_G] = DIV4(RTFRQCR, 16, 0x6fff, CLK_ENABLE_ON_INIT), + [DIV4_S] = DIV4(RTFRQCR, 12, 0x6fff, CLK_ENABLE_ON_INIT), + [DIV4_B] = DIV4(RTFRQCR, 8, 0x6fff, CLK_ENABLE_ON_INIT), + [DIV4_ZX] = DIV4(SYFRQCR, 20, 0x6fff, 0), + [DIV4_ZT] = DIV4(SYFRQCR, 16, 0x6fff, 0), + [DIV4_Z] = DIV4(SYFRQCR, 12, 0x6fff, 0), + [DIV4_ZD] = DIV4(SYFRQCR, 8, 0x6fff, 0), + [DIV4_HP] = DIV4(SYFRQCR, 4, 0x6fff, 0), + [DIV4_ZS] = DIV4(CMFRQCR, 12, 0x6fff, 0), + [DIV4_ZB] = DIV4(CMFRQCR, 8, 0x6fff, 0), + [DIV4_ZB3] = DIV4(CMFRQCR, 4, 0x6fff, 0), + [DIV4_CP] = DIV4(CMFRQCR, 0, 0x6fff, 0), +}; + +enum { DIV6_SUB, DIV6_SIUA, DIV6_SIUB, DIV6_MSU, DIV6_SPU, + DIV6_MVI3, DIV6_MF1, DIV6_MF2, + DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_VOU, + DIV6_NR }; + +static struct clk div6_clks[DIV6_NR] = { + [DIV6_SUB] = SH_CLK_DIV6(&sh7367_extal2_clk, SUBUSBCKCR, 0), + [DIV6_SIUA] = SH_CLK_DIV6(&pllc1_div2_clk, SCLKACR, 0), + [DIV6_SIUB] = SH_CLK_DIV6(&pllc1_div2_clk, SCLKBCR, 0), + [DIV6_MSU] = SH_CLK_DIV6(&pllc1_div2_clk, MSUCKCR, 0), + [DIV6_SPU] = SH_CLK_DIV6(&pllc1_div2_clk, SPUCKCR, 0), + [DIV6_MVI3] = SH_CLK_DIV6(&pllc1_div2_clk, MVI3CKCR, 0), + [DIV6_MF1] = SH_CLK_DIV6(&pllc1_div2_clk, MFCK1CR, 0), + [DIV6_MF2] = SH_CLK_DIV6(&pllc1_div2_clk, MFCK2CR, 0), + [DIV6_VCK1] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR1, 0), + [DIV6_VCK2] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR2, 0), + [DIV6_VCK3] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR3, 0), + [DIV6_VOU] = SH_CLK_DIV6(&pllc1_div2_clk, VOUCKCR, 0), +}; + +enum { RTMSTP001, + RTMSTP231, RTMSTP230, RTMSTP229, RTMSTP228, RTMSTP226, + RTMSTP216, RTMSTP206, RTMSTP205, RTMSTP201, + SYMSTP023, SYMSTP007, SYMSTP006, SYMSTP004, + SYMSTP003, SYMSTP002, SYMSTP001, SYMSTP000, + SYMSTP231, SYMSTP229, SYMSTP225, SYMSTP223, SYMSTP222, + SYMSTP215, SYMSTP214, SYMSTP213, SYMSTP211, + CMMSTP003, + MSTP_NR }; + +#define MSTP(_parent, _reg, _bit, _flags) \ + SH_CLK_MSTP32(_parent, _reg, _bit, _flags) + +static struct clk mstp_clks[MSTP_NR] = { + [RTMSTP001] = MSTP(&div6_clks[DIV6_SUB], RTMSTPCR0, 1, 0), /* IIC2 */ + [RTMSTP231] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 31, 0), /* VEU3 */ + [RTMSTP230] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 30, 0), /* VEU2 */ + [RTMSTP229] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 29, 0), /* VEU1 */ + [RTMSTP228] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 28, 0), /* VEU0 */ + [RTMSTP226] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 26, 0), /* VEU2H */ + [RTMSTP216] = MSTP(&div6_clks[DIV6_SUB], RTMSTPCR2, 16, 0), /* IIC0 */ + [RTMSTP206] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 6, 0), /* JPU */ + [RTMSTP205] = MSTP(&div6_clks[DIV6_VOU], RTMSTPCR2, 5, 0), /* VOU */ + [RTMSTP201] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 1, 0), /* VPU */ + [SYMSTP023] = MSTP(&div6_clks[DIV6_SPU], SYMSTPCR0, 23, 0), /* SPU1 */ + [SYMSTP007] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 7, 0), /* SCIFA5 */ + [SYMSTP006] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 6, 0), /* SCIFB */ + [SYMSTP004] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 4, 0), /* SCIFA0 */ + [SYMSTP003] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 3, 0), /* SCIFA1 */ + [SYMSTP002] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 2, 0), /* SCIFA2 */ + [SYMSTP001] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 1, 0), /* SCIFA3 */ + [SYMSTP000] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 0, 0), /* SCIFA4 */ + [SYMSTP231] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR2, 31, 0), /* SIU */ + [SYMSTP229] = MSTP(&r_clk, SYMSTPCR2, 29, 0), /* CMT10 */ + [SYMSTP225] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR2, 25, 0), /* IRDA */ + [SYMSTP223] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR2, 23, 0), /* IIC1 */ + [SYMSTP222] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR2, 22, 0), /* USBHS */ + [SYMSTP215] = MSTP(&div4_clks[DIV4_HP], SYMSTPCR2, 15, 0), /* FLCTL */ + [SYMSTP214] = MSTP(&div4_clks[DIV4_HP], SYMSTPCR2, 14, 0), /* SDHI0 */ + [SYMSTP213] = MSTP(&div4_clks[DIV4_HP], SYMSTPCR2, 13, 0), /* SDHI1 */ + [SYMSTP211] = MSTP(&div4_clks[DIV4_HP], SYMSTPCR2, 11, 0), /* SDHI2 */ + [CMMSTP003] = MSTP(&r_clk, CMMSTPCR0, 3, 0), /* KEYSC */ +}; + +#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk } +#define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk } + static struct clk_lookup lookups[] = { - { - .clk = &peripheral_clk, - }, { - .clk = &r_clk, - }, { - .clk = &usb0_clk, - }, { - .clk = &keysc0_clk, - } + /* main clocks */ + CLKDEV_CON_ID("r_clk", &r_clk), + CLKDEV_CON_ID("extalb1", &sh7367_extalb1_clk), + CLKDEV_CON_ID("extal2", &sh7367_extal2_clk), + CLKDEV_CON_ID("extalb1_div2_clk", &extalb1_div2_clk), + CLKDEV_CON_ID("extal2_div2_clk", &extal2_div2_clk), + CLKDEV_CON_ID("pllc1_clk", &pllc1_clk), + CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk), + CLKDEV_CON_ID("pllc2_clk", &pllc2_clk), + + /* DIV4 clocks */ + CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]), + CLKDEV_CON_ID("g_clk", &div4_clks[DIV4_G]), + CLKDEV_CON_ID("b_clk", &div4_clks[DIV4_B]), + CLKDEV_CON_ID("zx_clk", &div4_clks[DIV4_ZX]), + CLKDEV_CON_ID("zt_clk", &div4_clks[DIV4_ZT]), + CLKDEV_CON_ID("z_clk", &div4_clks[DIV4_Z]), + CLKDEV_CON_ID("zd_clk", &div4_clks[DIV4_ZD]), + CLKDEV_CON_ID("hp_clk", &div4_clks[DIV4_HP]), + CLKDEV_CON_ID("zs_clk", &div4_clks[DIV4_ZS]), + CLKDEV_CON_ID("zb_clk", &div4_clks[DIV4_ZB]), + CLKDEV_CON_ID("zb3_clk", &div4_clks[DIV4_ZB3]), + CLKDEV_CON_ID("cp_clk", &div4_clks[DIV4_CP]), + + /* DIV6 clocks */ + CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]), + CLKDEV_CON_ID("siua_clk", &div6_clks[DIV6_SIUA]), + CLKDEV_CON_ID("siub_clk", &div6_clks[DIV6_SIUB]), + CLKDEV_CON_ID("msu_clk", &div6_clks[DIV6_MSU]), + CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]), + CLKDEV_CON_ID("mvi3_clk", &div6_clks[DIV6_MVI3]), + CLKDEV_CON_ID("mf1_clk", &div6_clks[DIV6_MF1]), + CLKDEV_CON_ID("mf2_clk", &div6_clks[DIV6_MF2]), + CLKDEV_CON_ID("vck1_clk", &div6_clks[DIV6_VCK1]), + CLKDEV_CON_ID("vck2_clk", &div6_clks[DIV6_VCK2]), + CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]), + CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]), + + /* MSTP32 clocks */ + CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[RTMSTP001]), /* IIC2 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.4", &mstp_clks[RTMSTP231]), /* VEU3 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.3", &mstp_clks[RTMSTP230]), /* VEU2 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.2", &mstp_clks[RTMSTP229]), /* VEU1 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.1", &mstp_clks[RTMSTP228]), /* VEU0 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.5", &mstp_clks[RTMSTP226]), /* VEU2H */ + CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[RTMSTP216]), /* IIC0 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.6", &mstp_clks[RTMSTP206]), /* JPU */ + CLKDEV_DEV_ID("sh-vou", &mstp_clks[RTMSTP205]), /* VOU */ + CLKDEV_DEV_ID("uio_pdrv_genirq.0", &mstp_clks[RTMSTP201]), /* VPU */ + CLKDEV_DEV_ID("uio_pdrv_genirq.7", &mstp_clks[SYMSTP023]), /* SPU1 */ + CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[SYMSTP007]), /* SCIFA5 */ + CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[SYMSTP006]), /* SCIFB */ + CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[SYMSTP004]), /* SCIFA0 */ + CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[SYMSTP003]), /* SCIFA1 */ + CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[SYMSTP002]), /* SCIFA2 */ + CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[SYMSTP001]), /* SCIFA3 */ + CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[SYMSTP000]), /* SCIFA4 */ + CLKDEV_DEV_ID("sh_siu", &mstp_clks[SYMSTP231]), /* SIU */ + CLKDEV_CON_ID("cmt1", &mstp_clks[SYMSTP229]), /* CMT10 */ + CLKDEV_DEV_ID("sh_irda", &mstp_clks[SYMSTP225]), /* IRDA */ + CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[SYMSTP223]), /* IIC1 */ + CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[SYMSTP222]), /* USBHS */ + CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[SYMSTP222]), /* USBHS */ + CLKDEV_DEV_ID("sh_flctl", &mstp_clks[SYMSTP215]), /* FLCTL */ + CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[SYMSTP214]), /* SDHI0 */ + CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[SYMSTP213]), /* SDHI1 */ + CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[SYMSTP211]), /* SDHI2 */ + CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[CMMSTP003]), /* KEYSC */ }; void __init sh7367_clock_init(void) { - int i; + int k, ret = 0; + + for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++) + ret = clk_register(main_clks[k]); + + if (!ret) + ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table); + + if (!ret) + ret = sh_clk_div6_register(div6_clks, DIV6_NR); + + if (!ret) + ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); + + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); - for (i = 0; i < ARRAY_SIZE(lookups); i++) { - lookups[i].con_id = lookups[i].clk->name; - clkdev_add(&lookups[i]); - } + if (!ret) + clk_init(); + else + panic("failed to setup sh7367 clocks\n"); } diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index 38e9a2d275f0..b84cdbae4a5a 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -11,6 +11,8 @@ extern void sh7367_add_early_devices(void); extern void sh7367_add_standard_devices(void); extern void sh7367_clock_init(void); extern void sh7367_pinmux_init(void); +extern struct clk sh7367_extalb1_clk; +extern struct clk sh7367_extal2_clk; extern void sh7377_init_irq(void); extern void sh7377_add_early_devices(void); -- GitLab From 0163acf3c7fd2418f7bc86890e8950ddca510f07 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Fri, 21 May 2010 05:19:34 +0000 Subject: [PATCH 0085/5312] ARM: mach-shmobile: sh7377 clock framework V2 This patch is V2 of clock framework tables/code for sh7377. MSTP support is included for the following hardware blocks: KEYSC, SCIF, IIC, IRDA, FLCTL, USB, SDHI and UIO. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/Kconfig | 1 + arch/arm/mach-shmobile/Makefile | 2 +- arch/arm/mach-shmobile/board-g4evm.c | 19 +- arch/arm/mach-shmobile/clock-sh7377.c | 369 +++++++++++++++++++ arch/arm/mach-shmobile/include/mach/common.h | 3 + 5 files changed, 387 insertions(+), 7 deletions(-) create mode 100644 arch/arm/mach-shmobile/clock-sh7377.c diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index a2a0734344a8..a69e033ca045 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -15,6 +15,7 @@ config ARCH_SH7377 select CPU_V7 select HAVE_CLK select COMMON_CLKDEV + select SH_CLK_CPG select GENERIC_CLOCKEVENTS config ARCH_SH7372 diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index 3995b3bd64b4..5e16b4c69222 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -7,7 +7,7 @@ obj-y := timer.o console.o clock.o # CPU objects obj-$(CONFIG_ARCH_SH7367) += setup-sh7367.o clock-sh7367.o intc-sh7367.o -obj-$(CONFIG_ARCH_SH7377) += setup-sh7377.o clock-sh7367.o intc-sh7377.o +obj-$(CONFIG_ARCH_SH7377) += setup-sh7377.o clock-sh7377.o intc-sh7377.o obj-$(CONFIG_ARCH_SH7372) += setup-sh7372.o clock-sh7372.o intc-sh7372.o # Pinmux setup diff --git a/arch/arm/mach-shmobile/board-g4evm.c b/arch/arm/mach-shmobile/board-g4evm.c index b75372e0563f..e256b7cc4275 100644 --- a/arch/arm/mach-shmobile/board-g4evm.c +++ b/arch/arm/mach-shmobile/board-g4evm.c @@ -37,6 +37,7 @@ #include #include #include +#include /* * SDHI @@ -259,9 +260,8 @@ static void __init g4evm_map_io(void) { iotable_init(g4evm_io_desc, ARRAY_SIZE(g4evm_io_desc)); - /* setup early devices, clocks and console here as well */ + /* setup early devices and console here as well */ sh7377_add_early_devices(); - sh7367_clock_init(); /* use g3 clocks for now */ shmobile_setup_console(); } @@ -327,9 +327,6 @@ static void __init g4evm_init(void) gpio_request(GPIO_FN_EXTLP, NULL); gpio_request(GPIO_FN_IDIN, NULL); - /* enable clock in SMSTPCR3 */ - __raw_writel(__raw_readl(0xe615013c) & ~(1 << 22), 0xe615013c); - /* setup USB phy */ __raw_writew(0x0200, 0xe605810a); /* USBCR1 */ __raw_writew(0x00e0, 0xe60581c0); /* CPFCH */ @@ -384,11 +381,21 @@ static void __init g4evm_init(void) platform_add_devices(g4evm_devices, ARRAY_SIZE(g4evm_devices)); } +static void __init g4evm_timer_init(void) +{ + sh7377_clock_init(); + shmobile_timer.init(); +} + +static struct sys_timer g4evm_timer = { + .init = g4evm_timer_init, +}; + MACHINE_START(G4EVM, "g4evm") .phys_io = 0xe6000000, .io_pg_offst = ((0xe6000000) >> 18) & 0xfffc, .map_io = g4evm_map_io, .init_irq = sh7377_init_irq, .init_machine = g4evm_init, - .timer = &shmobile_timer, + .timer = &g4evm_timer, MACHINE_END diff --git a/arch/arm/mach-shmobile/clock-sh7377.c b/arch/arm/mach-shmobile/clock-sh7377.c new file mode 100644 index 000000000000..e007c28cf0a8 --- /dev/null +++ b/arch/arm/mach-shmobile/clock-sh7377.c @@ -0,0 +1,369 @@ +/* + * SH7377 clock framework support + * + * Copyright (C) 2010 Magnus Damm + * + * 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 + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include + +/* SH7377 registers */ +#define RTFRQCR 0xe6150000 +#define SYFRQCR 0xe6150004 +#define CMFRQCR 0xe61500E0 +#define VCLKCR1 0xe6150008 +#define VCLKCR2 0xe615000C +#define VCLKCR3 0xe615001C +#define FMSICKCR 0xe6150010 +#define FMSOCKCR 0xe6150014 +#define FSICKCR 0xe6150018 +#define PLLC1CR 0xe6150028 +#define PLLC2CR 0xe615002C +#define SUBUSBCKCR 0xe6150080 +#define SPUCKCR 0xe6150084 +#define MSUCKCR 0xe6150088 +#define MVI3CKCR 0xe6150090 +#define HDMICKCR 0xe6150094 +#define MFCK1CR 0xe6150098 +#define MFCK2CR 0xe615009C +#define DSITCKCR 0xe6150060 +#define DSIPCKCR 0xe6150064 +#define SMSTPCR0 0xe6150130 +#define SMSTPCR1 0xe6150134 +#define SMSTPCR2 0xe6150138 +#define SMSTPCR3 0xe615013C +#define SMSTPCR4 0xe6150140 + +/* Fixed 32 KHz root clock from EXTALR pin */ +static struct clk r_clk = { + .rate = 32768, +}; + +/* + * 26MHz default rate for the EXTALC1 root input clock. + * If needed, reset this with clk_set_rate() from the platform code. + */ +struct clk sh7377_extalc1_clk = { + .rate = 26666666, +}; + +/* + * 48MHz default rate for the EXTAL2 root input clock. + * If needed, reset this with clk_set_rate() from the platform code. + */ +struct clk sh7377_extal2_clk = { + .rate = 48000000, +}; + +/* A fixed divide-by-2 block */ +static unsigned long div2_recalc(struct clk *clk) +{ + return clk->parent->rate / 2; +} + +static struct clk_ops div2_clk_ops = { + .recalc = div2_recalc, +}; + +/* Divide extalc1 by two */ +static struct clk extalc1_div2_clk = { + .ops = &div2_clk_ops, + .parent = &sh7377_extalc1_clk, +}; + +/* Divide extal2 by two */ +static struct clk extal2_div2_clk = { + .ops = &div2_clk_ops, + .parent = &sh7377_extal2_clk, +}; + +/* Divide extal2 by four */ +static struct clk extal2_div4_clk = { + .ops = &div2_clk_ops, + .parent = &extal2_div2_clk, +}; + +/* PLLC1 */ +static unsigned long pllc1_recalc(struct clk *clk) +{ + unsigned long mult = 1; + + if (__raw_readl(PLLC1CR) & (1 << 14)) + mult = (((__raw_readl(RTFRQCR) >> 24) & 0x3f) + 1) * 2; + + return clk->parent->rate * mult; +} + +static struct clk_ops pllc1_clk_ops = { + .recalc = pllc1_recalc, +}; + +static struct clk pllc1_clk = { + .ops = &pllc1_clk_ops, + .flags = CLK_ENABLE_ON_INIT, + .parent = &extalc1_div2_clk, +}; + +/* Divide PLLC1 by two */ +static struct clk pllc1_div2_clk = { + .ops = &div2_clk_ops, + .parent = &pllc1_clk, +}; + +/* PLLC2 */ +static unsigned long pllc2_recalc(struct clk *clk) +{ + unsigned long mult = 1; + + if (__raw_readl(PLLC2CR) & (1 << 31)) + mult = (((__raw_readl(PLLC2CR) >> 24) & 0x3f) + 1) * 2; + + return clk->parent->rate * mult; +} + +static struct clk_ops pllc2_clk_ops = { + .recalc = pllc2_recalc, +}; + +static struct clk pllc2_clk = { + .ops = &pllc2_clk_ops, + .flags = CLK_ENABLE_ON_INIT, + .parent = &extalc1_div2_clk, +}; + +static struct clk *main_clks[] = { + &r_clk, + &sh7377_extalc1_clk, + &sh7377_extal2_clk, + &extalc1_div2_clk, + &extal2_div2_clk, + &extal2_div4_clk, + &pllc1_clk, + &pllc1_div2_clk, + &pllc2_clk, +}; + +static void div4_kick(struct clk *clk) +{ + unsigned long value; + + /* set KICK bit in SYFRQCR to update hardware setting */ + value = __raw_readl(SYFRQCR); + value |= (1 << 31); + __raw_writel(value, SYFRQCR); +} + +static int divisors[] = { 2, 3, 4, 6, 8, 12, 16, 18, + 24, 32, 36, 48, 0, 72, 96, 0 }; + +static struct clk_div_mult_table div4_div_mult_table = { + .divisors = divisors, + .nr_divisors = ARRAY_SIZE(divisors), +}; + +static struct clk_div4_table div4_table = { + .div_mult_table = &div4_div_mult_table, + .kick = div4_kick, +}; + +enum { DIV4_I, DIV4_ZG, DIV4_B, DIV4_M1, DIV4_CSIR, + DIV4_ZTR, DIV4_ZT, DIV4_Z, DIV4_HP, + DIV4_ZS, DIV4_ZB, DIV4_ZB3, DIV4_CP, DIV4_NR }; + +#define DIV4(_reg, _bit, _mask, _flags) \ + SH_CLK_DIV4(&pllc1_clk, _reg, _bit, _mask, _flags) + +static struct clk div4_clks[DIV4_NR] = { + [DIV4_I] = DIV4(RTFRQCR, 20, 0x6fff, CLK_ENABLE_ON_INIT), + [DIV4_ZG] = DIV4(RTFRQCR, 16, 0x6fff, CLK_ENABLE_ON_INIT), + [DIV4_B] = DIV4(RTFRQCR, 8, 0x6fff, CLK_ENABLE_ON_INIT), + [DIV4_M1] = DIV4(RTFRQCR, 4, 0x6fff, CLK_ENABLE_ON_INIT), + [DIV4_CSIR] = DIV4(RTFRQCR, 0, 0x6fff, 0), + [DIV4_ZTR] = DIV4(SYFRQCR, 20, 0x6fff, 0), + [DIV4_ZT] = DIV4(SYFRQCR, 16, 0x6fff, 0), + [DIV4_Z] = DIV4(SYFRQCR, 12, 0x6fff, 0), + [DIV4_HP] = DIV4(SYFRQCR, 4, 0x6fff, 0), + [DIV4_ZS] = DIV4(CMFRQCR, 12, 0x6fff, 0), + [DIV4_ZB] = DIV4(CMFRQCR, 8, 0x6fff, 0), + [DIV4_ZB3] = DIV4(CMFRQCR, 4, 0x6fff, 0), + [DIV4_CP] = DIV4(CMFRQCR, 0, 0x6fff, 0), +}; + +enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_FMSI, DIV6_FMSO, + DIV6_FSI, DIV6_SUB, DIV6_SPU, DIV6_MSU, DIV6_MVI3, DIV6_HDMI, + DIV6_MF1, DIV6_MF2, DIV6_DSIT, DIV6_DSIP, + DIV6_NR }; + +static struct clk div6_clks[] = { + [DIV6_VCK1] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR1, 0), + [DIV6_VCK2] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR2, 0), + [DIV6_VCK3] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR3, 0), + [DIV6_FMSI] = SH_CLK_DIV6(&pllc1_div2_clk, FMSICKCR, 0), + [DIV6_FMSO] = SH_CLK_DIV6(&pllc1_div2_clk, FMSOCKCR, 0), + [DIV6_FSI] = SH_CLK_DIV6(&pllc1_div2_clk, FSICKCR, 0), + [DIV6_SUB] = SH_CLK_DIV6(&sh7377_extal2_clk, SUBUSBCKCR, 0), + [DIV6_SPU] = SH_CLK_DIV6(&pllc1_div2_clk, SPUCKCR, 0), + [DIV6_MSU] = SH_CLK_DIV6(&pllc1_div2_clk, MSUCKCR, 0), + [DIV6_MVI3] = SH_CLK_DIV6(&pllc1_div2_clk, MVI3CKCR, 0), + [DIV6_HDMI] = SH_CLK_DIV6(&pllc1_div2_clk, HDMICKCR, 0), + [DIV6_MF1] = SH_CLK_DIV6(&pllc1_div2_clk, MFCK1CR, 0), + [DIV6_MF2] = SH_CLK_DIV6(&pllc1_div2_clk, MFCK2CR, 0), + [DIV6_DSIT] = SH_CLK_DIV6(&pllc1_div2_clk, DSITCKCR, 0), + [DIV6_DSIP] = SH_CLK_DIV6(&pllc1_div2_clk, DSIPCKCR, 0), +}; + +enum { MSTP001, + MSTP131, MSTP130, MSTP129, MSTP128, MSTP116, MSTP106, MSTP101, + MSTP223, MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200, + MSTP331, MSTP329, MSTP325, MSTP323, MSTP322, + MSTP315, MSTP314, MSTP313, + MSTP403, + MSTP_NR }; + +#define MSTP(_parent, _reg, _bit, _flags) \ + SH_CLK_MSTP32(_parent, _reg, _bit, _flags) + +static struct clk mstp_clks[] = { + [MSTP001] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR0, 1, 0), /* IIC2 */ + [MSTP131] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 31, 0), /* VEU3 */ + [MSTP130] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 30, 0), /* VEU2 */ + [MSTP129] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 29, 0), /* VEU1 */ + [MSTP128] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 28, 0), /* VEU0 */ + [MSTP116] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */ + [MSTP106] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 6, 0), /* JPU */ + [MSTP101] = MSTP(&div4_clks[DIV4_M1], SMSTPCR1, 1, 0), /* VPU */ + [MSTP223] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR2, 23, 0), /* SPU2 */ + [MSTP207] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 7, 0), /* SCIFA5 */ + [MSTP206] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 6, 0), /* SCIFB */ + [MSTP204] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 4, 0), /* SCIFA0 */ + [MSTP203] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 3, 0), /* SCIFA1 */ + [MSTP202] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 2, 0), /* SCIFA2 */ + [MSTP201] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 1, 0), /* SCIFA3 */ + [MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */ + [MSTP331] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 31, 0), /* SCIFA6 */ + [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */ + [MSTP325] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 25, 0), /* IRDA */ + [MSTP323] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */ + [MSTP322] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 22, 0), /* USB0 */ + [MSTP315] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 15, 0), /* FLCTL */ + [MSTP314] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 14, 0), /* SDHI0 */ + [MSTP313] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 13, 0), /* SDHI1 */ + [MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */ +}; + +#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk } +#define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk } + +static struct clk_lookup lookups[] = { + /* main clocks */ + CLKDEV_CON_ID("r_clk", &r_clk), + CLKDEV_CON_ID("extalc1", &sh7377_extalc1_clk), + CLKDEV_CON_ID("extal2", &sh7377_extal2_clk), + CLKDEV_CON_ID("extalc1_div2_clk", &extalc1_div2_clk), + CLKDEV_CON_ID("extal2_div2_clk", &extal2_div2_clk), + CLKDEV_CON_ID("extal2_div4_clk", &extal2_div4_clk), + CLKDEV_CON_ID("pllc1_clk", &pllc1_clk), + CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk), + CLKDEV_CON_ID("pllc2_clk", &pllc2_clk), + + /* DIV4 clocks */ + CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]), + CLKDEV_CON_ID("zg_clk", &div4_clks[DIV4_ZG]), + CLKDEV_CON_ID("b_clk", &div4_clks[DIV4_B]), + CLKDEV_CON_ID("m1_clk", &div4_clks[DIV4_M1]), + CLKDEV_CON_ID("csir_clk", &div4_clks[DIV4_CSIR]), + CLKDEV_CON_ID("ztr_clk", &div4_clks[DIV4_ZTR]), + CLKDEV_CON_ID("zt_clk", &div4_clks[DIV4_ZT]), + CLKDEV_CON_ID("z_clk", &div4_clks[DIV4_Z]), + CLKDEV_CON_ID("hp_clk", &div4_clks[DIV4_HP]), + CLKDEV_CON_ID("zs_clk", &div4_clks[DIV4_ZS]), + CLKDEV_CON_ID("zb_clk", &div4_clks[DIV4_ZB]), + CLKDEV_CON_ID("zb3_clk", &div4_clks[DIV4_ZB3]), + CLKDEV_CON_ID("cp_clk", &div4_clks[DIV4_CP]), + + /* DIV6 clocks */ + CLKDEV_CON_ID("vck1_clk", &div6_clks[DIV6_VCK1]), + CLKDEV_CON_ID("vck2_clk", &div6_clks[DIV6_VCK2]), + CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]), + CLKDEV_CON_ID("fmsi_clk", &div6_clks[DIV6_FMSI]), + CLKDEV_CON_ID("fmso_clk", &div6_clks[DIV6_FMSO]), + CLKDEV_CON_ID("fsi_clk", &div6_clks[DIV6_FSI]), + CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]), + CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]), + CLKDEV_CON_ID("msu_clk", &div6_clks[DIV6_MSU]), + CLKDEV_CON_ID("mvi3_clk", &div6_clks[DIV6_MVI3]), + CLKDEV_CON_ID("hdmi_clk", &div6_clks[DIV6_HDMI]), + CLKDEV_CON_ID("mf1_clk", &div6_clks[DIV6_MF1]), + CLKDEV_CON_ID("mf2_clk", &div6_clks[DIV6_MF2]), + CLKDEV_CON_ID("dsit_clk", &div6_clks[DIV6_DSIT]), + CLKDEV_CON_ID("dsip_clk", &div6_clks[DIV6_DSIP]), + + /* MSTP32 clocks */ + CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* IIC2 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.4", &mstp_clks[MSTP131]), /* VEU3 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.3", &mstp_clks[MSTP130]), /* VEU2 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.2", &mstp_clks[MSTP129]), /* VEU1 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.1", &mstp_clks[MSTP128]), /* VEU0 */ + CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* IIC0 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.5", &mstp_clks[MSTP106]), /* JPU */ + CLKDEV_DEV_ID("uio_pdrv_genirq.0", &mstp_clks[MSTP101]), /* VPU */ + CLKDEV_DEV_ID("uio_pdrv_genirq.6", &mstp_clks[MSTP223]), /* SPU2DSP0 */ + CLKDEV_DEV_ID("uio_pdrv_genirq.7", &mstp_clks[MSTP223]), /* SPU2DSP1 */ + CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), /* SCIFA5 */ + CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP206]), /* SCIFB */ + CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */ + CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP203]), /* SCIFA1 */ + CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP202]), /* SCIFA2 */ + CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), /* SCIFA3 */ + CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */ + CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP331]), /* SCIFA6 */ + CLKDEV_CON_ID("cmt1", &mstp_clks[MSTP329]), /* CMT10 */ + CLKDEV_DEV_ID("sh_irda", &mstp_clks[MSTP325]), /* IRDA */ + CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */ + CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USBHS */ + CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP322]), /* USBHS */ + CLKDEV_DEV_ID("sh_flctl", &mstp_clks[MSTP315]), /* FLCTL */ + CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */ + CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */ + CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */ +}; + +void __init sh7377_clock_init(void) +{ + int k, ret = 0; + + for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++) + ret = clk_register(main_clks[k]); + + if (!ret) + ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table); + + if (!ret) + ret = sh_clk_div6_register(div6_clks, DIV6_NR); + + if (!ret) + ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); + + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); + + if (!ret) + clk_init(); + else + panic("failed to setup sh7377 clocks\n"); +} diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index b84cdbae4a5a..efeef778a875 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -17,7 +17,10 @@ extern struct clk sh7367_extal2_clk; extern void sh7377_init_irq(void); extern void sh7377_add_early_devices(void); extern void sh7377_add_standard_devices(void); +extern void sh7377_clock_init(void); extern void sh7377_pinmux_init(void); +extern struct clk sh7377_extalc1_clk; +extern struct clk sh7377_extal2_clk; extern void sh7372_init_irq(void); extern void sh7372_add_early_devices(void); -- GitLab From ea95450eede38ca695db8c2202b1f5c7a0f9ebbb Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 20 May 2010 16:31:56 +0000 Subject: [PATCH 0086/5312] fbdev: add a MIPI DSI header This header adds defines for MIPI DSI and DCS commands and data formats. See http://www.mipi.org/ for details. Signed-off-by: Guennadi Liakhovetski Acked-by: Tomi Valkeinen Signed-off-by: Paul Mundt --- include/video/mipi_display.h | 130 +++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 include/video/mipi_display.h diff --git a/include/video/mipi_display.h b/include/video/mipi_display.h new file mode 100644 index 000000000000..ddcc8ca7316b --- /dev/null +++ b/include/video/mipi_display.h @@ -0,0 +1,130 @@ +/* + * Defines for Mobile Industry Processor Interface (MIPI(R)) + * Display Working Group standards: DSI, DCS, DBI, DPI + * + * Copyright (C) 2010 Guennadi Liakhovetski + * Copyright (C) 2006 Nokia Corporation + * Author: Imre Deak + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef MIPI_DISPLAY_H +#define MIPI_DISPLAY_H + +/* MIPI DSI Processor-to-Peripheral transaction types */ +enum { + MIPI_DSI_V_SYNC_START = 0x01, + MIPI_DSI_V_SYNC_END = 0x11, + MIPI_DSI_H_SYNC_START = 0x21, + MIPI_DSI_H_SYNC_END = 0x31, + + MIPI_DSI_COLOR_MODE_OFF = 0x02, + MIPI_DSI_COLOR_MODE_ON = 0x12, + MIPI_DSI_SHUTDOWN_PERIPHERAL = 0x22, + MIPI_DSI_TURN_ON_PERIPHERAL = 0x32, + + MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM = 0x03, + MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM = 0x13, + MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM = 0x23, + + MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM = 0x04, + MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM = 0x14, + MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM = 0x24, + + MIPI_DSI_DCS_SHORT_WRITE = 0x05, + MIPI_DSI_DCS_SHORT_WRITE_PARAM = 0x15, + + MIPI_DSI_DCS_READ = 0x06, + + MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE = 0x37, + + MIPI_DSI_END_OF_TRANSMISSION = 0x08, + + MIPI_DSI_NULL_PACKET = 0x09, + MIPI_DSI_BLANKING_PACKET = 0x19, + MIPI_DSI_GENERIC_LONG_WRITE = 0x29, + MIPI_DSI_DCS_LONG_WRITE = 0x39, + + MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20 = 0x0c, + MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24 = 0x1c, + MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16 = 0x2c, + + MIPI_DSI_PACKED_PIXEL_STREAM_30 = 0x0d, + MIPI_DSI_PACKED_PIXEL_STREAM_36 = 0x1d, + MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12 = 0x3d, + + MIPI_DSI_PACKED_PIXEL_STREAM_16 = 0x0e, + MIPI_DSI_PACKED_PIXEL_STREAM_18 = 0x1e, + MIPI_DSI_PIXEL_STREAM_3BYTE_18 = 0x2e, + MIPI_DSI_PACKED_PIXEL_STREAM_24 = 0x3e, +}; + +/* MIPI DSI Peripheral-to-Processor transaction types */ +enum { + MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT = 0x02, + MIPI_DSI_RX_END_OF_TRANSMISSION = 0x08, + MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE = 0x11, + MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE = 0x12, + MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE = 0x1a, + MIPI_DSI_RX_DCS_LONG_READ_RESPONSE = 0x1c, + MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE = 0x21, + MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE = 0x22, +}; + +/* MIPI DCS commands */ +enum { + MIPI_DCS_NOP = 0x00, + MIPI_DCS_SOFT_RESET = 0x01, + MIPI_DCS_GET_DISPLAY_ID = 0x04, + MIPI_DCS_GET_RED_CHANNEL = 0x06, + MIPI_DCS_GET_GREEN_CHANNEL = 0x07, + MIPI_DCS_GET_BLUE_CHANNEL = 0x08, + MIPI_DCS_GET_DISPLAY_STATUS = 0x09, + MIPI_DCS_GET_POWER_MODE = 0x0A, + MIPI_DCS_GET_ADDRESS_MODE = 0x0B, + MIPI_DCS_GET_PIXEL_FORMAT = 0x0C, + MIPI_DCS_GET_DISPLAY_MODE = 0x0D, + MIPI_DCS_GET_SIGNAL_MODE = 0x0E, + MIPI_DCS_GET_DIAGNOSTIC_RESULT = 0x0F, + MIPI_DCS_ENTER_SLEEP_MODE = 0x10, + MIPI_DCS_EXIT_SLEEP_MODE = 0x11, + MIPI_DCS_ENTER_PARTIAL_MODE = 0x12, + MIPI_DCS_ENTER_NORMAL_MODE = 0x13, + MIPI_DCS_EXIT_INVERT_MODE = 0x20, + MIPI_DCS_ENTER_INVERT_MODE = 0x21, + MIPI_DCS_SET_GAMMA_CURVE = 0x26, + MIPI_DCS_SET_DISPLAY_OFF = 0x28, + MIPI_DCS_SET_DISPLAY_ON = 0x29, + MIPI_DCS_SET_COLUMN_ADDRESS = 0x2A, + MIPI_DCS_SET_PAGE_ADDRESS = 0x2B, + MIPI_DCS_WRITE_MEMORY_START = 0x2C, + MIPI_DCS_WRITE_LUT = 0x2D, + MIPI_DCS_READ_MEMORY_START = 0x2E, + MIPI_DCS_SET_PARTIAL_AREA = 0x30, + MIPI_DCS_SET_SCROLL_AREA = 0x33, + MIPI_DCS_SET_TEAR_OFF = 0x34, + MIPI_DCS_SET_TEAR_ON = 0x35, + MIPI_DCS_SET_ADDRESS_MODE = 0x36, + MIPI_DCS_SET_SCROLL_START = 0x37, + MIPI_DCS_EXIT_IDLE_MODE = 0x38, + MIPI_DCS_ENTER_IDLE_MODE = 0x39, + MIPI_DCS_SET_PIXEL_FORMAT = 0x3A, + MIPI_DCS_WRITE_MEMORY_CONTINUE = 0x3C, + MIPI_DCS_READ_MEMORY_CONTINUE = 0x3E, + MIPI_DCS_SET_TEAR_SCANLINE = 0x44, + MIPI_DCS_GET_SCANLINE = 0x45, + MIPI_DCS_READ_DDB_START = 0xA1, + MIPI_DCS_READ_DDB_CONTINUE = 0xA8, +}; + +/* MIPI DCS pixel formats */ +#define MIPI_DCS_PIXEL_FMT_24BIT 7 +#define MIPI_DCS_PIXEL_FMT_18BIT 6 +#define MIPI_DCS_PIXEL_FMT_16BIT 5 +#define MIPI_DCS_PIXEL_FMT_12BIT 3 +#define MIPI_DCS_PIXEL_FMT_8BIT 2 +#define MIPI_DCS_PIXEL_FMT_3BIT 1 + +#endif -- GitLab From d473e0a577be3205474707dd27cff3d2c2b9e307 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Sun, 23 May 2010 13:55:34 +0000 Subject: [PATCH 0087/5312] ARM: mach-shmobile: add LCDC and MIPI DSI-Tx clock definitions to sh7372 Define clock objects for switching on and off clocks for LCDC0, LCDC1 and MIPI DSI-Tx. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/clock-sh7372.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 023de5e5a33c..f2f9a4ad53a4 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -240,7 +240,10 @@ static struct clk div6_clks[DIV6_NR] = { }; enum { MSTP001, - MSTP131, MSTP130, MSTP129, MSTP128, MSTP116, MSTP106, MSTP101, + MSTP131, MSTP130, + MSTP129, MSTP128, + MSTP118, MSTP117, MSTP116, + MSTP106, MSTP101, MSTP100, MSTP223, MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200, MSTP329, MSTP323, MSTP322, MSTP314, MSTP313, @@ -256,9 +259,12 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP130] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 30, 0), /* VEU2 */ [MSTP129] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 29, 0), /* VEU1 */ [MSTP128] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 28, 0), /* VEU0 */ + [MSTP118] = MSTP(&div6_clks[DIV4_B], SMSTPCR1, 18, 0), /* DSITX */ + [MSTP117] = MSTP(&div6_clks[DIV4_B], SMSTPCR1, 17, 0), /* LCDC1 */ [MSTP116] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */ [MSTP106] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 6, 0), /* JPU */ [MSTP101] = MSTP(&div4_clks[DIV4_M1], SMSTPCR1, 1, 0), /* VPU */ + [MSTP100] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 0, 0), /* LCDC0 */ [MSTP223] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR2, 23, 0), /* SPU2 */ [MSTP207] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 7, 0), /* SCIFA5 */ [MSTP206] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 6, 0), /* SCIFB */ @@ -334,9 +340,12 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("uio_pdrv_genirq.3", &mstp_clks[MSTP130]), /* VEU2 */ CLKDEV_DEV_ID("uio_pdrv_genirq.2", &mstp_clks[MSTP129]), /* VEU1 */ CLKDEV_DEV_ID("uio_pdrv_genirq.1", &mstp_clks[MSTP128]), /* VEU0 */ + CLKDEV_DEV_ID("sh-mipi-dsi.0", &mstp_clks[MSTP118]), /* DSITX */ + CLKDEV_DEV_ID("sh_mobile_lcdc_fb.1", &mstp_clks[MSTP117]), /* LCDC1 */ CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* IIC0 */ CLKDEV_DEV_ID("uio_pdrv_genirq.5", &mstp_clks[MSTP106]), /* JPU */ CLKDEV_DEV_ID("uio_pdrv_genirq.0", &mstp_clks[MSTP101]), /* VPU */ + CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[MSTP100]), /* LCDC0 */ CLKDEV_DEV_ID("uio_pdrv_genirq.6", &mstp_clks[MSTP223]), /* SPU2DSP0 */ CLKDEV_DEV_ID("uio_pdrv_genirq.7", &mstp_clks[MSTP223]), /* SPU2DSP1 */ CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), /* SCIFA5 */ -- GitLab From 1430e006a36da5401ad4420711b5a702ba17afa8 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 21 May 2010 15:15:41 +0000 Subject: [PATCH 0088/5312] sh: add a YUV422 output data format, that is also supported by LCDC The LCDC block is allowed to use one of the two output data formats, when used with MIPI DSI: RGB24 and YUV422. YUV422 is not currently handled by the LCDC driver, but we have to add a define for it for MIPI. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- include/video/sh_mobile_lcdc.h | 39 ++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h index 2cc893fc1f85..5eaea78ca111 100644 --- a/include/video/sh_mobile_lcdc.h +++ b/include/video/sh_mobile_lcdc.h @@ -3,24 +3,27 @@ #include -enum { RGB8, /* 24bpp, 8:8:8 */ - RGB9, /* 18bpp, 9:9 */ - RGB12A, /* 24bpp, 12:12 */ - RGB12B, /* 12bpp */ - RGB16, /* 16bpp */ - RGB18, /* 18bpp */ - RGB24, /* 24bpp */ - SYS8A, /* 24bpp, 8:8:8 */ - SYS8B, /* 18bpp, 8:8:2 */ - SYS8C, /* 18bpp, 2:8:8 */ - SYS8D, /* 16bpp, 8:8 */ - SYS9, /* 18bpp, 9:9 */ - SYS12, /* 24bpp, 12:12 */ - SYS16A, /* 16bpp */ - SYS16B, /* 18bpp, 16:2 */ - SYS16C, /* 18bpp, 2:16 */ - SYS18, /* 18bpp */ - SYS24 };/* 24bpp */ +enum { + RGB8, /* 24bpp, 8:8:8 */ + RGB9, /* 18bpp, 9:9 */ + RGB12A, /* 24bpp, 12:12 */ + RGB12B, /* 12bpp */ + RGB16, /* 16bpp */ + RGB18, /* 18bpp */ + RGB24, /* 24bpp */ + YUV422, /* 16bpp */ + SYS8A, /* 24bpp, 8:8:8 */ + SYS8B, /* 18bpp, 8:8:2 */ + SYS8C, /* 18bpp, 2:8:8 */ + SYS8D, /* 16bpp, 8:8 */ + SYS9, /* 18bpp, 9:9 */ + SYS12, /* 24bpp, 12:12 */ + SYS16A, /* 16bpp */ + SYS16B, /* 18bpp, 16:2 */ + SYS16C, /* 18bpp, 2:16 */ + SYS18, /* 18bpp */ + SYS24, /* 24bpp */ +}; enum { LCDC_CHAN_DISABLED = 0, LCDC_CHAN_MAINLCD, -- GitLab From 9fd04fe34af36344f61ebb24cc653726c231356e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Sun, 23 May 2010 14:00:43 +0000 Subject: [PATCH 0089/5312] sh-mobile: add support for displays, connected over the MIPI bus Some SH-mobile SoCs have a MIPI DSI controller, that can be used to connect MIPI displays to LCDC. This patch adds a platform driver for SH-mobile MIPI DSI unit. It uses existing hooks in the sh_mobile_lcdcfb.c driver for display activation and deactivation. Signed-off-by: Guennadi Liakhovetski Tested-by: Damian Hobson-Garcia Signed-off-by: Paul Mundt --- drivers/video/Kconfig | 8 + drivers/video/Makefile | 1 + drivers/video/sh_mipi_dsi.c | 505 ++++++++++++++++++++++++++++++++++++ include/video/sh_mipi_dsi.h | 35 +++ 4 files changed, 549 insertions(+) create mode 100644 drivers/video/sh_mipi_dsi.c create mode 100644 include/video/sh_mipi_dsi.h diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 6e16244f3ed1..773c4a68de89 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1879,6 +1879,13 @@ config FB_W100 If unsure, say N. +config SH_MIPI_DSI + tristate + depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK + +config SH_LCD_MIPI_DSI + bool + config FB_SH_MOBILE_LCDC tristate "SuperH Mobile LCDC framebuffer support" depends on FB && (SUPERH || ARCH_SHMOBILE) && HAVE_CLK @@ -1887,6 +1894,7 @@ config FB_SH_MOBILE_LCDC select FB_SYS_IMAGEBLIT select FB_SYS_FOPS select FB_DEFERRED_IO + select SH_MIPI_DSI if SH_LCD_MIPI_DSI ---help--- Frame buffer driver for the on-chip SH-Mobile LCD controller. diff --git a/drivers/video/Makefile b/drivers/video/Makefile index ddc2af2ba45b..3c3bf867ef18 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -123,6 +123,7 @@ obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o obj-$(CONFIG_FB_PS3) += ps3fb.o obj-$(CONFIG_FB_SM501) += sm501fb.o obj-$(CONFIG_FB_XILINX) += xilinxfb.o +obj-$(CONFIG_SH_MIPI_DSI) += sh_mipi_dsi.o obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o obj-$(CONFIG_FB_OMAP) += omap/ obj-y += omap2/ diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c new file mode 100644 index 000000000000..017ae9f47d36 --- /dev/null +++ b/drivers/video/sh_mipi_dsi.c @@ -0,0 +1,505 @@ +/* + * Renesas SH-mobile MIPI DSI support + * + * Copyright (C) 2010 Guennadi Liakhovetski + * + * This is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include