Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1435986 > unrolled thread

[PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree

Started byYoshinori Sato <ysato@users.sourceforge.jp>
First post2016-07-03 18:50 +0200
Last post2016-07-03 19:00 +0200
Articles 20 on this page of 32 — 4 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-03 18:50 +0200
    [PATCH v5 13/22] sh: irqchip: SH7751 IRQCHIP Driver Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-03 18:50 +0200
    [PATCH v5 11/22] sh: SH7750/51 CPG Driver Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-03 18:50 +0200
    [PATCH v5 04/22] sh: Use P1SEGADDR Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-03 18:50 +0200
      Re: [PATCH v5 04/22] sh: Use P1SEGADDR Rich Felker <dalias@libc.org> - 2016-07-04 03:50 +0200
        Re: [PATCH v5 04/22] sh: Use P1SEGADDR Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-06 16:20 +0200
          Re: [PATCH v5 04/22] sh: Use P1SEGADDR Rich Felker <dalias@libc.org> - 2016-07-06 17:00 +0200
    [PATCH v6 12/22] sh: Add PCI host bridge driver for SH7751 Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-03 18:50 +0200
      Re: [PATCH v6 12/22] sh: Add PCI host bridge driver for SH7751 Rob Herring <robh@kernel.org> - 2016-07-05 18:00 +0200
        Re: [PATCH v6 12/22] sh: Add PCI host bridge driver for SH7751 Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-06 18:20 +0200
    [PATCH v5 10/22] sh: Add board specific initialize of of-generic Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-03 18:50 +0200
      Re: [PATCH v5 10/22] sh: Add board specific initialize of of-generic Rich Felker <dalias@libc.org> - 2016-07-04 03:40 +0200
        Re: [PATCH v5 10/22] sh: Add board specific initialize of of-generic Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-06 16:30 +0200
    [PATCH v5 08/22] sh: Disable board specific code on device tree mode Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-03 18:50 +0200
    [PATCH v5 15/22] sh: Move common PCI stuff to arch/sh/kernel Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-03 18:50 +0200
      Re: [PATCH v5 15/22] sh: Move common PCI stuff to arch/sh/kernel Rich Felker <dalias@libc.org> - 2016-07-04 04:00 +0200
        Re: [PATCH v5 15/22] sh: Move common PCI stuff to arch/sh/kernel Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-06 18:20 +0200
    [PATCH v5 09/22] sh: Use GENERIC_IOMAP on device tree mode Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-03 18:50 +0200
    [PATCH v5 05/22] sh: command line passing chosen/bootargs in devicetree Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-03 19:00 +0200
    [PATCH v5 03/22] sh: set preset_lpj Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-03 19:00 +0200
    [PATCH v5 17/22] pci: PCI_HOST_GENERIC enable for SH Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-03 19:00 +0200
    [PATCH v5 01/22] sh: Add sh-specific early_init_dt_reserve_memory_arch Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-03 19:00 +0200
      Re: [PATCH v5 01/22] sh: Add sh-specific  early_init_dt_reserve_memory_arch Rich Felker <dalias@libc.org> - 2016-07-04 04:10 +0200
        Re: [PATCH v5 01/22] sh: Add sh-specific early_init_dt_reserve_memory_arch Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-06 16:00 +0200
          Re: [PATCH v5 01/22] sh: Add sh-specific  early_init_dt_reserve_memory_arch Rich Felker <dalias@libc.org> - 2016-07-06 17:00 +0200
    [PATCH v5 14/22] sh: SH7751 core dtsi Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-03 19:00 +0200
    [PATCH v5 06/22] sh: FDT address save before bank change Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-03 19:00 +0200
    [PATCH v5 20/22] sh: IO-DATA HDL-U (a.k.a landisk) DeviceTree Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-03 19:00 +0200
      Re: [PATCH v5 20/22] sh: IO-DATA HDL-U (a.k.a landisk) DeviceTree Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> - 2016-07-03 21:10 +0200
        Re: [PATCH v5 20/22] sh: IO-DATA HDL-U (a.k.a landisk) DeviceTree Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-06 18:20 +0200
    [PATCH v5 22/22] sh: Renesas RTS7751R2Dplus (a,k.a R2Dplus) DeviceTree Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-03 19:00 +0200
    [PATCH v5 18/22] sh: Add separate DTB build rule Yoshinori Sato <ysato@users.sourceforge.jp> - 2016-07-03 19:00 +0200

Page 1 of 2  [1] 2  Next page →


#1435986 — [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree

FromYoshinori Sato <ysato@users.sourceforge.jp>
Date2016-07-03 18:50 +0200
Subject[PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree
Message-ID<rQSKJ-2yo-3@gated-at.bofh.it>
SH get devicetree support. But it not working on existing H/W.

IO-DATA HDL-U (aka landisk) currentry supported.
This H/W like SH7751 evalution board. It's a best to use this as a
change base H/W.
RTS7751R2Dplus is QEMU-SH4 target. So easy trying.

Changes V5
- added "#address-cells" before interrupt-map
- remove interrupt-controller of landisk.dts and r2dplus.dts
- Add ".suppress_bind_attrs" to pci driver.
- some cleanup.

Changes V4
- split board depend patch.
- dts cleanup.

Changes V3
- PCI driver update for v4.7.
- New Clock driver. Unified PLL/Divider.
- R2Dplus support.
- Split DTS.
- Some cleanup.

Changes V2
- split DeviceTree suppoty update.
- PCI driver update.
- Some cleanup.

Yoshinori Sato (22):
  sh: Add sh-specific early_init_dt_reserve_memory_arch
  sh: More early unflatten device tree
  sh: set preset_lpj
  sh: Use P1SEGADDR
  sh: command line passing chosen/bootargs in devicetree
  sh: FDT address save before bank change
  sh: Passing FDT address on zImage
  sh: Disable board specific code on device tree mode
  sh: Use GENERIC_IOMAP on device tree mode
  sh: Add board specific initialize of of-generic
  sh: SH7750/51 CPG Driver
  sh: Add PCI host bridge driver for SH7751
  sh: irqchip: SH7751 IRQCHIP Driver
  sh: SH7751 core dtsi
  sh: Move common PCI stuff to arch/sh/kernel
  pci: pci_config_window move to linux/pci.h
  pci: PCI_HOST_GENERIC enable for SH
  sh: Add separate DTB build rule
  sh: IO-DATA HDL-U (a,k.a landisk) IRQCHIP driver
  sh: IO-DATA HDL-U (a,k.a landisk) DeviceTree
  sh: Renesas RTS7751R2Dplus (a,k.a R2Dplus) IRQCHIP Driver
  sh: Renesas RTS7751R2Dplus (a,k.a R2Dplus) DeviceTree

 .../bindings/clock/renesas,sh7750-cpg.txt          |  25 ++
 .../interrupt-controller/iodata-landisk.txt        |  31 ++
 .../interrupt-controller/renesas,sh7751-intc.txt   |  25 ++
 .../interrupt-controller/renesas-r2dplus.txt       |  38 +++
 .../devicetree/bindings/pci/sh7751-pci.txt         |  37 +++
 arch/sh/Kconfig                                    |   6 +-
 arch/sh/Makefile                                   |   9 +
 arch/sh/boards/Kconfig                             |   4 +
 arch/sh/boards/of-generic.c                        |  88 +++++-
 arch/sh/boot/compressed/head_32.S                  |   5 +-
 arch/sh/boot/dts/Makefile                          |   5 +
 arch/sh/boot/dts/include/dt-bindings               |   1 +
 arch/sh/boot/dts/landisk.dts                       |  61 ++++
 arch/sh/boot/dts/r2dplus.dts                       |  85 +++++
 arch/sh/boot/dts/sh7751.dtsi                       |  83 +++++
 arch/sh/drivers/Makefile                           |   2 +
 arch/sh/drivers/pci/Makefile                       |   2 -
 arch/sh/drivers/pci/common.c                       | 162 ----------
 arch/sh/drivers/pci/pci.c                          | 320 -------------------
 arch/sh/include/asm/io.h                           |   6 +
 arch/sh/kernel/Makefile                            |   2 +
 arch/sh/kernel/cpu/Makefile                        |   8 +-
 arch/sh/kernel/cpu/clock.c                         |   6 +-
 arch/sh/kernel/cpu/sh4/Makefile                    |   2 +
 arch/sh/kernel/head_32.S                           |   7 +-
 arch/sh/kernel/pci-common.c                        | 162 ++++++++++
 arch/sh/kernel/pci.c                               | 342 ++++++++++++++++++++
 arch/sh/kernel/setup.c                             |  15 +-
 drivers/clk/Kconfig                                |   1 +
 drivers/clk/Makefile                               |   3 +-
 drivers/clk/sh/Kconfig                             |   2 +
 drivers/clk/sh/Makefile                            |   1 +
 drivers/clk/sh/clk-sh7750cpg.c                     | 344 +++++++++++++++++++++
 drivers/irqchip/Kconfig                            |   5 +
 drivers/irqchip/Makefile                           |   1 +
 drivers/irqchip/irq-io-landisk.c                   |  72 +++++
 drivers/irqchip/irq-renesas-r2dplus.c              |  88 ++++++
 drivers/irqchip/irq-renesas-sh7751.c               | 141 +++++++++
 drivers/pci/ecam.h                                 |  17 +-
 drivers/pci/host/Kconfig                           |   9 +-
 drivers/pci/host/Makefile                          |   1 +
 drivers/pci/host/pci-sh7751.c                      | 326 +++++++++++++++++++
 include/dt-bindings/clock/renesas-sh7750.h         |  26 ++
 include/dt-bindings/interrupt-controller/sh_intc.h |   2 +
 include/linux/pci.h                                |  18 ++
 45 files changed, 2075 insertions(+), 521 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/renesas,sh7750-cpg.txt
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/iodata-landisk.txt
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/renesas,sh7751-intc.txt
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/renesas-r2dplus.txt
 create mode 100644 Documentation/devicetree/bindings/pci/sh7751-pci.txt
 create mode 120000 arch/sh/boot/dts/include/dt-bindings
 create mode 100644 arch/sh/boot/dts/landisk.dts
 create mode 100644 arch/sh/boot/dts/r2dplus.dts
 create mode 100644 arch/sh/boot/dts/sh7751.dtsi
 delete mode 100644 arch/sh/drivers/pci/common.c
 delete mode 100644 arch/sh/drivers/pci/pci.c
 create mode 100644 arch/sh/kernel/pci-common.c
 create mode 100644 arch/sh/kernel/pci.c
 create mode 100644 drivers/clk/sh/Kconfig
 create mode 100644 drivers/clk/sh/Makefile
 create mode 100644 drivers/clk/sh/clk-sh7750cpg.c
 create mode 100644 drivers/irqchip/irq-io-landisk.c
 create mode 100644 drivers/irqchip/irq-renesas-r2dplus.c
 create mode 100644 drivers/irqchip/irq-renesas-sh7751.c
 create mode 100644 drivers/pci/host/pci-sh7751.c
 create mode 100644 include/dt-bindings/clock/renesas-sh7750.h
 create mode 100644 include/dt-bindings/interrupt-controller/sh_intc.h

-- 
2.7.0

[toc] | [next] | [standalone]


#1435987 — [PATCH v5 13/22] sh: irqchip: SH7751 IRQCHIP Driver

FromYoshinori Sato <ysato@users.sourceforge.jp>
Date2016-07-03 18:50 +0200
Subject[PATCH v5 13/22] sh: irqchip: SH7751 IRQCHIP Driver
Message-ID<rQSKJ-2yo-23@gated-at.bofh.it>
In reply to#1435986
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
Acked-by: Rob Herring <robh@kernel.org>
---
 .../interrupt-controller/renesas,sh7751-intc.txt   |  25 ++++
 arch/sh/Kconfig                                    |   6 +-
 arch/sh/boards/Kconfig                             |   1 +
 drivers/irqchip/Kconfig                            |   5 +
 drivers/irqchip/Makefile                           |   1 +
 drivers/irqchip/irq-renesas-sh7751.c               | 141 +++++++++++++++++++++
 6 files changed, 176 insertions(+), 3 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/renesas,sh7751-intc.txt
 create mode 100644 drivers/irqchip/irq-renesas-sh7751.c

diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,sh7751-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,sh7751-intc.txt
new file mode 100644
index 0000000..2bc6f22f
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,sh7751-intc.txt
@@ -0,0 +1,25 @@
+DT bindings for the SH7751 interrupt controller
+
+Required properties:
+
+  - compatible: has to be "renesas,sh7751-intc".
+
+  - reg: Base address and length of interrupt controller register
+         and extend register.
+
+  - interrupt-controller: Identifies the node as an interrupt controller.
+
+  - #interrupt-cells: has to be <2>: an interrupt index and flags, as defined
+    in interrupts.txt in this directory.
+
+Example
+-------
+
+	shintc: interrupt-controller@ffd00000 {
+		compatible = "renesas,sh7751-intc";
+		#interrupt-cells = <2>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		interrupt-controller;
+		reg = <0xffd00000 14>, <0xfe080000 128>;
+	};
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index d06cac1..fee4333 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -29,7 +29,7 @@ config SUPERH
 	select ARCH_WANT_IPC_PARSE_VERSION
 	select HAVE_SYSCALL_TRACEPOINTS
 	select HAVE_REGS_AND_STACK_ACCESS_API
-	select MAY_HAVE_SPARSE_IRQ
+	select MAY_HAVE_SPARSE_IRQ if !SH_DEVICE_TREE
 	select IRQ_FORCED_THREADING
 	select RTC_LIB
 	select GENERIC_ATOMIC64
@@ -69,7 +69,7 @@ config SUPERH32
 	select HAVE_MIXED_BREAKPOINTS_REGS
 	select PERF_EVENTS
 	select ARCH_HIBERNATION_POSSIBLE if MMU
-	select SPARSE_IRQ
+	select SPARSE_IRQ if !SH_DEVICE_TREE
 	select HAVE_CC_STACKPROTECTOR
 
 config SUPERH64
@@ -863,7 +863,7 @@ config PCI
 	depends on SYS_SUPPORTS_PCI
 	select PCI_DOMAINS
 	select GENERIC_PCI_IOMAP
-	select NO_GENERIC_PCI_IOPORT_MAP
+	select NO_GENERIC_PCI_IOPORT_MAP if !SH_DEVICE_TREE
 	help
 	  Find out whether you have a PCI motherboard. PCI is the name of a
 	  bus system, i.e. the way the CPU talks to the other stuff inside
diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig
index cfde921..d33ae46 100644
--- a/arch/sh/boards/Kconfig
+++ b/arch/sh/boards/Kconfig
@@ -15,6 +15,7 @@ config SH_DEVICE_TREE
 	select GENERIC_IOMAP
 	select COMMON_CLK
 	select SYS_SUPPORTS_PCI
+	select GENERIC_IRQ_CHIP
 	help
 	  Select Board Described by Device Tree to build a kernel that
 	  does not hard-code any board-specific knowledge but instead uses
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index fa33c50..fd7f842 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -251,6 +251,11 @@ config LS_SCFG_MSI
 	depends on PCI && PCI_MSI
 	select PCI_MSI_IRQ_DOMAIN
 
+config RENESAS_SH_INTC
+	def_bool y if SH_DEVICE_TREE
+	select IRQ_DOMAIN
+	select IRQ_DOMAIN_HIERARCHY
+
 config PARTITION_PERCPU
 	bool
 
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 38853a1..2ab5735 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_RENESAS_SH_INTC)		+= irq-renesas-sh7751.o
diff --git a/drivers/irqchip/irq-renesas-sh7751.c b/drivers/irqchip/irq-renesas-sh7751.c
new file mode 100644
index 0000000..1710978
--- /dev/null
+++ b/drivers/irqchip/irq-renesas-sh7751.c
@@ -0,0 +1,141 @@
+/*
+ * SH7751 interrupt contoller driver
+ *
+ * Copyright 2016 Yoshinori Sato <ysato@users.sourceforge.jp>
+ */
+
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of.h>
+#include <linux/io.h>
+
+static struct sh7751_intc_regs {
+	void *icr;
+	void *ipr;
+	void *intpri00;
+	void *intreq00;
+	void *intmsk00;
+	void *intmskclr00;
+} sh7751_regs;
+
+static const unsigned int ipr_table[] = {
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0 - 7 */
+	0x41, 0xff, 0xff, 0x40, 0xff, 0xff, 0xff, 0xff, /* 8 - 15 */
+	0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x11, /* 16 - 23 */
+	0x11, 0x11, 0x11, 0x13, 0x12, 0x12, 0xff, 0xff, /* 24 - 31 */
+	0x30, 0x33, 0x32, 0x32, 0x32, 0x32, 0x32, 0x21, /* 32 - 39 */
+	0x21, 0x21, 0x21, 0x21, 0x32, 0x32, 0x32, 0x32, /* 40 - 47 */
+	0xff, 0xff, 0xff, 0x40, 0xff, 0xff, 0xff, 0xff, /* 48 - 55 */
+	0xff, 0xff, 0xff, 0x40, 0xff, 0xff, 0xff, 0xff, /* 56 - 63 */
+};
+
+static const unsigned int pri_table[] = {
+	0, 4, 4, 4, 4, 4, 4, 4,
+	8, 32, 32, 32, 12, 32, 32, 32,
+};
+
+static void sh_disable_irq(struct irq_data *data)
+{
+	int pos;
+	unsigned int addr;
+	unsigned long pri;
+	int irq = data->irq;
+	struct sh7751_intc_regs *reg = data->chip_data;
+
+	if (irq < 64) {
+		if (ipr_table[irq] != 0xff) {
+			addr = (ipr_table[irq] & 0xf0) >> 2;
+			pos = (ipr_table[irq] & 0x0f) << 4;
+			pri = ~(0x000f << pos);
+			pri &= __raw_readw(reg->ipr + addr);
+			__raw_writew(pri, reg->ipr + addr);
+		}
+	} else {
+		if (pri_table[irq - 64] < 32) {
+			pos = pri_table[irq - 64];
+			pri = ~(0x000f << pos);
+			pri &= __raw_readw(reg->intpri00);
+			__raw_writew(pri, reg->intpri00);
+		}
+	}
+}
+
+static void sh_enable_irq(struct irq_data *data)
+{
+	int pos;
+	unsigned int addr;
+	unsigned long pri;
+	int irq = data->irq;
+	struct sh7751_intc_regs *reg = data->chip_data;
+
+	if (irq < 64) {
+		if (ipr_table[irq] != 0xff) {
+			addr = (ipr_table[irq] & 0xf0) >> 2;
+			pos = (ipr_table[irq] & 0x0f) * 4;
+			pri = ~(0x000f << pos);
+			pri &= __raw_readw(reg->ipr + addr);
+			pri |= 1 << pos;
+			__raw_writew(pri, reg->ipr + addr);
+		}
+	} else {
+		if (pri_table[irq - 64] < 32) {
+			pos = pri_table[irq - 64];
+			pri = ~(0x000f << pos);
+			pri &= __raw_readw(reg->intpri00);
+			pri |= 1 << pos;
+			__raw_writew(pri, reg->intpri00);
+		}
+	}
+}
+
+static struct irq_chip sh_irq_chip = {
+	.name		= "SH-IPR",
+	.irq_unmask	= sh_enable_irq,
+	.irq_mask	= sh_disable_irq,
+};
+
+static __init int irq_map(struct irq_domain *h, unsigned int virq,
+			  irq_hw_number_t hw_irq_num)
+{
+	irq_set_chip_and_handler(virq, &sh_irq_chip, handle_level_irq);
+	irq_get_irq_data(virq)->chip_data = h->host_data;
+	irq_modify_status(virq, IRQ_NOREQUEST, IRQ_NOPROBE);
+
+	return 0;
+}
+
+static struct irq_domain_ops irq_ops = {
+	.map    = irq_map,
+	.xlate  = irq_domain_xlate_onecell,
+};
+
+static int __init sh_intc_7751_init(struct device_node *intc,
+				    struct device_node *parent)
+{
+	struct irq_domain *domain;
+	void *intc_baseaddr;
+	void *intc_baseaddr2;
+
+	intc_baseaddr = of_iomap(intc, 0);
+	intc_baseaddr2 = of_iomap(intc, 1);
+	if (!intc_baseaddr || !intc_baseaddr2)
+		panic("INTC regsiter not defined");
+
+	sh7751_regs.icr = intc_baseaddr;
+	sh7751_regs.ipr = intc_baseaddr + 4;
+	sh7751_regs.intpri00 = intc_baseaddr2;
+	sh7751_regs.intreq00 = intc_baseaddr2 + 0x20;
+	sh7751_regs.intmsk00 = intc_baseaddr2 + 0x40;
+	sh7751_regs.intmskclr00 = intc_baseaddr2 + 0x60;
+
+	domain = irq_domain_add_linear(intc, NR_IRQS, &irq_ops, &sh7751_regs);
+	if (!domain)
+		panic("%s: unable to create IRQ domain\n", intc->full_name);
+
+	irq_set_default_host(domain);
+	return 0;
+}
+
+IRQCHIP_DECLARE(sh_7751_intc, "renesas,sh7751-intc", sh_intc_7751_init);
-- 
2.7.0

[toc] | [prev] | [next] | [standalone]


#1435988 — [PATCH v5 11/22] sh: SH7750/51 CPG Driver

FromYoshinori Sato <ysato@users.sourceforge.jp>
Date2016-07-03 18:50 +0200
Subject[PATCH v5 11/22] sh: SH7750/51 CPG Driver
Message-ID<rQSKJ-2yo-15@gated-at.bofh.it>
In reply to#1435986
Convert SH specific clock framework to CCF.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
Acked-by: Rob Herring <robh@kernel.org>
---
 .../bindings/clock/renesas,sh7750-cpg.txt          |  25 ++
 arch/sh/boards/Kconfig                             |   1 +
 arch/sh/kernel/cpu/Makefile                        |   8 +-
 arch/sh/kernel/cpu/clock.c                         |   6 +-
 drivers/clk/Kconfig                                |   1 +
 drivers/clk/Makefile                               |   3 +-
 drivers/clk/sh/Kconfig                             |   2 +
 drivers/clk/sh/Makefile                            |   1 +
 drivers/clk/sh/clk-sh7750cpg.c                     | 344 +++++++++++++++++++++
 9 files changed, 387 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/renesas,sh7750-cpg.txt
 create mode 100644 drivers/clk/sh/Kconfig
 create mode 100644 drivers/clk/sh/Makefile
 create mode 100644 drivers/clk/sh/clk-sh7750cpg.c

diff --git a/Documentation/devicetree/bindings/clock/renesas,sh7750-cpg.txt b/Documentation/devicetree/bindings/clock/renesas,sh7750-cpg.txt
new file mode 100644
index 0000000..e763e2c
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/renesas,sh7750-cpg.txt
@@ -0,0 +1,25 @@
+* Renesas SH7750/51 CPG
+
+Required Properties:
+
+  - compatible: Must be "renesas,sh7750-cpg"
+
+  - clocks: Reference to the parent clocks (xtal or external)
+
+  - #clock-cells: Must be 1
+
+  - reg: Base address and length of the FREQCR
+         and Base address and length of the CLKSTP00 (optional)
+
+  - renesas,mult: PLL1 multiply rate
+
+Example
+-------
+
+        cpg: cpg@ffc00000 {
+                compatible = "renesas,sh7750-cpg";
+                clocks = <&oclk>;
+                #clock-cells = <1>;
+                renesas,mult = <12>;
+                reg = <0xffc00000 32>, <0xfe0a0000 16>;
+        };
diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig
index 9e4ccd0..b6ff9df 100644
--- a/arch/sh/boards/Kconfig
+++ b/arch/sh/boards/Kconfig
@@ -13,6 +13,7 @@ config SH_DEVICE_TREE
 	select CLKSRC_OF
 	select GENERIC_CALIBRATE_DELAY
 	select GENERIC_IOMAP
+	select COMMON_CLK
 	help
 	  Select Board Described by Device Tree to build a kernel that
 	  does not hard-code any board-specific knowledge but instead uses
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
index accc7ca..22ad0ee 100644
--- a/arch/sh/kernel/cpu/Makefile
+++ b/arch/sh/kernel/cpu/Makefile
@@ -16,6 +16,10 @@ obj-$(CONFIG_ARCH_SHMOBILE)	+= shmobile/
 # Common interfaces.
 
 obj-$(CONFIG_SH_ADC)		+= adc.o
+ifndef CONFIG_COMMON_CLK
 obj-$(CONFIG_SH_CLK_CPG_LEGACY)	+= clock-cpg.o
-
-obj-y	+= irq/ init.o clock.o fpu.o pfc.o proc.o
+endif
+ifndef CONFIG_GENERIC_IRQ_CHIP
+obj-y	+= irq/
+endif
+obj-y	+= init.o clock.o fpu.o pfc.o proc.o
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c
index 4187cf4..8e66e23 100644
--- a/arch/sh/kernel/cpu/clock.c
+++ b/arch/sh/kernel/cpu/clock.c
@@ -22,13 +22,15 @@
 
 int __init clk_init(void)
 {
-	int ret;
+	int ret = 0;
 
+#ifndef CONFIG_COMMON_CLK
 	ret = arch_clk_init();
 	if (unlikely(ret)) {
 		pr_err("%s: CPU clock registration failed.\n", __func__);
 		return ret;
 	}
+#endif
 
 	if (sh_mv.mv_clk_init) {
 		ret = sh_mv.mv_clk_init();
@@ -39,11 +41,13 @@ int __init clk_init(void)
 		}
 	}
 
+#ifndef CONFIG_COMMON_CLK
 	/* Kick the child clocks.. */
 	recalculate_root_clocks();
 
 	/* Enable the necessary init clocks */
 	clk_enable_init_clocks();
+#endif
 
 	return ret;
 }
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 98efbfc..60d19d0 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -213,6 +213,7 @@ source "drivers/clk/mvebu/Kconfig"
 source "drivers/clk/qcom/Kconfig"
 source "drivers/clk/renesas/Kconfig"
 source "drivers/clk/samsung/Kconfig"
