Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] irq: Add new flag to ack level-triggered interrupts before unmasking
From: Carlo Caione @ 2014-02-06 21:11 UTC (permalink / raw)
  To: linux-arm-kernel

Several irqchip drivers require the level-triggered interrupt to be
acked before unmasking to avoid that a second interrupt is immediately
triggered. This small patch introduces a new irqchip flags that is used
to ack the IRQ line before it is unmasked.

Signed-off-by: Carlo Caione <carlo@caione.org>
---
 include/linux/irq.h    |  2 ++
 kernel/irq/chip.c      | 10 ++++++++++
 kernel/irq/internals.h |  1 +
 kernel/irq/manage.c    |  2 +-
 4 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/include/linux/irq.h b/include/linux/irq.h
index 7dc1003..2cbe8d1 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -349,6 +349,7 @@ struct irq_chip {
  * IRQCHIP_ONOFFLINE_ENABLED:	Only call irq_on/off_line callbacks
  *				when irq enabled
  * IRQCHIP_SKIP_SET_WAKE:	Skip chip.irq_set_wake(), for this irq chip
+ * IRQCHIP_ACK_ON_UNMASK:	Ack level interrupts right before unmask
  */
 enum {
 	IRQCHIP_SET_TYPE_MASKED		= (1 <<  0),
@@ -357,6 +358,7 @@ enum {
 	IRQCHIP_ONOFFLINE_ENABLED	= (1 <<  3),
 	IRQCHIP_SKIP_SET_WAKE		= (1 <<  4),
 	IRQCHIP_ONESHOT_SAFE		= (1 <<  5),
+	IRQCHIP_ACK_ON_UNMASK		= (1 <<  6),
 };
 
 /* This include will go away once we isolated irq_desc usage to core code */
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index dc04c16..9d2d2e2 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -265,6 +265,16 @@ static inline void mask_ack_irq(struct irq_desc *desc)
 	irq_state_set_masked(desc);
 }
 
+void ack_unmask_irq(struct irq_desc *desc)
+{
+	if ((desc->irq_data.chip->flags & IRQCHIP_ACK_ON_UNMASK) &&
+	    (irqd_get_trigger_type(&desc->irq_data) & IRQ_TYPE_LEVEL_MASK) &&
+	    desc->irq_data.chip->irq_ack)
+			desc->irq_data.chip->irq_ack(&desc->irq_data);
+
+	unmask_irq(desc);
+}
+
 void mask_irq(struct irq_desc *desc)
 {
 	if (desc->irq_data.chip->irq_mask) {
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index 001fa5b..06ff850 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -73,6 +73,7 @@ extern void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu);
 extern void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu);
 extern void mask_irq(struct irq_desc *desc);
 extern void unmask_irq(struct irq_desc *desc);
+extern void ack_unmask_irq(struct irq_desc *desc);
 
 extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
 
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 481a13c..39505d8 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -718,7 +718,7 @@ again:
 
 	if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) &&
 	    irqd_irq_masked(&desc->irq_data))
-		unmask_irq(desc);
+		ack_unmask_irq(desc);
 
 out_unlock:
 	raw_spin_unlock_irq(&desc->lock);
-- 
1.8.5.3

^ permalink raw reply related

* [PATCH] ARM: enable IRQs in user undefined instruction vector
From: Russell King - ARM Linux @ 2014-02-06 20:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <52F3D024.5020804@bracey.fi>

On Thu, Feb 06, 2014 at 08:10:44PM +0200, Kevin Bracey wrote:
> The VFP code did take pains to increment the pre-emption count before  
> enabling interrupts, but it's not obvious whether it requires no  
> pre-emption between the bounce and handler, or just no pre-emption  
> during the handler.

Just take a moment to think about this.

- Userspace raises an undefined instruction exception, running on CPU 0.
- The kernel starts to handle the exception by saving the ARM state.
- Enables interrupts.
- Context switch occurs.
- VFP state is saved and the VFP is disabled.

Now, on CPU1...
- Context switch occurs to the above thread (due to thread migration).
- VFP will be in a disabled state.
- We read FPEXC, find that the VFP is disabled
- Load saved state into the VFP
- Check for an exception recorded in the VFP state, and handle it.

So, that seems to work.  I suspect most things will work just fine in
this case.  What /can't/ be allowed to happen is we can't start
reading state from the hardware to handle the exception (or even be
mid-restoring the state) and be preempted - if we do, we'll end up
in a right mess because we'll end up with inconsistent state.

> What about the iwmmxt and the crunchbits? They are only lazy-enable  
> routines, to activate an inactive coprocessor. Which I think makes them  
> safe. If we schedule before reaching the handler, when this context is  
> returned to, the coprocessor must still be disabled in our context - the  
> handler can proceed to enable it. And there can't be any other context  
> state to worry about, assuming the lazy enable scheme works.

Again, the restore needs to happen with preemption disabled so that
you don't end up with the state half-restored, and then when you
resume the thread, you restore the other half.

This is actually the case I'm more worried about - whether all the
various handlers are safe being entered with preemption enabled.
They weren't written for it so the current answer is that they
aren't safe.

> I share Alexey's Ignatov's concern that your patch ends up running the  
> support code with interrupts either on or off depending on whether you  
> came from user or supervisor mode, which feels a little odd. But then,  
> always enabling interrupts like the current code does, when they might  
> have been off in the SVC mode context, also seems wrong.

That is indeed wrong, but then we /used/ to have the requirement that
the kernel will _never_ execute VFP instructions.  That's changed
recently since we now permit neon instructions to be executed.

However, the requirements to execute these instructions is very strict:
preemption disabled, it must not fault.  If you do fault, none of the
standard handlers get invoked, instead you get a critical kernel message.
So, if it does happen, then it's quite a bug already.

