Re: [PATCH V2] ARM: NUC900: Add PCI driver support for NUC960

From: Marek Vasut
Date: Mon Nov 14 2011 - 06:44:45 EST


> Modify PCI driver for nuc960 per Russell's comments as following:
> (1)Use the common PCI swizzle API.
> (2)Use the pr_err insteading of prink.
> (3)Request the IO resource in ioport_resource tree.
>
> Signed-off-by: Wan ZongShun <mcuos.com@xxxxxxxxx>
>
> ---
> arch/arm/mach-w90x900/Kconfig | 1 +
> arch/arm/mach-w90x900/Makefile | 3 +
> arch/arm/mach-w90x900/include/mach/map.h | 4 +
> arch/arm/mach-w90x900/include/mach/regs-pci.h | 37 +++++
> arch/arm/mach-w90x900/nuc960.c | 2 +
> arch/arm/mach-w90x900/pci.c | 195
> +++++++++++++++++++++++++
> 6 files changed, 242 insertions(+), 0 deletions(-)
> create mode 100644 arch/arm/mach-w90x900/include/mach/regs-pci.h
> create mode 100644 arch/arm/mach-w90x900/pci.c
>
> diff --git a/arch/arm/mach-w90x900/Kconfig b/arch/arm/mach-w90x900/Kconfig
> index 69bab32..17be262 100644
> --- a/arch/arm/mach-w90x900/Kconfig
> +++ b/arch/arm/mach-w90x900/Kconfig
> @@ -41,6 +41,7 @@ menu "NUC960 Machines"
> config MACH_W90N960EVB
> bool "Nuvoton NUC960 Evaluation Board"
> select CPU_NUC960
> + select PCI
> help
> Say Y here if you are using the Nuvoton NUC960EVB
>
> diff --git a/arch/arm/mach-w90x900/Makefile
> b/arch/arm/mach-w90x900/Makefile index 828c032..0c35800 100644
> --- a/arch/arm/mach-w90x900/Makefile
> +++ b/arch/arm/mach-w90x900/Makefile
> @@ -17,3 +17,6 @@ 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
> +
> +# Add pci support for nuc960, nuc920
> +obj-$(CONFIG_PCI) += pci.o
> diff --git a/arch/arm/mach-w90x900/include/mach/map.h
> b/arch/arm/mach-w90x900/include/mach/map.h
> index 1a20953..69f6c73 100644
> --- a/arch/arm/mach-w90x900/include/mach/map.h
> +++ b/arch/arm/mach-w90x900/include/mach/map.h
> @@ -154,4 +154,8 @@
> #define W90X900_PA_EMC (0xB0003000)
> #define W90X900_SZ_EMC SZ_4K
>
> +/* PCI interface controller */
> +#define W90X900_VA_PCI W90X900_ADDR(0x00002000)
> +#define W90X900_PA_PCI (0xB0002000)
> +#define W90X900_SZ_PCI SZ_4K
> #endif /* __ASM_ARCH_MAP_H */
> diff --git a/arch/arm/mach-w90x900/include/mach/regs-pci.h
> b/arch/arm/mach-w90x900/include/mach/regs-pci.h
> new file mode 100644
> index 0000000..d1975eb
> --- /dev/null
> +++ b/arch/arm/mach-w90x900/include/mach/regs-pci.h
> @@ -0,0 +1,37 @@
> +/*
> + * arch/arm/mach-w90x900/include/mach/regs-pci.h
> + *
> + * Copyright (c) 2011 Nuvoton technology corporation.
> + *
> + * Wan ZongShun <mcuos.com@xxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation;version 2 of the License.
> + *
> + */
> +
> +#ifndef __ASM_ARCH_REGS_PCI_H
> +#define __ASM_ARCH_REGS_PCI_H
> +
> +#define PCI_BA W90X900_VA_PCI /* PCI Control */
> +/* PCI Control Registers */
> +#define REG_PCICTR (PCI_BA + 0x000)
> +#define REG_PCISTR (PCI_BA + 0x004)
> +#define REG_PCILATIMER (PCI_BA + 0x008)
> +#define REG_PCIINTEN (PCI_BA + 0x010)
> +#define REG_PCIINT (PCI_BA + 0x014)
> +#define REG_CFGADDR (PCI_BA + 0x020)
> +#define REG_CFGDATA (PCI_BA + 0x024)
> +#define REG_PCIARB (PCI_BA + 0x04C)
> +#define REG_PCIBIST (PCI_BA + 0x050)
> +
> +#define NUC900_PCI_IO_BASE 0xE0000000
> +#define NUC900_PCI_IO_END 0xE000FFFF
> +#define NUC900_PCI_IO_SIZE 0x10000
> +
> +#define NUC900_PCI_MEM_BASE 0xC0000000
> +#define NUC900_PCI_MEM_END 0xDFFFEFFFF
> +#define NUC900_PCI_MEM_SIZE 0x20000000
> +
> +#endif /* ___ASM_ARCH_REGS_PCI_H */
> diff --git a/arch/arm/mach-w90x900/nuc960.c
> b/arch/arm/mach-w90x900/nuc960.c index 8851a3a..0212964 100644
> --- a/arch/arm/mach-w90x900/nuc960.c
> +++ b/arch/arm/mach-w90x900/nuc960.c
> @@ -19,6 +19,7 @@
> #include <asm/mach/map.h>
> #include <mach/hardware.h>
> #include "cpu.h"
> +#include "clock.h"
>
> /* define specific CPU platform device */
>
> @@ -30,6 +31,7 @@ static struct platform_device *nuc960_dev[] __initdata =
> { /* define specific CPU platform io map */
>
> static struct map_desc nuc960evb_iodesc[] __initdata = {
> + IODESC_ENT(PCI),
> };
>
> /*Init NUC960 evb io*/
> diff --git a/arch/arm/mach-w90x900/pci.c b/arch/arm/mach-w90x900/pci.c
> new file mode 100644
> index 0000000..74095b0
> --- /dev/null
> +++ b/arch/arm/mach-w90x900/pci.c
> @@ -0,0 +1,195 @@
> +/*
> + * linux/arch/arm/mach-w90x900/pci.c
> + *
> + * Copyright (c) 2008 Nuvoton technology corporation.
> + *
> + * Wan ZongShun <mcuos.com@xxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation;version 2 of the License.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/pci.h>
> +#include <linux/ioport.h>
> +#include <linux/interrupt.h>
> +#include <linux/spinlock.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/delay.h>
> +
> +#include <mach/hardware.h>
> +#include <asm/irq.h>
> +#include <asm/system.h>
> +#include <asm/mach/pci.h>
> +
> +#include <mach/regs-pci.h>
> +#include <mach/regs-clock.h>
> +#include <mach/regs-gcr.h>
> +
> +#define EXTAL15M (0x03 << 2)
> +#define CK33DIV5 (0x05 << 4)
> +#define RESET_VAL1 0x20C0
> +#define RESET_VAL2 0x20CF
> +
> +static int nuc900_read_config(struct pci_bus *bus, unsigned int devfn,
> + int where, int size, unsigned int *val)
> +{
> + unsigned int v;
> +
> + __raw_writel(devfn * 0x100 + (where & 0xfffffffc), REG_CFGADDR);
> + v = __raw_readl(REG_CFGDATA);
> + switch (size) {
> + case 1:
> + *val = (v >> ((where % 4) * 8)) & 0xff;
> + break;
> + case 2:
> + *val = (v >> ((where % 4) * 8)) & 0xffff;
> + break;
> + default:

case 4 ? Default case should error out.

> + *val = v;
> + break;
> + }
> +
> + return PCIBIOS_SUCCESSFUL;
> +}
> +
> +
> +static int nuc900_write_config(struct pci_bus *bus, unsigned int devfn,
> + int where, int size, unsigned int val)
> +{
> + unsigned int v;
> +
> + __raw_writel(devfn * 0x100 + where, REG_CFGADDR);
> +
> + v = __raw_readl(REG_CFGDATA);
> +
> + __raw_writel(devfn * 0x100 + where, REG_CFGADDR);
> +
> + switch (size) {
> + case 1:
> + v &= ~(0xff << (where % 4) * 8);
> + v |= (val << (where % 4) * 8);
> + __raw_writel(val, REG_CFGDATA);
> + break;
> + case 2:
> + v &= ~(0xffff << (where % 4) * 8);
> + v |= (val << (where % 4) * 8);
> + __raw_writel(val, REG_CFGDATA);
> + break;
> + case 4:
> + __raw_writel(val, REG_CFGDATA);
> + break;
> + }
> + return PCIBIOS_SUCCESSFUL;
> +}
> +
> +static struct pci_ops pci_nuc900_ops = {
> + .read = nuc900_read_config,
> + .write = nuc900_write_config,
> +};
> +
> +static struct resource pci_io = {
> + .name = "NUC900 PCI IO",
> + .start = NUC900_PCI_IO_BASE,
> + .end = NUC900_PCI_IO_BASE + NUC900_PCI_IO_SIZE - 1,
> + .flags = IORESOURCE_IO,
> +};
> +
> +static struct resource pci_mem = {
> + .name = "nuc900 PCI Memory",
> + .start = NUC900_PCI_MEM_BASE,
> + .end = NUC900_PCI_MEM_BASE + NUC900_PCI_MEM_SIZE - 1,
> + .flags = IORESOURCE_MEM,
> +};
> +
> +static int __init pci_nuc900_setup_resources(struct resource **resource)
> +{
> + int ret = 0;
> +
> + ret = request_resource(&ioport_resource, &pci_io);
> + if (ret) {
> + pr_err("%s: failed to request resources: %d\n", __func__, ret);
> + goto out;
> + }

newline

> + ret = request_resource(&iomem_resource, &pci_mem);
> + if (ret) {
> + pr_err("%s: failed to request resources: %d\n", __func__, ret);
> + goto release_io_mem;
> + }
> +
> + /*
> + * bus->resource[0] is the IO resource for this bus
> + * bus->resource[1] is the mem resource for this bus
> + * bus->resource[2] is the prefetch mem resource for this bus
> + */
> + resource[0] = &pci_io;
> + resource[1] = &pci_mem;
> + resource[2] = NULL;
> +
> + goto out;
> +
> + release_io_mem:
> + release_resource(&pci_io);
> + out:
> + return ret;
> +}
> +
> +int __init pci_nuc900_setup(int nr, struct pci_sys_data *sys)
> +{
> + int ret = 0;
> +
> + if (nr > 0)
> + return 0;

pr_err() missing in this if ?

> +
> + sys->mem_offset = 0;
> + sys->io_offset = 0;
> + ret = pci_nuc900_setup_resources(sys->resource);
> + if (ret)
> + pr_err("%s: failed to setup resources: %d\n", __func__, ret);
> +
> + return !ret;
> +}
> +
> +struct pci_bus *pci_nuc900_scan_bus(int nr, struct pci_sys_data *sys)
> +{
> + return pci_scan_bus(sys->busnr, &pci_nuc900_ops, sys);
> +}
> +
> +void __init pci_nuc900_preinit(void)
> +{
> + /* CK33 from PLL0 */
> + __raw_writel(__raw_readl(REG_CLKSEL) & ~EXTAL15M, REG_CLKSEL);
> + /* PCI CLOCK = 200/6 = 33Mhz */
> + __raw_writel(((__raw_readl(REG_CLKDIV) &
> + (~(0xf<<4))) | CK33DIV5), REG_CLKDIV);
> +
> + /* enable PCI clock */
> + __raw_writel(__raw_readl(REG_CLKEN) | 0x4, REG_CLKEN);

What's this magic 0x4?

> +
> + __raw_writel(RESET_VAL1, REG_PCICTR);
> +
> + mdelay(100);
> +
> + __raw_writel(RESET_VAL2, REG_PCICTR);
> +
> + mdelay(200);
> +}
> +
> +static struct hw_pci nuc900_pci __initdata = {
> + .swizzle = pci_std_swizzle,
> + .setup = pci_nuc900_setup,
> + .nr_controllers = 1,
> + .scan = pci_nuc900_scan_bus,
> + .preinit = pci_nuc900_preinit,
> +};
> +
> +static int __init nuc900_pci_init(void)
> +{
> + pci_common_init(&nuc900_pci);
> + return 0;
> +}
> +
> +subsys_initcall(nuc900_pci_init);

Reviewed-by: Marek Vasut <marek.vasut@xxxxxxxxx>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/