+source "drivers/clk/sh/Kconfig"
 source "drivers/clk/tegra/Kconfig"
 source "drivers/clk/ti/Kconfig"
 
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index dcc5e69..c4bfbb9 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -86,5 +86,6 @@ obj-$(CONFIG_COMMON_CLK_VERSATILE)	+= versatile/
 obj-$(CONFIG_X86)			+= x86/
 obj-$(CONFIG_ARCH_ZX)			+= zte/
 obj-$(CONFIG_ARCH_ZYNQ)			+= zynq/
-obj-$(CONFIG_H8300)		+= h8300/
+obj-$(CONFIG_H8300)			+= h8300/
 obj-$(CONFIG_ARC_PLAT_AXS10X)		+= axs10x/
+obj-$(CONFIG_SUPERH)			+= sh/
diff --git a/drivers/clk/sh/Kconfig b/drivers/clk/sh/Kconfig
new file mode 100644
index 0000000..2090415
--- /dev/null
+++ b/drivers/clk/sh/Kconfig
@@ -0,0 +1,2 @@
+config COMMON_CLK_SH7750
+	bool "CPG driver for SH7750/SH7751"
diff --git a/drivers/clk/sh/Makefile b/drivers/clk/sh/Makefile
new file mode 100644
index 0000000..7ce4da3
--- /dev/null
+++ b/drivers/clk/sh/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_COMMON_CLK_SH7750) += clk-sh7750cpg.o
diff --git a/drivers/clk/sh/clk-sh7750cpg.c b/drivers/clk/sh/clk-sh7750cpg.c
new file mode 100644
index 0000000..a538be4
--- /dev/null
+++ b/drivers/clk/sh/clk-sh7750cpg.c
@@ -0,0 +1,344 @@
+/*
+ * Renesas SH7750/51 clock driver
+ *
+ * Copyright 2016 Yoshinori Sato <ysato@users.sourceforge.jp>
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+/* Available FREQCR settings */
+static const int freqcr_table[] = {
+	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0408,
+	0x0409, 0x040a, 0x040b, 0x040c, 0x0411, 0x0412,
+	0x0413, 0x0414, 0x041a, 0x041b, 0x041c, 0x0423,
+	0x0424, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c,
+	0x0451, 0x0452, 0x0453, 0x0454, 0x045a, 0x045b,
+	0x045c, 0x0463, 0x0464, 0x0491, 0x0492, 0x0493,
+	0x0494, 0x049a, 0x049b, 0x049c, 0x04a3, 0x04a4,
+	0x04da, 0x04db, 0x04dc, 0x04e3, 0x04e4, 0x0523,
+	0x0524, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004,
+	0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x0011,
+	0x0012, 0x0013, 0x0014, 0x0019, 0x001a, 0x001b,
+	0x001c, 0x0023, 0x0024, 0x0048, 0x0049, 0x004a,
+	0x004b, 0x004c, 0x0051, 0x0052, 0x0053, 0x0054,
+	0x0059, 0x005a, 0x005b, 0x005c, 0x0063, 0x0064,
+	0x0091, 0x0092, 0x0093, 0x0094, 0x0099, 0x009a,
+	0x009b, 0x009c, 0x00a3, 0x00a4, 0x00d1, 0x00d2,
+	0x00d3, 0x00d4, 0x00d9, 0x00da, 0x00db, 0x00dc,
+	0x00e3, 0x00e4, 0x0123, 0x0124, 0x0163, 0x0164,
+};
+
+struct priv {
+	void __iomem *freqcr;
+	void __iomem *clkstp;
+	int mult;
+	struct clk **clks;
+};
+
+struct cpg_clock {
+	struct clk_hw hw;
+	struct priv *priv;
+	int index;
+};
+
+struct clockname {
+	char *name;
+	int index;
+};
+
+static const struct clockname clocknames[] __initconst = {
+	{ .name = "sci", .index = 0 },
+	{ .name = "rtc", .index = 1 },
+	{ .name = "tmu0", .index = 2 },
+	{ .name = "tmu1", .index = 2 },
+	{ .name = "tmu2", .index = 2 },
+	{ .name = "scif", .index = 3 },
+	{ .name = "dmac", .index = 4 },
+	{ .name = "ubc", .index = 8 },
+	{ .name = "sq", .index = 9 },
+	{ .name = "intc", .index = 16 },
+	{ .name = "tmu3", .index = 17 },
+	{ .name = "tmu4", .index = 17 },
+	{ .name = "pcic", .index = 18 },
+	{ .name = "core", .index = 128 },
+};
+
+static const int iclk_div[] = {1, 2, 3, 4, 6, 8, 0, 0};
+static const int pclk_div[] = {2, 3, 4, 6, 8, 0, 0, 0};
+
+static DEFINE_SPINLOCK(clklock);
+
+#define to_cpg_clock(_hw) container_of(_hw, struct cpg_clock, hw)
+
+static unsigned long pllout(u16 freqcr, unsigned long parent_rate, int mult)
+{
+	if ((freqcr >> 10) & 1)
+		return parent_rate * mult;
+	else
+		return parent_rate;
+}
+
+static unsigned long cpg_recalc_rate(struct clk_hw *hw,
+				     unsigned long parent_rate)
+{
+	struct cpg_clock *cpg_clock = to_cpg_clock(hw);
+	struct priv *priv = cpg_clock->priv;
+	unsigned long div;
+	u16 freqcr;
+
+	freqcr = ioread16(priv->freqcr);
+	if (cpg_clock->index == 128)
+		div = iclk_div[(freqcr >> 6) & 7];
+	else
+		div = pclk_div[freqcr & 7];
+	return pllout(freqcr, parent_rate, priv->mult) / div;
+}
+
+static u16 get_best_freqcr(unsigned long rate,
+			   unsigned long pclk_rate,
+			   unsigned long parent, int mult)
+{
+	int i;
+	int div;
+	u16 freqcr;
+
+	for (i = 0; i < ARRAY_SIZE(freqcr_table); i++) {
+		freqcr = freqcr_table[i];
+		if (pllout(freqcr, parent, mult) / pclk_div[freqcr & 7]
+		    != pclk_rate)
+			continue;
+		div = iclk_div[(freqcr >> 6) & 7];
+		if (pllout(freqcr, parent, mult) / div < rate)
+			return freqcr;
+	}
+	return 0;
+}
+
+static long cpg_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	struct cpg_clock *cpg_clock = to_cpg_clock(hw);
+	struct priv *priv = cpg_clock->priv;
+	unsigned long pclk_rate;
+	u16 freqcr;
+	int div;
+
+	freqcr = ioread16(priv->freqcr);
+	pclk_rate = pllout(freqcr, *prate, priv->mult) / pclk_div[freqcr & 7];
+
+	freqcr = get_best_freqcr(rate, pclk_rate, *prate, priv->mult);
+	if (cpg_clock->index == 128)
+		div = iclk_div[(freqcr >> 6) & 7];
+	else
+		div = pclk_div[freqcr & 7];
+
+	return pllout(freqcr, *prate, priv->mult) / div;
+}
+
+static int cpg_set_rate(struct clk_hw *hw, unsigned long rate,
+			unsigned long parent_rate)
+{
+	struct cpg_clock *cpg_clock = to_cpg_clock(hw);
+	struct priv *priv = cpg_clock->priv;
+	unsigned long flags;
+	unsigned long pclk_rate;
+	u16 freqcr, new_freqcr;
+
+	if (cpg_clock->index != 128)
+		return 0;
+
+	freqcr = ioread16(priv->freqcr);
+	pclk_rate = pllout(freqcr, parent_rate, priv->mult) /
+		pclk_div[freqcr & 7];
+
+	new_freqcr = get_best_freqcr(rate, pclk_rate, parent_rate, priv->mult);
+
+	if ((freqcr & 0x0200) == 0 && (new_freqcr & 0x0200) != 0) {
+		/* PLL on */
+		/* required stable time */
+		spin_lock_irqsave(&clklock, flags);
+		iowrite16(0x5a00, priv->freqcr + 8);
+		iowrite16(0xa503, priv->freqcr + 12);
+		iowrite16(new_freqcr, priv->freqcr);
+		spin_unlock_irqrestore(&clklock, flags);
+	} else {
+		/* PLL state no change */
+		/* not required stable time */
+		iowrite16(new_freqcr, priv->freqcr);
+	}
+	return 0;
+}
+
+static int cpg_enable(struct clk_hw *hw)
+{
+	struct cpg_clock *cpg_clock = to_cpg_clock(hw);
+	struct priv *priv = cpg_clock->priv;
+	u8 stbcr;
+
+	switch ((cpg_clock->index >> 3) & 3) {
+	case 0:
+		/* STBCR */
+		stbcr = ioread8(priv->freqcr + 4);
+		stbcr &= ~(1 << (cpg_clock->index & 7));
+		iowrite8(stbcr, priv->freqcr + 4);
+		break;
+	case 1:
+		/* STBCR2 */
+		stbcr = ioread8(priv->freqcr + 16);
+		stbcr &= ~(1 << (cpg_clock->index & 7));
+		iowrite8(stbcr, priv->freqcr + 16);
+		break;
+	case 2:
+		/* CLKSTPCLR00 */
+		iowrite32(1 << (cpg_clock->index - 16), priv->clkstp + 8);
+		break;
+	}
+	return 0;
+}
+
+static void cpg_disable(struct clk_hw *hw)
+{
+	struct cpg_clock *cpg_clock = to_cpg_clock(hw);
+	struct priv *priv = cpg_clock->priv;
+	u8 stbcr;
+
+	switch ((cpg_clock->index >> 3) & 3) {
+	case 0:
+		/* STBCR */
+		stbcr = ioread8(priv->freqcr + 4);
+		stbcr |= (1 << (cpg_clock->index & 7));
+		iowrite8(stbcr, priv->freqcr + 4);
+		break;
+	case 1:
+		/* STBCR2 */
+		stbcr = ioread8(priv->freqcr + 16);
+		stbcr |= (1 << (cpg_clock->index & 7));
+		iowrite8(stbcr, priv->freqcr + 16);
+		break;
+	case 2:
+		/* CLKSTP00 */
+		iowrite32(1 << (cpg_clock->index - 16), priv->clkstp);
+		break;
+	}
+}
+
+struct clk *sh7750_onecell_get(struct of_phandle_args *clkspec, void *data)
+{
+	struct priv *priv = data;
+	unsigned int idx = clkspec->args[0];
+
+	if (idx >= ARRAY_SIZE(clocknames)) {
+		pr_err("%s: invalid clock index %u\n", __func__, idx);
+		return ERR_PTR(-EINVAL);
+	}
+
+	return priv->clks[idx];
+}
+
+static const struct clk_ops cpg_ops = {
+	.recalc_rate	= cpg_recalc_rate,
+	.round_rate	= cpg_round_rate,
+	.set_rate	= cpg_set_rate,
+	.enable		= cpg_enable,
+	.disable	= cpg_disable,
+};
+
+static struct clk *  __init sh7750_cpg_register(struct device_node *node,
+						const struct clockname *name,
+						const char *parent_name,
+						struct priv *priv)
+{
+	struct cpg_clock *cpg_clock;
+	struct clk_init_data init;
+	struct clk *clk;
+
+	cpg_clock = kzalloc(sizeof(struct cpg_clock), GFP_KERNEL);
+	if (!cpg_clock) {
+		pr_err("%s: failed to alloc memory", name->name);
+		return NULL;
+	}
+
+	init.name = name->name;
+	init.ops = &cpg_ops;
+	init.flags = CLK_IS_BASIC;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+	cpg_clock->hw.init = &init;
+	cpg_clock->priv = priv;
+	cpg_clock->index = name->index;
+
+	clk = clk_register(NULL, &cpg_clock->hw);
+	if (IS_ERR(clk)) {
+		pr_err("%s: failed to register %s pll clock (%ld)\n",
+		       __func__, name->name, PTR_ERR(clk));
+		return NULL;
+	}
+	return clk;
+}
+
+static void __init sh7750_cpg_setup(struct device_node *node)
+{
+	const char *parent_name;
+	struct priv *priv;
+	int i;
+
+	priv = kzalloc(sizeof(struct priv), GFP_KERNEL);
+	if (priv == NULL) {
+		pr_err("%s: failed to alloc memory",
+		       node->name);
+		return;
+	}
+	priv->clks = kmalloc_array(sizeof(priv->clks), ARRAY_SIZE(clocknames),
+				   GFP_KERNEL);
+	if (priv->clks == NULL) {
+		pr_err("%s: failed to alloc memory",
+		       node->name);
+		kfree(priv);
+		return;
+	}
+	for (i = 0; i < ARRAY_SIZE(clocknames); i++)
+		priv->clks[i] = ERR_PTR(-ENOENT);
+
+	priv->freqcr = of_iomap(node, 0);
+	if (priv->freqcr == NULL) {
+		pr_err("%s: failed to map frequenct control register",
+		       node->name);
+		goto free_clock;
+	}
+
+	/* Optional register */
+	priv->clkstp = of_iomap(node, 1);
+
+	of_property_read_u32_index(node, "renesas,mult", 0, &priv->mult);
+
+	parent_name = of_clk_get_parent_name(node, 0);
+
+	for (i = 0; i < ARRAY_SIZE(clocknames); i++) {
+		priv->clks[i] = sh7750_cpg_register(node, &clocknames[i],
+						    parent_name, priv);
+		if (priv->clks[i] == NULL)
+			goto unmap_reg;
+	}
+	of_clk_add_provider(node, sh7750_onecell_get, priv);
+	return;
+
+unmap_reg:
+	if (priv->clkstp)
+		iounmap(priv->clkstp);
+	iounmap(priv->freqcr);
+free_clock:
+	for (i = 0; i < ARRAY_SIZE(clocknames); i++)
+		if (priv->clks[i] != ERR_PTR(-ENOENT) && priv->clks[i])
+			clk_unregister(priv->clks[i]);
+	kfree(priv->clks);
+	kfree(priv);
+}
+
+CLK_OF_DECLARE(sh7750_cpg, "renesas,sh7750-cpg", sh7750_cpg_setup);
-- 
2.7.0

[toc] | [prev] | [next] | [standalone]


#1435989 — [PATCH v5 04/22] sh: Use P1SEGADDR

FromYoshinori Sato <ysato@users.sourceforge.jp>
Date2016-07-03 18:50 +0200
Subject[PATCH v5 04/22] sh: Use P1SEGADDR
Message-ID<rQSKJ-2yo-25@gated-at.bofh.it>
In reply to#1435986
FDT address is P1SEG. So not virtual address.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 arch/sh/kernel/setup.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index 86f2792..8e3b099 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -254,7 +254,7 @@ void __ref sh_fdt_init(phys_addr_t dt_phys)
 #ifdef CONFIG_USE_BUILTIN_DTB
 	dt_virt = __dtb_start;
 #else
-	dt_virt = phys_to_virt(dt_phys);
+	dt_virt = (void *)P1SEGADDR(dt_phys);
 #endif
 
 	if (!dt_virt || !early_init_dt_scan(dt_virt)) {
-- 
2.7.0

[toc] | [prev] | [next] | [standalone]


#1436110 — Re: [PATCH v5 04/22] sh: Use P1SEGADDR

FromRich Felker <dalias@libc.org>
Date2016-07-04 03:50 +0200
SubjectRe: [PATCH v5 04/22] sh: Use P1SEGADDR
Message-ID<rR1bk-7L2-9@gated-at.bofh.it>
In reply to#1435989
On Mon, Jul 04, 2016 at 01:46:24AM +0900, Yoshinori Sato wrote:
> FDT address is P1SEG. So not virtual address.
> 
> Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
> ---
>  arch/sh/kernel/setup.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
> index 86f2792..8e3b099 100644
> --- a/arch/sh/kernel/setup.c
> +++ b/arch/sh/kernel/setup.c
> @@ -254,7 +254,7 @@ void __ref sh_fdt_init(phys_addr_t dt_phys)
>  #ifdef CONFIG_USE_BUILTIN_DTB
>  	dt_virt = __dtb_start;
>  #else
> -	dt_virt = phys_to_virt(dt_phys);
> +	dt_virt = (void *)P1SEGADDR(dt_phys);
>  #endif
>  
>  	if (!dt_virt || !early_init_dt_scan(dt_virt)) {
> -- 

I don't think this change is correct, and I'm not sure what the
motivation is. It certainly can't work with !CONFIG_29BIT, and likely
can't work on nommu either (it won't work on J2). Maybe we have
different ideas about the sort of physical address the boot loader is
expected to pass; I would expect it to be something that, when passed
to phys_to_virt, yields an address the kernel can use to access the
memory. This does not necessarily mean it's MMU-mapped memory; it
could be (and in practice will be, I think) an address in the P1
segment obtained by adding PAGE_OFFSET (see asm/page.h).

Rich

[toc] | [prev] | [next] | [standalone]


#1437760 — Re: [PATCH v5 04/22] sh: Use P1SEGADDR

FromYoshinori Sato <ysato@users.sourceforge.jp>
Date2016-07-06 16:20 +0200
SubjectRe: [PATCH v5 04/22] sh: Use P1SEGADDR
Message-ID<rRVQd-1PF-23@gated-at.bofh.it>
In reply to#1436110
On Mon, 04 Jul 2016 10:48:52 +0900,
Rich Felker wrote:
> 
> On Mon, Jul 04, 2016 at 01:46:24AM +0900, Yoshinori Sato wrote:
> > FDT address is P1SEG. So not virtual address.
> > 
> > Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
> > ---
> >  arch/sh/kernel/setup.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
> > index 86f2792..8e3b099 100644
> > --- a/arch/sh/kernel/setup.c
> > +++ b/arch/sh/kernel/setup.c
> > @@ -254,7 +254,7 @@ void __ref sh_fdt_init(phys_addr_t dt_phys)
> >  #ifdef CONFIG_USE_BUILTIN_DTB
> >  	dt_virt = __dtb_start;
> >  #else
> > -	dt_virt = phys_to_virt(dt_phys);
> > +	dt_virt = (void *)P1SEGADDR(dt_phys);
> >  #endif
> >  
> >  	if (!dt_virt || !early_init_dt_scan(dt_virt)) {
> > -- 
> 
> I don't think this change is correct, and I'm not sure what the
> motivation is. It certainly can't work with !CONFIG_29BIT, and likely
> can't work on nommu either (it won't work on J2). Maybe we have
> different ideas about the sort of physical address the boot loader is
> expected to pass; I would expect it to be something that, when passed
> to phys_to_virt, yields an address the kernel can use to access the
> memory. This does not necessarily mean it's MMU-mapped memory; it
> could be (and in practice will be, I think) an address in the P1
> segment obtained by adding PAGE_OFFSET (see asm/page.h).
> 
> Rich

Hmm...
It's better to pass a virtual address in bootloader.

-- 
Yoshinori Sato
<ysato@users.sourceforge.jp>

[toc] | [prev] | [next] | [standalone]


#1437777 — Re: [PATCH v5 04/22] sh: Use P1SEGADDR

FromRich Felker <dalias@libc.org>
Date2016-07-06 17:00 +0200
SubjectRe: [PATCH v5 04/22] sh: Use P1SEGADDR
Message-ID<rRWsV-22V-1@gated-at.bofh.it>
In reply to#1437760
On Wed, Jul 06, 2016 at 11:11:44PM +0900, Yoshinori Sato wrote:
> On Mon, 04 Jul 2016 10:48:52 +0900,
> Rich Felker wrote:
> > 
> > On Mon, Jul 04, 2016 at 01:46:24AM +0900, Yoshinori Sato wrote:
> > > FDT address is P1SEG. So not virtual address.
> > > 
> > > Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
> > > ---
> > >  arch/sh/kernel/setup.c | 2 +-
> > >  1 file changed, 1 insertion(+), 1 deletion(-)
> > > 
> > > diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
> > > index 86f2792..8e3b099 100644
> > > --- a/arch/sh/kernel/setup.c
> > > +++ b/arch/sh/kernel/setup.c
> > > @@ -254,7 +254,7 @@ void __ref sh_fdt_init(phys_addr_t dt_phys)
> > >  #ifdef CONFIG_USE_BUILTIN_DTB
> > >  	dt_virt = __dtb_start;
> > >  #else
> > > -	dt_virt = phys_to_virt(dt_phys);
> > > +	dt_virt = (void *)P1SEGADDR(dt_phys);
> > >  #endif
> > >  
> > >  	if (!dt_virt || !early_init_dt_scan(dt_virt)) {
> > > -- 
> > 
> > I don't think this change is correct, and I'm not sure what the
> > motivation is. It certainly can't work with !CONFIG_29BIT, and likely
> > can't work on nommu either (it won't work on J2). Maybe we have
> > different ideas about the sort of physical address the boot loader is
> > expected to pass; I would expect it to be something that, when passed
> > to phys_to_virt, yields an address the kernel can use to access the
> > memory. This does not necessarily mean it's MMU-mapped memory; it
> > could be (and in practice will be, I think) an address in the P1
> > segment obtained by adding PAGE_OFFSET (see asm/page.h).
> 
> Hmm...
> It's better to pass a virtual address in bootloader.

I think we're just having a miscommunication on what "physical
address" vs "virtual address" means. I wouldn't call logical addresses
in the P1 segment "virtual" because they're not remapped by the MMU.
Could you provide an example showing the type of address your
bootloader is currently passing to the kernel and why it needs to be
mapped by P1SEGADDR rather than phys_to_virt?

Rich

[toc] | [prev] | [next] | [standalone]


#1435990 — [PATCH v6 12/22] sh: Add PCI host bridge driver for SH7751

FromYoshinori Sato <ysato@users.sourceforge.jp>
Date2016-07-03 18:50 +0200
Subject[PATCH v6 12/22] sh: Add PCI host bridge driver for SH7751
Message-ID<rQSKJ-2yo-27@gated-at.bofh.it>
In reply to#1435986
This is an alternative SH7751 PCI driver.
Existing driver (arch/sh/drivers/pci/pci-sh7751) uses SH specific interface.
But this driver uses common PCI interface. It is more modern and generic.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 .../devicetree/bindings/pci/sh7751-pci.txt         |  37 +++
 arch/sh/boards/Kconfig                             |   1 +
 arch/sh/drivers/Makefile                           |   2 +
 drivers/pci/host/Kconfig                           |   7 +
 drivers/pci/host/Makefile                          |   1 +
 drivers/pci/host/pci-sh7751.c                      | 327 +++++++++++++++++++++
 6 files changed, 375 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/sh7751-pci.txt
 create mode 100644 drivers/pci/host/pci-sh7751.c

diff --git a/Documentation/devicetree/bindings/pci/sh7751-pci.txt b/Documentation/devicetree/bindings/pci/sh7751-pci.txt
new file mode 100644
index 0000000..2df9af6
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/sh7751-pci.txt
@@ -0,0 +1,37 @@
+* Renesas SH7751 PCI host interfaces
+
+Required properties:
+  - compatible: "renesas,sh7751-pci" is required.
+    And board specific compatible if fixup required.
+  - reg: contain two entries.
+        first entry: PCI controller register base address and length.
+        second entry: BUS controller register base address and length.
+  - #address-cells: set to <2>
+  - #size-cells: set to <1>
+  - bus-range: PCI bus numbers covered
+  - device_type: set to "pci"
+  - ranges: ranges for the PCI memory and I/O regions.
+  - interrupt-map-mask and interrupt-map: standard PCI properties
+	to define the mapping of the PCI interface to interrupt
+	numbers.
+
+Example:
+	pci: pci-controller@fe200000 {
+		compatible = "renesas,sh7751-pci", "iodata,landisk";
+		device_type = "pci";
+		bus-range = <0 0>;
+		#address-cells = <2>;
+		#size-cells = <1>;
+		ranges = <0x02000000 0x00000000 0xfd000000 0xfd000000 0x00000000 0x01000000>,
+		         <0x01000000 0x00000000 0xfe240000 0x00000000 0x00000000 0x00040000>;
+		reg = <0xfe200000 0x0400>,
+		      <0xff800000 0x0030>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0x1800 0 7>;
+		interrupt-map = <0x0000 0 1 &cpldintc 0 0>,
+		                <0x0800 0 1 &cpldintc 1 0>,
+		                <0x1000 0 1 &cpldintc 2 0>,
+		                <0x1800 0 1 &cpldintc 3 0>,
+		                <0x1800 0 2 &cpldintc 0 0>;
+	};
+};
diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig
index b6ff9df..cfde921 100644
--- a/arch/sh/boards/Kconfig
+++ b/arch/sh/boards/Kconfig
@@ -14,6 +14,7 @@ config SH_DEVICE_TREE
 	select GENERIC_CALIBRATE_DELAY
 	select GENERIC_IOMAP
 	select COMMON_CLK
