* [PATCH v5 01/22] sh: Add sh-specific early_init_dt_reserve_memory_arch
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
@ 2016-07-03 16:46 ` Yoshinori Sato
2016-07-04 2:03 ` Rich Felker
2016-07-03 16:46 ` [PATCH v5 02/22] sh: More early unflatten device tree Yoshinori Sato
` (20 subsequent siblings)
21 siblings, 1 reply; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: linux-sh, linux-kernel; +Cc: Yoshinori Sato
sh used P1 address space in early device tree.
So need convert P1 to physical address before reserve memory.
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
arch/sh/boards/of-generic.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/arch/sh/boards/of-generic.c b/arch/sh/boards/of-generic.c
index 57d45dc..8dbf978 100644
--- a/arch/sh/boards/of-generic.c
+++ b/arch/sh/boards/of-generic.c
@@ -15,6 +15,7 @@
#include <linux/clocksource.h>
#include <linux/irqchip.h>
#include <linux/clk-provider.h>
+#include <linux/memblock.h>
#include <asm/machvec.h>
#include <asm/rtc.h>
@@ -203,3 +204,14 @@ static int __init sh_of_device_init(void)
return 0;
}
arch_initcall_sync(sh_of_device_init);
+
+int __init early_init_dt_reserve_memory_arch(phys_addr_t base,
+ phys_addr_t size, bool nomap)
+{
+ if (nomap)
+ return memblock_remove(base, size);
+
+ if (base >= P1SEG)
+ base &= ~P1SEG;
+ return memblock_reserve(base, size);
+}
--
2.7.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* Re: [PATCH v5 01/22] sh: Add sh-specific early_init_dt_reserve_memory_arch
2016-07-03 16:46 ` [PATCH v5 01/22] sh: Add sh-specific early_init_dt_reserve_memory_arch Yoshinori Sato
@ 2016-07-04 2:03 ` Rich Felker
2016-07-06 13:53 ` Yoshinori Sato
0 siblings, 1 reply; 67+ messages in thread
From: Rich Felker @ 2016-07-04 2:03 UTC (permalink / raw)
To: Yoshinori Sato; +Cc: linux-sh, linux-kernel
On Mon, Jul 04, 2016 at 01:46:21AM +0900, Yoshinori Sato wrote:
> sh used P1 address space in early device tree.
> So need convert P1 to physical address before reserve memory.
>
> Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
> ---
> arch/sh/boards/of-generic.c | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
> diff --git a/arch/sh/boards/of-generic.c b/arch/sh/boards/of-generic.c
> index 57d45dc..8dbf978 100644
> --- a/arch/sh/boards/of-generic.c
> +++ b/arch/sh/boards/of-generic.c
> @@ -15,6 +15,7 @@
> #include <linux/clocksource.h>
> #include <linux/irqchip.h>
> #include <linux/clk-provider.h>
> +#include <linux/memblock.h>
> #include <asm/machvec.h>
> #include <asm/rtc.h>
>
> @@ -203,3 +204,14 @@ static int __init sh_of_device_init(void)
> return 0;
> }
> arch_initcall_sync(sh_of_device_init);
> +
> +int __init early_init_dt_reserve_memory_arch(phys_addr_t base,
> + phys_addr_t size, bool nomap)
> +{
> + if (nomap)
> + return memblock_remove(base, size);
> +
> + if (base >= P1SEG)
> + base &= ~P1SEG;
> + return memblock_reserve(base, size);
> +}
> --
I think we need a consistent form of physical memory addressing in the
DT that doesn't require this. Hard-coding details of the segmented
memory model all over the place does not look like a good idea; it's
going to badly break anything with full 32-bit which I believe some
SH-4 models had (those with PMB?) and which J3/J4 will almost
certainly have.
Rich
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [PATCH v5 01/22] sh: Add sh-specific early_init_dt_reserve_memory_arch
2016-07-04 2:03 ` Rich Felker
@ 2016-07-06 13:53 ` Yoshinori Sato
2016-07-06 14:50 ` Rich Felker
0 siblings, 1 reply; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-06 13:53 UTC (permalink / raw)
To: Rich Felker; +Cc: linux-sh, linux-kernel
On Mon, 04 Jul 2016 11:03:50 +0900,
Rich Felker wrote:
>
> On Mon, Jul 04, 2016 at 01:46:21AM +0900, Yoshinori Sato wrote:
> > sh used P1 address space in early device tree.
> > So need convert P1 to physical address before reserve memory.
> >
> > Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
> > ---
> > arch/sh/boards/of-generic.c | 12 ++++++++++++
> > 1 file changed, 12 insertions(+)
> >
> > diff --git a/arch/sh/boards/of-generic.c b/arch/sh/boards/of-generic.c
> > index 57d45dc..8dbf978 100644
> > --- a/arch/sh/boards/of-generic.c
> > +++ b/arch/sh/boards/of-generic.c
> > @@ -15,6 +15,7 @@
> > #include <linux/clocksource.h>
> > #include <linux/irqchip.h>
> > #include <linux/clk-provider.h>
> > +#include <linux/memblock.h>
> > #include <asm/machvec.h>
> > #include <asm/rtc.h>
> >
> > @@ -203,3 +204,14 @@ static int __init sh_of_device_init(void)
> > return 0;
> > }
> > arch_initcall_sync(sh_of_device_init);
> > +
> > +int __init early_init_dt_reserve_memory_arch(phys_addr_t base,
> > + phys_addr_t size, bool nomap)
> > +{
> > + if (nomap)
> > + return memblock_remove(base, size);
> > +
> > + if (base >= P1SEG)
> > + base &= ~P1SEG;
> > + return memblock_reserve(base, size);
> > +}
> > --
>
> I think we need a consistent form of physical memory addressing in the
> DT that doesn't require this. Hard-coding details of the segmented
> memory model all over the place does not look like a good idea; it's
> going to badly break anything with full 32-bit which I believe some
> SH-4 models had (those with PMB?) and which J3/J4 will almost
> certainly have.
Even 32 bits mode are assigned to the same area now.
But lookup PMB more better.
It add "#ifdef CONFIG_29BIT".
Thanks.
> Rich
> --
> To unsubscribe from this list: send the line "unsubscribe linux-sh" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Yoshinori Sato
<ysato@users.sourceforge.jp>
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [PATCH v5 01/22] sh: Add sh-specific early_init_dt_reserve_memory_arch
2016-07-06 13:53 ` Yoshinori Sato
@ 2016-07-06 14:50 ` Rich Felker
0 siblings, 0 replies; 67+ messages in thread
From: Rich Felker @ 2016-07-06 14:50 UTC (permalink / raw)
To: Yoshinori Sato; +Cc: linux-sh, linux-kernel
On Wed, Jul 06, 2016 at 10:53:23PM +0900, Yoshinori Sato wrote:
> On Mon, 04 Jul 2016 11:03:50 +0900,
> Rich Felker wrote:
> >
> > On Mon, Jul 04, 2016 at 01:46:21AM +0900, Yoshinori Sato wrote:
> > > sh used P1 address space in early device tree.
> > > So need convert P1 to physical address before reserve memory.
> > >
> > > Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
> > > ---
> > > arch/sh/boards/of-generic.c | 12 ++++++++++++
> > > 1 file changed, 12 insertions(+)
> > >
> > > diff --git a/arch/sh/boards/of-generic.c b/arch/sh/boards/of-generic.c
> > > index 57d45dc..8dbf978 100644
> > > --- a/arch/sh/boards/of-generic.c
> > > +++ b/arch/sh/boards/of-generic.c
> > > @@ -15,6 +15,7 @@
> > > #include <linux/clocksource.h>
> > > #include <linux/irqchip.h>
> > > #include <linux/clk-provider.h>
> > > +#include <linux/memblock.h>
> > > #include <asm/machvec.h>
> > > #include <asm/rtc.h>
> > >
> > > @@ -203,3 +204,14 @@ static int __init sh_of_device_init(void)
> > > return 0;
> > > }
> > > arch_initcall_sync(sh_of_device_init);
> > > +
> > > +int __init early_init_dt_reserve_memory_arch(phys_addr_t base,
> > > + phys_addr_t size, bool nomap)
> > > +{
> > > + if (nomap)
> > > + return memblock_remove(base, size);
> > > +
> > > + if (base >= P1SEG)
> > > + base &= ~P1SEG;
> > > + return memblock_reserve(base, size);
> > > +}
> > > --
> >
> > I think we need a consistent form of physical memory addressing in the
> > DT that doesn't require this. Hard-coding details of the segmented
> > memory model all over the place does not look like a good idea; it's
> > going to badly break anything with full 32-bit which I believe some
> > SH-4 models had (those with PMB?) and which J3/J4 will almost
> > certainly have.
>
> Even 32 bits mode are assigned to the same area now.
> But lookup PMB more better.
>
> It add "#ifdef CONFIG_29BIT".
> Thanks.
I still don't think there should be any sh-specific code here. Can you
explain why you think it's needed with an example including real
addresses and how they'd get mapped incorrectly without this patch?
Rich
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v5 02/22] sh: More early unflatten device tree
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
2016-07-03 16:46 ` [PATCH v5 01/22] sh: Add sh-specific early_init_dt_reserve_memory_arch Yoshinori Sato
@ 2016-07-03 16:46 ` Yoshinori Sato
2016-07-03 16:46 ` [PATCH v5 03/22] sh: set preset_lpj Yoshinori Sato
` (19 subsequent siblings)
21 siblings, 0 replies; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: linux-sh, linux-kernel; +Cc: Yoshinori Sato
unflatten required MMU disabled.
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
arch/sh/boards/of-generic.c | 6 ------
arch/sh/kernel/setup.c | 7 +++++++
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/arch/sh/boards/of-generic.c b/arch/sh/boards/of-generic.c
index 8dbf978..3db4294 100644
--- a/arch/sh/boards/of-generic.c
+++ b/arch/sh/boards/of-generic.c
@@ -129,12 +129,6 @@ static void __init sh_of_setup(char **cmdline_p)
{
struct device_node *root;
-#ifdef CONFIG_USE_BUILTIN_DTB
- unflatten_and_copy_device_tree();
-#else
- unflatten_device_tree();
-#endif
-
board_time_init = sh_of_time_init;
sh_mv.mv_name = "Unknown SH model";
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index 5b9eb70..86f2792 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -271,6 +271,13 @@ void __ref sh_fdt_init(phys_addr_t dt_phys)
void __init setup_arch(char **cmdline_p)
{
+#ifdef CONFIG_OF
+#ifdef CONFIG_USE_BUILTIN_DTB
+ unflatten_and_copy_device_tree();
+#else
+ unflatten_device_tree();
+#endif
+#endif
enable_mmu();
ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
--
2.7.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH v5 03/22] sh: set preset_lpj
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
2016-07-03 16:46 ` [PATCH v5 01/22] sh: Add sh-specific early_init_dt_reserve_memory_arch Yoshinori Sato
2016-07-03 16:46 ` [PATCH v5 02/22] sh: More early unflatten device tree Yoshinori Sato
@ 2016-07-03 16:46 ` Yoshinori Sato
2016-07-03 16:46 ` [PATCH v5 04/22] sh: Use P1SEGADDR Yoshinori Sato
` (18 subsequent siblings)
21 siblings, 0 replies; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: linux-sh, linux-kernel; +Cc: Yoshinori Sato
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
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH v5 04/22] sh: Use P1SEGADDR
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
` (2 preceding siblings ...)
2016-07-03 16:46 ` [PATCH v5 03/22] sh: set preset_lpj Yoshinori Sato
@ 2016-07-03 16:46 ` Yoshinori Sato
2016-07-04 1:48 ` Rich Felker
2016-07-03 16:46 ` [PATCH v5 05/22] sh: command line passing chosen/bootargs in devicetree Yoshinori Sato
` (17 subsequent siblings)
21 siblings, 1 reply; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: linux-sh, linux-kernel; +Cc: Yoshinori Sato
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
^ permalink raw reply related [flat|nested] 67+ messages in thread
* Re: [PATCH v5 04/22] sh: Use P1SEGADDR
2016-07-03 16:46 ` [PATCH v5 04/22] sh: Use P1SEGADDR Yoshinori Sato
@ 2016-07-04 1:48 ` Rich Felker
2016-07-06 14:11 ` Yoshinori Sato
0 siblings, 1 reply; 67+ messages in thread
From: Rich Felker @ 2016-07-04 1:48 UTC (permalink / raw)
To: Yoshinori Sato; +Cc: linux-sh, linux-kernel
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
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [PATCH v5 04/22] sh: Use P1SEGADDR
2016-07-04 1:48 ` Rich Felker
@ 2016-07-06 14:11 ` Yoshinori Sato
2016-07-06 14:53 ` Rich Felker
0 siblings, 1 reply; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-06 14:11 UTC (permalink / raw)
To: Rich Felker; +Cc: linux-sh, linux-kernel
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>
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [PATCH v5 04/22] sh: Use P1SEGADDR
2016-07-06 14:11 ` Yoshinori Sato
@ 2016-07-06 14:53 ` Rich Felker
0 siblings, 0 replies; 67+ messages in thread
From: Rich Felker @ 2016-07-06 14:53 UTC (permalink / raw)
To: Yoshinori Sato; +Cc: linux-sh, linux-kernel
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
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v5 05/22] sh: command line passing chosen/bootargs in devicetree
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
` (3 preceding siblings ...)
2016-07-03 16:46 ` [PATCH v5 04/22] sh: Use P1SEGADDR Yoshinori Sato
@ 2016-07-03 16:46 ` Yoshinori Sato
2016-07-03 16:46 ` [PATCH v5 06/22] sh: FDT address save before bank change Yoshinori Sato
` (16 subsequent siblings)
21 siblings, 0 replies; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: linux-sh, linux-kernel; +Cc: Yoshinori Sato
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
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH v5 06/22] sh: FDT address save before bank change
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
` (4 preceding siblings ...)
2016-07-03 16:46 ` [PATCH v5 05/22] sh: command line passing chosen/bootargs in devicetree Yoshinori Sato
@ 2016-07-03 16:46 ` Yoshinori Sato
2016-07-03 16:46 ` [PATCH v5 07/22] sh: Passing FDT address on zImage Yoshinori Sato
` (15 subsequent siblings)
21 siblings, 0 replies; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: linux-sh, linux-kernel; +Cc: Yoshinori Sato
SH3/4 have register bank of R0-R7.
Preset FDT address assigned bank depend on boot loader.
Before setting a bank because we don't depend on a boot loader, it's evacuated.
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
arch/sh/kernel/head_32.S | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S
index 974bc15..ef44fe8 100644
--- a/arch/sh/kernel/head_32.S
+++ b/arch/sh/kernel/head_32.S
@@ -58,6 +58,9 @@ ENTRY(empty_zero_page)
*
*/
ENTRY(_stext)
+#ifdef CONFIG_OF
+ mov r4, r12 ! Store device tree blob pointer
+#endif
! Initialize Status Register
mov.l 1f, r0 ! MD=1, RB=0, BL=0, IMASK=0xF
ldc r0, sr
@@ -67,10 +70,6 @@ ENTRY(_stext)
ldc r0, r6_bank
#endif
-#ifdef CONFIG_OF
- mov r4, r12 ! Store device tree blob pointer in r12
-#endif
-
/*
* Prefetch if possible to reduce cache miss penalty.
*
--
2.7.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH v5 07/22] sh: Passing FDT address on zImage
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
` (5 preceding siblings ...)
2016-07-03 16:46 ` [PATCH v5 06/22] sh: FDT address save before bank change Yoshinori Sato
@ 2016-07-03 16:46 ` Yoshinori Sato
2016-07-03 16:46 ` [PATCH v5 08/22] sh: Disable board specific code on device tree mode Yoshinori Sato
` (14 subsequent siblings)
21 siblings, 0 replies; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: linux-sh, linux-kernel; +Cc: Yoshinori Sato
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
arch/sh/boot/compressed/head_32.S | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/sh/boot/compressed/head_32.S b/arch/sh/boot/compressed/head_32.S
index 3e15032..a980c48 100644
--- a/arch/sh/boot/compressed/head_32.S
+++ b/arch/sh/boot/compressed/head_32.S
@@ -11,10 +11,11 @@
.global startup
startup:
+ /* Save FDT address */
+ mov r4, r13
/* Load initial status register */
mov.l init_sr, r1
ldc r1, sr
-
/* Move myself to proper location if necessary */
mova 1f, r0
mov.l 1f, r2
@@ -83,7 +84,7 @@ l1:
/* Jump to the start of the decompressed kernel */
mov.l kernel_start_addr, r0
jmp @r0
- nop
+ mov r13,r4
.align 2
bss_start_addr:
--
2.7.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH v5 08/22] sh: Disable board specific code on device tree mode
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
` (6 preceding siblings ...)
2016-07-03 16:46 ` [PATCH v5 07/22] sh: Passing FDT address on zImage Yoshinori Sato
@ 2016-07-03 16:46 ` Yoshinori Sato
2016-07-03 16:46 ` [PATCH v5 09/22] sh: Use GENERIC_IOMAP " Yoshinori Sato
` (13 subsequent siblings)
21 siblings, 0 replies; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: linux-sh, linux-kernel; +Cc: Yoshinori Sato
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
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH v5 09/22] sh: Use GENERIC_IOMAP on device tree mode
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
` (7 preceding siblings ...)
2016-07-03 16:46 ` [PATCH v5 08/22] sh: Disable board specific code on device tree mode Yoshinori Sato
@ 2016-07-03 16:46 ` Yoshinori Sato
2016-07-03 16:46 ` [PATCH v5 10/22] sh: Add board specific initialize of of-generic Yoshinori Sato
` (12 subsequent siblings)
21 siblings, 0 replies; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: linux-sh, linux-kernel; +Cc: Yoshinori Sato
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
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH v5 10/22] sh: Add board specific initialize of of-generic
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
` (8 preceding siblings ...)
2016-07-03 16:46 ` [PATCH v5 09/22] sh: Use GENERIC_IOMAP " Yoshinori Sato
@ 2016-07-03 16:46 ` Yoshinori Sato
2016-07-04 1:35 ` Rich Felker
2016-07-03 16:46 ` [PATCH v5 11/22] sh: SH7750/51 CPG Driver Yoshinori Sato
` (11 subsequent siblings)
21 siblings, 1 reply; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: linux-sh, linux-kernel; +Cc: Yoshinori Sato
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
^ permalink raw reply related [flat|nested] 67+ messages in thread
* Re: [PATCH v5 10/22] sh: Add board specific initialize of of-generic
2016-07-03 16:46 ` [PATCH v5 10/22] sh: Add board specific initialize of of-generic Yoshinori Sato
@ 2016-07-04 1:35 ` Rich Felker
2016-07-06 14:27 ` Yoshinori Sato
0 siblings, 1 reply; 67+ messages in thread
From: Rich Felker @ 2016-07-04 1:35 UTC (permalink / raw)
To: Yoshinori Sato; +Cc: linux-sh, linux-kernel
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
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [PATCH v5 10/22] sh: Add board specific initialize of of-generic
2016-07-04 1:35 ` Rich Felker
@ 2016-07-06 14:27 ` Yoshinori Sato
0 siblings, 0 replies; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-06 14:27 UTC (permalink / raw)
To: Rich Felker; +Cc: linux-sh, linux-kernel
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>
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v5 11/22] sh: SH7750/51 CPG Driver
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
` (9 preceding siblings ...)
2016-07-03 16:46 ` [PATCH v5 10/22] sh: Add board specific initialize of of-generic Yoshinori Sato
@ 2016-07-03 16:46 ` Yoshinori Sato
[not found] ` <1467564402-2649-1-git-send-email-ysato-Rn4VEauK+AKRv+LV9MX5uooqe+aC9MnS@public.gmane.org>
` (10 subsequent siblings)
21 siblings, 0 replies; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: linux-sh, linux-kernel; +Cc: Yoshinori Sato
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
^ permalink raw reply related [flat|nested] 67+ messages in thread
[parent not found: <1467564402-2649-1-git-send-email-ysato-Rn4VEauK+AKRv+LV9MX5uooqe+aC9MnS@public.gmane.org>]
* [PATCH v6 12/22] sh: Add PCI host bridge driver for SH7751
[not found] ` <1467564402-2649-1-git-send-email-ysato-Rn4VEauK+AKRv+LV9MX5uooqe+aC9MnS@public.gmane.org>
@ 2016-07-03 16:46 ` Yoshinori Sato
2016-07-05 15:53 ` Rob Herring
[not found] ` <1467564402-2649-13-git-send-email-ysato-Rn4VEauK+AKRv+LV9MX5uooqe+aC9MnS@public.gmane.org>
2016-07-03 16:46 ` [PATCH v5 13/22] sh: irqchip: SH7751 IRQCHIP Driver Yoshinori Sato
1 sibling, 2 replies; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-pci-u79uwXL29TY76Z2rM5mHXA, linux-sh-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Yoshinori Sato
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
^ permalink raw reply related [flat|nested] 67+ messages in thread
* Re: [PATCH v6 12/22] sh: Add PCI host bridge driver for SH7751
2016-07-03 16:46 ` [PATCH v6 12/22] sh: Add PCI host bridge driver for SH7751 Yoshinori Sato
@ 2016-07-05 15:53 ` Rob Herring
2016-07-06 16:19 ` Yoshinori Sato
[not found] ` <1467564402-2649-13-git-send-email-ysato-Rn4VEauK+AKRv+LV9MX5uooqe+aC9MnS@public.gmane.org>
1 sibling, 1 reply; 67+ messages in thread
From: Rob Herring @ 2016-07-05 15:53 UTC (permalink / raw)
To: Yoshinori Sato; +Cc: devicetree, linux-pci, linux-sh, linux-kernel
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
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [PATCH v6 12/22] sh: Add PCI host bridge driver for SH7751
2016-07-05 15:53 ` Rob Herring
@ 2016-07-06 16:19 ` Yoshinori Sato
0 siblings, 0 replies; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-06 16:19 UTC (permalink / raw)
To: Rob Herring; +Cc: devicetree, linux-pci, linux-sh, linux-kernel
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>
^ permalink raw reply [flat|nested] 67+ messages in thread
[parent not found: <1467564402-2649-13-git-send-email-ysato-Rn4VEauK+AKRv+LV9MX5uooqe+aC9MnS@public.gmane.org>]
* Re: [PATCH v6 12/22] sh: Add PCI host bridge driver for SH7751
[not found] ` <1467564402-2649-13-git-send-email-ysato-Rn4VEauK+AKRv+LV9MX5uooqe+aC9MnS@public.gmane.org>
@ 2016-07-22 22:59 ` Bjorn Helgaas
0 siblings, 0 replies; 67+ messages in thread
From: Bjorn Helgaas @ 2016-07-22 22:59 UTC (permalink / raw)
To: Yoshinori Sato
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-pci-u79uwXL29TY76Z2rM5mHXA, linux-sh-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
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.
I'd like some details here about why we want this new driver. Will
the old one be removed? How should a user choose which one to use?
> 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
How do you plan to merge this? It looks like part of a large series,
and I've only seen a few pieces of it. The ones you've posted to
linux-pci seem mostly OK. I have a few minor comments below, but
after you fix those and write some text for the changelogs, I can ack
them and you can merge them along with the rest of the series.
Bjorn
> 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 */
Follow the indentation style of include/uapi/linux/pci_regs.h,
drivers/pci/host/pcie-rcar.c, drivers/pci/host/pci-mvebu.c, etc.:
#define SH4_PCICR 0x100
#define SH4_PCICR_PREFIX 0xA5000000
> + #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 */
The above are unused and can be omitted.
> + #define SH4_PCICR_ARBM BIT(6) /* PCI Arbitration Mode */
> +#define SH4_PCICR_MD (BIT(4) | BIT(5)) /* MD9 and MD10 status */
Indentation error (should match other fields above). Also, unused, so
can just be omitted.
> + #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 */
Above are unused.
> + #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 */
Unused.
> +#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 */
Field names are unused. You do write 0xc3ff to SH4_PCIINTM, but it's
a pain to match that up with these definitions. Either write out the
masks here, e.g., "#define SH4_PCIINTM_MRDPEIM 0x00000001", or build
up the SH4_PCIINTM from these definitions, or both.
> +#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 */
Field names unused. At least SH4_PCIPAR_CFGEN *could* be used in
CONFIG_CMD() below.
> +#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 ... */
See ... what?
> +#define SH4_PCIBCR1 0x1E0 /* Memory BCR1 Register */
> + #define SH4_PCIMBR0 SH4_PCIBCR1
Unused.
> +#define SH4_PCIBCR2 0x1E4 /* Memory BCR2 Register */
> + #define SH4_PCIMBMR0 SH4_PCIBCR2
Unused.
> +#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
Unused.
> +#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 */
Unused.
> +#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);
Use dev_info() so we can associate the message with a device and driver.
> + 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);
dev_info()
> + 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");
dev_warn()
> + 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
> + */
Multi-line comment style is:
/*
* set the command/...
* ...
*/
> + 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
>
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v5 13/22] sh: irqchip: SH7751 IRQCHIP Driver
[not found] ` <1467564402-2649-1-git-send-email-ysato-Rn4VEauK+AKRv+LV9MX5uooqe+aC9MnS@public.gmane.org>
2016-07-03 16:46 ` [PATCH v6 12/22] sh: Add PCI host bridge driver for SH7751 Yoshinori Sato
@ 2016-07-03 16:46 ` Yoshinori Sato
1 sibling, 0 replies; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-sh-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Yoshinori Sato
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
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH v5 14/22] sh: SH7751 core dtsi
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
` (11 preceding siblings ...)
[not found] ` <1467564402-2649-1-git-send-email-ysato-Rn4VEauK+AKRv+LV9MX5uooqe+aC9MnS@public.gmane.org>
@ 2016-07-03 16:46 ` Yoshinori Sato
2016-07-03 16:46 ` [PATCH v5 15/22] sh: Move common PCI stuff to arch/sh/kernel Yoshinori Sato
` (8 subsequent siblings)
21 siblings, 0 replies; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: devicetree, linux-sh, linux-kernel; +Cc: Yoshinori Sato
SH7751 core and internal peripheral define.
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
arch/sh/boot/dts/include/dt-bindings | 1 +
arch/sh/boot/dts/sh7751.dtsi | 83 ++++++++++++++++++++++
include/dt-bindings/clock/renesas-sh7750.h | 26 +++++++
include/dt-bindings/interrupt-controller/sh_intc.h | 2 +
4 files changed, 112 insertions(+)
create mode 120000 arch/sh/boot/dts/include/dt-bindings
create mode 100644 arch/sh/boot/dts/sh7751.dtsi
create mode 100644 include/dt-bindings/clock/renesas-sh7750.h
create mode 100644 include/dt-bindings/interrupt-controller/sh_intc.h
diff --git a/arch/sh/boot/dts/include/dt-bindings b/arch/sh/boot/dts/include/dt-bindings
new file mode 120000
index 0000000..08c00e4
--- /dev/null
+++ b/arch/sh/boot/dts/include/dt-bindings
@@ -0,0 +1 @@
+../../../../../include/dt-bindings
\ No newline at end of file
diff --git a/arch/sh/boot/dts/sh7751.dtsi b/arch/sh/boot/dts/sh7751.dtsi
new file mode 100644
index 0000000..713e72e
--- /dev/null
+++ b/arch/sh/boot/dts/sh7751.dtsi
@@ -0,0 +1,83 @@
+/*
+ * Device Tree Source for the SH7751
+ *
+ * Copyright (C) 2016 Yoshinori Sato
+ */
+
+#include <dt-bindings/interrupt-controller/sh_intc.h>
+#include <dt-bindings/clock/renesas-sh7750.h>
+
+/ {
+ oclk: oscillator {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <0>;
+ };
+ cpg: clock-controller@ffc00000 {
+ compatible = "renesas,sh7750-cpg";
+ clocks = <&oclk>;
+ #clock-cells = <1>;
+ renesas,mult = <12>;
+ reg = <0xffc00000 32>, <0xfe0a0000 16>;
+ };
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cpu@0 {
+ compatible = "renesas,sh4", "renesas,sh";
+ clock-frequency = <266666666>;
+ };
+ };
+ shintc: interrupt-controller@ffd00000 {
+ compatible = "renesas,sh7751-intc";
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ reg = <0xffd00000 14>, <0xfe080000 128>;
+
+ };
+ sci0: serial@ffe00000 {
+ compatible = "renesas,sci";
+ reg = <0xffe00000 0x20>;
+ interrupts = <evt2irq(0x4e0) 0>,
+ <evt2irq(0x500) 0>,
+ <evt2irq(0x540) 0>,
+ <evt2irq(0x520) 0>;
+ clocks = <&cpg SH7750_CLK_SCI>;
+ clock-names = "fck";
+ status = "disabled";
+ };
+ sci1: serial@ffe80000 {
+ compatible = "renesas,scif";
+ reg = <0xffe80000 0x100>;
+ interrupts = <evt2irq(0x700) 0>,
+ <evt2irq(0x720) 0>,
+ <evt2irq(0x760) 0>,
+ <evt2irq(0x740) 0>;
+ clocks = <&cpg SH7750_CLK_SCIF>;
+ clock-names = "fck";
+ status = "disabled";
+ };
+ tmu: timer@ffd80000 {
+ compatible = "renesas,tmu";
+ reg = <0xffd80000 12>;
+ interrupts = <evt2irq(0x400) 0>,
+ <evt2irq(0x420) 0>,
+ <evt2irq(0x440) 0>;
+ clocks = <&cpg SH7750_CLK_TMU0>;
+ clock-names = "fck";
+ renesas,channels-mask = <0x03>;
+ };
+ pci: pci-controller@fe200000 {
+ compatible = "renesas,sh7751-pci";
+ 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>;
+ status = "disabled";
+ };
+};
diff --git a/include/dt-bindings/clock/renesas-sh7750.h b/include/dt-bindings/clock/renesas-sh7750.h
new file mode 100644
index 0000000..546c0b1
--- /dev/null
+++ b/include/dt-bindings/clock/renesas-sh7750.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 Yoshinori Sato
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef __DT_BINDINGS_CLOCK_RENESAS_SH7750_H__
+#define __DT_BINDINGS_CLOCK_RENESAS_SH7750_H__
+
+#define SH7750_CLK_SCI 0
+#define SH7750_CLK_RTC 1
+#define SH7750_CLK_TMU0 2
+#define SH7750_CLK_TMU1 3
+#define SH7750_CLK_TMU2 4
+#define SH7750_CLK_SCIF 5
+#define SH7750_CLK_DMAC 6
+#define SH7750_CLK_UBC 7
+#define SH7750_CLK_SQ 8
+#define SH7750_CLK_INTC 9
+#define SH7750_CLK_TMU3 10
+#define SH7750_CLK_TMU4 11
+#define SH7750_CLK_PCIC 12
+
+#endif /* __DT_BINDINGS_CLOCK_RENESAS_CPG_MSSR_H__ */
diff --git a/include/dt-bindings/interrupt-controller/sh_intc.h b/include/dt-bindings/interrupt-controller/sh_intc.h
new file mode 100644
index 0000000..8c9dcdc
--- /dev/null
+++ b/include/dt-bindings/interrupt-controller/sh_intc.h
@@ -0,0 +1,2 @@
+#define evt2irq(evt) (((evt) >> 5) - 16)
+#define irq2evt(irq) (((irq) + 16) << 5)
--
2.7.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH v5 15/22] sh: Move common PCI stuff to arch/sh/kernel
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
` (12 preceding siblings ...)
2016-07-03 16:46 ` [PATCH v5 14/22] sh: SH7751 core dtsi Yoshinori Sato
@ 2016-07-03 16:46 ` Yoshinori Sato
2016-07-04 1:55 ` Rich Felker
2016-07-03 16:46 ` [PATCH v5 16/22] pci: pci_config_window move to linux/pci.h Yoshinori Sato
` (7 subsequent siblings)
21 siblings, 1 reply; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: linux-sh, linux-kernel; +Cc: Yoshinori Sato
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
^ permalink raw reply related [flat|nested] 67+ messages in thread
* Re: [PATCH v5 15/22] sh: Move common PCI stuff to arch/sh/kernel
2016-07-03 16:46 ` [PATCH v5 15/22] sh: Move common PCI stuff to arch/sh/kernel Yoshinori Sato
@ 2016-07-04 1:55 ` Rich Felker
2016-07-06 16:17 ` Yoshinori Sato
0 siblings, 1 reply; 67+ messages in thread
From: Rich Felker @ 2016-07-04 1:55 UTC (permalink / raw)
To: Yoshinori Sato; +Cc: linux-sh, linux-kernel
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
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [PATCH v5 15/22] sh: Move common PCI stuff to arch/sh/kernel
2016-07-04 1:55 ` Rich Felker
@ 2016-07-06 16:17 ` Yoshinori Sato
0 siblings, 0 replies; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-06 16:17 UTC (permalink / raw)
To: Rich Felker; +Cc: linux-sh, linux-kernel
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>
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v5 16/22] pci: pci_config_window move to linux/pci.h
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
` (13 preceding siblings ...)
2016-07-03 16:46 ` [PATCH v5 15/22] sh: Move common PCI stuff to arch/sh/kernel Yoshinori Sato
@ 2016-07-03 16:46 ` Yoshinori Sato
2016-07-03 16:46 ` [PATCH v5 17/22] pci: PCI_HOST_GENERIC enable for SH Yoshinori Sato
` (6 subsequent siblings)
21 siblings, 0 replies; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: linux-pci, linux-sh, linux-kernel; +Cc: Yoshinori Sato
Chanegs v4
none
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
drivers/pci/ecam.h | 17 +----------------
include/linux/pci.h | 18 ++++++++++++++++++
2 files changed, 19 insertions(+), 16 deletions(-)
diff --git a/drivers/pci/ecam.h b/drivers/pci/ecam.h
index 9878beb..f110091 100644
--- a/drivers/pci/ecam.h
+++ b/drivers/pci/ecam.h
@@ -18,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <linux/pci.h>
/*
* struct to hold pci ops and bus shift of the config window
@@ -31,22 +32,6 @@ struct pci_ecam_ops {
struct pci_config_window *);
};
-/*
- * struct to hold the mappings of a config space window. This
- * is expected to be used as sysdata for PCI controllers that
- * use ECAM.
- */
-struct pci_config_window {
- struct resource res;
- struct resource busr;
- void *priv;
- struct pci_ecam_ops *ops;
- union {
- void __iomem *win; /* 64-bit single mapping */
- void __iomem **winp; /* 32-bit per-bus mapping */
- };
-};
-
/* create and free pci_config_window */
struct pci_config_window *pci_ecam_create(struct device *dev,
struct resource *cfgres, struct resource *busr,
diff --git a/include/linux/pci.h b/include/linux/pci.h
index b67e4df..398896f 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -2026,6 +2026,24 @@ static inline bool pci_ari_enabled(struct pci_bus *bus)
return bus->self && bus->self->ari_enabled;
}
+/*
+ * struct to hold the mappings of a config space window. This
+ * is expected to be used as sysdata for PCI controllers that
+ * use ECAM.
+ */
+struct pci_ecam_ops;
+
+struct pci_config_window {
+ struct resource res;
+ struct resource busr;
+ void *priv;
+ struct pci_ecam_ops *ops;
+ union {
+ void __iomem *win; /* 64-bit single mapping */
+ void __iomem **winp; /* 32-bit per-bus mapping */
+ };
+};
+
/* provide the legacy pci_dma_* API */
#include <linux/pci-dma-compat.h>
--
2.7.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH v5 17/22] pci: PCI_HOST_GENERIC enable for SH
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
` (14 preceding siblings ...)
2016-07-03 16:46 ` [PATCH v5 16/22] pci: pci_config_window move to linux/pci.h Yoshinori Sato
@ 2016-07-03 16:46 ` Yoshinori Sato
2016-07-03 16:46 ` [PATCH v5 18/22] sh: Add separate DTB build rule Yoshinori Sato
` (5 subsequent siblings)
21 siblings, 0 replies; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: linux-pci, linux-sh, linux-kernel; +Cc: Yoshinori Sato
Changes v4
none
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
drivers/pci/host/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index df60505..83184eb 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -83,7 +83,7 @@ config PCI_HOST_COMMON
config PCI_HOST_GENERIC
bool "Generic PCI host controller"
- depends on (ARM || ARM64) && OF
+ depends on (ARM || ARM64 || SUPERH) && OF
select PCI_HOST_COMMON
help
Say Y here if you want to support a simple generic PCI host
--
2.7.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH v5 18/22] sh: Add separate DTB build rule
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
` (15 preceding siblings ...)
2016-07-03 16:46 ` [PATCH v5 17/22] pci: PCI_HOST_GENERIC enable for SH Yoshinori Sato
@ 2016-07-03 16:46 ` Yoshinori Sato
2016-07-03 16:46 ` [PATCH v5 19/22] sh: IO-DATA HDL-U (a.k.a landisk) IRQCHIP driver Yoshinori Sato
` (4 subsequent siblings)
21 siblings, 0 replies; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: linux-sh, linux-kernel; +Cc: Yoshinori Sato
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
arch/sh/Makefile | 7 +++++++
arch/sh/boot/dts/Makefile | 2 ++
2 files changed, 9 insertions(+)
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index 8adffa8..a44e630 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -189,6 +189,13 @@ drivers-$(CONFIG_OPROFILE) += arch/sh/oprofile/
boot := arch/sh/boot
+%.dtb %.dtb.S %.dtb.o: | scripts
+ $(Q)$(MAKE) $(build)=arch/sh/boot/dts arch/sh/boot/dts/$@
+
+PHONY += dtbs
+dtbs: scripts
+ $(Q)$(MAKE) $(build)=arch/sh/boot/dts
+
cflags-y += $(foreach d, $(cpuincdir-y), -Iarch/sh/include/$(d)) \
$(foreach d, $(machdir-y), -Iarch/sh/include/$(d))
diff --git a/arch/sh/boot/dts/Makefile b/arch/sh/boot/dts/Makefile
index e5ce3a0..38fdc38 100644
--- a/arch/sh/boot/dts/Makefile
+++ b/arch/sh/boot/dts/Makefile
@@ -1,3 +1,5 @@
obj-$(CONFIG_USE_BUILTIN_DTB) += $(patsubst "%",%,$(CONFIG_BUILTIN_DTB_SOURCE)).dtb.o
+dtstree := $(srctree)/$(src)
clean-files := *.dtb.S
+always := $(dtb-y)
--
2.7.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH v5 19/22] sh: IO-DATA HDL-U (a.k.a landisk) IRQCHIP driver
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
` (16 preceding siblings ...)
2016-07-03 16:46 ` [PATCH v5 18/22] sh: Add separate DTB build rule Yoshinori Sato
@ 2016-07-03 16:46 ` Yoshinori Sato
2016-07-11 14:02 ` Rob Herring
2016-07-03 16:46 ` [PATCH v5 20/22] sh: IO-DATA HDL-U (a.k.a landisk) DeviceTree Yoshinori Sato
` (3 subsequent siblings)
21 siblings, 1 reply; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: devicetree, linux-sh, linux-kernel; +Cc: Yoshinori Sato
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
.../interrupt-controller/iodata-landisk.txt | 31 ++++++++++
drivers/irqchip/Makefile | 2 +-
drivers/irqchip/irq-io-landisk.c | 72 ++++++++++++++++++++++
3 files changed, 104 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/iodata-landisk.txt
create mode 100644 drivers/irqchip/irq-io-landisk.c
diff --git a/Documentation/devicetree/bindings/interrupt-controller/iodata-landisk.txt b/Documentation/devicetree/bindings/interrupt-controller/iodata-landisk.txt
new file mode 100644
index 0000000..cf461dc
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/iodata-landisk.txt
@@ -0,0 +1,31 @@
+DT bindings for the I/O DATA HDL-U interrupt controller
+
+Required properties:
+
+ - compatible: has to be "iodata,landisk-intc".
+
+ - reg: Base address and length of interrupt controller register.
+
+ - #interrupt-cells: has to be <1>: an interrupt index.
+
+ - #address-cells: has to be <0>
+
+ - interrupt-map: Interrupt mapping on parent controller.
+
+Example
+-------
+
+ cpldintc: cpld@b0000000 {
+ compatible = "iodata,landisk-intc";
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ reg = <0xb0000000 8>;
+ interrupt-map=<0 &shintc evt2irq(0x2a0)>,
+ <1 &shintc evt2irq(0x2c0)>,
+ <2 &shintc evt2irq(0x2e0)>,
+ <3 &shintc evt2irq(0x300)>,
+ <4 &shintc evt2irq(0x320)>,
+ <5 &shintc evt2irq(0x340)>,
+ <6 &shintc evt2irq(0x360)>,
+ <7 &shintc evt2irq(0x380)>;
+ };
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 2ab5735..5e225cf 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -69,4 +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
+obj-$(CONFIG_RENESAS_SH_INTC) += irq-renesas-sh7751.o irq-io-landisk.o
diff --git a/drivers/irqchip/irq-io-landisk.c b/drivers/irqchip/irq-io-landisk.c
new file mode 100644
index 0000000..b7f3b41
--- /dev/null
+++ b/drivers/irqchip/irq-io-landisk.c
@@ -0,0 +1,72 @@
+/*
+ * IO-DATA LANDISK CPLD IRQ driver
+ *
+ * Copyright 2016 Yoshinori Sato <ysato@users.sourceforge.jp>
+ */
+
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+
+static void landisk_mask_irq(struct irq_data *data)
+{
+ u8 mask = __raw_readb(data->chip_data + 5);
+
+ mask &= ~(1 << (data->irq - 5));
+ __raw_writeb(mask, data->chip_data + 5);
+}
+
+static void landisk_unmask_irq(struct irq_data *data)
+{
+ u8 mask = __raw_readb(data->chip_data + 5);
+
+ mask |= (1 << (data->irq - 5));
+ __raw_writeb(mask, data->chip_data + 5);
+}
+
+static struct irq_chip cpld_irq_chip = {
+ .name = "LANDISK-CPLD",
+ .irq_unmask = landisk_unmask_irq,
+ .irq_mask = landisk_mask_irq,
+};
+
+static int cpld_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hw_irq_num)
+{
+ irq_set_chip_and_handler(virq, &cpld_irq_chip,
+ handle_simple_irq);
+ irq_set_chip_data(virq, d->host_data);
+
+ return 0;
+}
+
+static struct irq_domain_ops irq_ops = {
+ .xlate = irq_domain_xlate_onecell,
+ .map = cpld_map,
+};
+
+static int __init landisk_intc_of_init(struct device_node *intc,
+ struct device_node *parent)
+{
+ struct irq_domain *domain, *pdomain;
+ int num_irqpin;
+ void *baseaddr;
+
+ baseaddr = of_iomap(intc, 0);
+ pdomain = irq_find_host(parent);
+ of_get_property(intc, "interrupt-map", &num_irqpin);
+ num_irqpin /= sizeof(u32) * 3;
+ domain = irq_domain_create_hierarchy(pdomain, 0, num_irqpin,
+ of_node_to_fwnode(intc),
+ &irq_ops, baseaddr);
+ if (!domain)
+ panic("%s: unable to create IRQ domain\n", intc->full_name);
+ irq_domain_associate_many(domain, 5, 0, 8);
+ return 0;
+}
+
+IRQCHIP_DECLARE(cpld_intc, "iodata,landisk-intc", landisk_intc_of_init);
--
2.7.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* Re: [PATCH v5 19/22] sh: IO-DATA HDL-U (a.k.a landisk) IRQCHIP driver
2016-07-03 16:46 ` [PATCH v5 19/22] sh: IO-DATA HDL-U (a.k.a landisk) IRQCHIP driver Yoshinori Sato
@ 2016-07-11 14:02 ` Rob Herring
0 siblings, 0 replies; 67+ messages in thread
From: Rob Herring @ 2016-07-11 14:02 UTC (permalink / raw)
To: Yoshinori Sato; +Cc: devicetree, linux-sh, linux-kernel
On Mon, Jul 04, 2016 at 01:46:39AM +0900, Yoshinori Sato wrote:
> Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
> ---
> .../interrupt-controller/iodata-landisk.txt | 31 ++++++++++
> drivers/irqchip/Makefile | 2 +-
> drivers/irqchip/irq-io-landisk.c | 72 ++++++++++++++++++++++
> 3 files changed, 104 insertions(+), 1 deletion(-)
> create mode 100644 Documentation/devicetree/bindings/interrupt-controller/iodata-landisk.txt
> create mode 100644 drivers/irqchip/irq-io-landisk.c
>
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/iodata-landisk.txt b/Documentation/devicetree/bindings/interrupt-controller/iodata-landisk.txt
> new file mode 100644
> index 0000000..cf461dc
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/iodata-landisk.txt
> @@ -0,0 +1,31 @@
> +DT bindings for the I/O DATA HDL-U interrupt controller
> +
> +Required properties:
> +
> + - compatible: has to be "iodata,landisk-intc".
> +
> + - reg: Base address and length of interrupt controller register.
> +
> + - #interrupt-cells: has to be <1>: an interrupt index.
> +
> + - #address-cells: has to be <0>
> +
> + - interrupt-map: Interrupt mapping on parent controller.
> +
> +Example
> +-------
> +
> + cpldintc: cpld@b0000000 {
> + compatible = "iodata,landisk-intc";
> + #interrupt-cells = <1>;
> + #address-cells = <0>;
> + reg = <0xb0000000 8>;
> + interrupt-map=<0 &shintc evt2irq(0x2a0)>,
What is evt2irq? We only allow simple defines for DT files, not complex
macros.
Spaces around the '=' also needed.
> + <1 &shintc evt2irq(0x2c0)>,
> + <2 &shintc evt2irq(0x2e0)>,
> + <3 &shintc evt2irq(0x300)>,
> + <4 &shintc evt2irq(0x320)>,
> + <5 &shintc evt2irq(0x340)>,
> + <6 &shintc evt2irq(0x360)>,
> + <7 &shintc evt2irq(0x380)>;
> + };
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v5 20/22] sh: IO-DATA HDL-U (a.k.a landisk) DeviceTree
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
` (17 preceding siblings ...)
2016-07-03 16:46 ` [PATCH v5 19/22] sh: IO-DATA HDL-U (a.k.a landisk) IRQCHIP driver Yoshinori Sato
@ 2016-07-03 16:46 ` Yoshinori Sato
2016-07-03 19:00 ` Sergei Shtylyov
2016-07-03 16:46 ` [PATCH v5 21/22] sh: Renesas RTS7751R2Dplus (a.k.a R2Dplus) IRQCHIP Driver Yoshinori Sato
` (2 subsequent siblings)
21 siblings, 1 reply; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: devicetree, linux-sh, linux-kernel; +Cc: Yoshinori Sato
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
arch/sh/boot/dts/Makefile | 2 ++
arch/sh/boot/dts/landisk.dts | 61 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 63 insertions(+)
create mode 100644 arch/sh/boot/dts/landisk.dts
diff --git a/arch/sh/boot/dts/Makefile b/arch/sh/boot/dts/Makefile
index 38fdc38..cf5aec4 100644
--- a/arch/sh/boot/dts/Makefile
+++ b/arch/sh/boot/dts/Makefile
@@ -1,5 +1,7 @@
obj-$(CONFIG_USE_BUILTIN_DTB) += $(patsubst "%",%,$(CONFIG_BUILTIN_DTB_SOURCE)).dtb.o
+dtb-y += landisk.dtb
+
dtstree := $(srctree)/$(src)
clean-files := *.dtb.S
always := $(dtb-y)
diff --git a/arch/sh/boot/dts/landisk.dts b/arch/sh/boot/dts/landisk.dts
new file mode 100644
index 0000000..3745ae0
--- /dev/null
+++ b/arch/sh/boot/dts/landisk.dts
@@ -0,0 +1,61 @@
+/dts-v1/;
+
+#include "sh7751.dtsi"
+
+/ {
+ model = "iodata,HDL-U";
+ compatible = "iodata,hdl-u";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&shintc>;
+ chosen {
+ stdout-path = "serial1:115200n8";
+ };
+ aliases {
+ serial0 = &sci0;
+ serial1 = &sci1;
+ };
+
+ memory@0c000000 {
+ device_type = "memory";
+ reg = <0x0c000000 0x4000000>;
+ };
+
+ cpldintc: cpld@b0000000 {
+ compatible = "iodata,landisk-intc";
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ reg = <0xb0000000 8>;
+ interrupt-map=<0 &shintc evt2irq(0x2a0)>,
+ <1 &shintc evt2irq(0x2c0)>,
+ <2 &shintc evt2irq(0x2e0)>,
+ <3 &shintc evt2irq(0x300)>,
+ <4 &shintc evt2irq(0x320)>,
+ <5 &shintc evt2irq(0x340)>,
+ <6 &shintc evt2irq(0x360)>,
+ <7 &shintc evt2irq(0x380)>;
+ };
+};
+
+&oclk {
+ clock-frequency = <22222222>;
+};
+
+&sci0 {
+ status = "ok";
+};
+
+&sci1 {
+ status = "ok";
+};
+
+&pci {
+ compatible = "renesas,sh7751-pci", "iodata,landisk-pci";
+ interrupt-map-mask = <0x1800 0 7>;
+ interrupt-map = <0x0000 0 1 &cpldintc 0>,
+ <0x0800 0 1 &cpldintc 1>,
+ <0x1000 0 1 &cpldintc 2>,
+ <0x1000 0 2 &cpldintc 3>,
+ <0x1000 0 3 &cpldintc 0>;
+ status = "ok";
+};
--
2.7.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* Re: [PATCH v5 20/22] sh: IO-DATA HDL-U (a.k.a landisk) DeviceTree
2016-07-03 16:46 ` [PATCH v5 20/22] sh: IO-DATA HDL-U (a.k.a landisk) DeviceTree Yoshinori Sato
@ 2016-07-03 19:00 ` Sergei Shtylyov
2016-07-06 16:18 ` Yoshinori Sato
0 siblings, 1 reply; 67+ messages in thread
From: Sergei Shtylyov @ 2016-07-03 19:00 UTC (permalink / raw)
To: Yoshinori Sato, devicetree, linux-sh, linux-kernel
Hello.
On 07/03/2016 07:46 PM, Yoshinori Sato wrote:
> Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
[...]
> diff --git a/arch/sh/boot/dts/landisk.dts b/arch/sh/boot/dts/landisk.dts
> new file mode 100644
> index 0000000..3745ae0
> --- /dev/null
> +++ b/arch/sh/boot/dts/landisk.dts
> @@ -0,0 +1,61 @@
[...]
> +&oclk {
> + clock-frequency = <22222222>;
> +};
> +
> +&sci0 {
> + status = "ok";
Should be "okay". Sorry for overlooking it.
> +};
> +
> +&sci1 {
> + status = "ok";
Likewise.
[...]
MBR, Sergei
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [PATCH v5 20/22] sh: IO-DATA HDL-U (a.k.a landisk) DeviceTree
2016-07-03 19:00 ` Sergei Shtylyov
@ 2016-07-06 16:18 ` Yoshinori Sato
0 siblings, 0 replies; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-06 16:18 UTC (permalink / raw)
To: Sergei Shtylyov; +Cc: devicetree, linux-sh, linux-kernel
On Mon, 04 Jul 2016 04:00:59 +0900,
Sergei Shtylyov wrote:
>
> Hello.
>
> On 07/03/2016 07:46 PM, Yoshinori Sato wrote:
>
> > Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
>
> [...]
>
> > diff --git a/arch/sh/boot/dts/landisk.dts b/arch/sh/boot/dts/landisk.dts
> > new file mode 100644
> > index 0000000..3745ae0
> > --- /dev/null
> > +++ b/arch/sh/boot/dts/landisk.dts
> > @@ -0,0 +1,61 @@
> [...]
> > +&oclk {
> > + clock-frequency = <22222222>;
> > +};
> > +
> > +&sci0 {
> > + status = "ok";
>
> Should be "okay". Sorry for overlooking it.
>
> > +};
> > +
> > +&sci1 {
> > + status = "ok";
>
> Likewise.
>
> [...]
>
> MBR, Sergei
>
Updated.
Thanks.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-sh" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Yoshinori Sato
<ysato@users.sourceforge.jp>
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH v5 21/22] sh: Renesas RTS7751R2Dplus (a.k.a R2Dplus) IRQCHIP Driver
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
` (18 preceding siblings ...)
2016-07-03 16:46 ` [PATCH v5 20/22] sh: IO-DATA HDL-U (a.k.a landisk) DeviceTree Yoshinori Sato
@ 2016-07-03 16:46 ` Yoshinori Sato
2016-07-03 16:46 ` [PATCH v5 22/22] sh: Renesas RTS7751R2Dplus (a,k.a R2Dplus) DeviceTree Yoshinori Sato
2017-11-17 10:37 ` [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree John Paul Adrian Glaubitz
21 siblings, 0 replies; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: devicetree, linux-sh, linux-kernel; +Cc: Yoshinori Sato
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
.../interrupt-controller/renesas-r2dplus.txt | 38 ++++++++++
drivers/irqchip/Makefile | 2 +-
drivers/irqchip/irq-renesas-r2dplus.c | 88 ++++++++++++++++++++++
3 files changed, 127 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/renesas-r2dplus.txt
create mode 100644 drivers/irqchip/irq-renesas-r2dplus.c
diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas-r2dplus.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas-r2dplus.txt
new file mode 100644
index 0000000..5b74da4
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/renesas-r2dplus.txt
@@ -0,0 +1,38 @@
+DT bindings for the Renesas R0P751RLC0011RL (R2Dplus) interrupt controller
+
+Required properties:
+
+ - compatible: has to be "renesas,r2dplus-intc".
+
+ - reg: Base address and length of interrupt controller register.
+
+ - #interrupt-cells: has to be <1>: an interrupt index.
+
+ - #address-cells: has to be <0>
+
+ - interrupt-map: Interrupt mapping on parent controller.
+
+Example
+-------
+
+ fpgaintc: fpga@a4000000 {
+ compatible = "renesas,r2dplus-intc";
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ reg = <0xa4000000 0x40>;
+ interrupt-map=<0 &shintc evt2irq(0x200)>,
+ <1 &shintc evt2irq(0x220)>,
+ <2 &shintc evt2irq(0x240)>,
+ <3 &shintc evt2irq(0x260)>,
+ <4 &shintc evt2irq(0x280)>,
+ <5 &shintc evt2irq(0x2a0)>,
+ <6 &shintc evt2irq(0x2c0)>,
+ <7 &shintc evt2irq(0x2e0)>,
+ <8 &shintc evt2irq(0x300)>,
+ <9 &shintc evt2irq(0x320)>,
+ <10 &shintc evt2irq(0x340)>,
+ <11 &shintc evt2irq(0x360)>,
+ <12 &shintc evt2irq(0x380)>,
+ <13 &shintc evt2irq(0x3a0)>,
+ <14 &shintc evt2irq(0x3c0)>,
+ };
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 5e225cf..1e0f1c3 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -69,4 +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 irq-io-landisk.o
+obj-$(CONFIG_RENESAS_SH_INTC) += irq-renesas-sh7751.o irq-io-landisk.o irq-renesas-r2dplus.o
diff --git a/drivers/irqchip/irq-renesas-r2dplus.c b/drivers/irqchip/irq-renesas-r2dplus.c
new file mode 100644
index 0000000..3f80775
--- /dev/null
+++ b/drivers/irqchip/irq-renesas-r2dplus.c
@@ -0,0 +1,88 @@
+/*
+ * Renesas RTS7751R2D+ FPGA IRQ driver
+ *
+ * Copyright 2016 Yoshinori Sato <ysato@users.sourceforge.jp>
+ */
+
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+
+static const u16 mask_bit[] = {
+ BIT(11),
+ BIT(9),
+ BIT(8),
+ BIT(12),
+ BIT(10),
+ BIT(6),
+ BIT(5),
+ BIT(4),
+ BIT(7),
+ BIT(14),
+ BIT(13),
+ BIT(0),
+ BIT(15),
+};
+
+static void r2dplus_mask_irq(struct irq_data *data)
+{
+ u16 mask = __raw_readw(data->chip_data);
+
+ mask &= ~mask_bit[data->irq];
+ __raw_writew(mask, data->chip_data);
+}
+
+static void r2dplus_unmask_irq(struct irq_data *data)
+{
+ u16 mask = __raw_readw(data->chip_data);
+
+ mask |= mask_bit[data->irq];
+ __raw_writew(mask, data->chip_data);
+}
+
+static struct irq_chip fpga_irq_chip = {
+ .name = "R2DPLUS-FPGA",
+ .irq_unmask = r2dplus_unmask_irq,
+ .irq_mask = r2dplus_mask_irq,
+};
+
+static int fpga_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hw_irq_num)
+{
+ irq_set_chip_and_handler(virq, &fpga_irq_chip,
+ handle_simple_irq);
+ irq_set_chip_data(virq, d->host_data);
+
+ return 0;
+}
+
+static struct irq_domain_ops irq_ops = {
+ .xlate = irq_domain_xlate_onecell,
+ .map = fpga_map,
+};
+
+static int __init r2dplus_intc_of_init(struct device_node *intc,
+ struct device_node *parent)
+{
+ struct irq_domain *domain, *pdomain;
+ int num_irqpin;
+ void *baseaddr;
+
+ baseaddr = of_iomap(intc, 0);
+ pdomain = irq_find_host(parent);
+ of_get_property(intc, "interrupt-map", &num_irqpin);
+ num_irqpin /= sizeof(u32) * 3;
+ domain = irq_domain_create_hierarchy(pdomain, 0, num_irqpin,
+ of_node_to_fwnode(intc),
+ &irq_ops, baseaddr);
+ if (!domain)
+ panic("%s: unable to create IRQ domain\n", intc->full_name);
+ irq_domain_associate_many(domain, 0, 0, 16);
+ return 0;
+}
+
+IRQCHIP_DECLARE(cpld_intc, "renesas,r2dplus-intc", r2dplus_intc_of_init);
--
2.7.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH v5 22/22] sh: Renesas RTS7751R2Dplus (a,k.a R2Dplus) DeviceTree
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
` (19 preceding siblings ...)
2016-07-03 16:46 ` [PATCH v5 21/22] sh: Renesas RTS7751R2Dplus (a.k.a R2Dplus) IRQCHIP Driver Yoshinori Sato
@ 2016-07-03 16:46 ` Yoshinori Sato
2017-11-17 10:37 ` [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree John Paul Adrian Glaubitz
21 siblings, 0 replies; 67+ messages in thread
From: Yoshinori Sato @ 2016-07-03 16:46 UTC (permalink / raw)
To: devicetree, linux-sh, linux-kernel; +Cc: Yoshinori Sato
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
arch/sh/boot/dts/Makefile | 1 +
arch/sh/boot/dts/r2dplus.dts | 85 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 86 insertions(+)
create mode 100644 arch/sh/boot/dts/r2dplus.dts
diff --git a/arch/sh/boot/dts/Makefile b/arch/sh/boot/dts/Makefile
index cf5aec4..e059ce2b 100644
--- a/arch/sh/boot/dts/Makefile
+++ b/arch/sh/boot/dts/Makefile
@@ -1,6 +1,7 @@
obj-$(CONFIG_USE_BUILTIN_DTB) += $(patsubst "%",%,$(CONFIG_BUILTIN_DTB_SOURCE)).dtb.o
dtb-y += landisk.dtb
+otb-y += r2dplus.dtb
dtstree := $(srctree)/$(src)
clean-files := *.dtb.S
diff --git a/arch/sh/boot/dts/r2dplus.dts b/arch/sh/boot/dts/r2dplus.dts
new file mode 100644
index 0000000..f9c01f9
--- /dev/null
+++ b/arch/sh/boot/dts/r2dplus.dts
@@ -0,0 +1,85 @@
+/dts-v1/;
+
+#include "sh7751.dtsi"
+
+/ {
+ model = "renesas,RTS7751R2D+";
+ compatible = "renesas,r2dplus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&shintc>;
+ chosen {
+ stdout-path = "serial1:115200n8";
+ };
+ aliases {
+ serial1 = &sci1;
+ };
+
+ memory@0c000000 {
+ device_type = "memory";
+ reg = <0x0c000000 0x4000000>;
+ };
+
+ fpgaintc: fpga@a4000000 {
+ compatible = "renesas,r2dplus-intc";
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ reg = <0xa4000000 0x40>;
+ interrupt-map=<0 &shintc evt2irq(0x200)>,
+ <1 &shintc evt2irq(0x220)>,
+ <2 &shintc evt2irq(0x240)>,
+ <3 &shintc evt2irq(0x260)>,
+ <4 &shintc evt2irq(0x280)>,
+ <5 &shintc evt2irq(0x2a0)>,
+ <6 &shintc evt2irq(0x2c0)>,
+ <7 &shintc evt2irq(0x2e0)>,
+ <8 &shintc evt2irq(0x300)>,
+ <9 &shintc evt2irq(0x320)>,
+ <10 &shintc evt2irq(0x340)>,
+ <11 &shintc evt2irq(0x360)>,
+ <12 &shintc evt2irq(0x380)>,
+ <13 &shintc evt2irq(0x3a0)>,
+ <14 &shintc evt2irq(0x3c0)>;
+ };
+
+ ide: ide@b4001000 {
+ compatible = "ata-generic";
+ reg = <0xb4001000 0x10>, <0xb400080c 0x02>;
+ interrupt-parent = <&fpgaintc>;
+ interrupts = <1 0>;
+ reg-shift = <1>;
+ pio-mode = <0>;
+ };
+
+ sm501: display@13e00000 {
+ compatible = "smi,sm501";
+ reg = <0x10000000 0x13dfffff>, <0x13e00000 0x13ffffff>;
+ interrupt-parent = <&fpgaintc>;
+ interrupts = <4 0>;
+ mode = "640x480-16@60";
+ edid = [00 ff ff ff ff ff ff 00 04 21 00 00 00 00 00 00
+ 01 00 01 04 00 00 00 00 08 00 00 00 00 00 00 00
+ 00 00 00 20 00 00 01 40 01 00 01 00 01 00 01 00
+ 01 00 01 00 01 00 d6 09 80 a0 20 e0 2d 10 10 60
+ a2 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fd];
+ smi,devices = <1>;
+ };
+};
+
+&oclk {
+ clock-frequency = <60000000>;
+};
+
+&sci1 {
+ status = "ok";
+};
+
+&pci {
+ compatible = "renesas,sh7751-pci", "renesas.r2dplus-pci";
+ interrupt-map-mask = <0x1800 0 7>;
+ interrupt-map = <0x1000 0 1 &fpgaintc 3 0>;
+ status = "ok";
+};
--
2.7.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* Re: [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree
2016-07-03 16:46 [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree Yoshinori Sato
` (20 preceding siblings ...)
2016-07-03 16:46 ` [PATCH v5 22/22] sh: Renesas RTS7751R2Dplus (a,k.a R2Dplus) DeviceTree Yoshinori Sato
@ 2017-11-17 10:37 ` John Paul Adrian Glaubitz
2017-11-17 17:39 ` [J-core] " Rob Landley
21 siblings, 1 reply; 67+ messages in thread
From: John Paul Adrian Glaubitz @ 2017-11-17 10:37 UTC (permalink / raw)
To: Yoshinori Sato, linux-sh, linux-kernel, j-core
Hi there!
On 07/03/2016 06:46 PM, Yoshinori Sato wrote:
> 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.
This patch series - which would make a huge improvement - is still not
applied. It would be very useful to be able to test the device tree
implementation with QEMU.
Any of the SH maintainers can apply this?
Adrian
--
.''`. John Paul Adrian Glaubitz
: :' : Debian Developer - glaubitz@debian.org
`. `' Freie Universitaet Berlin - glaubitz@physik.fu-berlin.de
`- GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [J-core] [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree
2017-11-17 10:37 ` [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree John Paul Adrian Glaubitz
@ 2017-11-17 17:39 ` Rob Landley
2017-11-17 17:49 ` John Paul Adrian Glaubitz
0 siblings, 1 reply; 67+ messages in thread
From: Rob Landley @ 2017-11-17 17:39 UTC (permalink / raw)
To: John Paul Adrian Glaubitz, Yoshinori Sato, linux-sh, linux-kernel,
Rich Felker
On 11/17/2017 04:37 AM, John Paul Adrian Glaubitz wrote:
> Hi there!
>
> On 07/03/2016 06:46 PM, Yoshinori Sato wrote:
>> 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.
>
> This patch series - which would make a huge improvement - is still not
> applied. It would be very useful to be able to test the device tree
> implementation with QEMU.
>
> Any of the SH maintainers can apply this?
It's Rich's call, but given that it's _from_ one of the sh maintainers,
sounds to me like it can just go in if it still applies? (If there's
bugfixes needed they can go in -rc2 or so, after this merge window.)
Given that qemu serial's been broken for 9 months now, I doubt this
would make anything worse. (I should really check Cedric's qemu fork to
see if he fixed that...)
Rob
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [J-core] [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree
2017-11-17 17:39 ` [J-core] " Rob Landley
@ 2017-11-17 17:49 ` John Paul Adrian Glaubitz
2017-11-17 19:17 ` Rich Felker
0 siblings, 1 reply; 67+ messages in thread
From: John Paul Adrian Glaubitz @ 2017-11-17 17:49 UTC (permalink / raw)
To: Rob Landley; +Cc: Yoshinori Sato, linux-sh, linux-kernel, Rich Felker
I’ll have a go at this tonight and if the patches still apply fine, I’d just say go for it.
> On Nov 17, 2017, at 6:39 PM, Rob Landley <rob@landley.net> wrote:
>
>> On 11/17/2017 04:37 AM, John Paul Adrian Glaubitz wrote:
>> Hi there!
>>
>>> On 07/03/2016 06:46 PM, Yoshinori Sato wrote:
>>> 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.
>>
>> This patch series - which would make a huge improvement - is still not
>> applied. It would be very useful to be able to test the device tree
>> implementation with QEMU.
>>
>> Any of the SH maintainers can apply this?
>
> It's Rich's call, but given that it's _from_ one of the sh maintainers,
> sounds to me like it can just go in if it still applies? (If there's
> bugfixes needed they can go in -rc2 or so, after this merge window.)
>
> Given that qemu serial's been broken for 9 months now, I doubt this
> would make anything worse. (I should really check Cedric's qemu fork to
> see if he fixed that...)
>
> Rob
^ permalink raw reply [flat|nested] 67+ messages in thread
* Re: [J-core] [PATCH v5 00/22] sh: LANDISK and R2Dplus convert to device tree
2017-11-17 17:49 ` John Paul Adrian Glaubitz
@ 2017-11-17 19:17 ` Rich Felker
[not found] ` <7193aa1b-50e3-11d4-f93d-f567e2e06b8c@physik.fu-berlin.de>
0 siblings, 1 reply; 67+ messages in thread
From: Rich Felker @ 2017-11-17 19:17 UTC (permalink / raw)
To: John Paul Adrian Glaubitz
Cc: Rob Landley, Yoshinori Sato, linux-sh, linux-kernel
On Fri, Nov 17, 2017 at 06:49:39PM +0100, John Paul Adrian Glaubitz wrote:
> I’ll have a go at this tonight and if the patches still apply fine, I’d just say go for it.
There were significant problems that I don't think were ever
addressed, including incompatible changes in how boot command line was
handled and possibly ambiguity about what a physical address means
(zero based vs based in the zone SH3/4 excludes from MMU mapping) in
the contract for how the bootloader passes a DTB pointer in to the
kernel, or something similar.
This is a large part of why I want to get to the point where I can
build and boot a kernel on the LANDISK -- not being able to test any
of this is a blocker for moving everything to device tree.
Rich
> > On Nov 17, 2017, at 6:39 PM, Rob Landley <rob@landley.net> wrote:
> >
> >> On 11/17/2017 04:37 AM, John Paul Adrian Glaubitz wrote:
> >> Hi there!
> >>
> >>> On 07/03/2016 06:46 PM, Yoshinori Sato wrote:
> >>> 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.
> >>
> >> This patch series - which would make a huge improvement - is still not
> >> applied. It would be very useful to be able to test the device tree
> >> implementation with QEMU.
> >>
> >> Any of the SH maintainers can apply this?
> >
> > It's Rich's call, but given that it's _from_ one of the sh maintainers,
> > sounds to me like it can just go in if it still applies? (If there's
> > bugfixes needed they can go in -rc2 or so, after this merge window.)
> >
> > Given that qemu serial's been broken for 9 months now, I doubt this
> > would make anything worse. (I should really check Cedric's qemu fork to
> > see if he fixed that...)
> >
> > Rob
^ permalink raw reply [flat|nested] 67+ messages in thread