Re: [PATCH 4/6] irqchip: add irqchip driver for nuc900

2016-07-21 Thread Wan ZongShun
>
>> but I will remove the Macros related to nuc970 and avoid nuc970
>> interrupt using those Macro.
>>
>> But I still need hack this irqs.h like below, since here NR_IRQS defined
>> and it is need for nuc970 irqchip driver.
>>
>> #if !defined(CONFIG_SOC_NUC900)
>> #define NR_IRQS (IRQ_ADC+1)
>> #else
>> #define NR_IRQS 62
>> #endif
>
> Have you considered using CONFIG_SPARSE_IRQ? That would avoid the need
> for setting NR_IRQS entirely, but may also require more work elsewhere.

Sure, I will refer to your previous nuc900 series patches for SPARSE
IRQ, now I am waiting for rc1 release, and will send v3 patches.

>
> Arnd



-- 
---
Vincent Wan(Zongshun)
www.mcuos.com


Re: [PATCH v2 02/10] irqchip: add irqchip driver for nuc900

2016-07-15 Thread Wan ZongShun
2016-07-15 15:00 GMT+08:00 Arnd Bergmann :
> On Friday, July 15, 2016 1:15:58 PM CEST Wan Zongshun wrote:
>>
>> Actually, I have two choice to implement this function:
>>
>> option1:
>>
>> void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
>> {
>> u32 hwirq;
>>
>> (void)readl(aic_base + REG_AIC_IPER);
>> hwirq = readl(aic_base + REG_AIC_ISNR);
>>
>> handle_IRQ((irq_find_mapping(aic_domain, hwirq)), regs);
>> }
>
> (side note: I think you want handle_domain_irq())
>
>> option2:
>>
>> void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
>> {
>> u32 hwirq;
>>
>> hwirq = readl(aic_base + REG_AIC_IPER);
>> hwirq <<= 2;
>>
>> handle_IRQ((irq_find_mapping(aic_domain, hwirq)), regs);
>> }
>>
>> Though the option2 do shift for hwirq, but it seems better than do io
>> operation by readl,so I prefer to option2, agree?
>
> That will only return an irq number that is a multiple of four, which
> seems wrong since the numbers are not that. Did you mean to write
>
> hwirq = ilog2(hwirq);   ?

Sorry, my fault, I mean hwirq >>= 2, bit[7:2] indicates which irq is triggering.
so I have to do right shift 2 for IPER value.

>
> That assumes that REG_AIC_IPER contains a 32-bit value with one single
> bit set to indicate which IRQ was triggered.
>
> If the difference is only in performance, you could try measuring which
> of the two ends up being faster.

It seems hard to measure. I think Do IO operation should be slower
than shift 2. :)

>
> Arnd



-- 
---
Vincent Wan(Zongshun)
www.mcuos.com


Re: [PATCH v2 02/10] irqchip: add irqchip driver for nuc900

2016-07-14 Thread Wan Zongshun



On 2016年07月14日 21:54, Jason Cooper wrote:

Hi Wan Zongshun,

On Thu, Jul 14, 2016 at 11:36:53AM +0800, Wan Zongshun wrote:

On 2016年07月14日 04:09, Jason Cooper wrote:

On Sun, Jul 10, 2016 at 03:27:22PM +0800, Wan Zongshun wrote:

This patch is to add irqchip driver support for nuc900 plat,
current this driver only supports nuc970 SoC.

Signed-off-by: Wan Zongshun 
---
  arch/arm/mach-w90x900/include/mach/irqs.h |   5 +
  drivers/irqchip/Makefile  |   1 +
  drivers/irqchip/irq-nuc900.c  | 150 ++
  3 files changed, 156 insertions(+)
  create mode 100644 drivers/irqchip/irq-nuc900.c

diff --git a/arch/arm/mach-w90x900/include/mach/irqs.h 
b/arch/arm/mach-w90x900/include/mach/irqs.h
index 9d5cba3..3b035c6 100644
--- a/arch/arm/mach-w90x900/include/mach/irqs.h
+++ b/arch/arm/mach-w90x900/include/mach/irqs.h
@@ -59,7 +59,12 @@
  #define IRQ_KPI   W90X900_IRQ(29)
  #define IRQ_P2SGROUP  W90X900_IRQ(30)
  #define IRQ_ADC   W90X900_IRQ(31)
+
+#if !defined(CONFIG_SOC_NUC900)
  #define NR_IRQS   (IRQ_ADC+1)
+#else
+#define NR_IRQS62
+#endif


Arnd already covered this...



  /*for irq group*/

diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 38853a1..9ccd5af8a 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -69,3 +69,4 @@ obj-$(CONFIG_PIC32_EVIC)  += irq-pic32-evic.o
  obj-$(CONFIG_MVEBU_ODMI)  += irq-mvebu-odmi.o
  obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o
  obj-$(CONFIG_EZNPS_GIC)   += irq-eznps.o
+obj-$(CONFIG_SOC_NUC970)   += irq-nuc900.o
diff --git a/drivers/irqchip/irq-nuc900.c b/drivers/irqchip/irq-nuc900.c
new file mode 100644
index 000..c4b2e39
--- /dev/null
+++ b/drivers/irqchip/irq-nuc900.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#defineREG_AIC_SCR10x00
+#defineREG_AIC_SCR20x04
+#defineREG_AIC_SCR30x08
+#defineREG_AIC_SCR40x0C
+#defineREG_AIC_SCR50x10
+#defineREG_AIC_SCR60x14
+#defineREG_AIC_SCR70x18
+#defineREG_AIC_SCR80x1C
+#defineREG_AIC_SCR90x20
+#defineREG_AIC_SCR10   0x24
+#defineREG_AIC_SCR11   0x28
+#defineREG_AIC_SCR12   0x2C
+#defineREG_AIC_SCR13   0x30
+#defineREG_AIC_SCR14   0x34
+#defineREG_AIC_SCR15   0x38
+#defineREG_AIC_IRSR0x100
+#defineREG_AIC_IRSRH   0x104
+#defineREG_AIC_IASR0x108
+#defineREG_AIC_IASRH   0x10C
+#defineREG_AIC_ISR 0x110
+#defineREG_AIC_ISRH0x114
+#defineREG_AIC_IPER0x118
+#defineREG_AIC_ISNR0x120
+#defineREG_AIC_OISR0x124
+#defineREG_AIC_IMR 0x128
+#defineREG_AIC_IMRH0x12C
+#defineREG_AIC_MECR0x130
+#defineREG_AIC_MECRH   0x134
+#defineREG_AIC_MDCR0x138
+#defineREG_AIC_MDCRH   0x13C
+#defineREG_AIC_SSCR0x140
+#defineREG_AIC_SSCRH   0x144
+#defineREG_AIC_SCCR0x148
+#defineREG_AIC_SCCRH   0x14C
+#defineREG_AIC_EOSCR   0x150


Please remove unused defines.


Okay.




+
+static void __iomem *aic_base;
+static struct irq_domain *aic_domain;
+
+static void nuc900_irq_mask(struct irq_data *d)
+{
+   if (d->irq < 32)
+   writel(1 << (d->irq), aic_base + REG_AIC_MDCR);
+   else
+   writel(1 << (d->irq - 32), aic_base + REG_AIC_MDCRH);
+}
+
+static void nuc900_irq_ack(struct irq_data *d)
+{
+   writel(0x01, aic_base + REG_AIC_EOSCR);
+}
+
+static void nuc900_irq_unmask(struct irq_data *d)
+{
+   if (d->irq < 32)
+   writel(1 << (d->irq), aic_base + REG_AIC_MECR);
+   else
+   writel(1 << (d->irq - 32), aic_base + REG_AIC_MECRH);
+}
+
+static struct irq_chip nuc900_irq_chip = {
+   .irq_ack= nuc900_irq_ack,
+   .irq_mask   = nuc900_irq_mask,
+   .irq_unmask = nuc900_irq_unmask,
+};
+
+void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
+{
+   u32 hwirq;
+
+   hwirq = readl(aic_base + REG_AIC_IPER);
+   hwirq = readl(aic_base + REG_AIC_ISNR);
+   if (!hwirq)
+   writel(0x01, aic_base + REG_AIC_EOSCR);


Could you explain what's going on here?


AIC_IPER, When the AIC generates the interrupt, VECTOR represents
the interrupt channel number that is active, enabled, 

Re: [PATCH v2 02/10] irqchip: add irqchip driver for nuc900

2016-07-14 Thread Wan Zongshun



On 2016年07月12日 16:26, Arnd Bergmann wrote:

On Tuesday, July 12, 2016 3:04:42 PM CEST Wan Zongshun wrote:


Ideally, this should just go away once we use SPARSE_IRQ.


This platform also can use SPARSE_IRQ? this just a simple irq map and no
more irq number in this Soc.



SPARSE_IRQ is implied by ARCH_MULTIPLATFORM, so we will have to
use it once that gets enabled.

Your new irqchip driver already handles IRQ domains, so it will
work out of the box with SPARSE_IRQ, but you have to change the
reference to "NR_IRQS" into something else.

I've prototyped a patch series to enable ARCH_MULTIPLATFORM,
I hope you can start working from what I have and get it to run.


I go through the ARCH_MULTIPLATFORM and SPARSE_IRQ related codes, but I 
find I also have to define the NUC900_NR_IRQS firstly like below, so 
that I can init the .nr_irq.


+#if !defined(CONFIG_SOC_NUC970)
 #define NUC900_NR_IRQS (IRQ_ADC+1)
+#else
+#define NUC900_NR_IRQS 62
+#endif

 DT_MACHINE_START(nuc900_dt, "Nuvoton NUC900 (Device Tree Support)")
.dt_compat  = nuc900_dt_compat,
+   .nr_irqs= NUC900_NR_IRQS,
 MACHINE_END

and then in my irqchip driver, I will use the NUC900_NR_IRQS:

+aic_domain = irq_domain_add_linear(node, NUC900_NR_IRQS,
+   &aic_irq_domain_ops, NULL);


Is that a right usage?



Arnd

___
linux-arm-kernel mailing list
linux-arm-ker...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel




Re: [PATCH v2 02/10] irqchip: add irqchip driver for nuc900

2016-07-13 Thread Wan Zongshun



On 2016年07月14日 04:09, Jason Cooper wrote:

Hi Wan Zongshun,

On Sun, Jul 10, 2016 at 03:27:22PM +0800, Wan Zongshun wrote:

This patch is to add irqchip driver support for nuc900 plat,
current this driver only supports nuc970 SoC.

Signed-off-by: Wan Zongshun 
---
  arch/arm/mach-w90x900/include/mach/irqs.h |   5 +
  drivers/irqchip/Makefile  |   1 +
  drivers/irqchip/irq-nuc900.c  | 150 ++
  3 files changed, 156 insertions(+)
  create mode 100644 drivers/irqchip/irq-nuc900.c

diff --git a/arch/arm/mach-w90x900/include/mach/irqs.h 
b/arch/arm/mach-w90x900/include/mach/irqs.h
index 9d5cba3..3b035c6 100644
--- a/arch/arm/mach-w90x900/include/mach/irqs.h
+++ b/arch/arm/mach-w90x900/include/mach/irqs.h
@@ -59,7 +59,12 @@
  #define IRQ_KPI   W90X900_IRQ(29)
  #define IRQ_P2SGROUP  W90X900_IRQ(30)
  #define IRQ_ADC   W90X900_IRQ(31)
+
+#if !defined(CONFIG_SOC_NUC900)
  #define NR_IRQS   (IRQ_ADC+1)
+#else
+#define NR_IRQS62
+#endif


Arnd already covered this...



  /*for irq group*/

diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 38853a1..9ccd5af8a 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -69,3 +69,4 @@ obj-$(CONFIG_PIC32_EVIC)  += irq-pic32-evic.o
  obj-$(CONFIG_MVEBU_ODMI)  += irq-mvebu-odmi.o
  obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o
  obj-$(CONFIG_EZNPS_GIC)   += irq-eznps.o
+obj-$(CONFIG_SOC_NUC970)   += irq-nuc900.o
diff --git a/drivers/irqchip/irq-nuc900.c b/drivers/irqchip/irq-nuc900.c
new file mode 100644
index 000..c4b2e39
--- /dev/null
+++ b/drivers/irqchip/irq-nuc900.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#defineREG_AIC_SCR10x00
+#defineREG_AIC_SCR20x04
+#defineREG_AIC_SCR30x08
+#defineREG_AIC_SCR40x0C
+#defineREG_AIC_SCR50x10
+#defineREG_AIC_SCR60x14
+#defineREG_AIC_SCR70x18
+#defineREG_AIC_SCR80x1C
+#defineREG_AIC_SCR90x20
+#defineREG_AIC_SCR10   0x24
+#defineREG_AIC_SCR11   0x28
+#defineREG_AIC_SCR12   0x2C
+#defineREG_AIC_SCR13   0x30
+#defineREG_AIC_SCR14   0x34
+#defineREG_AIC_SCR15   0x38
+#defineREG_AIC_IRSR0x100
+#defineREG_AIC_IRSRH   0x104
+#defineREG_AIC_IASR0x108
+#defineREG_AIC_IASRH   0x10C
+#defineREG_AIC_ISR 0x110
+#defineREG_AIC_ISRH0x114
+#defineREG_AIC_IPER0x118
+#defineREG_AIC_ISNR0x120
+#defineREG_AIC_OISR0x124
+#defineREG_AIC_IMR 0x128
+#defineREG_AIC_IMRH0x12C
+#defineREG_AIC_MECR0x130
+#defineREG_AIC_MECRH   0x134
+#defineREG_AIC_MDCR0x138
+#defineREG_AIC_MDCRH   0x13C
+#defineREG_AIC_SSCR0x140
+#defineREG_AIC_SSCRH   0x144
+#defineREG_AIC_SCCR0x148
+#defineREG_AIC_SCCRH   0x14C
+#defineREG_AIC_EOSCR   0x150


Please remove unused defines.


Okay.




+
+static void __iomem *aic_base;
+static struct irq_domain *aic_domain;
+
+static void nuc900_irq_mask(struct irq_data *d)
+{
+   if (d->irq < 32)
+   writel(1 << (d->irq), aic_base + REG_AIC_MDCR);
+   else
+   writel(1 << (d->irq - 32), aic_base + REG_AIC_MDCRH);
+}
+
+static void nuc900_irq_ack(struct irq_data *d)
+{
+   writel(0x01, aic_base + REG_AIC_EOSCR);
+}
+
+static void nuc900_irq_unmask(struct irq_data *d)
+{
+   if (d->irq < 32)
+   writel(1 << (d->irq), aic_base + REG_AIC_MECR);
+   else
+   writel(1 << (d->irq - 32), aic_base + REG_AIC_MECRH);
+}
+
+static struct irq_chip nuc900_irq_chip = {
+   .irq_ack= nuc900_irq_ack,
+   .irq_mask   = nuc900_irq_mask,
+   .irq_unmask = nuc900_irq_unmask,
+};
+
+void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
+{
+   u32 hwirq;
+
+   hwirq = readl(aic_base + REG_AIC_IPER);
+   hwirq = readl(aic_base + REG_AIC_ISNR);
+   if (!hwirq)
+   writel(0x01, aic_base + REG_AIC_EOSCR);


Could you explain what's going on here?


AIC_IPER, When the AIC generates the interrupt, VECTOR represents the 
interrupt channel number that is active, enabled, and has the highest 
priority.


The value of VECTOR is copied to the register AIC_ISNR thereafter by the 
A

Re: [PATCH 00/20] iommu/amd: Use generic IOVA allocator

2016-07-13 Thread Wan Zongshun



On 2016年07月12日 18:55, Joerg Roedel wrote:

Hey Vincent,

On Tue, Jul 12, 2016 at 05:03:08PM +0800, Wan Zongshun wrote:

Currently, those patches can not work at my eCarrizo board.
When I merged your patches, boot failed, and no any info print to me.
I set iommu=pt, it also does not work; set iommu=soft, boot ok.

When I removed those patches, kernel boot ok.

This eCarrizo board uart doesnot work, so I can not get useful
information from kernel by uart console, I also set 'text' in boot
option, but still cannot print any log.


Thanks for your testing. The issue turned out to be an older bug, which
just got uncovered by these patches. I updated the branch at

git://git.kernel.org/pub/scm/linux/kernel/git/joro/linux.git 
amd-iommu-iova

This branch boots now on my Kaveri and Carrizo system. Can you please
give it a test too?


Joerg, I have tested the patches, it works now.



Thanks,

Joerg

___
iommu mailing list
io...@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu




Re: [PATCH v2 08/10] ARM: dts: nuc900: Add nuc970 dts files

2016-07-13 Thread Wan Zongshun



On 2016年07月12日 23:39, Afzal Mohammed wrote:

Hi,

On Sun, Jul 10, 2016 at 03:42:20PM +0800, Wan Zongshun wrote:

This patch is to add dts support for nuc970 platform.


cpu ! in soc ? lost in fab ? ;)


Do you mean I should add cpus into soc like?


cpus {
#address-cells = <0>;
#size-cells = <0>;

cpu {
compatible = "arm,arm926ej-s";
device_type = "cpu";
};
};



Regards
afzal




Re: [PATCH v2 06/10] soc: Add SoC specific driver support for nuc900

2016-07-12 Thread Wan Zongshun



On 2016年07月11日 16:03, Arnd Bergmann wrote:

On Sunday, July 10, 2016 3:27:26 PM CEST Wan Zongshun wrote:

+   ret = of_property_read_string(np, "compatible", &soc_dev_attr->soc_id);
+   if (ret)
   return -EINVAL;
+
+   soc_dev_attr->machine = "NUC900EVB";
+   soc_dev_attr->family = "NUC900";
+   soc_dev = soc_device_register(soc_dev_attr);
+   if (IS_ERR(soc_dev)) {
+   kfree(soc_dev_attr);
+   return -ENODEV;
+   }
+
+   ret = regmap_read(syscon_regmap, GCR_CHIPID, &nuc900_chipid);
+   if (ret)
+   return -ENODEV;
+
+   device_create_file(soc_device_to_device(soc_dev), &nuc900_chipid_attr);
+   device_create_file(soc_device_to_device(soc_dev), &nuc900_version_attr);
+
+   dev_info(&pdev->dev, "Nuvoton Chip ID: 0x%x, Version ID:0x%x\n",
+nuc900_chipid & GCR_CHIPID_MASK,
+(nuc900_chipid >> 24) & 0xff);


I'm still a bit unsure about the set of attributes here.

- The "soc_id" is read from the device tree from the field that contains
   the board name, I think for consistency you should try to map the
   GCR_CHIPID to the name of the SoC and assign that here

- The "machine" is hardcoded to "NUC900EVB", which in turn looks like
   a particular board but not the one you are running on. Maybe read
   that from the DT instead?

- The "revision" is not filled at all, I would suggest using something
   derived from the GCR_CHIPID register here

- you have two nonstandard attributes "chipid" and "version", which
   I'd hope to avoid -- the set of standard attributes is supposed to
   give enough information about the machine, and platform independent
   user space will never read those.


So, Maybe I can remove those two codes, no need push those information 
to user space?


device_create_file(soc_device_to_device(soc_dev), &nuc900_chipid_attr);
device_create_file(soc_device_to_device(soc_dev), &nuc900_version_attr);



Arnd

___
linux-arm-kernel mailing list
linux-arm-ker...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel




Re: [PATCH 00/20] iommu/amd: Use generic IOVA allocator

2016-07-12 Thread Wan Zongshun



On 2016年07月08日 19:44, Joerg Roedel wrote:

Hi,

here is a patch-set to make the AMD IOMMU driver use the
generic IOVA allocator, which is already used in the Intel
VT-d driver and a few other places.

The main reason for the conversion is to make the driver
benefit from the recent scalability improvements to the IOVA
code. Some of these improvements happened in the Intel VT-d
driver, these are not re-used but, for now, re-implemented.

This leaves more room for merging things together into
common code for the future.

The allocator that was previously used will be removed with
these patches.

Please review.


Joerg,

Currently, those patches can not work at my eCarrizo board.
When I merged your patches, boot failed, and no any info print to me.
I set iommu=pt, it also does not work; set iommu=soft, boot ok.

When I removed those patches, kernel boot ok.

This eCarrizo board uart doesnot work, so I can not get useful 
information from kernel by uart console, I also set 'text' in boot 
option, but still cannot print any log.



Vincent.



Thanks,

Joerg

Joerg Roedel (20):
   iommu: Add apply_dm_region call-back to iommu-ops
   iommu/amd: Select IOMMU_IOVA for AMD IOMMU
   iommu/amd: Allocate iova_domain for dma_ops_domain
   iommu/amd: Create a list of reserved iova addresses
   iommu/amd: Implement apply_dm_region call-back
   iommu/amd: Pass gfp-flags to iommu_map_page()
   iommu/amd: Remove special mapping code for dma_ops path
   iommu/amd: Make use of the generic IOVA allocator
   iommu/amd: Remove other remains of old address allocator
   iommu/amd: Remove align-parameter from __map_single()
   iommu/amd: Set up data structures for flush queue
   iommu/amd: Allow NULL pointer parameter for domain_flush_complete()
   iommu/amd: Implement flush queue
   iommu/amd: Implement timeout to flush unmap queues
   iommu/amd: Introduce dir2prot() helper
   iommu/amd: Optimize map_sg and unmap_sg
   iommu/amd: Use dev_data->domain in get_domain()
   iommu/amd: Handle IOMMU_DOMAIN_DMA in ops->domain_free call-back
   iommu/amd: Flush iova queue before releasing dma_ops_domain
   iommu/amd: Use container_of to get dma_ops_domain

  drivers/iommu/Kconfig   |   1 +
  drivers/iommu/amd_iommu.c   | 976 
  drivers/iommu/amd_iommu_types.h |   1 -
  drivers/iommu/iommu.c   |   3 +
  include/linux/iommu.h   |   3 +
  5 files changed, 387 insertions(+), 597 deletions(-)



Re: [PATCH v2 03/10] Clocksource: add nuc970 clocksource driver

2016-07-12 Thread Wan Zongshun



On 2016年07月11日 23:36, Arnd Bergmann wrote:

On Sunday, July 10, 2016 3:27:23 PM CEST Wan Zongshun wrote:


+config NUC900_TIMER
+bool "Clocksource timer for nuc900 platform" if COMPILE_TEST
+depends on ARM
+select CLKSRC_OF if OF
+select CLKSRC_MMIO
+help
+  Enables the clocksource for the NUC900 platform.



I have put this patch into my randconfig build system and found that
it lacks a dependency:



diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index e18ef32776a3..59b9251eef37 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -523,7 +523,7 @@ config CLKSRC_ST_LPC

  config NUC900_TIMER
  bool "Clocksource timer for nuc900 platform" if COMPILE_TEST
-depends on ARM
+depends on ARM && GENERIC_CLOCKEVENTS
  select CLKSRC_OF if OF
  select CLKSRC_MMIO
  help



So this patch, I still need submit or you have merged it?



Also the init function has changed its return type in linux-next:


+static void __init nuc970_timer_of_init(struct device_node *node)


This now needs to return an error code or we get:

../include/linux/of.h:1004:20: error: comparison of distinct pointer types 
lacks a cast [-Werror]
 .data = (fn == (fn_type)NULL) ? fn : fn  }

Daniel Lezcano seems to have implemented a migration strategy, but I
can't see what you are supposed to do here, since the
CLOCKSOURCE_OF_DECLARE_RET macro is no longer part of linux-next.


Wait for Daniel's comments? or what should I do now?



Arnd




Re: [PATCH v2 01/10] ARM: NUC900: Add nuc970 machine support

2016-07-12 Thread Wan Zongshun



On 2016年07月12日 12:30, Wan Zongshun wrote:



On 2016年07月12日 00:04, Arnd Bergmann wrote:

On Sunday, July 10, 2016 3:27:21 PM CEST Wan Zongshun wrote:

+ifeq ($(CONFIG_SOC_NUC970),)
  obj-y  := irq.o time.o mfp.o gpio.o clock.o
  obj-y  += clksel.o dev.o cpu.o
+endif
  # W90X900 CPU support files


When mfp.o is disabled like this, I get a link error in two drivers
using the exported interface:

ERROR: "mfp_set_groupg" [drivers/spi/spi-nuc900.ko] undefined!
ERROR: "mfp_set_groupi" [drivers/input/keyboard/w90p910_keypad.ko]
undefined!


Why remove mfp modules? this multifunction pin driver should be used for
those two drivers, if no mfp_set_groupX, I don't think driver can work.

Now mfp has standard driver subsystem?



Any idea for a better migration strategy?


Arnd, If you still think the mfp should be removed, we can send a series 
patches to instead of using mfp interface quickly, and do mfp set in 
local driver. Do you think it is ok?




Arnd




___
linux-arm-kernel mailing list
linux-arm-ker...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


Re: [PATCH v2 02/10] irqchip: add irqchip driver for nuc900

2016-07-12 Thread Wan Zongshun



On 2016年07月11日 23:46, Arnd Bergmann wrote:

On Sunday, July 10, 2016 3:27:22 PM CEST Wan Zongshun wrote:

+
+#if !defined(CONFIG_SOC_NUC900)
  #define NR_IRQS(IRQ_ADC+1)
+#else
+#define NR_IRQS62
+#endif



The Kconfig symbols are a bit confusing here: CONFIG_SOC_NUC900
controls the compilation of the soc_device driver, but I guess
what you actually mean here is CONFIG_SOC_NUC970, which is the
support for the actual chip.

Maybe rename the former to something less confusing and change
this to CONFIG_SOC_NUC970?


You are right, it should _NUC970. Many thanks!



Ideally, this should just go away once we use SPARSE_IRQ.


This platform also can use SPARSE_IRQ? this just a simple irq map and no 
more irq number in this Soc.




Arnd

___
linux-arm-kernel mailing list
linux-arm-ker...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel




Re: [PATCH v2 01/10] ARM: NUC900: Add nuc970 machine support

2016-07-11 Thread Wan Zongshun



On 2016年07月12日 00:04, Arnd Bergmann wrote:

On Sunday, July 10, 2016 3:27:21 PM CEST Wan Zongshun wrote:

+ifeq ($(CONFIG_SOC_NUC970),)
  obj-y  := irq.o time.o mfp.o gpio.o clock.o
  obj-y  += clksel.o dev.o cpu.o
+endif
  # W90X900 CPU support files


When mfp.o is disabled like this, I get a link error in two drivers
using the exported interface:

ERROR: "mfp_set_groupg" [drivers/spi/spi-nuc900.ko] undefined!
ERROR: "mfp_set_groupi" [drivers/input/keyboard/w90p910_keypad.ko] undefined!


Why remove mfp modules? this multifunction pin driver should be used for 
those two drivers, if no mfp_set_groupX, I don't think driver can work.


Now mfp has standard driver subsystem?



Any idea for a better migration strategy?

Arnd




Re: [PATCH v2 06/10] soc: Add SoC specific driver support for nuc900

2016-07-11 Thread Wan ZongShun
2016-07-11 18:24 GMT+08:00 Arnd Bergmann :
> On Monday, July 11, 2016 5:07:01 PM CEST Wan Zongshun wrote:
>>
>> On 2016年07月11日 16:03, Arnd Bergmann wrote:
>> > On Sunday, July 10, 2016 3:27:26 PM CEST Wan Zongshun wrote:
>> >> +   ret = of_property_read_string(np, "compatible", 
>> >> &soc_dev_attr->soc_id);
>> >> +   if (ret)
>> >>return -EINVAL;
>> >> +
>> >> +   soc_dev_attr->machine = "NUC900EVB";
>> >> +   soc_dev_attr->family = "NUC900";
>> >> +   soc_dev = soc_device_register(soc_dev_attr);
>> >> +   if (IS_ERR(soc_dev)) {
>> >> +   kfree(soc_dev_attr);
>> >> +   return -ENODEV;
>> >> +   }
>> >> +
>> >> +   ret = regmap_read(syscon_regmap, GCR_CHIPID, &nuc900_chipid);
>> >> +   if (ret)
>> >> +   return -ENODEV;
>> >> +
>> >> +   device_create_file(soc_device_to_device(soc_dev), 
>> >> &nuc900_chipid_attr);
>> >> +   device_create_file(soc_device_to_device(soc_dev), 
>> >> &nuc900_version_attr);
>> >> +
>> >> +   dev_info(&pdev->dev, "Nuvoton Chip ID: 0x%x, Version ID:0x%x\n",
>> >> +nuc900_chipid & GCR_CHIPID_MASK,
>> >> +(nuc900_chipid >> 24) & 0xff);
>> >
>> > I'm still a bit unsure about the set of attributes here.
>> >
>> > - The "soc_id" is read from the device tree from the field that contains
>> >the board name, I think for consistency you should try to map the
>> >GCR_CHIPID to the name of the SoC and assign that here
>>
>> I will try to get chipid and map it to soc name like: “nuc970”, "nuc910".
>>
>> And I will set this soc name to soc_id, ok?
>
> Ok.

Maybe I also can set versionid as soc name partly, like
nuc970-version1,nuc970-version2? and then set the to soc_id, make
sense?


>
>> > - The "machine" is hardcoded to "NUC900EVB", which in turn looks like
>> >a particular board but not the one you are running on. Maybe read
>> >that from the DT instead?
>>
>> Should I read nuc970-evb.dts's "model" or "compatible" properties?
>
> I think "model" is best here, but see what the others do.
>
> Arnd
>



-- 
---
Vincent Wan(Zongshun)
www.mcuos.com


Re: [PATCH] iommu/amd: Fix unity mapping initialization race

2016-07-11 Thread Wan ZongShun
>
>> Sorry, why you still say this 'init_device_table_dma' can block DMA?
>> I just think this function will enable DMA transfer, since  we set
>> the V and TV bits, right? or I misunderstand what "block DMA" mean?
>
> When the V and TV bits are not set, it means that all DMA from that
> device-id is forwared untranslated by the IOMMU. But if we set V and TV
> it means that there is translation information, and the IOMMU translates
> the requests using the rest of the DTE information. As all other bits
> are 0, this means that page-table-level is 0 (== no page-table) and that
> the global IW and IR bits are 0 too (== no read and write permissions).
> So all requests are blocked.
>

Clearly.

Thanks.

>
>
> Joerg
>
> ___
> iommu mailing list
> io...@lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/iommu



-- 
---
Vincent Wan(Zongshun)
www.mcuos.com


Re: [PATCH] iommu/amd: Fix unity mapping initialization race

2016-07-11 Thread Wan Zongshun



On 2016年07月11日 15:19, Joerg Roedel wrote:

On Sun, Jul 10, 2016 at 07:40:53PM +0800, Wan Zongshun wrote:

Do you mean we need enable the V and TV bits to DTE entry after all
DTEs tables were initialized completely?


Yes, this is what my patch does and what fixes the bug that was
reported on machines which have unity-mapping entries.


Okay, this patch should also better to general case not only unity-mapping.

How about the interrupt remap function? Do we need same considering for 
IV bit enable for interrupt remap?





I checked this function 'init_device_table_dma', and find it just set
V and TV bit, to set translation info valid and DTE bits127:1 valid.


Right, if no other bits are set this blocks all DMA from the gives
device-id.


Sorry, why you still say this 'init_device_table_dma' can block DMA?
I just think this function will enable DMA transfer, since  we set the V 
and TV bits, right? or I misunderstand what "block DMA" mean?





So I just think all things it should to do are to allow DMA access,
GPA-to-SPA translation should be active, why you add function
comments below is to not allow DMA access and suppress all page
faults?

/*
  * Init the device table to not allow DMA access for devices and
  * suppress all page faults
  */


Yeah, that comment needs to be updated. Not all DMA is blocked and
page-faults are not suppressed at all. Thanks for noticing.



Joerg




Re: [PATCH v2 06/10] soc: Add SoC specific driver support for nuc900

2016-07-11 Thread Wan Zongshun



On 2016年07月11日 16:03, Arnd Bergmann wrote:

On Sunday, July 10, 2016 3:27:26 PM CEST Wan Zongshun wrote:

+   ret = of_property_read_string(np, "compatible", &soc_dev_attr->soc_id);
+   if (ret)
   return -EINVAL;
+
+   soc_dev_attr->machine = "NUC900EVB";
+   soc_dev_attr->family = "NUC900";
+   soc_dev = soc_device_register(soc_dev_attr);
+   if (IS_ERR(soc_dev)) {
+   kfree(soc_dev_attr);
+   return -ENODEV;
+   }
+
+   ret = regmap_read(syscon_regmap, GCR_CHIPID, &nuc900_chipid);
+   if (ret)
+   return -ENODEV;
+
+   device_create_file(soc_device_to_device(soc_dev), &nuc900_chipid_attr);
+   device_create_file(soc_device_to_device(soc_dev), &nuc900_version_attr);
+
+   dev_info(&pdev->dev, "Nuvoton Chip ID: 0x%x, Version ID:0x%x\n",
+nuc900_chipid & GCR_CHIPID_MASK,
+(nuc900_chipid >> 24) & 0xff);


I'm still a bit unsure about the set of attributes here.

- The "soc_id" is read from the device tree from the field that contains
   the board name, I think for consistency you should try to map the
   GCR_CHIPID to the name of the SoC and assign that here


I will try to get chipid and map it to soc name like: “nuc970”, "nuc910".

And I will set this soc name to soc_id, ok?



- The "machine" is hardcoded to "NUC900EVB", which in turn looks like
   a particular board but not the one you are running on. Maybe read
   that from the DT instead?


Should I read nuc970-evb.dts's "model" or "compatible" properties?



- The "revision" is not filled at all, I would suggest using something
   derived from the GCR_CHIPID register here

- you have two nonstandard attributes "chipid" and "version", which
   I'd hope to avoid -- the set of standard attributes is supposed to
   give enough information about the machine, and platform independent
   user space will never read those.

Arnd




Re: [PATCH v2 05/10] power/reset: Add reset driver support for nuc900

2016-07-10 Thread Wan Zongshun



On 2016年07月11日 05:56, Paul Gortmaker wrote:

On Sun, Jul 10, 2016 at 3:27 AM, Wan Zongshun  wrote

This driver is to add reset support for nuc900 series,
currently, it only supports nuc970 SoC reset.

Signed-off-by: Wan Zongshun 
---
  drivers/power/reset/Kconfig|  7 +++
  drivers/power/reset/Makefile   |  1 +
  drivers/power/reset/nuc900-reset.c | 93 ++
  3 files changed, 101 insertions(+)
  create mode 100644 drivers/power/reset/nuc900-reset.c

diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 9bb2622..8c84892 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -94,6 +94,13 @@ config POWER_RESET_MSM
 help
   Power off and restart support for Qualcomm boards.

+config POWER_RESET_NUC900
+   bool "Nuc900 restart driver"


If this driver is bool and not tristate, then please remove all references
to MODULE_ and then the module.h include as well.


I will remove the following codes in my reset.c driver.

MODULE_DEVICE_TABLE(of, of_nuc900_reset_match);
#include 




Thanks,
Paul.
--


+   depends on ARCH_W90X900
+   help
+ Power off and restart support for Nuvoton NUC900 family of
+ reference boards.
+
  config POWER_RESET_LTC2952
 bool "LTC2952 PowerPath power-off driver"
 depends on OF_GPIO
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index ab7aa86..d4df889 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
  obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o
  obj-$(CONFIG_POWER_RESET_IMX) += imx-snvs-poweroff.o
  obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
+obj-$(CONFIG_POWER_RESET_NUC900) += nuc900-reset.o
  obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
  obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
  obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
diff --git a/drivers/power/reset/nuc900-reset.c 
b/drivers/power/reset/nuc900-reset.c
new file mode 100644
index 000..49986b7
--- /dev/null
+++ b/drivers/power/reset/nuc900-reset.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 



[...]

___
linux-arm-kernel mailing list
linux-arm-ker...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel




Re: [PATCH v2 02/10] irqchip: add irqchip driver for nuc900

2016-07-10 Thread Wan Zongshun



On 2016年07月11日 05:51, Paul Gortmaker wrote:

On Sun, Jul 10, 2016 at 3:27 AM, Wan Zongshun  wrote:

This patch is to add irqchip driver support for nuc900 plat,
current this driver only supports nuc970 SoC.

Signed-off-by: Wan Zongshun 
---
  arch/arm/mach-w90x900/include/mach/irqs.h |   5 +
  drivers/irqchip/Makefile  |   1 +
  drivers/irqchip/irq-nuc900.c  | 150 ++
  3 files changed, 156 insertions(+)
  create mode 100644 drivers/irqchip/irq-nuc900.c

diff --git a/arch/arm/mach-w90x900/include/mach/irqs.h 
b/arch/arm/mach-w90x900/include/mach/irqs.h
index 9d5cba3..3b035c6 100644
--- a/arch/arm/mach-w90x900/include/mach/irqs.h
+++ b/arch/arm/mach-w90x900/include/mach/irqs.h
@@ -59,7 +59,12 @@
  #define IRQ_KPIW90X900_IRQ(29)
  #define IRQ_P2SGROUP   W90X900_IRQ(30)
  #define IRQ_ADCW90X900_IRQ(31)
+
+#if !defined(CONFIG_SOC_NUC900)
  #define NR_IRQS(IRQ_ADC+1)
+#else
+#define NR_IRQS62
+#endif

  /*for irq group*/

diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 38853a1..9ccd5af8a 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -69,3 +69,4 @@ obj-$(CONFIG_PIC32_EVIC)  += irq-pic32-evic.o
  obj-$(CONFIG_MVEBU_ODMI)   += irq-mvebu-odmi.o
  obj-$(CONFIG_LS_SCFG_MSI)  += irq-ls-scfg-msi.o
  obj-$(CONFIG_EZNPS_GIC)+= irq-eznps.o
+obj-$(CONFIG_SOC_NUC970)   += irq-nuc900.o
diff --git a/drivers/irqchip/irq-nuc900.c b/drivers/irqchip/irq-nuc900.c
new file mode 100644
index 000..c4b2e39
--- /dev/null
+++ b/drivers/irqchip/irq-nuc900.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include 


Why do you include module.h when I don't see anything modular in
this driver?


Okay, I can delete it.



Paul.
--


+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+


[...]

___
linux-arm-kernel mailing list
linux-arm-ker...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel




Re: [PATCH v2 09/10] Documentation: devicetree: Add dts description for nuc900

2016-07-10 Thread Wan Zongshun



On 2016年07月11日 06:17, Arnd Bergmann wrote:

On Sunday, July 10, 2016 3:42:21 PM CEST Wan Zongshun wrote:

+
+Required properties:
+- compatible : Should be "nuvoton,nuc970-tmr"
+- reg : Address and length of the register set
+- clocks : Reference on the timer input clock
+- interrupts : Reference to the timer interrupt
+
+Example:
+
+tmr@0xb8001000 {


The name should be "timer", not "tmr", and the address should
not contain a leading "0x".


Ok, so all dts addresses has no need contain a leading "0x"?




+   compatible = "nuvoton,nuc970-tmr";
+   reg = <0xb8001000 0x1000>;
+   interrupts = <16>;
+   clocks = <&clks TIMER0_GATE>,
+   <&clks TIMER1_GATE>;
+   clock-names = "timer0", "timer1";
+};


The clocks/clock-names description does not match the example:
you only define a single clock in the required properties, but
have two separate inputs in the example. Please fix one or the
other.


Two clocks are necessary, so I only need modify this description like?

Required properties:
  clocks : Reference on the timer input clock, This list should be 2
   clocks, the order is timer0 , timer1.

Is it ok?



Arnd




Re: [PATCH] iommu/amd: Fix unity mapping initialization race

2016-07-10 Thread Wan Zongshun



On 2016年07月07日 00:00, Joerg Roedel wrote:

From: Joerg Roedel 

There is a race condition in the AMD IOMMU init code that
causes requested unity mappings to be blocked by the IOMMU
for a short period of time. This results on boot failures
and IO_PAGE_FAULTs on some machines.

Fix this by making sure the unity mappings are installed
before all other DMA is blocked.

Fixes: aafd8ba0ca74 ('iommu/amd: Implement add_device and remove_device')
Cc: sta...@vger.kernel.org # v4.2+
Signed-off-by: Joerg Roedel 
---
  drivers/iommu/amd_iommu_init.c | 14 --
  1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index d091def..59741ea 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -1568,13 +1568,23 @@ static int __init amd_iommu_init_pci(void)
break;
}

+   /*
+* Order is important here to make sure any unity map requirements are
+* fulfilled. The unity mappings are created and written to the device
+* table during the amd_iommu_init_api() call.
+*
+* After that we call init_device_table_dma() to make sure any
+* uninitialized DTE will block DMA, and in the end we flush the caches
+* of all IOMMUs to make sure the changes to the device table are
+* active.
+*/


Joerg,

Do you mean we need enable the V and TV bits to DTE entry after all DTEs 
tables were initialized completely?


I checked this function 'init_device_table_dma', and find it just set
V and TV bit, to set translation info valid and DTE bits127:1 valid.

So I just think all things it should to do are to allow DMA access,
GPA-to-SPA translation should be active, why you add function comments 
below is to not allow DMA access and suppress all page faults?


/*
 * Init the device table to not allow DMA access for devices and
 * suppress all page faults
 */
static void init_device_table_dma(void)


+   ret = amd_iommu_init_api();
+
init_device_table_dma();

for_each_iommu(iommu)
iommu_flush_all_caches(iommu);

-   ret = amd_iommu_init_api();
-
if (!ret)
print_iommu_info();




[PATCH v2 10/10] nuc900: add nuc970 platform defconfig file

2016-07-10 Thread Wan Zongshun
Add nuc970_defconfig file support.

Signed-off-by: Wan Zongshun 
---
 arch/arm/configs/nuc970_defconfig | 76 +++
 1 file changed, 76 insertions(+)
 create mode 100644 arch/arm/configs/nuc970_defconfig

diff --git a/arch/arm/configs/nuc970_defconfig 
b/arch/arm/configs/nuc970_defconfig
new file mode 100644
index 000..b39a406
--- /dev/null
+++ b/arch/arm/configs/nuc970_defconfig
@@ -0,0 +1,76 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_PERF=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="../rootfs"
+CONFIG_PERF_EVENTS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_ARCH_W90X900=y
+CONFIG_SOC_NUC970=y
+# CONFIG_MACH_W90P910EVB is not set
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_CMDLINE="root=/dev/ram0 console=ttyS0,115200n8 rdinit=/sbin/init 
mem=64M"
+CONFIG_KEXEC=y
+CONFIG_FPE_NWFPE=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_SUSPEND is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_SCSI=y
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_NUC970=y
+CONFIG_SERIAL_NUC970_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_NUC900=y
+# CONFIG_HWMON is not set
+# CONFIG_HID is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_IOMMU_SUPPORT is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_ROMFS_FS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_MESSAGE_LOGLEVEL_DEFAULT=7
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_DEBUG_FS=y
+CONFIG_RCU_CPU_STALL_TIMEOUT=300
+CONFIG_STRICT_DEVMEM=y
+# CONFIG_ARM_UNWIND is not set
-- 
2.7.4



[PATCH v2 09/10] Documentation: devicetree: Add dts description for nuc900

2016-07-10 Thread Wan Zongshun
This patch is to add dts description for nuc900 platform.

Signed-off-by: Wan Zongshun 
---
 .../devicetree/bindings/arm/nuvoton/nuc970.txt | 12 
 .../bindings/clock/nuvoton,nuc970-clk.txt  | 13 +
 .../interrupt-controller/nuvoton,nuc900-aic.txt| 15 +++
 .../bindings/reset/nuvoton,nuc900-reset.txt| 12 
 .../devicetree/bindings/serial/nuc970-uart.txt | 22 ++
 .../bindings/soc/nuvoton/nuvoton,nuc900-soc.txt| 12 
 .../bindings/timer/nuvoton,nuc970-tmr.txt  | 20 
 7 files changed, 106 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/nuvoton/nuc970.txt
 create mode 100644 
Documentation/devicetree/bindings/clock/nuvoton,nuc970-clk.txt
 create mode 100644 
Documentation/devicetree/bindings/interrupt-controller/nuvoton,nuc900-aic.txt
 create mode 100644 
Documentation/devicetree/bindings/reset/nuvoton,nuc900-reset.txt
 create mode 100644 Documentation/devicetree/bindings/serial/nuc970-uart.txt
 create mode 100644 
Documentation/devicetree/bindings/soc/nuvoton/nuvoton,nuc900-soc.txt
 create mode 100644 
Documentation/devicetree/bindings/timer/nuvoton,nuc970-tmr.txt

diff --git a/Documentation/devicetree/bindings/arm/nuvoton/nuc970.txt 
b/Documentation/devicetree/bindings/arm/nuvoton/nuc970.txt
new file mode 100644
index 000..0872f6f
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/nuvoton/nuc970.txt
@@ -0,0 +1,12 @@
+Nuvoton NUC970 SoC platform Device Tree Bindings
+--
+
+Boards with the NUC970 SoC shall have the following properties:
+
+Root node required properties:
+- compatible: Should be "syscon" or "nuvoton,nuc970-gcr"
+
+GCR register required properties:
+- compatible: Should be "nuvoton,nuc970-gcr"
+- reg: Should contain registers location and length
+
diff --git a/Documentation/devicetree/bindings/clock/nuvoton,nuc970-clk.txt 
b/Documentation/devicetree/bindings/clock/nuvoton,nuc970-clk.txt
new file mode 100644
index 000..82fcf32
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/nuvoton,nuc970-clk.txt
@@ -0,0 +1,13 @@
+NUC970 Clock Controller
+
+Clock required properties:
+- compatible: Should be "nuvoton,nuc970-clk"
+- reg: Should contain registers location and length
+
+Examples:
+
+clks: clk@b200 {
+   compatible = "nuvoton,nuc970-clk";
+   reg = <0xb200 0x200>;
+   #clock-cells = <1>;
+};
diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/nuvoton,nuc900-aic.txt 
b/Documentation/devicetree/bindings/interrupt-controller/nuvoton,nuc900-aic.txt
new file mode 100644
index 000..f265095
--- /dev/null
+++ 
b/Documentation/devicetree/bindings/interrupt-controller/nuvoton,nuc900-aic.txt
@@ -0,0 +1,15 @@
+NUC900 interrupt Controller
+
+Interrupt-controller required properties
+- compatible: Should be "nuvoton,nuc900-aic"
+- reg: Should contain registers location and length
+- interrupt-cells: set to 1
+
+Examples:
+
+aic: interrupt-controller@b8002000 {
+   compatible = "nuvoton,nuc900-aic";
+   interrupt-controller;
+   #interrupt-cells = <1>;
+   reg = <0xb8002000 0x1000>;
+};
diff --git a/Documentation/devicetree/bindings/reset/nuvoton,nuc900-reset.txt 
b/Documentation/devicetree/bindings/reset/nuvoton,nuc900-reset.txt
new file mode 100644
index 000..ab6056a
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/nuvoton,nuc900-reset.txt
@@ -0,0 +1,12 @@
+. Nuvoton NUC900 series, reset controller binding.
+
+Required properties:
+- compatible : Should be "nuvoton,nuc900-reset"
+- syscon : Reference to gcr controller.
+
+Example:
+
+reset {
+   compatible = "nuvoton,nuc900-reset";
+   syscon = <&gcr>;
+};
diff --git a/Documentation/devicetree/bindings/serial/nuc970-uart.txt 
b/Documentation/devicetree/bindings/serial/nuc970-uart.txt
new file mode 100644
index 000..a143a5e
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/nuc970-uart.txt
@@ -0,0 +1,22 @@
+NUC970 UART Controller
+
+Uart required properties:
+- compatible: Should be "nuvoton,nuc970-uart"
+- reg: Should contain registers location and length
+
+Examples:
+
+aliases {
+   serial0 = &uart0;
+};
+
+uart0: serial@b800 {
+   compatible = "nuvoton,nuc970-uart";
+   reg = <0xb800 0x1000>;
+   interrupts = <36>;
+   clocks = <&clks UART0_GATE>,
+<&clks UART0_ECLK_GATE>;
+   clock-names = "uart0", "uart0_eclk";
+   clock-frequency = <1200>;
+   status = "disabled";
+};
diff --git 
a/Documentation/devicetree/bindings/soc/nuvoton/nuvoton,nuc900-soc.txt 
b/Documentation/devicetree/bindings/soc/nuvoton/nuvoton,nuc900-soc.txt
new file mode 100644
index 000..0284edf
---

[PATCH v2 08/10] ARM: dts: nuc900: Add nuc970 dts files

2016-07-10 Thread Wan Zongshun
This patch is to add dts support for nuc970 platform.

Signed-off-by: Wan Zongshun 
---
 arch/arm/boot/dts/Makefile   |  1 +
 arch/arm/boot/dts/nuc970-evb.dts | 34 
 arch/arm/boot/dts/nuc970.dtsi| 88 
 3 files changed, 123 insertions(+)
 create mode 100644 arch/arm/boot/dts/nuc970-evb.dts
 create mode 100644 arch/arm/boot/dts/nuc970.dtsi

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 414b427..557477d 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -892,6 +892,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \
 dtb-$(CONFIG_ARCH_ZX) += zx296702-ad1.dtb
 dtb-$(CONFIG_ARCH_ASPEED) += aspeed-bmc-opp-palmetto.dtb \
aspeed-ast2500-evb.dtb
+dtb-$(CONFIG_SOC_NUC970) += nuc970-evb.dtb
 endif
 
 dtstree:= $(srctree)/$(src)