+	select SYS_SUPPORTS_PCI
 	help
 	  Select Board Described by Device Tree to build a kernel that
 	  does not hard-code any board-specific knowledge but instead uses
diff --git a/arch/sh/drivers/Makefile b/arch/sh/drivers/Makefile
index e13f06b..382e86f 100644
--- a/arch/sh/drivers/Makefile
+++ b/arch/sh/drivers/Makefile
@@ -4,7 +4,9 @@
 
 obj-y		+= dma/
 
+ifndef CONFIG_SH_DEVICE_TREE
 obj-$(CONFIG_PCI)		+= pci/
+endif
 obj-$(CONFIG_SUPERHYWAY)	+= superhyway/
 obj-$(CONFIG_PUSH_SWITCH)	+= push-switch.o
 obj-$(CONFIG_HEARTBEAT)		+= heartbeat.o
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 5d2374e..df60505 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -245,4 +245,11 @@ config PCIE_ARMADA_8K
 	  Designware hardware and therefore the driver re-uses the
 	  Designware core functions to implement the driver.
 
+config PCI_SH7751
+	bool "Renesas SH7751 On-Chip PCI controller"
+	depends on OF && SUPERH
+	select PCI_HOST_COMMON
+	help
+	  Say Y here if you want PCI support on SH7751.
+
 endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 9c8698e..4681e49 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -29,3 +29,4 @@ obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
 obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o
 obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o
 obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o
+obj-$(CONFIG_PCI_SH7751) += pci-sh7751.o
diff --git a/drivers/pci/host/pci-sh7751.c b/drivers/pci/host/pci-sh7751.c
new file mode 100644
index 0000000..21601f1
--- /dev/null
+++ b/drivers/pci/host/pci-sh7751.c
@@ -0,0 +1,327 @@
+/*
+ * SH7751 PCI driver
+ * Copyright (C) 2016 Yoshinori Sato
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include "../ecam.h"
+
+#define SH7751_PCICONF1            0x4           /* PCI Config Reg 1 */
+#define SH7751_PCICONF4            0x10          /* PCI Config Reg 4 */
+#define SH7751_PCICONF5            0x14          /* PCI Config Reg 5 */
+#define SH7751_PCICONF6            0x18          /* PCI Config Reg 6 */
+#define SH4_PCICR		0x100		/* PCI Control Register */
+  #define SH4_PCICR_PREFIX	  0xA5000000	/* CR prefix for write */
+  #define SH4_PCICR_FTO		  BIT(10)	/* TRDY/IRDY Enable */
+  #define SH4_PCICR_TRSB	  BIT(9)	/* Target Read Single */
+  #define SH4_PCICR_BSWP	  BIT(8)	/* Target Byte Swap */
+  #define SH4_PCICR_PLUP	  BIT(7)	/* Enable PCI Pullup */
+  #define SH4_PCICR_ARBM	  BIT(6)	/* PCI Arbitration Mode */
+#define SH4_PCICR_MD		  (BIT(4) | BIT(5))	/* MD9 and MD10 status */
+  #define SH4_PCICR_SERR	  BIT(3)	/* SERR output assert */
+  #define SH4_PCICR_INTA	  BIT(2)	/* INTA output assert */
+  #define SH4_PCICR_PRST	  BIT(1)	/* PCI Reset Assert */
+  #define SH4_PCICR_CFIN	  BIT(0)	/* Central Fun. Init Done */
+#define SH4_PCILSR0		0x104		/* PCI Local Space Register0 */
+#define SH4_PCILSR1		0x108		/* PCI Local Space Register1 */
+#define SH4_PCILAR0		0x10C		/* PCI Local Addr Register1 */
+#define SH4_PCILAR1		0x110		/* PCI Local Addr Register1 */
+#define SH4_PCIINTM		0x118		/* PCI Interrupt Mask */
+  #define SH4_PCIINTM_TTADIM	  BIT(14)	/* Target-target abort interrupt */
+  #define SH4_PCIINTM_TMTOIM	  BIT(9)	/* Target retry timeout */
+  #define SH4_PCIINTM_MDEIM	  BIT(8)	/* Master function disable error */
+  #define SH4_PCIINTM_APEDIM	  BIT(7)	/* Address parity error detection */
+  #define SH4_PCIINTM_SDIM	  BIT(6)	/* SERR detection */
+  #define SH4_PCIINTM_DPEITWM	  BIT(5)	/* Data parity error for target write */
+  #define SH4_PCIINTM_PEDITRM	  BIT(4)	/* PERR detection for target read */
+  #define SH4_PCIINTM_TADIMM	  BIT(3)	/* Target abort for master */
+  #define SH4_PCIINTM_MADIMM	  BIT(2)	/* Master abort for master */
+  #define SH4_PCIINTM_MWPDIM	  BIT(1)	/* Master write data parity error */
+  #define SH4_PCIINTM_MRDPEIM	  BIT(0)	/* Master read data parity error */
+#define SH4_PCIAINTM            0x134		/* Arbiter Int. Mask Register */
+#define SH4_PCIPAR		0x1C0		/* PIO Address Register */
+  #define SH4_PCIPAR_CFGEN	  0x80000000	/* Configuration Enable */
+  #define SH4_PCIPAR_BUSNO	  0x00FF0000	/* Config. Bus Number */
+  #define SH4_PCIPAR_DEVNO	  0x0000FF00	/* Config. Device Number */
+  #define SH4_PCIPAR_REGAD	  0x000000FC	/* Register Address Number */
+#define SH4_PCIPINT		0x1CC		/* Power Mgmnt Int. Register */
+  #define SH4_PCIPINT_D3	  0x00000002	/* D3 Pwr Mgmt. Interrupt */
+  #define SH4_PCIPINT_D0	  0x00000001	/* D0 Pwr Mgmt. Interrupt */
+#define SH4_PCICLKR		0x1D4		/* Clock Ctrl. Register */
+/* For definitions of BCR, MCR see ... */
+#define SH4_PCIBCR1		0x1E0		/* Memory BCR1 Register */
+  #define SH4_PCIMBR0		SH4_PCIBCR1
+#define SH4_PCIBCR2		0x1E4		/* Memory BCR2 Register */
+  #define SH4_PCIMBMR0		SH4_PCIBCR2
+#define SH4_PCIWCR1		0x1E8		/* Wait Control 1 Register */
+#define SH4_PCIWCR2		0x1EC		/* Wait Control 2 Register */
+#define SH4_PCIWCR3		0x1F0		/* Wait Control 3 Register */
+  #define SH4_PCIMBR2		SH4_PCIWCR3
+#define SH4_PCIMCR		0x1F4		/* Memory Control Register */
+#define SH4_PCIPDR		0x220		/* Port IO Data Register */
+
+/* Platform Specific Values */
+#define SH7751_VENDOR_ID             0x1054
+#define SH7751_DEVICE_ID             0x3505
+#define SH7751R_DEVICE_ID            0x350e
+
+/* Memory Control Registers */
+#define SH7751_BCR1                0x0000    /* Memory BCR1 Register */
+#define SH7751_BCR2                0x0004    /* Memory BCR2 Register */
+#define SH7751_BCR3                0x0050    /* Memory BCR3 Register */
+#define SH7751_WCR1                0x0008    /* Wait Control 1 Register */
+#define SH7751_WCR2                0x000C    /* Wait Control 2 Register */
+#define SH7751_WCR3                0x0010    /* Wait Control 3 Register */
+#define SH7751_MCR                 0x0014    /* Memory Control Register */
+
+#define pcic_writel(val, reg) iowrite32(val, pci_reg_base + (reg))
+#define pcic_readl(reg) ioread32(pci_reg_base + (reg))
+
+/*
+ * PCIC fixups
+ */
+
+#define PCIMCR_MRSET 0x40000000
+#define PCIMCR_RFSH  0x00000004
+
+static void __init landisk_fixup(void __iomem *pci_reg_base, void __iomem *bcr)
+{
+	unsigned long bcr1, mcr;
+
+	bcr1 = ioread32(bcr + SH7751_BCR1);
+	bcr1 |= 0x00080000;	/* Enable Bit 19 BREQEN, set PCIC to slave */
+	pcic_writel(bcr1, SH4_PCIBCR1);
+
+	mcr = ioread32(bcr + SH7751_MCR);
+	mcr &= (~PCIMCR_MRSET) & (~PCIMCR_RFSH);
+	pcic_writel(mcr, SH4_PCIMCR);
+
+	pcic_writel(0x0c000000, PCI_BASE_ADDRESS_1);
+	pcic_writel(0xd0000000, PCI_BASE_ADDRESS_2);
+	pcic_writel(0x0c000000, SH4_PCILAR0);
+	pcic_writel(0x00000000, SH4_PCILAR1);
+}
+
+static void __init r2dplus_fixup(void __iomem *pci_reg_base, void __iomem *bcr)
+{
+	unsigned long bcr1, mcr;
+
+	bcr1 = ioread32(bcr + SH7751_BCR1);
+	bcr1 |= 0x40080000;	/* Enable Bit 19 BREQEN, set PCIC to slave */
+	pcic_writel(bcr1, SH4_PCIBCR1);
+
+	/* Enable all interrupts, so we known what to fix */
+	pcic_writel(0x0000c3ff, SH4_PCIINTM);
+	pcic_writel(0x0000380f, SH4_PCIAINTM);
+
+	pcic_writel(0xfb900047, SH7751_PCICONF1);
+	pcic_writel(0xab000001, SH7751_PCICONF4);
+
+	mcr = ioread32(bcr + SH7751_MCR);
+	mcr &= (~PCIMCR_MRSET) & (~PCIMCR_RFSH);
+	pcic_writel(mcr, SH4_PCIMCR);
+
+	pcic_writel(0x0c000000, SH7751_PCICONF5);
+	pcic_writel(0xd0000000, SH7751_PCICONF6);
+	pcic_writel(0x0c000000, SH4_PCILAR0);
+	pcic_writel(0x00000000, SH4_PCILAR1);
+}
+
+/*
+ * Direct access to PCI hardware...
+ */
+#define CONFIG_CMD(bus, devfn, where) \
+	(0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
+
+/*
+ * Functions for accessing PCI configuration space with type 1 accesses
+ */
+static void __iomem *sh7751_map_bus(struct pci_bus *bus,
+				   unsigned int devfn, int where)
+{
+	struct pci_config_window *cfg = bus->sysdata;
+	void __iomem *pci_reg_base = (void __iomem *)cfg->res.start;
+
+	pcic_writel(CONFIG_CMD(bus, devfn, where), SH4_PCIPAR);
+	return pci_reg_base + SH4_PCIPDR;
+}
+
+static const struct of_device_id fixup_of_match[] = {
+	{ .compatible = "iodata,landisk-pci", .data = landisk_fixup, },
+	{ .compatible = "renesas,r2dplus-pci", .data = r2dplus_fixup, },
+	{ },
+};
+
+static const struct of_device_id sh7751_pci_of_match[] = {
+	{ .compatible = "renesas,sh7751-pci", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, sh7751_pci_of_match);
+
+static resource_size_t sh7751_align_resource(struct pci_dev *dev,
+					     const struct resource *res,
+					     resource_size_t start,
+					     resource_size_t size,
+					     resource_size_t align)
+{
+	if (res->flags & IORESOURCE_IO) {
+		if (start < PCIBIOS_MIN_IO + 0x1000)
+			start = PCIBIOS_MIN_IO + 0x1000;
+
+		/*
+		 * Put everything into 0x00-0xff region modulo 0x400.
+		 */
+		if (start & 0x300)
+			start = (start + 0x3ff) & ~0x3ff;
+	}
+
+	return start;
+}
+
+static void __init set_pci_bcr(void __iomem *pci_reg_base,
+			       void __iomem *bcr,
+			       unsigned int area)
+{
+	unsigned long word;
+
+	word = ioread32(bcr + SH7751_BCR1);
+	/* check BCR for SDRAM in area */
+	if (((word >> area) & 1) == 0) {
+		pr_info("PCI: Area %d is not configured for SDRAM. BCR1=0x%lx\n",
+			area, word);
+		return;
+	}
+	pcic_writel(word, SH4_PCIBCR1);
+
+	word = ioread16(bcr + SH7751_BCR2);
+	/* check BCR2 for 32bit SDRAM interface*/
+	if (((word >> (area << 1)) & 0x3) != 0x3) {
+		pr_info("PCI: Area %d is not 32 bit SDRAM. BCR2=0x%lx\n",
+			area, word);
+		return;
+	}
+	pcic_writel(word, SH4_PCIBCR2);
+}
+
+static __init int sh7751_cfg_init(struct device *dev,
+				  struct pci_config_window *cfg)
+{
+	cfg->priv = sh7751_align_resource;
+	return 0;
+}
+
+static struct pci_ecam_ops ecm_ops __initdata = {
+	.init	= sh7751_cfg_init,
+	.pci_ops = {
+		.read	= pci_generic_config_read32,
+		.write	= pci_generic_config_write32,
+		.map_bus	= sh7751_map_bus,
+	}
+};
+
+static __init int sh7751_pci_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	u32 id;
+	u32 reg, word;
+	void __iomem *pci_reg_base;
+	void __iomem *bcr;
+	const struct of_device_id *match;
+	void (*fixup_fn)(void __iomem *pci_reg_base, void __iomem *bcr);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	pci_reg_base = ioremap(res->start, resource_size(res));
+	if (IS_ERR(pci_reg_base))
+		return PTR_ERR(pci_reg_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	bcr = ioremap(res->start, resource_size(res));
+	if (IS_ERR(bcr))
+		return PTR_ERR(bcr);
+
+	/* check for SH7751/SH7751R hardware */
+	id = pcic_readl(PCI_VENDOR_ID);
+	if (id != ((SH7751_DEVICE_ID << 16) | SH7751_VENDOR_ID) &&
+	    id != ((SH7751R_DEVICE_ID << 16) | SH7751_VENDOR_ID)) {
+		pr_warn("PCI: This is not an SH7751(R)\n");
+		return -ENODEV;
+	}
+	dev_info(&pdev->dev, "PCI core found at %pR\n",
+		pci_reg_base);
+
+	/* Set the BCRs to enable PCI access */
+	reg = ioread32(bcr);
+	reg |= 0x80000;
+	iowrite32(reg, bcr);
+
+	/* Turn the clocks back on (not done in reset)*/
+	pcic_writel(0, SH4_PCICLKR);
+	/* Clear Powerdown IRQs (not done in reset) */
+	word = SH4_PCIPINT_D3 | SH4_PCIPINT_D0;
+	pcic_writel(word, SH4_PCIPINT);
+
+	/* set the command/status bits to:
+	 * Wait Cycle Control + Parity Enable + Bus Master +
+	 * Mem space enable
+	 */
+	word = PCI_COMMAND_WAIT | PCI_COMMAND_PARITY |
+	       PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+	pcic_writel(word, PCI_COMMAND);
+
+	/* define this host as the host bridge */
+	word = PCI_BASE_CLASS_BRIDGE << 24;
+	pcic_writel(word, PCI_CLASS_REVISION);
+
+	/* Set IO and Mem windows to local address
+	 * Make PCI and local address the same for easy 1 to 1 mapping
+	 */
+	word = memory_end - memory_start - 1;
+	pcic_writel(word, SH4_PCILSR0);
+	/* Set the values on window 0 PCI config registers */
+	word = P2SEGADDR(__pa(memory_start));
+	pcic_writel(word, SH4_PCILAR0);
+	pcic_writel(word, PCI_BASE_ADDRESS_1);
+
+	set_pci_bcr(pci_reg_base, bcr, (__pa(memory_start) >> 27) & 0x07);
+
+	/* configure the wait control registers */
+	word = ioread32(bcr + SH7751_WCR1);
+	pcic_writel(word, SH4_PCIWCR1);
+	word = ioread32(bcr + SH7751_WCR2);
+	pcic_writel(word, SH4_PCIWCR2);
+	word = ioread32(bcr + SH7751_WCR3);
+	pcic_writel(word, SH4_PCIWCR3);
+	word = ioread32(bcr + SH7751_MCR);
+	pcic_writel(word, SH4_PCIMCR);
+
+	match = of_match_node(fixup_of_match, pdev->dev.of_node);
+	if (match) {
+		fixup_fn = match->data;
+		fixup_fn(pci_reg_base, bcr);
+	}
+	/*
+	 * SH7751 init done, set central function init complete
+	 * use round robin mode to stop a device starving/overruning
+	 */
+	word = SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_ARBM;
+	pcic_writel(word, SH4_PCICR);
+
+	return pci_host_common_probe(pdev, &ecm_ops);
+}
+
+static __refdata struct platform_driver sh7751_pci_driver = {
+	.driver = {
+		.name = "sh7751-pci",
+		.of_match_table = sh7751_pci_of_match,
+		.suppress_bind_attrs = true,
+	},
+	.probe = sh7751_pci_probe,
+};
+builtin_platform_driver(sh7751_pci_driver);
-- 
2.7.0

[toc] | [prev] | [next] | [standalone]


#1437135 — Re: [PATCH v6 12/22] sh: Add PCI host bridge driver for SH7751

FromRob Herring <robh@kernel.org>
Date2016-07-05 18:00 +0200
SubjectRe: [PATCH v6 12/22] sh: Add PCI host bridge driver for SH7751
Message-ID<rRAVs-4Ms-5@gated-at.bofh.it>
In reply to#1435990
On Mon, Jul 04, 2016 at 01:46:32AM +0900, Yoshinori Sato wrote:
> This is an alternative SH7751 PCI driver.
> Existing driver (arch/sh/drivers/pci/pci-sh7751) uses SH specific interface.
> But this driver uses common PCI interface. It is more modern and generic.
> 
> Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
> ---
>  .../devicetree/bindings/pci/sh7751-pci.txt         |  37 +++

Please add acks when posting new versions.

>  arch/sh/boards/Kconfig                             |   1 +
>  arch/sh/drivers/Makefile                           |   2 +
>  drivers/pci/host/Kconfig                           |   7 +
>  drivers/pci/host/Makefile                          |   1 +
>  drivers/pci/host/pci-sh7751.c                      | 327 +++++++++++++++++++++
>  6 files changed, 375 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pci/sh7751-pci.txt
>  create mode 100644 drivers/pci/host/pci-sh7751.c

[toc] | [prev] | [next] | [standalone]


#1437822 — Re: [PATCH v6 12/22] sh: Add PCI host bridge driver for SH7751

FromYoshinori Sato <ysato@users.sourceforge.jp>
Date2016-07-06 18:20 +0200
SubjectRe: [PATCH v6 12/22] sh: Add PCI host bridge driver for SH7751
Message-ID<rRXIm-2ZF-7@gated-at.bofh.it>
In reply to#1437135
On Wed, 06 Jul 2016 00:53:06 +0900,
Rob Herring wrote:
> 
> On Mon, Jul 04, 2016 at 01:46:32AM +0900, Yoshinori Sato wrote:
> > This is an alternative SH7751 PCI driver.
> > Existing driver (arch/sh/drivers/pci/pci-sh7751) uses SH specific interface.
> > But this driver uses common PCI interface. It is more modern and generic.
> > 
> > Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
> > ---
> >  .../devicetree/bindings/pci/sh7751-pci.txt         |  37 +++
> 
> Please add acks when posting new versions.
> 
> >  arch/sh/boards/Kconfig                             |   1 +
> >  arch/sh/drivers/Makefile                           |   2 +
> >  drivers/pci/host/Kconfig                           |   7 +
> >  drivers/pci/host/Makefile                          |   1 +
> >  drivers/pci/host/pci-sh7751.c                      | 327 +++++++++++++++++++++
> >  6 files changed, 375 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/pci/sh7751-pci.txt
> >  create mode 100644 drivers/pci/host/pci-sh7751.c

Oh. Sorry.
I forgot it.

-- 
Yoshinori Sato
<ysato@users.sourceforge.jp>

[toc] | [prev] | [next] | [standalone]


#1435991 — [PATCH v5 10/22] sh: Add board specific initialize of of-generic

FromYoshinori Sato <ysato@users.sourceforge.jp>
Date2016-07-03 18:50 +0200
Subject[PATCH v5 10/22] sh: Add board specific initialize of of-generic
Message-ID<rQSKK-2yo-43@gated-at.bofh.it>
In reply to#1435986
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 arch/sh/boards/of-generic.c | 64 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/arch/sh/boards/of-generic.c b/arch/sh/boards/of-generic.c
index 2d3cda3..4038682 100644
--- a/arch/sh/boards/of-generic.c
+++ b/arch/sh/boards/of-generic.c
@@ -16,9 +16,15 @@
 #include <linux/irqchip.h>
 #include <linux/clk-provider.h>
 #include <linux/memblock.h>
+#include <linux/sm501-regs.h>
 #include <asm/machvec.h>
 #include <asm/rtc.h>
 
+struct model_setup {
+	char *name;
+	void (*fn)(void);
+};
+
 #ifdef CONFIG_SMP
 
 static void dummy_smp_setup(void)
@@ -125,10 +131,61 @@ static void __init sh_of_time_init(void)
 	clocksource_probe();
 }
 
+#define PA_LED		0xb0000001	/* LED Control Register */
+#define PA_SHUTDOWN	0xb0000003	/* Shutdown Control Register */
+static void landisk_power_off(void)
+{
+	__raw_writeb(0x01, PA_SHUTDOWN);
+}
+
+static void __init landisk_setup(void)
+{
+	/* LED ON */
+	__raw_writeb(__raw_readb(PA_LED) | 0x03, PA_LED);
+	pm_power_off = landisk_power_off;
+}
+
+#define PA_POWOFF	0xa4000030	/* Board Power OFF control */
+#define PA_OUTPORT	0xa4000036	/* LED control */
+static void rts7751r2d_power_off(void)
+{
+	__raw_writew(0x0001, PA_POWOFF);
+}
+
+static void __init r2dplus_setup(void)
+{
+	void __iomem *sm501_reg;
+
+	__raw_writew(0x0000, PA_OUTPORT);
+	pm_power_off = rts7751r2d_power_off;
+
+	/* sm501 dram configuration:
+	 * ColSizeX = 11 - External Memory Column Size: 256 words.
+	 * APX = 1 - External Memory Active to Pre-Charge Delay: 7 clocks.
+	 * RstX = 1 - External Memory Reset: Normal.
+	 * Rfsh = 1 - Local Memory Refresh to Command Delay: 12 clocks.
+	 * BwC =  1 - Local Memory Block Write Cycle Time: 2 clocks.
+	 * BwP =  1 - Local Memory Block Write to Pre-Charge Delay: 1 clock.
+	 * AP = 1 - Internal Memory Active to Pre-Charge Delay: 7 clocks.
+	 * Rst = 1 - Internal Memory Reset: Normal.
+	 * RA = 1 - Internal Memory Remain in Active State: Do not remain.
+	 */
+
+	sm501_reg = (void __iomem *)0xb3e00000 + SM501_DRAM_CONTROL;
+	writel(readl(sm501_reg) | 0x00f107c0, sm501_reg);
+}
+
+static const struct model_setup model_setup_table[] __initconst = {
+	{ .name = "iodata,HDL-U", .fn = landisk_setup, },
+	{ .name = "renesas,RTS7751R2D+", .fn = r2dplus_setup, },
+	{},
+};
+
 static void __init sh_of_setup(char **cmdline_p)
 {
 	struct device_node *root;
 	struct device_node *cpu;
+	const struct model_setup *setup;
 	u32 freq;
 
 	board_time_init = sh_of_time_init;
@@ -145,6 +202,13 @@ static void __init sh_of_setup(char **cmdline_p)
 	cpu = of_find_node_by_name(NULL, "cpu");
 	if (!of_property_read_u32(cpu, "clock-frequency", &freq))
 		preset_lpj = freq / CONFIG_HZ / 2;
+
+	for (setup = model_setup_table; setup->name; setup++) {
+		if (strcmp(setup->name, sh_mv.mv_name) == 0) {
+			setup->fn();
+			break;
+		}
+	}
 }
 
 static int sh_of_irq_demux(int irq)
-- 
2.7.0

[toc] | [prev] | [next] | [standalone]


#1436103 — Re: [PATCH v5 10/22] sh: Add board specific initialize of of-generic

FromRich Felker <dalias@libc.org>
Date2016-07-04 03:40 +0200
SubjectRe: [PATCH v5 10/22] sh: Add board specific initialize of of-generic
Message-ID<rR11D-7HN-3@gated-at.bofh.it>
In reply to#1435991
On Mon, Jul 04, 2016 at 01:46:30AM +0900, Yoshinori Sato wrote:
> Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
> ---
>  arch/sh/boards/of-generic.c | 64 +++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 64 insertions(+)
> 
> diff --git a/arch/sh/boards/of-generic.c b/arch/sh/boards/of-generic.c
> index 2d3cda3..4038682 100644
> --- a/arch/sh/boards/of-generic.c
> +++ b/arch/sh/boards/of-generic.c
> @@ -16,9 +16,15 @@
>  #include <linux/irqchip.h>
>  #include <linux/clk-provider.h>
>  #include <linux/memblock.h>
> +#include <linux/sm501-regs.h>
>  #include <asm/machvec.h>
>  #include <asm/rtc.h>
>  
> +struct model_setup {
> +	char *name;
> +	void (*fn)(void);
> +};
> +
>  #ifdef CONFIG_SMP
>  
>  static void dummy_smp_setup(void)
> @@ -125,10 +131,61 @@ static void __init sh_of_time_init(void)
>  	clocksource_probe();
>  }
>  
> +#define PA_LED		0xb0000001	/* LED Control Register */
> +#define PA_SHUTDOWN	0xb0000003	/* Shutdown Control Register */
> +static void landisk_power_off(void)
> +{
> +	__raw_writeb(0x01, PA_SHUTDOWN);
> +}
> +
> +static void __init landisk_setup(void)
> +{
> +	/* LED ON */
> +	__raw_writeb(__raw_readb(PA_LED) | 0x03, PA_LED);
> +	pm_power_off = landisk_power_off;
> +}
> +
> +#define PA_POWOFF	0xa4000030	/* Board Power OFF control */
> +#define PA_OUTPORT	0xa4000036	/* LED control */
> +static void rts7751r2d_power_off(void)
> +{
> +	__raw_writew(0x0001, PA_POWOFF);
> +}
> +
> +static void __init r2dplus_setup(void)
> +{
> +	void __iomem *sm501_reg;
> +
> +	__raw_writew(0x0000, PA_OUTPORT);
> +	pm_power_off = rts7751r2d_power_off;
> +
> +	/* sm501 dram configuration:
> +	 * ColSizeX = 11 - External Memory Column Size: 256 words.
> +	 * APX = 1 - External Memory Active to Pre-Charge Delay: 7 clocks.
> +	 * RstX = 1 - External Memory Reset: Normal.
> +	 * Rfsh = 1 - Local Memory Refresh to Command Delay: 12 clocks.
> +	 * BwC =  1 - Local Memory Block Write Cycle Time: 2 clocks.
> +	 * BwP =  1 - Local Memory Block Write to Pre-Charge Delay: 1 clock.
> +	 * AP = 1 - Internal Memory Active to Pre-Charge Delay: 7 clocks.
> +	 * Rst = 1 - Internal Memory Reset: Normal.
> +	 * RA = 1 - Internal Memory Remain in Active State: Do not remain.
> +	 */
> +
> +	sm501_reg = (void __iomem *)0xb3e00000 + SM501_DRAM_CONTROL;
> +	writel(readl(sm501_reg) | 0x00f107c0, sm501_reg);
> +}
> +
> +static const struct model_setup model_setup_table[] __initconst = {
> +	{ .name = "iodata,HDL-U", .fn = landisk_setup, },
> +	{ .name = "renesas,RTS7751R2D+", .fn = r2dplus_setup, },
> +	{},
> +};
> +
>  static void __init sh_of_setup(char **cmdline_p)
>  {
>  	struct device_node *root;
>  	struct device_node *cpu;
> +	const struct model_setup *setup;
>  	u32 freq;
>  
>  	board_time_init = sh_of_time_init;
> @@ -145,6 +202,13 @@ static void __init sh_of_setup(char **cmdline_p)
>  	cpu = of_find_node_by_name(NULL, "cpu");
>  	if (!of_property_read_u32(cpu, "clock-frequency", &freq))
>  		preset_lpj = freq / CONFIG_HZ / 2;
> +
> +	for (setup = model_setup_table; setup->name; setup++) {
> +		if (strcmp(setup->name, sh_mv.mv_name) == 0) {
> +			setup->fn();
> +			break;
> +		}
> +	}
>  }
>  
>  static int sh_of_irq_demux(int irq)
> -- 