The only case where the kernel intentionally provokes such a fault
(which won't even reach the normal VFP handler) is when testing for the
presence of VFP and there is no hardware fitted.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

^ permalink raw reply

* [PATCH 2/3] PCI: ARM: add support for virtual PCI host controller
From: Russell King - ARM Linux @ 2014-02-06 20:31 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201402060928.53310.arnd@arndb.de>

On Thu, Feb 06, 2014 at 09:28:52AM +0100, Arnd Bergmann wrote:
> It certainly seems workable. OTOH if we just manage to do a
> helper that scans the OF ranges, allocates the I/O window,
> remaps it and calls the existing pci_add_resource_offset()
> helper, PCI host drivers don't need to worry about the
> io_offsets computation either and just need to pull out the
> correct window locations if they need to set up the hardware
> translation windows (which I'd hope we can often let the boot
> loader take care of).

Wrong.  Think about it for a moment.

Let's say you have two host bridges.  One host bridge has an IO window
which maps to bus I/O address 0 at 0x40000000.  The other host bridge
has it's IO window which maps bus I/O address 0 to 0x48000000.

So, the contents of the /hardware/ BARs is going to be in the range
of 0x0000 to 0xffff.  That means the value found in them is meaningless
without knowing which bus it's on.

Now, remember we said that I/O was going to be in a fixed location of
a fixed size, that being 0xfee00000 and 1MB in size.  So, we map the
first IO window to 0xfee00000.  What about the other one?  Well,
that could be mapped to 0xfee10000.

However, we need the IO addresses visible to the Linux kernel to be
offset by 0x10000 for the second bus - merely reading the BAR and
storing that in a resource, for the driver to later pick up and pass
into inb()/outb() won't work.  There needs to be offsetting.  This is
the exact reason why we have the offsetting for IO windows.

Exactly the same goes for memory windows as well.  It's no good working
in the hosts physical address space when looking at BARs, because they're
not in that address space.  They're in the bus address space which can
be entirely different.

So, whenever you enumerate a PCI bus, and read the resource information
out of the BARs, you /must/ know how that address region specified in
the BAR as a /bus/ address maps to the /host/ address space.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

^ permalink raw reply

* [PATCH] iommu/exynos: Remove driver
From: Olof Johansson @ 2014-02-06 19:51 UTC (permalink / raw)
  To: linux-arm-kernel

The driver has been unbuildable due to unfulfilled dependencies since
3.11, and even if enabled it won't build due to build breakage. Emails
about status on this have gone unanswered, and fixes seem to have been
abandoned.

It's obvious that nobody cares about it, so let's remove it.

Signed-off-by: Olof Johansson <olof@lixom.net>
---
 drivers/iommu/Kconfig        |   21 -
 drivers/iommu/Makefile       |    1 -
 drivers/iommu/exynos-iommu.c | 1035 ------------------------------------------
 3 files changed, 1057 deletions(-)
 delete mode 100644 drivers/iommu/exynos-iommu.c

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 79bbc21..b893367 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -176,27 +176,6 @@ config TEGRA_IOMMU_SMMU
 	  space through the SMMU (System Memory Management Unit)
 	  hardware included on Tegra SoCs.
 
-config EXYNOS_IOMMU
-	bool "Exynos IOMMU Support"
-	depends on ARCH_EXYNOS && EXYNOS_DEV_SYSMMU
-	select IOMMU_API
-	help
-	  Support for the IOMMU(System MMU) of Samsung Exynos application
-	  processor family. This enables H/W multimedia accellerators to see
-	  non-linear physical memory chunks as a linear memory in their
-	  address spaces
-
-	  If unsure, say N here.
-
-config EXYNOS_IOMMU_DEBUG
-	bool "Debugging log for Exynos IOMMU"
-	depends on EXYNOS_IOMMU
-	help
-	  Select this to see the detailed log message that shows what
-	  happens in the IOMMU driver
-
-	  Say N unless you need kernel log message for IOMMU debugging
-
 config SHMOBILE_IPMMU
 	bool
 
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 5d58bf1..de6c909 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -14,7 +14,6 @@ obj-$(CONFIG_OMAP_IOVMM) += omap-iovmm.o
 obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o
 obj-$(CONFIG_TEGRA_IOMMU_GART) += tegra-gart.o
 obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o
-obj-$(CONFIG_EXYNOS_IOMMU) += exynos-iommu.o
 obj-$(CONFIG_SHMOBILE_IOMMU) += shmobile-iommu.o
 obj-$(CONFIG_SHMOBILE_IPMMU) += shmobile-ipmmu.o
 obj-$(CONFIG_FSL_PAMU) += fsl_pamu.o fsl_pamu_domain.o
diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
deleted file mode 100644
index 0740189..0000000
--- a/drivers/iommu/exynos-iommu.c
+++ /dev/null
@@ -1,1035 +0,0 @@
-/* linux/drivers/iommu/exynos_iommu.c
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifdef CONFIG_EXYNOS_IOMMU_DEBUG
-#define DEBUG
-#endif
-
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/mm.h>
-#include <linux/iommu.h>
-#include <linux/errno.h>
-#include <linux/list.h>
-#include <linux/memblock.h>
-#include <linux/export.h>
-
-#include <asm/cacheflush.h>
-#include <asm/pgtable.h>
-
-#include <mach/sysmmu.h>
-
-/* We does not consider super section mapping (16MB) */
-#define SECT_ORDER 20
-#define LPAGE_ORDER 16
-#define SPAGE_ORDER 12
-
-#define SECT_SIZE (1 << SECT_ORDER)
-#define LPAGE_SIZE (1 << LPAGE_ORDER)
-#define SPAGE_SIZE (1 << SPAGE_ORDER)
-
-#define SECT_MASK (~(SECT_SIZE - 1))
-#define LPAGE_MASK (~(LPAGE_SIZE - 1))
-#define SPAGE_MASK (~(SPAGE_SIZE - 1))
-
-#define lv1ent_fault(sent) (((*(sent) & 3) == 0) || ((*(sent) & 3) == 3))
-#define lv1ent_page(sent) ((*(sent) & 3) == 1)
-#define lv1ent_section(sent) ((*(sent) & 3) == 2)
-
-#define lv2ent_fault(pent) ((*(pent) & 3) == 0)
-#define lv2ent_small(pent) ((*(pent) & 2) == 2)
-#define lv2ent_large(pent) ((*(pent) & 3) == 1)
-
-#define section_phys(sent) (*(sent) & SECT_MASK)
-#define section_offs(iova) ((iova) & 0xFFFFF)
-#define lpage_phys(pent) (*(pent) & LPAGE_MASK)
-#define lpage_offs(iova) ((iova) & 0xFFFF)
-#define spage_phys(pent) (*(pent) & SPAGE_MASK)
-#define spage_offs(iova) ((iova) & 0xFFF)
-
-#define lv1ent_offset(iova) ((iova) >> SECT_ORDER)
-#define lv2ent_offset(iova) (((iova) & 0xFF000) >> SPAGE_ORDER)
-
-#define NUM_LV1ENTRIES 4096
-#define NUM_LV2ENTRIES 256
-
-#define LV2TABLE_SIZE (NUM_LV2ENTRIES * sizeof(long))
-
-#define SPAGES_PER_LPAGE (LPAGE_SIZE / SPAGE_SIZE)
-
-#define lv2table_base(sent) (*(sent) & 0xFFFFFC00)
-
-#define mk_lv1ent_sect(pa) ((pa) | 2)
-#define mk_lv1ent_page(pa) ((pa) | 1)
-#define mk_lv2ent_lpage(pa) ((pa) | 1)
-#define mk_lv2ent_spage(pa) ((pa) | 2)
-
-#define CTRL_ENABLE	0x5
-#define CTRL_BLOCK	0x7
-#define CTRL_DISABLE	0x0
-
-#define REG_MMU_CTRL		0x000
-#define REG_MMU_CFG		0x004
-#define REG_MMU_STATUS		0x008
-#define REG_MMU_FLUSH		0x00C
-#define REG_MMU_FLUSH_ENTRY	0x010
-#define REG_PT_BASE_ADDR	0x014
-#define REG_INT_STATUS		0x018
-#define REG_INT_CLEAR		0x01C
-
-#define REG_PAGE_FAULT_ADDR	0x024
-#define REG_AW_FAULT_ADDR	0x028
-#define REG_AR_FAULT_ADDR	0x02C
-#define REG_DEFAULT_SLAVE_ADDR	0x030
-
-#define REG_MMU_VERSION		0x034
-
-#define REG_PB0_SADDR		0x04C
-#define REG_PB0_EADDR		0x050
-#define REG_PB1_SADDR		0x054
-#define REG_PB1_EADDR		0x058
-
-static unsigned long *section_entry(unsigned long *pgtable, unsigned long iova)
-{
-	return pgtable + lv1ent_offset(iova);
-}
-
-static unsigned long *page_entry(unsigned long *sent, unsigned long iova)
-{
-	return (unsigned long *)__va(lv2table_base(sent)) + lv2ent_offset(iova);
-}
-
-enum exynos_sysmmu_inttype {
-	SYSMMU_PAGEFAULT,
-	SYSMMU_AR_MULTIHIT,
-	SYSMMU_AW_MULTIHIT,
-	SYSMMU_BUSERROR,
-	SYSMMU_AR_SECURITY,
-	SYSMMU_AR_ACCESS,
-	SYSMMU_AW_SECURITY,
-	SYSMMU_AW_PROTECTION, /* 7 */
-	SYSMMU_FAULT_UNKNOWN,
-	SYSMMU_FAULTS_NUM
-};
-
-/*
- * @itype: type of fault.
- * @pgtable_base: the physical address of page table base. This is 0 if @itype
- *                is SYSMMU_BUSERROR.
- * @fault_addr: the device (virtual) address that the System MMU tried to
- *             translated. This is 0 if @itype is SYSMMU_BUSERROR.
- */
-typedef int (*sysmmu_fault_handler_t)(enum exynos_sysmmu_inttype itype,
-			unsigned long pgtable_base, unsigned long fault_addr);
-
-static unsigned short fault_reg_offset[SYSMMU_FAULTS_NUM] = {
-	REG_PAGE_FAULT_ADDR,
-	REG_AR_FAULT_ADDR,
-	REG_AW_FAULT_ADDR,
-	REG_DEFAULT_SLAVE_ADDR,
-	REG_AR_FAULT_ADDR,
-	REG_AR_FAULT_ADDR,
-	REG_AW_FAULT_ADDR,
-	REG_AW_FAULT_ADDR
-};
-
-static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
-	"PAGE FAULT",
-	"AR MULTI-HIT FAULT",
-	"AW MULTI-HIT FAULT",
-	"BUS ERROR",
-	"AR SECURITY PROTECTION FAULT",
-	"AR ACCESS PROTECTION FAULT",
-	"AW SECURITY PROTECTION FAULT",
-	"AW ACCESS PROTECTION FAULT",
-	"UNKNOWN FAULT"
-};
-
-struct exynos_iommu_domain {
-	struct list_head clients; /* list of sysmmu_drvdata.node */
-	unsigned long *pgtable; /* lv1 page table, 16KB */
-	short *lv2entcnt; /* free lv2 entry counter for each section */
-	spinlock_t lock; /* lock for this structure */
-	spinlock_t pgtablelock; /* lock for modifying page table @ pgtable */
-};
-
-struct sysmmu_drvdata {
-	struct list_head node; /* entry of exynos_iommu_domain.clients */
-	struct device *sysmmu;	/* System MMU's device descriptor */
-	struct device *dev;	/* Owner of system MMU */
-	char *dbgname;
-	int nsfrs;
-	void __iomem **sfrbases;
-	struct clk *clk[2];
-	int activations;
-	rwlock_t lock;
-	struct iommu_domain *domain;
-	sysmmu_fault_handler_t fault_handler;
-	unsigned long pgtable;
-};
-
-static bool set_sysmmu_active(struct sysmmu_drvdata *data)
-{
-	/* return true if the System MMU was not active previously
-	   and it needs to be initialized */
-	return ++data->activations == 1;
-}
-
-static bool set_sysmmu_inactive(struct sysmmu_drvdata *data)
-{
-	/* return true if the System MMU is needed to be disabled */
-	BUG_ON(data->activations < 1);
-	return --data->activations == 0;
-}
-
-static bool is_sysmmu_active(struct sysmmu_drvdata *data)
-{
-	return data->activations > 0;
-}
-
-static void sysmmu_unblock(void __iomem *sfrbase)
-{
-	__raw_writel(CTRL_ENABLE, sfrbase + REG_MMU_CTRL);
-}
-
-static bool sysmmu_block(void __iomem *sfrbase)
-{
-	int i = 120;
-
-	__raw_writel(CTRL_BLOCK, sfrbase + REG_MMU_CTRL);
-	while ((i > 0) && !(__raw_readl(sfrbase + REG_MMU_STATUS) & 1))
-		--i;
-
-	if (!(__raw_readl(sfrbase + REG_MMU_STATUS) & 1)) {
-		sysmmu_unblock(sfrbase);
-		return false;
-	}
-
-	return true;
-}
-
-static void __sysmmu_tlb_invalidate(void __iomem *sfrbase)
-{
-	__raw_writel(0x1, sfrbase + REG_MMU_FLUSH);
-}
-
-static void __sysmmu_tlb_invalidate_entry(void __iomem *sfrbase,
-						unsigned long iova)
-{
-	__raw_writel((iova & SPAGE_MASK) | 1, sfrbase + REG_MMU_FLUSH_ENTRY);
-}
-
-static void __sysmmu_set_ptbase(void __iomem *sfrbase,
-				       unsigned long pgd)
-{
-	__raw_writel(0x1, sfrbase + REG_MMU_CFG); /* 16KB LV1, LRU */
-	__raw_writel(pgd, sfrbase + REG_PT_BASE_ADDR);
-
-	__sysmmu_tlb_invalidate(sfrbase);
-}
-
-static void __sysmmu_set_prefbuf(void __iomem *sfrbase, unsigned long base,
-						unsigned long size, int idx)
-{
-	__raw_writel(base, sfrbase + REG_PB0_SADDR + idx * 8);
-	__raw_writel(size - 1 + base,  sfrbase + REG_PB0_EADDR + idx * 8);
-}
-
-static void __set_fault_handler(struct sysmmu_drvdata *data,
-					sysmmu_fault_handler_t handler)
-{
-	unsigned long flags;
-
-	write_lock_irqsave(&data->lock, flags);
-	data->fault_handler = handler;
-	write_unlock_irqrestore(&data->lock, flags);
-}
-
-void exynos_sysmmu_set_fault_handler(struct device *dev,
-					sysmmu_fault_handler_t handler)
-{
-	struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
-
-	__set_fault_handler(data, handler);
-}
-
-static int default_fault_handler(enum exynos_sysmmu_inttype itype,
-		     unsigned long pgtable_base, unsigned long fault_addr)
-{
-	unsigned long *ent;
-
-	if ((itype >= SYSMMU_FAULTS_NUM) || (itype < SYSMMU_PAGEFAULT))
-		itype = SYSMMU_FAULT_UNKNOWN;
-
-	pr_err("%s occurred@0x%lx(Page table base: 0x%lx)\n",
-			sysmmu_fault_name[itype], fault_addr, pgtable_base);
-
-	ent = section_entry(__va(pgtable_base), fault_addr);
-	pr_err("\tLv1 entry: 0x%lx\n", *ent);
-
-	if (lv1ent_page(ent)) {
-		ent = page_entry(ent, fault_addr);
-		pr_err("\t Lv2 entry: 0x%lx\n", *ent);
-	}
-
-	pr_err("Generating Kernel OOPS... because it is unrecoverable.\n");
-
-	BUG();
-
-	return 0;
-}
-
-static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
-{
-	/* SYSMMU is in blocked when interrupt occurred. */
-	struct sysmmu_drvdata *data = dev_id;
-	struct resource *irqres;
-	struct platform_device *pdev;
-	enum exynos_sysmmu_inttype itype;
-	unsigned long addr = -1;
-
-	int i, ret = -ENOSYS;
-
-	read_lock(&data->lock);
-
-	WARN_ON(!is_sysmmu_active(data));
-
-	pdev = to_platform_device(data->sysmmu);
-	for (i = 0; i < (pdev->num_resources / 2); i++) {
-		irqres = platform_get_resource(pdev, IORESOURCE_IRQ, i);
-		if (irqres && ((int)irqres->start == irq))
-			break;
-	}
-
-	if (i == pdev->num_resources) {
-		itype = SYSMMU_FAULT_UNKNOWN;
-	} else {
-		itype = (enum exynos_sysmmu_inttype)
-			__ffs(__raw_readl(data->sfrbases[i] + REG_INT_STATUS));
-		if (WARN_ON(!((itype >= 0) && (itype < SYSMMU_FAULT_UNKNOWN))))
-			itype = SYSMMU_FAULT_UNKNOWN;
-		else
-			addr = __raw_readl(
-				data->sfrbases[i] + fault_reg_offset[itype]);
-	}
-
-	if (data->domain)
-		ret = report_iommu_fault(data->domain, data->dev,
-				addr, itype);
-
-	if ((ret == -ENOSYS) && data->fault_handler) {
-		unsigned long base = data->pgtable;
-		if (itype != SYSMMU_FAULT_UNKNOWN)
-			base = __raw_readl(
-					data->sfrbases[i] + REG_PT_BASE_ADDR);
-		ret = data->fault_handler(itype, base, addr);
-	}
-
-	if (!ret && (itype != SYSMMU_FAULT_UNKNOWN))
-		__raw_writel(1 << itype, data->sfrbases[i] + REG_INT_CLEAR);
-	else
-		dev_dbg(data->sysmmu, "(%s) %s is not handled.\n",
-				data->dbgname, sysmmu_fault_name[itype]);
-
-	if (itype != SYSMMU_FAULT_UNKNOWN)
-		sysmmu_unblock(data->sfrbases[i]);
-
-	read_unlock(&data->lock);
-
-	return IRQ_HANDLED;
-}
-
-static bool __exynos_sysmmu_disable(struct sysmmu_drvdata *data)
-{
-	unsigned long flags;
-	bool disabled = false;
-	int i;
-
-	write_lock_irqsave(&data->lock, flags);
-
-	if (!set_sysmmu_inactive(data))
-		goto finish;
-
-	for (i = 0; i < data->nsfrs; i++)
-		__raw_writel(CTRL_DISABLE, data->sfrbases[i] + REG_MMU_CTRL);
-
-	if (data->clk[1])
-		clk_disable(data->clk[1]);
-	if (data->clk[0])
-		clk_disable(data->clk[0]);
-
-	disabled = true;
-	data->pgtable = 0;
-	data->domain = NULL;
-finish:
-	write_unlock_irqrestore(&data->lock, flags);
-
-	if (disabled)
-		dev_dbg(data->sysmmu, "(%s) Disabled\n", data->dbgname);
-	else
-		dev_dbg(data->sysmmu, "(%s) %d times left to be disabled\n",
-					data->dbgname, data->activations);
-
-	return disabled;
-}
-
-/* __exynos_sysmmu_enable: Enables System MMU
- *
- * returns -error if an error occurred and System MMU is not enabled,
- * 0 if the System MMU has been just enabled and 1 if System MMU was already
- * enabled before.
- */
-static int __exynos_sysmmu_enable(struct sysmmu_drvdata *data,
-			unsigned long pgtable, struct iommu_domain *domain)
-{
-	int i, ret = 0;
-	unsigned long flags;
-
-	write_lock_irqsave(&data->lock, flags);
-
-	if (!set_sysmmu_active(data)) {
-		if (WARN_ON(pgtable != data->pgtable)) {
-			ret = -EBUSY;
-			set_sysmmu_inactive(data);
-		} else {
-			ret = 1;
-		}
-
-		dev_dbg(data->sysmmu, "(%s) Already enabled\n", data->dbgname);
-		goto finish;
-	}
-
-	if (data->clk[0])
-		clk_enable(data->clk[0]);
-	if (data->clk[1])
-		clk_enable(data->clk[1]);
-
-	data->pgtable = pgtable;
-
-	for (i = 0; i < data->nsfrs; i++) {
-		__sysmmu_set_ptbase(data->sfrbases[i], pgtable);
-
-		if ((readl(data->sfrbases[i] + REG_MMU_VERSION) >> 28) == 3) {
-			/* System MMU version is 3.x */
-			__raw_writel((1 << 12) | (2 << 28),
-					data->sfrbases[i] + REG_MMU_CFG);
-			__sysmmu_set_prefbuf(data->sfrbases[i], 0, -1, 0);
-			__sysmmu_set_prefbuf(data->sfrbases[i], 0, -1, 1);
-		}
-
-		__raw_writel(CTRL_ENABLE, data->sfrbases[i] + REG_MMU_CTRL);
-	}
-
-	data->domain = domain;
-
-	dev_dbg(data->sysmmu, "(%s) Enabled\n", data->dbgname);
-finish:
-	write_unlock_irqrestore(&data->lock, flags);
-
-	return ret;
-}
-
-int exynos_sysmmu_enable(struct device *dev, unsigned long pgtable)
-{
-	struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
-	int ret;
-
-	BUG_ON(!memblock_is_memory(pgtable));
-
-	ret = pm_runtime_get_sync(data->sysmmu);
-	if (ret < 0) {
-		dev_dbg(data->sysmmu, "(%s) Failed to enable\n", data->dbgname);
-		return ret;
-	}
-
-	ret = __exynos_sysmmu_enable(data, pgtable, NULL);
-	if (WARN_ON(ret < 0)) {
-		pm_runtime_put(data->sysmmu);
-		dev_err(data->sysmmu,
-			"(%s) Already enabled with page table %#lx\n",
-			data->dbgname, data->pgtable);
-	} else {
-		data->dev = dev;
-	}
-
-	return ret;
-}
-
-static bool exynos_sysmmu_disable(struct device *dev)
-{
-	struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
-	bool disabled;
-
-	disabled = __exynos_sysmmu_disable(data);
-	pm_runtime_put(data->sysmmu);
-
-	return disabled;
-}
-
-static void sysmmu_tlb_invalidate_entry(struct device *dev, unsigned long iova)
-{
-	unsigned long flags;
-	struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
-
-	read_lock_irqsave(&data->lock, flags);
-
-	if (is_sysmmu_active(data)) {
-		int i;
-		for (i = 0; i < data->nsfrs; i++) {
-			if (sysmmu_block(data->sfrbases[i])) {
-				__sysmmu_tlb_invalidate_entry(
-						data->sfrbases[i], iova);
-				sysmmu_unblock(data->sfrbases[i]);
-			}
-		}
-	} else {
-		dev_dbg(data->sysmmu,
-			"(%s) Disabled. Skipping invalidating TLB.\n",
-			data->dbgname);
-	}
-
-	read_unlock_irqrestore(&data->lock, flags);
-}
-
-void exynos_sysmmu_tlb_invalidate(struct device *dev)
-{
-	unsigned long flags;
-	struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
-
-	read_lock_irqsave(&data->lock, flags);
-
-	if (is_sysmmu_active(data)) {
-		int i;
-		for (i = 0; i < data->nsfrs; i++) {
-			if (sysmmu_block(data->sfrbases[i])) {
-				__sysmmu_tlb_invalidate(data->sfrbases[i]);
-				sysmmu_unblock(data->sfrbases[i]);
-			}
-		}
-	} else {
-		dev_dbg(data->sysmmu,
-			"(%s) Disabled. Skipping invalidating TLB.\n",
-			data->dbgname);
-	}
-
-	read_unlock_irqrestore(&data->lock, flags);
-}
-
-static int exynos_sysmmu_probe(struct platform_device *pdev)
-{
-	int i, ret;
-	struct device *dev;
-	struct sysmmu_drvdata *data;
-
-	dev = &pdev->dev;
-
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data) {
-		dev_dbg(dev, "Not enough memory\n");
-		ret = -ENOMEM;
-		goto err_alloc;
-	}
-
-	ret = dev_set_drvdata(dev, data);
-	if (ret) {
-		dev_dbg(dev, "Unabled to initialize driver data\n");
-		goto err_init;
-	}
-
-	data->nsfrs = pdev->num_resources / 2;
-	data->sfrbases = kmalloc(sizeof(*data->sfrbases) * data->nsfrs,
-								GFP_KERNEL);
-	if (data->sfrbases == NULL) {
-		dev_dbg(dev, "Not enough memory\n");
-		ret = -ENOMEM;
-		goto err_init;
-	}
-
-	for (i = 0; i < data->nsfrs; i++) {
-		struct resource *res;
-		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
-		if (!res) {
-			dev_dbg(dev, "Unable to find IOMEM region\n");
-			ret = -ENOENT;
-			goto err_res;
-		}
-
-		data->sfrbases[i] = ioremap(res->start, resource_size(res));
-		if (!data->sfrbases[i]) {
-			dev_dbg(dev, "Unable to map IOMEM @ PA:%#x\n",
-							res->start);
-			ret = -ENOENT;
-			goto err_res;
-		}
-	}
-
-	for (i = 0; i < data->nsfrs; i++) {
-		ret = platform_get_irq(pdev, i);
-		if (ret <= 0) {
-			dev_dbg(dev, "Unable to find IRQ resource\n");
-			goto err_irq;
-		}
-
-		ret = request_irq(ret, exynos_sysmmu_irq, 0,
-					dev_name(dev), data);
-		if (ret) {
-			dev_dbg(dev, "Unabled to register interrupt handler\n");
-			goto err_irq;
-		}
-	}
-
-	if (dev_get_platdata(dev)) {
-		char *deli, *beg;
-		struct sysmmu_platform_data *platdata = dev_get_platdata(dev);
-
-		beg = platdata->clockname;
-
-		for (deli = beg; (*deli != '\0') && (*deli != ','); deli++)
-			/* NOTHING */;
-
-		if (*deli == '\0')
-			deli = NULL;
-		else
-			*deli = '\0';
-
-		data->clk[0] = clk_get(dev, beg);
-		if (IS_ERR(data->clk[0])) {
-			data->clk[0] = NULL;
-			dev_dbg(dev, "No clock descriptor registered\n");
-		}
-
-		if (data->clk[0] && deli) {
-			*deli = ',';
-			data->clk[1] = clk_get(dev, deli + 1);
-			if (IS_ERR(data->clk[1]))
-				data->clk[1] = NULL;
-		}
-
-		data->dbgname = platdata->dbgname;
-	}
-
-	data->sysmmu = dev;
-	rwlock_init(&data->lock);
-	INIT_LIST_HEAD(&data->node);
-
-	__set_fault_handler(data, &default_fault_handler);
-
-	if (dev->parent)
-		pm_runtime_enable(dev);
-
-	dev_dbg(dev, "(%s) Initialized\n", data->dbgname);
-	return 0;
-err_irq:
-	while (i-- > 0) {
-		int irq;
-
-		irq = platform_get_irq(pdev, i);
-		free_irq(irq, data);
-	}
-err_res:
-	while (data->nsfrs-- > 0)
-		iounmap(data->sfrbases[data->nsfrs]);
-	kfree(data->sfrbases);
-err_init:
-	kfree(data);
-err_alloc:
-	dev_err(dev, "Failed to initialize\n");
-	return ret;
-}
-
-static struct platform_driver exynos_sysmmu_driver = {
-	.probe		= exynos_sysmmu_probe,
-	.driver		= {
-		.owner		= THIS_MODULE,
-		.name		= "exynos-sysmmu",
-	}
-};
-
-static inline void pgtable_flush(void *vastart, void *vaend)
-{
-	dmac_flush_range(vastart, vaend);
-	outer_flush_range(virt_to_phys(vastart),
-				virt_to_phys(vaend));
-}
-
-static int exynos_iommu_domain_init(struct iommu_domain *domain)
-{
-	struct exynos_iommu_domain *priv;
-
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	priv->pgtable = (unsigned long *)__get_free_pages(
-						GFP_KERNEL | __GFP_ZERO, 2);
-	if (!priv->pgtable)
-		goto err_pgtable;
-
-	priv->lv2entcnt = (short *)__get_free_pages(
-						GFP_KERNEL | __GFP_ZERO, 1);
-	if (!priv->lv2entcnt)
-		goto err_counter;
-
-	pgtable_flush(priv->pgtable, priv->pgtable + NUM_LV1ENTRIES);
-
-	spin_lock_init(&priv->lock);
-	spin_lock_init(&priv->pgtablelock);
-	INIT_LIST_HEAD(&priv->clients);
-
-	domain->geometry.aperture_start = 0;
-	domain->geometry.aperture_end   = ~0UL;
-	domain->geometry.force_aperture = true;
-
-	domain->priv = priv;
-	return 0;
-
-err_counter:
-	free_pages((unsigned long)priv->pgtable, 2);
-err_pgtable:
-	kfree(priv);
-	return -ENOMEM;
-}
-
-static void exynos_iommu_domain_destroy(struct iommu_domain *domain)
-{
-	struct exynos_iommu_domain *priv = domain->priv;
-	struct sysmmu_drvdata *data;
-	unsigned long flags;
-	int i;
-
-	WARN_ON(!list_empty(&priv->clients));
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	list_for_each_entry(data, &priv->clients, node) {
-		while (!exynos_sysmmu_disable(data->dev))
-			; /* until System MMU is actually disabled */
-	}
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	for (i = 0; i < NUM_LV1ENTRIES; i++)
-		if (lv1ent_page(priv->pgtable + i))
-			kfree(__va(lv2table_base(priv->pgtable + i)));
-
-	free_pages((unsigned long)priv->pgtable, 2);
-	free_pages((unsigned long)priv->lv2entcnt, 1);
-	kfree(domain->priv);
-	domain->priv = NULL;
-}
-
-static int exynos_iommu_attach_device(struct iommu_domain *domain,
-				   struct device *dev)
-{
-	struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
-	struct exynos_iommu_domain *priv = domain->priv;
-	unsigned long flags;
-	int ret;
-
-	ret = pm_runtime_get_sync(data->sysmmu);
-	if (ret < 0)
-		return ret;
-
-	ret = 0;
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	ret = __exynos_sysmmu_enable(data, __pa(priv->pgtable), domain);
-
-	if (ret == 0) {
-		/* 'data->node' must not be appeared in priv->clients */
-		BUG_ON(!list_empty(&data->node));
-		data->dev = dev;
-		list_add_tail(&data->node, &priv->clients);
-	}
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	if (ret < 0) {
-		dev_err(dev, "%s: Failed to attach IOMMU with pgtable %#lx\n",
-				__func__, __pa(priv->pgtable));
-		pm_runtime_put(data->sysmmu);
-	} else if (ret > 0) {
-		dev_dbg(dev, "%s: IOMMU with pgtable 0x%lx already attached\n",
-					__func__, __pa(priv->pgtable));
-	} else {
-		dev_dbg(dev, "%s: Attached new IOMMU with pgtable 0x%lx\n",
-					__func__, __pa(priv->pgtable));
-	}
-
-	return ret;
-}
-
-static void exynos_iommu_detach_device(struct iommu_domain *domain,
-				    struct device *dev)
-{
-	struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
-	struct exynos_iommu_domain *priv = domain->priv;
-	struct list_head *pos;
-	unsigned long flags;
-	bool found = false;
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	list_for_each(pos, &priv->clients) {
-		if (list_entry(pos, struct sysmmu_drvdata, node) == data) {
-			found = true;
-			break;
-		}
-	}
-
-	if (!found)
-		goto finish;
-
-	if (__exynos_sysmmu_disable(data)) {
-		dev_dbg(dev, "%s: Detached IOMMU with pgtable %#lx\n",
-					__func__, __pa(priv->pgtable));
-		list_del_init(&data->node);
-
-	} else {
-		dev_dbg(dev, "%s: Detaching IOMMU with pgtable %#lx delayed",
-					__func__, __pa(priv->pgtable));
-	}
-
-finish:
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	if (found)
-		pm_runtime_put(data->sysmmu);
-}
-
-static unsigned long *alloc_lv2entry(unsigned long *sent, unsigned long iova,
-					short *pgcounter)
-{
-	if (lv1ent_fault(sent)) {
-		unsigned long *pent;
-
-		pent = kzalloc(LV2TABLE_SIZE, GFP_ATOMIC);
-		BUG_ON((unsigned long)pent & (LV2TABLE_SIZE - 1));
-		if (!pent)
-			return NULL;
-
-		*sent = mk_lv1ent_page(__pa(pent));
-		*pgcounter = NUM_LV2ENTRIES;
-		pgtable_flush(pent, pent + NUM_LV2ENTRIES);
-		pgtable_flush(sent, sent + 1);
-	}
-
-	return page_entry(sent, iova);
-}
-
-static int lv1set_section(unsigned long *sent, phys_addr_t paddr, short *pgcnt)
-{
-	if (lv1ent_section(sent))
-		return -EADDRINUSE;
-
-	if (lv1ent_page(sent)) {
-		if (*pgcnt != NUM_LV2ENTRIES)
-			return -EADDRINUSE;
-
-		kfree(page_entry(sent, 0));
-
-		*pgcnt = 0;
-	}
-
-	*sent = mk_lv1ent_sect(paddr);
-
-	pgtable_flush(sent, sent + 1);
-
-	return 0;
-}
-
-static int lv2set_page(unsigned long *pent, phys_addr_t paddr, size_t size,
-								short *pgcnt)
-{
-	if (size == SPAGE_SIZE) {
-		if (!lv2ent_fault(pent))
-			return -EADDRINUSE;
-
-		*pent = mk_lv2ent_spage(paddr);
-		pgtable_flush(pent, pent + 1);
-		*pgcnt -= 1;
-	} else { /* size == LPAGE_SIZE */
-		int i;
-		for (i = 0; i < SPAGES_PER_LPAGE; i++, pent++) {
-			if (!lv2ent_fault(pent)) {
-				memset(pent, 0, sizeof(*pent) * i);
-				return -EADDRINUSE;
-			}
-
-			*pent = mk_lv2ent_lpage(paddr);
-		}
-		pgtable_flush(pent - SPAGES_PER_LPAGE, pent);
-		*pgcnt -= SPAGES_PER_LPAGE;
-	}
-
-	return 0;
-}
-
-static int exynos_iommu_map(struct iommu_domain *domain, unsigned long iova,
-			 phys_addr_t paddr, size_t size, int prot)
-{
-	struct exynos_iommu_domain *priv = domain->priv;
-	unsigned long *entry;
-	unsigned long flags;
-	int ret = -ENOMEM;
-
-	BUG_ON(priv->pgtable == NULL);
-
-	spin_lock_irqsave(&priv->pgtablelock, flags);
-
-	entry = section_entry(priv->pgtable, iova);
-
-	if (size == SECT_SIZE) {
-		ret = lv1set_section(entry, paddr,
-					&priv->lv2entcnt[lv1ent_offset(iova)]);
-	} else {
-		unsigned long *pent;
-
-		pent = alloc_lv2entry(entry, iova,
-					&priv->lv2entcnt[lv1ent_offset(iova)]);
-
-		if (!pent)
-			ret = -ENOMEM;
-		else
-			ret = lv2set_page(pent, paddr, size,
-					&priv->lv2entcnt[lv1ent_offset(iova)]);
-	}
-
-	if (ret) {
-		pr_debug("%s: Failed to map iova 0x%lx/0x%x bytes\n",
-							__func__, iova, size);
-	}
-
-	spin_unlock_irqrestore(&priv->pgtablelock, flags);
-
-	return ret;
-}
-
-static size_t exynos_iommu_unmap(struct iommu_domain *domain,
-					       unsigned long iova, size_t size)
-{
-	struct exynos_iommu_domain *priv = domain->priv;
-	struct sysmmu_drvdata *data;
-	unsigned long flags;
-	unsigned long *ent;
-
-	BUG_ON(priv->pgtable == NULL);
-
-	spin_lock_irqsave(&priv->pgtablelock, flags);
-
-	ent = section_entry(priv->pgtable, iova);
-
-	if (lv1ent_section(ent)) {
-		BUG_ON(size < SECT_SIZE);
-
-		*ent = 0;
-		pgtable_flush(ent, ent + 1);
-		size = SECT_SIZE;
-		goto done;
-	}
-
-	if (unlikely(lv1ent_fault(ent))) {
-		if (size > SECT_SIZE)
-			size = SECT_SIZE;
-		goto done;
-	}
-
-	/* lv1ent_page(sent) == true here */
-
-	ent = page_entry(ent, iova);
-
-	if (unlikely(lv2ent_fault(ent))) {
-		size = SPAGE_SIZE;
-		goto done;
-	}
-
-	if (lv2ent_small(ent)) {
-		*ent = 0;
-		size = SPAGE_SIZE;
-		priv->lv2entcnt[lv1ent_offset(iova)] += 1;
-		goto done;
-	}
-
-	/* lv1ent_large(ent) == true here */
-	BUG_ON(size < LPAGE_SIZE);
-
-	memset(ent, 0, sizeof(*ent) * SPAGES_PER_LPAGE);
-
-	size = LPAGE_SIZE;
-	priv->lv2entcnt[lv1ent_offset(iova)] += SPAGES_PER_LPAGE;
-done:
-	spin_unlock_irqrestore(&priv->pgtablelock, flags);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	list_for_each_entry(data, &priv->clients, node)
-		sysmmu_tlb_invalidate_entry(data->dev, iova);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-
-	return size;
-}
-
-static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *domain,
-					  dma_addr_t iova)
-{
-	struct exynos_iommu_domain *priv = domain->priv;
-	unsigned long *entry;
-	unsigned long flags;
-	phys_addr_t phys = 0;
-
-	spin_lock_irqsave(&priv->pgtablelock, flags);
-
-	entry = section_entry(priv->pgtable, iova);
-
-	if (lv1ent_section(entry)) {
-		phys = section_phys(entry) + section_offs(iova);
-	} else if (lv1ent_page(entry)) {
-		entry = page_entry(entry, iova);
-
-		if (lv2ent_large(entry))
-			phys = lpage_phys(entry) + lpage_offs(iova);
-		else if (lv2ent_small(entry))
-			phys = spage_phys(entry) + spage_offs(iova);
-	}
-
-	spin_unlock_irqrestore(&priv->pgtablelock, flags);
-
-	return phys;
-}
-
-static struct iommu_ops exynos_iommu_ops = {
-	.domain_init = &exynos_iommu_domain_init,
-	.domain_destroy = &exynos_iommu_domain_destroy,
-	.attach_dev = &exynos_iommu_attach_device,
-	.detach_dev = &exynos_iommu_detach_device,
-	.map = &exynos_iommu_map,
-	.unmap = &exynos_iommu_unmap,
-	.iova_to_phys = &exynos_iommu_iova_to_phys,
-	.pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE,
-};
-
-static int __init exynos_iommu_init(void)
-{
-	int ret;
-
-	ret = platform_driver_register(&exynos_sysmmu_driver);
-
-	if (ret == 0)
-		bus_set_iommu(&platform_bus_type, &exynos_iommu_ops);
-
-	return ret;
-}
-subsys_initcall(exynos_iommu_init);
-- 
1.7.10.4