diff --git a/arch/arm/boot/dts/nuc970-evb.dts b/arch/arm/boot/dts/nuc970-evb.dts
new file mode 100644
index 000..ae3fe90
--- /dev/null
+++ b/arch/arm/boot/dts/nuc970-evb.dts
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+#include "nuc970.dtsi"
+
+/ {
+   model = "Nuvoton NUC970 Development Board";
+   compatible = "nuvoton,nuc970";
+
+   aliases {
+   serial0 = &uart0;
+   };
+
+   memory {
+   reg = <0x 0x0400>;
+   };
+
+   soc {
+   apb@b800 {
+   uart0: serial@b800 {
+   status = "okay";
+   };
+   };
+   };
+};
diff --git a/arch/arm/boot/dts/nuc970.dtsi b/arch/arm/boot/dts/nuc970.dtsi
new file mode 100644
index 000..d476abd
--- /dev/null
+++ b/arch/arm/boot/dts/nuc970.dtsi
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include "skeleton.dtsi"
+#include 
+
+/ {
+   soc {
+   #address-cells = <1>;
+   #size-cells = <1>;
+   compatible = "simple-bus";
+   interrupt-parent = <&aic>;
+   ranges;
+
+   ahb@b000 {
+   compatible = "simple-bus";
+   #address-cells = <1>;
+   #size-cells = <1>;
+   ranges;
+
+   gcr: syscon@b000 {
+   compatible = "syscon", "nuvoton,nuc970-gcr";
+   reg = <0xb000 0x200>;
+   };
+
+   soc {
+   compatible = "nuvoton,nuc900-soc";
+   syscon = <&gcr>;
+   };
+
+   reset {
+   compatible = "nuvoton,nuc900-reset";
+   syscon = <&gcr>;
+   };
+
+   clks: clk@b200 {
+   compatible = "nuvoton,nuc970-clk";
+   reg = <0xb200 0x200>;
+   #clock-cells = <1>;
+   };
+
+   };
+
+   apb@b800 {
+   compatible = "simple-bus";
+   #address-cells = <1>;
+   #size-cells = <1>;
+   ranges;
+
+   aic: interrupt-controller@b8002000 {
+   compatible = "nuvoton,nuc900-aic";
+   interrupt-controller;
+   #interrupt-cells = <1>;
+   reg = <0xb8002000 0x1000>;
+   };
+
+
+   tmr@0xb8001000 {
+   compatible = "nuvoton,nuc970-tmr";
+   reg = <0xb8001000 0x1000>;
+   interrupts = <16>;
+   clocks = <&clks TIMER0_GATE>,
+<&clks TIMER1_GATE>;
+   clock-names = "timer0", "timer1";
+
+   };
+
+   uar

[PATCH v2 04/10] clk: add Clock driver for nuc970

2016-07-10 Thread Wan Zongshun
This patch is to add clock framework driver for nuc970.
The clock controller generates all clocks for Video, Audio,
CPU, system bus and all functionalities, nuc970 includes
two PLL modules.

Signed-off-by: Wan Zongshun 
---
 drivers/clk/Makefile|   1 +
 drivers/clk/nuc900/Makefile |   6 +
 drivers/clk/nuc900/clk-apll.c   | 168 
 drivers/clk/nuc900/clk-ccf.h|  53 +++
 drivers/clk/nuc900/clk-nuc970.c | 925 
 drivers/clk/nuc900/clk-upll.c   |  83 
 6 files changed, 1236 insertions(+)
 create mode 100644 drivers/clk/nuc900/Makefile
 create mode 100644 drivers/clk/nuc900/clk-apll.c
 create mode 100644 drivers/clk/nuc900/clk-ccf.h
 create mode 100644 drivers/clk/nuc900/clk-nuc970.c
 create mode 100644 drivers/clk/nuc900/clk-upll.c

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index dcc5e69..042377d 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -88,3 +88,4 @@ obj-$(CONFIG_ARCH_ZX) += zte/
 obj-$(CONFIG_ARCH_ZYNQ)+= zynq/
 obj-$(CONFIG_H8300)+= h8300/
 obj-$(CONFIG_ARC_PLAT_AXS10X)  += axs10x/
+obj-$(CONFIG_ARCH_W90X900) += nuc900/
diff --git a/drivers/clk/nuc900/Makefile b/drivers/clk/nuc900/Makefile
new file mode 100644
index 000..a6785ab
--- /dev/null
+++ b/drivers/clk/nuc900/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for nuvoton specific clk
+#
+
+obj-$(CONFIG_SOC_NUC970) += clk-apll.o clk-upll.o clk-nuc970.o
+
diff --git a/drivers/clk/nuc900/clk-apll.c b/drivers/clk/nuc900/clk-apll.c
new file mode 100644
index 000..a05aec7
--- /dev/null
+++ b/drivers/clk/nuc900/clk-apll.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "clk-ccf.h"
+
+struct clk_apll {
+   struct clk_hw   hw;
+   void __iomem*base;
+};
+
+#define to_clk_apll(clk) (container_of(clk, struct clk_apll, clk))
+
+static int clk_apll_set_rate(struct clk_hw *hw, unsigned long rate,
+unsigned long parent_rate)
+{
+   struct clk_apll *pll = to_clk_apll(hw);
+   unsigned long reg;
+
+   reg = readl(pll->base) & ~0x0FFF;
+
+   switch (rate) {
+   /*usbh*/
+   case 9600:
+   reg |= 0x8027;
+   break;
+   /*i2s*/
+   case 9840:
+   reg |= 0x8028;
+   break;
+   /*i2s*/
+   case 16950:
+   reg |= 0x21f0;
+   break;
+   /*system default, 264MHz*/
+   case 26400:
+   reg |= 0x15;
+   break;
+   case 3:
+   reg |= 0x18;
+   break;
+   default:
+   reg |= 0x15;
+   break;
+   }
+
+   writel(reg, pll->base);
+
+   return 0;
+}
+
+static unsigned long clk_apll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+   struct clk_apll *pll = to_clk_apll(hw);
+   unsigned long reg = readl(pll->base) & 0x0FFF;
+   unsigned long rate;
+
+   if (parent_rate != 1200)
+   return 0;
+
+   switch (reg) {
+   /*system default, 264MHz*/
+   case 0x15:
+   rate = 26400;
+   break;
+   case 0x18:
+   rate = 3;
+   break;
+   /*usbh*/
+   case 0x8027:
+   rate = 9600;
+   break;
+   /*i2s*/
+   case 0x8028:
+   rate = 9840;
+   break;
+   /*i2s*/
+   case 0x21f0:
+   rate = 16950;
+   break;
+   default:
+   rate = 26400;
+   break;
+   }
+
+   return rate;
+}
+
+static long clk_apll_round_rate(struct clk_hw *hw, unsigned long rate,
+   unsigned long *prate)
+{
+   return rate;
+}
+
+static int clk_apll_enable(struct clk_hw *hw)
+{
+   struct clk_apll *pll = to_clk_apll(hw);
+   unsigned long val;
+
+   val = readl(pll->base);
+   val &= ~0x1000;
+   val |= 0x4000;
+   writel(val, pll->base);
+
+   return 0;
+}
+
+static void clk_apll_disable(struct clk_hw *hw)
+{
+   struct clk_apll *pll = to_clk_apll(hw);
+   unsigned long val;
+
+   val = readl(pll->base);
+   val |= 0x1000;
+   val &= ~0x4000;
+   writel(val, pll->base);
+}
+
+static struct clk_ops clk_apll_ops = {
+   .recalc_rate = clk_apll_recalc_rate,
+   .enable = clk_apll_enable,
+   .disable = clk_apll_disable,
+   .se

[PATCH v2 00/10] ARM: NUC900: Add NUC970 SoC support

2016-07-10 Thread Wan Zongshun
Hi,

This patch series added Nuvoton new SoC NUC970 development board
support, this nuc970 belongs to nuc900 series, but many features are
not compatible with old nuc900 SoCs like nuc910, nuc920.

Those patches are basing on old w90x900 codes, and are using standard
linux subsystem interface, such as dts, driver/clk, driver/clocksource
, driver/irqchip drivers.

The old w90x900 plat such as nuc910,nuc960 codes will also be changed
to new style according to nuc970 codes after those patches was accepted.

PATCH V2:
The V2 patches change some code style, re-archtect some drivers and add reset
and soc drivers, split some dts patches according to maillist's comments.

Wan Zongshun (10):
  ARM: NUC900: Add nuc970 machine support
  irqchip: add irqchip driver for nuc900
  Clocksource: add nuc970 clocksource driver
  clk: add Clock driver for nuc970
  power/reset: Add reset driver support for nuc900
  soc: Add SoC specific driver support for nuc900
  ARM: dts: Add clock header file into dt-bindings
  ARM: dts: nuc900: Add nuc970 dts files
  Documentation: devicetree: Add dts description for nuc900
  nuc900: add nuc970 platform defconfig file

 .../devicetree/bindings/arm/nuvoton/nuc970.txt |  12 +
 .../bindings/clock/nuvoton,nuc970-clk.txt  |  13 +
 .../interrupt-controller/nuvoton,nuc900-aic.txt|  15 +
 .../bindings/reset/nuvoton,nuc900-reset.txt|  12 +
 .../devicetree/bindings/serial/nuc970-uart.txt |  22 +
 .../bindings/soc/nuvoton/nuvoton,nuc900-soc.txt|  12 +
 .../bindings/timer/nuvoton,nuc970-tmr.txt  |  20 +
 arch/arm/boot/dts/Makefile |   1 +
 arch/arm/boot/dts/nuc970-evb.dts   |  34 +
 arch/arm/boot/dts/nuc970.dtsi  |  88 ++
 arch/arm/configs/nuc970_defconfig  |  76 ++
 arch/arm/mach-w90x900/Kconfig  |  20 +
 arch/arm/mach-w90x900/Makefile |   3 +
 arch/arm/mach-w90x900/include/mach/irqs.h  |   5 +
 arch/arm/mach-w90x900/nuc900.c |  41 +
 drivers/clk/Makefile   |   1 +
 drivers/clk/nuc900/Makefile|   6 +
 drivers/clk/nuc900/clk-apll.c  | 168 
 drivers/clk/nuc900/clk-ccf.h   |  53 ++
 drivers/clk/nuc900/clk-nuc970.c| 925 +
 drivers/clk/nuc900/clk-upll.c  |  83 ++
 drivers/clocksource/Kconfig|   8 +
 drivers/clocksource/Makefile   |   1 +
 drivers/clocksource/timer-nuc900.c | 305 +++
 drivers/irqchip/Makefile   |   1 +
 drivers/irqchip/irq-nuc900.c   | 150 
 drivers/power/reset/Kconfig|   7 +
 drivers/power/reset/Makefile   |   1 +
 drivers/power/reset/nuc900-reset.c |  93 +++
 drivers/soc/Kconfig|   1 +
 drivers/soc/Makefile   |   1 +
 drivers/soc/nuvoton/Kconfig|  10 +
 drivers/soc/nuvoton/Makefile   |   1 +
 drivers/soc/nuvoton/soc-nuc900.c   | 100 +++
 include/dt-bindings/clock/nuc970-clock.h   | 233 ++
 35 files changed, 2522 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/nuvoton/nuc970.txt
 create mode 100644 
Documentation/devicetree/bindings/clock/nuvoton,nuc970-clk.txt
 create mode 100644 
Documentation/devicetree/bindings/interrupt-controller/nuvoton,nuc900-aic.txt
 create mode 100644 
Documentation/devicetree/bindings/reset/nuvoton,nuc900-reset.txt
 create mode 100644 Documentation/devicetree/bindings/serial/nuc970-uart.txt
 create mode 100644 
Documentation/devicetree/bindings/soc/nuvoton/nuvoton,nuc900-soc.txt
 create mode 100644 
Documentation/devicetree/bindings/timer/nuvoton,nuc970-tmr.txt
 create mode 100644 arch/arm/boot/dts/nuc970-evb.dts
 create mode 100644 arch/arm/boot/dts/nuc970.dtsi
 create mode 100644 arch/arm/configs/nuc970_defconfig
 create mode 100644 arch/arm/mach-w90x900/nuc900.c
 create mode 100644 drivers/clk/nuc900/Makefile
 create mode 100644 drivers/clk/nuc900/clk-apll.c
 create mode 100644 drivers/clk/nuc900/clk-ccf.h
 create mode 100644 drivers/clk/nuc900/clk-nuc970.c
 create mode 100644 drivers/clk/nuc900/clk-upll.c
 create mode 100644 drivers/clocksource/timer-nuc900.c
 create mode 100644 drivers/irqchip/irq-nuc900.c
 create mode 100644 drivers/power/reset/nuc900-reset.c
 create mode 100644 drivers/soc/nuvoton/Kconfig
 create mode 100644 drivers/soc/nuvoton/Makefile
 create mode 100644 drivers/soc/nuvoton/soc-nuc900.c
 create mode 100644 include/dt-bindings/clock/nuc970-clock.h

-- 
2.7.4



[PATCH v2 06/10] soc: Add SoC specific driver support for nuc900

2016-07-10 Thread Wan Zongshun
This patch is to add SoC specific driver for nuc970 SoC,
it is for getting nuc970 version id and chip id.

Signed-off-by: Wan Zongshun 
---
 drivers/soc/Kconfig  |   1 +
 drivers/soc/Makefile |   1 +
 drivers/soc/nuvoton/Kconfig  |  10 
 drivers/soc/nuvoton/Makefile |   1 +
 drivers/soc/nuvoton/soc-nuc900.c | 100 +++
 5 files changed, 113 insertions(+)
 create mode 100644 drivers/soc/nuvoton/Kconfig
 create mode 100644 drivers/soc/nuvoton/Makefile
 create mode 100644 drivers/soc/nuvoton/soc-nuc900.c

diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index cb58ef0..2119733 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -4,6 +4,7 @@ source "drivers/soc/bcm/Kconfig"
 source "drivers/soc/brcmstb/Kconfig"
 source "drivers/soc/fsl/qe/Kconfig"
 source "drivers/soc/mediatek/Kconfig"
+source "drivers/soc/nuvoton/Kconfig"
 source "drivers/soc/qcom/Kconfig"
 source "drivers/soc/rockchip/Kconfig"
 source "drivers/soc/samsung/Kconfig"
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 380230f..bb1bfba 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_ARCH_DOVE) += dove/
 obj-$(CONFIG_MACH_DOVE)+= dove/
 obj-y  += fsl/
 obj-$(CONFIG_ARCH_MEDIATEK)+= mediatek/
+obj-$(CONFIG_SOC_NUC900)   += nuvoton/
 obj-$(CONFIG_ARCH_QCOM)+= qcom/
 obj-$(CONFIG_ARCH_RENESAS) += renesas/
 obj-$(CONFIG_ARCH_ROCKCHIP)+= rockchip/
diff --git a/drivers/soc/nuvoton/Kconfig b/drivers/soc/nuvoton/Kconfig
new file mode 100644
index 000..53c106c
--- /dev/null
+++ b/drivers/soc/nuvoton/Kconfig
@@ -0,0 +1,10 @@
+#
+# ARM Versatile SoC drivers
+#
+config SOC_NUC900
+   bool "SoC bus device for the nuvoton NUC900 platforms"
+   depends on ARCH_W90X900
+   select SOC_BUS
+   help
+ Include support for the SoC bus on the NUC900 platforms
+ providing some sysfs information about the ASIC variant.
diff --git a/drivers/soc/nuvoton/Makefile b/drivers/soc/nuvoton/Makefile
new file mode 100644
index 000..88f9b7e
--- /dev/null
+++ b/drivers/soc/nuvoton/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SOC_NUC900)   += soc-nuc900.o
diff --git a/drivers/soc/nuvoton/soc-nuc900.c b/drivers/soc/nuvoton/soc-nuc900.c
new file mode 100644
index 000..034ef94
--- /dev/null
+++ b/drivers/soc/nuvoton/soc-nuc900.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* System ID in syscon */
+#define GCR_CHIPID 0x00
+#define GCR_CHIPID_MASK0x00ff
+
+static const struct of_device_id nuc900_soc_of_match[] = {
+   { .compatible = "nuvoton,nuc900-soc",   },
+   { }
+};
+
+static u32 nuc900_chipid;
+
+static ssize_t nuc900_get_chipid(struct device *dev,
+struct device_attribute *attr,
+char *buf)
+{
+   return sprintf(buf, "0x%x\n", nuc900_chipid & GCR_CHIPID_MASK);
+}
+
+static struct device_attribute nuc900_chipid_attr =
+   __ATTR(manufacturer,  S_IRUGO, nuc900_get_chipid,  NULL);
+
+static ssize_t nuc900_get_versionid(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+   return sprintf(buf, "0x%x\n", (nuc900_chipid >> 24) & 0xff);
+}
+
+static struct device_attribute nuc900_version_attr =
+   __ATTR(board,  S_IRUGO, nuc900_get_versionid,  NULL);
+
+static int nuc900_soc_probe(struct platform_device *pdev)
+{
+   static struct regmap *syscon_regmap;
+   struct soc_device *soc_dev;
+   struct soc_device_attribute *soc_dev_attr;
+   struct device_node *np = pdev->dev.of_node;
+   int ret;
+
+   syscon_regmap = syscon_regmap_lookup_by_phandle(np, "syscon");
+   if (IS_ERR(syscon_regmap))
+   return PTR_ERR(syscon_regmap);
+
+   soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+   if (!soc_dev_attr)
+   return -ENOMEM;
+
+   ret = of_property_read_string(np, "compatible", &soc_dev_attr->soc_id);
+   if (ret)
+   return -EINVAL;
+
+   soc_dev_attr->machine = "NUC900EVB";
+   soc_dev_attr->family = "NUC900";
+   soc_dev = soc_device_register(soc_dev_attr);
+   if (IS_ERR(soc_dev)) {
+   kfree(soc_dev_attr);
+   return -ENODEV

[PATCH v2 03/10] Clocksource: add nuc970 clocksource driver

2016-07-10 Thread Wan Zongshun
This patch is to add nuc970 clocksource driver support.

NUC970 general timer controller includes five channels, TIMER0, TIMER1,
TIMER2, TIMER3, and TIMER4, which allow user to easily implement a
counting scheme or timing control for applications.The timer possesses
features such as adjustable resolution, and programmable counting period.
The timer can generate an interrupt signal upon timeout, or provide the
current value of count during operation.

Currently, we are using TIMER0 and TIMER1 for clocksource and clockevent
device driver support.

Signed-off-by: Wan Zongshun 
---
 drivers/clocksource/Kconfig|   8 +
 drivers/clocksource/Makefile   |   1 +
 drivers/clocksource/timer-nuc900.c | 305 +
 3 files changed, 314 insertions(+)
 create mode 100644 drivers/clocksource/timer-nuc900.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 47352d2..441c5ee 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -427,4 +427,12 @@ config CLKSRC_ST_LPC
  Enable this option to use the Low Power controller timer
  as clocksource.
 
+config NUC900_TIMER
+bool "Clocksource timer for nuc900 platform" if COMPILE_TEST
+depends on ARM
+select CLKSRC_OF if OF
+select CLKSRC_MMIO
+help
+  Enables the clocksource for the NUC900 platform.
+
 endmenu
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 473974f..c74e252 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -67,3 +67,4 @@ obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o
 obj-$(CONFIG_H8300_TPU)+= h8300_tpu.o
 obj-$(CONFIG_CLKSRC_ST_LPC)+= clksrc_st_lpc.o
 obj-$(CONFIG_X86_NUMACHIP) += numachip.o
+obj-$(CONFIG_NUC900_TIMER) += timer-nuc900.o
diff --git a/drivers/clocksource/timer-nuc900.c 
b/drivers/clocksource/timer-nuc900.c
new file mode 100644
index 000..28ccbcf
--- /dev/null
+++ b/drivers/clocksource/timer-nuc900.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#define TMR_TCSR0  0x00
+#define TMR_TICR0  0x04
+#define TMR_TDR0   0x08
+#define TMR_TCSR1  0x10
+#define TMR_TICR1  0x14
+#define TMR_TDR1   0x18
+#define TMR_TISR   0x60
+
+#define RESETINT   0x1f
+#define PERIODIC   (0x01 << 27)
+#define ONESHOT(0x00 << 27)
+#define COUNTEN(0x01 << 30)
+#define INTEN  (0x01 << 29)
+
+#define TICKS_PER_SEC  100
+/* Divider = prescale + 1 */
+#define PRESCALE   0x63
+
+#defineTDR_SHIFT   24
+#defineTDR_MASK((1 << TDR_SHIFT) - 1)
+#define OPMODE_MASK~(0x03 << 27)
+
+struct nuc970_clockevents {
+   struct clock_event_device clkevt;
+   unsigned int timer0_load;
+   void __iomem *base;
+};
+
+struct nuc970_clockevents *clkevt_to_nuc970(struct clock_event_device *clk)
+{
+   return container_of(clk, struct nuc970_clockevents, clkevt);
+}
+
+static int nuc970_clockevent_set(bool periodic, struct clock_event_device *clk)
+{
+   struct nuc970_clockevents *evt = clkevt_to_nuc970(clk);
+   unsigned int val;
+
+   val = readl(evt->base + TMR_TCSR0);
+   val &= OPMODE_MASK;
+
+   writel(evt->timer0_load, evt->base + TMR_TICR0);
+
+   val |= periodic ? PERIODIC:ONESHOT;
+   val |= (COUNTEN | INTEN | PRESCALE);
+
+   writel(val, evt->base + TMR_TCSR0);
+
+   return 0;
+}
+
+
+static int nuc970_clockevent_set_oneshot(struct clock_event_device *clk)
+{
+   nuc970_clockevent_set(0, clk);
+   return 0;
+}
+
+static int nuc970_clockevent_set_periodic(struct clock_event_device *clk)
+{
+   nuc970_clockevent_set(1, clk);
+   return 0;
+}
+
+static int nuc970_clockevent_setnextevent(unsigned long evtval,
+ struct clock_event_device *clk)
+{
+   struct nuc970_clockevents *evt = clkevt_to_nuc970(clk);
+   unsigned int tcsr, tdelta;
+
+   tcsr = readl(evt->base + TMR_TCSR0);
+   tdelta = readl(evt->base + TMR_TICR0) - readl(evt->base + TMR_TDR0);
+
+   writel(evtval, evt->base + TMR_TICR0);
+
+   if (!(tcsr & COUNTEN) && ((tdelta > 2) || (tdelta == 0)))
+   writel(readl(evt->base + TMR_TCSR0) | COUNTEN,
+evt->base + TMR_TCSR0);
+
+   return 0;
+}
+
+static int nuc97

[PATCH v2 01/10] ARM: NUC900: Add nuc970 machine support

2016-07-10 Thread Wan Zongshun
NUC970 is a new SoC of Nuvoton nuc900 series, this patch is
to add machine file support for it.

Signed-off-by: Wan Zongshun 
---
 arch/arm/mach-w90x900/Kconfig  | 20 
 arch/arm/mach-w90x900/Makefile |  3 +++
 arch/arm/mach-w90x900/nuc900.c | 41 +
 3 files changed, 64 insertions(+)
 create mode 100644 arch/arm/mach-w90x900/nuc900.c

diff --git a/arch/arm/mach-w90x900/Kconfig b/arch/arm/mach-w90x900/Kconfig
index 69bab32..80ab00c 100644
--- a/arch/arm/mach-w90x900/Kconfig
+++ b/arch/arm/mach-w90x900/Kconfig
@@ -15,6 +15,26 @@ config CPU_NUC960
help
  Support for NUCP960 of Nuvoton NUC900 CPUs.
 
+config SOC_NUC970
+   bool "Nuvoton NUC970 SoC support"
+   select COMMON_CLK
+   select GENERIC_IRQ_CHIP
+   select HAVE_CLK_PREPARE
+   select IRQ_DOMAIN
+   select MULTI_IRQ_HANDLER
+   select MFD_SYSCON
+   select NUC900_TIMER
+   select SOC_NUC900
+   select USE_OF
+   help
+ Support for NUC970 of Nuvoton NUC900 SoCs.
+ The NUC970 series runs up to 300 MHz, with 16 KB I-cache,
+ 16 KB D-cache and MMU, 56KB embedded SRAM and 16 KB Internal
+ Boot ROM for booting from USB, NAND and SPI FLASH.
+ Detailed information please check the following link:
+ https://github.com/zswan/nuc900-document/blob/master/
+ NUC970_TechnicalReferenceManual_EN_Rev1.30.pdf
+
 menu "W90P910 Machines"
 
 config MACH_W90P910EVB
diff --git a/arch/arm/mach-w90x900/Makefile b/arch/arm/mach-w90x900/Makefile
index 828c032..d13ba5a 100644
--- a/arch/arm/mach-w90x900/Makefile
+++ b/arch/arm/mach-w90x900/Makefile
@@ -4,8 +4,10 @@
 
 # Object file lists.
 
+ifeq ($(CONFIG_SOC_NUC970),)
 obj-y  := irq.o time.o mfp.o gpio.o clock.o
 obj-y  += clksel.o dev.o cpu.o
+endif
 # W90X900 CPU support files
 
 obj-$(CONFIG_CPU_W90P910)  += nuc910.o
@@ -17,3 +19,4 @@ obj-$(CONFIG_CPU_NUC960)  += nuc960.o
 obj-$(CONFIG_MACH_W90P910EVB)  += mach-nuc910evb.o
 obj-$(CONFIG_MACH_W90P950EVB)  += mach-nuc950evb.o
 obj-$(CONFIG_MACH_W90N960EVB)  += mach-nuc960evb.o
+obj-$(CONFIG_SOC_NUC970)   += nuc900.o
diff --git a/arch/arm/mach-w90x900/nuc900.c b/arch/arm/mach-w90x900/nuc900.c
new file mode 100644
index 000..309c332
--- /dev/null
+++ b/arch/arm/mach-w90x900/nuc900.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+static void __init nuc900_machine_init(void)
+{
+   of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char *nuc900_dt_compat[] __initconst = {
+   "nuvoton,nuc970",
+   NULL,
+};
+
+DT_MACHINE_START(nuc900_dt, "Nuvoton NUC900 (Device Tree Support)")
+   .init_machine   = nuc900_machine_init,
+   .dt_compat  = nuc900_dt_compat,
+MACHINE_END
-- 
2.7.4



[PATCH v2 05/10] power/reset: Add reset driver support for nuc900

2016-07-10 Thread Wan Zongshun
This driver is to add reset support for nuc900 series,
currently, it only supports nuc970 SoC reset.

Signed-off-by: Wan Zongshun 
---
 drivers/power/reset/Kconfig|  7 +++
 drivers/power/reset/Makefile   |  1 +
 drivers/power/reset/nuc900-reset.c | 93 ++
 3 files changed, 101 insertions(+)
 create mode 100644 drivers/power/reset/nuc900-reset.c

diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 9bb2622..8c84892 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -94,6 +94,13 @@ config POWER_RESET_MSM
help
  Power off and restart support for Qualcomm boards.
 
+config POWER_RESET_NUC900
+   bool "Nuc900 restart driver"
+   depends on ARCH_W90X900
+   help
+ Power off and restart support for Nuvoton NUC900 family of
+ reference boards.
+
 config POWER_RESET_LTC2952
bool "LTC2952 PowerPath power-off driver"
depends on OF_GPIO
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index ab7aa86..d4df889 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
 obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o
 obj-$(CONFIG_POWER_RESET_IMX) += imx-snvs-poweroff.o
 obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
+obj-$(CONFIG_POWER_RESET_NUC900) += nuc900-reset.o
 obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
 obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
 obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
diff --git a/drivers/power/reset/nuc900-reset.c 
b/drivers/power/reset/nuc900-reset.c
new file mode 100644
index 000..49986b7
--- /dev/null
+++ b/drivers/power/reset/nuc900-reset.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define REG_WRPRTR 0x1fc
+#define REG_AHBIPRST   0x060
+
+static struct regmap *syscon;
+
+static int nuc900_restart_handler(struct notifier_block *this,
+ unsigned long mode, void *cmd)
+{
+   /*0:register protect enable*/
+   int write_protect = 0;
+
+   /*register protection disable*/
+   do {
+   regmap_read(syscon, REG_WRPRTR, &write_protect);
+
+   if (write_protect != 1) {
+   regmap_write(syscon, REG_WRPRTR, 0x59);
+   regmap_write(syscon, REG_WRPRTR, 0x16);
+   regmap_write(syscon, REG_WRPRTR, 0x88);
+   }
+
+   } while (write_protect != 1);
+
+   /*trigger reset*/
+   regmap_write(syscon, REG_AHBIPRST, 0x01);
+
+   return NOTIFY_DONE;
+}
+
+static struct notifier_block nuc900_restart_nb = {
+   .notifier_call = nuc900_restart_handler,
+   .priority = 128,
+};
+
+static int nuc900_reset_probe(struct platform_device *pdev)
+{
+   struct device *dev = &pdev->dev;
+   int err;
+
+   syscon = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
+   if (IS_ERR(syscon)) {
+   pr_err("%s: syscon lookup failed\n", dev->of_node->name);
+   return PTR_ERR(syscon);
+   }
+
+   err = register_restart_handler(&nuc900_restart_nb);
+   if (err)
+   dev_err(dev, "cannot register restart handler (err=%d)\n", err);
+
+   return err;
+}
+
+static const struct of_device_id of_nuc900_reset_match[] = {
+   { .compatible = "nuvoton,nuc900-reset", },
+   {},
+};
+MODULE_DEVICE_TABLE(of, of_nuc900_reset_match);
+
+static struct platform_driver nuc900_reset_driver = {
+   .probe = nuc900_reset_probe,
+   .driver = {
+   .name = "nuc900-reset",
+   .of_match_table = of_match_ptr(of_nuc900_reset_match),
+   },
+};
+
+static int __init nuc900_reset_init(void)
+{
+   return platform_driver_register(&nuc900_reset_driver);
+}
+device_initcall(nuc900_reset_init);
-- 
2.7.4



[PATCH v2 07/10] ARM: dts: Add clock header file into dt-bindings

2016-07-10 Thread Wan Zongshun
This patch is to add nuc970 clock Macros header file
into include/dt-bindings/clock.

Signed-off-by: Wan Zongshun 
---
 include/dt-bindings/clock/nuc970-clock.h | 233 +++
 1 file changed, 233 insertions(+)
 create mode 100644 include/dt-bindings/clock/nuc970-clock.h

diff --git a/include/dt-bindings/clock/nuc970-clock.h 
b/include/dt-bindings/clock/nuc970-clock.h
new file mode 100644
index 000..cbfcc77
--- /dev/null
+++ b/include/dt-bindings/clock/nuc970-clock.h
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_NUC970_H
+#define __DT_BINDINGS_CLOCK_NUC970_H
+
+/*SOURCE*/
+
+#defineXIN 0
+#defineAPLL1
+#defineUPLL2
+#defineXIN32K  3
+#defineXIN128_DIV  4
+
+/*ECLK*/
+
+#defineUSB_APLLDIV 5
+#defineUSB_UPLLDIV 6
+#defineUSB_ECLK_MUX7
+#defineUSB_ECLK_DIV8
+#defineUSB_ECLK_GATE   9
+#defineSD_APLLDIV  10
+#defineSD_UPLLDIV  11
+#defineSD_ECLK_MUX 12
+#defineSD_ECLK_DIV 13
+#defineSD_ECLK_GATE14
+#defineLCD_APLLDIV 15
+#defineLCD_UPLLDIV 16
+#defineLCD_ECLK_MUX17
+#defineLCD_ECLK_DIV18
+#defineLCD_ECLK_GATE   19
+#defineADC_APLLDIV 20
+#defineADC_UPLLDIV 21
+#defineADC_ECLK_MUX22
+#defineADC_ECLK_DIV23
+#defineADC_ECLK_GATE   24
+#defineAUDIO_APLLDIV   25
+#defineAUDIO_UPLLDIV   26
+#defineAUDIO_ECLK_MUX  27
+#defineAUDIO_ECLK_DIV  28
+#defineAUDIO_ECLK_GATE 29
+#defineCAP_APLLDIV 30
+#defineCAP_UPLLDIV 31
+#defineCAP_ECLK_MUX32
+#defineCAP_ECLK_DIV33
+#defineCAP_ECLK_GATE   34
+#defineSDH_APLLDIV 35
+#defineSDH_UPLLDIV 36
+#defineSDH_ECLK_MUX37
+#defineSDH_ECLK_DIV38
+#defineSDH_ECLK_GATE   39
+#defineEMMC_APLLDIV40
+#defineEMMC_UPLLDIV41
+#defineEMMC_ECLK_MUX   42
+#defineEMMC_ECLK_DIV   43
+#defineEMMC_ECLK_GATE  44
+#defineUART0_APLLDIV   45
+#defineUART0_UPLLDIV   46
+#defineUART0_ECLK_MUX  47
+#defineUART0_ECLK_DIV  48
+#defineUART0_ECLK_GATE 49
+#defineUART1_APLLDIV   50
+#defineUART1_UPLLDIV   51
+#defineUART1_ECLK_MUX  52
+#defineUART1_ECLK_DIV  53
+#defineUART1_ECLK_GATE 54
+#defineUART2_APLLDIV   55
+#defineUART2_UPLLDIV   56
+#defineUART2_ECLK_MUX  57
+#defineUART2_ECLK_DIV  58
+#defineUART2_ECLK_GATE 59
+#defineUART3_APLLDIV   60
+#defineUART3_UPLLDIV   61
+#defineUART3_ECLK_MUX  62
+#defineUART3_ECLK_DIV  63
+#defineUART3_ECLK_GATE 64
+#defineUART4_APLLDIV   65
+#defineUART4_UPLLDIV   66
+#defineUART4_ECLK_MUX  67
+#defineUART4_ECLK_DIV  68
+#defineUART4_ECLK_GATE 69
+#defineUART5_APLLDIV   70
+#defineUART5_UPLLDIV   71
+#defineUART5_ECLK_MUX  72
+#defineUART5_ECLK_DIV  73
+#defineUART5_ECLK_GATE 74
+#defineUART6_APLLDIV   75
+#defineUART6_UPLLDIV   76
+#defineUART6_ECLK_MUX  77
+#defineUART6_ECLK_DIV  78
+#defineUART6_ECLK_GATE 79
+#defineUART7_APLLDIV   80
+#defineUART7_UPLLDIV   81
+#defineUART7_ECLK_MUX  82
+#defineUART7_ECLK_DIV  83
+#defineUART7_ECLK_GATE 84
+#defineUART8_APLLDIV   85
+#defineUART8_UPLLDIV   86
+#defineUART8_ECLK_MUX  87
+#defineUART8_ECLK_DIV  88
+#defineUART8_ECLK_GATE 89
+#defineUART9_APLLDIV   90
+#defineUART9_UPLLDIV   91
+#defineUART9_ECLK_MUX  92
+#defineUART9_ECLK_DIV  93

[PATCH v2 02/10] irqchip: add irqchip driver for nuc900

2016-07-10 Thread Wan Zongshun
This patch is to add irqchip driver support for nuc900 plat,
current this driver only supports nuc970 SoC.

Signed-off-by: Wan Zongshun 
---
 arch/arm/mach-w90x900/include/mach/irqs.h |   5 +
 drivers/irqchip/Makefile  |   1 +
 drivers/irqchip/irq-nuc900.c  | 150 ++
 3 files changed, 156 insertions(+)
 create mode 100644 drivers/irqchip/irq-nuc900.c

diff --git a/arch/arm/mach-w90x900/include/mach/irqs.h 
b/arch/arm/mach-w90x900/include/mach/irqs.h
index 9d5cba3..3b035c6 100644
--- a/arch/arm/mach-w90x900/include/mach/irqs.h
+++ b/arch/arm/mach-w90x900/include/mach/irqs.h
@@ -59,7 +59,12 @@
 #define IRQ_KPIW90X900_IRQ(29)
 #define IRQ_P2SGROUP   W90X900_IRQ(30)
 #define IRQ_ADCW90X900_IRQ(31)
+
+#if !defined(CONFIG_SOC_NUC900)
 #define NR_IRQS(IRQ_ADC+1)
+#else
+#define NR_IRQS62
+#endif
 
 /*for irq group*/
 
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 38853a1..9ccd5af8a 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -69,3 +69,4 @@ obj-$(CONFIG_PIC32_EVIC)  += irq-pic32-evic.o
 obj-$(CONFIG_MVEBU_ODMI)   += irq-mvebu-odmi.o
 obj-$(CONFIG_LS_SCFG_MSI)  += irq-ls-scfg-msi.o
 obj-$(CONFIG_EZNPS_GIC)+= irq-eznps.o
+obj-$(CONFIG_SOC_NUC970)   += irq-nuc900.o
diff --git a/drivers/irqchip/irq-nuc900.c b/drivers/irqchip/irq-nuc900.c
new file mode 100644
index 000..c4b2e39
--- /dev/null
+++ b/drivers/irqchip/irq-nuc900.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#defineREG_AIC_SCR10x00
+#defineREG_AIC_SCR20x04
+#defineREG_AIC_SCR30x08
+#defineREG_AIC_SCR40x0C
+#defineREG_AIC_SCR50x10
+#defineREG_AIC_SCR60x14
+#defineREG_AIC_SCR70x18
+#defineREG_AIC_SCR80x1C
+#defineREG_AIC_SCR90x20
+#defineREG_AIC_SCR10   0x24
+#defineREG_AIC_SCR11   0x28
+#defineREG_AIC_SCR12   0x2C
+#defineREG_AIC_SCR13   0x30
+#defineREG_AIC_SCR14   0x34
+#defineREG_AIC_SCR15   0x38
+#defineREG_AIC_IRSR0x100
+#defineREG_AIC_IRSRH   0x104
+#defineREG_AIC_IASR0x108
+#defineREG_AIC_IASRH   0x10C
+#defineREG_AIC_ISR 0x110
+#defineREG_AIC_ISRH0x114
+#defineREG_AIC_IPER0x118
+#defineREG_AIC_ISNR0x120
+#defineREG_AIC_OISR0x124
+#defineREG_AIC_IMR 0x128
+#defineREG_AIC_IMRH0x12C
+#defineREG_AIC_MECR0x130
+#defineREG_AIC_MECRH   0x134
+#defineREG_AIC_MDCR0x138
+#defineREG_AIC_MDCRH   0x13C
+#defineREG_AIC_SSCR0x140
+#defineREG_AIC_SSCRH   0x144
+#defineREG_AIC_SCCR0x148
+#defineREG_AIC_SCCRH   0x14C
+#defineREG_AIC_EOSCR   0x150
+
+static void __iomem *aic_base;
+static struct irq_domain *aic_domain;
+
+static void nuc900_irq_mask(struct irq_data *d)
+{
+   if (d->irq < 32)
+   writel(1 << (d->irq), aic_base + REG_AIC_MDCR);
+   else
+   writel(1 << (d->irq - 32), aic_base + REG_AIC_MDCRH);
+}
+
+static void nuc900_irq_ack(struct irq_data *d)
+{
+   writel(0x01, aic_base + REG_AIC_EOSCR);
+}
+
+static void nuc900_irq_unmask(struct irq_data *d)
+{
+   if (d->irq < 32)
+   writel(1 << (d->irq), aic_base + REG_AIC_MECR);
+   else
+   writel(1 << (d->irq - 32), aic_base + REG_AIC_MECRH);
+}
+
+static struct irq_chip nuc900_irq_chip = {
+   .irq_ack= nuc900_irq_ack,
+   .irq_mask   = nuc900_irq_mask,
+   .irq_unmask = nuc900_irq_unmask,
+};
+
+void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
+{
+   u32 hwirq;
+
+   hwirq = readl(aic_base + REG_AIC_IPER);
+   hwirq = readl(aic_base + REG_AIC_ISNR);
+   if (!hwirq)
+   writel(0x01, aic_base + REG_AIC_EOSCR);
+
+   handle_IRQ((irq_find_mapping(aic_domain, hwirq)), regs);
+}
+
+static int aic_irq_domain_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hw)
+{
+   irq_set_chip_and_handler(virq, &nuc900_irq_chip, handle_level_irq);
+   irq_clear_status_flags(virq, IRQ_NOREQUEST);
+
+   return 0;
+}
+
+static struct irq_domain_ops aic_irq_domain_ops = {
+   .map = aic_irq_domain_map,
+   .xlate = irq_domain_xlate_onecell,
+};

Re: [PATCH 4/6] irqchip: add irqchip driver for nuc900

2016-07-08 Thread Wan Zongshun



On 2016年06月29日 23:27, Arnd Bergmann wrote:

On Saturday, June 25, 2016 6:37:20 PM CEST Wan Zongshun wrote:

+#define IRQ_WDTW90X900_IRQ(1)
+#define IRQ_WWDT   W90X900_IRQ(2)
+#define IRQ_LVDW90X900_IRQ(3)
+#define IRQ_EXT0   W90X900_IRQ(4)
+#define IRQ_EXT1   W90X900_IRQ(5)
+#define IRQ_EXT2   W90X900_IRQ(6)
+#define IRQ_EXT3   W90X900_IRQ(7)
+#define IRQ_EXT4   W90X900_IRQ(8)
+#define IRQ_EXT5   W90X900_IRQ(9)
+#define IRQ_EXT6   W90X900_IRQ(10)


I'd suggest dropping the list, the contents are now in the dts.


Arnd, I will drop this file later, since old w90x900 plat still need it.
but I will remove the Macros related to nuc970 and avoid nuc970 
interrupt using those Macro.


But I still need hack this irqs.h like below, since here NR_IRQS defined 
and it is need for nuc970 irqchip driver.


#if !defined(CONFIG_SOC_NUC900)
#define NR_IRQS (IRQ_ADC+1)
#else
#define NR_IRQS 62
#endif




diff --git a/arch/arm/mach-w90x900/include/mach/nuc970-regs-aic.h 
b/arch/arm/mach-w90x900/include/mach/nuc970-regs-aic.h
new file mode 100644
index 000..7a77016
--- /dev/null
+++ b/arch/arm/mach-w90x900/include/mach/nuc970-regs-aic.h
@@ -0,0 +1,53 @@
+#ifndef __ASM_ARCH_REGS_AIC_H
+#define __ASM_ARCH_REGS_AIC_H
+
+/*NUC970 AIC regs*/
+
+#defineREG_AIC_SCR10x00
+#defineREG_AIC_SCR20x04
+#defineREG_AIC_SCR30x08
+#defineREG_AIC_SCR40x0C
+#defineREG_AIC_SCR50x10


And like the clk driver, these should all be in the irqchip driver instead
of a separate header.


+
+static void __iomem *aic_base;
+static struct irq_domain *aic_domain;
+#define MAKE_HWIRQ(irqnum) (irqnum)


The macro appears to be unused.


+static void nuc970_irq_mask(struct irq_data *d)
+{
+   if (d->irq < 32)
+   __raw_writel(1 << (d->irq), aic_base + REG_AIC_MDCR);
+   else
+   __raw_writel(1 << (d->irq - 32), aic_base + REG_AIC_MDCRH);
+}


writel()

Arnd


___
linux-arm-kernel mailing list
linux-arm-ker...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel




Re: [PATCH 3/6] Clocksource: add nuc970 clocksource driver

2016-07-05 Thread Wan Zongshun



On 2016年06月28日 03:46, Daniel Lezcano wrote:

On 06/25/2016 12:37 PM, Wan Zongshun wrote:

This patch is to add nuc970 clocksource driver support.


Hi Wan,

add a detailed description of how works this timer and its general
design. If there is a pointer or a reference to a manual that would be
awesome.


Daniel,

I add a document link to you, and I will update this link in my patch later.

https://github.com/zswan/nuc900-document/blob/master/NUC970_TechnicalReferenceManual_EN_Rev1.30.pdf





Signed-off-by: Wan Zongshun 
---
  .../mach-w90x900/include/mach/nuc970-regs-timer.h  |  44 +
  drivers/clocksource/Kconfig|   8 +
  drivers/clocksource/Makefile   |   1 +
  drivers/clocksource/timer-nuc900.c | 207
+
  4 files changed, 260 insertions(+)
  create mode 100644
arch/arm/mach-w90x900/include/mach/nuc970-regs-timer.h
  create mode 100644 drivers/clocksource/timer-nuc900.c

diff --git a/arch/arm/mach-w90x900/include/mach/nuc970-regs-timer.h
b/arch/arm/mach-w90x900/include/mach/nuc970-regs-timer.h
new file mode 100644
index 000..43d7e8b
--- /dev/null
+++ b/arch/arm/mach-w90x900/include/mach/nuc970-regs-timer.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __ASM_ARCH_REGS_TIMER_H
+#define __ASM_ARCH_REGS_TIMER_H
+
+/* Timer Registers */
+
+#define TMR_BA0x0
+
+#define REG_TMR_TCSR0(TMR_BA+0x00)
+#define REG_TMR_TICR0(TMR_BA+0x04)
+#define REG_TMR_TDR0(TMR_BA+0x08)
+
+
+#define REG_TMR_TCSR1(TMR_BA+0x10)
+#define REG_TMR_TICR1(TMR_BA+0x14)
+#define REG_TMR_TDR1(TMR_BA+0x18)
+
+
+#define REG_TMR_TCSR2(TMR_BA+0x20)
+#define REG_TMR_TICR2(TMR_BA+0x24)
+#define REG_TMR_TDR2(TMR_BA+0x28)
+
+#define REG_TMR_TCSR3(TMR_BA+0x30)
+#define REG_TMR_TICR3(TMR_BA+0x34)
+#define REG_TMR_TDR3(TMR_BA+0x38)
+
+#define REG_TMR_TCSR4(TMR_BA+0x40)
+#define REG_TMR_TICR4(TMR_BA+0x44)
+#define REG_TMR_TDR4(TMR_BA+0x48)
+
+#define REG_TMR_TISR(TMR_BA+0x60)


Are these macros used only in the timer driver or somewhere else ?


They are using by the timer driver, and I will try to move 
mach-w90x900/include/mach/nuc970-regs-timer.h out of mach/ folder.


Do you think I should move those macros into this driver file?




+#endif /*  __ASM_ARCH_REGS_TIMER_H */
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 47352d2..441c5ee 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -427,4 +427,12 @@ config CLKSRC_ST_LPC
Enable this option to use the Low Power controller timer
as clocksource.

+config NUC900_TIMER
+bool "Clocksource timer for nuc900 platform" if COMPILE_TEST
+depends on ARM
+select CLKSRC_OF if OF
+select CLKSRC_MMIO
+help
+  Enables the clocksource for the NUC900 platform.
+
  endmenu
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 473974f..fcc2cc7 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -67,3 +67,4 @@ obj-$(CONFIG_H8300_TMR16)+= h8300_timer16.o
  obj-$(CONFIG_H8300_TPU)+= h8300_tpu.o
  obj-$(CONFIG_CLKSRC_ST_LPC)+= clksrc_st_lpc.o
  obj-$(CONFIG_X86_NUMACHIP)+= numachip.o
+obj-$(CONFIG_ARCH_W90X900)+= timer-nuc900.o


obj-$(CONFIG_NUC900_TIMER)


Sure, changed.



diff --git a/drivers/clocksource/timer-nuc900.c
b/drivers/clocksource/timer-nuc900.c
new file mode 100644
index 000..6ba025c
--- /dev/null
+++ b/drivers/clocksource/timer-nuc900.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 


Please do a cleanup with these headers.


Ok.




+#define RESETINT0x1f
+#define PERIOD(0x01 << 27)


PERIODIC


Ok.



+#define ONESHOT(0x00 << 27)
+#define COUNTEN(0x01 << 30)
+#define INTEN(0x01 << 29)
+
+#define TICKS_PER_SEC100
+/* Divider = prescale + 1 */
+#define PRESCALE0x63
+
+#defineTDR_SHIFT24
+#defineTDR_MASK((1 << TDR_SHIFT) - 1)
+
+static unsigned int tim

Re: [PATCH 4/6] irqchip: add irqchip driver for nuc900

2016-07-05 Thread Wan Zongshun



On 2016年06月29日 23:27, Arnd Bergmann wrote:

On Saturday, June 25, 2016 6:37:20 PM CEST Wan Zongshun wrote:

+#define IRQ_WDTW90X900_IRQ(1)
+#define IRQ_WWDT   W90X900_IRQ(2)
+#define IRQ_LVDW90X900_IRQ(3)
+#define IRQ_EXT0   W90X900_IRQ(4)
+#define IRQ_EXT1   W90X900_IRQ(5)
+#define IRQ_EXT2   W90X900_IRQ(6)
+#define IRQ_EXT3   W90X900_IRQ(7)
+#define IRQ_EXT4   W90X900_IRQ(8)
+#define IRQ_EXT5   W90X900_IRQ(9)
+#define IRQ_EXT6   W90X900_IRQ(10)


I'd suggest dropping the list, the contents are now in the dts.


Do you think I should put one irqmap header file into this
/arch/arm/boot/dts/include/dt-bindings folder, or I should removed those 
irqnumber map anywhere, just hardcode the irqnumber in dts file?





diff --git a/arch/arm/mach-w90x900/include/mach/nuc970-regs-aic.h 
b/arch/arm/mach-w90x900/include/mach/nuc970-regs-aic.h
new file mode 100644
index 000..7a77016
--- /dev/null
+++ b/arch/arm/mach-w90x900/include/mach/nuc970-regs-aic.h
@@ -0,0 +1,53 @@
+#ifndef __ASM_ARCH_REGS_AIC_H
+#define __ASM_ARCH_REGS_AIC_H
+
+/*NUC970 AIC regs*/
+
+#defineREG_AIC_SCR10x00
+#defineREG_AIC_SCR20x04
+#defineREG_AIC_SCR30x08
+#defineREG_AIC_SCR40x0C
+#defineREG_AIC_SCR50x10


And like the clk driver, these should all be in the irqchip driver instead
of a separate header.


Ok, changed.



+
+static void __iomem *aic_base;
+static struct irq_domain *aic_domain;
+#define MAKE_HWIRQ(irqnum) (irqnum)


The macro appears to be unused.

removed it.



+static void nuc970_irq_mask(struct irq_data *d)
+{
+   if (d->irq < 32)
+   __raw_writel(1 << (d->irq), aic_base + REG_AIC_MDCR);
+   else
+   __raw_writel(1 << (d->irq - 32), aic_base + REG_AIC_MDCRH);
+}


writel()

Arnd


___
linux-arm-kernel mailing list
linux-arm-ker...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel




Re: [PATCH 3/6] Clocksource: add nuc970 clocksource driver

2016-07-05 Thread Wan Zongshun



On 2016年06月29日 23:25, Arnd Bergmann wrote:

On Saturday, June 25, 2016 6:37:19 PM CEST Wan Zongshun wrote:

This patch is to add nuc970 clocksource driver support.

Signed-off-by: Wan Zongshun 
---
  .../mach-w90x900/include/mach/nuc970-regs-timer.h  |  44 +
  drivers/clocksource/Kconfig|   8 +
  drivers/clocksource/Makefile   |   1 +
  drivers/clocksource/timer-nuc900.c | 207 +
  4 files changed, 260 insertions(+)
  create mode 100644 arch/arm/mach-w90x900/include/mach/nuc970-regs-timer.h
  create mode 100644 drivers/clocksource/timer-nuc900.c

diff --git a/arch/arm/mach-w90x900/include/mach/nuc970-regs-timer.h 
b/arch/arm/mach-w90x900/include/mach/nuc970-regs-timer.h
new file mode 100644
index 000..43d7e8b
--- /dev/null
+++ b/arch/arm/mach-w90x900/include/mach/nuc970-regs-timer.h


Please move the contents of the header file into the driver. We try to not
have any new mach/*.h headers.


Ok, done.




+
+static unsigned int timer0_load;
+static void __iomem *tmr_base;
+
+static int nuc970_clockevent_set_oneshot(struct clock_event_device *evt)
+{
+   unsigned int val;
+
+   val = __raw_readl(tmr_base + REG_TMR_TCSR0);
+   val &= ~(0x03 << 27);
+
+   val |= (ONESHOT | COUNTEN | INTEN | PRESCALE);
+
+   __raw_writel(val, tmr_base + REG_TMR_TCSR0);
+   return 0;
+}
+


writel() instead of __raw_writel()


Ok, so this change will apply to all drivers.



Arnd

___
linux-arm-kernel mailing list
linux-arm-ker...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel




Re: [PATCH 1/6] ARM: NUC900: Add nuc970 machine support

2016-07-05 Thread Wan Zongshun



On 2016年06月29日 23:19, Arnd Bergmann wrote:

On Saturday, June 25, 2016 6:37:17 PM CEST Wan Zongshun wrote:

NUC970 is a new SoC of Nuvoton nuc900 series, this patch is
to add machine file support for it.

Signed-off-by: Wan Zongshun 


Nice to see some activity on the port!


---
  arch/arm/mach-w90x900/Kconfig  |  25 
  arch/arm/mach-w90x900/Makefile |   3 +
  .../mach-w90x900/include/mach/nuc970-regs-gcr.h|  56 
  arch/arm/mach-w90x900/mach-nuc970.c| 144 +
  4 files changed, 228 insertions(+)
  create mode 100644 arch/arm/mach-w90x900/include/mach/nuc970-regs-gcr.h
  create mode 100644 arch/arm/mach-w90x900/mach-nuc970.c

diff --git a/arch/arm/mach-w90x900/Kconfig b/arch/arm/mach-w90x900/Kconfig
index 69bab32..050833e 100644
--- a/arch/arm/mach-w90x900/Kconfig
+++ b/arch/arm/mach-w90x900/Kconfig
@@ -15,6 +15,21 @@ config CPU_NUC960
help
  Support for NUCP960 of Nuvoton NUC900 CPUs.

+config SOC_NUC970
+   bool
+select GENERIC_IRQ_CHIP
+select SOC_BUS
+select IRQ_DOMAIN
+select MULTI_IRQ_HANDLER
+select USE_OF
+select HAVE_CLK_PREPARE
+select HAVE_MACH_CLKDEV
+   select COMMON_CLK
+select NUC900_TIMER
+   help
+ Support for NUCP970 of Nuvoton NUC900 CPUs.
+


[style] This looks whitespace damaged, and please sort the line alphabetically.


Sure, changed.



I see you have done this in a way that is basically compatible with
CONFIG_ARCH_MULTIPLATFORM, good.

What is HAVE_MACH_CLKDEV for?


@@ -46,4 +61,14 @@ config MACH_W90N960EVB

  endmenu

+menu "NUC970 Machines"
+
+config MACH_NUC970EVB
+   bool "Nuvoton NUC970 Evaluation Board"
+   select SOC_NUC970
+   help
+  Say Y here if you are using the Nuvoton NUC970EVB
+
+endmenu


I'd leave out this entry, with the way have have structured the code 
(correctly),
there is no need to separate SoC-specific code from board specific code, since
they are the same.



Sure, removed it.


diff --git a/arch/arm/mach-w90x900/include/mach/nuc970-regs-gcr.h 
b/arch/arm/mach-w90x900/include/mach/nuc970-regs-gcr.h
new file mode 100644
index 000..e7eb653
--- /dev/null
+++ b/arch/arm/mach-w90x900/include/mach/nuc970-regs-gcr.h


Can you move the new headers to arch/arm/mach-w90x900/ directly?


+static int __init nuc900_restart_init(void)
+{
+   struct device_node *np;
+
+   np = of_find_compatible_node(NULL, NULL, "nuvoton,gcr");
+   wtcr_addr = of_iomap(np, 0);
+   if (!wtcr_addr)
+   return -ENODEV;
+
+   of_node_put(np);
+
+   return 0;
+}


Is this a watchdog node? If it is, the restart logic should just
move into the watchdog driver.


It is not watchdog node, just be global System control register node.





+   if (of_machine_is_compatible("nuvoton,nuc970evb"))
+   nuc970_init();


What is this for?


Currently, no used, remove it.




+   of_platform_populate(NULL, of_default_bus_match_table, NULL, parent);


We have actually moved away from using the soc_device as using the parent
for the other devices, just probe them separately. In fact the soc_device
could be handled by a driver in drivers/soc/nuvoton/


Do you think I should add nuc900 soc driver in this folder?
If I want to add nuc900 soc driver in drivers/soc/nuvoton/, can I keep 
my current dts structure no change, or Must I add a new node name soc {}?


I went through the code:soc-realview.c for reference, but I have no idea
about how to re-structure my dts file to match this type soc driver.




+static const char *nuc970_dt_compat[] __initconst = {
+   "nuvoton,nuc970evb",
+   NULL,
+};
+
+void nuc970_restart(enum reboot_mode mode, const char *cmd)
+{
+   if (wtcr_addr) {
+   while (__raw_readl(wtcr_addr + REG_WRPRTR) != 1) {
+   __raw_writel(0x59, wtcr_addr + REG_WRPRTR);
+   __raw_writel(0x16, wtcr_addr + REG_WRPRTR);
+   __raw_writel(0x88, wtcr_addr + REG_WRPRTR);
+   }
+
+   __raw_writel(1, wtcr_addr + REG_AHBIPRST);
+   }


Please use writel() instead of __raw_writel().


Does this change apply to all others drivers? or just machine file to 
use writel()?





+   soft_restart(0);
+}
+
+DT_MACHINE_START(nuc970_dt, "Nuvoton nuc970 evb")
+   .atag_offset= 0x100,


Removed it, thanks!



The .atag_offset can be removed here.

Arnd

___
linux-arm-kernel mailing list
linux-arm-ker...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel




Re: [PATCH 1/1] iommu/amd: initialize devid variable before using it

2016-06-26 Thread Wan ZongShun
2016-06-26 16:33 GMT+08:00 Nicolas Iooss :
> Commit 2a0cb4e2d423 ("iommu/amd: Add new map for storing IVHD dev entry
> type HID") added a call to DUMP_printk in init_iommu_from_acpi() which
> used the value of devid before this variable was initialized.
>
> Signed-off-by: Nicolas Iooss 
> ---
>  drivers/iommu/amd_iommu_init.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
> index 9e0034196e10..d091defc3426 100644
> --- a/drivers/iommu/amd_iommu_init.c
> +++ b/drivers/iommu/amd_iommu_init.c
> @@ -1107,13 +1107,13 @@ static int __init init_iommu_from_acpi(struct 
> amd_iommu *iommu,
> break;
> }
>
> +   devid = e->devid;
> DUMP_printk("  DEV_ACPI_HID(%s[%s])\t\tdevid: 
> %02x:%02x.%x\n",
> hid, uid,
> PCI_BUS_NUM(devid),
> PCI_SLOT(devid),
> PCI_FUNC(devid));
>
> -   devid  = e->devid;
> flags = e->flags;
>

Sure, thanks for your patch.
This is my fault.

> ret = add_acpi_hid_device(hid, uid, &devid, false);
> --
> 2.9.0
>



-- 
---
Vincent Wan(Zongshun)
www.mcuos.com


[PATCH 0/6] ARM: NUC900: Add NUC970 SoC support

2016-06-25 Thread Wan Zongshun
Hi,

This patch series added Nuvoton new SoC NUC970 development board
support, this nuc970 belongs to nuc900 series, but many features are
not compatible with old nuc900 SoCs like nuc910, nuc920.

Those patches are basing on old w90x900 codes, and are using standard
linux subsystem interface, such as dts, driver/clk, driver/clocksource
, driver/irqchip drivers.

The old w90x900 plat such as nuc910,nuc960 codes will also be changed
to new style according to nuc970 codes after those patches was accepted.

Wan Zongshun (6):
  ARM: NUC900: Add nuc970 machine support
  ARM: dts: nuc900: Add nuc970 dts files
  Clocksource: add nuc970 clocksource driver
  irqchip: add irqchip driver for nuc900
  clk: add Clock driver for nuc970
  nuc900: add nuc970 platform defconfig file

 .../devicetree/bindings/arm/nuvoton/nuc970.txt |   30 +
 arch/arm/boot/dts/Makefile |1 +
 arch/arm/boot/dts/nuc970-evb.dts   |   20 +
 arch/arm/boot/dts/nuc970.dtsi  |   93 ++
 arch/arm/configs/nuc970_defconfig  | 1278 
 arch/arm/mach-w90x900/Kconfig  |   25 +
 arch/arm/mach-w90x900/Makefile |3 +
 arch/arm/mach-w90x900/include/mach/irqs.h  |   69 ++
 .../mach-w90x900/include/mach/nuc970-regs-aic.h|   53 +
 .../mach-w90x900/include/mach/nuc970-regs-gcr.h|   56 +
 .../mach-w90x900/include/mach/nuc970-regs-timer.h  |   44 +
 arch/arm/mach-w90x900/mach-nuc970.c|  144 +++
 drivers/clk/Makefile   |1 +
 drivers/clk/nuc900/Makefile|6 +
 drivers/clk/nuc900/clk-apll.c  |  168 +++
 drivers/clk/nuc900/clk-ccf.h   |   53 +
 drivers/clk/nuc900/clk-nuc970.c|  920 ++
 drivers/clk/nuc900/clk-upll.c  |   83 ++
 drivers/clocksource/Kconfig|8 +
 drivers/clocksource/Makefile   |1 +
 drivers/clocksource/timer-nuc900.c |  207 
 drivers/irqchip/Makefile   |1 +
 drivers/irqchip/irq-nuc900.c   |  104 ++
 include/dt-bindings/clock/nuc970-clock.h   |  233 
 24 files changed, 3601 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/nuvoton/nuc970.txt
 create mode 100644 arch/arm/boot/dts/nuc970-evb.dts
 create mode 100644 arch/arm/boot/dts/nuc970.dtsi
 create mode 100644 arch/arm/configs/nuc970_defconfig
 create mode 100644 arch/arm/mach-w90x900/include/mach/nuc970-regs-aic.h
 create mode 100644 arch/arm/mach-w90x900/include/mach/nuc970-regs-gcr.h
 create mode 100644 arch/arm/mach-w90x900/include/mach/nuc970-regs-timer.h
 create mode 100644 arch/arm/mach-w90x900/mach-nuc970.c
 create mode 100644 drivers/clk/nuc900/Makefile
 create mode 100644 drivers/clk/nuc900/clk-apll.c
 create mode 100644 drivers/clk/nuc900/clk-ccf.h
 create mode 100644 drivers/clk/nuc900/clk-nuc970.c
 create mode 100644 drivers/clk/nuc900/clk-upll.c
 create mode 100644 drivers/clocksource/timer-nuc900.c
 create mode 100644 drivers/irqchip/irq-nuc900.c
 create mode 100644 include/dt-bindings/clock/nuc970-clock.h

-- 
2.7.4



[PATCH 3/6] Clocksource: add nuc970 clocksource driver

2016-06-25 Thread Wan Zongshun
This patch is to add nuc970 clocksource driver support.

Signed-off-by: Wan Zongshun 
---
 .../mach-w90x900/include/mach/nuc970-regs-timer.h  |  44 +
 drivers/clocksource/Kconfig|   8 +
 drivers/clocksource/Makefile   |   1 +
 drivers/clocksource/timer-nuc900.c | 207 +
 4 files changed, 260 insertions(+)
 create mode 100644 arch/arm/mach-w90x900/include/mach/nuc970-regs-timer.h
 create mode 100644 drivers/clocksource/timer-nuc900.c

diff --git a/arch/arm/mach-w90x900/include/mach/nuc970-regs-timer.h 
b/arch/arm/mach-w90x900/include/mach/nuc970-regs-timer.h
new file mode 100644
index 000..43d7e8b
--- /dev/null
+++ b/arch/arm/mach-w90x900/include/mach/nuc970-regs-timer.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __ASM_ARCH_REGS_TIMER_H
+#define __ASM_ARCH_REGS_TIMER_H
+
+/* Timer Registers */
+
+#define TMR_BA 0x0
+
+#define REG_TMR_TCSR0  (TMR_BA+0x00)
+#define REG_TMR_TICR0  (TMR_BA+0x04)
+#define REG_TMR_TDR0   (TMR_BA+0x08)
+
+
+#define REG_TMR_TCSR1  (TMR_BA+0x10)
+#define REG_TMR_TICR1  (TMR_BA+0x14)
+#define REG_TMR_TDR1   (TMR_BA+0x18)
+
+
+#define REG_TMR_TCSR2  (TMR_BA+0x20)
+#define REG_TMR_TICR2  (TMR_BA+0x24)
+#define REG_TMR_TDR2   (TMR_BA+0x28)
+
+#define REG_TMR_TCSR3  (TMR_BA+0x30)
+#define REG_TMR_TICR3  (TMR_BA+0x34)
+#define REG_TMR_TDR3   (TMR_BA+0x38)
+
+#define REG_TMR_TCSR4  (TMR_BA+0x40)
+#define REG_TMR_TICR4  (TMR_BA+0x44)
+#define REG_TMR_TDR4   (TMR_BA+0x48)
+
+#define REG_TMR_TISR   (TMR_BA+0x60)
+
+
+#endif /*  __ASM_ARCH_REGS_TIMER_H */
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 47352d2..441c5ee 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -427,4 +427,12 @@ config CLKSRC_ST_LPC
  Enable this option to use the Low Power controller timer
  as clocksource.
 
+config NUC900_TIMER
+bool "Clocksource timer for nuc900 platform" if COMPILE_TEST
+depends on ARM
+select CLKSRC_OF if OF
+select CLKSRC_MMIO
+help
+  Enables the clocksource for the NUC900 platform.
+
 endmenu
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 473974f..fcc2cc7 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -67,3 +67,4 @@ obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o
 obj-$(CONFIG_H8300_TPU)+= h8300_tpu.o
 obj-$(CONFIG_CLKSRC_ST_LPC)+= clksrc_st_lpc.o
 obj-$(CONFIG_X86_NUMACHIP) += numachip.o
+obj-$(CONFIG_ARCH_W90X900) += timer-nuc900.o
diff --git a/drivers/clocksource/timer-nuc900.c 
b/drivers/clocksource/timer-nuc900.c
new file mode 100644
index 000..6ba025c
--- /dev/null
+++ b/drivers/clocksource/timer-nuc900.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define RESETINT   0x1f
+#define PERIOD (0x01 << 27)
+#define ONESHOT(0x00 << 27)
+#define COUNTEN(0x01 << 30)
+#define INTEN  (0x01 << 29)
+
+#define TICKS_PER_SEC  100
+/* Divider = prescale + 1 */
+#define PRESCALE   0x63
+
+#defineTDR_SHIFT   24
+#defineTDR_MASK((1 << TDR_SHIFT) - 1)
+
+static unsigned int timer0_load;
+static void __iomem *tmr_base;
+
+static int nuc970_clockevent_set_oneshot(struct clock_event_device *evt)
+{
+   unsigned int val;
+
+   val = __raw_readl(tmr_base + REG_TMR_TCSR0);
+   val &= ~(0x03 << 27);
+
+   val |= (ONESHOT | COUNTEN | INTEN | PRESCALE);
+
+   __raw_writel(val, tmr_base + REG_TMR_TCSR0);
+   return 0;
+}
+
+static int nuc970_clockevent_set_periodic(struct clock_event_device *evt)
+{
+   unsigned int val;
+
+   val = __raw_readl(tmr_base + REG_TMR_TCSR0);
+   val &= ~(0x03 << 27);
+
+   __raw_writel(timer0_load, tmr_base + REG_TMR_TICR0);
+   val |= (PERIOD | COUNTEN | INTEN | PRESCALE);
+
+   __raw_writel(val, tmr

[PATCH 1/6] ARM: NUC900: Add nuc970 machine support

2016-06-25 Thread Wan Zongshun
NUC970 is a new SoC of Nuvoton nuc900 series, this patch is
to add machine file support for it.

Signed-off-by: Wan Zongshun 
---
 arch/arm/mach-w90x900/Kconfig  |  25 
 arch/arm/mach-w90x900/Makefile |   3 +
 .../mach-w90x900/include/mach/nuc970-regs-gcr.h|  56 
 arch/arm/mach-w90x900/mach-nuc970.c| 144 +
 4 files changed, 228 insertions(+)
 create mode 100644 arch/arm/mach-w90x900/include/mach/nuc970-regs-gcr.h
 create mode 100644 arch/arm/mach-w90x900/mach-nuc970.c

diff --git a/arch/arm/mach-w90x900/Kconfig b/arch/arm/mach-w90x900/Kconfig
index 69bab32..050833e 100644
--- a/arch/arm/mach-w90x900/Kconfig
+++ b/arch/arm/mach-w90x900/Kconfig
@@ -15,6 +15,21 @@ config CPU_NUC960
help
  Support for NUCP960 of Nuvoton NUC900 CPUs.
 
+config SOC_NUC970
+   bool
+select GENERIC_IRQ_CHIP
+select SOC_BUS
+select IRQ_DOMAIN
+select MULTI_IRQ_HANDLER
+select USE_OF
+select HAVE_CLK_PREPARE
+select HAVE_MACH_CLKDEV
+   select COMMON_CLK
+select NUC900_TIMER
+   help
+ Support for NUCP970 of Nuvoton NUC900 CPUs.
+
+
 menu "W90P910 Machines"
 
 config MACH_W90P910EVB
@@ -46,4 +61,14 @@ config MACH_W90N960EVB
 
 endmenu
 
+menu "NUC970 Machines"
+
+config MACH_NUC970EVB
+   bool "Nuvoton NUC970 Evaluation Board"
+   select SOC_NUC970
+   help
+  Say Y here if you are using the Nuvoton NUC970EVB
+
+endmenu
+
 endif
diff --git a/arch/arm/mach-w90x900/Makefile b/arch/arm/mach-w90x900/Makefile
index 828c032..6c99e6f 100644
--- a/arch/arm/mach-w90x900/Makefile
+++ b/arch/arm/mach-w90x900/Makefile
@@ -4,8 +4,10 @@
 
 # Object file lists.
 
+ifeq ($(CONFIG_SOC_NUC970),)
 obj-y  := irq.o time.o mfp.o gpio.o clock.o
 obj-y  += clksel.o dev.o cpu.o
+endif
 # W90X900 CPU support files
 
 obj-$(CONFIG_CPU_W90P910)  += nuc910.o
@@ -17,3 +19,4 @@ obj-$(CONFIG_CPU_NUC960)  += nuc960.o
 obj-$(CONFIG_MACH_W90P910EVB)  += mach-nuc910evb.o
 obj-$(CONFIG_MACH_W90P950EVB)  += mach-nuc950evb.o
 obj-$(CONFIG_MACH_W90N960EVB)  += mach-nuc960evb.o
+obj-$(CONFIG_MACH_NUC970EVB)   += mach-nuc970.o
diff --git a/arch/arm/mach-w90x900/include/mach/nuc970-regs-gcr.h 
b/arch/arm/mach-w90x900/include/mach/nuc970-regs-gcr.h
new file mode 100644
index 000..e7eb653
--- /dev/null
+++ b/arch/arm/mach-w90x900/include/mach/nuc970-regs-gcr.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __ASM_ARCH_REGS_GCR_H
+#define __ASM_ARCH_REGS_GCR_H
+
+/* NUC970 GCR regs */
+
+#define REG_PDID   0x000
+#define REG_PWRON  0x004
+#define REG_ARBCON 0x008
+#define REG_LVRDCR 0x020
+#define REG_MISCFCR0x030
+#define REG_MISCIER0x040
+#define REG_MISCISR0x044
+#define REG_ROMSUM00x048
+#define REG_ROMSUM10x04C
+#define REG_WKUPSER0x058
+#define REG_WKUPSSR0x05C
+#define REG_AHBIPRST   0x060
+#define REG_APBIPRST0  0x064
+#define REG_APBIPRST1  0x068
+#define REG_RSTSTS 0x06C
+#define REG_DDR_DS_CR  0x0E0
+#define REG_PORDISCR   0x100
+#define REG_ICEDBGCR   0x104
+#define REG_WRPRTR 0x1FC
+#define REG_MFP_GPA_L  0x070
+#define REG_MFP_GPA_H  0x074
+#define REG_MFP_GPB_L  0x078
+#define REG_MFP_GPB_H  0x07C
+#define REG_MFP_GPC_L  0x080
+#define REG_MFP_GPC_H  0x084
+#define REG_MFP_GPD_L  0x088
+#define REG_MFP_GPD_H  0x08C
+#define REG_MFP_GPE_L  0x090
+#define REG_MFP_GPE_H  0x094
+#define REG_MFP_GPF_L  0x098
+#define REG_MFP_GPF_H  0x09C
+#define REG_MFP_GPG_L  0x0A0
+#define REG_MFP_GPG_H  0x0A4
+#define REG_MFP_GPH_L  0x0A8
+#define REG_MFP_GPH_H  0x0AC
+#define REG_MFP_GPI_L  0x0B0
+#define REG_MFP_GPI_H  0x0B4
+#define REG_MFP_GPJ_L  0x0B8
+
+#endif /*  __ASM_ARCH_REGS_GCR_H */
diff --git a/arch/arm/mach-w90x900/mach-nuc970.c 
b/arch/arm/mach-w90x900/mach-nuc970.c
new file mode 100644
index 000..cbae366
--- /dev/null
+++ b/arch/arm/mach-w90x900/mach-nuc970.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#define GCR_CHIPID 0x00
+#define GCR_CHIPID_MASK0x00ff
+
+int chipid;
+int versionid;
+

[PATCH 5/6] clk: add Clock driver for nuc970

2016-06-25 Thread Wan Zongshun
Signed-off-by: Wan Zongshun 
---
 drivers/clk/Makefile|   1 +
 drivers/clk/nuc900/Makefile |   6 +
 drivers/clk/nuc900/clk-apll.c   | 168 
 drivers/clk/nuc900/clk-ccf.h|  53 +++
 drivers/clk/nuc900/clk-nuc970.c | 920 
 drivers/clk/nuc900/clk-upll.c   |  83 
 6 files changed, 1231 insertions(+)
 create mode 100644 drivers/clk/nuc900/Makefile
 create mode 100644 drivers/clk/nuc900/clk-apll.c
 create mode 100644 drivers/clk/nuc900/clk-ccf.h
 create mode 100644 drivers/clk/nuc900/clk-nuc970.c
 create mode 100644 drivers/clk/nuc900/clk-upll.c

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index dcc5e69..042377d 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -88,3 +88,4 @@ obj-$(CONFIG_ARCH_ZX) += zte/
 obj-$(CONFIG_ARCH_ZYNQ)+= zynq/
 obj-$(CONFIG_H8300)+= h8300/
 obj-$(CONFIG_ARC_PLAT_AXS10X)  += axs10x/
+obj-$(CONFIG_ARCH_W90X900) += nuc900/
diff --git a/drivers/clk/nuc900/Makefile b/drivers/clk/nuc900/Makefile
new file mode 100644
index 000..a6785ab
--- /dev/null
+++ b/drivers/clk/nuc900/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for nuvoton specific clk
+#
+
+obj-$(CONFIG_SOC_NUC970) += clk-apll.o clk-upll.o clk-nuc970.o
+
diff --git a/drivers/clk/nuc900/clk-apll.c b/drivers/clk/nuc900/clk-apll.c
new file mode 100644
index 000..4e1c202
--- /dev/null
+++ b/drivers/clk/nuc900/clk-apll.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "clk-ccf.h"
+
+struct clk_apll {
+   struct clk_hw   hw;
+   void __iomem*base;
+};
+
+#define to_clk_apll(clk) (container_of(clk, struct clk_apll, clk))
+
+static int clk_apll_set_rate(struct clk_hw *hw, unsigned long rate,
+unsigned long parent_rate)
+{
+   struct clk_apll *pll = to_clk_apll(hw);
+   unsigned long reg;
+
+   reg = readl(pll->base) & ~0x0FFF;
+
+   switch (rate) {
+   /*usbh*/
+   case 9600:
+   reg |= 0x8027;
+   break;
+   /*i2s*/
+   case 9840:
+   reg |= 0x8028;
+   break;
+   /*i2s*/
+   case 16950:
+   reg |= 0x21f0;
+   break;
+   /*system default, 264MHz*/
+   case 26400:
+   reg |= 0x15;
+   break;
+   case 3:
+   reg |= 0x18;
+   break;
+   default:
+   reg |= 0x15;
+   break;
+   }
+
+   writel(reg, pll->base);
+
+   return 0;
+}
+
+static unsigned long clk_apll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+   struct clk_apll *pll = to_clk_apll(hw);
+   unsigned long reg = readl(pll->base) & 0x0FFF;
+   unsigned long rate;
+
+   if (parent_rate != 1200)
+   return 0;
+
+   switch (reg) {
+   /*system default, 264MHz*/
+   case 0x15:
+   rate = 26400;
+   break;
+   case 0x18:
+   rate = 3;
+   break;
+   /*usbh*/
+   case 0x8027:
+   rate = 9600;
+   break;
+   /*i2s*/
+   case 0x8028:
+   rate = 9840;
+   break;
+   /*i2s*/
+   case 0x21f0:
+   rate = 16950;
+   break;
+   default:
+   rate = 26400;
+   break;
+   }
+
+   return rate;
+}
+
+static long clk_apll_round_rate(struct clk_hw *hw, unsigned long rate,
+   unsigned long *prate)
+{
+   return rate;
+}
+
+static int clk_apll_enable(struct clk_hw *hw)
+{
+   struct clk_apll *pll = to_clk_apll(hw);
+   unsigned long val;
+
+   val = __raw_readl(pll->base);
+   val &= ~0x1000;
+   val |= 0x4000;
+   __raw_writel(val, pll->base);
+
+   return 0;
+}
+
+static void clk_apll_disable(struct clk_hw *hw)
+{
+   struct clk_apll *pll = to_clk_apll(hw);
+   unsigned long val;
+
+   val = __raw_readl(pll->base);
+   val |= 0x1000;
+   val &= ~0x4000;
+   __raw_writel(val, pll->base);
+}
+
+static struct clk_ops clk_apll_ops = {
+   .recalc_rate = clk_apll_recalc_rate,
+   .enable = clk_apll_enable,
+   .disable = clk_apll_disable,
+   .set_rate = clk_apll_set_rate,
+   .round_rate = clk_apll_round_rate,
+};
+
+struct clk *nuc970_clk_apll(const char *name, const char *parent,
+  

[PATCH 4/6] irqchip: add irqchip driver for nuc900

2016-06-25 Thread Wan Zongshun
This patch is to add irqchip driver support for nuc900 plat,
current this driver only supports nuc970 SoC.

Signed-off-by: Wan Zongshun 
---
 arch/arm/mach-w90x900/include/mach/irqs.h  |  69 ++
 .../mach-w90x900/include/mach/nuc970-regs-aic.h|  53 +++
 drivers/irqchip/Makefile   |   1 +
 drivers/irqchip/irq-nuc900.c   | 104 +
 4 files changed, 227 insertions(+)
 create mode 100644 arch/arm/mach-w90x900/include/mach/nuc970-regs-aic.h
 create mode 100644 drivers/irqchip/irq-nuc900.c

diff --git a/arch/arm/mach-w90x900/include/mach/irqs.h 
b/arch/arm/mach-w90x900/include/mach/irqs.h
index 9d5cba3..c56d4bb 100644
--- a/arch/arm/mach-w90x900/include/mach/irqs.h
+++ b/arch/arm/mach-w90x900/include/mach/irqs.h
@@ -28,6 +28,8 @@
 
 /* Main cpu interrupts */
 
+#if !defined(CONFIG_SOC_NUC970)
+
 #define IRQ_WDTW90X900_IRQ(1)
 #define IRQ_GROUP0 W90X900_IRQ(2)
 #define IRQ_GROUP1 W90X900_IRQ(3)
@@ -83,4 +85,71 @@
 #defineIRQ_GROUP1_IRQ6 0x0040
 #defineIRQ_GROUP1_IRQ7 0x0080
 
+#else
+
+/*For nuc970*/
+#define IRQ_WDTW90X900_IRQ(1)
+#define IRQ_WWDT   W90X900_IRQ(2)
+#define IRQ_LVDW90X900_IRQ(3)
+#define IRQ_EXT0   W90X900_IRQ(4)
+#define IRQ_EXT1   W90X900_IRQ(5)
+#define IRQ_EXT2   W90X900_IRQ(6)
+#define IRQ_EXT3   W90X900_IRQ(7)
+#define IRQ_EXT4   W90X900_IRQ(8)
+#define IRQ_EXT5   W90X900_IRQ(9)
+#define IRQ_EXT6   W90X900_IRQ(10)
+#define IRQ_EXT7   W90X900_IRQ(11)
+#define IRQ_ACTL   W90X900_IRQ(12)
+#define IRQ_LCDW90X900_IRQ(13)
+#define IRQ_CAPW90X900_IRQ(14)
+#define IRQ_RTCW90X900_IRQ(15)
+#define IRQ_TMR0   W90X900_IRQ(16)
+#define IRQ_TMR1   W90X900_IRQ(17)
+#define IRQ_ADCW90X900_IRQ(18)
+#define IRQ_EMC0RX W90X900_IRQ(19)
+#define IRQ_EMC1RX W90X900_IRQ(20)
+#define IRQ_EMC0TX W90X900_IRQ(21)
+#define IRQ_EMC1TX W90X900_IRQ(22)
+#define IRQ_EHCI   W90X900_IRQ(23)
+#define IRQ_OHCI   W90X900_IRQ(24)
+#define IRQ_GDMA0  W90X900_IRQ(25)
+#define IRQ_GDMA1  W90X900_IRQ(26)
+#define IRQ_SDHW90X900_IRQ(27)
+#define IRQ_FMIW90X900_IRQ(28)
+#define IRQ_UDCW90X900_IRQ(29)
+#define IRQ_TMR2   W90X900_IRQ(30)
+#define IRQ_TMR3   W90X900_IRQ(31)
+#define IRQ_TMR4   W90X900_IRQ(32)
+#define IRQ_JPEG   W90X900_IRQ(33)
+#define IRQ_GE2D   W90X900_IRQ(34)
+#define IRQ_CRYPTO W90X900_IRQ(35)
+#define IRQ_UART0  W90X900_IRQ(36)
+#define IRQ_UART1  W90X900_IRQ(37)
+#define IRQ_UART2  W90X900_IRQ(38)
+#define IRQ_UART4  W90X900_IRQ(39)
+#define IRQ_UART6  W90X900_IRQ(40)
+#define IRQ_UART8  W90X900_IRQ(41)
+#define IRQ_UART10 W90X900_IRQ(42)
+#define IRQ_UART3  W90X900_IRQ(43)
+#define IRQ_UART5  W90X900_IRQ(44)
+#define IRQ_UART7  W90X900_IRQ(45)
+#define IRQ_UART9  W90X900_IRQ(46)
+#define IRQ_ETIMER0W90X900_IRQ(47)
+#define IRQ_ETIMER1W90X900_IRQ(48)
+#define IRQ_ETIMER2W90X900_IRQ(49)
+#define IRQ_ETIMER3W90X900_IRQ(50)
+#define IRQ_SPI0   W90X900_IRQ(51)
+#define IRQ_SPI1   W90X900_IRQ(52)
+#define IRQ_I2C0   W90X900_IRQ(53)
+#define IRQ_I2C1   W90X900_IRQ(54)
+#define IRQ_SMC0   W90X900_IRQ(55)
+#define IRQ_SMC1   W90X900_IRQ(56)
+#define IRQ_GPIO   W90X900_IRQ(57)
+#define IRQ_CAN0   W90X900_IRQ(58)
+#define IRQ_CAN1   W90X900_IRQ(59)
+#define IRQ_PWMW90X900_IRQ(60)
+#define IRQ_KPIW90X900_IRQ(61)
+#define NR_IRQS(IRQ_KPI+1)
+#endif
+
 #endif /* __ASM_ARCH_IRQ_H */
diff --git a/arch/arm/mach-w90x900/include/mach/nuc970-regs-aic.h 
b/arch/arm/mach-w90x900/include/mach/nuc970-regs-aic.h
new file mode 100644
index 000..7a77016
--- /dev/null
+++ b/arch/arm/mach-w90x900/include/mach/nuc970-regs-aic.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __ASM_ARCH_REGS_AIC_H
+#define __ASM_ARCH_REGS_AIC_H
+
+/*NUC970 AIC regs*/
+
+#defineREG_AIC_SCR10x00
+#defineREG_AIC_SCR20x04
+#defineREG_AIC_SCR30x08
+#defineREG_AIC_SCR40x0C
+#defineREG_AIC_SCR50x10
+#defineREG_AIC_SCR60x14
+#defineREG_AIC_SCR70x18
+#defineREG_AIC_SCR80x1C
+#defineREG_AIC_SCR90x20
+#defineREG_AIC_SCR10   0x24
+#defineREG_AIC_SCR11   0x28
+#defineREG_AIC_SCR12   0x2C
+#defineREG_AIC_SCR13   0x30
+#defineREG_AIC_SCR14   0x34
+#defineREG_AIC_SCR15   0x38

[PATCH 2/6] ARM: dts: nuc900: Add nuc970 dts files

2016-06-25 Thread Wan Zongshun
This patch is to add dts support for nuc970 platform.

Signed-off-by: Wan Zongshun 
---
 .../devicetree/bindings/arm/nuvoton/nuc970.txt |  30 +++
 arch/arm/boot/dts/Makefile |   1 +
 arch/arm/boot/dts/nuc970-evb.dts   |  20 ++
 arch/arm/boot/dts/nuc970.dtsi  |  93 
 include/dt-bindings/clock/nuc970-clock.h   | 233 +
 5 files changed, 377 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/nuvoton/nuc970.txt
 create mode 100644 arch/arm/boot/dts/nuc970-evb.dts
 create mode 100644 arch/arm/boot/dts/nuc970.dtsi
 create mode 100644 include/dt-bindings/clock/nuc970-clock.h

diff --git a/Documentation/devicetree/bindings/arm/nuvoton/nuc970.txt 
b/Documentation/devicetree/bindings/arm/nuvoton/nuc970.txt
new file mode 100644
index 000..df8637a
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/nuvoton/nuc970.txt
@@ -0,0 +1,30 @@
+Nuvoton NUC970 SoC platform Device Tree Bindings
+--
+
+Boards with the NUC970 SoC shall have the following properties:
+
+Root node required properties:
+- compatible: Should be "nuvoton,nuc970evb", "nuvoton,nuc970"
+
+Timer required properties:
+- compatible: Should be "nuvoton,tmr"
+- reg: Should contain registers location and length
+- interrupts: hwirq is direct mapping to irq number
+- clocks: phandle to input clock.
+
+Clock required properties:
+- compatible: Should be "nuvoton,clk"
+- reg: Should contain registers location and length
+
+Interrupt-controller required properties
+- compatible: Should be "nuvoton,aic"
+- reg: Should contain registers location and length
+- interrupt-cells: set to 1
+
+GCR register required properties:
+- compatible: Should be "nuvoton,gcr"
+- reg: Should contain registers location and length
+
+Uart required properties:
+- compatible: Should be "nuvoton,nuc970-uart"
+- reg: Should contain registers location and length
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 06b6c2d..c2e2a53 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -891,6 +891,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \
 dtb-$(CONFIG_ARCH_ZX) += zx296702-ad1.dtb
 dtb-$(CONFIG_ARCH_ASPEED) += aspeed-bmc-opp-palmetto.dtb \
aspeed-ast2500-evb.dtb
+dtb-$(CONFIG_SOC_NUC970) += nuc970-evb.dtb
 endif
 
 dtstree:= $(srctree)/$(src)
diff --git a/arch/arm/boot/dts/nuc970-evb.dts b/arch/arm/boot/dts/nuc970-evb.dts
new file mode 100644
index 000..bd56ad1
--- /dev/null
+++ b/arch/arm/boot/dts/nuc970-evb.dts
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+#include "nuc970.dtsi"
+
+/ {
+   model = "NUC970 EVB Board";
+   compatible = "nuvoton,nuc970evb", "nuvoton,nuc970";
+
+};
+
diff --git a/arch/arm/boot/dts/nuc970.dtsi b/arch/arm/boot/dts/nuc970.dtsi
new file mode 100644
index 000..8a6c225
--- /dev/null
+++ b/arch/arm/boot/dts/nuc970.dtsi
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016 Wan Zongshun 
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include "skeleton.dtsi"
+#include 
+
+/ {
+   compatible = "nuvoton,nuc970evb", "nuvoton,nuc970";
+
+   interrupt-parent = <&aic>;
+
+   aliases {
+   serial0 = &uart0;
+   };
+
+   memory {
+   reg = <0x 0x0400>;
+   };
+
+   cpus {
+   #address-cells = <0>;
+   #size-cells = <0>;
+
+   cpu {
+   compatible = "arm,arm926ej-s";
+   device_type = "cpu";
+   };
+   };
+
+   ahb@B000 {
+   compatible = "simple-bus";
+   #address-cells = <1>;
+   #size-cells = <1>;
+   reg = <0xB000 0x9000>;
+   ranges;
+
+   gcr: gcr@B000 {
+   compatible = "nuvoton,gcr";
+   reg = <0xB000 0x200>;
+   };
+
+   clks: clk@B200 {
+   compatible = "nuvoton,clk";
+   reg = <0xB200 0x200>;
+   #clock-cells = <1>;
+   };
+
+   

[PATCH 6/6] nuc900: add nuc970 platform defconfig file

2016-06-25 Thread Wan Zongshun
Add nuc970_defconfig file support.

Signed-off-by: Wan Zongshun 
---
 arch/arm/configs/nuc970_defconfig | 1278 +
 1 file changed, 1278 insertions(+)
 create mode 100644 arch/arm/configs/nuc970_defconfig

diff --git a/arch/arm/configs/nuc970_defconfig 
b/arch/arm/configs/nuc970_defconfig
new file mode 100644
index 000..3ee776c
--- /dev/null
+++ b/arch/arm/configs/nuc970_defconfig
@@ -0,0 +1,1278 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux/arm 4.7.0-rc3 Kernel Configuration
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_FIX_EARLYCON_MEM=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_VECTORS_BASE=0x
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+CONFIG_GENERIC_BUG=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_IRQ_WORK=y
+CONFIG_BUILDTIME_EXTABLE_SORT=y
+
+#
+# General setup
+#
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+# CONFIG_COMPILE_TEST is not set
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_LZ4=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_XZ is not set
+# CONFIG_KERNEL_LZO is not set
+# CONFIG_KERNEL_LZ4 is not set
+CONFIG_DEFAULT_HOSTNAME="(none)"
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+CONFIG_FHANDLE=y
+# CONFIG_USELIB is not set
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+# CONFIG_IRQ_DOMAIN_DEBUG is not set
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+
+#
+# Timers subsystem
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ_COMMON=y
+# CONFIG_HZ_PERIODIC is not set
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+
+#
+# CPU/Task time and stats accounting
+#
+CONFIG_TICK_CPU_ACCOUNTING=y
+# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
+# CONFIG_IRQ_TIME_ACCOUNTING is not set
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+
+#
+# RCU Subsystem
+#
+CONFIG_PREEMPT_RCU=y
+# CONFIG_RCU_EXPERT is not set
+CONFIG_SRCU=y
+# CONFIG_TASKS_RCU is not set
+CONFIG_RCU_STALL_COMMON=y
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_RCU_EXPEDITE_BOOT is not set
+# CONFIG_BUILD_BIN2C is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_NMI_LOG_BUF_SHIFT=13
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_CGROUPS=y
+# CONFIG_MEMCG is not set
+# CONFIG_BLK_CGROUP is not set
+CONFIG_CGROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_CFS_BANDWIDTH is not set
+CONFIG_RT_GROUP_SCHED=y
+# CONFIG_CGROUP_PIDS is not set
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_PERF=y
+# CONFIG_CGROUP_DEBUG is not set
+# CONFIG_CHECKPOINT_RESTORE is not set
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+# CONFIG_USER_NS is not set
+CONFIG_PID_NS=y
+# CONFIG_SCHED_AUTOGROUP is not set
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="../rootfs"
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
+CONFIG_RD_GZIP=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_XZ=y
+CONFIG_RD_LZO=y
+CONFIG_RD_LZ4=y
+CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_HAVE_UID16=y
+# CONFIG_EXPERT is not set
+CONFIG_UID16=y
+CONFIG_MULTIUSER=y
+# CONFIG_SGETMASK_SYSCALL is not set
+CONFIG_SYSFS_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ABSOLUTE_PERCPU is not set
+CONFIG_KALLSYMS_BASE_RELATIVE=y
+CONFIG_PRINTK=y
+CONFIG_PRINTK_NMI=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+# CONFIG_BPF_SYSCALL is not set
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_ADVISE_SYSCALLS=y
+# CONFIG_USERFAULTFD is not set
+CONFIG_MEMBARRIER=y
+# CONFIG_EMBEDDED is not set
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_PERF_EVENTS=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SYSTEM_DATA_VERIFICATION is not set
+# CONFIG_PROFILING is not set
+CONFIG_KEXEC_CORE=y
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+# CONFIG_JUMP_LABEL is not set
+# CONFIG_UPROBES is not set
+# CONFIG_HAVE_64BIT_ALIGNED_

[PATCH 0/6] ARM: NUC900: Add NUC970 SoC support

2016-06-25 Thread Wan Zongshun
Hi,

This patch series added Nuvoton new SoC NUC970 development board
support, this nuc970 belongs to nuc900 series, but many features are
not compatible with old nuc900 SoCs like nuc910, nuc920.

Those patches are basing on old w90x900 codes, and are using standard
linux subsystem interface, such as dts, driver/clk, driver/clocksource
, driver/irqchip drivers.

The old w90x900 plat such as nuc910,nuc960 codes will also be changed
to new style according to nuc970 codes after those patches was accepted.

Wan Zongshun (6):
  ARM: NUC900: Add nuc970 machine support
  ARM: dts: nuc900: Add nuc970 dts files
  Clocksource: add nuc970 clocksource driver
  irqchip: add irqchip driver for nuc900
  clk: add Clock driver for nuc970
  nuc900: add nuc970 platform defconfig file

 .../devicetree/bindings/arm/nuvoton/nuc970.txt |   30 +
 arch/arm/boot/dts/Makefile |1 +
 arch/arm/boot/dts/nuc970-evb.dts   |   20 +
 arch/arm/boot/dts/nuc970.dtsi  |   93 ++
 arch/arm/configs/nuc970_defconfig  | 1278 
 arch/arm/mach-w90x900/Kconfig  |   25 +
 arch/arm/mach-w90x900/Makefile |3 +
 arch/arm/mach-w90x900/include/mach/irqs.h  |   69 ++
 .../mach-w90x900/include/mach/nuc970-regs-aic.h|   53 +
 .../mach-w90x900/include/mach/nuc970-regs-gcr.h|   56 +
 .../mach-w90x900/include/mach/nuc970-regs-timer.h  |   44 +
 arch/arm/mach-w90x900/mach-nuc970.c|  144 +++
 drivers/clk/Makefile   |1 +
 drivers/clk/nuc900/Makefile|6 +
 drivers/clk/nuc900/clk-apll.c  |  168 +++
 drivers/clk/nuc900/clk-ccf.h   |   53 +
 drivers/clk/nuc900/clk-nuc970.c|  920 ++
 drivers/clk/nuc900/clk-upll.c  |   83 ++
 drivers/clocksource/Kconfig|8 +
 drivers/clocksource/Makefile   |1 +
 drivers/clocksource/timer-nuc900.c |  207 
 drivers/irqchip/Makefile   |1 +
 drivers/irqchip/irq-nuc900.c   |  104 ++
 include/dt-bindings/clock/nuc970-clock.h   |  233 
 24 files changed, 3601 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/nuvoton/nuc970.txt
 create mode 100644 arch/arm/boot/dts/nuc970-evb.dts
 create mode 100644 arch/arm/boot/dts/nuc970.dtsi
 create mode 100644 arch/arm/configs/nuc970_defconfig
 create mode 100644 arch/arm/mach-w90x900/include/mach/nuc970-regs-aic.h
 create mode 100644 arch/arm/mach-w90x900/include/mach/nuc970-regs-gcr.h
 create mode 100644 arch/arm/mach-w90x900/include/mach/nuc970-regs-timer.h
 create mode 100644 arch/arm/mach-w90x900/mach-nuc970.c
 create mode 100644 drivers/clk/nuc900/Makefile
 create mode 100644 drivers/clk/nuc900/clk-apll.c
 create mode 100644 drivers/clk/nuc900/clk-ccf.h
 create mode 100644 drivers/clk/nuc900/clk-nuc970.c
 create mode 100644 drivers/clk/nuc900/clk-upll.c
 create mode 100644 drivers/clocksource/timer-nuc900.c
 create mode 100644 drivers/irqchip/irq-nuc900.c
 create mode 100644 include/dt-bindings/clock/nuc970-clock.h

-- 
2.7.4



[PATCH 0/6] ARM: NUC900: Add NUC970 SoC support

2016-06-25 Thread Wan Zongshun
Hi,

This patch series added Nuvoton new SoC NUC970 development board
support, this nuc970 belongs to nuc900 series, but many features are
not compatible with old nuc900 SoCs like nuc910, nuc920.

Those patches are basing on old w90x900 codes, and are using standard
linux subsystem interface, such as dts, driver/clk, driver/clocksource
, driver/irqchip drivers.

The old w90x900 plat such as nuc910,nuc960 codes will also be changed
to new style according to nuc970 codes after those patches was accepted.

Wan Zongshun (6):
  ARM: NUC900: Add nuc970 machine support
  ARM: dts: nuc900: Add nuc970 dts files
  Clocksource: add nuc970 clocksource driver
  irqchip: add irqchip driver for nuc900
  clk: add Clock driver for nuc970
  nuc900: add nuc970 platform defconfig file

 .../devicetree/bindings/arm/nuvoton/nuc970.txt |   30 +
 arch/arm/boot/dts/Makefile |1 +
 arch/arm/boot/dts/nuc970-evb.dts   |   20 +
 arch/arm/boot/dts/nuc970.dtsi  |   93 ++
 arch/arm/configs/nuc970_defconfig  | 1278 
 arch/arm/mach-w90x900/Kconfig  |   25 +
 arch/arm/mach-w90x900/Makefile |3 +
 arch/arm/mach-w90x900/include/mach/irqs.h  |   69 ++
 .../mach-w90x900/include/mach/nuc970-regs-aic.h|   53 +
 .../mach-w90x900/include/mach/nuc970-regs-gcr.h|   56 +
 .../mach-w90x900/include/mach/nuc970-regs-timer.h  |   44 +
 arch/arm/mach-w90x900/mach-nuc970.c|  144 +++
 drivers/clk/Makefile   |1 +
 drivers/clk/nuc900/Makefile|6 +
 drivers/clk/nuc900/clk-apll.c  |  168 +++
 drivers/clk/nuc900/clk-ccf.h   |   53 +
 drivers/clk/nuc900/clk-nuc970.c|  920 ++
 drivers/clk/nuc900/clk-upll.c  |   83 ++
 drivers/clocksource/Kconfig|8 +
 drivers/clocksource/Makefile   |1 +
 drivers/clocksource/timer-nuc900.c |  207 
 drivers/irqchip/Makefile   |1 +
 drivers/irqchip/irq-nuc900.c   |  104 ++
 include/dt-bindings/clock/nuc970-clock.h   |  233 
 24 files changed, 3601 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/nuvoton/nuc970.txt
 create mode 100644 arch/arm/boot/dts/nuc970-evb.dts
 create mode 100644 arch/arm/boot/dts/nuc970.dtsi
 create mode 100644 arch/arm/configs/nuc970_defconfig
 create mode 100644 arch/arm/mach-w90x900/include/mach/nuc970-regs-aic.h
 create mode 100644 arch/arm/mach-w90x900/include/mach/nuc970-regs-gcr.h
 create mode 100644 arch/arm/mach-w90x900/include/mach/nuc970-regs-timer.h
 create mode 100644 arch/arm/mach-w90x900/mach-nuc970.c
 create mode 100644 drivers/clk/nuc900/Makefile
 create mode 100644 drivers/clk/nuc900/clk-apll.c
 create mode 100644 drivers/clk/nuc900/clk-ccf.h
 create mode 100644 drivers/clk/nuc900/clk-nuc970.c
 create mode 100644 drivers/clk/nuc900/clk-upll.c
 create mode 100644 drivers/clocksource/timer-nuc900.c
 create mode 100644 drivers/irqchip/irq-nuc900.c
 create mode 100644 include/dt-bindings/clock/nuc970-clock.h

-- 
2.7.4



[PATCH 0/6] ARM: NUC900: Add NUC970 SoC support

2016-06-25 Thread Wan Zongshun
Hi,

This patch series added Nuvoton new SoC NUC970 development board
support, this nuc970 belongs to nuc900 series, but many features are
not compatible with old nuc900 SoCs like nuc910, nuc920.

Those patches are basing on old w90x900 codes, and are using standard
linux subsystem interface, such as dts, driver/clk, driver/clocksource
, driver/irqchip drivers.

The old w90x900 plat such as nuc910,nuc960 codes will also be changed
to new style according to nuc970 codes after those patches was accepted.

Wan Zongshun (6):
  ARM: NUC900: Add nuc970 machine support
  ARM: dts: nuc900: Add nuc970 dts files
  Clocksource: add nuc970 clocksource driver
  irqchip: add irqchip driver for nuc900
  clk: add Clock driver for nuc970
  nuc900: add nuc970 platform defconfig file

 .../devicetree/bindings/arm/nuvoton/nuc970.txt |   30 +
 arch/arm/boot/dts/Makefile |1 +
 arch/arm/boot/dts/nuc970-evb.dts   |   20 +
 arch/arm/boot/dts/nuc970.dtsi  |   93 ++
 arch/arm/configs/nuc970_defconfig  | 1278 
 arch/arm/mach-w90x900/Kconfig  |   25 +
 arch/arm/mach-w90x900/Makefile |3 +
 arch/arm/mach-w90x900/include/mach/irqs.h  |   69 ++
 .../mach-w90x900/include/mach/nuc970-regs-aic.h|   53 +
 .../mach-w90x900/include/mach/nuc970-regs-gcr.h|   56 +
 .../mach-w90x900/include/mach/nuc970-regs-timer.h  |   44 +
 arch/arm/mach-w90x900/mach-nuc970.c|  144 +++
 drivers/clk/Makefile   |1 +
 drivers/clk/nuc900/Makefile|6 +
 drivers/clk/nuc900/clk-apll.c  |  168 +++
 drivers/clk/nuc900/clk-ccf.h   |   53 +
 drivers/clk/nuc900/clk-nuc970.c|  920 ++
 drivers/clk/nuc900/clk-upll.c  |   83 ++
 drivers/clocksource/Kconfig|8 +
 drivers/clocksource/Makefile   |1 +
 drivers/clocksource/timer-nuc900.c |  207 
 drivers/irqchip/Makefile   |1 +
 drivers/irqchip/irq-nuc900.c   |  104 ++
 include/dt-bindings/clock/nuc970-clock.h   |  233 
 24 files changed, 3601 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/nuvoton/nuc970.txt
 create mode 100644 arch/arm/boot/dts/nuc970-evb.dts
 create mode 100644 arch/arm/boot/dts/nuc970.dtsi
 create mode 100644 arch/arm/configs/nuc970_defconfig
 create mode 100644 arch/arm/mach-w90x900/include/mach/nuc970-regs-aic.h
 create mode 100644 arch/arm/mach-w90x900/include/mach/nuc970-regs-gcr.h
 create mode 100644 arch/arm/mach-w90x900/include/mach/nuc970-regs-timer.h
 create mode 100644 arch/arm/mach-w90x900/mach-nuc970.c
 create mode 100644 drivers/clk/nuc900/Makefile
 create mode 100644 drivers/clk/nuc900/clk-apll.c
 create mode 100644 drivers/clk/nuc900/clk-ccf.h
 create mode 100644 drivers/clk/nuc900/clk-nuc970.c
 create mode 100644 drivers/clk/nuc900/clk-upll.c
 create mode 100644 drivers/clocksource/timer-nuc900.c
 create mode 100644 drivers/irqchip/irq-nuc900.c
 create mode 100644 include/dt-bindings/clock/nuc970-clock.h

-- 
2.7.4



[PATCH v2] iommu/amd: Add proper error check in two functions

2016-06-15 Thread Wan Zongshun
From: Wan Zongshun 

This patch is to do the following:

1. Add error check for caller of iommu_device_create.

2. Add error check for caller of iommu_device_link and
move 'iommu = amd_iommu_rlookup_table[dev_data->devid]' out of
iommuv2 capability condition that make iommu_device_link also
use the 'iommu' to make code more clear and no more than 80
characters.

Signed-off-by: Wan Zongshun 
---
Changes from v1:

Don't fail the iommu_init_device() function when the iommu_device_link returned
an error,just print a warning message.
---
 drivers/iommu/amd_iommu.c  | 11 +--
 drivers/iommu/amd_iommu_init.c |  2 ++
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 634f636..dbdcaeb 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -476,6 +476,7 @@ out:
 static int iommu_init_device(struct device *dev)
 {
struct iommu_dev_data *dev_data;
+   struct amd_iommu *iommu;
int devid;
 
if (dev->archdata.iommu)
@@ -491,17 +492,15 @@ static int iommu_init_device(struct device *dev)
 
dev_data->alias = get_alias(dev);
 
-   if (dev_is_pci(dev) && pci_iommuv2_capable(to_pci_dev(dev))) {
-   struct amd_iommu *iommu;
+   iommu = amd_iommu_rlookup_table[dev_data->devid];
 
-   iommu = amd_iommu_rlookup_table[dev_data->devid];
+   if (dev_is_pci(dev) && pci_iommuv2_capable(to_pci_dev(dev)))
dev_data->iommu_v2 = iommu->is_iommu_v2;
-   }
 
dev->archdata.iommu = dev_data;
 
-   iommu_device_link(amd_iommu_rlookup_table[dev_data->devid]->iommu_dev,
- dev);
+   if (iommu_device_link(iommu->iommu_dev, dev))
+   dev_warn(dev, "Creating iommu device link failed in sysfs.\n");
 
return 0;
 }
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 9e00341..73fa986 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -1526,6 +1526,8 @@ static int iommu_init_pci(struct amd_iommu *iommu)
iommu->iommu_dev = iommu_device_create(&iommu->dev->dev, iommu,
   amd_iommu_groups, "ivhd%d",
   iommu->index);
+   if (IS_ERR(iommu->iommu_dev))
+   return PTR_ERR(iommu->iommu_dev);
 
return pci_enable_device(iommu->dev);
 }
-- 
1.9.1



Re: [PATCH v2] iommu/amd: Set AMD iommu callbacks for platform bus driver

2016-06-13 Thread Wan ZongShun
2016-05-10 21:21 GMT+08:00 Wan Zongshun :
> From: Wan Zongshun 
>
> AMD has more drivers will use ACPI to platform bus driver later,
> all those devices need iommu support, for example: eMMC driver.
>
> For latest AMD eMMC controller, it will utilize sdhci-acpi.c driver,
> which will rely on platform bus to match device and driver, where we
> will set 'dev' of struct platform_device as map_sg parameter passing
> to iommu driver for DMA request, so the iommu-ops are needed on the
> platform bus.

Joerg,

How about this patch? it will impact our new eMMC controller driver bringup.


Thanks.

>
> Signed-off-by: Wan Zongshun 
>
> ---
> changes from v1: Add comment why the iommu-ops are needed on platform bus.
> ---
>  drivers/iommu/amd_iommu.c | 4 
>  1 file changed, 4 insertions(+)
>
> diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
> index c430c10..547cdd4 100644
> --- a/drivers/iommu/amd_iommu.c
> +++ b/drivers/iommu/amd_iommu.c
> @@ -21,6 +21,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -2980,6 +2981,9 @@ int __init amd_iommu_init_api(void)
> if (err)
> return err;
>  #endif
> +   err = bus_set_iommu(&platform_bus_type, &amd_iommu_ops);
> +   if (err)
> +   return err;
> return 0;
>  }
>
> --
> 1.9.1
>



-- 
---
Vincent Wan(Zongshun)
www.mcuos.com


Re: [Patch v4 9/9] iommu/amd: Check the validation of irq table and domain id

2016-05-28 Thread Wan Zongshun



 Original Message 

From: Baoquan HE 

If not valid just skip reserving the old domain id.

Signed-off-by: Baoquan He 
---
 drivers/iommu/amd_iommu.c   | 4 
 drivers/iommu/amd_iommu_init.c  | 5 +++--
 drivers/iommu/amd_iommu_types.h | 5 +
 3 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index f3bd7fd..40c4a05 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -3697,10 +3697,6 @@ struct amd_ir_data {

 static struct irq_chip amd_ir_chip;

-#define DTE_IRQ_PHYS_ADDR_MASK (((1ULL << 45)-1) << 6)
-#define DTE_IRQ_REMAP_INTCTL(2ULL << 60)
-#define DTE_IRQ_TABLE_LEN   (8ULL << 1)
-#define DTE_IRQ_REMAP_ENABLE1ULL


At least, you should give reason comments to why you want move it.

Any drivers files you want to use them as well?



 static void set_dte_irq_entry(u16 devid, struct irq_remap_table *table)
 {
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 47e5972..263704a 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -670,7 +670,7 @@ static int copy_dev_tables(void)
u32 lo, hi, devid;
phys_addr_t old_devtb_phys;
struct dev_table_entry *old_devtb;
-   u16 dom_id, dte_v;
+   u16 dom_id, dte_v, irq_v;
struct amd_iommu *iommu;
static int copied;

@@ -692,7 +692,8 @@ static int copy_dev_tables(void)
 amd_iommu_dev_table[devid] = old_devtb[devid];
 dom_id = amd_iommu_dev_table[devid].data[1] & 
DEV_DOMID_MASK;
dte_v = amd_iommu_dev_table[devid].data[0] & DTE_FLAG_V;
-   if (!dte_v)
+   irq_v = amd_iommu_dev_table[devid].data[2] & 
DTE_IRQ_REMAP_ENABLE;
+   if (!dte_v || !irq_v || !dom_id)
continue;
 __set_bit(dom_id, amd_iommu_pd_alloc_bitmap);
 }
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
index 34acd73..08340f5 100644
--- a/drivers/iommu/amd_iommu_types.h
+++ b/drivers/iommu/amd_iommu_types.h
@@ -224,6 +224,11 @@

 #define PPR_REQ_FAULT  0x01

+#define DTE_IRQ_PHYS_ADDR_MASK (((1ULL << 45)-1) << 6)
+#define DTE_IRQ_REMAP_INTCTL(2ULL << 60)
+#define DTE_IRQ_TABLE_LEN   (8ULL << 1)
+#define DTE_IRQ_REMAP_ENABLE1ULL
+
 #define PAGE_MODE_NONE0x00
 #define PAGE_MODE_1_LEVEL 0x01
 #define PAGE_MODE_2_LEVEL 0x02



Re: [Patch v4 7/9] iommu/amd: copy old trans table from old kernel

2016-05-28 Thread Wan Zongshun



 Original Message 

From: Baoquan HE 

Here several things need be done:
1) Initialize amd_iommu_dev_table because it was set several times
   since kdump kernel reboot. We don't need the set because we will
   copy the content from old kernel.
2) Re-enable event/cmd buffer
3) Install the DTE table to reg
4) Flush all caches

Signed-off-by: Baoquan He 
---
 drivers/iommu/amd_iommu_init.c | 47 +-
 1 file changed, 42 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 71c7ac9..66a1fa5 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -35,7 +35,7 @@
 #include 
 #include 
 #include 
-
+#include 
 #include "amd_iommu_proto.h"
 #include "amd_iommu_types.h"
 #include "irq_remapping.h"
@@ -675,7 +675,7 @@ static int copy_dev_tables(void)
static int copied;

 for_each_iommu(iommu) {
-   if (!translation_pre_enabled()) {
+   if (!translation_pre_enabled(iommu)) {
pr_err("IOMMU:%d is not pre-enabled!/n", iommu->index);
return -1;
}
@@ -1160,8 +1160,13 @@ static int __init init_iommu_one(struct amd_iommu 
*iommu, struct ivhd_header *h)
iommu->int_enabled = false;

init_translation_status(iommu);
+   if (translation_pre_enabled(iommu) && !is_kdump_kernel()) {
+clear_translation_pre_enabled(iommu);
+pr_warn("Translation was enabled for IOMMU:%d but we are 
not in kdump mode\n",
+iommu->index);
+}

-   if (translation_pre_enabled())
+   if (translation_pre_enabled(iommu))
pr_warn("Translation is already enabled - trying to copy translation 
structures\n");

ret = init_iommu_from_acpi(iommu, h);
@@ -1730,9 +1735,41 @@ static void early_enable_iommu(struct amd_iommu *iommu)
 static void early_enable_iommus(void)
 {
struct amd_iommu *iommu;
+   bool is_pre_enabled=false;

-   for_each_iommu(iommu)
-   early_enable_iommu(iommu);
+   for_each_iommu(iommu) {
+   if ( translation_pre_enabled(iommu) ) {
+   is_pre_enabled = true;
+   break;
+   }
+   }


I wonder if you consider multi-iommus condition for your those series 
patches?



+
+   if ( !is_pre_enabled) {


Why not use translation_pre_enabled(iommu) to judge pre-enable directly?


+   for_each_iommu(iommu)
+   early_enable_iommu(iommu);
+   } else {
+   if (copy_dev_tables()) {
+   pr_err("Failed to copy translation tables from previous 
kernel.\n");
+   /*
+* If failed to copy dev tables from old kernel, 
continue to proceed
+* as it does in normal kernel.
+*/
+   for_each_iommu(iommu) {
+   clear_translation_pre_enabled(iommu);
+   early_enable_iommu(iommu);
+   }
+   } else {
+   pr_info("Copied translation tables from previous 
kernel.\n");
+   for_each_iommu(iommu) {
+   iommu_feature_disable(iommu, CONTROL_CMDBUF_EN);
+   iommu_feature_disable(iommu, 
CONTROL_EVT_LOG_EN);
+   iommu_enable_command_buffer(iommu);
+   iommu_enable_event_buffer(iommu);
+   iommu_set_device_table(iommu);
+   iommu_flush_all_caches(iommu);
+   }
+   }
+   }
 }

 static void enable_iommus_v2(void)



Re: [Patch v4 6/9] iommu/amd: Add function copy_dev_tables

2016-05-28 Thread Wan Zongshun



 Original Message 

Add function copy_dev_tables to copy old DTE of the 1st kernel to
the new DTE table. Since all iommu share the same DTE table the
copy only need be done once as long as the physical address of
old DTE table is retrieved from iommu reg. Besides the old domain
id occupied in 1st kernel need be reserved in order to avoid touch
the old translation tables.

Signed-off-by: Baoquan He 
---
 drivers/iommu/amd_iommu.c   |  2 +-
 drivers/iommu/amd_iommu_init.c  | 38 ++
 drivers/iommu/amd_iommu_types.h |  1 +
 3 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 1c916cc..f3bd7fd 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -2081,7 +2081,7 @@ static void set_dte_entry(u16 devid, struct 
protection_domain *domain, bool ats)
flags|= tmp;
}

-   flags &= ~(0xUL);
+   flags &= ~DEV_DOMID_MASK;
flags |= domain->id;

amd_iommu_dev_table[devid].data[1]  = flags;
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 9c1aa54..71c7ac9 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -664,6 +664,44 @@ static int get_dev_entry_bit(u16 devid, u8 bit)
 }


+static int copy_dev_tables(void)
+{
+   u64 entry;
+   u32 lo, hi, devid;
+   phys_addr_t old_devtb_phys;
+   struct dev_table_entry *old_devtb;
+   u16 dom_id, dte_v;
+   struct amd_iommu *iommu;
+   static int copied;
+
+for_each_iommu(iommu) {
+   if (!translation_pre_enabled()) {
+   pr_err("IOMMU:%d is not pre-enabled!/n", iommu->index);
+   return -1;
+   }


If one iommu is not pre-enabled, all iommus will be exit the copy.


+
+   if (copied)
+   continue;
+
+lo = readl(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET);
+hi = readl(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET + 4);
+entry = (((u64) hi) << 32) + lo;
+old_devtb_phys = entry & PAGE_MASK;
+old_devtb = memremap(old_devtb_phys, dev_table_size, 
MEMREMAP_WB);
+for (devid = 0; devid <= amd_iommu_last_bdf; ++devid) {
+amd_iommu_dev_table[devid] = old_devtb[devid];
+dom_id = amd_iommu_dev_table[devid].data[1] & 
DEV_DOMID_MASK;
+   dte_v = amd_iommu_dev_table[devid].data[0] & DTE_FLAG_V;
+   if (!dte_v)
+   continue;
+__set_bit(dom_id, amd_iommu_pd_alloc_bitmap);
+}
+   memunmap(old_devtb);
+   copied = 1;
+}
+   return 0;
+}
+
 void amd_iommu_apply_erratum_63(u16 devid)
 {
int sysmgt;
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
index 7796edf..34acd73 100644
--- a/drivers/iommu/amd_iommu_types.h
+++ b/drivers/iommu/amd_iommu_types.h
@@ -311,6 +311,7 @@
 #define DTE_FLAG_MASK  (0x3ffULL << 32)
 #define DTE_GLX_SHIFT  (56)
 #define DTE_GLX_MASK   (3)
+#define DEV_DOMID_MASK 0xULL

 #define DTE_GCR3_VAL_A(x)  (((x) >> 12) & 0x7ULL)
 #define DTE_GCR3_VAL_B(x)  (((x) >> 15) & 0x0ULL)



Re: [Patch v4 3/9] iommu/amd: Detect pre enabled translation

2016-05-28 Thread Wan Zongshun



 Original Message 

Add functions to check whether translation is already enabled in IOMMU.

Signed-off-by: Baoquan He 
---
 drivers/iommu/amd_iommu_init.c  | 25 +
 drivers/iommu/amd_iommu_types.h |  4 
 2 files changed, 29 insertions(+)

diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 8361367d..9e1dfcb 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -229,6 +229,26 @@ static int amd_iommu_enable_interrupts(void);
 static int __init iommu_go_to_state(enum iommu_init_state state);
 static void init_device_table_dma(void);

+
+static bool translation_pre_enabled(struct amd_iommu *iommu)
+{
+   return (iommu->flags & AMD_IOMMU_FLAG_TRANS_PRE_ENABLED);
+}
+
+static void clear_translation_pre_enabled(struct amd_iommu *iommu)
+{
+iommu->flags &= ~AMD_IOMMU_FLAG_TRANS_PRE_ENABLED;
+}
+
+static void init_translation_status(struct amd_iommu *iommu)
+{
+   u32 ctrl;
+
+   ctrl = readl(iommu->mmio_base + MMIO_CONTROL_OFFSET);
+   if (ctrl & (1int_enabled = false;

+   init_translation_status(iommu);
+
+   if (translation_pre_enabled())
+   pr_warn("Translation is already enabled - trying to copy translation 
structures\n");
+


You missed this 'iommu' parameter here, even I saw you fixed it in 
another patch, but please keep each patch to be meaningful.



ret = init_iommu_from_acpi(iommu, h);
if (ret)
return ret;
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
index 9d32b20..01783cc 100644
--- a/drivers/iommu/amd_iommu_types.h
+++ b/drivers/iommu/amd_iommu_types.h
@@ -384,6 +384,7 @@ extern struct kmem_cache *amd_iommu_irq_cache;
 #define APERTURE_PAGE_INDEX(a) (((a) >> 21) & 0x3fULL)


+
 /*
  * This struct is used to pass information about
  * incoming PPR faults around.
@@ -401,6 +402,8 @@ struct amd_iommu_fault {
 struct iommu_domain;
 struct irq_domain;

+#define AMD_IOMMU_FLAG_TRANS_PRE_ENABLED  (1 << 0)
+
 /*
  * This structure contains generic data for  IOMMU protection domains
  * independent of their use.
@@ -525,6 +528,7 @@ struct amd_iommu {
struct irq_domain *ir_domain;
struct irq_domain *msi_domain;
 #endif
+   u32 flags;
 };

 struct devid_map {



[PATCH] iommu/amd: Add proper error check in two functions

2016-05-10 Thread Wan Zongshun
From: Wan Zongshun 

This patch is to do the following:

1. Add error check for caller of iommu_device_create.

2. Add error check for caller of iommu_device_link and
move 'iommu = amd_iommu_rlookup_table[dev_data->devid]' out of
iommuv2 capability condition that make iommu_device_link also
use the 'iommu' to make code more clear and no more than 80
characters.

Signed-off-by: Wan Zongshun 
---
 drivers/iommu/amd_iommu.c  | 12 
 drivers/iommu/amd_iommu_init.c |  2 ++
 2 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 547cdd4..232a3b9 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -414,6 +414,7 @@ out:
 static int iommu_init_device(struct device *dev)
 {
struct iommu_dev_data *dev_data;
+   struct amd_iommu *iommu;
int devid;
 
if (dev->archdata.iommu)
@@ -427,19 +428,14 @@ static int iommu_init_device(struct device *dev)
if (!dev_data)
return -ENOMEM;
 
-   if (dev_is_pci(dev) && pci_iommuv2_capable(to_pci_dev(dev))) {
-   struct amd_iommu *iommu;
+   iommu = amd_iommu_rlookup_table[dev_data->devid];
 
-   iommu = amd_iommu_rlookup_table[dev_data->devid];
+   if (dev_is_pci(dev) && pci_iommuv2_capable(to_pci_dev(dev)))
dev_data->iommu_v2 = iommu->is_iommu_v2;
-   }
 
dev->archdata.iommu = dev_data;
 
-   iommu_device_link(amd_iommu_rlookup_table[dev_data->devid]->iommu_dev,
- dev);
-
-   return 0;
+   return iommu_device_link(iommu->iommu_dev, dev);
 }
 
 static void iommu_ignore_device(struct device *dev)
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 9e00341..73fa986 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -1526,6 +1526,8 @@ static int iommu_init_pci(struct amd_iommu *iommu)
iommu->iommu_dev = iommu_device_create(&iommu->dev->dev, iommu,
   amd_iommu_groups, "ivhd%d",
   iommu->index);
+   if (IS_ERR(iommu->iommu_dev))
+   return PTR_ERR(iommu->iommu_dev);
 
return pci_enable_device(iommu->dev);
 }
-- 
1.9.1



[PATCH v2] iommu/amd: Set AMD iommu callbacks for platform bus driver

2016-05-09 Thread Wan Zongshun
From: Wan Zongshun 

AMD has more drivers will use ACPI to platform bus driver later,
all those devices need iommu support, for example: eMMC driver.

For latest AMD eMMC controller, it will utilize sdhci-acpi.c driver,
which will rely on platform bus to match device and driver, where we
will set 'dev' of struct platform_device as map_sg parameter passing
to iommu driver for DMA request, so the iommu-ops are needed on the
platform bus.

Signed-off-by: Wan Zongshun 

---
changes from v1: Add comment why the iommu-ops are needed on platform bus.
---
 drivers/iommu/amd_iommu.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index c430c10..547cdd4 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -21,6 +21,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -2980,6 +2981,9 @@ int __init amd_iommu_init_api(void)
if (err)
return err;
 #endif
+   err = bus_set_iommu(&platform_bus_type, &amd_iommu_ops);
+   if (err)
+   return err;
return 0;
 }
 
-- 
1.9.1



Re: [PATCH] iommu/amd: Set AMD iommu callbacks for platform bus driver

2016-05-09 Thread Wan Zongshun



 Original Message 

On Thu, Apr 14, 2016 at 09:28:53AM -0400, Wan Zongshun wrote:

From: Wan Zongshun 

AMD has more drivers will use ACPI to platform bus driver later,
all those devices need iommu support, such as eMMC acpi driver.

Signed-off-by: Wan Zongshun 
---
 drivers/iommu/amd_iommu.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index c430c10..547cdd4 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -21,6 +21,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -2980,6 +2981,9 @@ int __init amd_iommu_init_api(void)
if (err)
return err;
 #endif
+   err = bus_set_iommu(&platform_bus_type, &amd_iommu_ops);
+   if (err)
+   return err;


Is the platform_bus_type always defined or does this code needs to be
guarded by another ifdef?


Joerg,

Currently, Only New eMMC driver will rely on this sdhci-acpi.c, but I 
could not find a suitable ifdef XXX micro to limit this 
platform_bus_type here like AMBA bus type before.


Do you think this MMC_SDHCI_ACPI is ok?

Vincent.





Joerg



Re: [RFT v2] iommu/amd: use subsys_initcall() on amdv2 iommu

2016-04-18 Thread Wan Zongshun



 Original Message 

On Mon, Apr 18, 2016 at 10:02:24AM +0300, Oded Gabbay wrote:

On Mon, Apr 18, 2016 at 9:55 AM, Luis R. Rodriguez  wrote:


On Apr 18, 2016 7:48 AM, "Oded Gabbay"  wrote:


On Wed, Apr 13, 2016 at 1:07 AM, Luis R. Rodriguez 
wrote:

On Mon, Apr 11, 2016 at 03:52:43PM +0200, Christian König wrote:

Am 11.04.2016 um 15:39 schrieb Oded Gabbay:

On Mon, Apr 11, 2016 at 4:28 PM, Christian König
 wrote:

Am 09.04.2016 um 02:25 schrieb Luis R. Rodriguez:

On Tue, Mar 29, 2016 at 10:41 AM, Luis R. Rodriguez
 wrote:

We need to ensure amd iommu v2 initializes before
driver uses such as drivers/gpu/drm/amd/amdkfd/kfd_module.c,
to do this make its init routine a subsys_initcall() which
ensures its load init is called first than modules when
built-in.

This reverts the old work around implemented through commit
1bacc894c227fad8a7 ("drivers: Move iommu/ before gpu/ in
Makefile"),
instead of making the dependency implicit by linker order this
makes the ordering requirement explicit through proper kernel
APIs.

Cc: Oded Gabbay 
Cc: Christian König 
Signed-off-by: Luis R. Rodriguez 


Sorry for not responding earlier. Just coming back to all the stuff
on my TODO list.

Patch is Acked-by: Christian König 


Christian,
Just wanted to be sure if you tested this patch-set or not.


I did NOT tested it. If AMD IOMMU requires something which will now
initialize after the IOMMU module we will obviously run into trouble
again.

I assumed that the creator of the patch did some testing.


Nope, hence [RTF] Request For Testing.


I don't think it should be merged without testing. If you already
tested it than fine. If not, I think I can do it in the next week or
so (just came back from PTO).


Yeah, agree totally.


Agreed, please let me know if someone is able to test and confirm
this works. It should work.

   Luis


Hi,
So I finally got to test this patch and it's not working.
The reason is that AMD IOMMUv2 gets initialized *before* AMD IOMMUv1
driver !


Thanks can you try using late_initcall() instead then?

   Luis


That will make it initialize *after* drm subsystem, which will cause
another bug.


Hold up, I thought that we needed AMD IOMMUv2 to get initialized
before AMD IOMMUv1 ? That's what the patch did. Can someone clarify
the requirements then?


We must keep AMD IOMMUv2 to get initialized after AMD IOMMUv1, So your 
patch make the sequence reverse.




I'll provide some review of the current state of affairs first, without the
patch. AMD IOMMUv1 uses x86_init.iommu.iommu_init and that has its own init
semantics. Specifically that gets called via pci_iommu_init() which is pegged
on the init order via rootfs_initcall(pci_iommu_init);

Then AMD IOMMUv2 uses module_init() and that when is built-in falls on to
__initcall() which is device_initcall().


Exactly, it is amd iommu v1 v2 call sequence.


The order is:

#define pure_initcall(fn)   __define_initcall(fn, 0)

#define core_initcall(fn)   __define_initcall(fn, 1)
#define core_initcall_sync(fn)  __define_initcall(fn, 1s)
#define postcore_initcall(fn)   __define_initcall(fn, 2)
#define postcore_initcall_sync(fn)  __define_initcall(fn, 2s)
#define arch_initcall(fn)   __define_initcall(fn, 3)
#define arch_initcall_sync(fn)  __define_initcall(fn, 3s)
#define subsys_initcall(fn) __define_initcall(fn, 4)
#define subsys_initcall_sync(fn)__define_initcall(fn, 4s)
#define fs_initcall(fn) __define_initcall(fn, 5)
#define fs_initcall_sync(fn)__define_initcall(fn, 5s)
#define rootfs_initcall(fn) __define_initcall(fn, rootfs)
#define device_initcall(fn) __define_initcall(fn, 6)
#define device_initcall_sync(fn)__define_initcall(fn, 6s)
#define late_initcall(fn)   __define_initcall(fn, 7)
#define late_initcall_sync(fn)  __define_initcall(fn, 7s)

So technically rootfs_initcall() (v1 amd) should be being called
first already, and after that AMD IOMMUv2 gets called next.

You said that with my patch you saw AMD IOMMUv2 kick off first,
that was intentional as I thought that's what you needed. Can
someone please describe the requirements?

Also what does drm use that you say has a conflict already? What
drm code are we talking about exactly ?


You have to take carefully to arrange the calling sequence for iommuv1, 
iommuv2, kfd module, and drm like the following sequence : v1 ->v2->kfd, 
drm.


iommuv1 -- rootfs_initcall(fn)
IOMMUV2 -- device_initcall(fn)
kfd module -- late_initcall(fn)
drm -- late_initcall(fn)

Thanks!
Wan Zongshun.



   Luis
___
iommu mailing list
io...@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu



[PATCH] iommu/amd: Set AMD iommu callbacks for platform bus driver

2016-04-13 Thread Wan Zongshun
From: Wan Zongshun 

AMD has more drivers will use ACPI to platform bus driver later,
all those devices need iommu support, such as eMMC acpi driver.

Signed-off-by: Wan Zongshun 
---
 drivers/iommu/amd_iommu.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index c430c10..547cdd4 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -21,6 +21,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -2980,6 +2981,9 @@ int __init amd_iommu_init_api(void)
if (err)
return err;
 #endif
+   err = bus_set_iommu(&platform_bus_type, &amd_iommu_ops);
+   if (err)
+   return err;
return 0;
 }
 
-- 
1.9.1



[PATCH V3 9/9] iommu/amd: Set AMD iommu callbacks for amba bus

2016-03-31 Thread Wan Zongshun
From: Wan Zongshun 

AMD Uart DMA belongs to ACPI HID type device, and its driver
is basing on AMBA Bus, need also IOMMU support.

This patch is just to set the AMD iommu callbacks for amba bus.

Signed-off-by: Wan Zongshun 
---
 drivers/iommu/amd_iommu.c | 13 -
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 713e7ea..c430c10 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -20,6 +20,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -2969,7 +2970,17 @@ static struct dma_map_ops amd_iommu_dma_ops = {
 
 int __init amd_iommu_init_api(void)
 {
-   return bus_set_iommu(&pci_bus_type, &amd_iommu_ops);
+   int err = 0;
+
+   err = bus_set_iommu(&pci_bus_type, &amd_iommu_ops);
+   if (err)
+   return err;
+#ifdef CONFIG_ARM_AMBA
+   err = bus_set_iommu(&amba_bustype, &amd_iommu_ops);
+   if (err)
+   return err;
+#endif
+   return 0;
 }
 
 int __init amd_iommu_init_dma_ops(void)
-- 
1.9.1



[PATCH V3 2/9] iommu/amd: Modify ivhd_header structure to support type 11h and 40h

2016-03-31 Thread Wan Zongshun
From: Suravee Suthikulpanit 

This patch modifies the existing struct ivhd_header,
which currently only support IVHD type 0x10, to add
new fields from IVHD type 11h and 40h.

It also modifies the pointer calculation to allow
support for IVHD type 11h and 40h

Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd_iommu_init.c | 35 +--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index dff1e01..22e078b 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -398,6 +398,22 @@ static void __init iommu_unmap_mmio_space(struct amd_iommu 
*iommu)
release_mem_region(iommu->mmio_phys, iommu->mmio_phys_end);
 }
 
+static inline u32 get_ivhd_header_size(struct ivhd_header *h)
+{
+   u32 size = 0;
+
+   switch (h->type) {
+   case 0x10:
+   size = 24;
+   break;
+   case 0x11:
+   case 0x40:
+   size = 40;
+   break;
+   }
+   return size;
+}
+
 /
  *
  * The functions below belong to the first pass of AMD IOMMU ACPI table
@@ -424,7 +440,14 @@ static int __init find_last_devid_from_ivhd(struct 
ivhd_header *h)
u8 *p = (void *)h, *end = (void *)h;
struct ivhd_entry *dev;
 
-   p += sizeof(*h);
+   u32 ivhd_size = get_ivhd_header_size(h);
+
+   if (!ivhd_size) {
+   pr_err("AMD-Vi: Unsupported IVHD type %#x\n", h->type);
+   return -EINVAL;
+   }
+
+   p += ivhd_size;
end += h->length;
 
while (p < end) {
@@ -789,6 +812,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
u32 dev_i, ext_flags = 0;
bool alias = false;
struct ivhd_entry *e;
+   u32 ivhd_size;
int ret;
 
 
@@ -804,7 +828,14 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
/*
 * Done. Now parse the device entries
 */
-   p += sizeof(struct ivhd_header);
+   ivhd_size = get_ivhd_header_size(h);
+   if (!ivhd_size) {
+   pr_err("AMD-Vi: Unsupported IVHD type %#x\n", h->type);
+   return -EINVAL;
+   }
+
+   p += ivhd_size;
+
end += h->length;
 
 
-- 
1.9.1



[PATCH V3 4/9] iommu/amd: Add new map for storing IVHD dev entry type HID

2016-03-31 Thread Wan Zongshun
From: Wan Zongshun 

This patch introduces acpihid_map, which is used to store
the new IVHD device entry extracted from BIOS IVRS table.

It also provides a utility function add_acpi_hid_device(),
to add this types of devices to the map.

Signed-off-by: Wan Zongshun 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd_iommu.c   |   1 +
 drivers/iommu/amd_iommu_init.c  | 122 
 drivers/iommu/amd_iommu_types.h |  14 +
 3 files changed, 137 insertions(+)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 374c129..d8e59a8 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -72,6 +72,7 @@ static DEFINE_SPINLOCK(dev_data_list_lock);
 
 LIST_HEAD(ioapic_map);
 LIST_HEAD(hpet_map);
+LIST_HEAD(acpihid_map);
 
 /*
  * Domain for untranslated devices - only allocated
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 8f49612..e7ebfa2 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -60,6 +60,10 @@
 #define IVHD_DEV_SPECIAL   0x48
 #define IVHD_DEV_ACPI_HID  0xf0
 
+#define UID_NOT_PRESENT 0
+#define UID_IS_INTEGER  1
+#define UID_IS_CHARACTER2
+
 #define IVHD_SPECIAL_IOAPIC1
 #define IVHD_SPECIAL_HPET  2
 
@@ -116,6 +120,11 @@ struct ivhd_entry {
u16 devid;
u8 flags;
u32 ext;
+   u32 hidh;
+   u64 cid;
+   u8 uidf;
+   u8 uidl;
+   u8 uid;
 } __attribute__((packed));
 
 /*
@@ -224,8 +233,12 @@ enum iommu_init_state {
 #define EARLY_MAP_SIZE 4
 static struct devid_map __initdata early_ioapic_map[EARLY_MAP_SIZE];
 static struct devid_map __initdata early_hpet_map[EARLY_MAP_SIZE];
+static struct acpihid_map_entry __initdata early_acpihid_map[EARLY_MAP_SIZE];
+
 static int __initdata early_ioapic_map_size;
 static int __initdata early_hpet_map_size;
+static int __initdata early_acpihid_map_size;
+
 static bool __initdata cmdline_maps;
 
 static enum iommu_init_state init_state = IOMMU_START_STATE;
@@ -765,6 +778,42 @@ static int __init add_special_device(u8 type, u8 id, u16 
*devid, bool cmd_line)
return 0;
 }
 
+static int __init add_acpi_hid_device(u8 *hid, u8 *uid, u16 *devid,
+ bool cmd_line)
+{
+   struct acpihid_map_entry *entry;
+   struct list_head *list = &acpihid_map;
+
+   list_for_each_entry(entry, list, list) {
+   if (strcmp(entry->hid, hid) ||
+   (*uid && *entry->uid && strcmp(entry->uid, uid)) ||
+   !entry->cmd_line)
+   continue;
+
+   pr_info("AMD-Vi: Command-line override for hid:%s uid:%s\n",
+   hid, uid);
+   *devid = entry->devid;
+   return 0;
+   }
+
+   entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+   if (!entry)
+   return -ENOMEM;
+
+   memcpy(entry->uid, uid, strlen(uid));
+   memcpy(entry->hid, hid, strlen(hid));
+   entry->devid = *devid;
+   entry->cmd_line = cmd_line;
+   entry->root_devid = (entry->devid & (~0x7));
+
+   pr_info("AMD-Vi:%s, add hid:%s, uid:%s, rdevid:%d\n",
+   entry->cmd_line ? "cmd" : "ivrs",
+   entry->hid, entry->uid, entry->root_devid);
+
+   list_add_tail(&entry->list, list);
+   return 0;
+}
+
 static int __init add_early_maps(void)
 {
int i, ret;
@@ -787,6 +836,15 @@ static int __init add_early_maps(void)
return ret;
}
 
+   for (i = 0; i < early_acpihid_map_size; ++i) {
+   ret = add_acpi_hid_device(early_acpihid_map[i].hid,
+ early_acpihid_map[i].uid,
+ &early_acpihid_map[i].devid,
+ early_acpihid_map[i].cmd_line);
+   if (ret)
+   return ret;
+   }
+
return 0;
 }
 
@@ -1007,6 +1065,70 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
 
break;
}
+   case IVHD_DEV_ACPI_HID: {
+   u16 devid;
+   u8 hid[ACPIHID_HID_LEN] = {0};
+   u8 uid[ACPIHID_UID_LEN] = {0};
+   int ret;
+
+   if (h->type != 0x40) {
+   pr_err(FW_BUG "Invalid IVHD device type %#x\n",
+  e->type);
+   break;
+   }
+
+   memcpy(hid, (u8 *)(&e->ext), ACPIHID_HID_LEN - 1);
+   hid[ACPIHID_HID_LEN - 1] = &#x

[PATCH V3 0/9] iommu/amd: enable ACPI hardware ID device support

2016-03-31 Thread Wan Zongshun
From: Wan Zongshun 

There are some devices indentified using ACPI HID format in AMD chip.
This patch series enable iommu support for those ACPI HID device, 
since the existing AMD iommu only supports PCI bus based device.

The latest public version of AMD IOMMU specification that describes
the support for IVHD type 40h and ACPI HID IVHD device type, 
implemented by this patch series, is available here:

http://support.amd.com/TechDocs/48882_IOMMU.pdf

The V2 added two new patches: patch 5 and patch 8 according to Joerg's
comments, there is a little modification in patch 6 to distinguish pci
and none pci.

The V3 added the fix for the booting issue Joerg experienced on the CZ
platform due to the IOMMU performance counter init code.

Suravee Suthikulpanit (4):
  iommu/amd: Adding Extended Feature Register check for PC support
  iommu/amd: Modify ivhd_header structure to support type 11h and 40h
  iommu/amd: Use the most comprehensive IVHD type that the driver can
support
  iommu/amd: Introduces ivrs_acpihid kernel parameter

Wan Zongshun (5):
  iommu/amd: Add new map for storing IVHD dev entry type HID
  iommu/amd: Make call-sites of get_device_id aware of its return value
  iommu/amd: Add iommu support for ACPI HID devices
  iommu/amd: Manage iommu_group for ACPI HID devices
  iommu/amd: Set AMD iommu callbacks for amba bus

 Documentation/kernel-parameters.txt |   7 +
 drivers/iommu/amd_iommu.c   | 167 +++---
 drivers/iommu/amd_iommu_init.c  | 329 +++-
 drivers/iommu/amd_iommu_types.h |  14 ++
 4 files changed, 457 insertions(+), 60 deletions(-)

-- 
1.9.1



[PATCH V3 5/9] iommu/amd: Introduces ivrs_acpihid kernel parameter

2016-03-31 Thread Wan Zongshun
From: Suravee Suthikulpanit 

This patch introduces a new kernel parameter, ivrs_acpihid.
This is used to override existing ACPI-HID IVHD device entry,
or add an entry in case it is missing in the IVHD.

Signed-off-by: Wan Zongshun 
Signed-off-by: Suravee Suthikulpanit 
---
 Documentation/kernel-parameters.txt |  7 +++
 drivers/iommu/amd_iommu_init.c  | 33 +
 2 files changed, 40 insertions(+)

diff --git a/Documentation/kernel-parameters.txt 
b/Documentation/kernel-parameters.txt
index ecc74fa..8c881a5 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1767,6 +1767,13 @@ bytes respectively. Such letter suffixes can also be 
entirely omitted.
PCI device 00:14.0 write the parameter as:
ivrs_hpet[0]=00:14.0
 
+   ivrs_acpihid[HW,X86_64]
+   Provide an override to the ACPI-HID:UID<->DEVICE-ID
+   mapping provided in the IVRS ACPI table. For
+   example, to map UART-HID:UID AMD0020:0 to
+   PCI device 00:14.5 write the parameter as:
+   ivrs_acpihid[00:14.5]=AMD0020:0
+
js= [HW,JOY] Analog joystick
See Documentation/input/joystick.txt.
 
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index e7ebfa2..9e00341 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -2477,10 +2477,43 @@ static int __init parse_ivrs_hpet(char *str)
return 1;
 }
 
+static int __init parse_ivrs_acpihid(char *str)
+{
+   u32 bus, dev, fn;
+   char *hid, *uid, *p;
+   char acpiid[ACPIHID_UID_LEN + ACPIHID_HID_LEN] = {0};
+   int ret, i;
+
+   ret = sscanf(str, "[%x:%x.%x]=%s", &bus, &dev, &fn, acpiid);
+   if (ret != 4) {
+   pr_err("AMD-Vi: Invalid command line: ivrs_acpihid(%s)\n", str);
+   return 1;
+   }
+
+   p = acpiid;
+   hid = strsep(&p, ":");
+   uid = p;
+
+   if (!hid || !(*hid) || !uid) {
+   pr_err("AMD-Vi: Invalid command line: hid or uid\n");
+   return 1;
+   }
+
+   i = early_acpihid_map_size++;
+   memcpy(early_acpihid_map[i].hid, hid, strlen(hid));
+   memcpy(early_acpihid_map[i].uid, uid, strlen(uid));
+   early_acpihid_map[i].devid =
+   ((bus & 0xff) << 8) | ((dev & 0x1f) << 3) | (fn & 0x7);
+   early_acpihid_map[i].cmd_line   = true;
+
+   return 1;
+}
+
 __setup("amd_iommu_dump",  parse_amd_iommu_dump);
 __setup("amd_iommu=",  parse_amd_iommu_options);
 __setup("ivrs_ioapic", parse_ivrs_ioapic);
 __setup("ivrs_hpet",   parse_ivrs_hpet);
+__setup("ivrs_acpihid",parse_ivrs_acpihid);
 
 IOMMU_INIT_FINISH(amd_iommu_detect,
  gart_iommu_hole_init,
-- 
1.9.1



[PATCH V3 7/9] iommu/amd: Add iommu support for ACPI HID devices

2016-03-31 Thread Wan Zongshun
From: Wan Zongshun 

Current IOMMU driver make assumption that the downstream devices are PCI.
With the newly added ACPI-HID IVHD device entry support, this is no
longer true. This patch is to add dev type check and to distinguish the
pci and acpihid device code path.

Signed-off-by: Wan Zongshun 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd_iommu.c | 69 ---
 1 file changed, 60 insertions(+), 9 deletions(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 400867f..0df651a3 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -19,6 +19,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -216,13 +217,60 @@ static struct iommu_dev_data *find_dev_data(u16 devid)
return dev_data;
 }
 
-static inline u16 get_device_id(struct device *dev)
+static inline int match_hid_uid(struct device *dev,
+   struct acpihid_map_entry *entry)
+{
+   const char *hid, *uid;
+
+   hid = acpi_device_hid(ACPI_COMPANION(dev));
+   uid = acpi_device_uid(ACPI_COMPANION(dev));
+
+   if (!hid || !(*hid))
+   return -ENODEV;
+
+   if (!uid || !(*uid))
+   return strcmp(hid, entry->hid);
+
+   if (!(*entry->uid))
+   return strcmp(hid, entry->hid);
+
+   return (strcmp(hid, entry->hid) || strcmp(uid, entry->uid));
+}
+
+static inline u16 get_pci_device_id(struct device *dev)
 {
struct pci_dev *pdev = to_pci_dev(dev);
 
return PCI_DEVID(pdev->bus->number, pdev->devfn);
 }
 
+static inline int get_acpihid_device_id(struct device *dev,
+   struct acpihid_map_entry **entry)
+{
+   struct acpihid_map_entry *p;
+
+   list_for_each_entry(p, &acpihid_map, list) {
+   if (!match_hid_uid(dev, p)) {
+   if (entry)
+   *entry = p;
+   return p->devid;
+   }
+   }
+   return -EINVAL;
+}
+
+static inline int get_device_id(struct device *dev)
+{
+   int devid;
+
+   if (dev_is_pci(dev))
+   devid = get_pci_device_id(dev);
+   else
+   devid = get_acpihid_device_id(dev, NULL);
+
+   return devid;
+}
+
 static struct iommu_dev_data *get_dev_data(struct device *dev)
 {
return dev->archdata.iommu;
@@ -303,10 +351,6 @@ static bool check_device(struct device *dev)
if (!dev || !dev->dma_mask)
return false;
 
-   /* No PCI device */
-   if (!dev_is_pci(dev))
-   return false;
-
devid = get_device_id(dev);
if (IS_ERR_VALUE(devid))
return false;
@@ -344,7 +388,6 @@ out:
 
 static int iommu_init_device(struct device *dev)
 {
-   struct pci_dev *pdev = to_pci_dev(dev);
struct iommu_dev_data *dev_data;
int devid;
 
@@ -359,10 +402,10 @@ static int iommu_init_device(struct device *dev)
if (!dev_data)
return -ENOMEM;
 
-   if (pci_iommuv2_capable(pdev)) {
+   if (dev_is_pci(dev) && pci_iommuv2_capable(to_pci_dev(dev))) {
struct amd_iommu *iommu;
 
-   iommu  = amd_iommu_rlookup_table[dev_data->devid];
+   iommu = amd_iommu_rlookup_table[dev_data->devid];
dev_data->iommu_v2 = iommu->is_iommu_v2;
}
 
@@ -2239,13 +2282,17 @@ static bool pci_pri_tlp_required(struct pci_dev *pdev)
 static int attach_device(struct device *dev,
 struct protection_domain *domain)
 {
-   struct pci_dev *pdev = to_pci_dev(dev);
+   struct pci_dev *pdev;
struct iommu_dev_data *dev_data;
unsigned long flags;
int ret;
 
dev_data = get_dev_data(dev);
 
+   if (!dev_is_pci(dev))
+   goto skip_ats_check;
+
+   pdev = to_pci_dev(dev);
if (domain->flags & PD_IOMMUV2_MASK) {
if (!dev_data->passthrough)
return -EINVAL;
@@ -2264,6 +2311,7 @@ static int attach_device(struct device *dev,
dev_data->ats.qdep= pci_ats_queue_depth(pdev);
}
 
+skip_ats_check:
write_lock_irqsave(&amd_iommu_devtable_lock, flags);
ret = __attach_device(dev_data, domain);
write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
@@ -2320,6 +2368,9 @@ static void detach_device(struct device *dev)
__detach_device(dev_data);
write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
 
+   if (!dev_is_pci(dev))
+   return;
+
if (domain->flags & PD_IOMMUV2_MASK && dev_data->iommu_v2)
pdev_iommuv2_disable(to_pci_dev(dev));
else if (dev_data->ats.enabled)
-- 
1.9.1



[PATCH V3 6/9] iommu/amd: Make call-sites of get_device_id aware of its return value

2016-03-31 Thread Wan Zongshun
From: Wan Zongshun 

This patch is to make the call-sites of get_device_id aware of its
return value.

Signed-off-by: Wan Zongshun 
---
 drivers/iommu/amd_iommu.c | 51 +--
 1 file changed, 41 insertions(+), 10 deletions(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index d8e59a8..400867f 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -279,9 +279,11 @@ static void init_unity_mappings_for_device(struct device 
*dev,
   struct dma_ops_domain *dma_dom)
 {
struct unity_map_entry *e;
-   u16 devid;
+   int devid;
 
devid = get_device_id(dev);
+   if (IS_ERR_VALUE(devid))
+   return;
 
list_for_each_entry(e, &amd_iommu_unity_map, list) {
if (!(devid >= e->devid_start && devid <= e->devid_end))
@@ -296,7 +298,7 @@ static void init_unity_mappings_for_device(struct device 
*dev,
  */
 static bool check_device(struct device *dev)
 {
-   u16 devid;
+   int devid;
 
if (!dev || !dev->dma_mask)
return false;
@@ -306,6 +308,8 @@ static bool check_device(struct device *dev)
return false;
 
devid = get_device_id(dev);
+   if (IS_ERR_VALUE(devid))
+   return false;
 
/* Out of our scope? */
if (devid > amd_iommu_last_bdf)
@@ -342,11 +346,16 @@ static int iommu_init_device(struct device *dev)
 {
struct pci_dev *pdev = to_pci_dev(dev);
struct iommu_dev_data *dev_data;
+   int devid;
 
if (dev->archdata.iommu)
return 0;
 
-   dev_data = find_dev_data(get_device_id(dev));
+   devid = get_device_id(dev);
+   if (IS_ERR_VALUE(devid))
+   return devid;
+
+   dev_data = find_dev_data(devid);
if (!dev_data)
return -ENOMEM;
 
@@ -367,9 +376,13 @@ static int iommu_init_device(struct device *dev)
 
 static void iommu_ignore_device(struct device *dev)
 {
-   u16 devid, alias;
+   u16 alias;
+   int devid;
 
devid = get_device_id(dev);
+   if (IS_ERR_VALUE(devid))
+   return;
+
alias = amd_iommu_alias_table[devid];
 
memset(&amd_iommu_dev_table[devid], 0, sizeof(struct dev_table_entry));
@@ -381,8 +394,14 @@ static void iommu_ignore_device(struct device *dev)
 
 static void iommu_uninit_device(struct device *dev)
 {
-   struct iommu_dev_data *dev_data = search_dev_data(get_device_id(dev));
+   int devid;
+   struct iommu_dev_data *dev_data;
+
+   devid = get_device_id(dev);
+   if (IS_ERR_VALUE(devid))
+   return;
 
+   dev_data = search_dev_data(devid);
if (!dev_data)
return;
 
@@ -2314,13 +2333,15 @@ static int amd_iommu_add_device(struct device *dev)
struct iommu_dev_data *dev_data;
struct iommu_domain *domain;
struct amd_iommu *iommu;
-   u16 devid;
-   int ret;
+   int ret, devid;
 
if (!check_device(dev) || get_dev_data(dev))
return 0;
 
devid = get_device_id(dev);
+   if (IS_ERR_VALUE(devid))
+   return devid;
+
iommu = amd_iommu_rlookup_table[devid];
 
ret = iommu_init_device(dev);
@@ -2358,12 +2379,15 @@ out:
 static void amd_iommu_remove_device(struct device *dev)
 {
struct amd_iommu *iommu;
-   u16 devid;
+   int devid;
 
if (!check_device(dev))
return;
 
devid = get_device_id(dev);
+   if (IS_ERR_VALUE(devid))
+   return;
+
iommu = amd_iommu_rlookup_table[devid];
 
iommu_uninit_device(dev);
@@ -3035,12 +3059,14 @@ static void amd_iommu_detach_device(struct iommu_domain 
*dom,
 {
struct iommu_dev_data *dev_data = dev->archdata.iommu;
struct amd_iommu *iommu;
-   u16 devid;
+   int devid;
 
if (!check_device(dev))
return;
 
devid = get_device_id(dev);
+   if (IS_ERR_VALUE(devid))
+   return;
 
if (dev_data->domain != NULL)
detach_device(dev);
@@ -3158,9 +3184,11 @@ static void amd_iommu_get_dm_regions(struct device *dev,
 struct list_head *head)
 {
struct unity_map_entry *entry;
-   u16 devid;
+   int devid;
 
devid = get_device_id(dev);
+   if (IS_ERR_VALUE(devid))
+   return;
 
list_for_each_entry(entry, &amd_iommu_unity_map, list) {
struct iommu_dm_region *region;
@@ -3862,6 +3890,9 @@ static struct irq_domain *get_irq_domain(struct 
irq_alloc_info *info)
case X86_IRQ_ALLOC_TYPE_MSI:
case X86_IRQ_ALLOC_TYPE_MSIX:
devid = get_device_id(&info->msi_dev->dev);
+   if (IS_ERR_VALUE(devid))
+   return NULL;
+
iommu = 

[PATCH V3 8/9] iommu/amd: Manage iommu_group for ACPI HID devices

2016-03-31 Thread Wan Zongshun
From: Wan Zongshun 

This patch creates a new function for finding or creating an IOMMU
group for acpihid(ACPI Hardware ID) device.

The acpihid devices with the same devid will be put into same group and
there will have the same domain id and share the same page table.

Signed-off-by: Wan Zongshun 
---
 drivers/iommu/amd_iommu.c | 33 -
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 0df651a3..713e7ea 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -276,6 +276,29 @@ static struct iommu_dev_data *get_dev_data(struct device 
*dev)
return dev->archdata.iommu;
 }
 
+/*
+* Find or create an IOMMU group for a acpihid device.
+*/
+static struct iommu_group *acpihid_device_group(struct device *dev)
+{
+   struct acpihid_map_entry *p, *entry = NULL;
+   u16 devid;
+
+   devid = get_acpihid_device_id(dev, &entry);
+   if (devid < 0)
+   return ERR_PTR(devid);
+
+   list_for_each_entry(p, &acpihid_map, list) {
+   if ((devid == p->devid) && p->group)
+   entry->group = p->group;
+   }
+
+   if (!entry->group)
+   entry->group = generic_device_group(dev);
+
+   return entry->group;
+}
+
 static bool pci_iommuv2_capable(struct pci_dev *pdev)
 {
static const int caps[] = {
@@ -2445,6 +2468,14 @@ static void amd_iommu_remove_device(struct device *dev)
iommu_completion_wait(iommu);
 }
 
+static struct iommu_group *amd_iommu_device_group(struct device *dev)
+{
+   if (dev_is_pci(dev))
+   return pci_device_group(dev);
+
+   return acpihid_device_group(dev);
+}
+
 /*
  *
  * The next functions belong to the dma_ops mapping/unmapping code.
@@ -3286,7 +3317,7 @@ static const struct iommu_ops amd_iommu_ops = {
.iova_to_phys = amd_iommu_iova_to_phys,
.add_device = amd_iommu_add_device,
.remove_device = amd_iommu_remove_device,
-   .device_group = pci_device_group,
+   .device_group = amd_iommu_device_group,
.get_dm_regions = amd_iommu_get_dm_regions,
.put_dm_regions = amd_iommu_put_dm_regions,
.pgsize_bitmap  = AMD_IOMMU_PGSIZES,
-- 
1.9.1



[PATCH V3 3/9] iommu/amd: Use the most comprehensive IVHD type that the driver can support

2016-03-31 Thread Wan Zongshun
From: Suravee Suthikulpanit 

The IVRS in more recent AMD system usually contains multiple
IVHD block types (e.g. 0x10, 0x11, and 0x40) for each IOMMU.
The newer IVHD types provide more information (e.g. new features
specified in the IOMMU spec), while maintain compatibility with
the older IVHD type.

Having multiple IVHD type allows older IOMMU drivers to still function
(e.g. using the older IVHD type 0x10) while the newer IOMMU driver can use
the newer IVHD types (e.g. 0x11 and 0x40). Therefore, the IOMMU driver
should only make use of the newest IVHD type that it can support.

This patch adds new logic to determine the highest level of IVHD type
it can support, and use it throughout the to initialize the driver.
This requires adding another pass to the IVRS parsing to determine
appropriate IVHD type (see function get_highest_supported_ivhd_type())
before parsing the contents.

[Vincent: fix the build error of IVHD_DEV_ACPI_HID flag not found]

Signed-off-by: Wan Zongshun 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd_iommu_init.c | 107 ++---
 1 file changed, 78 insertions(+), 29 deletions(-)

diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 22e078b..8f49612 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -44,7 +44,7 @@
  */
 #define IVRS_HEADER_LENGTH 48
 
-#define ACPI_IVHD_TYPE  0x10
+#define ACPI_IVHD_TYPE_MAX_SUPPORTED   0x40
 #define ACPI_IVMD_TYPE_ALL  0x20
 #define ACPI_IVMD_TYPE  0x21
 #define ACPI_IVMD_TYPE_RANGE0x22
@@ -58,6 +58,7 @@
 #define IVHD_DEV_EXT_SELECT 0x46
 #define IVHD_DEV_EXT_SELECT_RANGE   0x47
 #define IVHD_DEV_SPECIAL   0x48
+#define IVHD_DEV_ACPI_HID  0xf0
 
 #define IVHD_SPECIAL_IOAPIC1
 #define IVHD_SPECIAL_HPET  2
@@ -137,6 +138,7 @@ bool amd_iommu_irq_remap __read_mostly;
 
 static bool amd_iommu_detected;
 static bool __initdata amd_iommu_disabled;
+static int amd_iommu_target_ivhd_type;
 
 u16 amd_iommu_last_bdf;/* largest PCI device id we have
   to handle */
@@ -428,7 +430,15 @@ static inline u32 get_ivhd_header_size(struct ivhd_header 
*h)
  */
 static inline int ivhd_entry_length(u8 *ivhd)
 {
-   return 0x04 << (*ivhd >> 6);
+   u32 type = ((struct ivhd_entry *)ivhd)->type;
+
+   if (type < 0x80) {
+   return 0x04 << (*ivhd >> 6);
+   } else if (type == IVHD_DEV_ACPI_HID) {
+   /* For ACPI_HID, offset 21 is uid len */
+   return *((u8 *)ivhd + 21) + 22;
+   }
+   return 0;
 }
 
 /*
@@ -475,6 +485,22 @@ static int __init find_last_devid_from_ivhd(struct 
ivhd_header *h)
return 0;
 }
 
+static int __init check_ivrs_checksum(struct acpi_table_header *table)
+{
+   int i;
+   u8 checksum = 0, *p = (u8 *)table;
+
+   for (i = 0; i < table->length; ++i)
+   checksum += p[i];
+   if (checksum != 0) {
+   /* ACPI table corrupt */
+   pr_err(FW_BUG "AMD-Vi: IVRS invalid checksum\n");
+   return -ENODEV;
+   }
+
+   return 0;
+}
+
 /*
  * Iterate over all IVHD entries in the ACPI table and find the highest device
  * id which we need to handle. This is the first of three functions which parse
@@ -482,31 +508,19 @@ static int __init find_last_devid_from_ivhd(struct 
ivhd_header *h)
  */
 static int __init find_last_devid_acpi(struct acpi_table_header *table)
 {
-   int i;
-   u8 checksum = 0, *p = (u8 *)table, *end = (u8 *)table;
+   u8 *p = (u8 *)table, *end = (u8 *)table;
struct ivhd_header *h;
 
-   /*
-* Validate checksum here so we don't need to do it when
-* we actually parse the table
-*/
-   for (i = 0; i < table->length; ++i)
-   checksum += p[i];
-   if (checksum != 0)
-   /* ACPI table corrupt */
-   return -ENODEV;
-
p += IVRS_HEADER_LENGTH;
 
end += table->length;
while (p < end) {
h = (struct ivhd_header *)p;
-   switch (h->type) {
-   case ACPI_IVHD_TYPE:
-   find_last_devid_from_ivhd(h);
-   break;
-   default:
-   break;
+   if (h->type == amd_iommu_target_ivhd_type) {
+   int ret = find_last_devid_from_ivhd(h);
+
+   if (ret)
+   return ret;
}
p += h->length;
}
@@ -1164,6 +1178,32 @@ static int __init init_iommu_one(struct amd_iommu 
*iommu, struct ivhd_header *h)
return 0;
 }
 
+/**
+ * get_highest_supported_ivhd_type - Look up the appropriate IVHD type
+ * @ivrs  Pointer to the IVRS header
+ *

[PATCH V3 1/9] iommu/amd: Adding Extended Feature Register check for PC support

2016-03-31 Thread Wan Zongshun
From: Suravee Suthikulpanit 

The IVHD header type 11h and 40h introduce the PCSup bit in
the EFR Register Image bit fileds. This should be used to
determine the IOMMU performance support instead of relying
on the PNCounters and PNBanks.

Note also that the PNCouters and PNBanks bits in the IOMMU
attributes field of IVHD headers type 11h are incorrectly
programmed on some systems.

So, we should not rely on it to determine the performance
counter/banks size. Instead, these values should be read
from the MMIO Offset 0030h IOMMU Extended Feature Register.

Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd_iommu_init.c | 32 
 1 file changed, 24 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index bf4959f..dff1e01 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -99,7 +99,11 @@ struct ivhd_header {
u64 mmio_phys;
u16 pci_seg;
u16 info;
-   u32 efr;
+   u32 efr_attr;
+
+   /* Following only valid on IVHD type 11h and 40h */
+   u64 efr_reg; /* Exact copy of MMIO_EXT_FEATURES */
+   u64 res;
 } __attribute__((packed));
 
 /*
@@ -1078,13 +1082,25 @@ static int __init init_iommu_one(struct amd_iommu 
*iommu, struct ivhd_header *h)
iommu->pci_seg = h->pci_seg;
iommu->mmio_phys = h->mmio_phys;
 
-   /* Check if IVHD EFR contains proper max banks/counters */
-   if ((h->efr != 0) &&
-   ((h->efr & (0xF << 13)) != 0) &&
-   ((h->efr & (0x3F << 17)) != 0)) {
-   iommu->mmio_phys_end = MMIO_REG_END_OFFSET;
-   } else {
-   iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET;
+   switch (h->type) {
+   case 0x10:
+   /* Check if IVHD EFR contains proper max banks/counters */
+   if ((h->efr_attr != 0) &&
+   ((h->efr_attr & (0xF << 13)) != 0) &&
+   ((h->efr_attr & (0x3F << 17)) != 0))
+   iommu->mmio_phys_end = MMIO_REG_END_OFFSET;
+   else
+   iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET;
+   break;
+   case 0x11:
+   case 0x40:
+   if (h->efr_reg & (1 << 9))
+   iommu->mmio_phys_end = MMIO_REG_END_OFFSET;
+   else
+   iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET;
+   break;
+   default:
+   return -EINVAL;
}
 
iommu->mmio_base = iommu_map_mmio_space(iommu->mmio_phys,
-- 
1.9.1



Re: Warning from AMD IOMMU performance counters

2016-02-21 Thread Wan Zongshun



 Original Message 

Hi,

Since about 4.4, we've been seeing reports of this warning on every boot
from some users:

WARNING: CPU: 2 PID: 1 at drivers/iommu/amd_iommu_init.c:2301
amd_iommu_pc_get_set_reg_val+0xa8/0xe0()
Modules linked in:
CPU: 2 PID: 1 Comm: swapper/0 Not tainted 4.4.2-300.fc23.x86_64 #1
Hardware name: Hewlett-Packard HP EliteBook 755 G2/221C, BIOS M84 Ver.
01.10 10/20/2015
   26124b43 88042d687d20 813b0c9f
   88042d687d58 810a2f12 88042f014800
  0040  81d6c73d 
Call Trace:
  [] dump_stack+0x44/0x55
  [] warn_slowpath_common+0x82/0xc0
  [] ? memblock_find_dma_reserve+0x16a/0x16a
  [] warn_slowpath_null+0x1a/0x20
  [] amd_iommu_pc_get_set_reg_val+0xa8/0xe0
  [] iommu_go_to_state+0x4d6/0x1384
  [] ? kvasprintf+0x7a/0xa0
  [] ? memblock_find_dma_reserve+0x16a/0x16a
  [] amd_iommu_init+0x13/0x201
  [] pci_iommu_init+0x12/0x3c
  [] do_one_initcall+0xb3/0x200
  [] ? parse_args+0x295/0x4b0
  [] kernel_init_freeable+0x189/0x223
  [] ? rest_init+0x80/0x80
  [] kernel_init+0xe/0xe0
  [] ret_from_fork+0x3f/0x70
  [] ? rest_init+0x80/0x80

Full bugzilla https://bugzilla.redhat.com/show_bug.cgi?id=1310258

Any idea what might be causing this spew?


I also see this warning.

Suravee's the one of this patch series might be fix this issue, you can 
try it.


[PATCH V4 0/6] perf/amd/iommu: Enable multi-IOMMU support




Thanks,
Laura
___
iommu mailing list
io...@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu



[PATCH V2 2/8] iommu/amd: Use the most comprehensive IVHD type that the driver can support

2016-01-26 Thread Wan Zongshun
From: Suravee Suthikulpanit 

The IVRS in more recent AMD system usually contains multiple
IVHD block types (e.g. 0x10, 0x11, and 0x40) for each IOMMU.
The newer IVHD types provide more information (e.g. new features
specified in the IOMMU spec), while maintain compatibility with
the older IVHD type.

Having multiple IVHD type allows older IOMMU drivers to still function
(e.g. using the older IVHD type 0x10) while the newer IOMMU driver can use
the newer IVHD types (e.g. 0x11 and 0x40). Therefore, the IOMMU driver
should only make use of the newest IVHD type that it can support.

This patch adds new logic to determine the highest level of IVHD type
it can support, and use it throughout the to initialize the driver.
This requires adding another pass to the IVRS parsing to determine
appropriate IVHD type (see function get_highest_supported_ivhd_type())
before parsing the contents.

[Vincent: fix the build error of IVHD_DEV_ACPI_HID flag not found]

Signed-off-by: Wan Zongshun 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd_iommu_init.c | 107 ++---
 1 file changed, 78 insertions(+), 29 deletions(-)

diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 2ff7000..146f3ee 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -44,7 +44,7 @@
  */
 #define IVRS_HEADER_LENGTH 48
 
-#define ACPI_IVHD_TYPE  0x10
+#define ACPI_IVHD_TYPE_MAX_SUPPORTED   0x40
 #define ACPI_IVMD_TYPE_ALL  0x20
 #define ACPI_IVMD_TYPE  0x21
 #define ACPI_IVMD_TYPE_RANGE0x22
@@ -58,6 +58,7 @@
 #define IVHD_DEV_EXT_SELECT 0x46
 #define IVHD_DEV_EXT_SELECT_RANGE   0x47
 #define IVHD_DEV_SPECIAL   0x48
+#define IVHD_DEV_ACPI_HID  0xf0
 
 #define IVHD_SPECIAL_IOAPIC1
 #define IVHD_SPECIAL_HPET  2
@@ -137,6 +138,7 @@ bool amd_iommu_irq_remap __read_mostly;
 
 static bool amd_iommu_detected;
 static bool __initdata amd_iommu_disabled;
+static int amd_iommu_target_ivhd_type;
 
 u16 amd_iommu_last_bdf;/* largest PCI device id we have
   to handle */
@@ -424,7 +426,15 @@ static inline u32 get_ivhd_header_size(struct ivhd_header 
*h)
  */
 static inline int ivhd_entry_length(u8 *ivhd)
 {
-   return 0x04 << (*ivhd >> 6);
+   u32 type = ((struct ivhd_entry *)ivhd)->type;
+
+   if (type < 0x80) {
+   return 0x04 << (*ivhd >> 6);
+   } else if (type == IVHD_DEV_ACPI_HID) {
+   /* For ACPI_HID, offset 21 is uid len */
+   return *((u8 *)ivhd + 21) + 22;
+   }
+   return 0;
 }
 
 /*
@@ -470,6 +480,22 @@ static int __init find_last_devid_from_ivhd(struct 
ivhd_header *h)
return 0;
 }
 
+static int __init check_ivrs_checksum(struct acpi_table_header *table)
+{
+   int i;
+   u8 checksum = 0, *p = (u8 *)table;
+
+   for (i = 0; i < table->length; ++i)
+   checksum += p[i];
+   if (checksum != 0) {
+   /* ACPI table corrupt */
+   pr_err(FW_BUG "AMD-Vi: IVRS invalid checksum\n");
+   return -ENODEV;
+   }
+
+   return 0;
+}
+
 /*
  * Iterate over all IVHD entries in the ACPI table and find the highest device
  * id which we need to handle. This is the first of three functions which parse
@@ -477,31 +503,19 @@ static int __init find_last_devid_from_ivhd(struct 
ivhd_header *h)
  */
 static int __init find_last_devid_acpi(struct acpi_table_header *table)
 {
-   int i;
-   u8 checksum = 0, *p = (u8 *)table, *end = (u8 *)table;
+   u8 *p = (u8 *)table, *end = (u8 *)table;
struct ivhd_header *h;
 
-   /*
-* Validate checksum here so we don't need to do it when
-* we actually parse the table
-*/
-   for (i = 0; i < table->length; ++i)
-   checksum += p[i];
-   if (checksum != 0)
-   /* ACPI table corrupt */
-   return -ENODEV;
-
p += IVRS_HEADER_LENGTH;
 
end += table->length;
while (p < end) {
h = (struct ivhd_header *)p;
-   switch (h->type) {
-   case ACPI_IVHD_TYPE:
-   find_last_devid_from_ivhd(h);
-   break;
-   default:
-   break;
+   if (h->type == amd_iommu_target_ivhd_type) {
+   int ret = find_last_devid_from_ivhd(h);
+
+   if (ret)
+   return ret;
}
p += h->length;
}
@@ -1118,6 +1132,32 @@ static int __init init_iommu_one(struct amd_iommu 
*iommu, struct ivhd_header *h)
return 0;
 }
 
+/**
+ * get_highest_supported_ivhd_type - Look up the appropriate IVHD type
+ * @ivrs  Pointer to the IVRS header
+ *

[PATCH V2 8/8] iommu/amd: Set AMD iommu callbacks for amba bus

2016-01-26 Thread Wan Zongshun
From: Wan Zongshun 

AMD Uart DMA belongs to ACPI HID type device, and its driver
is basing on AMBA Bus, need also IOMMU support.

This patch is just to set the AMD iommu callbacks for amba bus.

Signed-off-by: Wan Zongshun 
---
 drivers/iommu/amd_iommu.c | 13 -
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 59398f9..9194161 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -20,6 +20,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -2965,7 +2966,17 @@ static struct dma_map_ops amd_iommu_dma_ops = {
 
 int __init amd_iommu_init_api(void)
 {
-   return bus_set_iommu(&pci_bus_type, &amd_iommu_ops);
+   int err = 0;
+
+   err = bus_set_iommu(&pci_bus_type, &amd_iommu_ops);
+   if (err)
+   return err;
+#ifdef CONFIG_ARM_AMBA
+   err = bus_set_iommu(&amba_bustype, &amd_iommu_ops);
+   if (err)
+   return err;
+#endif
+   return 0;
 }
 
 int __init amd_iommu_init_dma_ops(void)
-- 
1.9.1



[PATCH V2 3/8] iommu/amd: Add new map for storing IVHD dev entry type HID

2016-01-26 Thread Wan Zongshun
From: Wan Zongshun 

This patch introduces acpihid_map, which is used to store
the new IVHD device entry extracted from BIOS IVRS table.

It also provides a utility function add_acpi_hid_device(),
to add this types of devices to the map.

Signed-off-by: Wan Zongshun 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd_iommu.c   |   1 +
 drivers/iommu/amd_iommu_init.c  | 122 
 drivers/iommu/amd_iommu_types.h |  14 +
 3 files changed, 137 insertions(+)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 539b0de..8063ab2 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -72,6 +72,7 @@ static DEFINE_SPINLOCK(dev_data_list_lock);
 
 LIST_HEAD(ioapic_map);
 LIST_HEAD(hpet_map);
+LIST_HEAD(acpihid_map);
 
 /*
  * Domain for untranslated devices - only allocated
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 146f3ee..0a8e033 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -60,6 +60,10 @@
 #define IVHD_DEV_SPECIAL   0x48
 #define IVHD_DEV_ACPI_HID  0xf0
 
+#define UID_NOT_PRESENT 0
+#define UID_IS_INTEGER  1
+#define UID_IS_CHARACTER2
+
 #define IVHD_SPECIAL_IOAPIC1
 #define IVHD_SPECIAL_HPET  2
 
@@ -116,6 +120,11 @@ struct ivhd_entry {
u16 devid;
u8 flags;
u32 ext;
+   u32 hidh;
+   u64 cid;
+   u8 uidf;
+   u8 uidl;
+   u8 uid;
 } __attribute__((packed));
 
 /*
@@ -224,8 +233,12 @@ enum iommu_init_state {
 #define EARLY_MAP_SIZE 4
 static struct devid_map __initdata early_ioapic_map[EARLY_MAP_SIZE];
 static struct devid_map __initdata early_hpet_map[EARLY_MAP_SIZE];
+static struct acpihid_map_entry __initdata early_acpihid_map[EARLY_MAP_SIZE];
+
 static int __initdata early_ioapic_map_size;
 static int __initdata early_hpet_map_size;
+static int __initdata early_acpihid_map_size;
+
 static bool __initdata cmdline_maps;
 
 static enum iommu_init_state init_state = IOMMU_START_STATE;
@@ -760,6 +773,42 @@ static int __init add_special_device(u8 type, u8 id, u16 
*devid, bool cmd_line)
return 0;
 }
 
+static int __init add_acpi_hid_device(u8 *hid, u8 *uid, u16 *devid,
+ bool cmd_line)
+{
+   struct acpihid_map_entry *entry;
+   struct list_head *list = &acpihid_map;
+
+   list_for_each_entry(entry, list, list) {
+   if (strcmp(entry->hid, hid) ||
+   (*uid && *entry->uid && strcmp(entry->uid, uid)) ||
+   !entry->cmd_line)
+   continue;
+
+   pr_info("AMD-Vi: Command-line override for hid:%s uid:%s\n",
+   hid, uid);
+   *devid = entry->devid;
+   return 0;
+   }
+
+   entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+   if (!entry)
+   return -ENOMEM;
+
+   memcpy(entry->uid, uid, strlen(uid));
+   memcpy(entry->hid, hid, strlen(hid));
+   entry->devid = *devid;
+   entry->cmd_line = cmd_line;
+   entry->root_devid = (entry->devid & (~0x7));
+
+   pr_info("AMD-Vi:%s, add hid:%s, uid:%s, rdevid:%d\n",
+   entry->cmd_line ? "cmd" : "ivrs",
+   entry->hid, entry->uid, entry->root_devid);
+
+   list_add_tail(&entry->list, list);
+   return 0;
+}
+
 static int __init add_early_maps(void)
 {
int i, ret;
@@ -782,6 +831,15 @@ static int __init add_early_maps(void)
return ret;
}
 
+   for (i = 0; i < early_acpihid_map_size; ++i) {
+   ret = add_acpi_hid_device(early_acpihid_map[i].hid,
+ early_acpihid_map[i].uid,
+ &early_acpihid_map[i].devid,
+ early_acpihid_map[i].cmd_line);
+   if (ret)
+   return ret;
+   }
+
return 0;
 }
 
@@ -1001,6 +1059,70 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
 
break;
}
+   case IVHD_DEV_ACPI_HID: {
+   u16 devid;
+   u8 hid[ACPIHID_HID_LEN] = {0};
+   u8 uid[ACPIHID_UID_LEN] = {0};
+   int ret;
+
+   if (h->type != 0x40) {
+   pr_err(FW_BUG "Invalid IVHD device type %#x\n",
+  e->type);
+   break;
+   }
+
+   memcpy(hid, (u8 *)(&e->ext), ACPIHID_HID_LEN - 1);
+   hid[ACPIHID_HID_LEN - 1] = &#x

[PATCH V2 7/8] iommu/amd: Manage iommu_group for ACPI HID devices

2016-01-26 Thread Wan Zongshun
From: Wan Zongshun 

This patch creates a new function for finding or creating an IOMMU
group for acpihid(ACPI Hardware ID) device.

The acpihid devices with the same devid will be put into same group and
there will have the same domain id and share the same page table.

Signed-off-by: Wan Zongshun 
---
 drivers/iommu/amd_iommu.c | 33 -
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 4857d66..59398f9 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -275,6 +275,29 @@ static struct iommu_dev_data *get_dev_data(struct device 
*dev)
return dev->archdata.iommu;
 }
 
+/*
+* Find or create an IOMMU group for a acpihid device.
+*/
+static struct iommu_group *acpihid_device_group(struct device *dev)
+{
+   struct acpihid_map_entry *p, *entry = NULL;
+   u16 devid;
+
+   devid = get_acpihid_device_id(dev, &entry);
+   if (devid < 0)
+   return ERR_PTR(devid);
+
+   list_for_each_entry(p, &acpihid_map, list) {
+   if ((devid == p->devid) && p->group)
+   entry->group = p->group;
+   }
+
+   if (!entry->group)
+   entry->group = generic_device_group(dev);
+
+   return entry->group;
+}
+
 static bool pci_iommuv2_capable(struct pci_dev *pdev)
 {
static const int caps[] = {
@@ -2441,6 +2464,14 @@ static void amd_iommu_remove_device(struct device *dev)
iommu_completion_wait(iommu);
 }
 
+static struct iommu_group *amd_iommu_device_group(struct device *dev)
+{
+   if (dev_is_pci(dev))
+   return pci_device_group(dev);
+
+   return acpihid_device_group(dev);
+}
+
 /*
  *
  * The next functions belong to the dma_ops mapping/unmapping code.
@@ -3282,7 +3313,7 @@ static const struct iommu_ops amd_iommu_ops = {
.iova_to_phys = amd_iommu_iova_to_phys,
.add_device = amd_iommu_add_device,
.remove_device = amd_iommu_remove_device,
-   .device_group = pci_device_group,
+   .device_group = amd_iommu_device_group,
.get_dm_regions = amd_iommu_get_dm_regions,
.put_dm_regions = amd_iommu_put_dm_regions,
.pgsize_bitmap  = AMD_IOMMU_PGSIZES,
-- 
1.9.1



[PATCH V2 4/8] iommu/amd: Introduces ivrs_acpihid kernel parameter

2016-01-26 Thread Wan Zongshun
From: Suravee Suthikulpanit 

This patch introduces a new kernel parameter, ivrs_acpihid.
This is used to override existing ACPI-HID IVHD device entry,
or add an entry in case it is missing in the IVHD.

Signed-off-by: Wan Zongshun 
Signed-off-by: Suravee Suthikulpanit 
---
 Documentation/kernel-parameters.txt |  7 +++
 drivers/iommu/amd_iommu_init.c  | 33 +
 2 files changed, 40 insertions(+)

diff --git a/Documentation/kernel-parameters.txt 
b/Documentation/kernel-parameters.txt
index 742f69d..5c364c6 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1680,6 +1680,13 @@ bytes respectively. Such letter suffixes can also be 
entirely omitted.
PCI device 00:14.0 write the parameter as:
ivrs_hpet[0]=00:14.0
 
+   ivrs_acpihid[HW,X86_64]
+   Provide an override to the ACPI-HID:UID<->DEVICE-ID
+   mapping provided in the IVRS ACPI table. For
+   example, to map UART-HID:UID AMD0020:0 to
+   PCI device 00:14.5 write the parameter as:
+   ivrs_acpihid[00:14.5]=AMD0020:0
+
js= [HW,JOY] Analog joystick
See Documentation/input/joystick.txt.
 
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 0a8e033..ad05614 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -2430,10 +2430,43 @@ static int __init parse_ivrs_hpet(char *str)
return 1;
 }
 
+static int __init parse_ivrs_acpihid(char *str)
+{
+   u32 bus, dev, fn;
+   char *hid, *uid, *p;
+   char acpiid[ACPIHID_UID_LEN + ACPIHID_HID_LEN] = {0};
+   int ret, i;
+
+   ret = sscanf(str, "[%x:%x.%x]=%s", &bus, &dev, &fn, acpiid);
+   if (ret != 4) {
+   pr_err("AMD-Vi: Invalid command line: ivrs_acpihid(%s)\n", str);
+   return 1;
+   }
+
+   p = acpiid;
+   hid = strsep(&p, ":");
+   uid = p;
+
+   if (!hid || !(*hid) || !uid) {
+   pr_err("AMD-Vi: Invalid command line: hid or uid\n");
+   return 1;
+   }
+
+   i = early_acpihid_map_size++;
+   memcpy(early_acpihid_map[i].hid, hid, strlen(hid));
+   memcpy(early_acpihid_map[i].uid, uid, strlen(uid));
+   early_acpihid_map[i].devid =
+   ((bus & 0xff) << 8) | ((dev & 0x1f) << 3) | (fn & 0x7);
+   early_acpihid_map[i].cmd_line   = true;
+
+   return 1;
+}
+
 __setup("amd_iommu_dump",  parse_amd_iommu_dump);
 __setup("amd_iommu=",  parse_amd_iommu_options);
 __setup("ivrs_ioapic", parse_ivrs_ioapic);
 __setup("ivrs_hpet",   parse_ivrs_hpet);
+__setup("ivrs_acpihid",parse_ivrs_acpihid);
 
 IOMMU_INIT_FINISH(amd_iommu_detect,
  gart_iommu_hole_init,
-- 
1.9.1



[PATCH V2 6/8] iommu/amd: Add iommu support for ACPI HID devices

2016-01-26 Thread Wan Zongshun
From: Wan Zongshun 

Current IOMMU driver make assumption that the downstream devices are PCI.
With the newly added ACPI-HID IVHD device entry support, this is no
longer true. This patch is to add dev type check and to distinguish the
pci and acpihid device code path.

Signed-off-by: Wan Zongshun 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd_iommu.c | 69 ---
 1 file changed, 60 insertions(+), 9 deletions(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 10d6623..4857d66 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -19,6 +19,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -215,13 +216,60 @@ static struct iommu_dev_data *find_dev_data(u16 devid)
return dev_data;
 }
 
-static inline u16 get_device_id(struct device *dev)
+static inline int match_hid_uid(struct device *dev,
+   struct acpihid_map_entry *entry)
+{
+   const char *hid, *uid;
+
+   hid = acpi_device_hid(ACPI_COMPANION(dev));
+   uid = acpi_device_uid(ACPI_COMPANION(dev));
+
+   if (!hid || !(*hid))
+   return -ENODEV;
+
+   if (!uid || !(*uid))
+   return strcmp(hid, entry->hid);
+
+   if (!(*entry->uid))
+   return strcmp(hid, entry->hid);
+
+   return (strcmp(hid, entry->hid) || strcmp(uid, entry->uid));
+}
+
+static inline u16 get_pci_device_id(struct device *dev)
 {
struct pci_dev *pdev = to_pci_dev(dev);
 
return PCI_DEVID(pdev->bus->number, pdev->devfn);
 }
 
+static inline int get_acpihid_device_id(struct device *dev,
+   struct acpihid_map_entry **entry)
+{
+   struct acpihid_map_entry *p;
+
+   list_for_each_entry(p, &acpihid_map, list) {
+   if (!match_hid_uid(dev, p)) {
+   if (entry)
+   *entry = p;
+   return p->devid;
+   }
+   }
+   return -EINVAL;
+}
+
+static inline int get_device_id(struct device *dev)
+{
+   int devid;
+
+   if (dev_is_pci(dev))
+   devid = get_pci_device_id(dev);
+   else
+   devid = get_acpihid_device_id(dev, NULL);
+
+   return devid;
+}
+
 static struct iommu_dev_data *get_dev_data(struct device *dev)
 {
return dev->archdata.iommu;
@@ -302,10 +350,6 @@ static bool check_device(struct device *dev)
if (!dev || !dev->dma_mask)
return false;
 
-   /* No PCI device */
-   if (!dev_is_pci(dev))
-   return false;
-
devid = get_device_id(dev);
if (IS_ERR_VALUE(devid))
return false;
@@ -343,7 +387,6 @@ out:
 
 static int iommu_init_device(struct device *dev)
 {
-   struct pci_dev *pdev = to_pci_dev(dev);
struct iommu_dev_data *dev_data;
int devid;
 
@@ -358,10 +401,10 @@ static int iommu_init_device(struct device *dev)
if (!dev_data)
return -ENOMEM;
 
-   if (pci_iommuv2_capable(pdev)) {
+   if (dev_is_pci(dev) && pci_iommuv2_capable(to_pci_dev(dev))) {
struct amd_iommu *iommu;
 
-   iommu  = amd_iommu_rlookup_table[dev_data->devid];
+   iommu = amd_iommu_rlookup_table[dev_data->devid];
dev_data->iommu_v2 = iommu->is_iommu_v2;
}
 
@@ -2235,13 +2278,17 @@ static bool pci_pri_tlp_required(struct pci_dev *pdev)
 static int attach_device(struct device *dev,
 struct protection_domain *domain)
 {
-   struct pci_dev *pdev = to_pci_dev(dev);
+   struct pci_dev *pdev;
struct iommu_dev_data *dev_data;
unsigned long flags;
int ret;
 
dev_data = get_dev_data(dev);
 
+   if (!dev_is_pci(dev))
+   goto skip_ats_check;
+
+   pdev = to_pci_dev(dev);
if (domain->flags & PD_IOMMUV2_MASK) {
if (!dev_data->passthrough)
return -EINVAL;
@@ -2260,6 +2307,7 @@ static int attach_device(struct device *dev,
dev_data->ats.qdep= pci_ats_queue_depth(pdev);
}
 
+skip_ats_check:
write_lock_irqsave(&amd_iommu_devtable_lock, flags);
ret = __attach_device(dev_data, domain);
write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
@@ -2316,6 +2364,9 @@ static void detach_device(struct device *dev)
__detach_device(dev_data);
write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
 
+   if (!dev_is_pci(dev))
+   return;
+
if (domain->flags & PD_IOMMUV2_MASK && dev_data->iommu_v2)
pdev_iommuv2_disable(to_pci_dev(dev));
else if (dev_data->ats.enabled)
-- 
1.9.1



[PATCH V2 5/8] iommu/amd: Make call-sites of get_device_id aware of its return value

2016-01-26 Thread Wan Zongshun
From: Wan Zongshun 

This patch is to make the call-sites of get_device_id aware of its
return value.

Signed-off-by: Wan Zongshun 
---
 drivers/iommu/amd_iommu.c | 51 +--
 1 file changed, 41 insertions(+), 10 deletions(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 8063ab2..10d6623 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -278,9 +278,11 @@ static void init_unity_mappings_for_device(struct device 
*dev,
   struct dma_ops_domain *dma_dom)
 {
struct unity_map_entry *e;
-   u16 devid;
+   int devid;
 
devid = get_device_id(dev);
+   if (IS_ERR_VALUE(devid))
+   return;
 
list_for_each_entry(e, &amd_iommu_unity_map, list) {
if (!(devid >= e->devid_start && devid <= e->devid_end))
@@ -295,7 +297,7 @@ static void init_unity_mappings_for_device(struct device 
*dev,
  */
 static bool check_device(struct device *dev)
 {
-   u16 devid;
+   int devid;
 
if (!dev || !dev->dma_mask)
return false;
@@ -305,6 +307,8 @@ static bool check_device(struct device *dev)
return false;
 
devid = get_device_id(dev);
+   if (IS_ERR_VALUE(devid))
+   return false;
 
/* Out of our scope? */
if (devid > amd_iommu_last_bdf)
@@ -341,11 +345,16 @@ static int iommu_init_device(struct device *dev)
 {
struct pci_dev *pdev = to_pci_dev(dev);
struct iommu_dev_data *dev_data;
+   int devid;
 
if (dev->archdata.iommu)
return 0;
 
-   dev_data = find_dev_data(get_device_id(dev));
+   devid = get_device_id(dev);
+   if (IS_ERR_VALUE(devid))
+   return devid;
+
+   dev_data = find_dev_data(devid);
if (!dev_data)
return -ENOMEM;
 
@@ -366,9 +375,13 @@ static int iommu_init_device(struct device *dev)
 
 static void iommu_ignore_device(struct device *dev)
 {
-   u16 devid, alias;
+   u16 alias;
+   int devid;
 
devid = get_device_id(dev);
+   if (IS_ERR_VALUE(devid))
+   return;
+
alias = amd_iommu_alias_table[devid];
 
memset(&amd_iommu_dev_table[devid], 0, sizeof(struct dev_table_entry));
@@ -380,8 +393,14 @@ static void iommu_ignore_device(struct device *dev)
 
 static void iommu_uninit_device(struct device *dev)
 {
-   struct iommu_dev_data *dev_data = search_dev_data(get_device_id(dev));
+   int devid;
+   struct iommu_dev_data *dev_data;
+
+   devid = get_device_id(dev);
+   if (IS_ERR_VALUE(devid))
+   return;
 
+   dev_data = search_dev_data(devid);
if (!dev_data)
return;
 
@@ -2310,13 +2329,15 @@ static int amd_iommu_add_device(struct device *dev)
struct iommu_dev_data *dev_data;
struct iommu_domain *domain;
struct amd_iommu *iommu;
-   u16 devid;
-   int ret;
+   int ret, devid;
 
if (!check_device(dev) || get_dev_data(dev))
return 0;
 
devid = get_device_id(dev);
+   if (IS_ERR_VALUE(devid))
+   return devid;
+
iommu = amd_iommu_rlookup_table[devid];
 
ret = iommu_init_device(dev);
@@ -2354,12 +2375,15 @@ out:
 static void amd_iommu_remove_device(struct device *dev)
 {
struct amd_iommu *iommu;
-   u16 devid;
+   int devid;
 
if (!check_device(dev))
return;
 
devid = get_device_id(dev);
+   if (IS_ERR_VALUE(devid))
+   return;
+
iommu = amd_iommu_rlookup_table[devid];
 
iommu_uninit_device(dev);
@@ -3031,12 +3055,14 @@ static void amd_iommu_detach_device(struct iommu_domain 
*dom,
 {
struct iommu_dev_data *dev_data = dev->archdata.iommu;
struct amd_iommu *iommu;
-   u16 devid;
+   int devid;
 
if (!check_device(dev))
return;
 
devid = get_device_id(dev);
+   if (IS_ERR_VALUE(devid))
+   return;
 
if (dev_data->domain != NULL)
detach_device(dev);
@@ -3154,9 +3180,11 @@ static void amd_iommu_get_dm_regions(struct device *dev,
 struct list_head *head)
 {
struct unity_map_entry *entry;
-   u16 devid;
+   int devid;
 
devid = get_device_id(dev);
+   if (IS_ERR_VALUE(devid))
+   return;
 
list_for_each_entry(entry, &amd_iommu_unity_map, list) {
struct iommu_dm_region *region;
@@ -3858,6 +3886,9 @@ static struct irq_domain *get_irq_domain(struct 
irq_alloc_info *info)
case X86_IRQ_ALLOC_TYPE_MSI:
case X86_IRQ_ALLOC_TYPE_MSIX:
devid = get_device_id(&info->msi_dev->dev);
+   if (IS_ERR_VALUE(devid))
+   return NULL;
+
iommu = 

[PATCH V2 1/8] iommu/amd: Modify ivhd_header structure to support type 11h and 40h

2016-01-26 Thread Wan Zongshun
From: Suravee Suthikulpanit 

This patch modifies the existing struct ivhd_header, which currently
only support IVHD type 0x10, to add new fields from IVHD type 11h and 40h.
It also modifies the pointer calculation to allow support for IVHD type
11h and 40h

Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd_iommu_init.c | 47 +++---
 1 file changed, 40 insertions(+), 7 deletions(-)

diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 013bdff..2ff7000 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -88,7 +88,7 @@
 
 /*
  * structure describing one IOMMU in the ACPI table. Typically followed by one
- * or more ivhd_entrys.
+ * or more ivhd_entrys. This struct supports both IVHD type 10h, 11h and 40h.
  */
 struct ivhd_header {
u8 type;
@@ -99,7 +99,11 @@ struct ivhd_header {
u64 mmio_phys;
u16 pci_seg;
u16 info;
-   u32 efr;
+   u32 efr_attr;
+
+   /* Following only valid on IVHD type 11h and 40h */
+   u64 efr_reg_img; /* Exact copy of MMIO_EXT_FEATURES */
+   u64 res;
 } __attribute__((packed));
 
 /*
@@ -399,6 +403,22 @@ static void __init iommu_unmap_mmio_space(struct amd_iommu 
*iommu)
  *
  /
 
+static inline u32 get_ivhd_header_size(struct ivhd_header *h)
+{
+   u32 size = 0;
+
+   switch (h->type) {
+   case 0x10:
+   size = 24;
+   break;
+   case 0x11:
+   case 0x40:
+   size = 40;
+   break;
+   }
+   return size;
+}
+
 /*
  * This function calculates the length of a given IVHD entry
  */
@@ -415,8 +435,14 @@ static int __init find_last_devid_from_ivhd(struct 
ivhd_header *h)
 {
u8 *p = (void *)h, *end = (void *)h;
struct ivhd_entry *dev;
+   u32 ivhd_size = get_ivhd_header_size(h);
+
+   if (!ivhd_size) {
+   pr_err("AMD-Vi: Unsupported IVHD type %#x\n", h->type);
+   return -EINVAL;
+   }
 
-   p += sizeof(*h);
+   p += ivhd_size;
end += h->length;
 
while (p < end) {
@@ -781,6 +807,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
u32 dev_i, ext_flags = 0;
bool alias = false;
struct ivhd_entry *e;
+   u32 ivhd_size;
int ret;
 
 
@@ -796,7 +823,13 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
/*
 * Done. Now parse the device entries
 */
-   p += sizeof(struct ivhd_header);
+   ivhd_size = get_ivhd_header_size(h);
+   if (!ivhd_size) {
+   pr_err("AMD-Vi: Unsupported IVHD type %#x\n", h->type);
+   return -EINVAL;
+   }
+
+   p += ivhd_size;
end += h->length;
 
 
@@ -1047,9 +1080,9 @@ static int __init init_iommu_one(struct amd_iommu *iommu, 
struct ivhd_header *h)
iommu->mmio_phys = h->mmio_phys;
 
/* Check if IVHD EFR contains proper max banks/counters */
-   if ((h->efr != 0) &&
-   ((h->efr & (0xF << 13)) != 0) &&
-   ((h->efr & (0x3F << 17)) != 0)) {
+   if ((h->efr_attr != 0) &&
+   ((h->efr_attr & (0xF << 13)) != 0) &&
+   ((h->efr_attr & (0x3F << 17)) != 0)) {
iommu->mmio_phys_end = MMIO_REG_END_OFFSET;
} else {
iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET;
-- 
1.9.1



[PATCH V2 0/8] iommu/amd: enable ACPI hardware ID device support

2016-01-26 Thread Wan Zongshun
From: Wan Zongshun 

There are some devices indentified using ACPI HID format in AMD chip.
This patch series enable iommu support for those ACPI HID device, 
since the existing AMD iommu only supports PCI bus based device.

The latest public version of AMD IOMMU specification that describes
the support for IVHD type 40h and ACPI HID IVHD device type, 
implemented by this patch series, is available here:

http://support.amd.com/TechDocs/48882_IOMMU.pdf


The V2 adds two new patches: patch 5 and patch 8 according to Joerg's
comments.

There is a little modification in patch 6 to distinguish pci and none pci.


Suravee Suthikulpanit (3):
  iommu/amd: Modify ivhd_header structure to support type 11h and 40h
  iommu/amd: Use the most comprehensive IVHD type that the driver can
support
  iommu/amd: Introduces ivrs_acpihid kernel parameter

Wan Zongshun (5):
  iommu/amd: Add new map for storing IVHD dev entry type HID
  iommu/amd: Make call-sites of get_device_id aware of its return value
  iommu/amd: Add iommu support for ACPI HID devices
  iommu/amd: Manage iommu_group for ACPI HID devices
  iommu/amd: Set AMD iommu callbacks for amba bus

 Documentation/kernel-parameters.txt |   7 +
 drivers/iommu/amd_iommu.c   | 167 ---
 drivers/iommu/amd_iommu_init.c  | 309 +++-
 drivers/iommu/amd_iommu_types.h |  14 ++
 4 files changed, 440 insertions(+), 57 deletions(-)

-- 
1.9.1



[PATCH 1/6] iommu/amd: Modify ivhd_header structure to support type 11h and 40h

2016-01-04 Thread Wan Zongshun
From: Suravee Suthikulpanit 

This patch modifies the existing struct ivhd_header, which currently
only support IVHD type 0x10, to add new fields from IVHD type 11h and 40h.
It also modifies the pointer calculation to allow support for IVHD type
11h and 40h

Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd_iommu_init.c | 47 +++---
 1 file changed, 40 insertions(+), 7 deletions(-)

diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 013bdff..2ff7000 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -88,7 +88,7 @@
 
 /*
  * structure describing one IOMMU in the ACPI table. Typically followed by one
- * or more ivhd_entrys.
+ * or more ivhd_entrys. This struct supports both IVHD type 10h, 11h and 40h.
  */
 struct ivhd_header {
u8 type;
@@ -99,7 +99,11 @@ struct ivhd_header {
u64 mmio_phys;
u16 pci_seg;
u16 info;
-   u32 efr;
+   u32 efr_attr;
+
+   /* Following only valid on IVHD type 11h and 40h */
+   u64 efr_reg_img; /* Exact copy of MMIO_EXT_FEATURES */
+   u64 res;
 } __attribute__((packed));
 
 /*
@@ -399,6 +403,22 @@ static void __init iommu_unmap_mmio_space(struct amd_iommu 
*iommu)
  *
  /
 
+static inline u32 get_ivhd_header_size(struct ivhd_header *h)
+{
+   u32 size = 0;
+
+   switch (h->type) {
+   case 0x10:
+   size = 24;
+   break;
+   case 0x11:
+   case 0x40:
+   size = 40;
+   break;
+   }
+   return size;
+}
+
 /*
  * This function calculates the length of a given IVHD entry
  */
@@ -415,8 +435,14 @@ static int __init find_last_devid_from_ivhd(struct 
ivhd_header *h)
 {
u8 *p = (void *)h, *end = (void *)h;
struct ivhd_entry *dev;
+   u32 ivhd_size = get_ivhd_header_size(h);
+
+   if (!ivhd_size) {
+   pr_err("AMD-Vi: Unsupported IVHD type %#x\n", h->type);
+   return -EINVAL;
+   }
 
-   p += sizeof(*h);
+   p += ivhd_size;
end += h->length;
 
while (p < end) {
@@ -781,6 +807,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
u32 dev_i, ext_flags = 0;
bool alias = false;
struct ivhd_entry *e;
+   u32 ivhd_size;
int ret;
 
 
@@ -796,7 +823,13 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
/*
 * Done. Now parse the device entries
 */
-   p += sizeof(struct ivhd_header);
+   ivhd_size = get_ivhd_header_size(h);
+   if (!ivhd_size) {
+   pr_err("AMD-Vi: Unsupported IVHD type %#x\n", h->type);
+   return -EINVAL;
+   }
+
+   p += ivhd_size;
end += h->length;
 
 
@@ -1047,9 +1080,9 @@ static int __init init_iommu_one(struct amd_iommu *iommu, 
struct ivhd_header *h)
iommu->mmio_phys = h->mmio_phys;
 
/* Check if IVHD EFR contains proper max banks/counters */
-   if ((h->efr != 0) &&
-   ((h->efr & (0xF << 13)) != 0) &&
-   ((h->efr & (0x3F << 17)) != 0)) {
+   if ((h->efr_attr != 0) &&
+   ((h->efr_attr & (0xF << 13)) != 0) &&
+   ((h->efr_attr & (0x3F << 17)) != 0)) {
iommu->mmio_phys_end = MMIO_REG_END_OFFSET;
} else {
iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET;
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 0/6] iommu/amd: enable ACPI hardware ID device support

2016-01-04 Thread Wan Zongshun
From: Wan Zongshun 

This patch series enable ACPI hardware ID device support, 

There are some devices indentified using ACPI HID format in AMD chip.
This patch series enable iommu support for those ACPI HID device,
since the existing AMD iommu only supports PCI bus based device.

Suravee Suthikulpanit (3):
  iommu/amd: Modify ivhd_header structure to support type 11h and 40h
  iommu/amd: Use the most comprehensive IVHD type that the driver can
support
  iommu/amd: Introduces ivrs_acpihid kernel parameter

Wan Zongshun (3):
  iommu/amd: Add new map for storing IVHD dev entry type HID
  iommu/amd: Add support for non-pci devices
  iommu/amd: Manage iommu_group for non-pci devices

 Documentation/kernel-parameters.txt |   7 +
 drivers/iommu/amd_iommu.c   | 158 +++---
 drivers/iommu/amd_iommu_init.c  | 309 +++-
 drivers/iommu/amd_iommu_types.h |  14 ++
 4 files changed, 433 insertions(+), 55 deletions(-)

-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 6/6] iommu/amd: Manage iommu_group for non-pci devices

2016-01-04 Thread Wan Zongshun
From: Wan Zongshun 

This patch creates a new function for finding or creating an IOMMU
group for acpihid(ACPI Hardware ID) device.

The acpihid devices with the same devid will be put into same group and
there will have the same domain id and share the same page table.

Signed-off-by: Wan Zongshun 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd_iommu.c | 33 -
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 1902d01..e1083ce 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -232,6 +232,29 @@ static struct iommu_dev_data *get_dev_data(struct device 
*dev)
return dev->archdata.iommu;
 }
 
+/*
+* Find or create an IOMMU group for a acpihid device.
+*/
+static struct iommu_group *acpihid_device_group(struct device *dev)
+{
+   struct acpihid_map_entry *p, *entry = NULL;
+   u16 devid;
+
+   devid = get_acpihid_device_id(dev, &entry);
+   if (devid < 0)
+   return ERR_PTR(devid);
+
+   list_for_each_entry(p, &acpihid_map, list) {
+   if ((devid == p->devid) && p->group)
+   entry->group = p->group;
+   }
+
+   if (!entry->group)
+   entry->group = generic_device_group(dev);
+
+   return entry->group;
+}
+
 static bool pci_iommuv2_capable(struct pci_dev *pdev)
 {
static const int caps[] = {
@@ -2311,6 +2334,14 @@ static void amd_iommu_remove_device(struct device *dev)
iommu_completion_wait(iommu);
 }
 
+static struct iommu_group *amd_iommu_device_group(struct device *dev)
+{
+   if (dev_is_pci(dev))
+   return pci_device_group(dev);
+
+   return acpihid_device_group(dev);
+}
+
 /*
  *
  * The next functions belong to the dma_ops mapping/unmapping code.
@@ -3202,7 +3233,7 @@ static const struct iommu_ops amd_iommu_ops = {
.iova_to_phys = amd_iommu_iova_to_phys,
.add_device = amd_iommu_add_device,
.remove_device = amd_iommu_remove_device,
-   .device_group = pci_device_group,
+   .device_group = amd_iommu_device_group,
.get_dm_regions = amd_iommu_get_dm_regions,
.put_dm_regions = amd_iommu_put_dm_regions,
.pgsize_bitmap  = AMD_IOMMU_PGSIZES,
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/6] iommu/amd: Use the most comprehensive IVHD type that the driver can support

2016-01-04 Thread Wan Zongshun
From: Suravee Suthikulpanit 

The IVRS in more recent AMD system usually contains multiple
IVHD block types (e.g. 0x10, 0x11, and 0x40) for each IOMMU.
The newer IVHD types provide more information (e.g. new features
specified in the IOMMU spec), while maintain compatibility with
the older IVHD type.

Having multiple IVHD type allows older IOMMU drivers to still function
(e.g. using the older IVHD type 0x10) while the newer IOMMU driver can use
the newer IVHD types (e.g. 0x11 and 0x40). Therefore, the IOMMU driver
should only make use of the newest IVHD type that it can support.

This patch adds new logic to determine the highest level of IVHD type
it can support, and use it throughout the to initialize the driver.
This requires adding another pass to the IVRS parsing to determine
appropriate IVHD type (see function get_highest_supported_ivhd_type())
before parsing the contents.

[Vincent: fix the build error of IVHD_DEV_ACPI_HID flag not found]

Signed-off-by: Wan Zongshun 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd_iommu_init.c | 107 ++---
 1 file changed, 78 insertions(+), 29 deletions(-)

diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 2ff7000..146f3ee 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -44,7 +44,7 @@
  */
 #define IVRS_HEADER_LENGTH 48
 
-#define ACPI_IVHD_TYPE  0x10
+#define ACPI_IVHD_TYPE_MAX_SUPPORTED   0x40
 #define ACPI_IVMD_TYPE_ALL  0x20
 #define ACPI_IVMD_TYPE  0x21
 #define ACPI_IVMD_TYPE_RANGE0x22
@@ -58,6 +58,7 @@
 #define IVHD_DEV_EXT_SELECT 0x46
 #define IVHD_DEV_EXT_SELECT_RANGE   0x47
 #define IVHD_DEV_SPECIAL   0x48
+#define IVHD_DEV_ACPI_HID  0xf0
 
 #define IVHD_SPECIAL_IOAPIC1
 #define IVHD_SPECIAL_HPET  2
@@ -137,6 +138,7 @@ bool amd_iommu_irq_remap __read_mostly;
 
 static bool amd_iommu_detected;
 static bool __initdata amd_iommu_disabled;
+static int amd_iommu_target_ivhd_type;
 
 u16 amd_iommu_last_bdf;/* largest PCI device id we have
   to handle */
@@ -424,7 +426,15 @@ static inline u32 get_ivhd_header_size(struct ivhd_header 
*h)
  */
 static inline int ivhd_entry_length(u8 *ivhd)
 {
-   return 0x04 << (*ivhd >> 6);
+   u32 type = ((struct ivhd_entry *)ivhd)->type;
+
+   if (type < 0x80) {
+   return 0x04 << (*ivhd >> 6);
+   } else if (type == IVHD_DEV_ACPI_HID) {
+   /* For ACPI_HID, offset 21 is uid len */
+   return *((u8 *)ivhd + 21) + 22;
+   }
+   return 0;
 }
 
 /*
@@ -470,6 +480,22 @@ static int __init find_last_devid_from_ivhd(struct 
ivhd_header *h)
return 0;
 }
 
+static int __init check_ivrs_checksum(struct acpi_table_header *table)
+{
+   int i;
+   u8 checksum = 0, *p = (u8 *)table;
+
+   for (i = 0; i < table->length; ++i)
+   checksum += p[i];
+   if (checksum != 0) {
+   /* ACPI table corrupt */
+   pr_err(FW_BUG "AMD-Vi: IVRS invalid checksum\n");
+   return -ENODEV;
+   }
+
+   return 0;
+}
+
 /*
  * Iterate over all IVHD entries in the ACPI table and find the highest device
  * id which we need to handle. This is the first of three functions which parse
@@ -477,31 +503,19 @@ static int __init find_last_devid_from_ivhd(struct 
ivhd_header *h)
  */
 static int __init find_last_devid_acpi(struct acpi_table_header *table)
 {
-   int i;
-   u8 checksum = 0, *p = (u8 *)table, *end = (u8 *)table;
+   u8 *p = (u8 *)table, *end = (u8 *)table;
struct ivhd_header *h;
 
-   /*
-* Validate checksum here so we don't need to do it when
-* we actually parse the table
-*/
-   for (i = 0; i < table->length; ++i)
-   checksum += p[i];
-   if (checksum != 0)
-   /* ACPI table corrupt */
-   return -ENODEV;
-
p += IVRS_HEADER_LENGTH;
 
end += table->length;
while (p < end) {
h = (struct ivhd_header *)p;
-   switch (h->type) {
-   case ACPI_IVHD_TYPE:
-   find_last_devid_from_ivhd(h);
-   break;
-   default:
-   break;
+   if (h->type == amd_iommu_target_ivhd_type) {
+   int ret = find_last_devid_from_ivhd(h);
+
+   if (ret)
+   return ret;
}
p += h->length;
}
@@ -1118,6 +1132,32 @@ static int __init init_iommu_one(struct amd_iommu 
*iommu, struct ivhd_header *h)
return 0;
 }
 
+/**
+ * get_highest_supported_ivhd_type - Look up the appropriate IVHD type
+ * @ivrs  Pointer to the IVRS header
+ *

[PATCH 5/6] iommu/amd: Add support for non-pci devices

2016-01-04 Thread Wan Zongshun
From: Wan Zongshun 

Current IOMMU driver make assumption that the downstream devices are PCI.
With the newly added ACPI-HID IVHD device entry support, this is no
longer true. This patch is to add dev type check and to distinguish the
pci and acpihid device code path.

Signed-off-by: Wan Zongshun 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd_iommu.c | 124 +++---
 1 file changed, 106 insertions(+), 18 deletions(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 98acb89..1902d01 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -19,6 +19,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -176,13 +177,56 @@ static struct iommu_dev_data *find_dev_data(u16 devid)
return dev_data;
 }
 
-static inline u16 get_device_id(struct device *dev)
+static inline int match_hid_uid(struct device *dev,
+   struct acpihid_map_entry *entry)
+{
+   const char *hid, *uid;
+
+   hid = acpi_device_hid(ACPI_COMPANION(dev));
+   uid = acpi_device_uid(ACPI_COMPANION(dev));
+
+   if (!hid || !(*hid))
+   return -ENODEV;
+
+   if (!uid || !(*uid))
+   return strcmp(hid, entry->hid);
+
+   if (!(*entry->uid))
+   return strcmp(hid, entry->hid);
+
+   return -ENODEV;
+}
+
+static inline u16 get_pci_device_id(struct device *dev)
 {
struct pci_dev *pdev = to_pci_dev(dev);
 
return PCI_DEVID(pdev->bus->number, pdev->devfn);
 }
 
+static inline int get_acpihid_device_id(struct device *dev,
+   struct acpihid_map_entry **entry)
+{
+   struct acpihid_map_entry *p;
+
+   list_for_each_entry(p, &acpihid_map, list) {
+   if (!match_hid_uid(dev, p)) {
+   if (entry)
+   *entry = p;
+   return p->devid;
+   }
+   }
+   return -EINVAL;
+}
+
+static inline u16 get_device_id(struct device *dev)
+{
+   if (dev_is_pci(dev))
+   return get_pci_device_id(dev);
+   else
+   return get_acpihid_device_id(dev, NULL);
+}
+
 static struct iommu_dev_data *get_dev_data(struct device *dev)
 {
return dev->archdata.iommu;
@@ -262,7 +306,7 @@ static bool check_device(struct device *dev)
return false;
 
/* No PCI device */
-   if (!dev_is_pci(dev))
+   if (!dev_is_pci(dev) && (get_acpihid_device_id(dev, NULL) < 0))
return false;
 
devid = get_device_id(dev);
@@ -298,7 +342,7 @@ out:
iommu_group_put(group);
 }
 
-static int iommu_init_device(struct device *dev)
+static int iommu_init_pci_device(struct device *dev)
 {
struct pci_dev *pdev = to_pci_dev(dev);
struct iommu_dev_data *dev_data;
@@ -325,6 +369,32 @@ static int iommu_init_device(struct device *dev)
return 0;
 }
 
+static int iommu_init_acpihid_device(struct device *dev)
+{
+   struct iommu_dev_data *dev_data;
+
+   if (dev->archdata.iommu)
+   return 0;
+
+   dev_data = find_dev_data(get_device_id(dev));
+   if (!dev_data)
+   return -ENOMEM;
+
+   dev->archdata.iommu = dev_data;
+
+   iommu_device_link(amd_iommu_rlookup_table[dev_data->devid]->iommu_dev,
+ dev);
+
+   return 0;
+}
+
+static int iommu_init_device(struct device *dev)
+{
+   if (dev_is_pci(dev))
+   return iommu_init_pci_device(dev);
+   return iommu_init_acpihid_device(dev);
+}
+
 static void iommu_ignore_device(struct device *dev)
 {
u16 devid, alias;
@@ -2066,19 +2136,16 @@ static bool pci_pri_tlp_required(struct pci_dev *pdev)
return (status & PCI_PRI_TLP_OFF) ? true : false;
 }
 
-/*
- * If a device is not yet associated with a domain, this function
- * assigns it visible for the hardware
- */
-static int attach_device(struct device *dev,
-struct protection_domain *domain)
+static int setup_ats_device(struct device *dev,
+   struct protection_domain *domain)
 {
-   struct pci_dev *pdev = to_pci_dev(dev);
-   struct iommu_dev_data *dev_data;
-   unsigned long flags;
-   int ret;
+   struct pci_dev *pdev;
+   struct iommu_dev_data *dev_data = get_dev_data(dev);
 
-   dev_data = get_dev_data(dev);
+   if (!dev_is_pci(dev))
+   return 0;
+
+   pdev = to_pci_dev(dev);
 
if (domain->flags & PD_IOMMUV2_MASK) {
if (!dev_data->passthrough)
@@ -2098,6 +2165,25 @@ static int attach_device(struct device *dev,
dev_data->ats.qdep= pci_ats_queue_depth(pdev);
}
 
+   return 0;
+}
+
+/*
+ * If a device is not yet associated with a domain, this function
+ * assigns it visible for the hardware
+ */
+static i

[PATCH 3/6] iommu/amd: Add new map for storing IVHD dev entry type HID

2016-01-04 Thread Wan Zongshun
From: Wan Zongshun 

This patch introduces acpihid_map, which is used to store
the new IVHD device entry extracted from BIOS IVRS table.

It also provides a utility function add_acpi_hid_device(),
to add this types of devices to the map.

Signed-off-by: Wan Zongshun 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd_iommu.c   |   1 +
 drivers/iommu/amd_iommu_init.c  | 122 
 drivers/iommu/amd_iommu_types.h |  14 +
 3 files changed, 137 insertions(+)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 9097b11..98acb89 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -72,6 +72,7 @@ static DEFINE_SPINLOCK(dev_data_list_lock);
 
 LIST_HEAD(ioapic_map);
 LIST_HEAD(hpet_map);
+LIST_HEAD(acpihid_map);
 
 /*
  * Domain for untranslated devices - only allocated
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 146f3ee..0a8e033 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -60,6 +60,10 @@
 #define IVHD_DEV_SPECIAL   0x48
 #define IVHD_DEV_ACPI_HID  0xf0
 
+#define UID_NOT_PRESENT 0
+#define UID_IS_INTEGER  1
+#define UID_IS_CHARACTER2
+
 #define IVHD_SPECIAL_IOAPIC1
 #define IVHD_SPECIAL_HPET  2
 
@@ -116,6 +120,11 @@ struct ivhd_entry {
u16 devid;
u8 flags;
u32 ext;
+   u32 hidh;
+   u64 cid;
+   u8 uidf;
+   u8 uidl;
+   u8 uid;
 } __attribute__((packed));
 
 /*
@@ -224,8 +233,12 @@ enum iommu_init_state {
 #define EARLY_MAP_SIZE 4
 static struct devid_map __initdata early_ioapic_map[EARLY_MAP_SIZE];
 static struct devid_map __initdata early_hpet_map[EARLY_MAP_SIZE];
+static struct acpihid_map_entry __initdata early_acpihid_map[EARLY_MAP_SIZE];
+
 static int __initdata early_ioapic_map_size;
 static int __initdata early_hpet_map_size;
+static int __initdata early_acpihid_map_size;
+
 static bool __initdata cmdline_maps;
 
 static enum iommu_init_state init_state = IOMMU_START_STATE;
@@ -760,6 +773,42 @@ static int __init add_special_device(u8 type, u8 id, u16 
*devid, bool cmd_line)
return 0;
 }
 
+static int __init add_acpi_hid_device(u8 *hid, u8 *uid, u16 *devid,
+ bool cmd_line)
+{
+   struct acpihid_map_entry *entry;
+   struct list_head *list = &acpihid_map;
+
+   list_for_each_entry(entry, list, list) {
+   if (strcmp(entry->hid, hid) ||
+   (*uid && *entry->uid && strcmp(entry->uid, uid)) ||
+   !entry->cmd_line)
+   continue;
+
+   pr_info("AMD-Vi: Command-line override for hid:%s uid:%s\n",
+   hid, uid);
+   *devid = entry->devid;
+   return 0;
+   }
+
+   entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+   if (!entry)
+   return -ENOMEM;
+
+   memcpy(entry->uid, uid, strlen(uid));
+   memcpy(entry->hid, hid, strlen(hid));
+   entry->devid = *devid;
+   entry->cmd_line = cmd_line;
+   entry->root_devid = (entry->devid & (~0x7));
+
+   pr_info("AMD-Vi:%s, add hid:%s, uid:%s, rdevid:%d\n",
+   entry->cmd_line ? "cmd" : "ivrs",
+   entry->hid, entry->uid, entry->root_devid);
+
+   list_add_tail(&entry->list, list);
+   return 0;
+}
+
 static int __init add_early_maps(void)
 {
int i, ret;
@@ -782,6 +831,15 @@ static int __init add_early_maps(void)
return ret;
}
 
+   for (i = 0; i < early_acpihid_map_size; ++i) {
+   ret = add_acpi_hid_device(early_acpihid_map[i].hid,
+ early_acpihid_map[i].uid,
+ &early_acpihid_map[i].devid,
+ early_acpihid_map[i].cmd_line);
+   if (ret)
+   return ret;
+   }
+
return 0;
 }
 
@@ -1001,6 +1059,70 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
 
break;
}
+   case IVHD_DEV_ACPI_HID: {
+   u16 devid;
+   u8 hid[ACPIHID_HID_LEN] = {0};
+   u8 uid[ACPIHID_UID_LEN] = {0};
+   int ret;
+
+   if (h->type != 0x40) {
+   pr_err(FW_BUG "Invalid IVHD device type %#x\n",
+  e->type);
+   break;
+   }
+
+   memcpy(hid, (u8 *)(&e->ext), ACPIHID_HID_LEN - 1);
+   hid[ACPIHID_HID_LEN - 1] = &#x

[PATCH 4/6] iommu/amd: Introduces ivrs_acpihid kernel parameter

2016-01-04 Thread Wan Zongshun
From: Suravee Suthikulpanit 

This patch introduces a new kernel parameter, ivrs_acpihid.
This is used to override existing ACPI-HID IVHD device entry,
or add an entry in case it is missing in the IVHD.

Signed-off-by: Wan Zongshun 
Signed-off-by: Suravee Suthikulpanit 
---
 Documentation/kernel-parameters.txt |  7 +++
 drivers/iommu/amd_iommu_init.c  | 33 +
 2 files changed, 40 insertions(+)

diff --git a/Documentation/kernel-parameters.txt 
b/Documentation/kernel-parameters.txt
index 742f69d..5c364c6 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1680,6 +1680,13 @@ bytes respectively. Such letter suffixes can also be 
entirely omitted.
PCI device 00:14.0 write the parameter as:
ivrs_hpet[0]=00:14.0
 
+   ivrs_acpihid[HW,X86_64]
+   Provide an override to the ACPI-HID:UID<->DEVICE-ID
+   mapping provided in the IVRS ACPI table. For
+   example, to map UART-HID:UID AMD0020:0 to
+   PCI device 00:14.5 write the parameter as:
+   ivrs_acpihid[00:14.5]=AMD0020:0
+
js= [HW,JOY] Analog joystick
See Documentation/input/joystick.txt.
 
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 0a8e033..ad05614 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -2430,10 +2430,43 @@ static int __init parse_ivrs_hpet(char *str)
return 1;
 }
 
+static int __init parse_ivrs_acpihid(char *str)
+{
+   u32 bus, dev, fn;
+   char *hid, *uid, *p;
+   char acpiid[ACPIHID_UID_LEN + ACPIHID_HID_LEN] = {0};
+   int ret, i;
+
+   ret = sscanf(str, "[%x:%x.%x]=%s", &bus, &dev, &fn, acpiid);
+   if (ret != 4) {
+   pr_err("AMD-Vi: Invalid command line: ivrs_acpihid(%s)\n", str);
+   return 1;
+   }
+
+   p = acpiid;
+   hid = strsep(&p, ":");
+   uid = p;
+
+   if (!hid || !(*hid) || !uid) {
+   pr_err("AMD-Vi: Invalid command line: hid or uid\n");
+   return 1;
+   }
+
+   i = early_acpihid_map_size++;
+   memcpy(early_acpihid_map[i].hid, hid, strlen(hid));
+   memcpy(early_acpihid_map[i].uid, uid, strlen(uid));
+   early_acpihid_map[i].devid =
+   ((bus & 0xff) << 8) | ((dev & 0x1f) << 3) | (fn & 0x7);
+   early_acpihid_map[i].cmd_line   = true;
+
+   return 1;
+}
+
 __setup("amd_iommu_dump",  parse_amd_iommu_dump);
 __setup("amd_iommu=",  parse_amd_iommu_options);
 __setup("ivrs_ioapic", parse_ivrs_ioapic);
 __setup("ivrs_hpet",   parse_ivrs_hpet);
+__setup("ivrs_acpihid",parse_ivrs_acpihid);
 
 IOMMU_INIT_FINISH(amd_iommu_detect,
  gart_iommu_hole_init,
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] iommu/amd: set AMD iommu-callbacks for the amba bus

2015-12-29 Thread Wan Zongshun
From: Wan Zongshun 

Since uart dma is using AMD iommu, and it bases on amba bus.
So we need set callbacks for amba bus type firstly.

Signed-off-by: Wan Zongshun 
---
 drivers/iommu/amd_iommu.c | 13 -
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 8b2be1e..9097b11 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -35,6 +35,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -2758,7 +2759,17 @@ static struct dma_map_ops amd_iommu_dma_ops = {
 
 int __init amd_iommu_init_api(void)
 {
-   return bus_set_iommu(&pci_bus_type, &amd_iommu_ops);
+   int err = 0;
+
+   err = bus_set_iommu(&pci_bus_type, &amd_iommu_ops);
+   if (err)
+   return err;
+#ifdef CONFIG_ARM_AMBA
+   err = bus_set_iommu(&amba_bustype, &amd_iommu_ops);
+   if (err)
+   return err;
+#endif
+   return 0;
 }
 
 int __init amd_iommu_init_dma_ops(void)
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] iommu:Check that iommu_device_create has completed successfully in alloc_iommu

2015-12-28 Thread Wan ZongShun
2015-12-29 13:10 GMT+08:00 Nicholas Krause :
> This adds the proper check to alloc_iommu to make sure that the call
> to iommu_device_create has completed successfully and if not return
> to the caller the error code returned after freeing up resources
> allocated previously by alloc_iommu.
>
> Signed-off-by: Nicholas Krause 
> ---
>  drivers/iommu/dmar.c | 5 -
>  1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
> index 80e3c17..27333b6 100644
> --- a/drivers/iommu/dmar.c
> +++ b/drivers/iommu/dmar.c
> @@ -1069,9 +1069,12 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
> iommu->iommu_dev = iommu_device_create(NULL, iommu,
>intel_iommu_groups,
>"%s", iommu->name);
> +   if (IS_ERR(iommu->iommu_dev)) {
> +   err = PTR_ERR(iommu->iommu_dev);
> +   goto err_unmap;
> +   }

If so, will this bad 'iommu->iommu_dev' break your iommu work?  It
seems not necessary.

>
> return 0;
> -
>  err_unmap:
> unmap_iommu(iommu);
>  error_free_seq_id:
> --
> 2.5.0
>
> ___
> iommu mailing list
> io...@lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/iommu



-- 
---
Vincent Wan(Zongshun)
www.mcuos.com
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 1/3] mmc: sdhci-pci: Add AMD HS200 mode tuning function

2015-12-22 Thread Wan ZongShun
2015-12-22 17:52 GMT+08:00 Andy Shevchenko :
> On Tue, Dec 22, 2015 at 6:40 PM, Wan Zongshun  wrote:
>> From: Wan Zongshun 
>>
>> This patch is to add software tuning functions for AMD hs200
>> mode.
>>
>> Signed-off-by: Wan Zongshun 
>> ---
>>  drivers/mmc/host/sdhci-pci-core.c | 146 
>> ++
>>  1 file changed, 146 insertions(+)
>>
>> diff --git a/drivers/mmc/host/sdhci-pci-core.c 
>> b/drivers/mmc/host/sdhci-pci-core.c
>> index 08f4a9f..01c5723 100644
>> --- a/drivers/mmc/host/sdhci-pci-core.c
>> +++ b/drivers/mmc/host/sdhci-pci-core.c
>> @@ -729,6 +729,152 @@ enum amd_chipset_gen {
>> AMD_CHIPSET_UNKNOWN,
>>  };
>>
>> +struct tuning_descriptor {
>> +   unsigned char tune_around;
>> +   bool this_tune_ok;
>> +   bool last_tune_ok;
>> +   bool valid_front_end;
>> +   unsigned char valid_front;
>> +   unsigned char valid_window_max;
>> +   unsigned char tune_low_max;
>> +   unsigned char tune_low;
>> +   unsigned char valid_window;
>> +   unsigned char tune_result;
>> +};
>> +
>> +#define AMD_EMMC_TUNE_REG 0xb8
>> +static struct tuning_descriptor tdescriptor;
>
> Global variable?!

Okay, will change it to local.

>
>> +
>> +static int tuning_reset(struct sdhci_host *host)
>
> Better prefixes?

Do you mean I should not name this function to tuning reset?

>
>> +{
>> +   unsigned int val;
>> +   unsigned long flags;
>> +
>> +   spin_lock_irqsave(&host->lock, flags);
>> +
>> +   val = sdhci_readw(host, SDHCI_HOST_CONTROL2);
>> +   val |= SDHCI_CTRL_PRESET_VAL_ENABLE | SDHCI_CTRL_EXEC_TUNING;
>> +   sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
>> +
>> +   val = sdhci_readw(host, SDHCI_HOST_CONTROL2);
>> +   val &= ~SDHCI_CTRL_EXEC_TUNING;
>> +   sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
>> +
>> +   spin_unlock_irqrestore(&host->lock, flags);
>> +
>> +   return 0;
>> +}
>> +
>> +static int config_tuning_phase(struct sdhci_host *host, unsigned char phase)
>> +{
>> +   struct sdhci_pci_slot *slot = sdhci_priv(host);
>> +   struct pci_dev *pdev = slot->chip->pdev;
>> +   unsigned int val;
>> +   unsigned long flags;
>> +
>> +   spin_lock_irqsave(&host->lock, flags);
>> +
>> +   pci_read_config_dword(pdev, AMD_EMMC_TUNE_REG, &val);
>> +   val &= ~0xf;
>> +   val |= (0x10800 | phase);
>
> Magic.

Okay, I will make 0x10800 to be see more clearly, will define each bit
Macro for it.

>
>> +   pci_write_config_dword(pdev, AMD_EMMC_TUNE_REG, val);
>> +
>> +   spin_unlock_irqrestore(&host->lock, flags);
>> +
>> +   return 0;
>> +}
>> +
>> +static int find_good_phase(struct sdhci_host *host)
>> +{
>> +   struct tuning_descriptor *td = &tdescriptor;
>> +   struct sdhci_pci_slot *slot = sdhci_priv(host);
>> +   struct pci_dev *pdev = slot->chip->pdev;
>> +   unsigned int val;
>> +   unsigned long flags;
>> +
>> +   spin_lock_irqsave(&host->lock, flags);
>> +
>> +   if (td->this_tune_ok == false)
>> +   td->valid_front_end = 1;
>> +
>> +   if (td->valid_front_end)
>> +   td->valid_front = td->valid_front;
>> +   else if (td->this_tune_ok)
>> +   td->valid_front = td->valid_front + 1;
>> +
>> +   if ((!td->this_tune_ok && td->last_tune_ok) ||
>> +   (td->tune_around == 11)) {
>
> Magic.
>
>> +   if (td->valid_window > td->valid_window_max) {
>> +   td->valid_window_max = td->valid_window;
>> +   td->tune_low_max = td->tune_low;
>> +   }
>> +   }
>> +
>> +   if (td->this_tune_ok) {
>> +   if (!td->last_tune_ok)
>> +   td->tune_low = td->tune_around;
>> +   td->valid_window = td->valid_window + 1;
>> +   } else {
>> +   if (td->last_tune_ok)
>> +   td->valid_window = 0x0;
>> +   }
>> +
>> +   td->last_tune_ok = td->this_tune_ok;
>> +
>> +   if (td->tune_around == 11) {
>> +   if ((td->valid_front + td->

Re: [PATCH 2/3] mmc: sdhci-pci: Add platform tuning callback for amd hs200 mode

2015-12-22 Thread Wan ZongShun
>> +
>>  static const struct sdhci_pci_fixes sdhci_amd = {
>> .probe  = amd_probe,
>> +   .probe_slot = amd_probe_slot,
>>  };
>>
>>  static const struct pci_device_id pci_ids[] = {
>> @@ -1508,6 +1519,17 @@ static int sdhci_pci_select_drive_strength(struct 
>> sdhci_host *host,
>>card_drv, drv_type);
>>  }
>>
>> +static int sdhci_pci_platform_execute_tuning(struct sdhci_host *host,
>> +u32 opcode)
>> +{
>> +   struct sdhci_pci_slot *slot = sdhci_priv(host);
>> +
>> +   if (!slot->platform_execute_tuning)
>> +   return -EPERM;
>
> Here you return an error code.
>
>> +
>> +   return slot->platform_execute_tuning(host, opcode);
>> +}
>> +
>>  static const struct sdhci_ops sdhci_pci_ops = {
>> .set_clock  = sdhci_set_clock,
>> .enable_dma = sdhci_pci_enable_dma,
>> @@ -1516,6 +1538,7 @@ static const struct sdhci_ops sdhci_pci_ops = {
>> .set_uhs_signaling = sdhci_set_uhs_signaling,
>> .hw_reset   = sdhci_pci_hw_reset,
>> .select_drive_strength  = sdhci_pci_select_drive_strength,
>> +   .platform_execute_tuning = sdhci_pci_platform_execute_tuning,
>>  };
>>
>>  
>> /*\
>> diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h
>> index d1a0b4d..48d98f1 100644
>> --- a/drivers/mmc/host/sdhci-pci.h
>> +++ b/drivers/mmc/host/sdhci-pci.h
>> @@ -83,6 +83,7 @@ struct sdhci_pci_slot {
>>  struct mmc_card *card,
>>  unsigned int max_dtr, int host_drv,
>>  int card_drv, int *drv_type);
>> +   int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
>>  };
>>
>>  struct sdhci_pci_chip {
>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>> index 2753b722d..2a5a6ce 100644
>> --- a/drivers/mmc/host/sdhci.c
>> +++ b/drivers/mmc/host/sdhci.c
>> @@ -1937,7 +1937,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, 
>> u32 opcode)
>> spin_unlock_irqrestore(&host->lock, flags);
>> err = host->ops->platform_execute_tuning(host, opcode);
>> sdhci_runtime_pm_put(host);
>> -   return err;
>> +   if (err != EPERM)
>
> …and here you ignore it. Perhaps better to introduce various positive codes
>
> #define AMD_TUNNING_DONE 0
> #define AMD_TUNNING_NA 1

Andy, It looks a good idea, thanks.


>
>
>> +   return err;
>> }
>>
>> ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
>> --
>> 1.9.1
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to majord...@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at  http://www.tux.org/lkml/
>
>
>
> --
> With Best Regards,
> Andy Shevchenko



-- 
---
Vincent Wan(Zongshun)
www.mcuos.com
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 3/3] mmc: sdhci-pci: enable AMD emmc hs200 mode

2015-12-22 Thread Wan Zongshun
From: Wan Zongshun 

This patch is to remove the SDHCI_QUIRK2_BROKEN_HS200 quirk and
enable the emmc hs200 mode for AMD current platforms.

Signed-off-by: Wan Zongshun 
---
 drivers/mmc/host/sdhci-pci-core.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/mmc/host/sdhci-pci-core.c 
b/drivers/mmc/host/sdhci-pci-core.c
index e7b2bbe..17697fd 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -897,10 +897,8 @@ static int amd_probe(struct sdhci_pci_chip *chip)
}
}
 
-   if ((gen == AMD_CHIPSET_BEFORE_ML) || (gen == AMD_CHIPSET_CZ)) {
+   if ((gen == AMD_CHIPSET_BEFORE_ML) || (gen == AMD_CHIPSET_CZ))
chip->quirks2 |= SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD;
-   chip->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
-   }
 
return 0;
 }
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/3] mmc: sdhci-pci: Add AMD HS200 mode tuning function

2015-12-22 Thread Wan Zongshun
From: Wan Zongshun 

This patch is to add software tuning functions for AMD hs200
mode.

Signed-off-by: Wan Zongshun 
---
 drivers/mmc/host/sdhci-pci-core.c | 146 ++
 1 file changed, 146 insertions(+)

diff --git a/drivers/mmc/host/sdhci-pci-core.c 
b/drivers/mmc/host/sdhci-pci-core.c
index 08f4a9f..01c5723 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -729,6 +729,152 @@ enum amd_chipset_gen {
AMD_CHIPSET_UNKNOWN,
 };
 
+struct tuning_descriptor {
+   unsigned char tune_around;
+   bool this_tune_ok;
+   bool last_tune_ok;
+   bool valid_front_end;
+   unsigned char valid_front;
+   unsigned char valid_window_max;
+   unsigned char tune_low_max;
+   unsigned char tune_low;
+   unsigned char valid_window;
+   unsigned char tune_result;
+};
+
+#define AMD_EMMC_TUNE_REG 0xb8
+static struct tuning_descriptor tdescriptor;
+
+static int tuning_reset(struct sdhci_host *host)
+{
+   unsigned int val;
+   unsigned long flags;
+
+   spin_lock_irqsave(&host->lock, flags);
+
+   val = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+   val |= SDHCI_CTRL_PRESET_VAL_ENABLE | SDHCI_CTRL_EXEC_TUNING;
+   sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
+
+   val = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+   val &= ~SDHCI_CTRL_EXEC_TUNING;
+   sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
+
+   spin_unlock_irqrestore(&host->lock, flags);
+
+   return 0;
+}
+
+static int config_tuning_phase(struct sdhci_host *host, unsigned char phase)
+{
+   struct sdhci_pci_slot *slot = sdhci_priv(host);
+   struct pci_dev *pdev = slot->chip->pdev;
+   unsigned int val;
+   unsigned long flags;
+
+   spin_lock_irqsave(&host->lock, flags);
+
+   pci_read_config_dword(pdev, AMD_EMMC_TUNE_REG, &val);
+   val &= ~0xf;
+   val |= (0x10800 | phase);
+   pci_write_config_dword(pdev, AMD_EMMC_TUNE_REG, val);
+
+   spin_unlock_irqrestore(&host->lock, flags);
+
+   return 0;
+}
+
+static int find_good_phase(struct sdhci_host *host)
+{
+   struct tuning_descriptor *td = &tdescriptor;
+   struct sdhci_pci_slot *slot = sdhci_priv(host);
+   struct pci_dev *pdev = slot->chip->pdev;
+   unsigned int val;
+   unsigned long flags;
+
+   spin_lock_irqsave(&host->lock, flags);
+
+   if (td->this_tune_ok == false)
+   td->valid_front_end = 1;
+
+   if (td->valid_front_end)
+   td->valid_front = td->valid_front;
+   else if (td->this_tune_ok)
+   td->valid_front = td->valid_front + 1;
+
+   if ((!td->this_tune_ok && td->last_tune_ok) ||
+   (td->tune_around == 11)) {
+   if (td->valid_window > td->valid_window_max) {
+   td->valid_window_max = td->valid_window;
+   td->tune_low_max = td->tune_low;
+   }
+   }
+
+   if (td->this_tune_ok) {
+   if (!td->last_tune_ok)
+   td->tune_low = td->tune_around;
+   td->valid_window = td->valid_window + 1;
+   } else {
+   if (td->last_tune_ok)
+   td->valid_window = 0x0;
+   }
+
+   td->last_tune_ok = td->this_tune_ok;
+
+   if (td->tune_around == 11) {
+   if ((td->valid_front + td->valid_window) >
+   td->valid_window_max) {
+   if (td->valid_front > td->valid_window)
+   td->tune_result =
+   ((td->valid_front - td->valid_window) >> 1);
+   else
+   td->tune_result = td->tune_low +
+   ((td->valid_window + td->valid_front) >> 1);
+   } else {
+   td->tune_result =
+   td->tune_low_max + (td->valid_window_max >> 1);
+   }
+
+   if (td->tune_result > 0x0b)
+   td->tune_result = 0x0b;
+
+   pci_read_config_dword(pdev, AMD_EMMC_TUNE_REG, &val);
+   val &= ~0xf;
+   val |= (0x10800 | td->tune_result);
+   pci_write_config_dword(pdev, AMD_EMMC_TUNE_REG, val);
+   }
+
+   spin_unlock_irqrestore(&host->lock, flags);
+
+   return 0;
+}
+
+static int amd_execute_tuning(struct sdhci_host *host, u32 opcode)
+{
+   struct tuning_descriptor *td = &tdescriptor;
+
+   tuning_reset(host);
+
+   for (td->tune_around = 0; td->tune_around < 12; td->tune_around++) {
+
+   config_tuning_phase(host, td

[PATCH 2/3] mmc: sdhci-pci: Add platform tuning callback for amd hs200 mode

2015-12-22 Thread Wan Zongshun
From: Wan Zongshun 

AMD hs200 mode tuning mode is not compatible with standard tuning process,
so we need .platform_execute_tuning callback support in sdhci-pci-core.c,
this patch is to do:

1. Add platform_execute_tuning callback in sdhci_pci_slot.
2. Implement sdhci_pci_ops.platform_execute_tuning function.

Signed-off-by: Wan Zongshun 
---
Hi Ulf,

Though modifying sdhci_pci_ops to be not const that is easy to implement
my requirement, I am not sure it is right to do this.

So I just follow sdhci_pci_select_drive_strength style to add new callback:
sdhci_pci_platform_execute_tuning.

But I also met trouble in sdhci_execute_tuning of sdhci.c, I have to suppose
only sdhci_pci_platform_execute_tuning is returning -EPERM(current code,
my assumption is right), so that those vendor that has no
slot->platform_execute_tuning could be skipped and go next standard
tuning process.

If you have better idea for my requirement, please correct me.

Thanks!
Wan Zongshun.

---
 drivers/mmc/host/sdhci-pci-core.c | 23 +++
 drivers/mmc/host/sdhci-pci.h  |  1 +
 drivers/mmc/host/sdhci.c  |  3 ++-
 3 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-pci-core.c 
b/drivers/mmc/host/sdhci-pci-core.c
index 01c5723..e7b2bbe 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -905,8 +905,19 @@ static int amd_probe(struct sdhci_pci_chip *chip)
return 0;
 }
 
+static int amd_probe_slot(struct sdhci_pci_slot *slot)
+{
+   struct sdhci_host *host = slot->host;
+
+   if (host->quirks2 & SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD)
+   slot->platform_execute_tuning = amd_execute_tuning;
+
+   return 0;
+}
+
 static const struct sdhci_pci_fixes sdhci_amd = {
.probe  = amd_probe,
+   .probe_slot = amd_probe_slot,
 };
 
 static const struct pci_device_id pci_ids[] = {
@@ -1508,6 +1519,17 @@ static int sdhci_pci_select_drive_strength(struct 
sdhci_host *host,
   card_drv, drv_type);
 }
 
+static int sdhci_pci_platform_execute_tuning(struct sdhci_host *host,
+u32 opcode)
+{
+   struct sdhci_pci_slot *slot = sdhci_priv(host);
+
+   if (!slot->platform_execute_tuning)
+   return -EPERM;
+
+   return slot->platform_execute_tuning(host, opcode);
+}
+
 static const struct sdhci_ops sdhci_pci_ops = {
.set_clock  = sdhci_set_clock,
.enable_dma = sdhci_pci_enable_dma,
@@ -1516,6 +1538,7 @@ static const struct sdhci_ops sdhci_pci_ops = {
.set_uhs_signaling = sdhci_set_uhs_signaling,
.hw_reset   = sdhci_pci_hw_reset,
.select_drive_strength  = sdhci_pci_select_drive_strength,
+   .platform_execute_tuning = sdhci_pci_platform_execute_tuning,
 };
 
 /*\
diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h
index d1a0b4d..48d98f1 100644
--- a/drivers/mmc/host/sdhci-pci.h
+++ b/drivers/mmc/host/sdhci-pci.h
@@ -83,6 +83,7 @@ struct sdhci_pci_slot {
 struct mmc_card *card,
 unsigned int max_dtr, int host_drv,
 int card_drv, int *drv_type);
+   int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
 };
 
 struct sdhci_pci_chip {
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 2753b722d..2a5a6ce 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1937,7 +1937,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 
opcode)
spin_unlock_irqrestore(&host->lock, flags);
err = host->ops->platform_execute_tuning(host, opcode);
sdhci_runtime_pm_put(host);
-   return err;
+   if (err != EPERM)
+   return err;
}
 
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] clk: let clk_disable() return immediately if clk is NULL or error

2015-12-20 Thread Wan ZongShun
2015-12-05 14:17 GMT+08:00 Masahiro Yamada :
> The clk_disable() in the common clock framework (drivers/clk/clk.c)
> returns immediately if the given clk is NULL or an error pointer.
> It allows drivers to call clk_disable() (and clk_disable_unprepare())
> with a clock that might be NULL or an error pointer as long as the
> drivers are only used along with the common clock framework.
>
> Unfortunately, NULL/error checking is missing from some of non-common
> clk_disable() implementations.  This prevents us from completely
> dropping NULL/error from callers.  Let's add IS_ERR_OR_NULL(clk)
> checks to all callees.
>
> Signed-off-by: Masahiro Yamada 
> ---
>
>  arch/arm/mach-ep93xx/clock.c |  2 +-
>  arch/arm/mach-lpc32xx/clock.c|  3 +++
>  arch/arm/mach-mmp/clock.c|  3 +++
>  arch/arm/mach-sa1100/clock.c | 15 ---
>  arch/arm/mach-w90x900/clock.c|  3 +++
>  arch/blackfin/mach-bf609/clock.c |  3 +++
>  arch/m68k/coldfire/clk.c |  4 
>  arch/mips/bcm63xx/clk.c  |  3 +++
>  arch/mips/lantiq/clk.c   |  3 +++
>  drivers/sh/clk/core.c|  2 +-
>  10 files changed, 32 insertions(+), 9 deletions(-)
>
> diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
> index 39ef3b6..4e11f7d 100644
> --- a/arch/arm/mach-ep93xx/clock.c
> +++ b/arch/arm/mach-ep93xx/clock.c
> @@ -293,7 +293,7 @@ void clk_disable(struct clk *clk)
>  {
> unsigned long flags;
>
> -   if (!clk)
> +   if (IS_ERR_OR_NULL(clk))
> return;
>
> spin_lock_irqsave(&clk_lock, flags);
> diff --git a/arch/arm/mach-lpc32xx/clock.c b/arch/arm/mach-lpc32xx/clock.c
> index 661c8f4..07faac2 100644
> --- a/arch/arm/mach-lpc32xx/clock.c
> +++ b/arch/arm/mach-lpc32xx/clock.c
> @@ -1125,6 +1125,9 @@ void clk_disable(struct clk *clk)
>  {
> unsigned long flags;
>
> +   if (IS_ERR_OR_NULL(clk))
> +   return;
> +
> spin_lock_irqsave(&global_clkregs_lock, flags);
> local_clk_disable(clk);
> spin_unlock_irqrestore(&global_clkregs_lock, flags);
> diff --git a/arch/arm/mach-mmp/clock.c b/arch/arm/mach-mmp/clock.c
> index 7c6f95f..7b33122 100644
> --- a/arch/arm/mach-mmp/clock.c
> +++ b/arch/arm/mach-mmp/clock.c
> @@ -67,6 +67,9 @@ void clk_disable(struct clk *clk)
>  {
> unsigned long flags;
>
> +   if (IS_ERR_OR_NULL(clk))
> +   return;
> +
> WARN_ON(clk->enabled == 0);
>
> spin_lock_irqsave(&clocks_lock, flags);
> diff --git a/arch/arm/mach-sa1100/clock.c b/arch/arm/mach-sa1100/clock.c
> index cbf53bb..ea103fd 100644
> --- a/arch/arm/mach-sa1100/clock.c
> +++ b/arch/arm/mach-sa1100/clock.c
> @@ -85,13 +85,14 @@ void clk_disable(struct clk *clk)
>  {
> unsigned long flags;
>
> -   if (clk) {
> -   WARN_ON(clk->enabled == 0);
> -   spin_lock_irqsave(&clocks_lock, flags);
> -   if (--clk->enabled == 0)
> -   clk->ops->disable(clk);
> -   spin_unlock_irqrestore(&clocks_lock, flags);
> -   }
> +   if (IS_ERR_OR_NULL(clk))
> +   return;
> +
> +   WARN_ON(clk->enabled == 0);
> +   spin_lock_irqsave(&clocks_lock, flags);
> +   if (--clk->enabled == 0)
> +   clk->ops->disable(clk);
> +   spin_unlock_irqrestore(&clocks_lock, flags);
>  }
>  EXPORT_SYMBOL(clk_disable);
>
> diff --git a/arch/arm/mach-w90x900/clock.c b/arch/arm/mach-w90x900/clock.c
> index 2c371ff..90ec250 100644
> --- a/arch/arm/mach-w90x900/clock.c
> +++ b/arch/arm/mach-w90x900/clock.c
> @@ -46,6 +46,9 @@ void clk_disable(struct clk *clk)
>  {
> unsigned long flags;
>
> +   if (IS_ERR_OR_NULL(clk))
> +   return;

Looks good for w90x900 platform.
Acked-by: Wan Zongshun 

> +
> WARN_ON(clk->enabled == 0);
>
> spin_lock_irqsave(&clocks_lock, flags);
> diff --git a/arch/blackfin/mach-bf609/clock.c 
> b/arch/blackfin/mach-bf609/clock.c
> index 3783058..fed8015 100644
> --- a/arch/blackfin/mach-bf609/clock.c
> +++ b/arch/blackfin/mach-bf609/clock.c
> @@ -97,6 +97,9 @@ EXPORT_SYMBOL(clk_enable);
>
>  void clk_disable(struct clk *clk)
>  {
> +   if (IS_ERR_OR_NULL(clk))
> +   return;
> +
> if (clk->ops && clk->ops->disable)
> clk->ops->disable(clk);
>  }
> diff --git a/arch/m68k/coldfire/clk.c b/arch/m68k/coldfire/clk.c
> index fddfdcc..eb0e8c1 100644
> --- a/arch/m68k/coldfire/clk.c
> +++ b/arch/m68k/coldfire/clk.c
> @@ -101,6 +101,10 @@ 

[PATCH v2] Implement i8042 detect by BIOS FADT i8042 flag

2015-12-02 Thread Wan Zongshun
Detecting x86 platform supporting i8042 or not, we should resort
to BIOS's FADT i8042 flag per ACPI spec.

Currently, Windows is conforming to this spec, and request this
flag to detect i8042 supporting.

Signed-off-by: Wan Zongshun 
---
 drivers/input/serio/i8042-x86ia64io.h | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/input/serio/i8042-x86ia64io.h 
b/drivers/input/serio/i8042-x86ia64io.h
index c115565..73686bd 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -9,6 +9,7 @@
 
 #ifdef CONFIG_X86
 #include 
+#include 
 #endif
 
 /*
@@ -1047,6 +1048,9 @@ static int __init i8042_platform_init(void)
/* Just return if pre-detection shows no i8042 controller exist */
if (!x86_platform.i8042_detect())
return -ENODEV;
+
+   if (!(acpi_gbl_FADT.boot_flags & ACPI_FADT_8042))
+   return -ENODEV;
 #endif
 
 /*
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[tip:x86/cpu] x86/cpu: Add CLZERO detection

2015-11-01 Thread tip-bot for Wan Zongshun
Commit-ID:  2167ceabf34163727ca4e283c0f030e3960932e5
Gitweb: http://git.kernel.org/tip/2167ceabf34163727ca4e283c0f030e3960932e5
Author: Wan Zongshun 
AuthorDate: Fri, 30 Oct 2015 13:11:39 +0100
Committer:  Ingo Molnar 
CommitDate: Sun, 1 Nov 2015 11:26:23 +0100

x86/cpu: Add CLZERO detection

AMD Fam17h processors introduce support for the CLZERO
instruction. It zeroes out the 64 byte cache line specified in
RAX.

Add the bit here to allow /proc/cpuinfo to list the feature.

Boris: we're adding this as a separate ->x86_capability leaf
because CPUID_8008_EBX is going to contain more feature bits
and it will fill out with time.

Signed-off-by: Wan Zongshun 
Signed-off-by: Aravind Gopalakrishnan 
[ Wrap code in patch form, fix comments. ]
Signed-off-by: Borislav Petkov 
Cc: Andy Lutomirski 
Cc: Borislav Petkov 
Cc: Denys Vlasenko 
Cc: H. Peter Anvin 
Cc: Huang Rui 
Cc: Linus Torvalds 
Cc: Peter Zijlstra 
Cc: Thomas Gleixner 
Cc: Tony Luck 
Link: http://lkml.kernel.org/r/1446207099-24948-4-git-send-email...@alien8.de
Signed-off-by: Ingo Molnar 
---
 arch/x86/include/asm/cpufeature.h | 5 -
 arch/x86/kernel/cpu/common.c  | 1 +
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/cpufeature.h 
b/arch/x86/include/asm/cpufeature.h
index 9727b3b..e4f8010 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -12,7 +12,7 @@
 #include 
 #endif
 
-#define NCAPINTS   13  /* N 32-bit words worth of info */
+#define NCAPINTS   14  /* N 32-bit words worth of info */
 #define NBUGINTS   1   /* N 32-bit bug flags */
 
 /*
@@ -255,6 +255,9 @@
 /* Intel-defined CPU QoS Sub-leaf, CPUID level 0x000F:1 (edx), word 12 */
 #define X86_FEATURE_CQM_OCCUP_LLC (12*32+ 0) /* LLC occupancy monitoring if 1 
*/
 
+/* AMD-defined CPU features, CPUID level 0x8008 (ebx), word 13 */
+#define X86_FEATURE_CLZERO (13*32+0) /* CLZERO instruction */
+
 /*
  * BUG word(s)
  */
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index de22ea7..4ddd780 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -670,6 +670,7 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
 
c->x86_virt_bits = (eax >> 8) & 0xff;
c->x86_phys_bits = eax & 0xff;
+   c->x86_capability[13] = cpuid_ebx(0x8008);
}
 #ifdef CONFIG_X86_32
else if (cpu_has(c, X86_FEATURE_PAE) || cpu_has(c, X86_FEATURE_PSE36))
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] input: i8042: add quirk to implement i8042 detect for AMD

2015-10-16 Thread Wan ZongShun
2015-10-16 16:58 GMT+08:00 Borislav Petkov :
> On Fri, Oct 16, 2015 at 09:27:00AM -0400, Vincent Wan wrote:
>> Detecting platform supports i8042 or not, AMD resorted to
>> BIOS's FADT i8042 flag.
>>
>> Signed-off-by: Vincent Wan 
>> ---
>>  drivers/input/serio/i8042-x86ia64io.h | 6 ++
>>  1 file changed, 6 insertions(+)

>>  /*
>> @@ -1047,6 +1048,11 @@ static int __init i8042_platform_init(void)
>>   /* Just return if pre-detection shows no i8042 controller exist */
>>   if (!x86_platform.i8042_detect())
>>   return -ENODEV;
>> +
>> + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
>
> Why the vendor check if you're accessing a bit defined in the ACPI spec?

>From intel's 'x86_platform.i8042_detect' implementation, I doubt if
their BIOS is providing this i8024 flag.
So I have to implement my codes carefully.

>
>> + if (!(acpi_gbl_FADT.boot_flags & ACPI_FADT_8042))
>> +         return -ENODEV;
>> + }
>
> --
> Regards/Gruss,
> Boris.
>
> ECO tip #101: Trim your mails when you reply.



-- 
---
Vincent Wan(Zongshun)
www.mcuos.com
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 16/18] ARM/w90x900/time: Migrate to new 'set-state' interface

2015-07-24 Thread Wan ZongShun
2015-07-17 13:11 GMT+08:00 Viresh Kumar :
> Migrate w90x900 driver to the new 'set-state' interface provided by
> clockevents core, the earlier 'set-mode' interface is marked obsolete
> now.
>
> This also enables us to implement callbacks for new states of clockevent
> devices, for example: ONESHOT_STOPPED.
>
> Cc: Wan ZongShun 
> Signed-off-by: Viresh Kumar 
> ---
>  arch/arm/mach-w90x900/time.c | 51 
> 
>  1 file changed, 28 insertions(+), 23 deletions(-)
>
> diff --git a/arch/arm/mach-w90x900/time.c b/arch/arm/mach-w90x900/time.c
> index 9230d3725599..cd1966ec9143 100644
> --- a/arch/arm/mach-w90x900/time.c
> +++ b/arch/arm/mach-w90x900/time.c
> @@ -48,31 +48,32 @@
>
>  static unsigned int timer0_load;
>
> -static void nuc900_clockevent_setmode(enum clock_event_mode mode,
> -   struct clock_event_device *clk)
> +static int nuc900_clockevent_shutdown(struct clock_event_device *evt)
>  {
> -   unsigned int val;
> +   unsigned int val = __raw_readl(REG_TCSR0) & ~(0x03 << 27);
>
> -   val = __raw_readl(REG_TCSR0);
> -   val &= ~(0x03 << 27);
> +   __raw_writel(val, REG_TCSR0);
> +   return 0;
> +}
> +
> +static int nuc900_clockevent_set_oneshot(struct clock_event_device *evt)
> +{
> +   unsigned int val = __raw_readl(REG_TCSR0) & ~(0x03 << 27);
>
> -   switch (mode) {
> -   case CLOCK_EVT_MODE_PERIODIC:
> -   __raw_writel(timer0_load, REG_TICR0);
> -   val |= (PERIOD | COUNTEN | INTEN | PRESCALE);
> -   break;
> +   val |= (ONESHOT | COUNTEN | INTEN | PRESCALE);
>
> -   case CLOCK_EVT_MODE_ONESHOT:
> -   val |= (ONESHOT | COUNTEN | INTEN | PRESCALE);
> -   break;
> +   __raw_writel(val, REG_TCSR0);
> +   return 0;
> +}
>
> -   case CLOCK_EVT_MODE_UNUSED:
> -   case CLOCK_EVT_MODE_SHUTDOWN:
> -   case CLOCK_EVT_MODE_RESUME:
> -   break;
> -   }
> +static int nuc900_clockevent_set_periodic(struct clock_event_device *evt)
> +{
> +   unsigned int val = __raw_readl(REG_TCSR0) & ~(0x03 << 27);
>
> +   __raw_writel(timer0_load, REG_TICR0);
> +   val |= (PERIOD | COUNTEN | INTEN | PRESCALE);
> __raw_writel(val, REG_TCSR0);
> +   return 0;
>  }
>
>  static int nuc900_clockevent_setnextevent(unsigned long evt,
> @@ -90,11 +91,15 @@ static int nuc900_clockevent_setnextevent(unsigned long 
> evt,
>  }
>
>  static struct clock_event_device nuc900_clockevent_device = {
> -   .name   = "nuc900-timer0",
> -   .features   = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
> -   .set_mode   = nuc900_clockevent_setmode,
> -   .set_next_event = nuc900_clockevent_setnextevent,
> -   .rating = 300,
> +   .name   = "nuc900-timer0",
> +   .features   = CLOCK_EVT_FEAT_PERIODIC |
> + CLOCK_EVT_FEAT_ONESHOT,
> +   .set_state_shutdown = nuc900_clockevent_shutdown,
> +   .set_state_periodic = nuc900_clockevent_set_periodic,
> +   .set_state_oneshot  = nuc900_clockevent_set_oneshot,
> +   .tick_resume= nuc900_clockevent_shutdown,
> +   .set_next_event = nuc900_clockevent_setnextevent,
> +   .rating = 300,
>  };
>

Acked-by: Wan zongshun 

thanks!

>  /*IRQ handler for the timer*/
> --
> 2.4.0
>



-- 
---
Vincent Wan(Zongshun)
www.mcuos.com
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 01/15] ARM: kill off set_irq_flags usage

2015-06-13 Thread Wan ZongShun
2015-06-10 2:26 GMT+08:00 Rob Herring :
> set_irq_flags is ARM specific with custom flags which have genirq
> equivalents. Convert drivers to use the genirq interfaces directly, so we
> can kill off set_irq_flags. The translation of flags is as follows:
>
> IRQF_VALID -> !IRQ_NOREQUEST
> IRQF_PROBE -> !IRQ_NOPROBE
> IRQF_NOAUTOEN -> IRQ_NOAUTOEN
>
> For IRQs managed by an irqdomain, the irqdomain core code handles clearing
> and setting IRQ_NOREQUEST already, so there is no need to do this in
> .map() functions and we can simply remove the set_irq_flags calls. Some
> users also set IRQ_NOPROBE and this has been maintained although it is not
> clear that is really needed. There appears to be a great deal of blind
> Cc: Robert Jarzmik 
> Cc: Simtec Linux Team 
> Cc: Kukjin Kim 
> Cc: Krzysztof Kozlowski 
> Cc: Wan ZongShun 

For Nuvoton W90x900
Acked-by: Wan ZongShun 

> Cc: linux-arm-ker...@lists.infradead.org
> Cc: linux-o...@vger.kernel.org
> +++ b/arch/arm/mach-w90x900/irq.c
> @@ -211,6 +211,6 @@ void __init nuc900_init_irq(void)
> for (irqno = IRQ_WDT; irqno <= IRQ_ADC; irqno++) {
> irq_set_chip_and_handler(irqno, &nuc900_irq_chip,
>  handle_level_irq);
> -   set_irq_flags(irqno, IRQF_VALID);
> +   irq_clear_status_flags(irqno, IRQ_NOREQUEST);
> }
>  }
> --
> 2.1.0
>



-- 
---
Vincent Wan(Zongshun)
www.mcuos.com
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH V2 3/3] SDHCI: Change AMD SDHCI quirk application scope

2015-06-11 Thread Wan ZongShun
Change this quirk to apply to AMD Carrizo platform.

Signed-off-by: Wan ZongShun 

Tested-by: Nath, Arindam 
Tested-by: Ramesh, Ramya 
---
 drivers/mmc/host/sdhci-pci.c | 25 -
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index f208f20..94f54d2 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -724,14 +724,37 @@ static const struct sdhci_pci_fixes sdhci_rtsx = {
.probe_slot = rtsx_probe_slot,
 };
 
+/*AMD chipset generation*/
+enum amd_chipset_gen {
+   AMD_CHIPSET_BEFORE_ML,
+   AMD_CHIPSET_CZ,
+   AMD_CHIPSET_NL,
+   AMD_CHIPSET_UNKNOWN,
+};
+
 static int amd_probe(struct sdhci_pci_chip *chip)
 {
struct pci_dev  *smbus_dev;
+   enum amd_chipset_gen gen;
 
smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, NULL);
+   if (smbus_dev) {
+   gen = AMD_CHIPSET_BEFORE_ML;
+   } else {
+   smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
+   PCI_DEVICE_ID_AMD_KERNCZ_SMBUS, NULL);
+   if (smbus_dev) {
+   if (smbus_dev->revision < 0x51)
+   gen = AMD_CHIPSET_CZ;
+   else
+   gen = AMD_CHIPSET_NL;
+   } else {
+   gen = AMD_CHIPSET_UNKNOWN;
+   }
+   }
 
-   if (smbus_dev && (smbus_dev->revision < 0x51)) {
+   if ((gen == AMD_CHIPSET_BEFORE_ML) || (gen == AMD_CHIPSET_CZ)) {
chip->quirks2 |= SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD;
chip->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
}
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


  1   2   >