I think all of this code should be in appropriate driver files, not
of-generic.c. Much of it looks like it should be pm (power management)
drivers for which I'd assume there's an existing framework. I'm not
sure about the DRAM control. For the LED I think there's an LED GPIO
framework already too that would be appropriate and that probably
only needs appropriate nodes in the DT, not even any code.

Rich

[toc] | [prev] | [next] | [standalone]


#1437765 — Re: [PATCH v5 10/22] sh: Add board specific initialize of of-generic

FromYoshinori Sato <ysato@users.sourceforge.jp>
Date2016-07-06 16:30 +0200
SubjectRe: [PATCH v5 10/22] sh: Add board specific initialize of of-generic
Message-ID<rRVZT-1T1-7@gated-at.bofh.it>
In reply to#1436103
On Mon, 04 Jul 2016 10:35:57 +0900,
Rich Felker wrote:
> 
> On Mon, Jul 04, 2016 at 01:46:30AM +0900, Yoshinori Sato wrote:
> > Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
> > ---
> >  arch/sh/boards/of-generic.c | 64 +++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 64 insertions(+)
> > 
> > diff --git a/arch/sh/boards/of-generic.c b/arch/sh/boards/of-generic.c
> > index 2d3cda3..4038682 100644
> > --- a/arch/sh/boards/of-generic.c
> > +++ b/arch/sh/boards/of-generic.c
> > @@ -16,9 +16,15 @@
> >  #include <linux/irqchip.h>
> >  #include <linux/clk-provider.h>
> >  #include <linux/memblock.h>
> > +#include <linux/sm501-regs.h>
> >  #include <asm/machvec.h>
> >  #include <asm/rtc.h>
> >  
> > +struct model_setup {
> > +	char *name;
> > +	void (*fn)(void);
> > +};
> > +
> >  #ifdef CONFIG_SMP
> >  
> >  static void dummy_smp_setup(void)
> > @@ -125,10 +131,61 @@ static void __init sh_of_time_init(void)
> >  	clocksource_probe();
> >  }
> >  
> > +#define PA_LED		0xb0000001	/* LED Control Register */
> > +#define PA_SHUTDOWN	0xb0000003	/* Shutdown Control Register */
> > +static void landisk_power_off(void)
> > +{
> > +	__raw_writeb(0x01, PA_SHUTDOWN);
> > +}
> > +
> > +static void __init landisk_setup(void)
> > +{
> > +	/* LED ON */
> > +	__raw_writeb(__raw_readb(PA_LED) | 0x03, PA_LED);
> > +	pm_power_off = landisk_power_off;
> > +}
> > +
> > +#define PA_POWOFF	0xa4000030	/* Board Power OFF control */
> > +#define PA_OUTPORT	0xa4000036	/* LED control */
> > +static void rts7751r2d_power_off(void)
> > +{
> > +	__raw_writew(0x0001, PA_POWOFF);
> > +}
> > +
> > +static void __init r2dplus_setup(void)
> > +{
> > +	void __iomem *sm501_reg;
> > +
> > +	__raw_writew(0x0000, PA_OUTPORT);
> > +	pm_power_off = rts7751r2d_power_off;
> > +
> > +	/* sm501 dram configuration:
> > +	 * ColSizeX = 11 - External Memory Column Size: 256 words.
> > +	 * APX = 1 - External Memory Active to Pre-Charge Delay: 7 clocks.
> > +	 * RstX = 1 - External Memory Reset: Normal.
> > +	 * Rfsh = 1 - Local Memory Refresh to Command Delay: 12 clocks.
> > +	 * BwC =  1 - Local Memory Block Write Cycle Time: 2 clocks.
> > +	 * BwP =  1 - Local Memory Block Write to Pre-Charge Delay: 1 clock.
> > +	 * AP = 1 - Internal Memory Active to Pre-Charge Delay: 7 clocks.
> > +	 * Rst = 1 - Internal Memory Reset: Normal.
> > +	 * RA = 1 - Internal Memory Remain in Active State: Do not remain.
> > +	 */
> > +
> > +	sm501_reg = (void __iomem *)0xb3e00000 + SM501_DRAM_CONTROL;
> > +	writel(readl(sm501_reg) | 0x00f107c0, sm501_reg);
> > +}
> > +
> > +static const struct model_setup model_setup_table[] __initconst = {
> > +	{ .name = "iodata,HDL-U", .fn = landisk_setup, },
> > +	{ .name = "renesas,RTS7751R2D+", .fn = r2dplus_setup, },
> > +	{},
> > +};
> > +
> >  static void __init sh_of_setup(char **cmdline_p)
> >  {
> >  	struct device_node *root;
> >  	struct device_node *cpu;
> > +	const struct model_setup *setup;
> >  	u32 freq;
> >  
> >  	board_time_init = sh_of_time_init;
> > @@ -145,6 +202,13 @@ static void __init sh_of_setup(char **cmdline_p)
> >  	cpu = of_find_node_by_name(NULL, "cpu");
> >  	if (!of_property_read_u32(cpu, "clock-frequency", &freq))
> >  		preset_lpj = freq / CONFIG_HZ / 2;
> > +
> > +	for (setup = model_setup_table; setup->name; setup++) {
> > +		if (strcmp(setup->name, sh_mv.mv_name) == 0) {
> > +			setup->fn();
> > +			break;
> > +		}
> > +	}
> >  }
> >  
> >  static int sh_of_irq_demux(int irq)
> > -- 
> 
> I think all of this code should be in appropriate driver files, not
> of-generic.c. Much of it looks like it should be pm (power management)
> drivers for which I'd assume there's an existing framework. I'm not
> sure about the DRAM control. For the LED I think there's an LED GPIO
> framework already too that would be appropriate and that probably
> only needs appropriate nodes in the DT, not even any code.
> 
> Rich

OK.
I'll separate code.

-- 
Yoshinori Sato
<ysato@users.sourceforge.jp>

[toc] | [prev] | [next] | [standalone]


#1435992 — [PATCH v5 08/22] sh: Disable board specific code on device tree mode

FromYoshinori Sato <ysato@users.sourceforge.jp>
Date2016-07-03 18:50 +0200
Subject[PATCH v5 08/22] sh: Disable board specific code on device tree mode
Message-ID<rQSKK-2yo-47@gated-at.bofh.it>
In reply to#1435986
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 arch/sh/Makefile                | 2 ++
 arch/sh/kernel/cpu/sh4/Makefile | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index 3b2c8b4..8adffa8 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -132,6 +132,7 @@ core-$(CONFIG_SH_FPU_EMU)	+= arch/sh/math-emu/
 
 core-$(CONFIG_USE_BUILTIN_DTB)	+= arch/sh/boot/dts/
 
+ifneq ($(CONFIG_SH_DEVICE_TREE),y)
 # Mach groups
 machdir-$(CONFIG_SOLUTION_ENGINE)		+= mach-se
 machdir-$(CONFIG_SH_HP6XX)			+= mach-hp6xx
@@ -152,6 +153,7 @@ machdir-$(CONFIG_SH_LANDISK)			+= mach-landisk
 machdir-$(CONFIG_SH_LBOX_RE2)			+= mach-lboxre2
 machdir-$(CONFIG_SH_CAYMAN)			+= mach-cayman
 machdir-$(CONFIG_SH_RSK)			+= mach-rsk
+endif
 
 ifneq ($(machdir-y),)
 core-y	+= $(addprefix arch/sh/boards/, \
diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile
index 3a1dbc7..b822c0c 100644
--- a/arch/sh/kernel/cpu/sh4/Makefile
+++ b/arch/sh/kernel/cpu/sh4/Makefile
@@ -14,6 +14,7 @@ perf-$(CONFIG_CPU_SUBTYPE_SH7750)	:= perf_event.o
 perf-$(CONFIG_CPU_SUBTYPE_SH7750S)	:= perf_event.o
 perf-$(CONFIG_CPU_SUBTYPE_SH7091)	:= perf_event.o
 
+ifndef CONFIG_OF
 # CPU subtype setup
 obj-$(CONFIG_CPU_SUBTYPE_SH7750)	+= setup-sh7750.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7750R)	+= setup-sh7750.o
@@ -31,6 +32,7 @@ endif
 
 # Additional clocks by subtype
 clock-$(CONFIG_CPU_SUBTYPE_SH4_202)	+= clock-sh4-202.o
+endif
 
 obj-y					+= $(clock-y)
 obj-$(CONFIG_PERF_EVENTS)		+= $(perf-y)
-- 
2.7.0

[toc] | [prev] | [next] | [standalone]


#1435993 — [PATCH v5 15/22] sh: Move common PCI stuff to arch/sh/kernel

FromYoshinori Sato <ysato@users.sourceforge.jp>
Date2016-07-03 18:50 +0200
Subject[PATCH v5 15/22] sh: Move common PCI stuff to arch/sh/kernel
Message-ID<rQSKK-2yo-37@gated-at.bofh.it>
In reply to#1435986
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 arch/sh/drivers/pci/Makefile |   2 -
 arch/sh/drivers/pci/common.c | 162 --------------------
 arch/sh/drivers/pci/pci.c    | 320 ----------------------------------------
 arch/sh/kernel/Makefile      |   2 +
 arch/sh/kernel/pci-common.c  | 162 ++++++++++++++++++++
 arch/sh/kernel/pci.c         | 342 +++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 506 insertions(+), 484 deletions(-)
 delete mode 100644 arch/sh/drivers/pci/common.c
 delete mode 100644 arch/sh/drivers/pci/pci.c
 create mode 100644 arch/sh/kernel/pci-common.c
 create mode 100644 arch/sh/kernel/pci.c

diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile
index 82f0a33..fffbede 100644
--- a/arch/sh/drivers/pci/Makefile
+++ b/arch/sh/drivers/pci/Makefile
@@ -1,8 +1,6 @@
 #
 # Makefile for the PCI specific kernel interface routines under Linux.
 #
-obj-y					+= common.o pci.o
-
 obj-$(CONFIG_CPU_SUBTYPE_SH7751)	+= pci-sh7751.o ops-sh4.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7751R)	+= pci-sh7751.o ops-sh4.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7763)	+= pci-sh7780.o ops-sh4.o
diff --git a/arch/sh/drivers/pci/common.c b/arch/sh/drivers/pci/common.c
deleted file mode 100644
index dbf1381..0000000
--- a/arch/sh/drivers/pci/common.c
+++ /dev/null
@@ -1,162 +0,0 @@
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#include <linux/kernel.h>
-
-/*
- * These functions are used early on before PCI scanning is done
- * and all of the pci_dev and pci_bus structures have been created.
- */
-static struct pci_dev *fake_pci_dev(struct pci_channel *hose,
-	int top_bus, int busnr, int devfn)
-{
-	static struct pci_dev dev;
-	static struct pci_bus bus;
-
-	dev.bus = &bus;
-	dev.sysdata = hose;
-	dev.devfn = devfn;
-	bus.number = busnr;
-	bus.sysdata = hose;
-	bus.ops = hose->pci_ops;
-
-	if(busnr != top_bus)
-		/* Fake a parent bus structure. */
-		bus.parent = &bus;
-	else
-		bus.parent = NULL;
-
-	return &dev;
-}
-
-#define EARLY_PCI_OP(rw, size, type)					\
-int __init early_##rw##_config_##size(struct pci_channel *hose,		\
-	int top_bus, int bus, int devfn, int offset, type value)	\
-{									\
-	return pci_##rw##_config_##size(				\
-		fake_pci_dev(hose, top_bus, bus, devfn),		\
-		offset, value);						\
-}
-
-EARLY_PCI_OP(read, byte, u8 *)
-EARLY_PCI_OP(read, word, u16 *)
-EARLY_PCI_OP(read, dword, u32 *)
-EARLY_PCI_OP(write, byte, u8)
-EARLY_PCI_OP(write, word, u16)
-EARLY_PCI_OP(write, dword, u32)
-
-int __init pci_is_66mhz_capable(struct pci_channel *hose,
-				int top_bus, int current_bus)
-{
-	u32 pci_devfn;
-	unsigned short vid;
-	int cap66 = -1;
-	u16 stat;
-
-	printk(KERN_INFO "PCI: Checking 66MHz capabilities...\n");
-
-	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
-		if (PCI_FUNC(pci_devfn))
-			continue;
-		if (early_read_config_word(hose, top_bus, current_bus,
-					   pci_devfn, PCI_VENDOR_ID, &vid) !=
-		    PCIBIOS_SUCCESSFUL)
-			continue;
-		if (vid == 0xffff)
-			continue;
-
-		/* check 66MHz capability */
-		if (cap66 < 0)
-			cap66 = 1;
-		if (cap66) {
-			early_read_config_word(hose, top_bus, current_bus,
-					       pci_devfn, PCI_STATUS, &stat);
-			if (!(stat & PCI_STATUS_66MHZ)) {
-				printk(KERN_DEBUG
-				       "PCI: %02x:%02x not 66MHz capable.\n",
-				       current_bus, pci_devfn);
-				cap66 = 0;
-				break;
-			}
-		}
-	}
-
-	return cap66 > 0;
-}
-
-static void pcibios_enable_err(unsigned long __data)
-{
-	struct pci_channel *hose = (struct pci_channel *)__data;
-
-	del_timer(&hose->err_timer);
-	printk(KERN_DEBUG "PCI: re-enabling error IRQ.\n");
-	enable_irq(hose->err_irq);
-}
-
-static void pcibios_enable_serr(unsigned long __data)
-{
-	struct pci_channel *hose = (struct pci_channel *)__data;
-
-	del_timer(&hose->serr_timer);
-	printk(KERN_DEBUG "PCI: re-enabling system error IRQ.\n");
-	enable_irq(hose->serr_irq);
-}
-
-void pcibios_enable_timers(struct pci_channel *hose)
-{
-	if (hose->err_irq) {
-		init_timer(&hose->err_timer);
-		hose->err_timer.data = (unsigned long)hose;
-		hose->err_timer.function = pcibios_enable_err;
-	}
-
-	if (hose->serr_irq) {
-		init_timer(&hose->serr_timer);
-		hose->serr_timer.data = (unsigned long)hose;
-		hose->serr_timer.function = pcibios_enable_serr;
-	}
-}
-
-/*
- * A simple handler for the regular PCI status errors, called from IRQ
- * context.
- */
-unsigned int pcibios_handle_status_errors(unsigned long addr,
-					  unsigned int status,
-					  struct pci_channel *hose)
-{
-	unsigned int cmd = 0;
-
-	if (status & PCI_STATUS_REC_MASTER_ABORT) {
-		printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n", addr);
-		cmd |= PCI_STATUS_REC_MASTER_ABORT;
-	}
-
-	if (status & PCI_STATUS_REC_TARGET_ABORT) {
-		printk(KERN_DEBUG "PCI: target abort: ");
-		pcibios_report_status(PCI_STATUS_REC_TARGET_ABORT |
-				      PCI_STATUS_SIG_TARGET_ABORT |
-				      PCI_STATUS_REC_MASTER_ABORT, 1);
-		printk("\n");
-
-		cmd |= PCI_STATUS_REC_TARGET_ABORT;
-	}
-
-	if (status & (PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY)) {
-		printk(KERN_DEBUG "PCI: parity error detected: ");
-		pcibios_report_status(PCI_STATUS_PARITY |
-				      PCI_STATUS_DETECTED_PARITY, 1);
-		printk("\n");
-
-		cmd |= PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY;
-
-		/* Now back off of the IRQ for awhile */
-		if (hose->err_irq) {
-			disable_irq_nosync(hose->err_irq);
-			hose->err_timer.expires = jiffies + HZ;
-			add_timer(&hose->err_timer);
-		}
-	}
-
-	return cmd;
-}
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
deleted file mode 100644
index d5462b7..0000000
--- a/arch/sh/drivers/pci/pci.c
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * New-style PCI core.
- *
- * Copyright (c) 2004 - 2009  Paul Mundt
- * Copyright (c) 2002  M. R. Brown
- *
- * Modelled after arch/mips/pci/pci.c:
- *  Copyright (C) 2003, 04 Ralf Baechle (ralf@linux-mips.org)
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/dma-debug.h>
-#include <linux/io.h>
-#include <linux/mutex.h>
-#include <linux/spinlock.h>
-#include <linux/export.h>
-
-unsigned long PCIBIOS_MIN_IO = 0x0000;
-unsigned long PCIBIOS_MIN_MEM = 0;
-
-/*
- * The PCI controller list.
- */
-static struct pci_channel *hose_head, **hose_tail = &hose_head;
-
-static int pci_initialized;
-
-static void pcibios_scanbus(struct pci_channel *hose)
-{
-	static int next_busno;
-	static int need_domain_info;
-	LIST_HEAD(resources);
-	struct resource *res;
-	resource_size_t offset;
-	int i;
-	struct pci_bus *bus;
-
-	for (i = 0; i < hose->nr_resources; i++) {
-		res = hose->resources + i;
-		offset = 0;
-		if (res->flags & IORESOURCE_IO)
-			offset = hose->io_offset;
-		else if (res->flags & IORESOURCE_MEM)
-			offset = hose->mem_offset;
-		pci_add_resource_offset(&resources, res, offset);
-	}
-
-	bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
-				&resources);
-	hose->bus = bus;
-
-	need_domain_info = need_domain_info || hose->index;
-	hose->need_domain_info = need_domain_info;
-
-	if (!bus) {
-		pci_free_resource_list(&resources);
-		return;
-	}
-
-	next_busno = bus->busn_res.end + 1;
-	/* Don't allow 8-bit bus number overflow inside the hose -
-	   reserve some space for bridges. */
-	if (next_busno > 224) {
-		next_busno = 0;
-		need_domain_info = 1;
-	}
-
-	pci_bus_size_bridges(bus);
-	pci_bus_assign_resources(bus);
-	pci_bus_add_devices(bus);
-}
-
-/*
- * This interrupt-safe spinlock protects all accesses to PCI
- * configuration space.
- */
-DEFINE_RAW_SPINLOCK(pci_config_lock);
-static DEFINE_MUTEX(pci_scan_mutex);
-
-int register_pci_controller(struct pci_channel *hose)
-{
-	int i;
-
-	for (i = 0; i < hose->nr_resources; i++) {
-		struct resource *res = hose->resources + i;
-
-		if (res->flags & IORESOURCE_IO) {
-			if (request_resource(&ioport_resource, res) < 0)
-				goto out;
-		} else {
-			if (request_resource(&iomem_resource, res) < 0)
-				goto out;
-		}
-	}
-
-	*hose_tail = hose;
-	hose_tail = &hose->next;
-
-	/*
-	 * Do not panic here but later - this might happen before console init.
-	 */
-	if (!hose->io_map_base) {
-		printk(KERN_WARNING
-		       "registering PCI controller with io_map_base unset\n");
-	}
-
-	/*
-	 * Setup the ERR/PERR and SERR timers, if available.
-	 */
-	pcibios_enable_timers(hose);
-
-	/*
-	 * Scan the bus if it is register after the PCI subsystem
-	 * initialization.
-	 */
-	if (pci_initialized) {
-		mutex_lock(&pci_scan_mutex);
-		pcibios_scanbus(hose);
-		mutex_unlock(&pci_scan_mutex);
-	}
-
-	return 0;
-
-out:
-	for (--i; i >= 0; i--)
-		release_resource(&hose->resources[i]);
-
-	printk(KERN_WARNING "Skipping PCI bus scan due to resource conflict\n");
-	return -1;
-}
-
-static int __init pcibios_init(void)
-{
-	struct pci_channel *hose;
-
-	/* Scan all of the recorded PCI controllers.  */
-	for (hose = hose_head; hose; hose = hose->next)
-		pcibios_scanbus(hose);
-
-	pci_fixup_irqs(pci_common_swizzle, pcibios_map_platform_irq);
-
-	dma_debug_add_bus(&pci_bus_type);
-
-	pci_initialized = 1;
-
-	return 0;
-}
-subsys_initcall(pcibios_init);
-
-/*
- *  Called after each bus is probed, but before its children
- *  are examined.
- */
-void pcibios_fixup_bus(struct pci_bus *bus)
-{
-}
-
-/*
- * We need to avoid collisions with `mirrored' VGA ports
- * and other strange ISA hardware, so we always want the
- * addresses to be allocated in the 0x000-0x0ff region
- * modulo 0x400.
- */
-resource_size_t pcibios_align_resource(void *data, const struct resource *res,
-				resource_size_t size, resource_size_t align)
-{
-	struct pci_dev *dev = data;
-	struct pci_channel *hose = dev->sysdata;
-	resource_size_t start = res->start;
-
-	if (res->flags & IORESOURCE_IO) {
-		if (start < PCIBIOS_MIN_IO + hose->resources[0].start)
-			start = PCIBIOS_MIN_IO + hose->resources[0].start;
-
-		/*
-                 * Put everything into 0x00-0xff region modulo 0x400.
-		 */
-		if (start & 0x300)
-			start = (start + 0x3ff) & ~0x3ff;
-	}
-
-	return start;
-}
-
-static void __init
-pcibios_bus_report_status_early(struct pci_channel *hose,
-				int top_bus, int current_bus,
-				unsigned int status_mask, int warn)
-{
-	unsigned int pci_devfn;
-	u16 status;
-	int ret;
-
-	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
-		if (PCI_FUNC(pci_devfn))
-			continue;
-		ret = early_read_config_word(hose, top_bus, current_bus,
-					     pci_devfn, PCI_STATUS, &status);
-		if (ret != PCIBIOS_SUCCESSFUL)
-			continue;
-		if (status == 0xffff)
-			continue;
-
-		early_write_config_word(hose, top_bus, current_bus,
-					pci_devfn, PCI_STATUS,
-					status & status_mask);
-		if (warn)
-			printk("(%02x:%02x: %04X) ", current_bus,
-			       pci_devfn, status);
-	}
-}
-
-/*
- * We can't use pci_find_device() here since we are
- * called from interrupt context.
- */
-static void __init_refok
-pcibios_bus_report_status(struct pci_bus *bus, unsigned int status_mask,
-			  int warn)
-{
-	struct pci_dev *dev;
-
-	list_for_each_entry(dev, &bus->devices, bus_list) {
-		u16 status;
-
-		/*
-		 * ignore host bridge - we handle
-		 * that separately
-		 */
-		if (dev->bus->number == 0 && dev->devfn == 0)
-			continue;
-
-		pci_read_config_word(dev, PCI_STATUS, &status);
-		if (status == 0xffff)
-			continue;
-
-		if ((status & status_mask) == 0)
-			continue;
-
-		/* clear the status errors */
-		pci_write_config_word(dev, PCI_STATUS, status & status_mask);
-
-		if (warn)
-			printk("(%s: %04X) ", pci_name(dev), status);
-	}
-
-	list_for_each_entry(dev, &bus->devices, bus_list)
-		if (dev->subordinate)
-			pcibios_bus_report_status(dev->subordinate, status_mask, warn);
-}
-
-void __init_refok pcibios_report_status(unsigned int status_mask, int warn)
-{
-	struct pci_channel *hose;
-
-	for (hose = hose_head; hose; hose = hose->next) {
-		if (unlikely(!hose->bus))
-			pcibios_bus_report_status_early(hose, hose_head->index,
-					hose->index, status_mask, warn);
-		else
-			pcibios_bus_report_status(hose->bus, status_mask, warn);
-	}
-}
-
-int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
-			enum pci_mmap_state mmap_state, int write_combine)
-{
-	/*
-	 * I/O space can be accessed via normal processor loads and stores on
-	 * this platform but for now we elect not to do this and portable
-	 * drivers should not do this anyway.
-	 */
-	if (mmap_state == pci_mmap_io)
-		return -EINVAL;
-
-	/*
-	 * Ignore write-combine; for now only return uncached mappings.
-	 */
-	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
-	return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
-			       vma->vm_end - vma->vm_start,
-			       vma->vm_page_prot);
-}
-
-#ifndef CONFIG_GENERIC_IOMAP
-
-void __iomem *__pci_ioport_map(struct pci_dev *dev,
-			       unsigned long port, unsigned int nr)
-{
-	struct pci_channel *chan = dev->sysdata;
-
-	if (unlikely(!chan->io_map_base)) {
-		chan->io_map_base = sh_io_port_base;
-
-		if (pci_domains_supported)
-			panic("To avoid data corruption io_map_base MUST be "
-			      "set with multiple PCI domains.");
-	}
-
-	return (void __iomem *)(chan->io_map_base + port);
-}
-
-void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
-{
-	iounmap(addr);
-}
-EXPORT_SYMBOL(pci_iounmap);
-
-#endif /* CONFIG_GENERIC_IOMAP */
-
-EXPORT_SYMBOL(PCIBIOS_MIN_IO);
-EXPORT_SYMBOL(PCIBIOS_MIN_MEM);
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index 09040fd..a9a54c2 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -46,5 +46,7 @@ obj-$(CONFIG_DWARF_UNWINDER)	+= dwarf.o
 obj-$(CONFIG_PERF_EVENTS)	+= perf_event.o perf_callchain.o
 
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)		+= hw_breakpoint.o
+obj-$(CONFIG_PCI)		+= pci.o pci-common.o
 
 ccflags-y := -Werror