^ permalink raw reply related

* [PATCHv5] omap3: Add basic support for 720MHz part
From: Laurent Pinchart @ 2014-02-06 19:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1527616.Ycr1jOn0QT@avalon>

Hi all,

On Friday 22 June 2012 11:33:51 Laurent Pinchart wrote:
> On Thursday 10 February 2011 08:45:00 Kevin Hilman wrote:
> > Sanjeev Premi <premi@ti.com> writes:
> > > This patch adds support for speed enhanced variant of OMAP35x
> > > processors. These parts allow ARM and IVA running at 720MHz
> > > and 520MHz respectively.
> > > 
> > > These parts can be detected at runtime by reading contents of
> > > PRODID.SKUID[3:0] at 0x4830A20C [1].
> > > 
> > > This patch specifically does following:
> > >  * Add new OPP to omap34xx_opp_def_list[] - disabled by default.
> > >  * Detect devices capable of running at new OPP.
> > >  * Enable new OPP only if device supports it.
> > >  * Check for presence of IVA before attempting to enable the
> > >  
> > >    corresponding OPP.
> > >   
> > >   [1] http://focus.ti.com/lit/ug/spruff1d/spruff1d.pdf
> > > 
> > > It appears from discussions (on this patch) that a variant of
> > > OMAP3430 supports this OPP but lacks runtime detection. This
> > > 
> > > OPP can be enabled for these device by either:
> > >  1) Setting the bit corresponding to OMAP3_HAS_720MHZ
> > >  
> > >     in 'omap3_features'. (Refer changes to id.c)
> > >  
> > >  2) Removing check for omap3_has_720mhz() before enabling
> > >  
> > >     the OPP. (Refer changes to opp3xxx_data.c)
> > >  
> > >  3) Calling opp_enable() for 720MHz/VDD1 and 520MHz/VDD2 in
> > >  
> > >     the board file. (Refer changes to opp3xxx_data.c).
> > >     This should, ideally, be done before omap3_opp_init() is
> > >     called during device_initcall().
> > > 
> > > CAUTION: This should be done for identified parts only.
> > > 
> > >          Else, the device could be damaged permanently.
> > > 
> > > Signed-off-by: Sanjeev Premi <premi@ti.com>
> > > Reviewed-by: G, Manjunath Kondaiah <manjugk@ti.com>
> > 
> > Acked-by: Kevin Hilman <khilman@ti.com>
> 
> This patch seems to never have made it upstream. Is there a reason for that
> ?

Ping ?

-- 
Regards,

Laurent Pinchart

^ permalink raw reply

* [PATCH v2 12/12] ARM: exynos: Allow wake-up using GIC interrupts
From: Tomasz Figa @ 2014-02-06 19:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391713977-22300-1-git-send-email-t.figa@samsung.com>

This patch restores the ability to receive wake-up events from internal
GIC interrupts, e.g. RTC tick or alarm interrupts.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/mach-exynos/pm.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c
index ada1c83..15af0ce 100644
--- a/arch/arm/mach-exynos/pm.c
+++ b/arch/arm/mach-exynos/pm.c
@@ -17,6 +17,7 @@
 #include <linux/suspend.h>
 #include <linux/syscore_ops.h>
 #include <linux/io.h>
+#include <linux/irqchip/arm-gic.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 
@@ -35,6 +36,16 @@
 #include "common.h"
 #include "regs-pmu.h"
 
+/**
+ * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping
+ * @hwirq: Hardware IRQ signal of the GIC
+ * @mask: Mask in PMU wake-up mask register
+ */
+struct exynos_wkup_irq {
+	unsigned int hwirq;
+	u32 mask;
+};
+
 static struct sleep_save exynos5_sys_save[] = {
 	SAVE_ITEM(EXYNOS5_SYS_I2C_CFG),
 };
@@ -48,8 +59,47 @@ static struct sleep_save exynos_core_save[] = {
 	SAVE_ITEM(S5P_SROM_BC3),
 };
 
+/*
+ * GIC wake-up support
+ */
+
 static u32 exynos_irqwake_intmask = 0xffffffff;
 
+static const struct exynos_wkup_irq exynos4_wkup_irq[] = {
+	{ 76, BIT(1) }, /* RTC alarm */
+	{ 77, BIT(2) }, /* RTC tick */
+	{ /* sentinel */ },
+};
+
+static const struct exynos_wkup_irq exynos5250_wkup_irq[] = {
+	{ 75, BIT(1) }, /* RTC alarm */
+	{ 76, BIT(2) }, /* RTC tick */
+	{ /* sentinel */ },
+};
+
+static int exynos_irq_set_wake(struct irq_data *data, unsigned int state)
+{
+	const struct exynos_wkup_irq *wkup_irq;
+
+	if (soc_is_exynos5250())
+		wkup_irq = exynos5250_wkup_irq;
+	else
+		wkup_irq = exynos4_wkup_irq;
+
+	while (wkup_irq->mask) {
+		if (wkup_irq->hwirq == data->hwirq) {
+			if (!state)
+				exynos_irqwake_intmask |= wkup_irq->mask;
+			else
+				exynos_irqwake_intmask &= ~wkup_irq->mask;
+			return 0;
+		}
+		++wkup_irq;
+	}
+
+	return -ENOENT;
+}
+
 /* For Cortex-A9 Diagnostic and Power control register */
 static unsigned int save_arm_register[2];
 