+CFLAGS_pci.o := -O0
diff --git a/arch/sh/kernel/pci-common.c b/arch/sh/kernel/pci-common.c
new file mode 100644
index 0000000..dbf1381
--- /dev/null
+++ b/arch/sh/kernel/pci-common.c
@@ -0,0 +1,162 @@
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/kernel.h>
+
+/*
+ * These functions are used early on before PCI scanning is done
+ * and all of the pci_dev and pci_bus structures have been created.
+ */
+static struct pci_dev *fake_pci_dev(struct pci_channel *hose,
+	int top_bus, int busnr, int devfn)
+{
+	static struct pci_dev dev;
+	static struct pci_bus bus;
+
+	dev.bus = &bus;
+	dev.sysdata = hose;
+	dev.devfn = devfn;
+	bus.number = busnr;
+	bus.sysdata = hose;
+	bus.ops = hose->pci_ops;
+
+	if(busnr != top_bus)
+		/* Fake a parent bus structure. */
+		bus.parent = &bus;
+	else
+		bus.parent = NULL;
+
+	return &dev;
+}
+
+#define EARLY_PCI_OP(rw, size, type)					\
+int __init early_##rw##_config_##size(struct pci_channel *hose,		\
+	int top_bus, int bus, int devfn, int offset, type value)	\
+{									\
+	return pci_##rw##_config_##size(				\
+		fake_pci_dev(hose, top_bus, bus, devfn),		\
+		offset, value);						\
+}
+
+EARLY_PCI_OP(read, byte, u8 *)
+EARLY_PCI_OP(read, word, u16 *)
+EARLY_PCI_OP(read, dword, u32 *)
+EARLY_PCI_OP(write, byte, u8)
+EARLY_PCI_OP(write, word, u16)
+EARLY_PCI_OP(write, dword, u32)
+
+int __init pci_is_66mhz_capable(struct pci_channel *hose,
+				int top_bus, int current_bus)
+{
+	u32 pci_devfn;
+	unsigned short vid;
+	int cap66 = -1;
+	u16 stat;
+
+	printk(KERN_INFO "PCI: Checking 66MHz capabilities...\n");
+
+	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
+		if (PCI_FUNC(pci_devfn))
+			continue;
+		if (early_read_config_word(hose, top_bus, current_bus,
+					   pci_devfn, PCI_VENDOR_ID, &vid) !=
+		    PCIBIOS_SUCCESSFUL)
+			continue;
+		if (vid == 0xffff)
+			continue;
+
+		/* check 66MHz capability */
+		if (cap66 < 0)
+			cap66 = 1;
+		if (cap66) {
+			early_read_config_word(hose, top_bus, current_bus,
+					       pci_devfn, PCI_STATUS, &stat);
+			if (!(stat & PCI_STATUS_66MHZ)) {
+				printk(KERN_DEBUG
+				       "PCI: %02x:%02x not 66MHz capable.\n",
+				       current_bus, pci_devfn);
+				cap66 = 0;
+				break;
+			}
+		}
+	}
+
+	return cap66 > 0;
+}
+
+static void pcibios_enable_err(unsigned long __data)
+{
+	struct pci_channel *hose = (struct pci_channel *)__data;
+
+	del_timer(&hose->err_timer);
+	printk(KERN_DEBUG "PCI: re-enabling error IRQ.\n");
+	enable_irq(hose->err_irq);
+}
+
+static void pcibios_enable_serr(unsigned long __data)
+{
+	struct pci_channel *hose = (struct pci_channel *)__data;
+
+	del_timer(&hose->serr_timer);
+	printk(KERN_DEBUG "PCI: re-enabling system error IRQ.\n");
+	enable_irq(hose->serr_irq);
+}
+
+void pcibios_enable_timers(struct pci_channel *hose)
+{
+	if (hose->err_irq) {
+		init_timer(&hose->err_timer);
+		hose->err_timer.data = (unsigned long)hose;
+		hose->err_timer.function = pcibios_enable_err;
+	}
+
+	if (hose->serr_irq) {
+		init_timer(&hose->serr_timer);
+		hose->serr_timer.data = (unsigned long)hose;
+		hose->serr_timer.function = pcibios_enable_serr;
+	}
+}
+
+/*
+ * A simple handler for the regular PCI status errors, called from IRQ
+ * context.
+ */
+unsigned int pcibios_handle_status_errors(unsigned long addr,
+					  unsigned int status,
+					  struct pci_channel *hose)
+{
+	unsigned int cmd = 0;
+
+	if (status & PCI_STATUS_REC_MASTER_ABORT) {
+		printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n", addr);
+		cmd |= PCI_STATUS_REC_MASTER_ABORT;
+	}
+
+	if (status & PCI_STATUS_REC_TARGET_ABORT) {
+		printk(KERN_DEBUG "PCI: target abort: ");
+		pcibios_report_status(PCI_STATUS_REC_TARGET_ABORT |
+				      PCI_STATUS_SIG_TARGET_ABORT |
+				      PCI_STATUS_REC_MASTER_ABORT, 1);
+		printk("\n");
+
+		cmd |= PCI_STATUS_REC_TARGET_ABORT;
+	}
+
+	if (status & (PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY)) {
+		printk(KERN_DEBUG "PCI: parity error detected: ");
+		pcibios_report_status(PCI_STATUS_PARITY |
+				      PCI_STATUS_DETECTED_PARITY, 1);
+		printk("\n");
+
+		cmd |= PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY;
+
+		/* Now back off of the IRQ for awhile */
+		if (hose->err_irq) {
+			disable_irq_nosync(hose->err_irq);
+			hose->err_timer.expires = jiffies + HZ;
+			add_timer(&hose->err_timer);
+		}
+	}
+
+	return cmd;
+}
diff --git a/arch/sh/kernel/pci.c b/arch/sh/kernel/pci.c
new file mode 100644
index 0000000..9cf0ba4
--- /dev/null
+++ b/arch/sh/kernel/pci.c
@@ -0,0 +1,342 @@
+/*
+ * New-style PCI core.
+ *
+ * Copyright (c) 2004 - 2009  Paul Mundt
+ * Copyright (c) 2002  M. R. Brown
+ *
+ * Modelled after arch/mips/pci/pci.c:
+ *  Copyright (C) 2003, 04 Ralf Baechle (ralf@linux-mips.org)
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/dma-debug.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/export.h>
+
+unsigned long PCIBIOS_MIN_IO = 0x0000;
+unsigned long PCIBIOS_MIN_MEM = 0;
+
+/*
+ * The PCI controller list.
+ */
+static struct pci_channel *hose_head, **hose_tail = &hose_head;
+
+static int pci_initialized;
+
+static void pcibios_scanbus(struct pci_channel *hose)
+{
+	static int next_busno;
+	static int need_domain_info;
+	LIST_HEAD(resources);
+	struct resource *res;
+	resource_size_t offset;
+	int i;
+	struct pci_bus *bus;
+
+	for (i = 0; i < hose->nr_resources; i++) {
+		res = hose->resources + i;
+		offset = 0;
+		if (res->flags & IORESOURCE_IO)
+			offset = hose->io_offset;
+		else if (res->flags & IORESOURCE_MEM)
+			offset = hose->mem_offset;
+		pci_add_resource_offset(&resources, res, offset);
+	}
+
+	bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
+				&resources);
+	hose->bus = bus;
+
+	need_domain_info = need_domain_info || hose->index;
+	hose->need_domain_info = need_domain_info;
+
+	if (!bus) {
+		pci_free_resource_list(&resources);
+		return;
+	}
+
+	next_busno = bus->busn_res.end + 1;
+	/* Don't allow 8-bit bus number overflow inside the hose -
+	   reserve some space for bridges. */
+	if (next_busno > 224) {
+		next_busno = 0;
+		need_domain_info = 1;
+	}
+
+	pci_bus_size_bridges(bus);
+	pci_bus_assign_resources(bus);
+	pci_bus_add_devices(bus);
+}
+
+/*
+ * This interrupt-safe spinlock protects all accesses to PCI
+ * configuration space.
+ */
+DEFINE_RAW_SPINLOCK(pci_config_lock);
+static DEFINE_MUTEX(pci_scan_mutex);
+
+int register_pci_controller(struct pci_channel *hose)
+{
+	int i;
+
+	for (i = 0; i < hose->nr_resources; i++) {
+		struct resource *res = hose->resources + i;
+
+		if (res->flags & IORESOURCE_IO) {
+			if (request_resource(&ioport_resource, res) < 0)
+				goto out;
+		} else {
+			if (request_resource(&iomem_resource, res) < 0)
+				goto out;
+		}
+	}
+
+	*hose_tail = hose;
+	hose_tail = &hose->next;
+
+	/*
+	 * Do not panic here but later - this might happen before console init.
+	 */
+	if (!hose->io_map_base) {
+		printk(KERN_WARNING
+		       "registering PCI controller with io_map_base unset\n");
+	}
+
+	/*
+	 * Setup the ERR/PERR and SERR timers, if available.
+	 */
+	pcibios_enable_timers(hose);
+
+	/*
+	 * Scan the bus if it is register after the PCI subsystem
+	 * initialization.
+	 */
+	if (pci_initialized) {
+		mutex_lock(&pci_scan_mutex);
+		pcibios_scanbus(hose);
+		mutex_unlock(&pci_scan_mutex);
+	}
+
+	return 0;
+
+out:
+	for (--i; i >= 0; i--)
+		release_resource(&hose->resources[i]);
+
+	printk(KERN_WARNING "Skipping PCI bus scan due to resource conflict\n");
+	return -1;
+}
+
+#ifndef CONFIG_SH_DEVICE_TREE
+static int __init pcibios_init(void)
+{
+	struct pci_channel *hose;
+
+	/* Scan all of the recorded PCI controllers.  */
+	for (hose = hose_head; hose; hose = hose->next)
+		pcibios_scanbus(hose);
+
+	pci_fixup_irqs(pci_common_swizzle, pcibios_map_platform_irq);
+
+	dma_debug_add_bus(&pci_bus_type);
+
+	pci_initialized = 1;
+
+	return 0;
+}
+subsys_initcall(pcibios_init);
+#endif
+
+/*
+ *  Called after each bus is probed, but before its children
+ *  are examined.
+ */
+void pcibios_fixup_bus(struct pci_bus *bus)
+{
+}
+
+#ifndef CONFIG_SH_DEVICE_TREE
+/*
+ * We need to avoid collisions with `mirrored' VGA ports
+ * and other strange ISA hardware, so we always want the
+ * addresses to be allocated in the 0x000-0x0ff region
+ * modulo 0x400.
+ */
+resource_size_t pcibios_align_resource(void *data, const struct resource *res,
+				resource_size_t size, resource_size_t align)
+{
+	struct pci_dev *dev = data;
+	struct pci_channel *hose = dev->sysdata;
+	resource_size_t start = res->start;
+
+	if (res->flags & IORESOURCE_IO) {
+		if (start < PCIBIOS_MIN_IO + hose->resources[0].start)
+			start = PCIBIOS_MIN_IO + hose->resources[0].start;
+
+		/*
+                 * Put everything into 0x00-0xff region modulo 0x400.
+		 */
+		if (start & 0x300)
+			start = (start + 0x3ff) & ~0x3ff;
+	}
+
+	return start;
+}
+#else
+typedef resource_size_t (*align_resource_fn)(struct pci_dev *dev,
+					     const struct resource *res,
+					     resource_size_t start,
+					     resource_size_t size,
+					     resource_size_t align);
+
+resource_size_t pcibios_align_resource(void *data, const struct resource *res,
+				resource_size_t size, resource_size_t align)
+{
+	resource_size_t start = res->start;
+	struct pci_dev *dev = data;
+	struct pci_config_window *cfg = dev->sysdata;
+	align_resource_fn fn;
+
+	fn = (align_resource_fn)(cfg->priv);
+	return fn(dev, res, start, size, align);
+}
+#endif
+
+static void __init
+pcibios_bus_report_status_early(struct pci_channel *hose,
+				int top_bus, int current_bus,
+				unsigned int status_mask, int warn)
+{
+	unsigned int pci_devfn;
+	u16 status;
+	int ret;
+
+	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
+		if (PCI_FUNC(pci_devfn))
+			continue;
+		ret = early_read_config_word(hose, top_bus, current_bus,
+					     pci_devfn, PCI_STATUS, &status);
+		if (ret != PCIBIOS_SUCCESSFUL)
+			continue;
+		if (status == 0xffff)
+			continue;
+
+		early_write_config_word(hose, top_bus, current_bus,
+					pci_devfn, PCI_STATUS,
+					status & status_mask);
+		if (warn)
+			printk("(%02x:%02x: %04X) ", current_bus,
+			       pci_devfn, status);
+	}
+}
+
+/*
+ * We can't use pci_find_device() here since we are
+ * called from interrupt context.
+ */
+static void __init_refok
+pcibios_bus_report_status(struct pci_bus *bus, unsigned int status_mask,
+			  int warn)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		u16 status;
+
+		/*
+		 * ignore host bridge - we handle
+		 * that separately
+		 */
+		if (dev->bus->number == 0 && dev->devfn == 0)
+			continue;
+
+		pci_read_config_word(dev, PCI_STATUS, &status);
+		if (status == 0xffff)
+			continue;
+
+		if ((status & status_mask) == 0)
+			continue;
+
+		/* clear the status errors */
+		pci_write_config_word(dev, PCI_STATUS, status & status_mask);
+
+		if (warn)
+			printk("(%s: %04X) ", pci_name(dev), status);
+	}
+
+	list_for_each_entry(dev, &bus->devices, bus_list)
+		if (dev->subordinate)
+			pcibios_bus_report_status(dev->subordinate, status_mask, warn);
+}
+
+void __init_refok pcibios_report_status(unsigned int status_mask, int warn)
+{
+	struct pci_channel *hose;
+
+	for (hose = hose_head; hose; hose = hose->next) {
+		if (unlikely(!hose->bus))
+			pcibios_bus_report_status_early(hose, hose_head->index,
+					hose->index, status_mask, warn);
+		else
+			pcibios_bus_report_status(hose->bus, status_mask, warn);
+	}
+}
+
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+			enum pci_mmap_state mmap_state, int write_combine)
+{
+	/*
+	 * I/O space can be accessed via normal processor loads and stores on
+	 * this platform but for now we elect not to do this and portable
+	 * drivers should not do this anyway.
+	 */
+	if (mmap_state == pci_mmap_io)
+		return -EINVAL;
+
+	/*
+	 * Ignore write-combine; for now only return uncached mappings.
+	 */
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot);
+}
+
+#ifndef CONFIG_GENERIC_IOMAP
+
+void __iomem *__pci_ioport_map(struct pci_dev *dev,
+			       unsigned long port, unsigned int nr)
+{
+	struct pci_channel *chan = dev->sysdata;
+
+	if (unlikely(!chan->io_map_base)) {
+		chan->io_map_base = sh_io_port_base;
+
+		if (pci_domains_supported)
+			panic("To avoid data corruption io_map_base MUST be "
+			      "set with multiple PCI domains.");
+	}
+
+	return (void __iomem *)(chan->io_map_base + port);
+}
+
+void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
+{
+	iounmap(addr);
+}
+EXPORT_SYMBOL(pci_iounmap);
+
+#endif /* CONFIG_GENERIC_IOMAP */
+
+EXPORT_SYMBOL(PCIBIOS_MIN_IO);
+EXPORT_SYMBOL(PCIBIOS_MIN_MEM);
-- 
2.7.0

[toc] | [prev] | [next] | [standalone]


#1436111 — Re: [PATCH v5 15/22] sh: Move common PCI stuff to arch/sh/kernel

FromRich Felker <dalias@libc.org>
Date2016-07-04 04:00 +0200
SubjectRe: [PATCH v5 15/22] sh: Move common PCI stuff to arch/sh/kernel
Message-ID<rR1kZ-7Ok-1@gated-at.bofh.it>
In reply to#1435993
On Mon, Jul 04, 2016 at 01:46:35AM +0900, Yoshinori Sato wrote:
> Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
> ---
>  arch/sh/drivers/pci/Makefile |   2 -
>  arch/sh/drivers/pci/common.c | 162 --------------------
>  arch/sh/drivers/pci/pci.c    | 320 ----------------------------------------
>  arch/sh/kernel/Makefile      |   2 +
>  arch/sh/kernel/pci-common.c  | 162 ++++++++++++++++++++
>  arch/sh/kernel/pci.c         | 342 +++++++++++++++++++++++++++++++++++++++++++
>  6 files changed, 506 insertions(+), 484 deletions(-)
>  delete mode 100644 arch/sh/drivers/pci/common.c
>  delete mode 100644 arch/sh/drivers/pci/pci.c
>  create mode 100644 arch/sh/kernel/pci-common.c
>  create mode 100644 arch/sh/kernel/pci.c
> 
> diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile
> index 82f0a33..fffbede 100644
> --- a/arch/sh/drivers/pci/Makefile
> +++ b/arch/sh/drivers/pci/Makefile
> @@ -1,8 +1,6 @@
>  #
>  # Makefile for the PCI specific kernel interface routines under Linux.
>  #
> -obj-y					+= common.o pci.o
> -
>  obj-$(CONFIG_CPU_SUBTYPE_SH7751)	+= pci-sh7751.o ops-sh4.o
>  obj-$(CONFIG_CPU_SUBTYPE_SH7751R)	+= pci-sh7751.o ops-sh4.o
>  obj-$(CONFIG_CPU_SUBTYPE_SH7763)	+= pci-sh7780.o ops-sh4.o
> diff --git a/arch/sh/drivers/pci/common.c b/arch/sh/drivers/pci/common.c
> deleted file mode 100644
> index dbf1381..0000000
> --- a/arch/sh/drivers/pci/common.c
> +++ /dev/null
> @@ -1,162 +0,0 @@
> -#include <linux/pci.h>
> -#include <linux/interrupt.h>
> -#include <linux/timer.h>
> -#include <linux/kernel.h>
> -
> -/*
> - * These functions are used early on before PCI scanning is done
> - * and all of the pci_dev and pci_bus structures have been created.
> - */
> -static struct pci_dev *fake_pci_dev(struct pci_channel *hose,
> -	int top_bus, int busnr, int devfn)
> -{
> -	static struct pci_dev dev;
> -	static struct pci_bus bus;
> -
> -	dev.bus = &bus;
> -	dev.sysdata = hose;
> -	dev.devfn = devfn;
> -	bus.number = busnr;
> -	bus.sysdata = hose;
> -	bus.ops = hose->pci_ops;
> -
> -	if(busnr != top_bus)
> -		/* Fake a parent bus structure. */
> -		bus.parent = &bus;
> -	else
> -		bus.parent = NULL;
> -
> -	return &dev;
> -}
> -
> -#define EARLY_PCI_OP(rw, size, type)					\
> -int __init early_##rw##_config_##size(struct pci_channel *hose,		\
> -	int top_bus, int bus, int devfn, int offset, type value)	\
> -{									\
> -	return pci_##rw##_config_##size(				\
> -		fake_pci_dev(hose, top_bus, bus, devfn),		\
> -		offset, value);						\
> -}
> -
> -EARLY_PCI_OP(read, byte, u8 *)
> -EARLY_PCI_OP(read, word, u16 *)
> -EARLY_PCI_OP(read, dword, u32 *)
> -EARLY_PCI_OP(write, byte, u8)
> -EARLY_PCI_OP(write, word, u16)
> -EARLY_PCI_OP(write, dword, u32)
> -
> -int __init pci_is_66mhz_capable(struct pci_channel *hose,
> -				int top_bus, int current_bus)
> -{
> -	u32 pci_devfn;
> -	unsigned short vid;
> -	int cap66 = -1;
> -	u16 stat;
> -
> -	printk(KERN_INFO "PCI: Checking 66MHz capabilities...\n");
> -
> -	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
> -		if (PCI_FUNC(pci_devfn))
> -			continue;
> -		if (early_read_config_word(hose, top_bus, current_bus,
> -					   pci_devfn, PCI_VENDOR_ID, &vid) !=
> -		    PCIBIOS_SUCCESSFUL)
> -			continue;
> -		if (vid == 0xffff)
> -			continue;
> -
> -		/* check 66MHz capability */
> -		if (cap66 < 0)
> -			cap66 = 1;
> -		if (cap66) {
> -			early_read_config_word(hose, top_bus, current_bus,
> -					       pci_devfn, PCI_STATUS, &stat);
> -			if (!(stat & PCI_STATUS_66MHZ)) {
> -				printk(KERN_DEBUG
> -				       "PCI: %02x:%02x not 66MHz capable.\n",
> -				       current_bus, pci_devfn);
> -				cap66 = 0;
> -				break;
> -			}
> -		}
> -	}
> -
> -	return cap66 > 0;
> -}
> -
> -static void pcibios_enable_err(unsigned long __data)
> -{
> -	struct pci_channel *hose = (struct pci_channel *)__data;
> -
> -	del_timer(&hose->err_timer);
> -	printk(KERN_DEBUG "PCI: re-enabling error IRQ.\n");
> -	enable_irq(hose->err_irq);
> -}
> -
> -static void pcibios_enable_serr(unsigned long __data)
> -{
> -	struct pci_channel *hose = (struct pci_channel *)__data;
> -
> -	del_timer(&hose->serr_timer);
> -	printk(KERN_DEBUG "PCI: re-enabling system error IRQ.\n");
> -	enable_irq(hose->serr_irq);
> -}
> -
> -void pcibios_enable_timers(struct pci_channel *hose)
> -{
> -	if (hose->err_irq) {
> -		init_timer(&hose->err_timer);
> -		hose->err_timer.data = (unsigned long)hose;
> -		hose->err_timer.function = pcibios_enable_err;
> -	}
> -
> -	if (hose->serr_irq) {
> -		init_timer(&hose->serr_timer);
> -		hose->serr_timer.data = (unsigned long)hose;
> -		hose->serr_timer.function = pcibios_enable_serr;
> -	}
> -}
> -
> -/*
> - * A simple handler for the regular PCI status errors, called from IRQ
> - * context.
> - */
> -unsigned int pcibios_handle_status_errors(unsigned long addr,
> -					  unsigned int status,
> -					  struct pci_channel *hose)
> -{
> -	unsigned int cmd = 0;
> -
> -	if (status & PCI_STATUS_REC_MASTER_ABORT) {
> -		printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n", addr);
> -		cmd |= PCI_STATUS_REC_MASTER_ABORT;
> -	}
> -
> -	if (status & PCI_STATUS_REC_TARGET_ABORT) {
> -		printk(KERN_DEBUG "PCI: target abort: ");
> -		pcibios_report_status(PCI_STATUS_REC_TARGET_ABORT |
> -				      PCI_STATUS_SIG_TARGET_ABORT |
> -				      PCI_STATUS_REC_MASTER_ABORT, 1);
> -		printk("\n");
> -
> -		cmd |= PCI_STATUS_REC_TARGET_ABORT;
> -	}
> -
> -	if (status & (PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY)) {
> -		printk(KERN_DEBUG "PCI: parity error detected: ");
> -		pcibios_report_status(PCI_STATUS_PARITY |
> -				      PCI_STATUS_DETECTED_PARITY, 1);
> -		printk("\n");
> -
> -		cmd |= PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY;
> -
> -		/* Now back off of the IRQ for awhile */
> -		if (hose->err_irq) {
> -			disable_irq_nosync(hose->err_irq);
> -			hose->err_timer.expires = jiffies + HZ;
> -			add_timer(&hose->err_timer);
> -		}
> -	}
> -
> -	return cmd;
> -}
> diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
> deleted file mode 100644
> index d5462b7..0000000
> --- a/arch/sh/drivers/pci/pci.c
> +++ /dev/null
> @@ -1,320 +0,0 @@
> -/*
> - * New-style PCI core.
> - *
> - * Copyright (c) 2004 - 2009  Paul Mundt
> - * Copyright (c) 2002  M. R. Brown
> - *
> - * Modelled after arch/mips/pci/pci.c:
> - *  Copyright (C) 2003, 04 Ralf Baechle (ralf@linux-mips.org)
> - *
> - * This file is subject to the terms and conditions of the GNU General Public
> - * License.  See the file "COPYING" in the main directory of this archive
> - * for more details.
> - */
> -#include <linux/kernel.h>
> -#include <linux/mm.h>
> -#include <linux/pci.h>
> -#include <linux/init.h>
> -#include <linux/types.h>
> -#include <linux/dma-debug.h>
> -#include <linux/io.h>
> -#include <linux/mutex.h>
> -#include <linux/spinlock.h>
> -#include <linux/export.h>
> -
> -unsigned long PCIBIOS_MIN_IO = 0x0000;
> -unsigned long PCIBIOS_MIN_MEM = 0;
> -
> -/*
> - * The PCI controller list.
> - */
> -static struct pci_channel *hose_head, **hose_tail = &hose_head;
> -
> -static int pci_initialized;
> -
> -static void pcibios_scanbus(struct pci_channel *hose)
> -{
> -	static int next_busno;
> -	static int need_domain_info;
> -	LIST_HEAD(resources);
> -	struct resource *res;
> -	resource_size_t offset;
> -	int i;
> -	struct pci_bus *bus;
> -
> -	for (i = 0; i < hose->nr_resources; i++) {
> -		res = hose->resources + i;
> -		offset = 0;
> -		if (res->flags & IORESOURCE_IO)
> -			offset = hose->io_offset;
> -		else if (res->flags & IORESOURCE_MEM)
> -			offset = hose->mem_offset;
> -		pci_add_resource_offset(&resources, res, offset);
> -	}
> -
> -	bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
> -				&resources);
> -	hose->bus = bus;
> -
> -	need_domain_info = need_domain_info || hose->index;
> -	hose->need_domain_info = need_domain_info;
> -
> -	if (!bus) {
> -		pci_free_resource_list(&resources);
> -		return;
> -	}
> -
> -	next_busno = bus->busn_res.end + 1;
> -	/* Don't allow 8-bit bus number overflow inside the hose -
> -	   reserve some space for bridges. */
> -	if (next_busno > 224) {
> -		next_busno = 0;
> -		need_domain_info = 1;
> -	}
> -
> -	pci_bus_size_bridges(bus);
> -	pci_bus_assign_resources(bus);
> -	pci_bus_add_devices(bus);
> -}
> -
> -/*
> - * This interrupt-safe spinlock protects all accesses to PCI
> - * configuration space.
> - */
> -DEFINE_RAW_SPINLOCK(pci_config_lock);
> -static DEFINE_MUTEX(pci_scan_mutex);
> -
> -int register_pci_controller(struct pci_channel *hose)
> -{
> -	int i;
> -
> -	for (i = 0; i < hose->nr_resources; i++) {
> -		struct resource *res = hose->resources + i;
> -
> -		if (res->flags & IORESOURCE_IO) {
> -			if (request_resource(&ioport_resource, res) < 0)
> -				goto out;
> -		} else {
> -			if (request_resource(&iomem_resource, res) < 0)
> -				goto out;
> -		}
> -	}
> -
> -	*hose_tail = hose;
> -	hose_tail = &hose->next;
> -
> -	/*
> -	 * Do not panic here but later - this might happen before console init.
> -	 */
> -	if (!hose->io_map_base) {
> -		printk(KERN_WARNING
> -		       "registering PCI controller with io_map_base unset\n");
> -	}
> -
> -	/*
> -	 * Setup the ERR/PERR and SERR timers, if available.
> -	 */
> -	pcibios_enable_timers(hose);
> -
> -	/*
> -	 * Scan the bus if it is register after the PCI subsystem
> -	 * initialization.
> -	 */
> -	if (pci_initialized) {
> -		mutex_lock(&pci_scan_mutex);
> -		pcibios_scanbus(hose);
> -		mutex_unlock(&pci_scan_mutex);
> -	}
> -
> -	return 0;
> -
> -out:
> -	for (--i; i >= 0; i--)
> -		release_resource(&hose->resources[i]);
> -
> -	printk(KERN_WARNING "Skipping PCI bus scan due to resource conflict\n");
> -	return -1;
> -}
> -
> -static int __init pcibios_init(void)
> -{
> -	struct pci_channel *hose;
> -
> -	/* Scan all of the recorded PCI controllers.  */
> -	for (hose = hose_head; hose; hose = hose->next)
> -		pcibios_scanbus(hose);
> -
> -	pci_fixup_irqs(pci_common_swizzle, pcibios_map_platform_irq);
> -
> -	dma_debug_add_bus(&pci_bus_type);
> -
> -	pci_initialized = 1;
> -
> -	return 0;
> -}
> -subsys_initcall(pcibios_init);
> -
> -/*
> - *  Called after each bus is probed, but before its children
> - *  are examined.
> - */
> -void pcibios_fixup_bus(struct pci_bus *bus)
> -{
> -}
> -
> -/*
> - * We need to avoid collisions with `mirrored' VGA ports
> - * and other strange ISA hardware, so we always want the
> - * addresses to be allocated in the 0x000-0x0ff region
> - * modulo 0x400.
> - */
> -resource_size_t pcibios_align_resource(void *data, const struct resource *res,
> -				resource_size_t size, resource_size_t align)
> -{
> -	struct pci_dev *dev = data;
> -	struct pci_channel *hose = dev->sysdata;
> -	resource_size_t start = res->start;
> -
> -	if (res->flags & IORESOURCE_IO) {
> -		if (start < PCIBIOS_MIN_IO + hose->resources[0].start)
> -			start = PCIBIOS_MIN_IO + hose->resources[0].start;
> -
> -		/*
> -                 * Put everything into 0x00-0xff region modulo 0x400.
> -		 */
> -		if (start & 0x300)
> -			start = (start + 0x3ff) & ~0x3ff;
> -	}
> -
> -	return start;
> -}
> -
> -static void __init
> -pcibios_bus_report_status_early(struct pci_channel *hose,
> -				int top_bus, int current_bus,
> -				unsigned int status_mask, int warn)
> -{
> -	unsigned int pci_devfn;
> -	u16 status;
> -	int ret;
> -
> -	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
> -		if (PCI_FUNC(pci_devfn))
> -			continue;
> -		ret = early_read_config_word(hose, top_bus, current_bus,
> -					     pci_devfn, PCI_STATUS, &status);
> -		if (ret != PCIBIOS_SUCCESSFUL)
> -			continue;
> -		if (status == 0xffff)
> -			continue;
> -
> -		early_write_config_word(hose, top_bus, current_bus,
> -					pci_devfn, PCI_STATUS,
> -					status & status_mask);
> -		if (warn)
> -			printk("(%02x:%02x: %04X) ", current_bus,
> -			       pci_devfn, status);
> -	}
> -}
> -
> -/*
> - * We can't use pci_find_device() here since we are
> - * called from interrupt context.
> - */
> -static void __init_refok
> -pcibios_bus_report_status(struct pci_bus *bus, unsigned int status_mask,
> -			  int warn)
> -{
> -	struct pci_dev *dev;
> -
> -	list_for_each_entry(dev, &bus->devices, bus_list) {
> -		u16 status;
> -
> -		/*
> -		 * ignore host bridge - we handle
> -		 * that separately
> -		 */
> -		if (dev->bus->number == 0 && dev->devfn == 0)
> -			continue;
> -
> -		pci_read_config_word(dev, PCI_STATUS, &status);
> -		if (status == 0xffff)
> -			continue;
> -
> -		if ((status & status_mask) == 0)
> -			continue;
> -
> -		/* clear the status errors */
> -		pci_write_config_word(dev, PCI_STATUS, status & status_mask);
> -
> -		if (warn)
> -			printk("(%s: %04X) ", pci_name(dev), status);
> -	}
> -
> -	list_for_each_entry(dev, &bus->devices, bus_list)
> -		if (dev->subordinate)
> -			pcibios_bus_report_status(dev->subordinate, status_mask, warn);
> -}
> -
> -void __init_refok pcibios_report_status(unsigned int status_mask, int warn)
> -{
> -	struct pci_channel *hose;
> -
> -	for (hose = hose_head; hose; hose = hose->next) {
> -		if (unlikely(!hose->bus))
> -			pcibios_bus_report_status_early(hose, hose_head->index,
> -					hose->index, status_mask, warn);
> -		else
> -			pcibios_bus_report_status(hose->bus, status_mask, warn);
> -	}
> -}
> -
> -int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
> -			enum pci_mmap_state mmap_state, int write_combine)
> -{
> -	/*
> -	 * I/O space can be accessed via normal processor loads and stores on
> -	 * this platform but for now we elect not to do this and portable
> -	 * drivers should not do this anyway.
> -	 */
> -	if (mmap_state == pci_mmap_io)
> -		return -EINVAL;
> -
> -	/*
> -	 * Ignore write-combine; for now only return uncached mappings.
> -	 */
> -	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
> -
> -	return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
> -			       vma->vm_end - vma->vm_start,
> -			       vma->vm_page_prot);
> -}
> -
> -#ifndef CONFIG_GENERIC_IOMAP
> -
> -void __iomem *__pci_ioport_map(struct pci_dev *dev,
> -			       unsigned long port, unsigned int nr)
> -{
> -	struct pci_channel *chan = dev->sysdata;
> -
> -	if (unlikely(!chan->io_map_base)) {
> -		chan->io_map_base = sh_io_port_base;
> -
> -		if (pci_domains_supported)
> -			panic("To avoid data corruption io_map_base MUST be "
> -			      "set with multiple PCI domains.");
> -	}
> -
> -	return (void __iomem *)(chan->io_map_base + port);
> -}
> -
> -void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
> -{
> -	iounmap(addr);
> -}
> -EXPORT_SYMBOL(pci_iounmap);
> -
> -#endif /* CONFIG_GENERIC_IOMAP */
> -
> -EXPORT_SYMBOL(PCIBIOS_MIN_IO);
> -EXPORT_SYMBOL(PCIBIOS_MIN_MEM);
> diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
> index 09040fd..a9a54c2 100644
> --- a/arch/sh/kernel/Makefile
> +++ b/arch/sh/kernel/Makefile
> @@ -46,5 +46,7 @@ obj-$(CONFIG_DWARF_UNWINDER)	+= dwarf.o
>  obj-$(CONFIG_PERF_EVENTS)	+= perf_event.o perf_callchain.o
>  
>  obj-$(CONFIG_HAVE_HW_BREAKPOINT)		+= hw_breakpoint.o
> +obj-$(CONFIG_PCI)		+= pci.o pci-common.o
>  
>  ccflags-y := -Werror
> +CFLAGS_pci.o := -O0
> diff --git a/arch/sh/kernel/pci-common.c b/arch/sh/kernel/pci-common.c
> new file mode 100644
> index 0000000..dbf1381
> --- /dev/null
> +++ b/arch/sh/kernel/pci-common.c
> @@ -0,0 +1,162 @@
> +#include <linux/pci.h>
> +#include <linux/interrupt.h>
> +#include <linux/timer.h>
> +#include <linux/kernel.h>
> +
> +/*
> + * These functions are used early on before PCI scanning is done
> + * and all of the pci_dev and pci_bus structures have been created.
> + */
> +static struct pci_dev *fake_pci_dev(struct pci_channel *hose,
> +	int top_bus, int busnr, int devfn)
> +{
> +	static struct pci_dev dev;
> +	static struct pci_bus bus;
> +
> +	dev.bus = &bus;
> +	dev.sysdata = hose;
> +	dev.devfn = devfn;
> +	bus.number = busnr;
> +	bus.sysdata = hose;
> +	bus.ops = hose->pci_ops;
> +
> +	if(busnr != top_bus)
> +		/* Fake a parent bus structure. */
> +		bus.parent = &bus;
> +	else
> +		bus.parent = NULL;
> +
> +	return &dev;
> +}
> +
> +#define EARLY_PCI_OP(rw, size, type)					\
> +int __init early_##rw##_config_##size(struct pci_channel *hose,		\
> +	int top_bus, int bus, int devfn, int offset, type value)	\
> +{									\
> +	return pci_##rw##_config_##size(				\
> +		fake_pci_dev(hose, top_bus, bus, devfn),		\
> +		offset, value);						\
> +}
> +
> +EARLY_PCI_OP(read, byte, u8 *)
> +EARLY_PCI_OP(read, word, u16 *)
> +EARLY_PCI_OP(read, dword, u32 *)
> +EARLY_PCI_OP(write, byte, u8)
> +EARLY_PCI_OP(write, word, u16)
> +EARLY_PCI_OP(write, dword, u32)
> +
> +int __init pci_is_66mhz_capable(struct pci_channel *hose,
> +				int top_bus, int current_bus)
> +{
> +	u32 pci_devfn;
> +	unsigned short vid;
> +	int cap66 = -1;
> +	u16 stat;
> +
> +	printk(KERN_INFO "PCI: Checking 66MHz capabilities...\n");
> +
> +	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
> +		if (PCI_FUNC(pci_devfn))
> +			continue;
> +		if (early_read_config_word(hose, top_bus, current_bus,
> +					   pci_devfn, PCI_VENDOR_ID, &vid) !=
> +		    PCIBIOS_SUCCESSFUL)
> +			continue;
> +		if (vid == 0xffff)
> +			continue;
> +
> +		/* check 66MHz capability */
> +		if (cap66 < 0)
> +			cap66 = 1;
> +		if (cap66) {
> +			early_read_config_word(hose, top_bus, current_bus,
> +					       pci_devfn, PCI_STATUS, &stat);
> +			if (!(stat & PCI_STATUS_66MHZ)) {
> +				printk(KERN_DEBUG
> +				       "PCI: %02x:%02x not 66MHz capable.\n",
> +				       current_bus, pci_devfn);
> +				cap66 = 0;
> +				break;
> +			}
> +		}
> +	}
> +
> +	return cap66 > 0;
> +}
> +
> +static void pcibios_enable_err(unsigned long __data)
> +{
> +	struct pci_channel *hose = (struct pci_channel *)__data;
> +
> +	del_timer(&hose->err_timer);
> +	printk(KERN_DEBUG "PCI: re-enabling error IRQ.\n");
> +	enable_irq(hose->err_irq);
> +}
> +
> +static void pcibios_enable_serr(unsigned long __data)
> +{
> +	struct pci_channel *hose = (struct pci_channel *)__data;
> +
> +	del_timer(&hose->serr_timer);
> +	printk(KERN_DEBUG "PCI: re-enabling system error IRQ.\n");
> +	enable_irq(hose->serr_irq);
> +}
> +
> +void pcibios_enable_timers(struct pci_channel *hose)
> +{
> +	if (hose->err_irq) {
> +		init_timer(&hose->err_timer);
> +		hose->err_timer.data = (unsigned long)hose;
> +		hose->err_timer.function = pcibios_enable_err;
> +	}
> +
> +	if (hose->serr_irq) {
> +		init_timer(&hose->serr_timer);
> +		hose->serr_timer.data = (unsigned long)hose;
> +		hose->serr_timer.function = pcibios_enable_serr;
> +	}
> +}
> +
> +/*
> + * A simple handler for the regular PCI status errors, called from IRQ
> + * context.
> + */
> +unsigned int pcibios_handle_status_errors(unsigned long addr,
> +					  unsigned int status,
> +					  struct pci_channel *hose)
> +{
> +	unsigned int cmd = 0;
> +
> +	if (status & PCI_STATUS_REC_MASTER_ABORT) {
> +		printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n", addr);
> +		cmd |= PCI_STATUS_REC_MASTER_ABORT;
> +	}
> +
> +	if (status & PCI_STATUS_REC_TARGET_ABORT) {
> +		printk(KERN_DEBUG "PCI: target abort: ");
> +		pcibios_report_status(PCI_STATUS_REC_TARGET_ABORT |
> +				      PCI_STATUS_SIG_TARGET_ABORT |
> +				      PCI_STATUS_REC_MASTER_ABORT, 1);
> +		printk("\n");
> +
> +		cmd |= PCI_STATUS_REC_TARGET_ABORT;
> +	}
> +
> +	if (status & (PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY)) {
> +		printk(KERN_DEBUG "PCI: parity error detected: ");
> +		pcibios_report_status(PCI_STATUS_PARITY |
> +				      PCI_STATUS_DETECTED_PARITY, 1);
> +		printk("\n");
> +
> +		cmd |= PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY;
> +
> +		/* Now back off of the IRQ for awhile */
> +		if (hose->err_irq) {
> +			disable_irq_nosync(hose->err_irq);
> +			hose->err_timer.expires = jiffies + HZ;
> +			add_timer(&hose->err_timer);
> +		}
> +	}
> +
> +	return cmd;
> +}
> diff --git a/arch/sh/kernel/pci.c b/arch/sh/kernel/pci.c
> new file mode 100644
> index 0000000..9cf0ba4
> --- /dev/null
> +++ b/arch/sh/kernel/pci.c
> @@ -0,0 +1,342 @@
> +/*
> + * New-style PCI core.
> + *
> + * Copyright (c) 2004 - 2009  Paul Mundt
> + * Copyright (c) 2002  M. R. Brown
> + *
> + * Modelled after arch/mips/pci/pci.c:
> + *  Copyright (C) 2003, 04 Ralf Baechle (ralf@linux-mips.org)
> + *
> + * This file is subject to the terms and conditions of the GNU General Public
> + * License.  See the file "COPYING" in the main directory of this archive
> + * for more details.
> + */
> +#include <linux/kernel.h>
> +#include <linux/mm.h>
> +#include <linux/pci.h>
> +#include <linux/init.h>
> +#include <linux/types.h>
> +#include <linux/dma-debug.h>
> +#include <linux/io.h>
> +#include <linux/mutex.h>
> +#include <linux/spinlock.h>
> +#include <linux/export.h>
> +
> +unsigned long PCIBIOS_MIN_IO = 0x0000;
> +unsigned long PCIBIOS_MIN_MEM = 0;
> +
> +/*
> + * The PCI controller list.
> + */
> +static struct pci_channel *hose_head, **hose_tail = &hose_head;
> +
> +static int pci_initialized;
> +
> +static void pcibios_scanbus(struct pci_channel *hose)
> +{
> +	static int next_busno;
> +	static int need_domain_info;
> +	LIST_HEAD(resources);
> +	struct resource *res;
> +	resource_size_t offset;
> +	int i;
> +	struct pci_bus *bus;
> +
> +	for (i = 0; i < hose->nr_resources; i++) {
> +		res = hose->resources + i;
> +		offset = 0;
> +		if (res->flags & IORESOURCE_IO)
> +			offset = hose->io_offset;
> +		else if (res->flags & IORESOURCE_MEM)
> +			offset = hose->mem_offset;
> +		pci_add_resource_offset(&resources, res, offset);
> +	}
> +
> +	bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
> +				&resources);
> +	hose->bus = bus;
> +
> +	need_domain_info = need_domain_info || hose->index;
> +	hose->need_domain_info = need_domain_info;
> +
> +	if (!bus) {
> +		pci_free_resource_list(&resources);
> +		return;
> +	}
> +
> +	next_busno = bus->busn_res.end + 1;
> +	/* Don't allow 8-bit bus number overflow inside the hose -
> +	   reserve some space for bridges. */
> +	if (next_busno > 224) {
> +		next_busno = 0;
> +		need_domain_info = 1;
> +	}
> +
> +	pci_bus_size_bridges(bus);
> +	pci_bus_assign_resources(bus);
> +	pci_bus_add_devices(bus);
> +}
> +
> +/*
> + * This interrupt-safe spinlock protects all accesses to PCI
> + * configuration space.
> + */
> +DEFINE_RAW_SPINLOCK(pci_config_lock);
> +static DEFINE_MUTEX(pci_scan_mutex);
> +
> +int register_pci_controller(struct pci_channel *hose)
> +{
> +	int i;
> +
> +	for (i = 0; i < hose->nr_resources; i++) {
> +		struct resource *res = hose->resources + i;
> +
> +		if (res->flags & IORESOURCE_IO) {
> +			if (request_resource(&ioport_resource, res) < 0)
> +				goto out;
> +		} else {
> +			if (request_resource(&iomem_resource, res) < 0)
> +				goto out;
> +		}
> +	}
> +
> +	*hose_tail = hose;
> +	hose_tail = &hose->next;
> +
> +	/*
> +	 * Do not panic here but later - this might happen before console init.
> +	 */
> +	if (!hose->io_map_base) {
> +		printk(KERN_WARNING
> +		       "registering PCI controller with io_map_base unset\n");
> +	}
> +
> +	/*
> +	 * Setup the ERR/PERR and SERR timers, if available.
> +	 */
> +	pcibios_enable_timers(hose);
> +
> +	/*
> +	 * Scan the bus if it is register after the PCI subsystem
> +	 * initialization.
> +	 */
> +	if (pci_initialized) {
> +		mutex_lock(&pci_scan_mutex);
> +		pcibios_scanbus(hose);
> +		mutex_unlock(&pci_scan_mutex);
> +	}
> +
> +	return 0;
> +
> +out:
> +	for (--i; i >= 0; i--)
> +		release_resource(&hose->resources[i]);
> +
> +	printk(KERN_WARNING "Skipping PCI bus scan due to resource conflict\n");
> +	return -1;
> +}
> +
> +#ifndef CONFIG_SH_DEVICE_TREE
> +static int __init pcibios_init(void)
> +{
> +	struct pci_channel *hose;
> +
> +	/* Scan all of the recorded PCI controllers.  */
> +	for (hose = hose_head; hose; hose = hose->next)
> +		pcibios_scanbus(hose);
> +
> +	pci_fixup_irqs(pci_common_swizzle, pcibios_map_platform_irq);
> +
> +	dma_debug_add_bus(&pci_bus_type);
> +
> +	pci_initialized = 1;
> +
> +	return 0;
> +}
> +subsys_initcall(pcibios_init);
> +#endif
> +
> +/*
> + *  Called after each bus is probed, but before its children
> + *  are examined.
> + */
> +void pcibios_fixup_bus(struct pci_bus *bus)
> +{
> +}
> +
> +#ifndef CONFIG_SH_DEVICE_TREE
> +/*
> + * We need to avoid collisions with `mirrored' VGA ports
> + * and other strange ISA hardware, so we always want the
> + * addresses to be allocated in the 0x000-0x0ff region
> + * modulo 0x400.
> + */
> +resource_size_t pcibios_align_resource(void *data, const struct resource *res,
> +				resource_size_t size, resource_size_t align)
> +{
> +	struct pci_dev *dev = data;
> +	struct pci_channel *hose = dev->sysdata;
> +	resource_size_t start = res->start;
> +
> +	if (res->flags & IORESOURCE_IO) {
> +		if (start < PCIBIOS_MIN_IO + hose->resources[0].start)
> +			start = PCIBIOS_MIN_IO + hose->resources[0].start;
> +
> +		/*
> +                 * Put everything into 0x00-0xff region modulo 0x400.
> +		 */
> +		if (start & 0x300)
> +			start = (start + 0x3ff) & ~0x3ff;
> +	}
> +
> +	return start;
> +}
> +#else
> +typedef resource_size_t (*align_resource_fn)(struct pci_dev *dev,
> +					     const struct resource *res,
> +					     resource_size_t start,
> +					     resource_size_t size,
> +					     resource_size_t align);
> +
> +resource_size_t pcibios_align_resource(void *data, const struct resource *res,
> +				resource_size_t size, resource_size_t align)
> +{
> +	resource_size_t start = res->start;
> +	struct pci_dev *dev = data;
> +	struct pci_config_window *cfg = dev->sysdata;
> +	align_resource_fn fn;
> +
> +	fn = (align_resource_fn)(cfg->priv);
> +	return fn(dev, res, start, size, align);
> +}
> +#endif
> +
> +static void __init
> +pcibios_bus_report_status_early(struct pci_channel *hose,
> +				int top_bus, int current_bus,
> +				unsigned int status_mask, int warn)
> +{
> +	unsigned int pci_devfn;
> +	u16 status;
> +	int ret;
> +
> +	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
> +		if (PCI_FUNC(pci_devfn))
> +			continue;
> +		ret = early_read_config_word(hose, top_bus, current_bus,
> +					     pci_devfn, PCI_STATUS, &status);
> +		if (ret != PCIBIOS_SUCCESSFUL)
> +			continue;
> +		if (status == 0xffff)
> +			continue;
> +
> +		early_write_config_word(hose, top_bus, current_bus,
> +					pci_devfn, PCI_STATUS,
> +					status & status_mask);
> +		if (warn)
> +			printk("(%02x:%02x: %04X) ", current_bus,
> +			       pci_devfn, status);
> +	}
> +}
> +
> +/*
> + * We can't use pci_find_device() here since we are
> + * called from interrupt context.
> + */
> +static void __init_refok
> +pcibios_bus_report_status(struct pci_bus *bus, unsigned int status_mask,
> +			  int warn)
> +{
> +	struct pci_dev *dev;
> +
> +	list_for_each_entry(dev, &bus->devices, bus_list) {
> +		u16 status;
> +
> +		/*
> +		 * ignore host bridge - we handle
> +		 * that separately
> +		 */
> +		if (dev->bus->number == 0 && dev->devfn == 0)
> +			continue;
> +
> +		pci_read_config_word(dev, PCI_STATUS, &status);
> +		if (status == 0xffff)
> +			continue;
> +
> +		if ((status & status_mask) == 0)
> +			continue;
> +
> +		/* clear the status errors */
> +		pci_write_config_word(dev, PCI_STATUS, status & status_mask);
> +
> +		if (warn)
> +			printk("(%s: %04X) ", pci_name(dev), status);
> +	}
> +
> +	list_for_each_entry(dev, &bus->devices, bus_list)
> +		if (dev->subordinate)
> +			pcibios_bus_report_status(dev->subordinate, status_mask, warn);
> +}
> +
> +void __init_refok pcibios_report_status(unsigned int status_mask, int warn)
> +{
> +	struct pci_channel *hose;
> +
> +	for (hose = hose_head; hose; hose = hose->next) {
> +		if (unlikely(!hose->bus))
> +			pcibios_bus_report_status_early(hose, hose_head->index,
> +					hose->index, status_mask, warn);
> +		else
> +			pcibios_bus_report_status(hose->bus, status_mask, warn);
> +	}
> +}
> +
> +int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
> +			enum pci_mmap_state mmap_state, int write_combine)
> +{
> +	/*
> +	 * I/O space can be accessed via normal processor loads and stores on
> +	 * this platform but for now we elect not to do this and portable
> +	 * drivers should not do this anyway.
> +	 */
> +	if (mmap_state == pci_mmap_io)
> +		return -EINVAL;
> +
> +	/*
> +	 * Ignore write-combine; for now only return uncached mappings.
> +	 */
> +	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
> +
> +	return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
> +			       vma->vm_end - vma->vm_start,
> +			       vma->vm_page_prot);
> +}
> +
> +#ifndef CONFIG_GENERIC_IOMAP
> +
> +void __iomem *__pci_ioport_map(struct pci_dev *dev,
> +			       unsigned long port, unsigned int nr)
> +{
> +	struct pci_channel *chan = dev->sysdata;
> +
> +	if (unlikely(!chan->io_map_base)) {
> +		chan->io_map_base = sh_io_port_base;
> +
> +		if (pci_domains_supported)
> +			panic("To avoid data corruption io_map_base MUST be "
> +			      "set with multiple PCI domains.");
> +	}
> +
> +	return (void __iomem *)(chan->io_map_base + port);
> +}
> +
> +void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
> +{
> +	iounmap(addr);
> +}
> +EXPORT_SYMBOL(pci_iounmap);
> +
> +#endif /* CONFIG_GENERIC_IOMAP */
> +
> +EXPORT_SYMBOL(PCIBIOS_MIN_IO);
> +EXPORT_SYMBOL(PCIBIOS_MIN_MEM);
> -- 
> 2.7.0
> 
> --