@@ -258,6 +308,9 @@ void __init exynos_pm_init(void)
 {
 	u32 tmp;
 
+	/* Platform-specific GIC callback */
+	gic_arch_extn.irq_set_wake = exynos_irq_set_wake;
+
 	/* All wakeup disable */
 	tmp = __raw_readl(S5P_WAKEUP_MASK);
 	tmp |= ((0xFF << 8) | (0x1F << 1));
-- 
1.8.5.2

^ permalink raw reply related

* [PATCH v2 11/12] ARM: EXYNOS: Stop using legacy Samsung PM code
From: Tomasz Figa @ 2014-02-06 19:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391713977-22300-1-git-send-email-t.figa@samsung.com>

Since Exynos SoCs does not follow most of the semantics of older SoCs
when configuring the system to enter sleep, there is no reason to rely
on the legacy Samsung PM core anymore.

This patch adds local Exynos suspend ops and removes all the code left
unnecessary. As a side effect, suspend support on Exynos becomes
multiplatform-friendly.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/mach-exynos/Kconfig                |  8 ---
 arch/arm/mach-exynos/Makefile               |  2 +-
 arch/arm/mach-exynos/common.h               |  8 +++
 arch/arm/mach-exynos/include/mach/pm-core.h | 75 -------------------------
 arch/arm/mach-exynos/pm.c                   | 79 ++++++++++++++++++++++++---
 arch/arm/mach-exynos/regs-pmu.h             |  2 +
 arch/arm/mach-exynos/sleep.S                | 85 +++++++++++++++++++++++++++++
 arch/arm/plat-samsung/s5p-sleep.S           | 45 ---------------
 8 files changed, 167 insertions(+), 137 deletions(-)
 delete mode 100644 arch/arm/mach-exynos/include/mach/pm-core.h
 create mode 100644 arch/arm/mach-exynos/sleep.S

diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 0964d97..fcd78c2 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -49,8 +49,6 @@ config CPU_EXYNOS4210
 	select ARCH_HAS_BANDGAP
 	select ARM_CPU_SUSPEND if PM_SLEEP
 	select PINCTRL_EXYNOS
-	select S5P_PM if PM_SLEEP
-	select S5P_SLEEP if PM_SLEEP
 	select SAMSUNG_DMADEV
 	help
 	  Enable EXYNOS4210 CPU support
@@ -61,8 +59,6 @@ config SOC_EXYNOS4212
 	depends on ARCH_EXYNOS4
 	select ARCH_HAS_BANDGAP
 	select PINCTRL_EXYNOS
-	select S5P_PM if PM_SLEEP
-	select S5P_SLEEP if PM_SLEEP
 	select SAMSUNG_DMADEV
 	help
 	  Enable EXYNOS4212 SoC support
@@ -84,8 +80,6 @@ config SOC_EXYNOS5250
 	select ARCH_HAS_BANDGAP
 	select PINCTRL_EXYNOS
 	select PM_GENERIC_DOMAINS if PM_RUNTIME
-	select S5P_PM if PM_SLEEP
-	select S5P_SLEEP if PM_SLEEP
 	select S5P_DEV_MFC
 	select SAMSUNG_DMADEV
 	help
@@ -96,8 +90,6 @@ config SOC_EXYNOS5420
 	default y
 	depends on ARCH_EXYNOS5
 	select PM_GENERIC_DOMAINS if PM_RUNTIME
-	select S5P_PM if PM_SLEEP
-	select S5P_SLEEP if PM_SLEEP
 	help
 	  Enable EXYNOS5420 SoC support
 
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
index 8930b66..58fe9e6 100644
--- a/arch/arm/mach-exynos/Makefile
+++ b/arch/arm/mach-exynos/Makefile
@@ -14,7 +14,7 @@ obj-				:=
 
 obj-$(CONFIG_ARCH_EXYNOS)	+= common.o
 
-obj-$(CONFIG_S5P_PM)		+= pm.o
+obj-$(CONFIG_PM_SLEEP)		+= pm.o sleep.o
 obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o
 obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o
 
diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index 82e08fb..aba6a2a 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -27,12 +27,20 @@ void exynos_init_late(void);
 
 void exynos_firmware_init(void);
 
+#ifdef CONFIG_PINCTRL_EXYNOS
+extern u32 exynos_get_eint_wake_mask(void);
+#else
+static inline u32 exynos_get_eint_wake_mask(void) { return 0xffffffff; }
+#endif
+
 #ifdef CONFIG_PM_SLEEP
 extern void __init exynos_pm_init(void);
 #else
 static inline void exynos_pm_init(void) {}
 #endif
 
+extern void exynos_cpu_resume(void);
+
 extern struct smp_operations exynos_smp_ops;
 
 extern void exynos_cpu_die(unsigned int cpu);
diff --git a/arch/arm/mach-exynos/include/mach/pm-core.h b/arch/arm/mach-exynos/include/mach/pm-core.h
deleted file mode 100644
index dc0697c..0000000
--- a/arch/arm/mach-exynos/include/mach/pm-core.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* linux/arch/arm/mach-exynos4/include/mach/pm-core.h
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * Based on arch/arm/mach-s3c2410/include/mach/pm-core.h,
- * Copyright 2008 Simtec Electronics
- *      Ben Dooks <ben@simtec.co.uk>
- *      http://armlinux.simtec.co.uk/
- *
- * EXYNOS4210 - PM core support for arch/arm/plat-s5p/pm.c
- *
- * 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 __ASM_ARCH_PM_CORE_H
-#define __ASM_ARCH_PM_CORE_H __FILE__
-
-#include <linux/of.h>
-#include <mach/map.h>
-
-#define S5P_EINT_WAKEUP_MASK			(S5P_VA_PMU + 0x0604)
-#define S5P_WAKEUP_MASK				(S5P_VA_PMU + 0x0608)
-
-#ifdef CONFIG_PINCTRL_EXYNOS
-extern u32 exynos_get_eint_wake_mask(void);
-#else
-static inline u32 exynos_get_eint_wake_mask(void) { return 0xffffffff; }
-#endif
-
-static inline void s3c_pm_debug_init_uart(void)
-{
-	/* nothing here yet */
-}
-
-static inline void s3c_pm_arch_prepare_irqs(void)
-{
-	__raw_writel(exynos_get_eint_wake_mask(), S5P_EINT_WAKEUP_MASK);
-	__raw_writel(s3c_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK);
-}
-
-static inline void s3c_pm_arch_stop_clocks(void)
-{
-	/* nothing here yet */
-}
-
-static inline void s3c_pm_arch_show_resume_irqs(void)
-{
-	/* nothing here yet */
-}
-
-static inline void s3c_pm_arch_update_uart(void __iomem *regs,
-					   struct pm_uart_save *save)
-{
-	/* nothing here yet */
-}
-
-static inline void s3c_pm_restored_gpios(void)
-{
-	/* nothing here yet */
-}
-
-static inline void samsung_pm_saved_gpios(void)
-{
-	/* nothing here yet */
-}
-
-/* Compatibility definitions to make plat-samsung/pm.c compile */
-#define IRQ_EINT_BIT(x)		1
-#define s3c_irqwake_intallow	0
-#define s3c_irqwake_eintallow	0
-
-#endif /* __ASM_ARCH_PM_CORE_H */
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c
index 596ed13..ada1c83 100644
--- a/arch/arm/mach-exynos/pm.c
+++ b/arch/arm/mach-exynos/pm.c
@@ -23,14 +23,14 @@
 #include <asm/cacheflush.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/smp_scu.h>
+#include <asm/suspend.h>
 
 #include <plat/cpu.h>
-#include <plat/pm.h>
+#include <plat/pm-common.h>
 #include <plat/pll.h>
 #include <plat/regs-srom.h>
 
 #include <mach/map.h>
-#include <mach/pm-core.h>
 
 #include "common.h"
 #include "regs-pmu.h"
@@ -48,6 +48,7 @@ static struct sleep_save exynos_core_save[] = {
 	SAVE_ITEM(S5P_SROM_BC3),
 };
 
+static u32 exynos_irqwake_intmask = 0xffffffff;
 
 /* For Cortex-A9 Diagnostic and Power control register */
 static unsigned int save_arm_register[2];
@@ -72,6 +73,10 @@ static void exynos_pm_prepare(void)
 {
 	unsigned int tmp;
 
+	/* Set wake-up mask registers */
+	__raw_writel(exynos_get_eint_wake_mask(), S5P_EINT_WAKEUP_MASK);
+	__raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK);
+
 	s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save));
 
 	if (soc_is_exynos5250()) {
@@ -89,7 +94,7 @@ static void exynos_pm_prepare(void)
 
 	/* ensure@least INFORM0 has the resume address */
 
-	__raw_writel(virt_to_phys(s3c_cpu_resume), S5P_INFORM0);
+	__raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0);
 }
 
 static int exynos_pm_suspend(void)
@@ -187,14 +192,71 @@ static struct syscore_ops exynos_pm_syscore_ops = {
 	.resume		= exynos_pm_resume,
 };
 
-void __init exynos_pm_init(void)
+/*
+ * Suspend Ops
+ */
+
+static int exynos_suspend_enter(suspend_state_t state)
 {
-	u32 tmp;
+	int ret;
+
+	s3c_pm_debug_init();
+
+	S3C_PMDBG("%s: suspending the system...\n", __func__);
+
+	S3C_PMDBG("%s: wakeup masks: %08x,%08x\n", __func__,
+			exynos_irqwake_intmask, exynos_get_eint_wake_mask());
 
-	pm_cpu_prep = exynos_pm_prepare;
-	pm_cpu_sleep = exynos_cpu_suspend;
+	if (exynos_irqwake_intmask == -1U
+	    && exynos_get_eint_wake_mask() == -1U) {
+		pr_err("%s: No wake-up sources!\n", __func__);
+		pr_err("%s: Aborting sleep\n", __func__);
+		return -EINVAL;
+	}
+
+	s3c_pm_save_uarts();
+	exynos_pm_prepare();
+	flush_cache_all();
+	s3c_pm_check_store();
+
+	ret = cpu_suspend(0, exynos_cpu_suspend);
+	if (ret)
+		return ret;
+
+	s3c_pm_restore_uarts();
 
-	s3c_pm_init();
+	S3C_PMDBG("%s: wakeup stat: %08x\n", __func__,
+			__raw_readl(S5P_WAKEUP_STAT));
+
+	s3c_pm_check_restore();
+
+	S3C_PMDBG("%s: resuming the system...\n", __func__);
+
+	return 0;
+}
+
+static int exynos_suspend_prepare(void)
+{
+	s3c_pm_check_prepare();
+
+	return 0;
+}
+
+static void exynos_suspend_finish(void)
+{
+	s3c_pm_check_cleanup();
+}
+
+static const struct platform_suspend_ops exynos_suspend_ops = {
+	.enter		= exynos_suspend_enter,
+	.prepare	= exynos_suspend_prepare,
+	.finish		= exynos_suspend_finish,
+	.valid		= suspend_valid_only_mem,
+};
+
+void __init exynos_pm_init(void)
+{
+	u32 tmp;
 
 	/* All wakeup disable */
 	tmp = __raw_readl(S5P_WAKEUP_MASK);
@@ -202,4 +264,5 @@ void __init exynos_pm_init(void)
 	__raw_writel(tmp, S5P_WAKEUP_MASK);
 
 	register_syscore_ops(&exynos_pm_syscore_ops);
+	suspend_set_ops(&exynos_suspend_ops);
 }
diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h
index 7c029ce..2c15a8f 100644
--- a/arch/arm/mach-exynos/regs-pmu.h
+++ b/arch/arm/mach-exynos/regs-pmu.h
@@ -31,6 +31,8 @@
 #define EXYNOS5440_SWRESET			S5P_PMUREG(0x00C4)
 
 #define S5P_WAKEUP_STAT				S5P_PMUREG(0x0600)
+#define S5P_EINT_WAKEUP_MASK			S5P_PMUREG(0x0604)
+#define S5P_WAKEUP_MASK				S5P_PMUREG(0x0608)
 
 #define S5P_INFORM0				S5P_PMUREG(0x0800)
 #define S5P_INFORM1				S5P_PMUREG(0x0804)