Is this code specific to particular PCI bus hardware on Renesas SH
systems? If so it probably should be kept as a driver file rather than
in arch/sh/kernel core, but I don't actually see a lot of code that
looks hardware-specific. If there's not actually much or anything
hardware-specific about it, could we perhaps unify it with other PCI
bus support code outside or arch/sh?

Rich

[toc] | [prev] | [next] | [standalone]


#1437825 — Re: [PATCH v5 15/22] sh: Move common PCI stuff to arch/sh/kernel

FromYoshinori Sato <ysato@users.sourceforge.jp>
Date2016-07-06 18:20 +0200
SubjectRe: [PATCH v5 15/22] sh: Move common PCI stuff to arch/sh/kernel
Message-ID<rRXIm-2ZF-11@gated-at.bofh.it>
In reply to#1436111
On Mon, 04 Jul 2016 10:55:12 +0900,
Rich Felker wrote:
> 
> On Mon, Jul 04, 2016 at 01:46:35AM +0900, Yoshinori Sato wrote:
> > Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
> > ---
> >  arch/sh/drivers/pci/Makefile |   2 -
> >  arch/sh/drivers/pci/common.c | 162 --------------------
> >  arch/sh/drivers/pci/pci.c    | 320 ----------------------------------------
> >  arch/sh/kernel/Makefile      |   2 +
> >  arch/sh/kernel/pci-common.c  | 162 ++++++++++++++++++++
> >  arch/sh/kernel/pci.c         | 342 +++++++++++++++++++++++++++++++++++++++++++
> >  6 files changed, 506 insertions(+), 484 deletions(-)
> >  delete mode 100644 arch/sh/drivers/pci/common.c
> >  delete mode 100644 arch/sh/drivers/pci/pci.c
> >  create mode 100644 arch/sh/kernel/pci-common.c
> >  create mode 100644 arch/sh/kernel/pci.c
> > 
> > diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile
> > index 82f0a33..fffbede 100644
> > --- a/arch/sh/drivers/pci/Makefile
> > +++ b/arch/sh/drivers/pci/Makefile
> > @@ -1,8 +1,6 @@
> >  #
> >  # Makefile for the PCI specific kernel interface routines under Linux.
> >  #
> > -obj-y					+= common.o pci.o
> > -
> >  obj-$(CONFIG_CPU_SUBTYPE_SH7751)	+= pci-sh7751.o ops-sh4.o
> >  obj-$(CONFIG_CPU_SUBTYPE_SH7751R)	+= pci-sh7751.o ops-sh4.o
> >  obj-$(CONFIG_CPU_SUBTYPE_SH7763)	+= pci-sh7780.o ops-sh4.o
> > diff --git a/arch/sh/drivers/pci/common.c b/arch/sh/drivers/pci/common.c
> > deleted file mode 100644
> > index dbf1381..0000000
> > --- a/arch/sh/drivers/pci/common.c
> > +++ /dev/null
> > @@ -1,162 +0,0 @@
> > -#include <linux/pci.h>
> > -#include <linux/interrupt.h>
> > -#include <linux/timer.h>
> > -#include <linux/kernel.h>
> > -
> > -/*
> > - * These functions are used early on before PCI scanning is done
> > - * and all of the pci_dev and pci_bus structures have been created.
> > - */
> > -static struct pci_dev *fake_pci_dev(struct pci_channel *hose,
> > -	int top_bus, int busnr, int devfn)
> > -{
> > -	static struct pci_dev dev;
> > -	static struct pci_bus bus;
> > -
> > -	dev.bus = &bus;
> > -	dev.sysdata = hose;
> > -	dev.devfn = devfn;
> > -	bus.number = busnr;
> > -	bus.sysdata = hose;
> > -	bus.ops = hose->pci_ops;
> > -
> > -	if(busnr != top_bus)
> > -		/* Fake a parent bus structure. */
> > -		bus.parent = &bus;
> > -	else
> > -		bus.parent = NULL;
> > -
> > -	return &dev;
> > -}
> > -
> > -#define EARLY_PCI_OP(rw, size, type)					\
> > -int __init early_##rw##_config_##size(struct pci_channel *hose,		\
> > -	int top_bus, int bus, int devfn, int offset, type value)	\
> > -{									\
> > -	return pci_##rw##_config_##size(				\
> > -		fake_pci_dev(hose, top_bus, bus, devfn),		\
> > -		offset, value);						\
> > -}
> > -
> > -EARLY_PCI_OP(read, byte, u8 *)
> > -EARLY_PCI_OP(read, word, u16 *)
> > -EARLY_PCI_OP(read, dword, u32 *)
> > -EARLY_PCI_OP(write, byte, u8)
> > -EARLY_PCI_OP(write, word, u16)
> > -EARLY_PCI_OP(write, dword, u32)
> > -
> > -int __init pci_is_66mhz_capable(struct pci_channel *hose,
> > -				int top_bus, int current_bus)
> > -{
> > -	u32 pci_devfn;
> > -	unsigned short vid;
> > -	int cap66 = -1;
> > -	u16 stat;
> > -
> > -	printk(KERN_INFO "PCI: Checking 66MHz capabilities...\n");
> > -
> > -	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
> > -		if (PCI_FUNC(pci_devfn))
> > -			continue;
> > -		if (early_read_config_word(hose, top_bus, current_bus,
> > -					   pci_devfn, PCI_VENDOR_ID, &vid) !=
> > -		    PCIBIOS_SUCCESSFUL)
> > -			continue;
> > -		if (vid == 0xffff)
> > -			continue;
> > -
> > -		/* check 66MHz capability */
> > -		if (cap66 < 0)
> > -			cap66 = 1;
> > -		if (cap66) {
> > -			early_read_config_word(hose, top_bus, current_bus,
> > -					       pci_devfn, PCI_STATUS, &stat);
> > -			if (!(stat & PCI_STATUS_66MHZ)) {
> > -				printk(KERN_DEBUG
> > -				       "PCI: %02x:%02x not 66MHz capable.\n",
> > -				       current_bus, pci_devfn);
> > -				cap66 = 0;
> > -				break;
> > -			}
> > -		}
> > -	}
> > -
> > -	return cap66 > 0;
> > -}
> > -
> > -static void pcibios_enable_err(unsigned long __data)
> > -{
> > -	struct pci_channel *hose = (struct pci_channel *)__data;
> > -
> > -	del_timer(&hose->err_timer);
> > -	printk(KERN_DEBUG "PCI: re-enabling error IRQ.\n");
> > -	enable_irq(hose->err_irq);
> > -}
> > -
> > -static void pcibios_enable_serr(unsigned long __data)
> > -{
> > -	struct pci_channel *hose = (struct pci_channel *)__data;
> > -
> > -	del_timer(&hose->serr_timer);
> > -	printk(KERN_DEBUG "PCI: re-enabling system error IRQ.\n");
> > -	enable_irq(hose->serr_irq);
> > -}
> > -
> > -void pcibios_enable_timers(struct pci_channel *hose)
> > -{
> > -	if (hose->err_irq) {
> > -		init_timer(&hose->err_timer);
> > -		hose->err_timer.data = (unsigned long)hose;
> > -		hose->err_timer.function = pcibios_enable_err;
> > -	}
> > -
> > -	if (hose->serr_irq) {
> > -		init_timer(&hose->serr_timer);
> > -		hose->serr_timer.data = (unsigned long)hose;
> > -		hose->serr_timer.function = pcibios_enable_serr;
> > -	}
> > -}
> > -
> > -/*
> > - * A simple handler for the regular PCI status errors, called from IRQ
> > - * context.
> > - */
> > -unsigned int pcibios_handle_status_errors(unsigned long addr,
> > -					  unsigned int status,
> > -					  struct pci_channel *hose)
> > -{
> > -	unsigned int cmd = 0;
> > -
> > -	if (status & PCI_STATUS_REC_MASTER_ABORT) {
> > -		printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n", addr);
> > -		cmd |= PCI_STATUS_REC_MASTER_ABORT;
> > -	}
> > -
> > -	if (status & PCI_STATUS_REC_TARGET_ABORT) {
> > -		printk(KERN_DEBUG "PCI: target abort: ");
> > -		pcibios_report_status(PCI_STATUS_REC_TARGET_ABORT |
> > -				      PCI_STATUS_SIG_TARGET_ABORT |
> > -				      PCI_STATUS_REC_MASTER_ABORT, 1);
> > -		printk("\n");
> > -
> > -		cmd |= PCI_STATUS_REC_TARGET_ABORT;
> > -	}
> > -
> > -	if (status & (PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY)) {
> > -		printk(KERN_DEBUG "PCI: parity error detected: ");
> > -		pcibios_report_status(PCI_STATUS_PARITY |
> > -				      PCI_STATUS_DETECTED_PARITY, 1);
> > -		printk("\n");
> > -
> > -		cmd |= PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY;
> > -
> > -		/* Now back off of the IRQ for awhile */
> > -		if (hose->err_irq) {
> > -			disable_irq_nosync(hose->err_irq);
> > -			hose->err_timer.expires = jiffies + HZ;
> > -			add_timer(&hose->err_timer);
> > -		}
> > -	}
> > -
> > -	return cmd;
> > -}
> > diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
> > deleted file mode 100644
> > index d5462b7..0000000
> > --- a/arch/sh/drivers/pci/pci.c
> > +++ /dev/null
> > @@ -1,320 +0,0 @@
> > -/*
> > - * New-style PCI core.
> > - *
> > - * Copyright (c) 2004 - 2009  Paul Mundt
> > - * Copyright (c) 2002  M. R. Brown
> > - *
> > - * Modelled after arch/mips/pci/pci.c:
> > - *  Copyright (C) 2003, 04 Ralf Baechle (ralf@linux-mips.org)
> > - *
> > - * This file is subject to the terms and conditions of the GNU General Public
> > - * License.  See the file "COPYING" in the main directory of this archive
> > - * for more details.
> > - */
> > -#include <linux/kernel.h>
> > -#include <linux/mm.h>
> > -#include <linux/pci.h>
> > -#include <linux/init.h>
> > -#include <linux/types.h>
> > -#include <linux/dma-debug.h>
> > -#include <linux/io.h>
> > -#include <linux/mutex.h>
> > -#include <linux/spinlock.h>
> > -#include <linux/export.h>
> > -
> > -unsigned long PCIBIOS_MIN_IO = 0x0000;
> > -unsigned long PCIBIOS_MIN_MEM = 0;
> > -
> > -/*
> > - * The PCI controller list.
> > - */
> > -static struct pci_channel *hose_head, **hose_tail = &hose_head;
> > -
> > -static int pci_initialized;
> > -
> > -static void pcibios_scanbus(struct pci_channel *hose)
> > -{
> > -	static int next_busno;
> > -	static int need_domain_info;
> > -	LIST_HEAD(resources);
> > -	struct resource *res;
> > -	resource_size_t offset;
> > -	int i;
> > -	struct pci_bus *bus;
> > -
> > -	for (i = 0; i < hose->nr_resources; i++) {
> > -		res = hose->resources + i;
> > -		offset = 0;
> > -		if (res->flags & IORESOURCE_IO)
> > -			offset = hose->io_offset;
> > -		else if (res->flags & IORESOURCE_MEM)
> > -			offset = hose->mem_offset;
> > -		pci_add_resource_offset(&resources, res, offset);
> > -	}
> > -
> > -	bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
> > -				&resources);
> > -	hose->bus = bus;
> > -
> > -	need_domain_info = need_domain_info || hose->index;
> > -	hose->need_domain_info = need_domain_info;
> > -
> > -	if (!bus) {
> > -		pci_free_resource_list(&resources);
> > -		return;
> > -	}
> > -
> > -	next_busno = bus->busn_res.end + 1;
> > -	/* Don't allow 8-bit bus number overflow inside the hose -
> > -	   reserve some space for bridges. */
> > -	if (next_busno > 224) {
> > -		next_busno = 0;
> > -		need_domain_info = 1;
> > -	}
> > -
> > -	pci_bus_size_bridges(bus);
> > -	pci_bus_assign_resources(bus);
> > -	pci_bus_add_devices(bus);
> > -}
> > -
> > -/*
> > - * This interrupt-safe spinlock protects all accesses to PCI
> > - * configuration space.
> > - */
> > -DEFINE_RAW_SPINLOCK(pci_config_lock);
> > -static DEFINE_MUTEX(pci_scan_mutex);
> > -
> > -int register_pci_controller(struct pci_channel *hose)
> > -{
> > -	int i;
> > -
> > -	for (i = 0; i < hose->nr_resources; i++) {
> > -		struct resource *res = hose->resources + i;
> > -
> > -		if (res->flags & IORESOURCE_IO) {
> > -			if (request_resource(&ioport_resource, res) < 0)
> > -				goto out;
> > -		} else {
> > -			if (request_resource(&iomem_resource, res) < 0)
> > -				goto out;
> > -		}
> > -	}
> > -
> > -	*hose_tail = hose;
> > -	hose_tail = &hose->next;
> > -
> > -	/*
> > -	 * Do not panic here but later - this might happen before console init.
> > -	 */
> > -	if (!hose->io_map_base) {
> > -		printk(KERN_WARNING
> > -		       "registering PCI controller with io_map_base unset\n");
> > -	}
> > -
> > -	/*
> > -	 * Setup the ERR/PERR and SERR timers, if available.
> > -	 */
> > -	pcibios_enable_timers(hose);
> > -
> > -	/*
> > -	 * Scan the bus if it is register after the PCI subsystem
> > -	 * initialization.
> > -	 */
> > -	if (pci_initialized) {
> > -		mutex_lock(&pci_scan_mutex);
> > -		pcibios_scanbus(hose);
> > -		mutex_unlock(&pci_scan_mutex);
> > -	}
> > -
> > -	return 0;
> > -
> > -out:
> > -	for (--i; i >= 0; i--)
> > -		release_resource(&hose->resources[i]);
> > -
> > -	printk(KERN_WARNING "Skipping PCI bus scan due to resource conflict\n");
> > -	return -1;
> > -}
> > -
> > -static int __init pcibios_init(void)
> > -{
> > -	struct pci_channel *hose;
> > -
> > -	/* Scan all of the recorded PCI controllers.  */
> > -	for (hose = hose_head; hose; hose = hose->next)
> > -		pcibios_scanbus(hose);
> > -
> > -	pci_fixup_irqs(pci_common_swizzle, pcibios_map_platform_irq);
> > -
> > -	dma_debug_add_bus(&pci_bus_type);
> > -
> > -	pci_initialized = 1;
> > -
> > -	return 0;
> > -}
> > -subsys_initcall(pcibios_init);
> > -
> > -/*
> > - *  Called after each bus is probed, but before its children
> > - *  are examined.
> > - */
> > -void pcibios_fixup_bus(struct pci_bus *bus)
> > -{
> > -}
> > -
> > -/*
> > - * We need to avoid collisions with `mirrored' VGA ports
> > - * and other strange ISA hardware, so we always want the
> > - * addresses to be allocated in the 0x000-0x0ff region
> > - * modulo 0x400.
> > - */
> > -resource_size_t pcibios_align_resource(void *data, const struct resource *res,
> > -				resource_size_t size, resource_size_t align)
> > -{
> > -	struct pci_dev *dev = data;
> > -	struct pci_channel *hose = dev->sysdata;
> > -	resource_size_t start = res->start;
> > -
> > -	if (res->flags & IORESOURCE_IO) {
> > -		if (start < PCIBIOS_MIN_IO + hose->resources[0].start)
> > -			start = PCIBIOS_MIN_IO + hose->resources[0].start;
> > -
> > -		/*
> > -                 * Put everything into 0x00-0xff region modulo 0x400.
> > -		 */
> > -		if (start & 0x300)
> > -			start = (start + 0x3ff) & ~0x3ff;
> > -	}
> > -
> > -	return start;
> > -}
> > -
> > -static void __init
> > -pcibios_bus_report_status_early(struct pci_channel *hose,
> > -				int top_bus, int current_bus,
> > -				unsigned int status_mask, int warn)
> > -{
> > -	unsigned int pci_devfn;
> > -	u16 status;
> > -	int ret;
> > -
> > -	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
> > -		if (PCI_FUNC(pci_devfn))
> > -			continue;
> > -		ret = early_read_config_word(hose, top_bus, current_bus,
> > -					     pci_devfn, PCI_STATUS, &status);
> > -		if (ret != PCIBIOS_SUCCESSFUL)
> > -			continue;
> > -		if (status == 0xffff)
> > -			continue;
> > -
> > -		early_write_config_word(hose, top_bus, current_bus,
> > -					pci_devfn, PCI_STATUS,
> > -					status & status_mask);
> > -		if (warn)
> > -			printk("(%02x:%02x: %04X) ", current_bus,
> > -			       pci_devfn, status);
> > -	}
> > -}
> > -
> > -/*
> > - * We can't use pci_find_device() here since we are
> > - * called from interrupt context.
> > - */
> > -static void __init_refok
> > -pcibios_bus_report_status(struct pci_bus *bus, unsigned int status_mask,
> > -			  int warn)
> > -{
> > -	struct pci_dev *dev;
> > -
> > -	list_for_each_entry(dev, &bus->devices, bus_list) {
> > -		u16 status;
> > -
> > -		/*
> > -		 * ignore host bridge - we handle
> > -		 * that separately
> > -		 */
> > -		if (dev->bus->number == 0 && dev->devfn == 0)
> > -			continue;
> > -
> > -		pci_read_config_word(dev, PCI_STATUS, &status);
> > -		if (status == 0xffff)
> > -			continue;
> > -
> > -		if ((status & status_mask) == 0)
> > -			continue;
> > -
> > -		/* clear the status errors */
> > -		pci_write_config_word(dev, PCI_STATUS, status & status_mask);
> > -
> > -		if (warn)
> > -			printk("(%s: %04X) ", pci_name(dev), status);
> > -	}
> > -
> > -	list_for_each_entry(dev, &bus->devices, bus_list)
> > -		if (dev->subordinate)
> > -			pcibios_bus_report_status(dev->subordinate, status_mask, warn);
> > -}
> > -
> > -void __init_refok pcibios_report_status(unsigned int status_mask, int warn)
> > -{
> > -	struct pci_channel *hose;
> > -
> > -	for (hose = hose_head; hose; hose = hose->next) {
> > -		if (unlikely(!hose->bus))
> > -			pcibios_bus_report_status_early(hose, hose_head->index,
> > -					hose->index, status_mask, warn);
> > -		else
> > -			pcibios_bus_report_status(hose->bus, status_mask, warn);
> > -	}
> > -}
> > -
> > -int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
> > -			enum pci_mmap_state mmap_state, int write_combine)
> > -{
> > -	/*
> > -	 * I/O space can be accessed via normal processor loads and stores on
> > -	 * this platform but for now we elect not to do this and portable
> > -	 * drivers should not do this anyway.
> > -	 */
> > -	if (mmap_state == pci_mmap_io)
> > -		return -EINVAL;
> > -
> > -	/*
> > -	 * Ignore write-combine; for now only return uncached mappings.
> > -	 */
> > -	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
> > -
> > -	return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
> > -			       vma->vm_end - vma->vm_start,
> > -			       vma->vm_page_prot);
> > -}
> > -
> > -#ifndef CONFIG_GENERIC_IOMAP
> > -
> > -void __iomem *__pci_ioport_map(struct pci_dev *dev,
> > -			       unsigned long port, unsigned int nr)
> > -{
> > -	struct pci_channel *chan = dev->sysdata;
> > -
> > -	if (unlikely(!chan->io_map_base)) {
> > -		chan->io_map_base = sh_io_port_base;
> > -
> > -		if (pci_domains_supported)
> > -			panic("To avoid data corruption io_map_base MUST be "
> > -			      "set with multiple PCI domains.");
> > -	}
> > -
> > -	return (void __iomem *)(chan->io_map_base + port);
> > -}
> > -
> > -void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
> > -{
> > -	iounmap(addr);
> > -}
> > -EXPORT_SYMBOL(pci_iounmap);
> > -
> > -#endif /* CONFIG_GENERIC_IOMAP */
> > -
> > -EXPORT_SYMBOL(PCIBIOS_MIN_IO);
> > -EXPORT_SYMBOL(PCIBIOS_MIN_MEM);
> > diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
> > index 09040fd..a9a54c2 100644
> > --- a/arch/sh/kernel/Makefile
> > +++ b/arch/sh/kernel/Makefile
> > @@ -46,5 +46,7 @@ obj-$(CONFIG_DWARF_UNWINDER)	+= dwarf.o
> >  obj-$(CONFIG_PERF_EVENTS)	+= perf_event.o perf_callchain.o
> >  
> >  obj-$(CONFIG_HAVE_HW_BREAKPOINT)		+= hw_breakpoint.o
> > +obj-$(CONFIG_PCI)		+= pci.o pci-common.o
> >  
> >  ccflags-y := -Werror
> > +CFLAGS_pci.o := -O0
> > diff --git a/arch/sh/kernel/pci-common.c b/arch/sh/kernel/pci-common.c
> > new file mode 100644
> > index 0000000..dbf1381
> > --- /dev/null
> > +++ b/arch/sh/kernel/pci-common.c
> > @@ -0,0 +1,162 @@
> > +#include <linux/pci.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/timer.h>
> > +#include <linux/kernel.h>
> > +
> > +/*
> > + * These functions are used early on before PCI scanning is done
> > + * and all of the pci_dev and pci_bus structures have been created.
> > + */
> > +static struct pci_dev *fake_pci_dev(struct pci_channel *hose,
> > +	int top_bus, int busnr, int devfn)
> > +{
> > +	static struct pci_dev dev;
> > +	static struct pci_bus bus;
> > +
> > +	dev.bus = &bus;
> > +	dev.sysdata = hose;
> > +	dev.devfn = devfn;
> > +	bus.number = busnr;
> > +	bus.sysdata = hose;
> > +	bus.ops = hose->pci_ops;
> > +
> > +	if(busnr != top_bus)
> > +		/* Fake a parent bus structure. */
> > +		bus.parent = &bus;
> > +	else
> > +		bus.parent = NULL;
> > +
> > +	return &dev;
> > +}
> > +
> > +#define EARLY_PCI_OP(rw, size, type)					\
> > +int __init early_##rw##_config_##size(struct pci_channel *hose,		\
> > +	int top_bus, int bus, int devfn, int offset, type value)	\
> > +{									\
> > +	return pci_##rw##_config_##size(				\
> > +		fake_pci_dev(hose, top_bus, bus, devfn),		\
> > +		offset, value);						\
> > +}
> > +
> > +EARLY_PCI_OP(read, byte, u8 *)
> > +EARLY_PCI_OP(read, word, u16 *)
> > +EARLY_PCI_OP(read, dword, u32 *)
> > +EARLY_PCI_OP(write, byte, u8)
> > +EARLY_PCI_OP(write, word, u16)
> > +EARLY_PCI_OP(write, dword, u32)
> > +
> > +int __init pci_is_66mhz_capable(struct pci_channel *hose,
> > +				int top_bus, int current_bus)
> > +{
> > +	u32 pci_devfn;
> > +	unsigned short vid;
> > +	int cap66 = -1;
> > +	u16 stat;
> > +
> > +	printk(KERN_INFO "PCI: Checking 66MHz capabilities...\n");
> > +
> > +	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
> > +		if (PCI_FUNC(pci_devfn))
> > +			continue;
> > +		if (early_read_config_word(hose, top_bus, current_bus,
> > +					   pci_devfn, PCI_VENDOR_ID, &vid) !=
> > +		    PCIBIOS_SUCCESSFUL)
> > +			continue;
> > +		if (vid == 0xffff)
> > +			continue;
> > +
> > +		/* check 66MHz capability */
> > +		if (cap66 < 0)
> > +			cap66 = 1;
> > +		if (cap66) {
> > +			early_read_config_word(hose, top_bus, current_bus,
> > +					       pci_devfn, PCI_STATUS, &stat);
> > +			if (!(stat & PCI_STATUS_66MHZ)) {
> > +				printk(KERN_DEBUG
> > +				       "PCI: %02x:%02x not 66MHz capable.\n",
> > +				       current_bus, pci_devfn);
> > +				cap66 = 0;
> > +				break;
> > +			}
> > +		}
> > +	}
> > +
> > +	return cap66 > 0;
> > +}
> > +
> > +static void pcibios_enable_err(unsigned long __data)
> > +{
> > +	struct pci_channel *hose = (struct pci_channel *)__data;
> > +
> > +	del_timer(&hose->err_timer);
> > +	printk(KERN_DEBUG "PCI: re-enabling error IRQ.\n");
> > +	enable_irq(hose->err_irq);
> > +}
> > +
> > +static void pcibios_enable_serr(unsigned long __data)
> > +{
> > +	struct pci_channel *hose = (struct pci_channel *)__data;
> > +
> > +	del_timer(&hose->serr_timer);
> > +	printk(KERN_DEBUG "PCI: re-enabling system error IRQ.\n");
> > +	enable_irq(hose->serr_irq);
> > +}
> > +
> > +void pcibios_enable_timers(struct pci_channel *hose)
> > +{
> > +	if (hose->err_irq) {
> > +		init_timer(&hose->err_timer);
> > +		hose->err_timer.data = (unsigned long)hose;
> > +		hose->err_timer.function = pcibios_enable_err;
> > +	}
> > +
> > +	if (hose->serr_irq) {
> > +		init_timer(&hose->serr_timer);
> > +		hose->serr_timer.data = (unsigned long)hose;
> > +		hose->serr_timer.function = pcibios_enable_serr;
> > +	}
> > +}
> > +
> > +/*
> > + * A simple handler for the regular PCI status errors, called from IRQ
> > + * context.
> > + */
> > +unsigned int pcibios_handle_status_errors(unsigned long addr,
> > +					  unsigned int status,
> > +					  struct pci_channel *hose)
> > +{
> > +	unsigned int cmd = 0;
> > +
> > +	if (status & PCI_STATUS_REC_MASTER_ABORT) {
> > +		printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n", addr);
> > +		cmd |= PCI_STATUS_REC_MASTER_ABORT;
> > +	}
> > +
> > +	if (status & PCI_STATUS_REC_TARGET_ABORT) {
> > +		printk(KERN_DEBUG "PCI: target abort: ");
> > +		pcibios_report_status(PCI_STATUS_REC_TARGET_ABORT |
> > +				      PCI_STATUS_SIG_TARGET_ABORT |
> > +				      PCI_STATUS_REC_MASTER_ABORT, 1);
> > +		printk("\n");
> > +
> > +		cmd |= PCI_STATUS_REC_TARGET_ABORT;
> > +	}
> > +
> > +	if (status & (PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY)) {
> > +		printk(KERN_DEBUG "PCI: parity error detected: ");
> > +		pcibios_report_status(PCI_STATUS_PARITY |
> > +				      PCI_STATUS_DETECTED_PARITY, 1);
> > +		printk("\n");
> > +
> > +		cmd |= PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY;
> > +
> > +		/* Now back off of the IRQ for awhile */
> > +		if (hose->err_irq) {
> > +			disable_irq_nosync(hose->err_irq);
> > +			hose->err_timer.expires = jiffies + HZ;
> > +			add_timer(&hose->err_timer);
> > +		}
> > +	}
> > +
> > +	return cmd;
> > +}
> > diff --git a/arch/sh/kernel/pci.c b/arch/sh/kernel/pci.c
> > new file mode 100644
> > index 0000000..9cf0ba4
> > --- /dev/null
> > +++ b/arch/sh/kernel/pci.c
> > @@ -0,0 +1,342 @@
> > +/*
> > + * New-style PCI core.
> > + *
> > + * Copyright (c) 2004 - 2009  Paul Mundt
> > + * Copyright (c) 2002  M. R. Brown
> > + *
> > + * Modelled after arch/mips/pci/pci.c:
> > + *  Copyright (C) 2003, 04 Ralf Baechle (ralf@linux-mips.org)
> > + *
> > + * This file is subject to the terms and conditions of the GNU General Public
> > + * License.  See the file "COPYING" in the main directory of this archive
> > + * for more details.
> > + */
> > +#include <linux/kernel.h>
> > +#include <linux/mm.h>
> > +#include <linux/pci.h>
> > +#include <linux/init.h>
> > +#include <linux/types.h>
> > +#include <linux/dma-debug.h>
> > +#include <linux/io.h>
> > +#include <linux/mutex.h>
> > +#include <linux/spinlock.h>
> > +#include <linux/export.h>
> > +
> > +unsigned long PCIBIOS_MIN_IO = 0x0000;
> > +unsigned long PCIBIOS_MIN_MEM = 0;
> > +
> > +/*
> > + * The PCI controller list.
> > + */
> > +static struct pci_channel *hose_head, **hose_tail = &hose_head;
> > +
> > +static int pci_initialized;
> > +
> > +static void pcibios_scanbus(struct pci_channel *hose)
> > +{
> > +	static int next_busno;
> > +	static int need_domain_info;
> > +	LIST_HEAD(resources);
> > +	struct resource *res;
> > +	resource_size_t offset;
> > +	int i;
> > +	struct pci_bus *bus;
> > +
> > +	for (i = 0; i < hose->nr_resources; i++) {
> > +		res = hose->resources + i;
> > +		offset = 0;
> > +		if (res->flags & IORESOURCE_IO)
> > +			offset = hose->io_offset;
> > +		else if (res->flags & IORESOURCE_MEM)
> > +			offset = hose->mem_offset;
> > +		pci_add_resource_offset(&resources, res, offset);
> > +	}
> > +
> > +	bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
> > +				&resources);
> > +	hose->bus = bus;
> > +
> > +	need_domain_info = need_domain_info || hose->index;
> > +	hose->need_domain_info = need_domain_info;
> > +
> > +	if (!bus) {
> > +		pci_free_resource_list(&resources);
> > +		return;
> > +	}
> > +
> > +	next_busno = bus->busn_res.end + 1;
> > +	/* Don't allow 8-bit bus number overflow inside the hose -
> > +	   reserve some space for bridges. */
> > +	if (next_busno > 224) {
> > +		next_busno = 0;
> > +		need_domain_info = 1;
> > +	}
> > +
> > +	pci_bus_size_bridges(bus);
> > +	pci_bus_assign_resources(bus);
> > +	pci_bus_add_devices(bus);
> > +}
> > +
> > +/*
> > + * This interrupt-safe spinlock protects all accesses to PCI
> > + * configuration space.
> > + */
> > +DEFINE_RAW_SPINLOCK(pci_config_lock);
> > +static DEFINE_MUTEX(pci_scan_mutex);
> > +
> > +int register_pci_controller(struct pci_channel *hose)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < hose->nr_resources; i++) {
> > +		struct resource *res = hose->resources + i;
> > +
> > +		if (res->flags & IORESOURCE_IO) {
> > +			if (request_resource(&ioport_resource, res) < 0)
> > +				goto out;
> > +		} else {
> > +			if (request_resource(&iomem_resource, res) < 0)
> > +				goto out;
> > +		}
> > +	}
> > +
> > +	*hose_tail = hose;
> > +	hose_tail = &hose->next;
> > +
> > +	/*
> > +	 * Do not panic here but later - this might happen before console init.
> > +	 */
> > +	if (!hose->io_map_base) {
> > +		printk(KERN_WARNING
> > +		       "registering PCI controller with io_map_base unset\n");
> > +	}
> > +
> > +	/*
> > +	 * Setup the ERR/PERR and SERR timers, if available.
> > +	 */
> > +	pcibios_enable_timers(hose);
> > +
> > +	/*
> > +	 * Scan the bus if it is register after the PCI subsystem
> > +	 * initialization.
> > +	 */
> > +	if (pci_initialized) {
> > +		mutex_lock(&pci_scan_mutex);
> > +		pcibios_scanbus(hose);
> > +		mutex_unlock(&pci_scan_mutex);
> > +	}
> > +
> > +	return 0;
> > +
> > +out:
> > +	for (--i; i >= 0; i--)
> > +		release_resource(&hose->resources[i]);
> > +
> > +	printk(KERN_WARNING "Skipping PCI bus scan due to resource conflict\n");
> > +	return -1;
> > +}
> > +
> > +#ifndef CONFIG_SH_DEVICE_TREE
> > +static int __init pcibios_init(void)
> > +{
> > +	struct pci_channel *hose;
> > +
> > +	/* Scan all of the recorded PCI controllers.  */
> > +	for (hose = hose_head; hose; hose = hose->next)
> > +		pcibios_scanbus(hose);
> > +
> > +	pci_fixup_irqs(pci_common_swizzle, pcibios_map_platform_irq);
> > +
> > +	dma_debug_add_bus(&pci_bus_type);
> > +
> > +	pci_initialized = 1;
> > +
> > +	return 0;
> > +}
> > +subsys_initcall(pcibios_init);
> > +#endif
> > +
> > +/*
> > + *  Called after each bus is probed, but before its children
> > + *  are examined.
> > + */
> > +void pcibios_fixup_bus(struct pci_bus *bus)
> > +{
> > +}
> > +
> > +#ifndef CONFIG_SH_DEVICE_TREE
> > +/*
> > + * We need to avoid collisions with `mirrored' VGA ports
> > + * and other strange ISA hardware, so we always want the
> > + * addresses to be allocated in the 0x000-0x0ff region
> > + * modulo 0x400.
> > + */
> > +resource_size_t pcibios_align_resource(void *data, const struct resource *res,
> > +				resource_size_t size, resource_size_t align)
> > +{
> > +	struct pci_dev *dev = data;
> > +	struct pci_channel *hose = dev->sysdata;
> > +	resource_size_t start = res->start;
> > +
> > +	if (res->flags & IORESOURCE_IO) {
> > +		if (start < PCIBIOS_MIN_IO + hose->resources[0].start)
> > +			start = PCIBIOS_MIN_IO + hose->resources[0].start;
> > +
> > +		/*
> > +                 * Put everything into 0x00-0xff region modulo 0x400.
> > +		 */
> > +		if (start & 0x300)
> > +			start = (start + 0x3ff) & ~0x3ff;
> > +	}
> > +
> > +	return start;
> > +}
> > +#else
> > +typedef resource_size_t (*align_resource_fn)(struct pci_dev *dev,
> > +					     const struct resource *res,
> > +					     resource_size_t start,
> > +					     resource_size_t size,
> > +					     resource_size_t align);
> > +
> > +resource_size_t pcibios_align_resource(void *data, const struct resource *res,
> > +				resource_size_t size, resource_size_t align)
> > +{
> > +	resource_size_t start = res->start;
> > +	struct pci_dev *dev = data;
> > +	struct pci_config_window *cfg = dev->sysdata;
> > +	align_resource_fn fn;
> > +
> > +	fn = (align_resource_fn)(cfg->priv);
> > +	return fn(dev, res, start, size, align);
> > +}
> > +#endif
> > +
> > +static void __init
> > +pcibios_bus_report_status_early(struct pci_channel *hose,
> > +				int top_bus, int current_bus,
> > +				unsigned int status_mask, int warn)
> > +{
> > +	unsigned int pci_devfn;
> > +	u16 status;
> > +	int ret;
> > +
> > +	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
> > +		if (PCI_FUNC(pci_devfn))
> > +			continue;
> > +		ret = early_read_config_word(hose, top_bus, current_bus,
> > +					     pci_devfn, PCI_STATUS, &status);
> > +		if (ret != PCIBIOS_SUCCESSFUL)
> > +			continue;
> > +		if (status == 0xffff)
> > +			continue;
> > +
> > +		early_write_config_word(hose, top_bus, current_bus,
> > +					pci_devfn, PCI_STATUS,
> > +					status & status_mask);
> > +		if (warn)
> > +			printk("(%02x:%02x: %04X) ", current_bus,
> > +			       pci_devfn, status);
> > +	}
> > +}
> > +
> > +/*
> > + * We can't use pci_find_device() here since we are
> > + * called from interrupt context.
> > + */
> > +static void __init_refok
> > +pcibios_bus_report_status(struct pci_bus *bus, unsigned int status_mask,
> > +			  int warn)
> > +{
> > +	struct pci_dev *dev;
> > +
> > +	list_for_each_entry(dev, &bus->devices, bus_list) {
> > +		u16 status;
> > +
> > +		/*
> > +		 * ignore host bridge - we handle
> > +		 * that separately
> > +		 */
> > +		if (dev->bus->number == 0 && dev->devfn == 0)
> > +			continue;
> > +
> > +		pci_read_config_word(dev, PCI_STATUS, &status);
> > +		if (status == 0xffff)
> > +			continue;
> > +
> > +		if ((status & status_mask) == 0)
> > +			continue;
> > +
> > +		/* clear the status errors */
> > +		pci_write_config_word(dev, PCI_STATUS, status & status_mask);
> > +
> > +		if (warn)
> > +			printk("(%s: %04X) ", pci_name(dev), status);
> > +	}
> > +
> > +	list_for_each_entry(dev, &bus->devices, bus_list)
> > +		if (dev->subordinate)
> > +			pcibios_bus_report_status(dev->subordinate, status_mask, warn);
> > +}
> > +
> > +void __init_refok pcibios_report_status(unsigned int status_mask, int warn)
> > +{
> > +	struct pci_channel *hose;
> > +
> > +	for (hose = hose_head; hose; hose = hose->next) {
> > +		if (unlikely(!hose->bus))
> > +			pcibios_bus_report_status_early(hose, hose_head->index,
> > +					hose->index, status_mask, warn);
> > +		else
> > +			pcibios_bus_report_status(hose->bus, status_mask, warn);
> > +	}
> > +}
> > +
> > +int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
> > +			enum pci_mmap_state mmap_state, int write_combine)
> > +{
> > +	/*
> > +	 * I/O space can be accessed via normal processor loads and stores on
> > +	 * this platform but for now we elect not to do this and portable
> > +	 * drivers should not do this anyway.
> > +	 */
> > +	if (mmap_state == pci_mmap_io)
> > +		return -EINVAL;
> > +
> > +	/*
> > +	 * Ignore write-combine; for now only return uncached mappings.
> > +	 */
> > +	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
> > +
> > +	return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
> > +			       vma->vm_end - vma->vm_start,
> > +			       vma->vm_page_prot);
> > +}
> > +
> > +#ifndef CONFIG_GENERIC_IOMAP
> > +
> > +void __iomem *__pci_ioport_map(struct pci_dev *dev,
> > +			       unsigned long port, unsigned int nr)
> > +{
> > +	struct pci_channel *chan = dev->sysdata;
> > +
> > +	if (unlikely(!chan->io_map_base)) {
> > +		chan->io_map_base = sh_io_port_base;
> > +
> > +		if (pci_domains_supported)
> > +			panic("To avoid data corruption io_map_base MUST be "
> > +			      "set with multiple PCI domains.");
> > +	}
> > +
> > +	return (void __iomem *)(chan->io_map_base + port);
> > +}
> > +
> > +void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
> > +{
> > +	iounmap(addr);
> > +}
> > +EXPORT_SYMBOL(pci_iounmap);
> > +
> > +#endif /* CONFIG_GENERIC_IOMAP */
> > +
> > +EXPORT_SYMBOL(PCIBIOS_MIN_IO);
> > +EXPORT_SYMBOL(PCIBIOS_MIN_MEM);
> > -- 
> > 2.7.0
> > 
> > --
> 
> Is this code specific to particular PCI bus hardware on Renesas SH
> systems? If so it probably should be kept as a driver file rather than
> in arch/sh/kernel core, but I don't actually see a lot of code that
> looks hardware-specific. If there's not actually much or anything
> hardware-specific about it, could we perhaps unify it with other PCI
> bus support code outside or arch/sh?
> 
> Rich

Yes. Common PCI framework required this functions.
I think put arch/sh/kernel is more better.

-- 
Yoshinori Sato
<ysato@users.sourceforge.jp>

[toc] | [prev] | [next] | [standalone]


#1435994 — [PATCH v5 09/22] sh: Use GENERIC_IOMAP on device tree mode

FromYoshinori Sato <ysato@users.sourceforge.jp>
Date2016-07-03 18:50 +0200
Subject[PATCH v5 09/22] sh: Use GENERIC_IOMAP on device tree mode
Message-ID<rQSKK-2yo-41@gated-at.bofh.it>
In reply to#1435986
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 arch/sh/boards/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig
index 5e52d53..9e4ccd0 100644
--- a/arch/sh/boards/Kconfig
+++ b/arch/sh/boards/Kconfig
@@ -12,6 +12,7 @@ config SH_DEVICE_TREE
 	select OF_EARLY_FLATTREE
 	select CLKSRC_OF
 	select GENERIC_CALIBRATE_DELAY
+	select GENERIC_IOMAP
 	help
 	  Select Board Described by Device Tree to build a kernel that
 	  does not hard-code any board-specific knowledge but instead uses
-- 
2.7.0

[toc] | [prev] | [next] | [standalone]


#1435995 — [PATCH v5 05/22] sh: command line passing chosen/bootargs in devicetree

FromYoshinori Sato <ysato@users.sourceforge.jp>
Date2016-07-03 19:00 +0200
Subject[PATCH v5 05/22] sh: command line passing chosen/bootargs in devicetree
Message-ID<rQSUp-2BS-5@gated-at.bofh.it>
In reply to#1435986
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 arch/sh/kernel/setup.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index 8e3b099..bdf57e5 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -280,6 +280,7 @@ void __init setup_arch(char **cmdline_p)
 #endif
 	enable_mmu();
 
+#ifndef CONFIG_OF
 	ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
 
 	printk(KERN_NOTICE "Boot params:\n"
@@ -301,6 +302,7 @@ void __init setup_arch(char **cmdline_p)
 
 	if (!MOUNT_ROOT_RDONLY)
 		root_mountflags &= ~MS_RDONLY;
+#endif
 	init_mm.start_code = (unsigned long) _text;
 	init_mm.end_code = (unsigned long) _etext;
 	init_mm.end_data = (unsigned long) _edata;
@@ -323,9 +325,13 @@ void __init setup_arch(char **cmdline_p)
 #endif
 #endif
 
+#if !defined(CONFIG_OF) || defined(CONFIG_USE_BUILTIN_DTB)
 	/* Save unparsed command line copy for /proc/cmdline */
 	memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
 	*cmdline_p = command_line;
+#else
+	*cmdline_p = boot_command_line;
+#endif
 
 	parse_early_param();
 
-- 
2.7.0

[toc] | [prev] | [next] | [standalone]


#1435996 — [PATCH v5 03/22] sh: set preset_lpj

FromYoshinori Sato <ysato@users.sourceforge.jp>
Date2016-07-03 19:00 +0200
Subject[PATCH v5 03/22] sh: set preset_lpj
Message-ID<rQSUp-2BS-9@gated-at.bofh.it>
In reply to#1435986
Generic callibrate delay required this value.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
 arch/sh/boards/of-generic.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/sh/boards/of-generic.c b/arch/sh/boards/of-generic.c
index 3db4294..2d3cda3 100644
--- a/arch/sh/boards/of-generic.c
+++ b/arch/sh/boards/of-generic.c
@@ -128,6 +128,8 @@ static void __init sh_of_time_init(void)
 static void __init sh_of_setup(char **cmdline_p)
 {
 	struct device_node *root;
+	struct device_node *cpu;
+	u32 freq;
 
 	board_time_init = sh_of_time_init;
 
@@ -139,6 +141,10 @@ static void __init sh_of_setup(char **cmdline_p)
 	}
 
 	sh_of_smp_probe();
+
+	cpu = of_find_node_by_name(NULL, "cpu");
+	if (!of_property_read_u32(cpu, "clock-frequency", &freq))
+		preset_lpj = freq / CONFIG_HZ / 2;
 }
 
 static int sh_of_irq_demux(int irq)
-- 
2.7.0

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | linux.kernel


csiph-web