diff --git a/arch/arm/mach-exynos/sleep.S b/arch/arm/mach-exynos/sleep.S
new file mode 100644
index 0000000..a2613e9
--- /dev/null
+++ b/arch/arm/mach-exynos/sleep.S
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Exynos low-level resume code
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#define CPU_MASK	0xff0ffff0
+#define CPU_CORTEX_A9	0x410fc090
+
+	/*
+	 * The following code is located into the .data section. This is to
+	 * allow l2x0_regs_phys to be accessed with a relative load while we
+	 * can't rely on any MMU translation. We could have put l2x0_regs_phys
+	 * in the .text section as well, but some setups might insist on it to
+	 * be truly read-only. (Reference from: arch/arm/kernel/sleep.S)
+	 */
+	.data
+	.align
+
+	/*
+	 * sleep magic, to allow the bootloader to check for an valid
+	 * image to resume to. Must be the first word before the
+	 * exynos_cpu_resume entry.
+	 */
+
+	.word	0x2bedf00d
+
+	/*
+	 * exynos_cpu_resume
+	 *
+	 * resume code entry for bootloader to call
+	 */
+
+ENTRY(exynos_cpu_resume)
+#ifdef CONFIG_CACHE_L2X0
+	mrc	p15, 0, r0, c0, c0, 0
+	ldr	r1, =CPU_MASK
+	and	r0, r0, r1
+	ldr	r1, =CPU_CORTEX_A9
+	cmp	r0, r1
+	bne	skip_l2_resume
+	adr	r0, l2x0_regs_phys
+	ldr	r0, [r0]
+	cmp	r0, #0
+	beq	skip_l2_resume
+	ldr	r1, [r0, #L2X0_R_PHY_BASE]
+	ldr	r2, [r1, #L2X0_CTRL]
+	tst	r2, #0x1
+	bne	skip_l2_resume
+	ldr	r2, [r0, #L2X0_R_AUX_CTRL]
+	str	r2, [r1, #L2X0_AUX_CTRL]
+	ldr	r2, [r0, #L2X0_R_TAG_LATENCY]
+	str	r2, [r1, #L2X0_TAG_LATENCY_CTRL]
+	ldr	r2, [r0, #L2X0_R_DATA_LATENCY]
+	str	r2, [r1, #L2X0_DATA_LATENCY_CTRL]
+	ldr	r2, [r0, #L2X0_R_PREFETCH_CTRL]
+	str	r2, [r1, #L2X0_PREFETCH_CTRL]
+	ldr	r2, [r0, #L2X0_R_PWR_CTRL]
+	str	r2, [r1, #L2X0_POWER_CTRL]
+	mov	r2, #1
+	str	r2, [r1, #L2X0_CTRL]
+skip_l2_resume:
+#endif
+	b	cpu_resume
+ENDPROC(exynos_cpu_resume)
+#ifdef CONFIG_CACHE_L2X0
+	.globl l2x0_regs_phys
+l2x0_regs_phys:
+	.long	0
+#endif
diff --git a/arch/arm/plat-samsung/s5p-sleep.S b/arch/arm/plat-samsung/s5p-sleep.S
index 20764bd..c500165 100644
--- a/arch/arm/plat-samsung/s5p-sleep.S
+++ b/arch/arm/plat-samsung/s5p-sleep.S
@@ -23,18 +23,7 @@
 
 #include <linux/linkage.h>
 #include <asm/asm-offsets.h>
-#include <asm/hardware/cache-l2x0.h>
 
-#define CPU_MASK	0xff0ffff0
-#define CPU_CORTEX_A9	0x410fc090
-
-/*
- *	 The following code is located into the .data section. This is to
- *	 allow l2x0_regs_phys to be accessed with a relative load while we
- *	 can't rely on any MMU translation. We could have put l2x0_regs_phys
- *	 in the .text section as well, but some setups might insist on it to
- *	 be truly read-only. (Reference from: arch/arm/kernel/sleep.S)
- */
 	.data
 	.align
 
@@ -53,39 +42,5 @@
 	 */
 
 ENTRY(s3c_cpu_resume)
-#ifdef CONFIG_CACHE_L2X0
-	mrc	p15, 0, r0, c0, c0, 0
-	ldr	r1, =CPU_MASK
-	and	r0, r0, r1
-	ldr	r1, =CPU_CORTEX_A9
-	cmp	r0, r1
-	bne	skip_l2_resume
-	adr	r0, l2x0_regs_phys
-	ldr	r0, [r0]
-	cmp	r0, #0
-	beq	skip_l2_resume
-	ldr	r1, [r0, #L2X0_R_PHY_BASE]
-	ldr	r2, [r1, #L2X0_CTRL]
-	tst	r2, #0x1
-	bne	skip_l2_resume
-	ldr	r2, [r0, #L2X0_R_AUX_CTRL]
-	str	r2, [r1, #L2X0_AUX_CTRL]
-	ldr	r2, [r0, #L2X0_R_TAG_LATENCY]
-	str	r2, [r1, #L2X0_TAG_LATENCY_CTRL]
-	ldr	r2, [r0, #L2X0_R_DATA_LATENCY]
-	str	r2, [r1, #L2X0_DATA_LATENCY_CTRL]
-	ldr	r2, [r0, #L2X0_R_PREFETCH_CTRL]
-	str	r2, [r1, #L2X0_PREFETCH_CTRL]
-	ldr	r2, [r0, #L2X0_R_PWR_CTRL]
-	str	r2, [r1, #L2X0_POWER_CTRL]
-	mov	r2, #1
-	str	r2, [r1, #L2X0_CTRL]
-skip_l2_resume:
-#endif
 	b	cpu_resume
 ENDPROC(s3c_cpu_resume)
-#ifdef CONFIG_CACHE_L2X0
-	.globl l2x0_regs_phys
-l2x0_regs_phys:
-	.long	0
-#endif
-- 
1.8.5.2

^ permalink raw reply related

* [PATCH v2 10/12] ARM: EXYNOS: Remove PM initcalls and useless indirection
From: Tomasz Figa @ 2014-02-06 19:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391713977-22300-1-git-send-email-t.figa@samsung.com>

This patch simplifies Exynos PM initialization and makes it
multiplatform friendly by replacing initcalls used originally to invoke
all the initialization code with explicit function calls.

In addition, an useless subsys_interface is removed, as all its .add_dev
callback did was setting two function pointers.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/mach-exynos/common.c |  1 +
 arch/arm/mach-exynos/common.h |  6 ++++++
 arch/arm/mach-exynos/pm.c     | 50 +++++++++++--------------------------------
 3 files changed, 19 insertions(+), 38 deletions(-)

diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c
index f18be40..fb4e7dc 100644
--- a/arch/arm/mach-exynos/common.c
+++ b/arch/arm/mach-exynos/common.c
@@ -315,6 +315,7 @@ void __init exynos_init_late(void)
 		return;
 
 	pm_genpd_poweroff_unused();
+	exynos_pm_init();
 }
 
 static int __init exynos_fdt_map_chipid(unsigned long node, const char *uname,
diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index f76967b..82e08fb 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -27,6 +27,12 @@ void exynos_init_late(void);
 
 void exynos_firmware_init(void);
 
+#ifdef CONFIG_PM_SLEEP
+extern void __init exynos_pm_init(void);
+#else
+static inline void exynos_pm_init(void) {}
+#endif
+
 extern struct smp_operations exynos_smp_ops;
 
 extern void exynos_cpu_die(unsigned int cpu);
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c
index ba18214..596ed13 100644
--- a/arch/arm/mach-exynos/pm.c
+++ b/arch/arm/mach-exynos/pm.c
@@ -92,39 +92,6 @@ static void exynos_pm_prepare(void)
 	__raw_writel(virt_to_phys(s3c_cpu_resume), S5P_INFORM0);
 }
 
-static int exynos_pm_add(struct device *dev, struct subsys_interface *sif)
-{
-	pm_cpu_prep = exynos_pm_prepare;
-	pm_cpu_sleep = exynos_cpu_suspend;
-
-	return 0;
-}
-
-static struct subsys_interface exynos_pm_interface = {
-	.name		= "exynos_pm",
-	.subsys		= &exynos_subsys,
-	.add_dev	= exynos_pm_add,
-};
-
-static __init int exynos_pm_drvinit(void)
-{
-	unsigned int tmp;
-
-	if (soc_is_exynos5440())
-		return 0;
-
-	s3c_pm_init();
-
-	/* All wakeup disable */
-
-	tmp = __raw_readl(S5P_WAKEUP_MASK);
-	tmp |= ((0xFF << 8) | (0x1F << 1));
-	__raw_writel(tmp, S5P_WAKEUP_MASK);
-
-	return subsys_interface_register(&exynos_pm_interface);
-}
-arch_initcall(exynos_pm_drvinit);
-
 static int exynos_pm_suspend(void)
 {
 	unsigned long tmp;
@@ -220,12 +187,19 @@ static struct syscore_ops exynos_pm_syscore_ops = {
 	.resume		= exynos_pm_resume,
 };
 
-static __init int exynos_pm_syscore_init(void)
+void __init exynos_pm_init(void)
 {
-	if (soc_is_exynos5440())
-		return 0;
+	u32 tmp;
+
+	pm_cpu_prep = exynos_pm_prepare;
+	pm_cpu_sleep = exynos_cpu_suspend;
+
+	s3c_pm_init();
+
+	/* All wakeup disable */
+	tmp = __raw_readl(S5P_WAKEUP_MASK);
+	tmp |= ((0xFF << 8) | (0x1F << 1));
+	__raw_writel(tmp, S5P_WAKEUP_MASK);
 
 	register_syscore_ops(&exynos_pm_syscore_ops);
-	return 0;
 }
-arch_initcall(exynos_pm_syscore_init);
-- 
1.8.5.2

^ permalink raw reply related

* [PATCH v2 09/12] ARM: EXYNOS: Kconfig: Fix abuse of CONFIG_PM
From: Tomasz Figa @ 2014-02-06 19:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391713977-22300-1-git-send-email-t.figa@samsung.com>

CONFIG_PM means that at least one of CONFIG_PM_SLEEP and
CONFIG_PM_RUNTIME is enabled, while multiple entries in
mach-exynos/Kconfig abused it to enable sleep- and runtime-specific
functionality.

This patch fixes this abuse by replacing dependencies on CONFIG_PM with
appropriate dependencies on either CONFIG_PM_SLEEP or CONFIG_PM_RUNTIME,
whichever is appropriate.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/mach-exynos/Kconfig | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 4c414af..0964d97 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -24,7 +24,7 @@ config ARCH_EXYNOS4
 	select HAVE_SMP
 	select MIGHT_HAVE_CACHE_L2X0
 	select PINCTRL
-	select PM_GENERIC_DOMAINS if PM
+	select PM_GENERIC_DOMAINS if PM_RUNTIME
 	select S5P_DEV_MFC
 	help
 	  Samsung EXYNOS4 SoCs based systems
@@ -47,10 +47,10 @@ config CPU_EXYNOS4210
 	default y
 	depends on ARCH_EXYNOS4
 	select ARCH_HAS_BANDGAP
-	select ARM_CPU_SUSPEND if PM
+	select ARM_CPU_SUSPEND if PM_SLEEP
 	select PINCTRL_EXYNOS
-	select S5P_PM if PM
-	select S5P_SLEEP if PM
+	select S5P_PM if PM_SLEEP
+	select S5P_SLEEP if PM_SLEEP
 	select SAMSUNG_DMADEV
 	help
 	  Enable EXYNOS4210 CPU support
@@ -61,8 +61,8 @@ config SOC_EXYNOS4212
 	depends on ARCH_EXYNOS4
 	select ARCH_HAS_BANDGAP
 	select PINCTRL_EXYNOS
-	select S5P_PM if PM
-	select S5P_SLEEP if PM
+	select S5P_PM if PM_SLEEP
+	select S5P_SLEEP if PM_SLEEP
 	select SAMSUNG_DMADEV
 	help
 	  Enable EXYNOS4212 SoC support
@@ -83,9 +83,9 @@ config SOC_EXYNOS5250
 	depends on ARCH_EXYNOS5
 	select ARCH_HAS_BANDGAP
 	select PINCTRL_EXYNOS
-	select PM_GENERIC_DOMAINS if PM
-	select S5P_PM if PM
-	select S5P_SLEEP if PM
+	select PM_GENERIC_DOMAINS if PM_RUNTIME
+	select S5P_PM if PM_SLEEP
+	select S5P_SLEEP if PM_SLEEP
 	select S5P_DEV_MFC
 	select SAMSUNG_DMADEV
 	help
@@ -95,9 +95,9 @@ config SOC_EXYNOS5420
 	bool "SAMSUNG EXYNOS5420"
 	default y
 	depends on ARCH_EXYNOS5
-	select PM_GENERIC_DOMAINS if PM
-	select S5P_PM if PM
-	select S5P_SLEEP if PM
+	select PM_GENERIC_DOMAINS if PM_RUNTIME
+	select S5P_PM if PM_SLEEP
+	select S5P_SLEEP if PM_SLEEP
 	help
 	  Enable EXYNOS5420 SoC support
 
-- 
1.8.5.2

^ permalink raw reply related

* [PATCH v2 08/12] ARM: SAMSUNG: pm: Move s3c_pm_check_* prototypes to plat/pm-common.h
From: Tomasz Figa @ 2014-02-06 19:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391713977-22300-1-git-send-email-t.figa@samsung.com>

To allow using Samsung PM memory check helpers on platforms that do not
use the legacy Samsung PM core, this patch moves prototypes of relevant
functions to plat/pm-common.h header.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/plat-samsung/include/plat/pm-common.h | 14 ++++++++++++++
 arch/arm/plat-samsung/include/plat/pm.h        | 14 --------------
 arch/arm/plat-samsung/pm-check.c               |  2 +-
 3 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/arch/arm/plat-samsung/include/plat/pm-common.h b/arch/arm/plat-samsung/include/plat/pm-common.h
index 741723e..8705f9e 100644
--- a/arch/arm/plat-samsung/include/plat/pm-common.h
+++ b/arch/arm/plat-samsung/include/plat/pm-common.h
@@ -93,4 +93,18 @@ static inline void s3c_pm_save_uarts(void) { }
 static inline void s3c_pm_restore_uarts(void) { }
 #endif
 
+/* suspend memory checking */
+
+#ifdef CONFIG_SAMSUNG_PM_CHECK
+extern void s3c_pm_check_prepare(void);
+extern void s3c_pm_check_restore(void);
+extern void s3c_pm_check_cleanup(void);
+extern void s3c_pm_check_store(void);
+#else
+#define s3c_pm_check_prepare() do { } while (0)
+#define s3c_pm_check_restore() do { } while (0)
+#define s3c_pm_check_cleanup() do { } while (0)
+#define s3c_pm_check_store()   do { } while (0)
+#endif
+
 #endif
diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h
index 4099e8d..e17d871 100644
--- a/arch/arm/plat-samsung/include/plat/pm.h
+++ b/arch/arm/plat-samsung/include/plat/pm.h
@@ -80,20 +80,6 @@ extern void s3c_pm_debug_smdkled(u32 set, u32 clear);
 static inline void s3c_pm_debug_smdkled(u32 set, u32 clear) { }
 #endif /* CONFIG_S3C_PM_DEBUG_LED_SMDK */
 
-/* suspend memory checking */
-
-#ifdef CONFIG_SAMSUNG_PM_CHECK
-extern void s3c_pm_check_prepare(void);
-extern void s3c_pm_check_restore(void);
-extern void s3c_pm_check_cleanup(void);
-extern void s3c_pm_check_store(void);
-#else
-#define s3c_pm_check_prepare() do { } while(0)
-#define s3c_pm_check_restore() do { } while(0)
-#define s3c_pm_check_cleanup() do { } while(0)
-#define s3c_pm_check_store()   do { } while(0)
-#endif
-
 /**
  * s3c_pm_configure_extint() - ensure pins are correctly set for IRQ
  *
diff --git a/arch/arm/plat-samsung/pm-check.c b/arch/arm/plat-samsung/pm-check.c
index 3cbd626..04aff2c 100644
--- a/arch/arm/plat-samsung/pm-check.c
+++ b/arch/arm/plat-samsung/pm-check.c
@@ -19,7 +19,7 @@
 #include <linux/ioport.h>
 #include <linux/slab.h>
 
-#include <plat/pm.h>
+#include <plat/pm-common.h>
 
 #if CONFIG_SAMSUNG_PM_CHECK_CHUNKSIZE < 1
 #error CONFIG_SAMSUNG_PM_CHECK_CHUNKSIZE must be a positive non-zero value
-- 
1.8.5.2

^ permalink raw reply related

* [PATCH v2 07/12] ARM: SAMSUNG: Move common save/restore helpers to separate file
From: Tomasz Figa @ 2014-02-06 19:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391713977-22300-1-git-send-email-t.figa@samsung.com>

To separate legacy PM code from generic helpers, this patch moves the
generic register save/restore helpers to a new file called pm-common.c
that is compiled always when CONFIG_PM_SLEEP is enabled, to allow
platforms that do not want to use the legacy PM code use the generic
helpers.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/plat-samsung/Makefile                 |  1 +
 arch/arm/plat-samsung/include/plat/pm-common.h | 26 +++++++++
 arch/arm/plat-samsung/include/plat/pm.h        | 25 ---------
 arch/arm/plat-samsung/pm-common.c              | 75 ++++++++++++++++++++++++++
 arch/arm/plat-samsung/pm.c                     | 56 -------------------
 5 files changed, 102 insertions(+), 81 deletions(-)
 create mode 100644 arch/arm/plat-samsung/pm-common.c

diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index ba30a16..25c826e 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_SAMSUNG_DMADEV)	+= dma-ops.o
 
 # PM support
 
+obj-$(CONFIG_PM_SLEEP)		+= pm-common.o
 obj-$(CONFIG_SAMSUNG_PM)	+= pm.o
 obj-$(CONFIG_SAMSUNG_PM_GPIO)	+= pm-gpio.o
 obj-$(CONFIG_SAMSUNG_PM_CHECK)	+= pm-check.o
diff --git a/arch/arm/plat-samsung/include/plat/pm-common.h b/arch/arm/plat-samsung/include/plat/pm-common.h
index f72974a..741723e 100644
--- a/arch/arm/plat-samsung/include/plat/pm-common.h
+++ b/arch/arm/plat-samsung/include/plat/pm-common.h
@@ -13,6 +13,32 @@
 #ifndef __PLAT_SAMSUNG_PM_COMMON_H
 #define __PLAT_SAMSUNG_PM_COMMON_H __FILE__
 
+#include <linux/irq.h>
+
+/* sleep save info */
+
+/**
+ * struct sleep_save - save information for shared peripherals.
+ * @reg: Pointer to the register to save.
+ * @val: Holder for the value saved from reg.
+ *
+ * This describes a list of registers which is used by the pm core and
+ * other subsystem to save and restore register values over suspend.
+ */
+struct sleep_save {
+	void __iomem	*reg;
+	unsigned long	val;
+};
+
+#define SAVE_ITEM(x) \
+	{ .reg = (x) }
+
+/* helper functions to save/restore lists of registers. */
+
+extern void s3c_pm_do_save(struct sleep_save *ptr, int count);
+extern void s3c_pm_do_restore(const struct sleep_save *ptr, int count);
+extern void s3c_pm_do_restore_core(const struct sleep_save *ptr, int count);
+
 /* PM debug functions */
 
 /**
diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h
index 2e04396..4099e8d 100644
--- a/arch/arm/plat-samsung/include/plat/pm.h
+++ b/arch/arm/plat-samsung/include/plat/pm.h
@@ -15,7 +15,6 @@
  * management
 */
 
-#include <linux/irq.h>
 #include <plat/pm-common.h>
 
 struct device;
@@ -59,30 +58,6 @@ extern unsigned long s3c_pm_flags;
 
 extern int s3c2410_cpu_suspend(unsigned long);
 
-/* sleep save info */
-
-/**
- * struct sleep_save - save information for shared peripherals.
- * @reg: Pointer to the register to save.
- * @val: Holder for the value saved from reg.
- *
- * This describes a list of registers which is used by the pm core and
- * other subsystem to save and restore register values over suspend.
- */
-struct sleep_save {
-	void __iomem	*reg;
-	unsigned long	val;
-};
-
-#define SAVE_ITEM(x) \
-	{ .reg = (x) }
-
-/* helper functions to save/restore lists of registers. */
-
-extern void s3c_pm_do_save(struct sleep_save *ptr, int count);
-extern void s3c_pm_do_restore(const struct sleep_save *ptr, int count);
-extern void s3c_pm_do_restore_core(const struct sleep_save *ptr, int count);
-
 #ifdef CONFIG_SAMSUNG_PM
 extern int s3c_irq_wake(struct irq_data *data, unsigned int state);
 extern int s3c_irqext_wake(struct irq_data *data, unsigned int state);
diff --git a/arch/arm/plat-samsung/pm-common.c b/arch/arm/plat-samsung/pm-common.c
new file mode 100644
index 0000000..515cd53
--- /dev/null
+++ b/arch/arm/plat-samsung/pm-common.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *	Tomasz Figa <t.figa@samsung.com>
+ * Copyright (C) 2008 Openmoko, Inc.
+ * Copyright (C) 2004-2008 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *	http://armlinux.simtec.co.uk/
+ *
+ * Samsung common power management helper functions.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+
+#include <plat/pm-common.h>
+
+/* helper functions to save and restore register state */
+
+/**
+ * s3c_pm_do_save() - save a set of registers for restoration on resume.
+ * @ptr: Pointer to an array of registers.
+ * @count: Size of the ptr array.
+ *
+ * Run through the list of registers given, saving their contents in the
+ * array for later restoration when we wakeup.
+ */
+void s3c_pm_do_save(struct sleep_save *ptr, int count)
+{
+	for (; count > 0; count--, ptr++) {
+		ptr->val = __raw_readl(ptr->reg);
+		S3C_PMDBG("saved %p value %08lx\n", ptr->reg, ptr->val);
+	}
+}
+
+/**
+ * s3c_pm_do_restore() - restore register values from the save list.
+ * @ptr: Pointer to an array of registers.
+ * @count: Size of the ptr array.
+ *
+ * Restore the register values saved from s3c_pm_do_save().
+ *
+ * Note, we do not use S3C_PMDBG() in here, as the system may not have
+ * restore the UARTs state yet
+*/
+
+void s3c_pm_do_restore(const struct sleep_save *ptr, int count)
+{
+	for (; count > 0; count--, ptr++) {
+		pr_debug("restore %p (restore %08lx, was %08x)\n",
+				ptr->reg, ptr->val, __raw_readl(ptr->reg));
+
+		__raw_writel(ptr->val, ptr->reg);
+	}
+}
+
+/**
+ * s3c_pm_do_restore_core() - early restore register values from save list.
+ *
+ * This is similar to s3c_pm_do_restore() except we try and minimise the
+ * side effects of the function in case registers that hardware might need
+ * to work has been restored.
+ *
+ * WARNING: Do not put any debug in here that may effect memory or use
+ * peripherals, as things may be changing!
+*/
+
+void s3c_pm_do_restore_core(const struct sleep_save *ptr, int count)
+{
+	for (; count > 0; count--, ptr++)
+		__raw_writel(ptr->val, ptr->reg);
+}
diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c
index a655192..0e7ac5f 100644
--- a/arch/arm/plat-samsung/pm.c
+++ b/arch/arm/plat-samsung/pm.c
@@ -65,62 +65,6 @@ int s3c_irqext_wake(struct irq_data *data, unsigned int state)
 	return 0;
 }
 
-/* helper functions to save and restore register state */
-
-/**
- * s3c_pm_do_save() - save a set of registers for restoration on resume.
- * @ptr: Pointer to an array of registers.
- * @count: Size of the ptr array.
- *
- * Run through the list of registers given, saving their contents in the
- * array for later restoration when we wakeup.
- */
-void s3c_pm_do_save(struct sleep_save *ptr, int count)
-{
-	for (; count > 0; count--, ptr++) {
-		ptr->val = __raw_readl(ptr->reg);
-		S3C_PMDBG("saved %p value %08lx\n", ptr->reg, ptr->val);
-	}
-}
-
-/**
- * s3c_pm_do_restore() - restore register values from the save list.
- * @ptr: Pointer to an array of registers.
- * @count: Size of the ptr array.
- *
- * Restore the register values saved from s3c_pm_do_save().
- *
- * Note, we do not use S3C_PMDBG() in here, as the system may not have
- * restore the UARTs state yet
-*/
-
-void s3c_pm_do_restore(const struct sleep_save *ptr, int count)
-{
-	for (; count > 0; count--, ptr++) {
-		printk(KERN_DEBUG "restore %p (restore %08lx, was %08x)\n",
-		       ptr->reg, ptr->val, __raw_readl(ptr->reg));
-
-		__raw_writel(ptr->val, ptr->reg);
-	}
-}
-
-/**
- * s3c_pm_do_restore_core() - early restore register values from save list.
- *
- * This is similar to s3c_pm_do_restore() except we try and minimise the
- * side effects of the function in case registers that hardware might need
- * to work has been restored.
- *
- * WARNING: Do not put any debug in here that may effect memory or use
- * peripherals, as things may be changing!
-*/
-
-void s3c_pm_do_restore_core(const struct sleep_save *ptr, int count)
-{
-	for (; count > 0; count--, ptr++)
-		__raw_writel(ptr->val, ptr->reg);
-}
-
 /* s3c2410_pm_show_resume_irqs
  *
  * print any IRQs asserted at resume time (ie, we woke from)
-- 
1.8.5.2

^ permalink raw reply related

* [PATCH v2 06/12] ARM: SAMSUNG: pm: Move Samsung PM debug code into separate file
From: Tomasz Figa @ 2014-02-06 19:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391713977-22300-1-git-send-email-t.figa@samsung.com>

Not all Samsung SoC platforms are going to use the legacy Samsung PM
code enabled by CONFIG_SAMSUNG_PM_DEBUG. To allow using Samsung PM debug
helpers on such platforms, related code is moved to separate file and
a plat/pm-common.h header is added to separate legacy and generic code.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/plat-samsung/Makefile                 |  1 +
 arch/arm/plat-samsung/include/plat/pm-common.h | 70 ++++++++++++++++++
 arch/arm/plat-samsung/include/plat/pm.h        | 39 +---------
 arch/arm/plat-samsung/pm-debug.c               | 98 ++++++++++++++++++++++++++
 arch/arm/plat-samsung/pm.c                     | 85 ----------------------
 5 files changed, 170 insertions(+), 123 deletions(-)
 create mode 100644 arch/arm/plat-samsung/include/plat/pm-common.h
 create mode 100644 arch/arm/plat-samsung/pm-debug.c

diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index 9267d29..ba30a16 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_SAMSUNG_DMADEV)	+= dma-ops.o
 obj-$(CONFIG_SAMSUNG_PM)	+= pm.o
 obj-$(CONFIG_SAMSUNG_PM_GPIO)	+= pm-gpio.o
 obj-$(CONFIG_SAMSUNG_PM_CHECK)	+= pm-check.o
+obj-$(CONFIG_SAMSUNG_PM_DEBUG)	+= pm-debug.o
 
 obj-$(CONFIG_SAMSUNG_WAKEMASK)	+= wakeup-mask.o
 obj-$(CONFIG_SAMSUNG_WDT_RESET)	+= watchdog-reset.o
diff --git a/arch/arm/plat-samsung/include/plat/pm-common.h b/arch/arm/plat-samsung/include/plat/pm-common.h
new file mode 100644
index 0000000..f72974a
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/pm-common.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *	Tomasz Figa <t.figa@samsung.com>
+ * Copyright (c) 2004 Simtec Electronics
+ *	http://armlinux.simtec.co.uk/
+ *	Written by Ben Dooks, <ben@simtec.co.uk>
+ *
+ * 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 __PLAT_SAMSUNG_PM_COMMON_H
+#define __PLAT_SAMSUNG_PM_COMMON_H __FILE__
+
+/* PM debug functions */
+
+/**
+ * struct pm_uart_save - save block for core UART
+ * @ulcon: Save value for S3C2410_ULCON
+ * @ucon: Save value for S3C2410_UCON
+ * @ufcon: Save value for S3C2410_UFCON
+ * @umcon: Save value for S3C2410_UMCON
+ * @ubrdiv: Save value for S3C2410_UBRDIV
+ *
+ * Save block for UART registers to be held over sleep and restored if they
+ * are needed (say by debug).
+*/
+struct pm_uart_save {
+	u32	ulcon;
+	u32	ucon;
+	u32	ufcon;
+	u32	umcon;
+	u32	ubrdiv;
+	u32	udivslot;
+};
+
+#ifdef CONFIG_SAMSUNG_PM_DEBUG
+/**
+ * s3c_pm_dbg() - low level debug function for use in suspend/resume.
+ * @msg: The message to print.
+ *
+ * This function is used mainly to debug the resume process before the system
+ * can rely on printk/console output. It uses the low-level debugging output
+ * routine printascii() to do its work.
+ */
+extern void s3c_pm_dbg(const char *msg, ...);
+
+/**
+ * s3c_pm_debug_init() - suspend/resume low level debug initialization.
+ * @base: Virtual base of UART to use for suspend/resume debugging.
+ *
+ * This function needs to be called before S3C_PMDBG() can be used, to set up
+ * UART port base address and configuration.
+ */
+extern void s3c_pm_debug_init(void);
+
+#define S3C_PMDBG(fmt...) s3c_pm_dbg(fmt)
+
+extern void s3c_pm_save_uarts(void);
+extern void s3c_pm_restore_uarts(void);
+#else
+#define S3C_PMDBG(fmt...) pr_debug(fmt)
+#define s3c_pm_debug_init() do { } while (0)
+
+static inline void s3c_pm_save_uarts(void) { }
+static inline void s3c_pm_restore_uarts(void) { }
+#endif
+
+#endif
diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h
index 21758c6..2e04396 100644
--- a/arch/arm/plat-samsung/include/plat/pm.h
+++ b/arch/arm/plat-samsung/include/plat/pm.h
@@ -16,6 +16,7 @@
 */
 
 #include <linux/irq.h>
+#include <plat/pm-common.h>
 
 struct device;
 
@@ -76,26 +77,6 @@ struct sleep_save {
 #define SAVE_ITEM(x) \
 	{ .reg = (x) }
 
-/**
- * struct pm_uart_save - save block for core UART
- * @ulcon: Save value for S3C2410_ULCON
- * @ucon: Save value for S3C2410_UCON
- * @ufcon: Save value for S3C2410_UFCON
- * @umcon: Save value for S3C2410_UMCON
- * @ubrdiv: Save value for S3C2410_UBRDIV
- *
- * Save block for UART registers to be held over sleep and restored if they
- * are needed (say by debug).
-*/
-struct pm_uart_save {
-	u32	ulcon;
-	u32	ucon;
-	u32	ufcon;
-	u32	umcon;
-	u32	ubrdiv;
-	u32	udivslot;
-};
-
 /* helper functions to save/restore lists of registers. */
 
 extern void s3c_pm_do_save(struct sleep_save *ptr, int count);
@@ -112,24 +93,6 @@ extern void s3c_cpu_resume(void);
 #define s3c_cpu_resume NULL
 #endif
 
-/* PM debug functions */
-
-#ifdef CONFIG_SAMSUNG_PM_DEBUG
-/**
- * s3c_pm_dbg() - low level debug function for use in suspend/resume.
- * @msg: The message to print.
- *
- * This function is used mainly to debug the resume process before the system
- * can rely on printk/console output. It uses the low-level debugging output
- * routine printascii() to do its work.
- */
-extern void s3c_pm_dbg(const char *msg, ...);
-
-#define S3C_PMDBG(fmt...) s3c_pm_dbg(fmt)
-#else
-#define S3C_PMDBG(fmt...) printk(KERN_DEBUG fmt)
-#endif
-
 #ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK
 /**
  * s3c_pm_debug_smdkled() - Debug PM suspend/resume via SMDK Board LEDs
diff --git a/arch/arm/plat-samsung/pm-debug.c b/arch/arm/plat-samsung/pm-debug.c
new file mode 100644
index 0000000..9f979b2
--- /dev/null
+++ b/arch/arm/plat-samsung/pm-debug.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *	Tomasz Figa <t.figa@samsung.com>
+ * Copyright (C) 2008 Openmoko, Inc.
+ * Copyright (C) 2004-2008 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *	http://armlinux.simtec.co.uk/
+ *
+ * Samsung common power management (suspend to RAM) debug support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/serial_core.h>
+#include <linux/io.h>
+
+#include <asm/mach/map.h>
+
+#include <plat/cpu.h>
+#include <plat/pm-common.h>
+#include <plat/regs-serial.h>
+
+#ifdef CONFIG_SAMSUNG_ATAGS
+#include <mach/pm-core.h>
+#else
+static inline void s3c_pm_debug_init_uart(void) {}
+static inline void s3c_pm_arch_update_uart(void __iomem *regs,
+					   struct pm_uart_save *save) {}
+#endif
+
+static struct pm_uart_save uart_save;
+
+extern void printascii(const char *);
+
+void s3c_pm_dbg(const char *fmt, ...)
+{
+	va_list va;
+	char buff[256];
+
+	va_start(va, fmt);
+	vsnprintf(buff, sizeof(buff), fmt, va);
+	va_end(va);
+
+	printascii(buff);
+}
+
+void s3c_pm_debug_init(void)
+{
+	/* restart uart clocks so we can use them to output */
+	s3c_pm_debug_init_uart();
+}
+
+static inline void __iomem *s3c_pm_uart_base(void)
+{
+	unsigned long paddr;
+	unsigned long vaddr;
+
+	debug_ll_addr(&paddr, &vaddr);
+
+	return (void __iomem *)vaddr;
+}
+
+void s3c_pm_save_uarts(void)
+{
+	void __iomem *regs = s3c_pm_uart_base();
+	struct pm_uart_save *save = &uart_save;
+
+	save->ulcon = __raw_readl(regs + S3C2410_ULCON);
+	save->ucon = __raw_readl(regs + S3C2410_UCON);
+	save->ufcon = __raw_readl(regs + S3C2410_UFCON);
+	save->umcon = __raw_readl(regs + S3C2410_UMCON);
+	save->ubrdiv = __raw_readl(regs + S3C2410_UBRDIV);
+
+	if (!soc_is_s3c2410())
+		save->udivslot = __raw_readl(regs + S3C2443_DIVSLOT);
+
+	S3C_PMDBG("UART[%p]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n",
+		  regs, save->ulcon, save->ucon, save->ufcon, save->ubrdiv);
+}
+
+void s3c_pm_restore_uarts(void)
+{
+	void __iomem *regs = s3c_pm_uart_base();
+	struct pm_uart_save *save = &uart_save;
+
+	s3c_pm_arch_update_uart(regs, save);
+
+	__raw_writel(save->ulcon, regs + S3C2410_ULCON);
+	__raw_writel(save->ucon,  regs + S3C2410_UCON);
+	__raw_writel(save->ufcon, regs + S3C2410_UFCON);
+	__raw_writel(save->umcon, regs + S3C2410_UMCON);
+	__raw_writel(save->ubrdiv, regs + S3C2410_UBRDIV);
+
+	if (!soc_is_s3c2410())
+		__raw_writel(save->udivslot, regs + S3C2443_DIVSLOT);
+}
diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c
index 7c1d4385..a655192 100644
--- a/arch/arm/plat-samsung/pm.c
+++ b/arch/arm/plat-samsung/pm.c
@@ -17,16 +17,11 @@
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/of.h>
-#include <linux/serial_core.h>
 #include <linux/io.h>
 
 #include <asm/cacheflush.h>
-#include <asm/mach/map.h>
 #include <asm/suspend.h>
 
-#include <plat/cpu.h>
-#include <plat/regs-serial.h>
-
 #ifdef CONFIG_SAMSUNG_ATAGS
 #include <mach/hardware.h>
 #include <mach/map.h>
@@ -46,86 +41,6 @@
 
 unsigned long s3c_pm_flags;
 
-/* Debug code:
- *
- * This code supports debug output to the low level UARTs for use on
- * resume before the console layer is available.
-*/
-
-#ifdef CONFIG_SAMSUNG_PM_DEBUG
-extern void printascii(const char *);
-
-void s3c_pm_dbg(const char *fmt, ...)
-{
-	va_list va;
-	char buff[256];
-
-	va_start(va, fmt);
-	vsnprintf(buff, sizeof(buff), fmt, va);
-	va_end(va);
-
-	printascii(buff);
-}
-
-static inline void s3c_pm_debug_init(void)
-{
-	/* restart uart clocks so we can use them to output */
-	s3c_pm_debug_init_uart();
-}
-
-static struct pm_uart_save uart_save;
-
-static inline void __iomem *s3c_pm_uart_base(void)
-{
-	unsigned long paddr;
-	unsigned long vaddr;
-
-	debug_ll_addr(&paddr, &vaddr);
-
-	return (void __iomem *)vaddr;
-}
-
-static void s3c_pm_save_uarts(void)
-{
-	void __iomem *regs = s3c_pm_uart_base();
-	struct pm_uart_save *save = &uart_save;
-
-	save->ulcon = __raw_readl(regs + S3C2410_ULCON);
-	save->ucon = __raw_readl(regs + S3C2410_UCON);
-	save->ufcon = __raw_readl(regs + S3C2410_UFCON);
-	save->umcon = __raw_readl(regs + S3C2410_UMCON);
-	save->ubrdiv = __raw_readl(regs + S3C2410_UBRDIV);
-
-	if (!soc_is_s3c2410())
-		save->udivslot = __raw_readl(regs + S3C2443_DIVSLOT);
-
-	S3C_PMDBG("UART[%p]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n",
-		  regs, save->ulcon, save->ucon, save->ufcon, save->ubrdiv);
-}
-
-static void s3c_pm_restore_uarts(void)
-{
-	void __iomem *regs = s3c_pm_uart_base();
-	struct pm_uart_save *save = &uart_save;
-
-	s3c_pm_arch_update_uart(regs, save);
-
-	__raw_writel(save->ulcon, regs + S3C2410_ULCON);
-	__raw_writel(save->ucon,  regs + S3C2410_UCON);
-	__raw_writel(save->ufcon, regs + S3C2410_UFCON);
-	__raw_writel(save->umcon, regs + S3C2410_UMCON);
-	__raw_writel(save->ubrdiv, regs + S3C2410_UBRDIV);
-
-	if (!soc_is_s3c2410())
-		__raw_writel(save->udivslot, regs + S3C2443_DIVSLOT);
-}
-#else
-#define s3c_pm_debug_init() do { } while (0)
-
-static void s3c_pm_save_uarts(void) { }
-static void s3c_pm_restore_uarts(void) { }
-#endif
-
 /* The IRQ ext-int code goes here, it is too small to currently bother
  * with its own file. */
 
-- 
1.8.5.2

^ permalink raw reply related

* [PATCH v2 05/12] ARM: SAMSUNG: pm: Consolidate PM debug functions
From: Tomasz Figa @ 2014-02-06 19:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391713977-22300-1-git-send-email-t.figa@samsung.com>

This patch removes one-line functions that was used just to pass
constant arguments to lower level functions. After previous patches the
need for those constants has been eliminated, so the main functions can
be called directly.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/plat-samsung/pm.c | 20 ++++++--------------
 1 file changed, 6 insertions(+), 14 deletions(-)

diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c
index 53b3d67..7c1d4385 100644
--- a/arch/arm/plat-samsung/pm.c
+++ b/arch/arm/plat-samsung/pm.c
@@ -85,9 +85,10 @@ static inline void __iomem *s3c_pm_uart_base(void)
 	return (void __iomem *)vaddr;
 }
 
-static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save)
+static void s3c_pm_save_uarts(void)
 {
 	void __iomem *regs = s3c_pm_uart_base();
+	struct pm_uart_save *save = &uart_save;
 
 	save->ulcon = __raw_readl(regs + S3C2410_ULCON);
 	save->ucon = __raw_readl(regs + S3C2410_UCON);
@@ -98,18 +99,14 @@ static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save)
 	if (!soc_is_s3c2410())
 		save->udivslot = __raw_readl(regs + S3C2443_DIVSLOT);
 
-	S3C_PMDBG("UART[%d]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n",
-		  uart, save->ulcon, save->ucon, save->ufcon, save->ubrdiv);
-}
-
-static void s3c_pm_save_uarts(void)
-{
-	s3c_pm_save_uart(CONFIG_DEBUG_S3C_UART, &uart_save);
+	S3C_PMDBG("UART[%p]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n",
+		  regs, save->ulcon, save->ucon, save->ufcon, save->ubrdiv);
 }
 
-static void s3c_pm_restore_uart(unsigned int uart, struct pm_uart_save *save)
+static void s3c_pm_restore_uarts(void)
 {
 	void __iomem *regs = s3c_pm_uart_base();
+	struct pm_uart_save *save = &uart_save;
 
 	s3c_pm_arch_update_uart(regs, save);
 
@@ -122,11 +119,6 @@ static void s3c_pm_restore_uart(unsigned int uart, struct pm_uart_save *save)
 	if (!soc_is_s3c2410())
 		__raw_writel(save->udivslot, regs + S3C2443_DIVSLOT);
 }
-
-static void s3c_pm_restore_uarts(void)
-{
-	s3c_pm_restore_uart(CONFIG_DEBUG_S3C_UART, &uart_save);
-}
 #else
 #define s3c_pm_debug_init() do { } while (0)
 
-- 
1.8.5.2

^ permalink raw reply related

* [PATCH v2 04/12] ARM: SAMSUNG: pm: Use debug_ll_addr() to get UART base address
From: Tomasz Figa @ 2014-02-06 19:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391713977-22300-1-git-send-email-t.figa@samsung.com>

This patch modifies Samsung PM debug helpers to use a multiplatform
friendly way of getting base address of debug UART port, so instead
of using a per-mach static macro, a generic debug_ll_addr() helper
is used.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/plat-samsung/pm.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c
index 5d9daf6..53b3d67 100644
--- a/arch/arm/plat-samsung/pm.c
+++ b/arch/arm/plat-samsung/pm.c
@@ -21,6 +21,7 @@
 #include <linux/io.h>
 
 #include <asm/cacheflush.h>
+#include <asm/mach/map.h>
 #include <asm/suspend.h>
 
 #include <plat/cpu.h>
@@ -74,9 +75,19 @@ static inline void s3c_pm_debug_init(void)
 
 static struct pm_uart_save uart_save;
 
+static inline void __iomem *s3c_pm_uart_base(void)
+{
+	unsigned long paddr;
+	unsigned long vaddr;
+
+	debug_ll_addr(&paddr, &vaddr);
+
+	return (void __iomem *)vaddr;
+}
+
 static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save)
 {
-	void __iomem *regs = S3C_VA_UARTx(uart);
+	void __iomem *regs = s3c_pm_uart_base();
 
 	save->ulcon = __raw_readl(regs + S3C2410_ULCON);
 	save->ucon = __raw_readl(regs + S3C2410_UCON);
@@ -98,7 +109,7 @@ static void s3c_pm_save_uarts(void)
 
 static void s3c_pm_restore_uart(unsigned int uart, struct pm_uart_save *save)
 {
-	void __iomem *regs = S3C_VA_UARTx(uart);
+	void __iomem *regs = s3c_pm_uart_base();
 
 	s3c_pm_arch_update_uart(regs, save);
 
-- 
1.8.5.2

^ permalink raw reply related

* [PATCH v2 03/12] ARM: SAMSUNG: pm: Save UART DIVSLOT register based on SoC type
From: Tomasz Figa @ 2014-02-06 19:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391713977-22300-1-git-send-email-t.figa@samsung.com>

The only SoC that does not have DIVSLOT register is S3C2410, so instead
of exporting a variable for platforms to set if DIVSLOT register should
be preserved, it's enough to simply check whether we are running on
a S3C2410 instead.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/mach-s3c64xx/pm.c              |  1 -
 arch/arm/mach-s5p64x0/pm.c              |  1 -
 arch/arm/plat-samsung/include/plat/pm.h |  2 --
 arch/arm/plat-samsung/pm.c              | 18 +++++-------------
 4 files changed, 5 insertions(+), 17 deletions(-)

diff --git a/arch/arm/mach-s3c64xx/pm.c b/arch/arm/mach-s3c64xx/pm.c
index b5a6698..6b37694 100644
--- a/arch/arm/mach-s3c64xx/pm.c
+++ b/arch/arm/mach-s3c64xx/pm.c
@@ -332,7 +332,6 @@ static __init int s3c64xx_pm_initcall(void)
 {
 	pm_cpu_prep = s3c64xx_pm_prepare;
 	pm_cpu_sleep = s3c64xx_cpu_suspend;
-	pm_uart_udivslot = 1;
 
 #ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK
 	gpio_request(S3C64XX_GPN(12), "DEBUG_LED0");
diff --git a/arch/arm/mach-s5p64x0/pm.c b/arch/arm/mach-s5p64x0/pm.c
index 861e15c..ec8229c 100644
--- a/arch/arm/mach-s5p64x0/pm.c
+++ b/arch/arm/mach-s5p64x0/pm.c
@@ -161,7 +161,6 @@ static int s5p64x0_pm_add(struct device *dev, struct subsys_interface *sif)
 {
 	pm_cpu_prep = s5p64x0_pm_prepare;
 	pm_cpu_sleep = s5p64x0_cpu_suspend;
-	pm_uart_udivslot = 1;
 
 	return 0;
 }
diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h
index ff6063f..21758c6 100644
--- a/arch/arm/plat-samsung/include/plat/pm.h
+++ b/arch/arm/plat-samsung/include/plat/pm.h
@@ -54,8 +54,6 @@ extern int (*pm_cpu_sleep)(unsigned long);
 
 extern unsigned long s3c_pm_flags;
 
-extern unsigned char pm_uart_udivslot;  /* true to save UART UDIVSLOT */
-
 /* from sleep.S */
 
 extern int s3c2410_cpu_suspend(unsigned long);
diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c
index e5b0f2c..5d9daf6 100644
--- a/arch/arm/plat-samsung/pm.c
+++ b/arch/arm/plat-samsung/pm.c
@@ -23,6 +23,7 @@
 #include <asm/cacheflush.h>
 #include <asm/suspend.h>
 
+#include <plat/cpu.h>
 #include <plat/regs-serial.h>
 
 #ifdef CONFIG_SAMSUNG_ATAGS
@@ -71,17 +72,6 @@ static inline void s3c_pm_debug_init(void)
 	s3c_pm_debug_init_uart();
 }
 
-#else
-#define s3c_pm_debug_init() do { } while(0)
-
-#endif /* CONFIG_SAMSUNG_PM_DEBUG */
-
-/* Save the UART configurations if we are configured for debug. */
-
-unsigned char pm_uart_udivslot;
-
-#ifdef CONFIG_SAMSUNG_PM_DEBUG
-
 static struct pm_uart_save uart_save;
 
 static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save)
@@ -94,7 +84,7 @@ static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save)
 	save->umcon = __raw_readl(regs + S3C2410_UMCON);
 	save->ubrdiv = __raw_readl(regs + S3C2410_UBRDIV);
 
-	if (pm_uart_udivslot)
+	if (!soc_is_s3c2410())
 		save->udivslot = __raw_readl(regs + S3C2443_DIVSLOT);
 
 	S3C_PMDBG("UART[%d]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n",
@@ -118,7 +108,7 @@ static void s3c_pm_restore_uart(unsigned int uart, struct pm_uart_save *save)
 	__raw_writel(save->umcon, regs + S3C2410_UMCON);
 	__raw_writel(save->ubrdiv, regs + S3C2410_UBRDIV);
 
-	if (pm_uart_udivslot)
+	if (!soc_is_s3c2410())
 		__raw_writel(save->udivslot, regs + S3C2443_DIVSLOT);
 }
 
@@ -127,6 +117,8 @@ static void s3c_pm_restore_uarts(void)
 	s3c_pm_restore_uart(CONFIG_DEBUG_S3C_UART, &uart_save);
 }
 #else
+#define s3c_pm_debug_init() do { } while (0)
+
 static void s3c_pm_save_uarts(void) { }
 static void s3c_pm_restore_uarts(void) { }
 #endif
-- 
1.8.5.2

^ permalink raw reply related

* [PATCH v2 02/12] ARM: SAMSUNG: Add soc_is_s3c2410() helper
From: Tomasz Figa @ 2014-02-06 19:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391713977-22300-1-git-send-email-t.figa@samsung.com>

Due to the S3C2410 SoC being quite different from other S3C24xx SoCs
in some aspects, such as availability of DIVSLOT register in its UART
blocks, there is a need sometimes to check whether we are running on
this SoC, not just the S3C24xx series. This patch adds soc_is_s3c2410()
helper function for this purpose.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/plat-samsung/include/plat/cpu.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/plat-samsung/include/plat/cpu.h b/arch/arm/plat-samsung/include/plat/cpu.h
index 335beb3..6bf86f6 100644
--- a/arch/arm/plat-samsung/include/plat/cpu.h
+++ b/arch/arm/plat-samsung/include/plat/cpu.h
@@ -20,6 +20,9 @@
 
 extern unsigned long samsung_cpu_id;
 
+#define S3C2410_CPU_ID		0x32410000
+#define S3C2410_CPU_MASK	0xFFFFFFFF
+
 #define S3C24XX_CPU_ID		0x32400000
 #define S3C24XX_CPU_MASK	0xFFF00000
 
@@ -56,6 +59,7 @@ static inline int is_samsung_##name(void)	\
 	return ((samsung_cpu_id & mask) == (id & mask));	\
 }
 
+IS_SAMSUNG_CPU(s3c2410, S3C2410_CPU_ID, S3C2410_CPU_MASK)
 IS_SAMSUNG_CPU(s3c24xx, S3C24XX_CPU_ID, S3C24XX_CPU_MASK)
 IS_SAMSUNG_CPU(s3c2412, S3C2412_CPU_ID, S3C2412_CPU_MASK)
 IS_SAMSUNG_CPU(s3c6400, S3C6400_CPU_ID, S3C64XX_CPU_MASK)
@@ -76,8 +80,10 @@ IS_SAMSUNG_CPU(exynos5440, EXYNOS5440_SOC_ID, EXYNOS5_SOC_MASK)
     defined(CONFIG_CPU_S3C2442) || defined(CONFIG_CPU_S3C244X) || \
     defined(CONFIG_CPU_S3C2443)
 # define soc_is_s3c24xx()	is_samsung_s3c24xx()
+# define soc_is_s3c2410()	is_samsung_s3c2410()
 #else
 # define soc_is_s3c24xx()	0
+# define soc_is_s3c2410()	0
 #endif
 
 #if defined(CONFIG_CPU_S3C2412)
-- 
1.8.5.2

^ permalink raw reply related

* [PATCH v2 01/12] ARM: EXYNOS: Do not resume l2x0 if not enabled before suspend
From: Tomasz Figa @ 2014-02-06 19:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391713977-22300-1-git-send-email-t.figa@samsung.com>

Trying to resume l2x0 if it was not enabled before suspend leads to
system crash. This patch prevents this by checking if l2x0_regs_phys is
a valid pointer to l2x0 context data saved on initialization.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/plat-samsung/s5p-sleep.S | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/arch/arm/plat-samsung/s5p-sleep.S b/arch/arm/plat-samsung/s5p-sleep.S
index a030e73..20764bd 100644
--- a/arch/arm/plat-samsung/s5p-sleep.S
+++ b/arch/arm/plat-samsung/s5p-sleep.S
@@ -59,13 +59,15 @@ ENTRY(s3c_cpu_resume)
 	and	r0, r0, r1
 	ldr	r1, =CPU_CORTEX_A9
 	cmp	r0, r1
-	bne	resume_l2on
+	bne	skip_l2_resume
 	adr	r0, l2x0_regs_phys
 	ldr	r0, [r0]
+	cmp	r0, #0
+	beq	skip_l2_resume
 	ldr	r1, [r0, #L2X0_R_PHY_BASE]
 	ldr	r2, [r1, #L2X0_CTRL]
 	tst	r2, #0x1
-	bne	resume_l2on
+	bne	skip_l2_resume
 	ldr	r2, [r0, #L2X0_R_AUX_CTRL]
 	str	r2, [r1, #L2X0_AUX_CTRL]
 	ldr	r2, [r0, #L2X0_R_TAG_LATENCY]
@@ -78,7 +80,7 @@ ENTRY(s3c_cpu_resume)
 	str	r2, [r1, #L2X0_POWER_CTRL]
 	mov	r2, #1
 	str	r2, [r1, #L2X0_CTRL]
-resume_l2on:
+skip_l2_resume:
 #endif
 	b	cpu_resume
 ENDPROC(s3c_cpu_resume)
-- 
1.8.5.2

^ permalink raw reply related

* [PATCH v2 00/12] Samsung PM consolidation part 2 (multiplatform)
From: Tomasz Figa @ 2014-02-06 19:12 UTC (permalink / raw)
  To: linux-arm-kernel

Current Samsung PM code is heavily unprepared for multiplatform systems.
The design implies accessing functions and global variables defined in
particular mach- subdirectory from common code in plat-, which is not
allowed when building ARCH_MULTIPLATFORM. In addition there is a lot of
forced code unification, which makes common function handle any possible
quirks of all supported SoCs. In the end this design turned out to not
work too well, ending with a lot of empty functions exported from mach-,
just because code in common pm.c calls them. Moreover, recent trend of
moving lower level suspend/resume code to proper drivers, like pinctrl
or clk, made a lot of code there redundant, especially on DT-only platforms
like Exynos.

This patch series attempts to untie Exynos PM support from the legacy
Samsung PM core and make it multiplatform-aware, by isolating truly
generic parts of the latter, making them multiplatform-friendly and then
reimplementing Exynos PM support in a multiplatform-capable way by using
those generic parts. The result is that now PM initialization is started
from mach-exynos*-dt, which calls Exynos-specific initialization code that
registers platform_suspend_ops, so control flow is basically reversed
ending with mach- code calling more generic plat- code if needed.

This is limited to Exynos right now, but remaining SoCs could follow
in further series.

Depends on Samsung PM consolidation part 1 (clocks) series:
 - http://thread.gmane.org/gmane.linux.kernel.samsung-soc/26816

On Exynos4210-based Trats, Exynos4412-based Trats2 and Exynos5250-based
Arndale boards (except suspend/resume, which is broken because of
unrelated reasons):

Tested-by: Tomasz Figa <t.figa@samsung.com>

Changes since v1 (RFC):
 - fixed l2x0 resume,
 - fixed checkpatch complaints (about issues in existing code being moved),
 - rebased on top of current linux-next,
 - slightly reordered patches to make the order more logical.

Tomasz Figa (12):
  ARM: EXYNOS: Do not resume l2x0 if not enabled before suspend
  ARM: SAMSUNG: Add soc_is_s3c2410() helper
  ARM: SAMSUNG: pm: Save UART DIVSLOT register based on SoC type
  ARM: SAMSUNG: pm: Use debug_ll_addr() to get UART base address
  ARM: SAMSUNG: pm: Consolidate PM debug functions
  ARM: SAMSUNG: pm: Move Samsung PM debug code into separate file
  ARM: SAMSUNG: Move common save/restore helpers to separate file
  ARM: SAMSUNG: pm: Move s3c_pm_check_* prototypes to plat/pm-common.h
  ARM: EXYNOS: Kconfig: Fix abuse of CONFIG_PM
  ARM: EXYNOS: Remove PM initcalls and useless indirection
  ARM: EXYNOS: Stop using legacy Samsung PM code
  ARM: exynos: Allow wake-up using GIC interrupts

 arch/arm/mach-exynos/Kconfig                   |  16 +--
 arch/arm/mach-exynos/Makefile                  |   2 +-
 arch/arm/mach-exynos/common.c                  |   1 +
 arch/arm/mach-exynos/common.h                  |  14 ++
 arch/arm/mach-exynos/include/mach/pm-core.h    |  75 -----------
 arch/arm/mach-exynos/pm.c                      | 172 +++++++++++++++++++------
 arch/arm/mach-exynos/regs-pmu.h                |   2 +
 arch/arm/mach-exynos/sleep.S                   |  85 ++++++++++++
 arch/arm/mach-s3c64xx/pm.c                     |   1 -
 arch/arm/mach-s5p64x0/pm.c                     |   1 -
 arch/arm/plat-samsung/Makefile                 |   2 +
 arch/arm/plat-samsung/include/plat/cpu.h       |   6 +
 arch/arm/plat-samsung/include/plat/pm-common.h | 110 ++++++++++++++++
 arch/arm/plat-samsung/include/plat/pm.h        |  80 +-----------
 arch/arm/plat-samsung/pm-check.c               |   2 +-
 arch/arm/plat-samsung/pm-common.c              |  75 +++++++++++
 arch/arm/plat-samsung/pm-debug.c               |  98 ++++++++++++++
 arch/arm/plat-samsung/pm.c                     | 146 ---------------------
 arch/arm/plat-samsung/s5p-sleep.S              |  43 -------
 19 files changed, 531 insertions(+), 400 deletions(-)
 delete mode 100644 arch/arm/mach-exynos/include/mach/pm-core.h
 create mode 100644 arch/arm/mach-exynos/sleep.S
 create mode 100644 arch/arm/plat-samsung/include/plat/pm-common.h
 create mode 100644 arch/arm/plat-samsung/pm-common.c
 create mode 100644 arch/arm/plat-samsung/pm-debug.c

-- 
1.8.5.2

^ permalink raw reply

* [PATCH v6 18/19] ARM: mvebu: Enable watchdog support in defconfig
From: Jason Cooper @ 2014-02-06 19:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140206191023.GA19328@localhost>

On Thu, Feb 06, 2014 at 04:10:24PM -0300, Ezequiel Garcia wrote:
> On Thu, Feb 06, 2014 at 12:51:59PM -0500, Jason Cooper wrote:
> > On Thu, Feb 06, 2014 at 02:20:25PM -0300, Ezequiel Garcia wrote:
> > > Now that we have proper support for Armada 370/XP watchdog
> > > let's enable it in the defconfig.
> > > 
> > > Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
> > > ---
> > >  arch/arm/configs/mvebu_defconfig | 2 ++
> > >  1 file changed, 2 insertions(+)
> > 
> > If this ends up being the last version for this series, I'll add a patch
> > for multi_v7_defconfig.  Otherwise, please add for the next round.
> > 
> 
> Oh, yes, I forgot about your request on this. Let's hope I don't forget
> next time.

Yes, we found the i2c hang because of multi_v7, so it's definitely worth
the effort.

thx,

Jason.

^ permalink raw reply

* [PATCH v6 18/19] ARM: mvebu: Enable watchdog support in defconfig
From: Ezequiel Garcia @ 2014-02-06 19:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140206175159.GI8533@titan.lakedaemon.net>

On Thu, Feb 06, 2014 at 12:51:59PM -0500, Jason Cooper wrote:
> On Thu, Feb 06, 2014 at 02:20:25PM -0300, Ezequiel Garcia wrote:
> > Now that we have proper support for Armada 370/XP watchdog
> > let's enable it in the defconfig.
> > 
> > Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
> > ---
> >  arch/arm/configs/mvebu_defconfig | 2 ++
> >  1 file changed, 2 insertions(+)
> 
> If this ends up being the last version for this series, I'll add a patch
> for multi_v7_defconfig.  Otherwise, please add for the next round.
> 

Oh, yes, I forgot about your request on this. Let's hope I don't forget
next time.
-- 
Ezequiel Garc?a, Free Electrons
Embedded Linux, Kernel and Android Engineering
http://free-electrons.com

^ permalink raw reply

* [PATCH] clk: at91: remove redundant assignment
From: Colin King @ 2014-02-06 18:53 UTC (permalink / raw)
  To: linux-arm-kernel

From: Colin Ian King <colin.king@canonical.com>

remove the redundant shift = shift assignment, it is extraneous.

Signed-off-by: Colin Ian King <colin.king@canonical.com>
---
 drivers/clk/at91/clk-programmable.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c
index fd792b2..ff86efe 100644
--- a/drivers/clk/at91/clk-programmable.c
+++ b/drivers/clk/at91/clk-programmable.c
@@ -109,7 +109,7 @@ static long clk_programmable_round_rate(struct clk_hw *hw, unsigned long rate,
 	unsigned long best_diff;
 	unsigned long new_diff;
 	unsigned long cur_rate;
-	int shift = shift;
+	int shift;
 
 	if (rate > *parent_rate)
 		return *parent_rate;
-- 
1.9.rc1

^ permalink raw reply related

* [PATCH] ARM: mm: Fix the memblock allocation for LPAE machines
From: Santosh Shilimkar @ 2014-02-06 18:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140206184153.GV26684@n2100.arm.linux.org.uk>

On Thursday 06 February 2014 01:41 PM, Russell King - ARM Linux wrote:
> On Wed, Feb 05, 2014 at 07:50:55PM -0500, Santosh Shilimkar wrote:
>> On Wednesday 05 February 2014 06:48 PM, Russell King - ARM Linux wrote:
>>> On Wed, Feb 05, 2014 at 06:39:44PM -0500, Santosh Shilimkar wrote:
>>>> Russell,
>>>>
>>>> On Saturday 01 February 2014 03:14 PM, Santosh Shilimkar wrote:
>>>>> Commit ad6492b8 added much needed memblock_virt_alloc_low() and further
>>>>> commit 07bacb3 {memblock, bootmem: restore goal for alloc_low} fixed the
>>>>> issue with low memory limit thansk to Yinghai. But even after all these fixes,
>>>>> there is still one case where the limit check done with ARCH_LOW_ADDRESS_LIMIT
>>>>> for low memory fails. Russell pointed out the issue with 32 bit LPAE machines
>>>>> in below thread.
>>>>> 	https://lkml.org/lkml/2014/1/28/364
>>>>>
>>>>> Since on some LPAE machines where memory start address is beyond 4GB,
>>>>> the low memory marker in memblock will be set to default
>>>>> ARCH_LOW_ADDRESS_LIMIT which is wrong. We can fix this by letting
>>>>> architectures set the ARCH_LOW_ADDRESS_LIMIT using another export
>>>>> similar to memblock_set_current_limit() but am not sure whether
>>>>> its worth the trouble. Tell me if you think otherwise.
>>>>>
>>>>> Rather am just trying to fix that one broken case using memblock_virt_alloc()
>>>>> in setup code since the memblock.current_limit is updated appropriately
>>>>> makes it work on all ARM 32 bit machines.
>>>>>
>>>>> Cc: Yinghai Lu <yinghai@kernel.org>
>>>>> Cc: Russell King <linux@arm.linux.org.uk>
>>>>> Cc: Strashko, Grygorii <grygorii.strashko@ti.com>
>>>>> Cc: Andrew Morton <akpm@linux-foundation.org>
>>>>> Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
>>>>> ---
>>>> Whats you say here ? We should get the fix for the
>>>> issue. If you are ok, I can drop the patch in patch system.
>>>
>>> Is this still an issue, or has Tejun fixed it by some other means?  I've not
>>> noticed anything being broken at the moment.
>>>
>>> Can you confirm whether we still have an issue without this patch please?
>>>
>> Fixes for all cases exist except 'LPAE + memory start beyond 4 GB'.
>> This case is still broken and  hence I posted the $subject patch.
> 
> Okay.  Patch system please then.  Thanks.
> 
Thanks.  patch 7952/1

Regards,
Santosh

^ permalink raw reply

* [PATCH] ARM: mm: Fix the memblock allocation for LPAE machines
From: Russell King - ARM Linux @ 2014-02-06 18:41 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <52F2DC6F.8070005@ti.com>

On Wed, Feb 05, 2014 at 07:50:55PM -0500, Santosh Shilimkar wrote:
> On Wednesday 05 February 2014 06:48 PM, Russell King - ARM Linux wrote:
> > On Wed, Feb 05, 2014 at 06:39:44PM -0500, Santosh Shilimkar wrote:
> >> Russell,
> >>
> >> On Saturday 01 February 2014 03:14 PM, Santosh Shilimkar wrote:
> >>> Commit ad6492b8 added much needed memblock_virt_alloc_low() and further
> >>> commit 07bacb3 {memblock, bootmem: restore goal for alloc_low} fixed the
> >>> issue with low memory limit thansk to Yinghai. But even after all these fixes,
> >>> there is still one case where the limit check done with ARCH_LOW_ADDRESS_LIMIT
> >>> for low memory fails. Russell pointed out the issue with 32 bit LPAE machines
> >>> in below thread.
> >>> 	https://lkml.org/lkml/2014/1/28/364
> >>>
> >>> Since on some LPAE machines where memory start address is beyond 4GB,
> >>> the low memory marker in memblock will be set to default
> >>> ARCH_LOW_ADDRESS_LIMIT which is wrong. We can fix this by letting
> >>> architectures set the ARCH_LOW_ADDRESS_LIMIT using another export
> >>> similar to memblock_set_current_limit() but am not sure whether
> >>> its worth the trouble. Tell me if you think otherwise.
> >>>
> >>> Rather am just trying to fix that one broken case using memblock_virt_alloc()
> >>> in setup code since the memblock.current_limit is updated appropriately
> >>> makes it work on all ARM 32 bit machines.
> >>>
> >>> Cc: Yinghai Lu <yinghai@kernel.org>
> >>> Cc: Russell King <linux@arm.linux.org.uk>
> >>> Cc: Strashko, Grygorii <grygorii.strashko@ti.com>
> >>> Cc: Andrew Morton <akpm@linux-foundation.org>
> >>> Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
> >>> ---
> >> Whats you say here ? We should get the fix for the
> >> issue. If you are ok, I can drop the patch in patch system.
> > 
> > Is this still an issue, or has Tejun fixed it by some other means?  I've not
> > noticed anything being broken at the moment.
> > 
> > Can you confirm whether we still have an issue without this patch please?
> > 
> Fixes for all cases exist except 'LPAE + memory start beyond 4 GB'.
> This case is still broken and  hence I posted the $subject patch.

Okay.  Patch system please then.  Thanks.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

^ permalink raw reply

* [PATCH] clk: samsung: Initialize clock table with error pointers
From: Tomasz Figa @ 2014-02-06 18:33 UTC (permalink / raw)
  To: linux-arm-kernel

Before this patch, the driver was simply zeroing the clock table, which
is incorrect, because invalid clock numbers returned NULL instead of
error pointers. This patch fixes this by changing the driver to
initialize the array with PTR_ERR(-ENOENT).

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/clk/samsung/clk.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
index 91bec3e..f3a71d0 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -58,12 +58,17 @@ struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump(
 void __init samsung_clk_init(struct device_node *np, void __iomem *base,
 			     unsigned long nr_clks)
 {
+	int i;
+
 	reg_base = base;
 
-	clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
+	clk_table = kmalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
 	if (!clk_table)
 		panic("could not allocate clock lookup table\n");
 
+	for (i = 0; i < nr_clks; ++i)
+		clk_table[i] = ERR_PTR(-ENOENT);
+
 	if (!np)
 		return;
 
-- 
1.8.5.2

^ permalink raw reply related

* [PATCH v2 9/9] ARM: EXYNOS: pm: Drop legacy Exynos4 clock suspend/resume code
From: Tomasz Figa @ 2014-02-06 18:16 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391710616-14226-1-git-send-email-t.figa@samsung.com>

All the suspend/resume handling is already implemented in Exynos4 clock
driver, so this legacy code can be safely dropped.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/mach-exynos/pm.c | 148 +---------------------------------------------
 1 file changed, 2 insertions(+), 146 deletions(-)

diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c
index e00025b..ba18214 100644
--- a/arch/arm/mach-exynos/pm.c
+++ b/arch/arm/mach-exynos/pm.c
@@ -35,56 +35,6 @@
 #include "common.h"
 #include "regs-pmu.h"
 
-#define EXYNOS4_EPLL_LOCK			(S5P_VA_CMU + 0x0C010)
-#define EXYNOS4_VPLL_LOCK			(S5P_VA_CMU + 0x0C020)
-
-#define EXYNOS4_EPLL_CON0			(S5P_VA_CMU + 0x0C110)
-#define EXYNOS4_EPLL_CON1			(S5P_VA_CMU + 0x0C114)
-#define EXYNOS4_VPLL_CON0			(S5P_VA_CMU + 0x0C120)
-#define EXYNOS4_VPLL_CON1			(S5P_VA_CMU + 0x0C124)
-
-#define EXYNOS4_CLKSRC_MASK_TOP			(S5P_VA_CMU + 0x0C310)
-#define EXYNOS4_CLKSRC_MASK_CAM			(S5P_VA_CMU + 0x0C320)
-#define EXYNOS4_CLKSRC_MASK_TV			(S5P_VA_CMU + 0x0C324)
-#define EXYNOS4_CLKSRC_MASK_LCD0		(S5P_VA_CMU + 0x0C334)
-#define EXYNOS4_CLKSRC_MASK_MAUDIO		(S5P_VA_CMU + 0x0C33C)
-#define EXYNOS4_CLKSRC_MASK_FSYS		(S5P_VA_CMU + 0x0C340)
-#define EXYNOS4_CLKSRC_MASK_PERIL0		(S5P_VA_CMU + 0x0C350)
-#define EXYNOS4_CLKSRC_MASK_PERIL1		(S5P_VA_CMU + 0x0C354)
-
-#define EXYNOS4_CLKSRC_MASK_DMC			(S5P_VA_CMU + 0x10300)
-
-#define EXYNOS4_EPLLCON0_LOCKED_SHIFT		(29)
-#define EXYNOS4_VPLLCON0_LOCKED_SHIFT		(29)
-
-#define EXYNOS4210_CLKSRC_MASK_LCD1		(S5P_VA_CMU + 0x0C338)
-
-static const struct sleep_save exynos4_set_clksrc[] = {
-	{ .reg = EXYNOS4_CLKSRC_MASK_TOP		, .val = 0x00000001, },
-	{ .reg = EXYNOS4_CLKSRC_MASK_CAM		, .val = 0x11111111, },
-	{ .reg = EXYNOS4_CLKSRC_MASK_TV			, .val = 0x00000111, },
-	{ .reg = EXYNOS4_CLKSRC_MASK_LCD0		, .val = 0x00001111, },
-	{ .reg = EXYNOS4_CLKSRC_MASK_MAUDIO		, .val = 0x00000001, },
-	{ .reg = EXYNOS4_CLKSRC_MASK_FSYS		, .val = 0x01011111, },
-	{ .reg = EXYNOS4_CLKSRC_MASK_PERIL0		, .val = 0x01111111, },
-	{ .reg = EXYNOS4_CLKSRC_MASK_PERIL1		, .val = 0x01110111, },
-	{ .reg = EXYNOS4_CLKSRC_MASK_DMC		, .val = 0x00010000, },
-};
-
-static const struct sleep_save exynos4210_set_clksrc[] = {
-	{ .reg = EXYNOS4210_CLKSRC_MASK_LCD1		, .val = 0x00001111, },
-};
-
-static struct sleep_save exynos4_epll_save[] = {
-	SAVE_ITEM(EXYNOS4_EPLL_CON0),
-	SAVE_ITEM(EXYNOS4_EPLL_CON1),
-};
-
-static struct sleep_save exynos4_vpll_save[] = {
-	SAVE_ITEM(EXYNOS4_VPLL_CON0),
-	SAVE_ITEM(EXYNOS4_VPLL_CON1),
-};
-
 static struct sleep_save exynos5_sys_save[] = {
 	SAVE_ITEM(EXYNOS5_SYS_I2C_CFG),
 };
@@ -124,10 +74,7 @@ static void exynos_pm_prepare(void)
 
 	s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save));
 
-	if (!soc_is_exynos5250()) {
-		s3c_pm_do_save(exynos4_epll_save, ARRAY_SIZE(exynos4_epll_save));
-		s3c_pm_do_save(exynos4_vpll_save, ARRAY_SIZE(exynos4_vpll_save));
-	} else {
+	if (soc_is_exynos5250()) {
 		s3c_pm_do_save(exynos5_sys_save, ARRAY_SIZE(exynos5_sys_save));
 		/* Disable USE_RETENTION of JPEG_MEM_OPTION */
 		tmp = __raw_readl(EXYNOS5_JPEG_MEM_OPTION);
@@ -143,15 +90,6 @@ static void exynos_pm_prepare(void)
 	/* ensure at least INFORM0 has the resume address */
 
 	__raw_writel(virt_to_phys(s3c_cpu_resume), S5P_INFORM0);
-
-	/* Before enter central sequence mode, clock src register have to set */
-
-	if (!soc_is_exynos5250())
-		s3c_pm_do_restore_core(exynos4_set_clksrc, ARRAY_SIZE(exynos4_set_clksrc));
-
-	if (soc_is_exynos4210())
-		s3c_pm_do_restore_core(exynos4210_set_clksrc, ARRAY_SIZE(exynos4210_set_clksrc));
-
 }
 
 static int exynos_pm_add(struct device *dev, struct subsys_interface *sif)
@@ -162,73 +100,6 @@ static int exynos_pm_add(struct device *dev, struct subsys_interface *sif)
 	return 0;
 }
 
-static unsigned long pll_base_rate;
-
-static void exynos4_restore_pll(void)
-{
-	unsigned long pll_con, locktime, lockcnt;
-	unsigned long pll_in_rate;
-	unsigned int p_div, epll_wait = 0, vpll_wait = 0;
-
-	if (pll_base_rate == 0)
-		return;
-
-	pll_in_rate = pll_base_rate;
-
-	/* EPLL */
-	pll_con = exynos4_epll_save[0].val;
-
-	if (pll_con & (1 << 31)) {
-		pll_con &= (PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT);
-		p_div = (pll_con >> PLL46XX_PDIV_SHIFT);
-
-		pll_in_rate /= 1000000;
-
-		locktime = (3000 / pll_in_rate) * p_div;
-		lockcnt = locktime * 10000 / (10000 / pll_in_rate);
-
-		__raw_writel(lockcnt, EXYNOS4_EPLL_LOCK);
-
-		s3c_pm_do_restore_core(exynos4_epll_save,
-					ARRAY_SIZE(exynos4_epll_save));
-		epll_wait = 1;
-	}
-
-	pll_in_rate = pll_base_rate;
-
-	/* VPLL */
-	pll_con = exynos4_vpll_save[0].val;
-
-	if (pll_con & (1 << 31)) {
-		pll_in_rate /= 1000000;
-		/* 750us */
-		locktime = 750;
-		lockcnt = locktime * 10000 / (10000 / pll_in_rate);
-
-		__raw_writel(lockcnt, EXYNOS4_VPLL_LOCK);
-
-		s3c_pm_do_restore_core(exynos4_vpll_save,
-					ARRAY_SIZE(exynos4_vpll_save));
-		vpll_wait = 1;
-	}
-
-	/* Wait PLL locking */
-
-	do {
-		if (epll_wait) {
-			pll_con = __raw_readl(EXYNOS4_EPLL_CON0);
-			if (pll_con & (1 << EXYNOS4_EPLLCON0_LOCKED_SHIFT))
-				epll_wait = 0;
-		}
-
-		if (vpll_wait) {
-			pll_con = __raw_readl(EXYNOS4_VPLL_CON0);
-			if (pll_con & (1 << EXYNOS4_VPLLCON0_LOCKED_SHIFT))
-				vpll_wait = 0;
-		}
-	} while (epll_wait || vpll_wait);
-}
-
 static struct subsys_interface exynos_pm_interface = {
 	.name		= "exynos_pm",
 	.subsys		= &exynos_subsys,
@@ -237,7 +108,6 @@ static struct subsys_interface exynos_pm_interface = {
 
 static __init int exynos_pm_drvinit(void)
 {
-	struct clk *pll_base;
 	unsigned int tmp;
 
 	if (soc_is_exynos5440())
@@ -251,15 +121,6 @@ static __init int exynos_pm_drvinit(void)
 	tmp |= ((0xFF << 8) | (0x1F << 1));
 	__raw_writel(tmp, S5P_WAKEUP_MASK);
 
-	if (!soc_is_exynos5250()) {
-		pll_base = clk_get(NULL, "xtal");
-
-		if (!IS_ERR(pll_base)) {
-			pll_base_rate = clk_get_rate(pll_base);
-			clk_put(pll_base);
-		}
-	}
-
 	return subsys_interface_register(&exynos_pm_interface);
 }
 arch_initcall(exynos_pm_drvinit);
@@ -343,13 +204,8 @@ static void exynos_pm_resume(void)
 
 	s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save));
 
-	if (!soc_is_exynos5250()) {
-		exynos4_restore_pll();
-
-#ifdef CONFIG_SMP
+	if (IS_ENABLED(CONFIG_SMP) && !soc_is_exynos5250())
 		scu_enable(S5P_VA_SCU);
-#endif
-	}
 
 early_wakeup:
 
-- 
1.8.5.2

^ permalink raw reply related


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