Message ID | 1309945678-18813-2-git-send-email-bs14@csr.com |
---|---|
State | New |
Headers | show |
On Wed, Jul 06, 2011 at 02:47:56AM -0700, Barry Song wrote: > +static int sirfsoc_timer_set_next_event(unsigned long delta, > + struct clock_event_device *ce) > +{ > + unsigned long now, next; > + > + writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); > + now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO); > + do { > + next = now + delta; > + writel_relaxed(next, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0); > + writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); > + now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO); > + } while ((next - now) > delta); > + > + return 0; > +} Please have a look at any of the callsites of clockevents_program_event() in kernel/time/. You'll notice that they loop in some fashion should your set_next_event() return -ETIME. As there is the possibility that if you can't program the event (because it has already passed) then it is likely that there is some work which needs to be done before the next event is set. So the repeat logic should stay in the common code and not be duplicated in each platform.
On Wednesday 06 July 2011, Barry Song wrote: > From: Binghua Duan <binghua.duan@csr.com> > > SiRFprimaII is the latest generation application processor from CSR’s > Multifunction SoC product family. Designed around an ARM cortex A9 core, > high-speed memory bus, advanced 3D accelerator and full-HD multi-format > video decoder, SiRFprimaII is able to meet the needs of complicated > applications for modern multifunction devices that require heavy concurrent > applications and fluid user experience. Integrated with GPS baseband, > analog and PMU, this new platform is designed to provide a cost effective > solution for Automotive and Consumer markets. > > This patch adds the basic support for this SoC and EVB board based on device > tree. It is following the ZYNQ of Grant Likely in some degree. > > Signed-off-by: Binghua Duan <Binghua.Duan@csr.com> > Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com> > Signed-off-by: Zhiwu Song <Zhiwu.Song@csr.com> > Signed-off-by: Yuping Luo <Yuping.Luo@csr.com> > Signed-off-by: Bin Shi <Bin.Shi@csr.com> > Signed-off-by: Huayi Li <Huayi.Li@csr.com> > Signed-off-by: Barry Song <Baohua.Song@csr.com> Reviewed-by: Arnd Bergmann <arnd@arndb.de> I think this is good for 3.1, but there are still a few things about the device tree file could be improved. > + axi { > + compatible = "simple-bus"; > + #address-cells = <1>; > + #size-cells = <1>; > + ranges = <0x40000000 0x40000000 0x80000000>; > + > + sirfsoc-iobus { > + compatible = "simple-bus"; > + #address-cells = <1>; > + #size-cells = <1>; > + ranges = <0x40000000 0x40000000 0x80000000>; > + > + l2-cache-controller@0x80040000 { > + compatible = "arm,pl310-cache"; > + reg = <0x80040000 0x1000>; > + interrupts = <59>; > + }; > + > + intc: interrupt-controller@0x80020000 { > + #interrupt-cells = <1>; > + interrupt-controller; > + compatible = "sirf,prima2-intc"; > + reg = <0x80020000 0x1000>; > + }; > + > + sys-iobg { > + compatible = "simple-bus"; > + #address-cells = <1>; > + #size-cells = <1>; > + ranges = <0x88000000 0x88000000 0x40000>; > + > + clock-controller@0x88000000 { > + compatible = "sirf,prima2-clkc"; > + reg = <0x88000000 0x1000>; > + interrupts = <3>; > + }; The axi bus and the sirfsoc-iobus seem to be identical in their scope, so it's probably enough to model one of them. I would normally recommend defining the ranges so that addresses are local to the respective bus, like axi { ranges = <0 0x40000000 0x80000000>; sys-iobg { ranges = <0 0x48000000 0x40000>; clock-controller@0x88000000 { compatible = "sirf,prima2-clkc"; reg = <0 0x1000>; } reset-controller@0x88010000 { compatible = "sirf,prima2-rstc"; reg = <0x10000 0x1000>; }; } } > + disp-iobg { > + compatible = "simple-bus"; > + #address-cells = <1>; > + #size-cells = <1>; > + ranges = <0x90010000 0x90010000 0x30000>; > + > + display@0x90010000 { > + compatible = "sirf,prima2-lcd"; > + reg = <0x90010000 0x20000>; > + interrupts = <30>; > + }; > + > + vpp@0x90020000 { > + compatible = "sirf,prima2-vpp"; > + reg = <0x90020000 0x10000>; > + interrupts = <31>; > + }; > + }; > + > + graphics-iobg { > + compatible = "simple-bus"; > + #address-cells = <1>; > + #size-cells = <1>; > + ranges = <0x98000000 0x98000000 0x8000000>; > + > + graphics@0x98000000 { > + compatible = "sirf,prima2-graphics"; > + reg = <0x98000000 0x8000000>; > + interrupts = <6>; > + }; > + }; Are the display and graphics units CSR developments? If the GPU is in fact licensed from someone else (powervr, arm, ...), you should probably list the actual name of the device. > + multimedia-iobg { > + compatible = "simple-bus"; > + #address-cells = <1>; > + #size-cells = <1>; > + ranges = <0xa0000000 0xa0000000 0x8000000>; > + > + multimedia@0xa0000000 { > + compatible = "sirf,prima2-multimedia"; > + reg = <0xa0000000 0x8000000>; > + interrupts = <5>; > + }; > + }; "multimedia" sounds like a too generic term. What does this do? > + uart0: uart@0xb0050000 { > + cell-index = <0>; > + compatible = "sirf,prima2-uart"; > + reg = <0xb0050000 0x10000>; > + interrupts = <17>; > + }; > + > + uart1: uart@0xb0060000 { > + cell-index = <1>; > + compatible = "sirf,prima2-uart"; > + reg = <0xb0060000 0x10000>; > + interrupts = <18>; > + }; > + > + uart2: uart@0xb0070000 { > + cell-index = <2>; > + compatible = "sirf,prima2-uart"; > + reg = <0xb0070000 0x10000>; > + interrupts = <19>; > + }; Are these proprietary uarts, or are they compatible to 8250 and the like? You might want to set a clock-frequency property as of_serial.c uses. > + rtc-iobg { > + compatible = "sirf,prima2-rtciobg", "simple-bus"; > + #address-cells = <1>; > + #size-cells = <1>; > + reg = <0x80030000 0x10000>; > + > + gpsrtc@0x1000 { > + compatible = "sirf,prima2-gpsrtc"; > + reg = <0x1000 0x1000>; > + interrupts = <55 56 57>; > + }; > + > + sysrtc@0x2000 { > + compatible = "sirf,prima2-sysrtc"; > + reg = <0x2000 0x1000>; > + interrupts = <52 53 54>; > + }; > + > + pwrc@0x3000 { > + compatible = "sirf,prima2-pwrc"; > + reg = <0x3000 0x1000>; > + interrupts = <32>; > + }; > + }; Are these rtc implementations related? From the register layout, I would guess that they are supposed to be used by the same driver, so it's probably a good idea to add a "compatible" property with a common name for all three. > + uus-iobg { > + compatible = "simple-bus"; > + #address-cells = <1>; > + #size-cells = <1>; > + ranges = <0xb8000000 0xb8000000 0x40000>; > + > + usb0: usb@0xb00E0000 { > + compatible = "sirf,prima2-usb"; > + reg = <0xb8000000 0x10000>; > + interrupts = <10>; > + }; > + > + usb1: usb@0xb00f0000 { > + compatible = "sirf,prima2-usb"; > + reg = <0xb8010000 0x10000>; > + interrupts = <11>; > + }; Is the usb implementation compatible to an existing one? Many SoCs use one of ehci, ohci or musb. If that's the case, you should look at the respective bindings. > + sata@0xb00f0000 { > + compatible = "sirf,prima2-sata"; > + reg = <0xb8020000 0x10000>; > + interrupts = <37>; > + }; Same thing here. Most sata controllers are compatible to some standard implementation. > + security@0xb00f0000 { > + compatible = "sirf,prima2-security"; > + reg = <0xb8030000 0x10000>; > + interrupts = <42>; > + }; > + }; > + }; > + }; > +}; Arnd
Hi Arnd, thanks. 2011/7/6 Arnd Bergmann <arnd@arndb.de>: > On Wednesday 06 July 2011, Barry Song wrote: >> From: Binghua Duan <binghua.duan@csr.com> >> >> SiRFprimaII is the latest generation application processor from CSR’s >> Multifunction SoC product family. Designed around an ARM cortex A9 core, >> high-speed memory bus, advanced 3D accelerator and full-HD multi-format >> video decoder, SiRFprimaII is able to meet the needs of complicated >> applications for modern multifunction devices that require heavy concurrent >> applications and fluid user experience. Integrated with GPS baseband, >> analog and PMU, this new platform is designed to provide a cost effective >> solution for Automotive and Consumer markets. >> >> This patch adds the basic support for this SoC and EVB board based on device >> tree. It is following the ZYNQ of Grant Likely in some degree. >> >> Signed-off-by: Binghua Duan <Binghua.Duan@csr.com> >> Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com> >> Signed-off-by: Zhiwu Song <Zhiwu.Song@csr.com> >> Signed-off-by: Yuping Luo <Yuping.Luo@csr.com> >> Signed-off-by: Bin Shi <Bin.Shi@csr.com> >> Signed-off-by: Huayi Li <Huayi.Li@csr.com> >> Signed-off-by: Barry Song <Baohua.Song@csr.com> > > Reviewed-by: Arnd Bergmann <arnd@arndb.de> > > I think this is good for 3.1, but there are still a few things about > the device tree file could be improved. > >> + axi { >> + compatible = "simple-bus"; >> + #address-cells = <1>; >> + #size-cells = <1>; >> + ranges = <0x40000000 0x40000000 0x80000000>; >> + >> + sirfsoc-iobus { >> + compatible = "simple-bus"; >> + #address-cells = <1>; >> + #size-cells = <1>; >> + ranges = <0x40000000 0x40000000 0x80000000>; >> + >> + l2-cache-controller@0x80040000 { >> + compatible = "arm,pl310-cache"; >> + reg = <0x80040000 0x1000>; >> + interrupts = <59>; >> + }; >> + >> + intc: interrupt-controller@0x80020000 { >> + #interrupt-cells = <1>; >> + interrupt-controller; >> + compatible = "sirf,prima2-intc"; >> + reg = <0x80020000 0x1000>; >> + }; >> + >> + sys-iobg { >> + compatible = "simple-bus"; >> + #address-cells = <1>; >> + #size-cells = <1>; >> + ranges = <0x88000000 0x88000000 0x40000>; >> + >> + clock-controller@0x88000000 { >> + compatible = "sirf,prima2-clkc"; >> + reg = <0x88000000 0x1000>; >> + interrupts = <3>; >> + }; > > > The axi bus and the sirfsoc-iobus seem to be identical in their scope, > so it's probably enough to model one of them. ok. > > I would normally recommend defining the ranges so that addresses are local > to the respective bus, like > > axi { > ranges = <0 0x40000000 0x80000000>; > > sys-iobg { > ranges = <0 0x48000000 0x40000>; > clock-controller@0x88000000 { > compatible = "sirf,prima2-clkc"; > reg = <0 0x1000>; > } > > reset-controller@0x88010000 { > compatible = "sirf,prima2-rstc"; > reg = <0x10000 0x1000>; > }; > } > } i am not sure whether it make us a little more difficult to know the real address at first glance.we will need to calculate. all addresses are 1:1 mapped in this chip. bus map can work even though we only give "ranges;" without real "ranges = <0x....>;". i also find i missed grant's comment about deleting "0x" after "@" in this patch. > > >> + disp-iobg { >> + compatible = "simple-bus"; >> + #address-cells = <1>; >> + #size-cells = <1>; >> + ranges = <0x90010000 0x90010000 0x30000>; >> + >> + display@0x90010000 { >> + compatible = "sirf,prima2-lcd"; >> + reg = <0x90010000 0x20000>; >> + interrupts = <30>; >> + }; >> + >> + vpp@0x90020000 { >> + compatible = "sirf,prima2-vpp"; >> + reg = <0x90020000 0x10000>; >> + interrupts = <31>; >> + }; >> + }; >> + >> + graphics-iobg { >> + compatible = "simple-bus"; >> + #address-cells = <1>; >> + #size-cells = <1>; >> + ranges = <0x98000000 0x98000000 0x8000000>; >> + >> + graphics@0x98000000 { >> + compatible = "sirf,prima2-graphics"; >> + reg = <0x98000000 0x8000000>; >> + interrupts = <6>; >> + }; >> + }; > > Are the display and graphics units CSR developments? If the GPU is > in fact licensed from someone else (powervr, arm, ...), you should > probably list the actual name of the device. GPU is powervr sgx 531, so could we define compatible as "powervr,sgx531"? > >> + multimedia-iobg { >> + compatible = "simple-bus"; >> + #address-cells = <1>; >> + #size-cells = <1>; >> + ranges = <0xa0000000 0xa0000000 0x8000000>; >> + >> + multimedia@0xa0000000 { >> + compatible = "sirf,prima2-multimedia"; >> + reg = <0xa0000000 0x8000000>; >> + interrupts = <5>; >> + }; >> + }; > > "multimedia" sounds like a too generic term. What does this do? video decoding. > >> + uart0: uart@0xb0050000 { >> + cell-index = <0>; >> + compatible = "sirf,prima2-uart"; >> + reg = <0xb0050000 0x10000>; >> + interrupts = <17>; >> + }; >> + >> + uart1: uart@0xb0060000 { >> + cell-index = <1>; >> + compatible = "sirf,prima2-uart"; >> + reg = <0xb0060000 0x10000>; >> + interrupts = <18>; >> + }; >> + >> + uart2: uart@0xb0070000 { >> + cell-index = <2>; >> + compatible = "sirf,prima2-uart"; >> + reg = <0xb0070000 0x10000>; >> + interrupts = <19>; >> + }; > > Are these proprietary uarts, or are they compatible to 8250 and the > like? You might want to set a clock-frequency property as of_serial.c > uses. it is not compatible with 8250 . > >> + rtc-iobg { >> + compatible = "sirf,prima2-rtciobg", "simple-bus"; >> + #address-cells = <1>; >> + #size-cells = <1>; >> + reg = <0x80030000 0x10000>; >> + >> + gpsrtc@0x1000 { >> + compatible = "sirf,prima2-gpsrtc"; >> + reg = <0x1000 0x1000>; >> + interrupts = <55 56 57>; >> + }; >> + >> + sysrtc@0x2000 { >> + compatible = "sirf,prima2-sysrtc"; >> + reg = <0x2000 0x1000>; >> + interrupts = <52 53 54>; >> + }; >> + >> + pwrc@0x3000 { >> + compatible = "sirf,prima2-pwrc"; >> + reg = <0x3000 0x1000>; >> + interrupts = <32>; >> + }; >> + }; > > Are these rtc implementations related? From the register layout, I would > guess that they are supposed to be used by the same driver, so it's > probably a good idea to add a "compatible" property with a common name > for all three. in fact, because they are slow, they can't be accessed by mapped address directly, the only common point they have is we need to access them through mapped address in rtc-iobg indirectly just like we access i2c/spi/nand devices. they are three different devices with different purpose and register layout in fact. > >> + uus-iobg { >> + compatible = "simple-bus"; >> + #address-cells = <1>; >> + #size-cells = <1>; >> + ranges = <0xb8000000 0xb8000000 0x40000>; >> + >> + usb0: usb@0xb00E0000 { >> + compatible = "sirf,prima2-usb"; >> + reg = <0xb8000000 0x10000>; >> + interrupts = <10>; >> + }; >> + >> + usb1: usb@0xb00f0000 { >> + compatible = "sirf,prima2-usb"; >> + reg = <0xb8010000 0x10000>; >> + interrupts = <11>; >> + }; > > Is the usb implementation compatible to an existing one? Many SoCs > use one of ehci, ohci or musb. If that's the case, you should look > at the respective bindings. > >> + sata@0xb00f0000 { >> + compatible = "sirf,prima2-sata"; >> + reg = <0xb8020000 0x10000>; >> + interrupts = <37>; >> + }; > > Same thing here. Most sata controllers are compatible to some > standard implementation. ok. i see :-). let me have some check with ic guys and send v4 with these fixes. > >> + security@0xb00f0000 { >> + compatible = "sirf,prima2-security"; >> + reg = <0xb8030000 0x10000>; >> + interrupts = <42>; >> + }; >> + }; >> + }; >> + }; >> +}; > > Arnd > _______________________________________________ > devicetree-discuss mailing list > devicetree-discuss@lists.ozlabs.org > https://lists.ozlabs.org/listinfo/devicetree-discuss > Thanks barry
On Wed, Jul 06, 2011 at 02:47:56AM -0700, Barry Song wrote: > diff --git a/arch/arm/mach-prima2/include/mach/io.h b/arch/arm/mach-prima2/include/mach/io.h > new file mode 100644 > index 0000000..fc54f16 > --- /dev/null > +++ b/arch/arm/mach-prima2/include/mach/io.h > @@ -0,0 +1,21 @@ > +/* > + * arch/arm/mach-prima2/include/mach/io.h > + * > + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. > + * > + * Licensed under GPLv2 or later. > + */ > + > +#ifndef __MACH_PRIMA2_IO_H > +#define __MACH_PRIMA2_IO_H > + > +#define IO_SPACE_LIMIT 0xffffffff Can folk please start putting comments in their io.h file explaining their choice for this definition? Looking through the existing files, it is almost impossible to infer the reason the value was picked, which makes future maintanence a headache. IO_SPACE_LIMIT sets the upper bound for the PCI/ISA style IO accessor macros (inb, et.al.) My guidance is: 1. If you have no support for ISA/PCI/PC card drivers, then set this to zero to prevent ISA/PCI drivers reserving IO port space. You should be able to leave __io() set to __typesafe_io() without risking any ISA driver stamping on memory as those drivers should no longer successfully initialize with this set to zero. 2. If you have MMIO-mapped IO space (eg, a PCI bridge which forwards MMIO accesses in a window to PCI IO space) or equivalent, then set this to the size of the window, or 64K-1. Explain this. 3. If you have MMIO-mapped IO space which is scattered (eg, multiple PC cards with their IO space individually mapped as separate 64K blocks) then explain this and set it to 0xffffffff for the time being. In any case, having the chosen value documented, and if it is for specific devices on the board, documenting that too, would really help. I shall be making this change to asm/io.h shortly: #include <mach/io.h> +/* + * This is the limit of PCI/ISA/PC card IO space, which is by default + * 64K if we have PC card, PCI or ISA support. Otherwise, default to + * zero to prevent ISA/PCI drivers claiming IO space (and potentially + * oopsing.) + * + * Only set this larger if you really need inb() et.al. to operate over + * a larger address space (eg, for multiple MMIO-mapped PC card sockets + * as found on SA11x0 and PXA.) + */ +#ifndef IO_SPACE_LIMIT +#if defined(CONFIG_PCI) || defined(CONFIG_ISA) || defined(CONFIG_PCCARD) +#define IO_SPACE_LIMIT ((resource_size_t)0xffff) +#else +#define IO_SPACE_LIMIT ((resource_size_t)0) +#endif +#endif Thanks.
On Wednesday 06 July 2011, Russell King - ARM Linux wrote: > On Wed, Jul 06, 2011 at 02:47:56AM -0700, Barry Song wrote: > > diff --git a/arch/arm/mach-prima2/include/mach/io.h b/arch/arm/mach- > > + > > +#ifndef __MACH_PRIMA2_IO_H > > +#define __MACH_PRIMA2_IO_H > > + > > +#define IO_SPACE_LIMIT 0xffffffff > > Can folk please start putting comments in their io.h file explaining their > choice for this definition? Looking through the existing files, it is > almost impossible to infer the reason the value was picked, which makes > future maintanence a headache. I had the same comment for one of the earlier versions of the patch set, but we agreed that I'd come up with a way to remove this at a later stage for all platforms that don't have PC-style PIO. Right now, the only platforms that use a value other than 0xffffffff are ones that actually have PCI and set it to 0xffff. > IO_SPACE_LIMIT sets the upper bound for the PCI/ISA style IO accessor > macros (inb, et.al.) > > My guidance is: > > 1. If you have no support for ISA/PCI/PC card drivers, then set this to > zero to prevent ISA/PCI drivers reserving IO port space. You should > be able to leave __io() set to __typesafe_io() without risking any > ISA driver stamping on memory as those drivers should no longer > successfully initialize with this set to zero. > > 2. If you have MMIO-mapped IO space (eg, a PCI bridge which forwards > MMIO accesses in a window to PCI IO space) or equivalent, then set > this to the size of the window, or 64K-1. Explain this. > > 3. If you have MMIO-mapped IO space which is scattered (eg, multiple > PC cards with their IO space individually mapped as separate 64K > blocks) then explain this and set it to 0xffffffff for the time > being. Sounds good. > I shall be making this change to asm/io.h shortly: > > #include <mach/io.h> > > +/* > + * This is the limit of PCI/ISA/PC card IO space, which is by default > + * 64K if we have PC card, PCI or ISA support. Otherwise, default to > + * zero to prevent ISA/PCI drivers claiming IO space (and potentially > + * oopsing.) > + * > + * Only set this larger if you really need inb() et.al. to operate over > + * a larger address space (eg, for multiple MMIO-mapped PC card sockets > + * as found on SA11x0 and PXA.) > + */ > +#ifndef IO_SPACE_LIMIT > +#if defined(CONFIG_PCI) || defined(CONFIG_ISA) || defined(CONFIG_PCCARD) > +#define IO_SPACE_LIMIT ((resource_size_t)0xffff) > +#else > +#define IO_SPACE_LIMIT ((resource_size_t)0) > +#endif > +#endif Good idea. The related change that I want to do is to conditionalize all drivers that require PC-style I/O on the respective bus they use, so we can also remove the __io macro for platforms that don't need it and catch all drivers using inb/outb at compile time. To do that, I'm working on a patch set that splits the 8250 driver into separate parts for platform drivers (mostly MMIO) and ISA drivers (mostly PIO), since that seems to be the only driver that we need on non-PIO platforms that uses inb/outb directly. Arnd
On Wed, Jul 06, 2011 at 02:42:04PM +0200, Arnd Bergmann wrote: > Good idea. The related change that I want to do is to conditionalize > all drivers that require PC-style I/O on the respective bus they > use, so we can also remove the __io macro for platforms that don't > need it and catch all drivers using inb/outb at compile time. And what about those which use ioport_map() and ioread/write ? The approach of setting IO_SPACE_LIMIT to zero makes those harmless even if inb/outb are provided. > To do that, I'm working on a patch set that splits the 8250 > driver into separate parts for platform drivers (mostly MMIO) > and ISA drivers (mostly PIO), since that seems to be the only > driver that we need on non-PIO platforms that uses inb/outb > directly. I don't really see the point of that given the ioread/iowrite et.al. semantics. And note that ioread/iowrite are unsupportable on some ARM platforms with ISA because of weird addressing techniques (and that renders PATA unsupportable on those platforms, while the old IDE stuff can continue to work with CF cards.)
On Wed, Jul 06, 2011 at 02:42:04PM +0200, Arnd Bergmann wrote: > I had the same comment for one of the earlier versions of the patch > set, but we agreed that I'd come up with a way to remove this at a > later stage for all platforms that don't have PC-style PIO. > > Right now, the only platforms that use a value other than 0xffffffff > are ones that actually have PCI and set it to 0xffff. As I point out, you can't use that as a reason to work out why the macro is being set. Various platforms have it set to 0xffffffff, and use the PCI/ISA IO accessor with virtual memory addresses provided by (eg) the PCMCIA subsystem - SA11x0 and PXA come to mind on that. The problem there is that we can't just change the thing because there is that constant thorn known as cs89x0.c, which also uses these macros, and that driver has never been properly updated (it contains _lots_ of platform specific hacks in it.) Changing the base address for the PCI/ISA IO accessor on those platforms is likely to completely break at least this driver. Plus there are is at least one platform which sets it to 0xffff yet doesn't appear to have PCI selected (VT8500). So I don't think we can even use the 64K-1 value to infer anything about the platform. This is why we need the reasoning behind the value for this macro documented.
On Wednesday 06 July 2011, Barry Song wrote: > > I would normally recommend defining the ranges so that addresses are local > > to the respective bus, like > > > > axi { > > ranges = <0 0x40000000 0x80000000>; > > > > sys-iobg { > > ranges = <0 0x48000000 0x40000>; > > clock-controller@0x88000000 { > > compatible = "sirf,prima2-clkc"; > > reg = <0 0x1000>; > > } > > > > reset-controller@0x88010000 { > > compatible = "sirf,prima2-rstc"; > > reg = <0x10000 0x1000>; > > }; > > } > > } > > i am not sure whether it make us a little more difficult to know the > real address at first glance.we will need to calculate. > all addresses are 1:1 mapped in this chip. bus map can work even > though we only give "ranges;" without real "ranges = <0x....>;". So each iobg still passes down the entire 32-bit address? Note that you never have to do the calculation in the driver source, of_iomap and the resource logic both take care of this. There are multiple ways to handle this, and an empty ranges property usually works fine, but I find that less readable. Another way to handle these is to have a separate range for each child bus, as in arch/powerpc/boot/dts/gef_ppc9a.dts To stay in the example, this would mean doing something like axi { #address-cells = <2>; #size-cells = <1>; ranges = <0 0 0x80000000 0x08000000 // axi devices 1 0 0x88000000 0x08000000 // sys-iobg 2 0 0x90000000 0x00010000 // mem-iobg 3 0 0x90010000 0x07fe0000 // disp-iobg ... >; l2-cache-controller@80040000 { compatible = "arm,pl310-cache"; reg = <0 0x40000 0x1000>; interrupts = <59>; }; sys-iobg { #address-cells = <1>; #size-cells = <1>; ranges = <1 0 0 0x40000>; clock-controller@88000000 { compatible = "sirf,prima2-clkc"; reg = <0 0x1000>; } reset-controller@88010000 { compatible = "sirf,prima2-rstc"; reg = <0x10000 0x1000>; }; } } > >> + > >> + graphics-iobg { > >> + compatible = "simple-bus"; > >> + #address-cells = <1>; > >> + #size-cells = <1>; > >> + ranges = <0x98000000 0x98000000 0x8000000>; > >> + > >> + graphics@0x98000000 { > >> + compatible = "sirf,prima2-graphics"; > >> + reg = <0x98000000 0x8000000>; > >> + interrupts = <6>; > >> + }; > >> + }; > > > > Are the display and graphics units CSR developments? If the GPU is > > in fact licensed from someone else (powervr, arm, ...), you should > > probably list the actual name of the device. > > GPU is powervr sgx 531, so could we define compatible as "powervr,sgx531"? Probably yes. You should have a look if there are already bindings for this that define other attributes. Also, if there is any customization inside of the chip, you should have another more specific identifier that makes it possible that this is the version that csr has modified. > >> + multimedia-iobg { > >> + compatible = "simple-bus"; > >> + #address-cells = <1>; > >> + #size-cells = <1>; > >> + ranges = <0xa0000000 0xa0000000 0x8000000>; > >> + > >> + multimedia@0xa0000000 { > >> + compatible = "sirf,prima2-multimedia"; > >> + reg = <0xa0000000 0x8000000>; > >> + interrupts = <5>; > >> + }; > >> + }; > > > > "multimedia" sounds like a too generic term. What does this do? > > video decoding. sirf,prima2-video-codec is probably better than, but if anyone has other suggestions, you could use something else. > > Are these proprietary uarts, or are they compatible to 8250 and the > > like? You might want to set a clock-frequency property as of_serial.c > > uses. > > it is not compatible with 8250 . ok > > Are these rtc implementations related? From the register layout, I would > > guess that they are supposed to be used by the same driver, so it's > > probably a good idea to add a "compatible" property with a common name > > for all three. > > in fact, because they are slow, they can't be accessed by mapped > address directly, the only common point they have is we need to access > them through mapped address in rtc-iobg indirectly just like we access > i2c/spi/nand devices. > > they are three different devices with different purpose and register > layout in fact. Ok. Arnd
On Wednesday 06 July 2011, Russell King - ARM Linux wrote: > On Wed, Jul 06, 2011 at 02:42:04PM +0200, Arnd Bergmann wrote: > > Good idea. The related change that I want to do is to conditionalize > > all drivers that require PC-style I/O on the respective bus they > > use, so we can also remove the __io macro for platforms that don't > > need it and catch all drivers using inb/outb at compile time. > > And what about those which use ioport_map() and ioread/write ? ioport_map should return an error if IO_SPACE_LIMIT is zero. I also tried just forcing a link error by not providing any ioport_map in that case, which didn't cause major problems in my tests. If that works for the general case, I'd prefer that option. If we have no drivers using ioport_map, ioread/iowrite automatically becomes a non-issue. > The approach of setting IO_SPACE_LIMIT to zero makes those harmless > even if inb/outb are provided. I'm not arguing against setting IO_SPACE_LIMIT to zero, I just want to do more on top of that. There are numerous drivers that we are able to enable on non-PIO machines that clearly cannot work because they depend on a bus that's not there. This includes stuff like gameport, pcmcia, or various rtc. > > To do that, I'm working on a patch set that splits the 8250 > > driver into separate parts for platform drivers (mostly MMIO) > > and ISA drivers (mostly PIO), since that seems to be the only > > driver that we need on non-PIO platforms that uses inb/outb > > directly. > > I don't really see the point of that given the ioread/iowrite et.al. > semantics. > > And note that ioread/iowrite are unsupportable on some ARM platforms > with ISA because of weird addressing techniques (and that renders > PATA unsupportable on those platforms, while the old IDE stuff can > continue to work with CF cards.) Different issue, but I'm sure that they are supportable. What we ended up doing on the PCIe bus in one of the Cell blades was to encode special regions in the __iomem token returned from pci_iomap that would trigger indirect access in iowrite32. For the simple case where all buses use the same weird addressing, the regular CONFIG_GENERIC_IOMAP support should be enough already. Arnd
On Wed, Jul 06, 2011 at 02:42:04PM +0200, Arnd Bergmann wrote: > Right now, the only platforms that use a value other than 0xffffffff > are ones that actually have PCI and set it to 0xffff. Note that those platforms using soc_common need to have their inb() et.al. defined to be compatible with readb() et.al. as soc_common ioremaps the IO resource and passes that into the PCMCIA layer as the per-socket IO offset. The alternative is to rip that out, and use fixed mappings and fixed per-SoC IO offsets. So, I think as part of this idea, we should - for the time being - default IO_SPACE_LIMIT to 0xffffffff if PCMCIA_SOC_COMMON is enabled in any way. The plus side is that we get that condition documented, and so can do something about it later.
On Wednesday 06 July 2011, Russell King - ARM Linux wrote: > On Wed, Jul 06, 2011 at 02:42:04PM +0200, Arnd Bergmann wrote: > > Right now, the only platforms that use a value other than 0xffffffff > > are ones that actually have PCI and set it to 0xffff. > > Note that those platforms using soc_common need to have their inb() et.al. > defined to be compatible with readb() et.al. as soc_common ioremaps the > IO resource and passes that into the PCMCIA layer as the per-socket IO > offset. > > The alternative is to rip that out, and use fixed mappings and fixed > per-SoC IO offsets. > > So, I think as part of this idea, we should - for the time being - > default IO_SPACE_LIMIT to 0xffffffff if PCMCIA_SOC_COMMON is enabled in > any way. The plus side is that we get that condition documented, and > so can do something about it later. Ok, sounds good. Arnd
2011/7/6 Russell King - ARM Linux <linux@arm.linux.org.uk>: > On Wed, Jul 06, 2011 at 02:47:56AM -0700, Barry Song wrote: >> +static int sirfsoc_timer_set_next_event(unsigned long delta, >> + struct clock_event_device *ce) >> +{ >> + unsigned long now, next; >> + >> + writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); >> + now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO); >> + do { >> + next = now + delta; >> + writel_relaxed(next, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0); >> + writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); >> + now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO); >> + } while ((next - now) > delta); >> + >> + return 0; >> +} > > Please have a look at any of the callsites of clockevents_program_event() > in kernel/time/. You'll notice that they loop in some fashion should your > set_next_event() return -ETIME. ok. looks like the function can be fixed to: static int sirfsoc_timer_set_next_event(unsigned long delta, struct clock_event_device *ce) { unsigned long now, next; writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO); next = now + delta; writel_relaxed(next, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0); writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO); return next - now > delta ? -ETIME : 0; } > > As there is the possibility that if you can't program the event (because > it has already passed) then it is likely that there is some work which > needs to be done before the next event is set. So the repeat logic should > stay in the common code and not be duplicated in each platform. > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel >
On Wed, Jul 06, 2011 at 04:41:05PM +0200, Arnd Bergmann wrote: > On Wednesday 06 July 2011, Russell King - ARM Linux wrote: > > And note that ioread/iowrite are unsupportable on some ARM platforms > > with ISA because of weird addressing techniques (and that renders > > PATA unsupportable on those platforms, while the old IDE stuff can > > continue to work with CF cards.) > > Different issue, but I'm sure that they are supportable. Ha, you've no idea what kind of messed up ideas hardware people come up with then. Take this - this is real hardware which I've had Linux running on continuously for the last 13 years. Here is the /proc/ioports: 0000-000f : pcmcia_socket0 0000-000f : pcmcia0.0 0000-0007 : ide-cs 000e-000e : ide-cs 0220-0238 : am79c961 0220-0237 : eth0 0278-027f : reserved 02f8-02ff : serial 0300-030f : pcmcia_socket1 0300-030f : pcmcia1.0 0378-037a : parport0 03bc-03be : reserved 03e0-03e1 : i82365 03f8-03ff : serial ISA devices have either 8 data lines or 16 data lines. 1) If the device has 8 data lines, then it is accessible on physical addresses ISA_BASE + (ioport << 2). 2) If the device has 16 data lines, then: a) for an ISA device which transfers 8-bit accesses on the low byte lane, registers are accessible at ISA_BASE + ((ioport & ~1) << 1). For even ioports, use a byte access. For odd ioports, use a word access. b) for an ISA Device which transfers even 8-bit accesses on the low byte lane and odd 8-bit accesses on the high byte lane, registers are accessible at ISA_BASE + ((ioport & ~1) << 1) + (ioport & 1). (PCs sort this out via the IOCS16 signal, which is not connected in this example.) c) for 16-bit accesses, these are always naturally aligned, so these registers are accessible at ISA_BASE + ((ioport & ~1) << 1). So, let's look at some examples. Serial ports (standard 16550A) at ISA bus address 0x2f8 and 0x3f8. So, the translation from ISA address to bus offset is: 0x2f8 => 0xbe0 0x3f8 => 0xfe0 0x2f9 => 0xbe4 0x3f9 => 0xfe4 0x2fa => 0xbe8 0x3fa => 0xfe8 etc. The PCMCIA controller is a standard i82365 at the standard ISA address of 0x3e0. This has the following translation: 0x3e0 => 0x7c0(b) 0x3e1 => 0x7c0(w) An inserted PCMCIA card may require: 0x100 => 0x200(b) 0x101 => 0x200(w) or 0x201(b) 0x102 => 0x204(b) 0x103 => 0x204(w) or 0x205(b) So, if you do an ioport_map() to convert from the ISA address to a bus specific address, and _then_ add the device specific offset, you end up with information lost, and you no longer know how to manipulate the cookie into the correct bus address and access type. The alternative is you keep the returned ioport cookie the same as the ISA address, and do all the conversion in ioread/iowrite - that's even more horrible than how it's already doing because then you need to know if its real MMIO or IO, and whether it's an 8 bit IO device, 16-bit low byte lane IO device, or a 16-bit both byte lane IO device. Plus whether the MMIO is in the broken PCMCIA controller IO space (CPU address bit 11 missing and CPU address bit 19 mapped to two bus address bits...)
2011/7/6 Russell King - ARM Linux <linux@arm.linux.org.uk>: > On Wed, Jul 06, 2011 at 02:47:56AM -0700, Barry Song wrote: >> diff --git a/arch/arm/mach-prima2/include/mach/io.h b/arch/arm/mach-prima2/include/mach/io.h >> new file mode 100644 >> index 0000000..fc54f16 >> --- /dev/null >> +++ b/arch/arm/mach-prima2/include/mach/io.h >> @@ -0,0 +1,21 @@ >> +/* >> + * arch/arm/mach-prima2/include/mach/io.h >> + * >> + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. >> + * >> + * Licensed under GPLv2 or later. >> + */ >> + >> +#ifndef __MACH_PRIMA2_IO_H >> +#define __MACH_PRIMA2_IO_H >> + >> +#define IO_SPACE_LIMIT 0xffffffff > > Can folk please start putting comments in their io.h file explaining their > choice for this definition? Looking through the existing files, it is > almost impossible to infer the reason the value was picked, which makes > future maintanence a headache. > > IO_SPACE_LIMIT sets the upper bound for the PCI/ISA style IO accessor > macros (inb, et.al.) > > My guidance is: > > 1. If you have no support for ISA/PCI/PC card drivers, then set this to > zero to prevent ISA/PCI drivers reserving IO port space. You should > be able to leave __io() set to __typesafe_io() without risking any > ISA driver stamping on memory as those drivers should no longer > successfully initialize with this set to zero. > > 2. If you have MMIO-mapped IO space (eg, a PCI bridge which forwards > MMIO accesses in a window to PCI IO space) or equivalent, then set > this to the size of the window, or 64K-1. Explain this. > > 3. If you have MMIO-mapped IO space which is scattered (eg, multiple > PC cards with their IO space individually mapped as separate 64K > blocks) then explain this and set it to 0xffffffff for the time > being. > > In any case, having the chosen value documented, and if it is for > specific devices on the board, documenting that too, would really > help. > > I shall be making this change to asm/io.h shortly: > > #include <mach/io.h> > > +/* > + * This is the limit of PCI/ISA/PC card IO space, which is by default > + * 64K if we have PC card, PCI or ISA support. Otherwise, default to > + * zero to prevent ISA/PCI drivers claiming IO space (and potentially > + * oopsing.) > + * > + * Only set this larger if you really need inb() et.al. to operate over > + * a larger address space (eg, for multiple MMIO-mapped PC card sockets > + * as found on SA11x0 and PXA.) > + */ > +#ifndef IO_SPACE_LIMIT > +#if defined(CONFIG_PCI) || defined(CONFIG_ISA) || defined(CONFIG_PCCARD) > +#define IO_SPACE_LIMIT ((resource_size_t)0xffff) > +#else > +#define IO_SPACE_LIMIT ((resource_size_t)0) > +#endif > +#endif if you define that in asm/io.h as you said: #ifndef IO_SPACE_LIMIT #if defined(PCMCIA_SOC_COMMON) #define IO_SPACE_LIMIT ((resource_size_t)0xffffffff) #else #if defined(CONFIG_PCI) || defined(CONFIG_ISA) || defined(CONFIG_PCCARD) #define IO_SPACE_LIMIT ((resource_size_t)0xffff) #else #define IO_SPACE_LIMIT ((resource_size_t)0) #endif #endif #endif i'd like to delete IO_SPACE_LIMIT in my io.h. otherwise, i'd like to try "#define IO_SPACE_LIMIT ((resource_size_t)0)" in my io.h since i have no real CONFIG_PCI/ISA/PCCARD/PCMCIA_SOC_COMMON. > > Thanks. > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel >
On Wednesday 06 July 2011, Russell King - ARM Linux wrote: > Ha, you've no idea what kind of messed up ideas hardware people come up > with then. Take this - this is real hardware which I've had Linux > running on continuously for the last 13 years. Here is the /proc/ioports: > < skipped lots of interesting information about how messed up the hardware can be> > So, if you do an ioport_map() to convert from the ISA address to a bus > specific address, and then add the device specific offset, you end up > with information lost, and you no longer know how to manipulate the > cookie into the correct bus address and access type. > > The alternative is you keep the returned ioport cookie the same as the > ISA address, and do all the conversion in ioread/iowrite - that's even > more horrible than how it's already doing because then you need to know > if its real MMIO or IO, and whether it's an 8 bit IO device, 16-bit > low byte lane IO device, or a 16-bit both byte lane IO device. Plus > whether the MMIO is in the broken PCMCIA controller IO space (CPU > address bit 11 missing and CPU address bit 19 mapped to two bus > address bits...) Well, first of all, I never suggested converting drivers to use iowrite, you brought that up. So as long as the 16-bit ISA driver keep using inb/outb, an iowrite implementation would not need to bother about this specific problem and don't even need a private iowrite implementation but instead move that platform over to use CONFIG_GENERIC_IOMAP. What lib/iomap.c does is indeed to look at the address, by default it assumes that __iomem tokens below 0x10000 are IO ports, while larger values are MMIO addresses. This appears to work fine on x86, and AFAICT, it should still work with both the botched PIO mapping (minus the 16-bit devices) and the botched MMIO mapping, since both will just end up calling the fixups in arch/arm/mach-ebsa110/io.c. The only problem you will hit is when there are ISA devices with MMIO addresses below 0x40000, which is impossible on PCs but perhaps not on arbitrarily incompatible ISA buses. Arnd
On Wed, 6 Jul 2011, Arnd Bergmann wrote: > On Wednesday 06 July 2011, Russell King - ARM Linux wrote: > > I shall be making this change to asm/io.h shortly: > > > > #include <mach/io.h> > > > > +/* > > + * This is the limit of PCI/ISA/PC card IO space, which is by default > > + * 64K if we have PC card, PCI or ISA support. Otherwise, default to > > + * zero to prevent ISA/PCI drivers claiming IO space (and potentially > > + * oopsing.) > > + * > > + * Only set this larger if you really need inb() et.al. to operate over > > + * a larger address space (eg, for multiple MMIO-mapped PC card sockets > > + * as found on SA11x0 and PXA.) > > + */ > > +#ifndef IO_SPACE_LIMIT > > +#if defined(CONFIG_PCI) || defined(CONFIG_ISA) || defined(CONFIG_PCCARD) > > +#define IO_SPACE_LIMIT ((resource_size_t)0xffff) > > +#else > > +#define IO_SPACE_LIMIT ((resource_size_t)0) > > +#endif > > +#endif > > Good idea. The related change that I want to do is to conditionalize > all drivers that require PC-style I/O on the respective bus they > use, so we can also remove the __io macro for platforms that don't > need it and catch all drivers using inb/outb at compile time. In the spirit of removing as much machine specific and globally used defines (see my patch series removing a bunch of mach/memory.h instances), I'd like to see a solution that would make IO_SPACE_LIMIT into a variable, or having the same definition with a fixed mapping, for as many SOCs as possible. Nicolas
On Wed, Jul 06, 2011 at 12:35:54PM -0400, Nicolas Pitre wrote: > In the spirit of removing as much machine specific and globally used > defines (see my patch series removing a bunch of mach/memory.h > instances), I'd like to see a solution that would make IO_SPACE_LIMIT > into a variable, or having the same definition with a fixed mapping, for > as many SOCs as possible. In theory it should be possible to have it defined as 64K across everything. ISTR that you were against that with SA1100 platforms because of the PCMCIA problem though...
On Wednesday 06 July 2011 19:42:48 Russell King - ARM Linux wrote: > On Wed, Jul 06, 2011 at 12:35:54PM -0400, Nicolas Pitre wrote: > > In the spirit of removing as much machine specific and globally used > > defines (see my patch series removing a bunch of mach/memory.h > > instances), I'd like to see a solution that would make IO_SPACE_LIMIT > > into a variable, or having the same definition with a fixed mapping, for > > as many SOCs as possible. > > In theory it should be possible to have it defined as 64K across > everything. ISTR that you were against that with SA1100 platforms > because of the PCMCIA problem though... If the problem is only with a few platforms, my preference would be to hardcode this to 64k or 0, and leave the platforms that require something else out of the common zImage for now. For all platforms that only need the 64k window and don't have any of other special needs, I would also like to hardcode the virtual address window eventually, so that inb/outb can still be a single instruction. Arnd
On Wed, 6 Jul 2011, Russell King - ARM Linux wrote: > On Wed, Jul 06, 2011 at 12:35:54PM -0400, Nicolas Pitre wrote: > > In the spirit of removing as much machine specific and globally used > > defines (see my patch series removing a bunch of mach/memory.h > > instances), I'd like to see a solution that would make IO_SPACE_LIMIT > > into a variable, or having the same definition with a fixed mapping, for > > as many SOCs as possible. > > In theory it should be possible to have it defined as 64K across > everything. ISTR that you were against that with SA1100 platforms > because of the PCMCIA problem though... To be honest, if I was against it, the reasons have long been swapped out of my brain. And since those machines with pretenses of ISA-type buses are fading away in terms of actual users, I don't really mind if they are not consolidated. As long as those machines with PCI or none of it can rely on shared definitions that should be good enough. Nicolas
On Wed, 6 Jul 2011, Arnd Bergmann wrote: > On Wednesday 06 July 2011 19:42:48 Russell King - ARM Linux wrote: > > On Wed, Jul 06, 2011 at 12:35:54PM -0400, Nicolas Pitre wrote: > > > In the spirit of removing as much machine specific and globally used > > > defines (see my patch series removing a bunch of mach/memory.h > > > instances), I'd like to see a solution that would make IO_SPACE_LIMIT > > > into a variable, or having the same definition with a fixed mapping, for > > > as many SOCs as possible. > > > > In theory it should be possible to have it defined as 64K across > > everything. ISTR that you were against that with SA1100 platforms > > because of the PCMCIA problem though... > > If the problem is only with a few platforms, my preference would be > to hardcode this to 64k or 0, and leave the platforms that require > something else out of the common zImage for now. > > For all platforms that only need the 64k window and don't have any > of other special needs, I would also like to hardcode the virtual > address window eventually, so that inb/outb can still be a single > instruction. I would say that hardcoding the virtual mapping is probably the first thing to do. That would certainly simplify the rest of the kernel. Nicolas
On Wed, Jul 06, 2011 at 02:11:29PM -0400, Nicolas Pitre wrote: > On Wed, 6 Jul 2011, Arnd Bergmann wrote: > > If the problem is only with a few platforms, my preference would be > > to hardcode this to 64k or 0, and leave the platforms that require > > something else out of the common zImage for now. > > > > For all platforms that only need the 64k window and don't have any > > of other special needs, I would also like to hardcode the virtual > > address window eventually, so that inb/outb can still be a single > > instruction. > > I would say that hardcoding the virtual mapping is probably the first > thing to do. That would certainly simplify the rest of the kernel. We _used_ to hard-code that mapping, but it became painful to supply that information into soc_common, which isn't supposed to be ARM specific. So going back to hard-coded mappings is a backwards step - essentially reintroducing one problem which was already solved to resolve a different problem. That isn't progress, that's merely changing one resolution for another.
On Wed, 6 Jul 2011, Russell King - ARM Linux wrote: > On Wed, Jul 06, 2011 at 02:11:29PM -0400, Nicolas Pitre wrote: > > On Wed, 6 Jul 2011, Arnd Bergmann wrote: > > > If the problem is only with a few platforms, my preference would be > > > to hardcode this to 64k or 0, and leave the platforms that require > > > something else out of the common zImage for now. > > > > > > For all platforms that only need the 64k window and don't have any > > > of other special needs, I would also like to hardcode the virtual > > > address window eventually, so that inb/outb can still be a single > > > instruction. > > > > I would say that hardcoding the virtual mapping is probably the first > > thing to do. That would certainly simplify the rest of the kernel. > > We _used_ to hard-code that mapping, but it became painful to supply > that information into soc_common, which isn't supposed to be ARM > specific. > > So going back to hard-coded mappings is a backwards step - essentially > reintroducing one problem which was already solved to resolve a different > problem. > > That isn't progress, that's merely changing one resolution for another. Let's simply let the problematic cases RIP then. Maybe those PCMCIA equipped ARM board will get out of commission eventually. Nicolas
On Thu, Jul 07, 2011 at 12:09:24AM +0800, Barry Song wrote: > if you define that in asm/io.h as you said: > > #ifndef IO_SPACE_LIMIT > #if defined(PCMCIA_SOC_COMMON) > #define IO_SPACE_LIMIT ((resource_size_t)0xffffffff) > #else > #if defined(CONFIG_PCI) || defined(CONFIG_ISA) || defined(CONFIG_PCCARD) > #define IO_SPACE_LIMIT ((resource_size_t)0xffff) > #else > #define IO_SPACE_LIMIT ((resource_size_t)0) > #endif > #endif > #endif > > i'd like to delete IO_SPACE_LIMIT in my io.h. > > otherwise, i'd like to try "#define IO_SPACE_LIMIT > ((resource_size_t)0)" in my io.h since i have no real > CONFIG_PCI/ISA/PCCARD/PCMCIA_SOC_COMMON. Thanks - stopping the 0xffffffff madness in new platforms is great. If you also omit the definition for __io() and set NO_IOPORT in your Kconfig, you should also end up with inb() et.al. undefined by asm/io.h, which should cause build-time failures if an ISA/PCI/PCMCIA driver attempts to build.
On Wednesday 06 July 2011 21:10:00 Russell King - ARM Linux wrote: > On Thu, Jul 07, 2011 at 12:09:24AM +0800, Barry Song wrote: > > if you define that in asm/io.h as you said: > > > > #ifndef IO_SPACE_LIMIT > > #if defined(PCMCIA_SOC_COMMON) > > #define IO_SPACE_LIMIT ((resource_size_t)0xffffffff) > > #else > > #if defined(CONFIG_PCI) || defined(CONFIG_ISA) || defined(CONFIG_PCCARD) > > #define IO_SPACE_LIMIT ((resource_size_t)0xffff) > > #else > > #define IO_SPACE_LIMIT ((resource_size_t)0) > > #endif > > #endif > > #endif > > > > i'd like to delete IO_SPACE_LIMIT in my io.h. > > > > otherwise, i'd like to try "#define IO_SPACE_LIMIT > > ((resource_size_t)0)" in my io.h since i have no real > > CONFIG_PCI/ISA/PCCARD/PCMCIA_SOC_COMMON. > > Thanks - stopping the 0xffffffff madness in new platforms is great. FWIW, I've double-checked the Xilinx zynq platform that I've already queued up for 3.1: this one defines IO_SPACE_LIMIT to 0xffff because PCI support will get merged later, so that's fine. > If you also omit the definition for __io() and set NO_IOPORT in your > Kconfig, you should also end up with inb() et.al. undefined by asm/io.h, > which should cause build-time failures if an ISA/PCI/PCMCIA driver > attempts to build. Just as a follow-up, this is what I was referring to in the other sub-thread. Setting NO_IOPORT and removing __io does work for a lot of things today, but breaks randconfig builds left and right. I want to clean that up by adding 'depends on HAS_IOPORT' at the correct places and then switch all platforms that don't need it to remove __io. Arnd
On Wed, Jul 06, 2011 at 10:31:50PM +0200, Arnd Bergmann wrote: > Just as a follow-up, this is what I was referring to in the other > sub-thread. Setting NO_IOPORT and removing __io does work for a lot > of things today, but breaks randconfig builds left and right. I want > to clean that up by adding 'depends on HAS_IOPORT' at the correct places > and then switch all platforms that don't need it to remove __io. It's not that easy. NO_IOPORT was brought in by Viro to work around various platforms which broke - such as RiscPC. Viro was well aware of that platform, and we had a discussion about it. The conclusion (I think) was that NO_IOPORT was to prevent ioport_map() et.al. on platforms which couldn't provide a sane definition - eg: (11 Feb 2007)... 19:50 < rmk> inb(port) | inb(port + 1) << 8 is not identical to addr = ioport_map(port); readb(addr) | readb(addr + 1) 19:51 < rmk> inb(port) | inb(port + 1) << 8 _is_ identical to addr = ioport_map(port); readb(addr) | readb(addr + (1 << 2)) 19:53 < rmk> inw(port) | inw(port + 2) equates to addr = ioport_map(port); readw(addr) | readw(addr + (2 << 2)) So, while the above referred to platform uses inb etc, it sets NO_IOPORT to stop the devres breakage, which in turn disables HAS_IOPORT. So, HAS_IOPORT does not mean the ISA/PCI accessors are not provided. It means there will be no devres support for it and ioport_map() is probably missing. I've added Viro to this thread in case he'd like to correct me (if he remembers the background to HAS_IOPORT/NO_IOPORT etc.)
On Wednesday 06 July 2011 22:50:59 Russell King - ARM Linux wrote: > On Wed, Jul 06, 2011 at 10:31:50PM +0200, Arnd Bergmann wrote: > > Just as a follow-up, this is what I was referring to in the other > > sub-thread. Setting NO_IOPORT and removing __io does work for a lot > > of things today, but breaks randconfig builds left and right. I want > > to clean that up by adding 'depends on HAS_IOPORT' at the correct places > > and then switch all platforms that don't need it to remove __io. > > It's not that easy. NO_IOPORT was brought in by Viro to work around > various platforms which broke - such as RiscPC. Viro was well aware > of that platform, and we had a discussion about it. > > The conclusion (I think) was that NO_IOPORT was to prevent ioport_map() > et.al. on platforms which couldn't provide a sane definition - eg: > > (11 Feb 2007)... > 19:50 < rmk> inb(port) | inb(port + 1) << 8 is not identical to addr = ioport_map(port); readb(addr) | readb(addr + 1) > 19:51 < rmk> inb(port) | inb(port + 1) << 8 is identical to addr = ioport_map(port); readb(addr) | readb(addr + (1 << 2)) > 19:53 < rmk> inw(port) | inw(port + 2) equates to addr = ioport_map(port); readw(addr) | readw(addr + (2 << 2)) > > So, while the above referred to platform uses inb etc, it sets > NO_IOPORT to stop the devres breakage, which in turn disables > HAS_IOPORT. > > So, HAS_IOPORT does not mean the ISA/PCI accessors are not provided. > It means there will be no devres support for it and ioport_map() is > probably missing. > > I've added Viro to this thread in case he'd like to correct me (if he > remembers the background to HAS_IOPORT/NO_IOPORT etc.) Thanks for the exact reference. You've mentioned this before and I tried to find the discussion but couldn't. I understand that the original meaning of NO_IOPORT/HAS_IOPORT is very limited, and I would like to extend it in a way to allow both the scenario with inb/outb but without ioport_map and the case where you have no PIO space at all. CONFIG_HAS_IOPORT is nice in that it mirrors CONFIG_HAS_IOMEM for readl/writel, so my preferred solution would be to repurpose that symbol to mean that inb/outb are available, while introducing a new symbol to mean that ioport_map is also available, e.g. CONFIG_HAS_IOPORT_MAP for the cases where we now use CONFIG_HAS_IOPORT. Arnd
2011/7/7 Arnd Bergmann <arnd@arndb.de>: > On Wednesday 06 July 2011 21:10:00 Russell King - ARM Linux wrote: >> On Thu, Jul 07, 2011 at 12:09:24AM +0800, Barry Song wrote: >> > if you define that in asm/io.h as you said: >> > >> > #ifndef IO_SPACE_LIMIT >> > #if defined(PCMCIA_SOC_COMMON) >> > #define IO_SPACE_LIMIT ((resource_size_t)0xffffffff) >> > #else >> > #if defined(CONFIG_PCI) || defined(CONFIG_ISA) || defined(CONFIG_PCCARD) >> > #define IO_SPACE_LIMIT ((resource_size_t)0xffff) >> > #else >> > #define IO_SPACE_LIMIT ((resource_size_t)0) >> > #endif >> > #endif >> > #endif >> > >> > i'd like to delete IO_SPACE_LIMIT in my io.h. >> > >> > otherwise, i'd like to try "#define IO_SPACE_LIMIT >> > ((resource_size_t)0)" in my io.h since i have no real >> > CONFIG_PCI/ISA/PCCARD/PCMCIA_SOC_COMMON. >> >> Thanks - stopping the 0xffffffff madness in new platforms is great. > > FWIW, I've double-checked the Xilinx zynq platform that I've already queued > up for 3.1: this one defines IO_SPACE_LIMIT to 0xffff because PCI support > will get merged later, so that's fine. as far as i know, zynq still has some static mapping tables and board file board_dt.c. as you have reviewed csr platform very carefully, i guess those can get fixed in zynq later too :-) xilinx zynq and csr prima2 should be the pioneering two new SoCs to move to DT in arm for the moment. at least, these two things can try to get same. > >> If you also omit the definition for __io() and set NO_IOPORT in your >> Kconfig, you should also end up with inb() et.al. undefined by asm/io.h, >> which should cause build-time failures if an ISA/PCI/PCMCIA driver >> attempts to build. > > Just as a follow-up, this is what I was referring to in the other > sub-thread. Setting NO_IOPORT and removing __io does work for a lot > of things today, but breaks randconfig builds left and right. I want > to clean that up by adding 'depends on HAS_IOPORT' at the correct places > and then switch all platforms that don't need it to remove __io. > > Arnd >
2011/7/6 Arnd Bergmann <arnd@arndb.de>: > On Wednesday 06 July 2011, Barry Song wrote: > >> > I would normally recommend defining the ranges so that addresses are local >> > to the respective bus, like >> > >> > axi { >> > ranges = <0 0x40000000 0x80000000>; >> > >> > sys-iobg { >> > ranges = <0 0x48000000 0x40000>; >> > clock-controller@0x88000000 { >> > compatible = "sirf,prima2-clkc"; >> > reg = <0 0x1000>; >> > } >> > >> > reset-controller@0x88010000 { >> > compatible = "sirf,prima2-rstc"; >> > reg = <0x10000 0x1000>; >> > }; >> > } >> > } >> >> i am not sure whether it make us a little more difficult to know the >> real address at first glance.we will need to calculate. >> all addresses are 1:1 mapped in this chip. bus map can work even >> though we only give "ranges;" without real "ranges = <0x....>;". > > So each iobg still passes down the entire 32-bit address? yes. each iobg is basically transparent for address transferring. ranges = <0x40000000 0x40000000 0x80000000>; should be ok. > > Note that you never have to do the calculation in the driver > source, of_iomap and the resource logic both take care of this. > > There are multiple ways to handle this, and an empty ranges property > usually works fine, but I find that less readable. > > Another way to handle these is to have a separate range for > each child bus, as in arch/powerpc/boot/dts/gef_ppc9a.dts > > To stay in the example, this would mean doing something like > > axi { > #address-cells = <2>; > #size-cells = <1>; > > ranges = <0 0 0x80000000 0x08000000 // axi devices > 1 0 0x88000000 0x08000000 // sys-iobg > 2 0 0x90000000 0x00010000 // mem-iobg > 3 0 0x90010000 0x07fe0000 // disp-iobg > ... >; > > l2-cache-controller@80040000 { > compatible = "arm,pl310-cache"; > reg = <0 0x40000 0x1000>; > interrupts = <59>; > }; > > sys-iobg { > #address-cells = <1>; > #size-cells = <1>; > ranges = <1 0 0 0x40000>; > clock-controller@88000000 { > compatible = "sirf,prima2-clkc"; > reg = <0 0x1000>; > } > > reset-controller@88010000 { > compatible = "sirf,prima2-rstc"; > reg = <0x10000 0x1000>; > }; > } > } > > > >> >> + >> >> + graphics-iobg { >> >> + compatible = "simple-bus"; >> >> + #address-cells = <1>; >> >> + #size-cells = <1>; >> >> + ranges = <0x98000000 0x98000000 0x8000000>; >> >> + >> >> + graphics@0x98000000 { >> >> + compatible = "sirf,prima2-graphics"; >> >> + reg = <0x98000000 0x8000000>; >> >> + interrupts = <6>; >> >> + }; >> >> + }; >> > >> > Are the display and graphics units CSR developments? If the GPU is >> > in fact licensed from someone else (powervr, arm, ...), you should >> > probably list the actual name of the device. >> >> GPU is powervr sgx 531, so could we define compatible as "powervr,sgx531"? > > Probably yes. You should have a look if there are already bindings for > this that define other attributes. Also, if there is any customization > inside of the chip, you should have another more specific identifier > that makes it possible that this is the version that csr has modified. > >> >> + multimedia-iobg { >> >> + compatible = "simple-bus"; >> >> + #address-cells = <1>; >> >> + #size-cells = <1>; >> >> + ranges = <0xa0000000 0xa0000000 0x8000000>; >> >> + >> >> + multimedia@0xa0000000 { >> >> + compatible = "sirf,prima2-multimedia"; >> >> + reg = <0xa0000000 0x8000000>; >> >> + interrupts = <5>; >> >> + }; >> >> + }; >> > >> > "multimedia" sounds like a too generic term. What does this do? >> >> video decoding. > > sirf,prima2-video-codec is probably better than, but if anyone has other > suggestions, you could use something else. > >> > Are these proprietary uarts, or are they compatible to 8250 and the >> > like? You might want to set a clock-frequency property as of_serial.c >> > uses. >> >> it is not compatible with 8250 . > > ok > >> > Are these rtc implementations related? From the register layout, I would >> > guess that they are supposed to be used by the same driver, so it's >> > probably a good idea to add a "compatible" property with a common name >> > for all three. >> >> in fact, because they are slow, they can't be accessed by mapped >> address directly, the only common point they have is we need to access >> them through mapped address in rtc-iobg indirectly just like we access >> i2c/spi/nand devices. >> >> they are three different devices with different purpose and register >> layout in fact. > > Ok. > > Arnd >
On Wednesday 06 July 2011, Nicolas Pitre wrote: > > Good idea. The related change that I want to do is to conditionalize > > all drivers that require PC-style I/O on the respective bus they > > use, so we can also remove the __io macro for platforms that don't > > need it and catch all drivers using inb/outb at compile time. > > In the spirit of removing as much machine specific and globally used > defines (see my patch series removing a bunch of mach/memory.h > instances), I'd like to see a solution that would make IO_SPACE_LIMIT > into a variable, or having the same definition with a fixed mapping, for > as many SOCs as possible. I think we don't need to make it a variable as long as we don't need to support all platforms together in one kernel. Any combinations of recent platforms should be fine the way that Russell suggested (0xffff if PCI/ISA/PCMCIA is enabled at compile-time, 0 otherwise). Arnd
On Thu, Jul 07, 2011 at 01:43:03PM +0200, Arnd Bergmann wrote: > On Thursday 07 July 2011, Barry Song wrote: > > > FWIW, I've double-checked the Xilinx zynq platform that I've already queued > > > up for 3.1: this one defines IO_SPACE_LIMIT to 0xffff because PCI support > > > will get merged later, so that's fine. > > > > as far as i know, zynq still has some static mapping tables and board > > file board_dt.c. as you have reviewed csr platform very carefully, i > > guess those can get fixed in zynq later too :-) > > xilinx zynq and csr prima2 should be the pioneering two new SoCs to > > move to DT in arm for the moment. at least, these two things can try > > to get same. > > Good point. I'm not planning to change the initial xilinx code, since > it's already in the tree, but I'd like to apply the patch below > to make it do the same as prima2 in this regard. > John, can you ack this patch? How similar are prima2 and zynq after this patch and a diff between their two subdirectories? Are there any differences which can be eliminated? Is there any commonality which can be factored out from the two? Should the two be occupying separate mach directories? I think this is something we need to pay attention to now.
On Thu, Jul 07, 2011 at 03:21:06PM +0200, Arnd Bergmann wrote: > What's left then are basically the headers. There is significant > room for consolidation there, and I think most of them have been > looked at by people before or are currently being worked on. > Below is the complete diff between the headers of the two platforms > as they are being proposed now. Thanks for that. diff -w might be a good idea on these to eliminate changes due to whitespace differences. It has found one thing which should be fixed... > diff -urN arch/arm/mach-prima2/include/mach/vmalloc.h arch/arm/mach-zynq/include/mach/vmalloc.h > --- arch/arm/mach-prima2/include/mach/vmalloc.h 2011-07-07 13:21:41.000000000 +0000 > +++ arch/arm/mach-zynq/include/mach/vmalloc.h 2011-07-07 13:22:07.000000000 +0000 > @@ -1,14 +1,20 @@ > -/* > - * arch/arm/ach-prima2/include/mach/vmalloc.h > +/* arch/arm/mach-zynq/include/mach/vmalloc.h > * > - * Copyright (c) 2010 â 2011 Cambridge Silicon Radio Limited, a CSR plc group company. > + * Copyright (C) 2011 Xilinx > * > - * Licensed under GPLv2 or later. > + * This software is licensed under the terms of the GNU General Public > + * License version 2, as published by the Free Software Foundation, and > + * may be copied, distributed, and modified under those terms. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > */ > > -#ifndef __MACH_VMALLOC_H > -#define __MACH_VMALLOC_H > +#ifndef __MACH_VMALLOC_H__ > +#define __MACH_VMALLOC_H__ > > -#define VMALLOC_END 0xFEC00000 > +#define VMALLOC_END 0xE0000000UL Prima2 should add a UL suffix to VMALLOC_END to ensure that it is properly typed.
2011/7/7 Russell King - ARM Linux <linux@arm.linux.org.uk>: > On Thu, Jul 07, 2011 at 03:21:06PM +0200, Arnd Bergmann wrote: >> What's left then are basically the headers. There is significant >> room for consolidation there, and I think most of them have been >> looked at by people before or are currently being worked on. >> Below is the complete diff between the headers of the two platforms >> as they are being proposed now. > > Thanks for that. diff -w might be a good idea on these to eliminate > changes due to whitespace differences. It has found one thing which > should be fixed... > >> diff -urN arch/arm/mach-prima2/include/mach/vmalloc.h arch/arm/mach-zynq/include/mach/vmalloc.h >> --- arch/arm/mach-prima2/include/mach/vmalloc.h 2011-07-07 13:21:41.000000000 +0000 >> +++ arch/arm/mach-zynq/include/mach/vmalloc.h 2011-07-07 13:22:07.000000000 +0000 >> @@ -1,14 +1,20 @@ >> -/* >> - * arch/arm/ach-prima2/include/mach/vmalloc.h >> +/* arch/arm/mach-zynq/include/mach/vmalloc.h >> * >> - * Copyright (c) 2010 – 2011 Cambridge Silicon Radio Limited, a CSR plc group company. >> + * Copyright (C) 2011 Xilinx >> * >> - * Licensed under GPLv2 or later. >> + * This software is licensed under the terms of the GNU General Public >> + * License version 2, as published by the Free Software Foundation, and >> + * may be copied, distributed, and modified under those terms. >> + * >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> */ >> >> -#ifndef __MACH_VMALLOC_H >> -#define __MACH_VMALLOC_H >> +#ifndef __MACH_VMALLOC_H__ >> +#define __MACH_VMALLOC_H__ >> >> -#define VMALLOC_END 0xFEC00000 >> +#define VMALLOC_END 0xE0000000UL > > Prima2 should add a UL suffix to VMALLOC_END to ensure that it is > properly typed. simply adding a UL suffix will make compiling fail since arch/arm/kernel/debug.S will refer to the macro calculating virtual address of SIRFSOC_UART1_VA_BASE and UL is not legal in asm. samsung has one way to handle this: plat-samsung/include/plat/map-base.h #define S3C_ADDR_BASE 0xF6000000 #ifndef __ASSEMBLY__ #define S3C_ADDR(x) ((void __iomem __force *)S3C_ADDR_BASE + (x)) #else #define S3C_ADDR(x) (S3C_ADDR_BASE + (x)) #endif #define S3C_VA_UART S3C_ADDR(0x01000000) /* UART */ mach-s5pc100/include/mach/debug-macro.S: .macro addruart, rp, rv ldr \rp, = S3C_PA_UART ldr \rv, = S3C_VA_UART #if CONFIG_DEBUG_S3C_UART != 0 add \rp, \rp, #(0x400 * CONFIG_DEBUG_S3C_UART) add \rv, \rv, #(0x400 * CONFIG_DEBUG_S3C_UART) #endif .endm Samsung hasn't UL for S3C_ADDR_BASE in asm context, so its arch/arm/kernel/debug.S can compile. in C context, "(void __iomem __force *)" works to force the right type. To fix my problem, i might simply give the direct address to SIRFSOC_UART1_VA_BASE: #define SIRFSOC_UART1_VA_BASE 0xFEC60000 instead of #define SIRFSOC_UART1_VA_BASE SIRFSOC_VA(0x060000) >
On Fri, Jul 08, 2011 at 10:18:57AM +0800, Barry Song wrote: > simply adding a UL suffix will make compiling fail since > arch/arm/kernel/debug.S will refer to the macro calculating virtual > address of SIRFSOC_UART1_VA_BASE and UL is not legal in asm. A solution for VMALLOC_END would be to include linux/const.h and use _AC(value, UL). I think you're the only one who bases their IO addressing off VMALLOC_END.
On Fri, 8 Jul 2011, Russell King - ARM Linux wrote: > On Fri, Jul 08, 2011 at 10:18:57AM +0800, Barry Song wrote: > > simply adding a UL suffix will make compiling fail since > > arch/arm/kernel/debug.S will refer to the macro calculating virtual > > address of SIRFSOC_UART1_VA_BASE and UL is not legal in asm. > > A solution for VMALLOC_END would be to include linux/const.h and use > _AC(value, UL). I think you're the only one who bases their IO > addressing off VMALLOC_END. This is also a bad idea to use VMALLOC_END like that since this is another per-architecture constant which is targetted for a global removal. Nicolas
On Fri, Jul 08, 2011 at 09:38:56AM -0400, Nicolas Pitre wrote: > On Fri, 8 Jul 2011, Russell King - ARM Linux wrote: > > > On Fri, Jul 08, 2011 at 10:18:57AM +0800, Barry Song wrote: > > > simply adding a UL suffix will make compiling fail since > > > arch/arm/kernel/debug.S will refer to the macro calculating virtual > > > address of SIRFSOC_UART1_VA_BASE and UL is not legal in asm. > > > > A solution for VMALLOC_END would be to include linux/const.h and use > > _AC(value, UL). I think you're the only one who bases their IO > > addressing off VMALLOC_END. > > This is also a bad idea to use VMALLOC_END like that since this is > another per-architecture constant which is targetted for a global > removal. Let's get the story straight and avoid confusion... Using _AC(value, UL) is not a bad idea, nor is adding UL as a suffix for VMALLOC_END. Basing IO addresses off VMALLOC_END is questionable, but we have to have some value for this. Rather than trying to convert everything to a variable, I think some effort needs to be spent trying to keep this as a constant. We've grown too much to have lots of variances in the kernel memory layout and we really should be trying to standardize on this stuff. Part of that is helped with your patch for the StrongARM cache flushing. We just need to take that further.
On Fri, 8 Jul 2011, Russell King - ARM Linux wrote: > On Fri, Jul 08, 2011 at 09:38:56AM -0400, Nicolas Pitre wrote: > > On Fri, 8 Jul 2011, Russell King - ARM Linux wrote: > > > > > On Fri, Jul 08, 2011 at 10:18:57AM +0800, Barry Song wrote: > > > > simply adding a UL suffix will make compiling fail since > > > > arch/arm/kernel/debug.S will refer to the macro calculating virtual > > > > address of SIRFSOC_UART1_VA_BASE and UL is not legal in asm. > > > > > > A solution for VMALLOC_END would be to include linux/const.h and use > > > _AC(value, UL). I think you're the only one who bases their IO > > > addressing off VMALLOC_END. > > > > This is also a bad idea to use VMALLOC_END like that since this is > > another per-architecture constant which is targetted for a global > > removal. > > Let's get the story straight and avoid confusion... > > Using _AC(value, UL) is not a bad idea, nor is adding UL as a suffix for > VMALLOC_END. Absolutely. > Basing IO addresses off VMALLOC_END is questionable, but we have to > have some value for this. Exact. I just wouldn't want to see VMALLOC_END even more entangled into SOC specific mappings. > Rather than trying to convert everything to a variable, I think some > effort needs to be spent trying to keep this as a constant. We've > grown too much to have lots of variances in the kernel memory layout > and we really should be trying to standardize on this stuff. Indeed. The VMALLOC_END case is possibly different as we were trying to find a way to adjust it automatically at run time which would be one thing less for platforms to care about. Having a globally fixed value for it would also solve the multiple definition problem. But some machines have a large set of IO mappings while some others have a small one, so having a one size fits all solution here might be suboptimal. Nicolas
On Friday 08 July 2011 20:09:29 Nicolas Pitre wrote: > Indeed. The VMALLOC_END case is possibly different as we were trying to > find a way to adjust it automatically at run time which would be one > thing less for platforms to care about. Having a globally fixed value > for it would also solve the multiple definition problem. But some > machines have a large set of IO mappings while some others have a > small one, so having a one size fits all solution here might be > suboptimal. Is everything between VMALLOC_END and 0xfeffffff guaranteed to come from iotable_init? If so, we could perhaps turn it into a variable that gets initialized to 0xfeffffff and decreased by iotable_init to be just below the lowest address that has actually been mapped. Obviously, anything that derives values from VMALLOC_END at compile time would need to change, too. Arnd
On Fri, 8 Jul 2011, Arnd Bergmann wrote: > On Friday 08 July 2011 20:09:29 Nicolas Pitre wrote: > > Indeed. The VMALLOC_END case is possibly different as we were trying to > > find a way to adjust it automatically at run time which would be one > > thing less for platforms to care about. Having a globally fixed value > > for it would also solve the multiple definition problem. But some > > machines have a large set of IO mappings while some others have a > > small one, so having a one size fits all solution here might be > > suboptimal. > > Is everything between VMALLOC_END and 0xfeffffff guaranteed to come > from iotable_init? If so, we could perhaps turn it into a variable > that gets initialized to 0xfeffffff and decreased by iotable_init > to be just below the lowest address that has actually been mapped. > > Obviously, anything that derives values from VMALLOC_END at compile > time would need to change, too. You then have a catch22 situation, because one thing that gets derived from VMALLOC_END is the highmem threshold, and that has to be determined before iotable_init can be used. And having a fixed highmem threshold is not any better than a globally fixed VMALLOC_END of course. Nicolas
diff --git a/Documentation/devicetree/bindings/arm/sirf.txt b/Documentation/devicetree/bindings/arm/sirf.txt new file mode 100644 index 0000000..6b07f65 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/sirf.txt @@ -0,0 +1,3 @@ +prima2 "cb" evalutation board +Required root node properties: + - compatible = "sirf,prima2-cb", "sirf,prima2"; diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9adc278..06ee145 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -879,6 +879,19 @@ config ARCH_VT8500 select HAVE_PWM help Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip. + +config ARCH_PRIMA2 + bool "CSR SiRFSoC PRIMA2 ARM Cortex A9 Platform" + select CPU_V7 + select GENERIC_TIME + select GENERIC_CLOCKEVENTS + select CLKDEV_LOOKUP + select GENERIC_IRQ_CHIP + select USE_OF + select ZONE_DMA + help + Support for CSR SiRFSoC ARM Cortex A9 Platform + endchoice # diff --git a/arch/arm/Makefile b/arch/arm/Makefile index f5b2b39..1d693d0 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -169,6 +169,7 @@ machine-$(CONFIG_ARCH_OMAP3) := omap2 machine-$(CONFIG_ARCH_OMAP4) := omap2 machine-$(CONFIG_ARCH_ORION5X) := orion5x machine-$(CONFIG_ARCH_PNX4008) := pnx4008 +machine-$(CONFIG_ARCH_PRIMA2) := prima2 machine-$(CONFIG_ARCH_PXA) := pxa machine-$(CONFIG_ARCH_REALVIEW) := realview machine-$(CONFIG_ARCH_RPC) := rpc diff --git a/arch/arm/boot/dts/prima2-cb.dts b/arch/arm/boot/dts/prima2-cb.dts new file mode 100644 index 0000000..182717e --- /dev/null +++ b/arch/arm/boot/dts/prima2-cb.dts @@ -0,0 +1,423 @@ +/dts-v1/; +/ { + model = "SiRF Prima2 EVB"; + compatible = "sirf,prima2-cb", "sirf,prima2"; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&intc>; + + memory { + reg = <0x00000000 0x20000000>; + }; + + chosen { + bootargs = "mem=512M real_root=/dev/mmcblk0p2 console=ttyS0 panel=1 bootsplash=true bpp=16 androidboot.console=ttyS1"; + linux,stdout-path = &uart1; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + reg = <0x0>; + d-cache-line-size = <32>; + i-cache-line-size = <32>; + d-cache-size = <32768>; + i-cache-size = <32768>; + /* from bootloader */ + timebase-frequency = <0>; + bus-frequency = <0>; + clock-frequency = <0>; + }; + }; + + axi { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x40000000 0x40000000 0x80000000>; + + sirfsoc-iobus { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x40000000 0x40000000 0x80000000>; + + l2-cache-controller@0x80040000 { + compatible = "arm,pl310-cache"; + reg = <0x80040000 0x1000>; + interrupts = <59>; + }; + + intc: interrupt-controller@0x80020000 { + #interrupt-cells = <1>; + interrupt-controller; + compatible = "sirf,prima2-intc"; + reg = <0x80020000 0x1000>; + }; + + sys-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x88000000 0x88000000 0x40000>; + + clock-controller@0x88000000 { + compatible = "sirf,prima2-clkc"; + reg = <0x88000000 0x1000>; + interrupts = <3>; + }; + + reset-controller@0x88010000 { + compatible = "sirf,prima2-rstc"; + reg = <0x88010000 0x1000>; + }; + }; + + mem-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x90000000 0x90000000 0x10000>; + + memory-controller@0x90000000 { + compatible = "sirf,prima2-memc"; + reg = <0x90000000 0x10000>; + interrupts = <27>; + }; + }; + + disp-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x90010000 0x90010000 0x30000>; + + display@0x90010000 { + compatible = "sirf,prima2-lcd"; + reg = <0x90010000 0x20000>; + interrupts = <30>; + }; + + vpp@0x90020000 { + compatible = "sirf,prima2-vpp"; + reg = <0x90020000 0x10000>; + interrupts = <31>; + }; + }; + + graphics-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x98000000 0x98000000 0x8000000>; + + graphics@0x98000000 { + compatible = "sirf,prima2-graphics"; + reg = <0x98000000 0x8000000>; + interrupts = <6>; + }; + }; + + multimedia-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xa0000000 0xa0000000 0x8000000>; + + multimedia@0xa0000000 { + compatible = "sirf,prima2-multimedia"; + reg = <0xa0000000 0x8000000>; + interrupts = <5>; + }; + }; + + dsp-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xa8000000 0xa8000000 0x2000000>; + + dspif@0xa8000000 { + compatible = "sirf,prima2-dspif"; + reg = <0xa8000000 0x10000>; + interrupts = <9>; + }; + + gps@0xa8010000 { + compatible = "sirf,prima2-gps"; + reg = <0xa8010000 0x10000>; + interrupts = <7>; + }; + + dsp@0xa9000000 { + compatible = "sirf,prima2-dsp"; + reg = <0xa9000000 0x1000000>; + interrupts = <8>; + }; + }; + + peri-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xb0000000 0xb0000000 0x180000>; + + timer@0xb0020000 { + compatible = "sirf,prima2-tick"; + reg = <0xb0020000 0x1000>; + interrupts = <0>; + }; + + nand@0xb0030000 { + compatible = "sirf,prima2-nand"; + reg = <0xb0030000 0x10000>; + interrupts = <41>; + }; + + audio@0xb0040000 { + compatible = "sirf,prima2-audio"; + reg = <0xb0040000 0x10000>; + interrupts = <35>; + }; + + uart0: uart@0xb0050000 { + cell-index = <0>; + compatible = "sirf,prima2-uart"; + reg = <0xb0050000 0x10000>; + interrupts = <17>; + }; + + uart1: uart@0xb0060000 { + cell-index = <1>; + compatible = "sirf,prima2-uart"; + reg = <0xb0060000 0x10000>; + interrupts = <18>; + }; + + uart2: uart@0xb0070000 { + cell-index = <2>; + compatible = "sirf,prima2-uart"; + reg = <0xb0070000 0x10000>; + interrupts = <19>; + }; + + usp0: usp@0xb0080000 { + cell-index = <0>; + compatible = "sirf,prima2-usp"; + reg = <0xb0080000 0x10000>; + interrupts = <20>; + }; + + usp1: usp@0xb0090000 { + cell-index = <1>; + compatible = "sirf,prima2-usp"; + reg = <0xb0090000 0x10000>; + interrupts = <21>; + }; + + usp2: usp@0xb00a0000 { + cell-index = <2>; + compatible = "sirf,prima2-usp"; + reg = <0xb00a0000 0x10000>; + interrupts = <22>; + }; + + dmac0: dma-controller@0xb00b0000 { + cell-index = <0>; + compatible = "sirf,prima2-dmac"; + reg = <0xb00b0000 0x10000>; + interrupts = <12>; + }; + + dmac1: dma-controller@0xb0160000 { + cell-index = <1>; + compatible = "sirf,prima2-dmac"; + reg = <0xb0160000 0x10000>; + interrupts = <13>; + }; + + vip@0xb00C0000 { + compatible = "sirf,prima2-vip"; + reg = <0xb00C0000 0x10000>; + }; + + spi0: spi@0xb00D0000 { + cell-index = <0>; + compatible = "sirf,prima2-spi"; + reg = <0xb00D0000 0x10000>; + interrupts = <15>; + }; + + spi1: spi@0xb0170000 { + cell-index = <1>; + compatible = "sirf,prima2-spi"; + reg = <0xb0170000 0x10000>; + interrupts = <16>; + }; + + i2c0: i2c@0xb00E0000 { + cell-index = <0>; + compatible = "sirf,prima2-i2c"; + reg = <0xb00E0000 0x10000>; + interrupts = <24>; + }; + + i2c1: i2c@0xb00f0000 { + cell-index = <1>; + compatible = "sirf,prima2-i2c"; + reg = <0xb00f0000 0x10000>; + interrupts = <25>; + }; + + tsc@0xb0110000 { + compatible = "sirf,prima2-tsc"; + reg = <0xb0110000 0x10000>; + interrupts = <33>; + }; + + gpio: gpio-controller@0xb0120000 { + #gpio-cells = <2>; + #interrupt-cells = <2>; + compatible = "sirf,prima2-gpio"; + reg = <0xb0120000 0x10000>; + gpio-controller; + interrupt-controller; + }; + + pwm@0xb0130000 { + compatible = "sirf,prima2-pwm"; + reg = <0xb0130000 0x10000>; + }; + + efusesys@0xb0140000 { + compatible = "sirf,prima2-efuse"; + reg = <0xb0140000 0x10000>; + }; + + pulsec@0xb0150000 { + compatible = "sirf,prima2-pulsec"; + reg = <0xb0150000 0x10000>; + interrupts = <48>; + }; + + pci-iobg { + compatible = "sirf,prima2-pciiobg", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x56000000 0x56000000 0x1b00000>; + + sd0: sdhci@0x56000000 { + cell-index = <0>; + compatible = "sirf,prima2-sdhc"; + reg = <0x56000000 0x100000>; + interrupts = <38>; + }; + + sd1: sdhci@0x56100000 { + cell-index = <1>; + compatible = "sirf,prima2-sdhc"; + reg = <0x56100000 0x100000>; + interrupts = <38>; + }; + + sd2: sdhci@0x56200000 { + cell-index = <2>; + compatible = "sirf,prima2-sdhc"; + reg = <0x56200000 0x100000>; + interrupts = <23>; + }; + + sd3: sdhci@0x56300000 { + cell-index = <3>; + compatible = "sirf,prima2-sdhc"; + reg = <0x56300000 0x100000>; + interrupts = <23>; + }; + + sd4: sdhci@0x56400000 { + cell-index = <4>; + compatible = "sirf,prima2-sdhc"; + reg = <0x56400000 0x100000>; + interrupts = <39>; + }; + + sd5: sdhci@0x56500000 { + cell-index = <5>; + compatible = "sirf,prima2-sdhc"; + reg = <0x56500000 0x100000>; + interrupts = <39>; + }; + + pci-copy@0x57900000 { + compatible = "sirf,prima2-pcicp"; + reg = <0x57900000 0x100000>; + interrupts = <40>; + }; + + rom-interface@0x57a00000 { + compatible = "sirf,prima2-romif"; + reg = <0x57a00000 0x100000>; + }; + }; + }; + + rtc-iobg { + compatible = "sirf,prima2-rtciobg", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x80030000 0x10000>; + + gpsrtc@0x1000 { + compatible = "sirf,prima2-gpsrtc"; + reg = <0x1000 0x1000>; + interrupts = <55 56 57>; + }; + + sysrtc@0x2000 { + compatible = "sirf,prima2-sysrtc"; + reg = <0x2000 0x1000>; + interrupts = <52 53 54>; + }; + + pwrc@0x3000 { + compatible = "sirf,prima2-pwrc"; + reg = <0x3000 0x1000>; + interrupts = <32>; + }; + }; + + uus-iobg { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xb8000000 0xb8000000 0x40000>; + + usb0: usb@0xb00E0000 { + compatible = "sirf,prima2-usb"; + reg = <0xb8000000 0x10000>; + interrupts = <10>; + }; + + usb1: usb@0xb00f0000 { + compatible = "sirf,prima2-usb"; + reg = <0xb8010000 0x10000>; + interrupts = <11>; + }; + + sata@0xb00f0000 { + compatible = "sirf,prima2-sata"; + reg = <0xb8020000 0x10000>; + interrupts = <37>; + }; + + security@0xb00f0000 { + compatible = "sirf,prima2-security"; + reg = <0xb8030000 0x10000>; + interrupts = <42>; + }; + }; + }; + }; +}; diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile new file mode 100644 index 0000000..d44f7ae --- /dev/null +++ b/arch/arm/mach-prima2/Makefile @@ -0,0 +1,5 @@ +obj-y := timer.o +obj-y += irq.o +obj-y += clock.o +obj-y += rstc.o +obj-y += prima2.o diff --git a/arch/arm/mach-prima2/Makefile.boot b/arch/arm/mach-prima2/Makefile.boot new file mode 100644 index 0000000..d023db3 --- /dev/null +++ b/arch/arm/mach-prima2/Makefile.boot @@ -0,0 +1,3 @@ +zreladdr-y := 0x00008000 +params_phys-y := 0x00000100 +initrd_phys-y := 0x00800000 diff --git a/arch/arm/mach-prima2/clock.c b/arch/arm/mach-prima2/clock.c new file mode 100644 index 0000000..f9a2aaf --- /dev/null +++ b/arch/arm/mach-prima2/clock.c @@ -0,0 +1,509 @@ +/* + * Clock tree for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include <linux/module.h> +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/io.h> +#include <linux/clkdev.h> +#include <linux/clk.h> +#include <linux/spinlock.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <asm/mach/map.h> +#include <mach/map.h> + +#define SIRFSOC_CLKC_CLK_EN0 0x0000 +#define SIRFSOC_CLKC_CLK_EN1 0x0004 +#define SIRFSOC_CLKC_REF_CFG 0x0014 +#define SIRFSOC_CLKC_CPU_CFG 0x0018 +#define SIRFSOC_CLKC_MEM_CFG 0x001c +#define SIRFSOC_CLKC_SYS_CFG 0x0020 +#define SIRFSOC_CLKC_IO_CFG 0x0024 +#define SIRFSOC_CLKC_DSP_CFG 0x0028 +#define SIRFSOC_CLKC_GFX_CFG 0x002c +#define SIRFSOC_CLKC_MM_CFG 0x0030 +#define SIRFSOC_LKC_LCD_CFG 0x0034 +#define SIRFSOC_CLKC_MMC_CFG 0x0038 +#define SIRFSOC_CLKC_PLL1_CFG0 0x0040 +#define SIRFSOC_CLKC_PLL2_CFG0 0x0044 +#define SIRFSOC_CLKC_PLL3_CFG0 0x0048 +#define SIRFSOC_CLKC_PLL1_CFG1 0x004c +#define SIRFSOC_CLKC_PLL2_CFG1 0x0050 +#define SIRFSOC_CLKC_PLL3_CFG1 0x0054 +#define SIRFSOC_CLKC_PLL1_CFG2 0x0058 +#define SIRFSOC_CLKC_PLL2_CFG2 0x005c +#define SIRFSOC_CLKC_PLL3_CFG2 0x0060 + +#define SIRFSOC_CLOCK_VA_BASE SIRFSOC_VA(0x005000) + +#define KHZ 1000 +#define MHZ (KHZ * KHZ) + +struct clk_ops { + unsigned long (*get_rate)(struct clk *clk); + long (*round_rate)(struct clk *clk, unsigned long rate); + int (*set_rate)(struct clk *clk, unsigned long rate); + int (*enable)(struct clk *clk); + int (*disable)(struct clk *clk); + struct clk *(*get_parent)(struct clk *clk); + int (*set_parent)(struct clk *clk, struct clk *parent); +}; + +struct clk { + struct clk *parent; /* parent clk */ + unsigned long rate; /* clock rate in Hz */ + signed char usage; /* clock enable count */ + signed char enable_bit; /* enable bit: 0 ~ 63 */ + unsigned short regofs; /* register offset */ + struct clk_ops *ops; /* clock operation */ +}; + +static DEFINE_SPINLOCK(clocks_lock); + +static inline unsigned long clkc_readl(unsigned reg) +{ + return readl(SIRFSOC_CLOCK_VA_BASE + reg); +} + +static inline void clkc_writel(u32 val, unsigned reg) +{ + writel(val, SIRFSOC_CLOCK_VA_BASE + reg); +} + +/* + * osc_rtc - real time oscillator - 32.768KHz + * osc_sys - high speed oscillator - 26MHz + */ + +static struct clk clk_rtc = { + .rate = 32768, +}; + +static struct clk clk_osc = { + .rate = 26 * MHZ, +}; + +/* + * std pll + */ +static unsigned long std_pll_get_rate(struct clk *clk) +{ + unsigned long fin = clk_get_rate(clk->parent); + u32 regcfg2 = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 - + SIRFSOC_CLKC_PLL1_CFG0; + + if (clkc_readl(regcfg2) & BIT(2)) { + /* pll bypass mode */ + clk->rate = fin; + } else { + /* fout = fin * nf / nr / od */ + u32 cfg0 = clkc_readl(clk->regofs); + u32 nf = (cfg0 & (BIT(13) - 1)) + 1; + u32 nr = ((cfg0 >> 13) & (BIT(6) - 1)) + 1; + u32 od = ((cfg0 >> 19) & (BIT(4) - 1)) + 1; + WARN_ON(fin % MHZ); + clk->rate = fin / MHZ * nf / nr / od * MHZ; + } + + return clk->rate; +} + +static int std_pll_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long fin, nf, nr, od, reg; + + /* + * fout = fin * nf / (nr * od); + * set od = 1, nr = fin/MHz, so fout = nf * MHz + */ + + nf = rate / MHZ; + if (unlikely((rate % MHZ) || nf > BIT(13) || nf < 1)) + return -EINVAL; + + fin = clk_get_rate(clk->parent); + BUG_ON(fin < MHZ); + + nr = fin / MHZ; + BUG_ON((fin % MHZ) || nr > BIT(6)); + + od = 1; + + reg = (nf - 1) | ((nr - 1) << 13) | ((od - 1) << 19); + clkc_writel(reg, clk->regofs); + + reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG1 - SIRFSOC_CLKC_PLL1_CFG0; + clkc_writel((nf >> 1) - 1, reg); + + reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 - SIRFSOC_CLKC_PLL1_CFG0; + while (!(clkc_readl(reg) & BIT(6))) + cpu_relax(); + + clk->rate = 0; /* set to zero will force recalculation */ + return 0; +} + +static struct clk_ops std_pll_ops = { + .get_rate = std_pll_get_rate, + .set_rate = std_pll_set_rate, +}; + +static struct clk clk_pll1 = { + .parent = &clk_osc, + .regofs = SIRFSOC_CLKC_PLL1_CFG0, + .ops = &std_pll_ops, +}; + +static struct clk clk_pll2 = { + .parent = &clk_osc, + .regofs = SIRFSOC_CLKC_PLL2_CFG0, + .ops = &std_pll_ops, +}; + +static struct clk clk_pll3 = { + .parent = &clk_osc, + .regofs = SIRFSOC_CLKC_PLL3_CFG0, + .ops = &std_pll_ops, +}; + +/* + * clock domains - cpu, mem, sys/io + */ + +static struct clk clk_mem; + +static struct clk *dmn_get_parent(struct clk *clk) +{ + struct clk *clks[] = { + &clk_osc, &clk_rtc, &clk_pll1, &clk_pll2, &clk_pll3 + }; + u32 cfg = clkc_readl(clk->regofs); + WARN_ON((cfg & (BIT(3) - 1)) > 4); + return clks[cfg & (BIT(3) - 1)]; +} + +static int dmn_set_parent(struct clk *clk, struct clk *parent) +{ + const struct clk *clks[] = { + &clk_osc, &clk_rtc, &clk_pll1, &clk_pll2, &clk_pll3 + }; + u32 cfg = clkc_readl(clk->regofs); + int i; + for (i = 0; i < ARRAY_SIZE(clks); i++) { + if (clks[i] == parent) { + cfg &= ~(BIT(3) - 1); + clkc_writel(cfg | i, clk->regofs); + /* BIT(3) - switching status: 1 - busy, 0 - done */ + while (clkc_readl(clk->regofs) & BIT(3)) + cpu_relax(); + return 0; + } + } + return -EINVAL; +} + +static unsigned long dmn_get_rate(struct clk *clk) +{ + unsigned long fin = clk_get_rate(clk->parent); + u32 cfg = clkc_readl(clk->regofs); + if (cfg & BIT(24)) { + /* fcd bypass mode */ + clk->rate = fin; + } else { + /* + * wait count: bit[19:16], hold count: bit[23:20] + */ + u32 wait = (cfg >> 16) & (BIT(4) - 1); + u32 hold = (cfg >> 20) & (BIT(4) - 1); + + clk->rate = fin / (wait + hold + 2); + } + + return clk->rate; +} + +static int dmn_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long fin; + unsigned ratio, wait, hold, reg; + unsigned bits = (clk == &clk_mem) ? 3 : 4; + + fin = clk_get_rate(clk->parent); + ratio = fin / rate; + + if (unlikely(ratio < 2 || ratio > BIT(bits + 1))) + return -EINVAL; + + WARN_ON(fin % rate); + + wait = (ratio >> 1) - 1; + hold = ratio - wait - 2; + + reg = clkc_readl(clk->regofs); + reg &= ~(((BIT(bits) - 1) << 16) | ((BIT(bits) - 1) << 20)); + reg |= (wait << 16) | (hold << 20) | BIT(25); + clkc_writel(reg, clk->regofs); + + /* waiting FCD been effective */ + while (clkc_readl(clk->regofs) & BIT(25)) + cpu_relax(); + + clk->rate = 0; /* set to zero will force recalculation */ + + return 0; +} + +/* + * cpu clock has no FCD register in Prima2, can only change pll + */ +static int cpu_set_rate(struct clk *clk, unsigned long rate) +{ + int ret1, ret2; + struct clk *cur_parent, *tmp_parent; + + cur_parent = dmn_get_parent(clk); + BUG_ON(cur_parent == NULL || cur_parent->usage > 1); + + /* switch to tmp pll before setting parent clock's rate */ + tmp_parent = cur_parent == &clk_pll1 ? &clk_pll2 : &clk_pll1; + ret1 = dmn_set_parent(clk, tmp_parent); + BUG_ON(ret1); + + ret2 = clk_set_rate(cur_parent, rate); + + ret1 = dmn_set_parent(clk, cur_parent); + + clk->rate = 0; /* set to zero will force recalculation */ + + return ret2 ? ret2 : ret1; +} + +static struct clk_ops cpu_ops = { + .get_parent = dmn_get_parent, + .set_parent = dmn_set_parent, + .set_rate = cpu_set_rate, +}; + +static struct clk clk_cpu = { + .parent = &clk_pll1, + .regofs = SIRFSOC_CLKC_CPU_CFG, + .ops = &cpu_ops, +}; + + +static struct clk_ops msi_ops = { + .set_rate = dmn_set_rate, + .get_rate = dmn_get_rate, + .set_parent = dmn_set_parent, + .get_parent = dmn_get_parent, +}; + +static struct clk clk_mem = { + .parent = &clk_pll2, + .regofs = SIRFSOC_CLKC_MEM_CFG, + .ops = &msi_ops, +}; + +static struct clk clk_sys = { + .parent = &clk_pll3, + .regofs = SIRFSOC_CLKC_SYS_CFG, + .ops = &msi_ops, +}; + +static struct clk clk_io = { + .parent = &clk_pll3, + .regofs = SIRFSOC_CLKC_IO_CFG, + .ops = &msi_ops, +}; + +/* + * on-chip clock sets + */ +static struct clk_lookup onchip_clks[] = { + { + .dev_id = "rtc", + .clk = &clk_rtc, + }, { + .dev_id = "osc", + .clk = &clk_osc, + }, { + .dev_id = "pll1", + .clk = &clk_pll1, + }, { + .dev_id = "pll2", + .clk = &clk_pll2, + }, { + .dev_id = "pll3", + .clk = &clk_pll3, + }, { + .dev_id = "cpu", + .clk = &clk_cpu, + }, { + .dev_id = "mem", + .clk = &clk_mem, + }, { + .dev_id = "sys", + .clk = &clk_sys, + }, { + .dev_id = "io", + .clk = &clk_io, + }, +}; + +int clk_enable(struct clk *clk) +{ + unsigned long flags; + + if (unlikely(IS_ERR_OR_NULL(clk))) + return -EINVAL; + + if (clk->parent) + clk_enable(clk->parent); + + spin_lock_irqsave(&clocks_lock, flags); + if (!clk->usage++ && clk->ops && clk->ops->enable) + clk->ops->enable(clk); + spin_unlock_irqrestore(&clocks_lock, flags); + return 0; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ + unsigned long flags; + + if (unlikely(IS_ERR_OR_NULL(clk))) + return; + + WARN_ON(!clk->usage); + + spin_lock_irqsave(&clocks_lock, flags); + if (--clk->usage == 0 && clk->ops && clk->ops->disable) + clk->ops->disable(clk); + spin_unlock_irqrestore(&clocks_lock, flags); + + if (clk->parent) + clk_disable(clk->parent); +} +EXPORT_SYMBOL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + if (unlikely(IS_ERR_OR_NULL(clk))) + return 0; + + if (clk->rate) + return clk->rate; + + if (clk->ops && clk->ops->get_rate) + return clk->ops->get_rate(clk); + + return clk_get_rate(clk->parent); +} +EXPORT_SYMBOL(clk_get_rate); + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + if (unlikely(IS_ERR_OR_NULL(clk))) + return 0; + + if (clk->ops && clk->ops->round_rate) + return clk->ops->round_rate(clk, rate); + + return 0; +} +EXPORT_SYMBOL(clk_round_rate); + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + if (unlikely(IS_ERR_OR_NULL(clk))) + return -EINVAL; + + if (!clk->ops || !clk->ops->set_rate) + return -EINVAL; + + return clk->ops->set_rate(clk, rate); +} +EXPORT_SYMBOL(clk_set_rate); + +int clk_set_parent(struct clk *clk, struct clk *parent) +{ + int ret; + unsigned long flags; + + if (unlikely(IS_ERR_OR_NULL(clk))) + return -EINVAL; + + if (!clk->ops || !clk->ops->set_parent) + return -EINVAL; + + spin_lock_irqsave(&clocks_lock, flags); + ret = clk->ops->set_parent(clk, parent); + if (!ret) { + parent->usage += clk->usage; + clk->parent->usage -= clk->usage; + BUG_ON(clk->parent->usage < 0); + clk->parent = parent; + } + spin_unlock_irqrestore(&clocks_lock, flags); + return ret; +} +EXPORT_SYMBOL(clk_set_parent); + +struct clk *clk_get_parent(struct clk *clk) +{ + unsigned long flags; + + if (unlikely(IS_ERR_OR_NULL(clk))) + return NULL; + + if (!clk->ops || !clk->ops->get_parent) + return clk->parent; + + spin_lock_irqsave(&clocks_lock, flags); + clk->parent = clk->ops->get_parent(clk); + spin_unlock_irqrestore(&clocks_lock, flags); + return clk->parent; +} +EXPORT_SYMBOL(clk_get_parent); + +static void __init sirfsoc_clk_init(void) +{ + clkdev_add_table(onchip_clks, ARRAY_SIZE(onchip_clks)); +} + +static struct of_device_id clkc_ids[] = { + { .compatible = "sirf,prima2-clkc" }, +}; + +void __init sirfsoc_of_clk_init(void) +{ + struct device_node *np; + struct resource res; + struct map_desc sirfsoc_clkc_iodesc = { + .virtual = SIRFSOC_CLOCK_VA_BASE, + .type = MT_DEVICE, + }; + + np = of_find_matching_node(NULL, clkc_ids); + if (!np) + panic("unable to find compatible clkc node in dtb\n"); + + if (of_address_to_resource(np, 0, &res)) + panic("unable to find clkc range in dtb"); + of_node_put(np); + + sirfsoc_clkc_iodesc.pfn = __phys_to_pfn(res.start); + sirfsoc_clkc_iodesc.length = 1 + res.end - res.start; + + iotable_init(&sirfsoc_clkc_iodesc, 1); + + sirfsoc_clk_init(); +} diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h new file mode 100644 index 0000000..83e5d21 --- /dev/null +++ b/arch/arm/mach-prima2/common.h @@ -0,0 +1,26 @@ +/* + * This file contains common function prototypes to avoid externs in the c files. + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __MACH_PRIMA2_COMMON_H__ +#define __MACH_PRIMA2_COMMON_H__ + +#include <linux/init.h> +#include <asm/mach/time.h> + +extern struct sys_timer sirfsoc_timer; + +extern void __init sirfsoc_of_irq_init(void); +extern void __init sirfsoc_of_clk_init(void); + +#ifndef CONFIG_DEBUG_LL +static inline void sirfsoc_map_lluart(void) {} +#else +extern void __init sirfsoc_map_lluart(void); +#endif + +#endif diff --git a/arch/arm/mach-prima2/include/mach/clkdev.h b/arch/arm/mach-prima2/include/mach/clkdev.h new file mode 100644 index 0000000..6693251 --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/clkdev.h @@ -0,0 +1,15 @@ +/* + * arch/arm/mach-prima2/include/mach/clkdev.h + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __MACH_CLKDEV_H +#define __MACH_CLKDEV_H + +#define __clk_get(clk) ({ 1; }) +#define __clk_put(clk) do { } while (0) + +#endif diff --git a/arch/arm/mach-prima2/include/mach/debug-macro.S b/arch/arm/mach-prima2/include/mach/debug-macro.S new file mode 100644 index 0000000..bf75106 --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/debug-macro.S @@ -0,0 +1,29 @@ +/* + * arch/arm/mach-prima2/include/mach/debug-macro.S + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include <mach/hardware.h> +#include <mach/uart.h> + + .macro addruart, rp, rv + ldr \rp, =SIRFSOC_UART1_PA_BASE @ physical + ldr \rv, =SIRFSOC_UART1_VA_BASE @ virtual + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #SIRFSOC_UART_TXFIFO_DATA] + .endm + + .macro busyuart,rd,rx + .endm + + .macro waituart,rd,rx +1001: ldr \rd, [\rx, #SIRFSOC_UART_TXFIFO_STATUS] + tst \rd, #SIRFSOC_UART1_TXFIFO_EMPTY + beq 1001b + .endm + diff --git a/arch/arm/mach-prima2/include/mach/entry-macro.S b/arch/arm/mach-prima2/include/mach/entry-macro.S new file mode 100644 index 0000000..1c8a50f --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/entry-macro.S @@ -0,0 +1,29 @@ +/* + * arch/arm/mach-prima2/include/mach/entry-macro.S + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include <mach/hardware.h> + +#define SIRFSOC_INT_ID 0x38 + + .macro get_irqnr_preamble, base, tmp + ldr \base, =sirfsoc_intc_base + ldr \base, [\base] + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \irqnr, [\base, #SIRFSOC_INT_ID] @ Get the highest priority irq + cmp \irqnr, #0x40 @ the irq num can't be larger than 0x3f + movges \irqnr, #0 + .endm + + .macro disable_fiq + .endm + + .macro arch_ret_to_user, tmp1, tmp2 + .endm + diff --git a/arch/arm/mach-prima2/include/mach/hardware.h b/arch/arm/mach-prima2/include/mach/hardware.h new file mode 100644 index 0000000..105b969 --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/hardware.h @@ -0,0 +1,15 @@ +/* + * arch/arm/mach-prima2/include/mach/hardware.h + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __MACH_HARDWARE_H__ +#define __MACH_HARDWARE_H__ + +#include <asm/sizes.h> +#include <mach/map.h> + +#endif diff --git a/arch/arm/mach-prima2/include/mach/io.h b/arch/arm/mach-prima2/include/mach/io.h new file mode 100644 index 0000000..fc54f16 --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/io.h @@ -0,0 +1,21 @@ +/* + * arch/arm/mach-prima2/include/mach/io.h + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __MACH_PRIMA2_IO_H +#define __MACH_PRIMA2_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +/* + * We don't actually have real ISA nor PCI buses, but there is so many + * drivers out there that might just work if we fake them... + */ +#define __io(a) __typesafe_io(a) +#define __mem_pci(a) (a) + +#endif diff --git a/arch/arm/mach-prima2/include/mach/irqs.h b/arch/arm/mach-prima2/include/mach/irqs.h new file mode 100644 index 0000000..bb354f9 --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/irqs.h @@ -0,0 +1,17 @@ +/* + * arch/arm/mach-prima2/include/mach/irqs.h + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __ASM_ARCH_IRQS_H +#define __ASM_ARCH_IRQS_H + +#define SIRFSOC_INTENAL_IRQ_START 0 +#define SIRFSOC_INTENAL_IRQ_END 59 + +#define NR_IRQS 220 + +#endif diff --git a/arch/arm/mach-prima2/include/mach/map.h b/arch/arm/mach-prima2/include/mach/map.h new file mode 100644 index 0000000..66b1ae2 --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/map.h @@ -0,0 +1,16 @@ +/* + * memory & I/O static mapping definitions for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __MACH_PRIMA2_MAP_H__ +#define __MACH_PRIMA2_MAP_H__ + +#include <mach/vmalloc.h> + +#define SIRFSOC_VA(x) (VMALLOC_END + ((x) & 0x00FFF000)) + +#endif diff --git a/arch/arm/mach-prima2/include/mach/memory.h b/arch/arm/mach-prima2/include/mach/memory.h new file mode 100644 index 0000000..368cd5a --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/memory.h @@ -0,0 +1,21 @@ +/* + * arch/arm/mach-prima2/include/mach/memory.h + * + * Copyright (c) 2010 – 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +#define PLAT_PHYS_OFFSET UL(0x00000000) + +/* + * Restrict DMA-able region to workaround silicon limitation. + * The limitation restricts buffers available for DMA to SD/MMC + * hardware to be below 256MB + */ +#define ARM_DMA_ZONE_SIZE (SZ_256M) + +#endif diff --git a/arch/arm/mach-prima2/include/mach/system.h b/arch/arm/mach-prima2/include/mach/system.h new file mode 100644 index 0000000..0dbd257 --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/system.h @@ -0,0 +1,29 @@ +/* + * arch/arm/mach-prima2/include/mach/system.h + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __MACH_SYSTEM_H__ +#define __MACH_SYSTEM_H__ + +#include <linux/bitops.h> +#include <mach/hardware.h> + +#define SIRFSOC_SYS_RST_BIT BIT(31) + +extern void __iomem *sirfsoc_rstc_base; + +static inline void arch_idle(void) +{ + cpu_do_idle(); +} + +static inline void arch_reset(char mode, const char *cmd) +{ + writel(SIRFSOC_SYS_RST_BIT, sirfsoc_rstc_base); +} + +#endif diff --git a/arch/arm/mach-prima2/include/mach/timex.h b/arch/arm/mach-prima2/include/mach/timex.h new file mode 100644 index 0000000..d6f98a7 --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/timex.h @@ -0,0 +1,14 @@ +/* + * arch/arm/mach-prima2/include/mach/timex.h + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __MACH_TIMEX_H__ +#define __MACH_TIMEX_H__ + +#define CLOCK_TICK_RATE 1000000 + +#endif diff --git a/arch/arm/mach-prima2/include/mach/uart.h b/arch/arm/mach-prima2/include/mach/uart.h new file mode 100644 index 0000000..de2fc2b --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/uart.h @@ -0,0 +1,23 @@ +/* + * arch/arm/mach-prima2/include/mach/uart.h + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __MACH_PRIMA2_SIRFSOC_UART_H +#define __MACH_PRIMA2_SIRFSOC_UART_H + +/* UART-1: used as serial debug port */ +#define SIRFSOC_UART1_PA_BASE 0xb0060000 +#define SIRFSOC_UART1_VA_BASE SIRFSOC_VA(0x060000) +#define SIRFSOC_UART1_SIZE SZ_4K + +#define SIRFSOC_UART_TXFIFO_STATUS 0x0114 +#define SIRFSOC_UART_TXFIFO_DATA 0x0118 + +#define SIRFSOC_UART1_TXFIFO_FULL (1 << 5) +#define SIRFSOC_UART1_TXFIFO_EMPTY (1 << 6) + +#endif diff --git a/arch/arm/mach-prima2/include/mach/uncompress.h b/arch/arm/mach-prima2/include/mach/uncompress.h new file mode 100644 index 0000000..83125c6 --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/uncompress.h @@ -0,0 +1,40 @@ +/* + * arch/arm/mach-prima2/include/mach/uncompress.h + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __ASM_ARCH_UNCOMPRESS_H +#define __ASM_ARCH_UNCOMPRESS_H + +#include <linux/io.h> +#include <mach/hardware.h> +#include <mach/uart.h> + +void arch_decomp_setup(void) +{ +} + +#define arch_decomp_wdog() + +static __inline__ void putc(char c) +{ + /* + * during kernel decompression, all mappings are flat: + * virt_addr == phys_addr + */ + while (__raw_readl(SIRFSOC_UART1_PA_BASE + SIRFSOC_UART_TXFIFO_STATUS) + & SIRFSOC_UART1_TXFIFO_FULL) + barrier(); + + __raw_writel(c, SIRFSOC_UART1_PA_BASE + SIRFSOC_UART_TXFIFO_DATA); +} + +static inline void flush(void) +{ +} + +#endif + diff --git a/arch/arm/mach-prima2/include/mach/vmalloc.h b/arch/arm/mach-prima2/include/mach/vmalloc.h new file mode 100644 index 0000000..116d0a5 --- /dev/null +++ b/arch/arm/mach-prima2/include/mach/vmalloc.h @@ -0,0 +1,14 @@ +/* + * arch/arm/ach-prima2/include/mach/vmalloc.h + * + * Copyright (c) 2010 – 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#ifndef __MACH_VMALLOC_H +#define __MACH_VMALLOC_H + +#define VMALLOC_END 0xFEC00000 + +#endif diff --git a/arch/arm/mach-prima2/irq.c b/arch/arm/mach-prima2/irq.c new file mode 100644 index 0000000..c3404cb --- /dev/null +++ b/arch/arm/mach-prima2/irq.c @@ -0,0 +1,71 @@ +/* + * interrupt controller support for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include <linux/init.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <mach/hardware.h> +#include <asm/mach/irq.h> +#include <linux/of.h> +#include <linux/of_address.h> + +#define SIRFSOC_INT_RISC_MASK0 0x0018 +#define SIRFSOC_INT_RISC_MASK1 0x001C +#define SIRFSOC_INT_RISC_LEVEL0 0x0020 +#define SIRFSOC_INT_RISC_LEVEL1 0x0024 + +void __iomem *sirfsoc_intc_base; + +static __init void +sirfsoc_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num) +{ + struct irq_chip_generic *gc; + struct irq_chip_type *ct; + + gc = irq_alloc_generic_chip("SIRFINTC", 1, irq_start, base, handle_level_irq); + ct = gc->chip_types; + + ct->chip.irq_mask = irq_gc_mask_clr_bit; + ct->chip.irq_unmask = irq_gc_mask_set_bit; + ct->regs.mask = SIRFSOC_INT_RISC_MASK0; + + irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST, 0); +} + +static __init void sirfsoc_irq_init(void) +{ + sirfsoc_alloc_gc(sirfsoc_intc_base, 0, 32); + sirfsoc_alloc_gc(sirfsoc_intc_base + 4, 32, SIRFSOC_INTENAL_IRQ_END - 32); + + writel_relaxed(0, sirfsoc_intc_base + SIRFSOC_INT_RISC_LEVEL0); + writel_relaxed(0, sirfsoc_intc_base + SIRFSOC_INT_RISC_LEVEL1); + + writel_relaxed(0, sirfsoc_intc_base + SIRFSOC_INT_RISC_MASK0); + writel_relaxed(0, sirfsoc_intc_base + SIRFSOC_INT_RISC_MASK1); +} + +static struct of_device_id intc_ids[] = { + { .compatible = "sirf,prima2-intc" }, +}; + +void __init sirfsoc_of_irq_init(void) +{ + struct device_node *np; + + np = of_find_matching_node(NULL, intc_ids); + if (!np) + panic("unable to find compatible intc node in dtb\n"); + + sirfsoc_intc_base = of_iomap(np, 0); + if (!sirfsoc_intc_base) + panic("unable to map intc cpu registers\n"); + + of_node_put(np); + + sirfsoc_irq_init(); +} diff --git a/arch/arm/mach-prima2/prima2.c b/arch/arm/mach-prima2/prima2.c new file mode 100644 index 0000000..f6b04a1 --- /dev/null +++ b/arch/arm/mach-prima2/prima2.c @@ -0,0 +1,40 @@ +/* + * Defines machines for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include "common.h" + +static struct of_device_id sirfsoc_of_bus_ids[] __initdata = { + { .compatible = "simple-bus", }, + {}, +}; + +void __init sirfsoc_mach_init(void) +{ + of_platform_bus_probe(NULL, sirfsoc_of_bus_ids, NULL); +} + +static const char *prima2cb_dt_match[] __initdata = { + "sirf,prima2-cb", + NULL +}; + +MACHINE_START(PRIMA2_EVB, "prima2cb") + .boot_params = 0x00000100, + .init_early = sirfsoc_of_clk_init, + .map_io = sirfsoc_map_lluart, + .init_irq = sirfsoc_of_irq_init, + .timer = &sirfsoc_timer, + .init_machine = sirfsoc_mach_init, + .dt_compat = prima2cb_dt_match, +MACHINE_END diff --git a/arch/arm/mach-prima2/rstc.c b/arch/arm/mach-prima2/rstc.c new file mode 100644 index 0000000..d074786 --- /dev/null +++ b/arch/arm/mach-prima2/rstc.c @@ -0,0 +1,69 @@ +/* + * reset controller for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include <linux/kernel.h> +#include <linux/mutex.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/of.h> +#include <linux/of_address.h> + +void __iomem *sirfsoc_rstc_base; +static DEFINE_MUTEX(rstc_lock); + +static struct of_device_id rstc_ids[] = { + { .compatible = "sirf,prima2-rstc" }, +}; + +static int __init sirfsoc_of_rstc_init(void) +{ + struct device_node *np; + + np = of_find_matching_node(NULL, rstc_ids); + if (!np) + panic("unable to find compatible rstc node in dtb\n"); + + sirfsoc_rstc_base = of_iomap(np, 0); + if (!sirfsoc_rstc_base) + panic("unable to map rstc cpu registers\n"); + + of_node_put(np); + + return 0; +} +early_initcall(sirfsoc_of_rstc_init); + +int sirfsoc_reset_device(struct device *dev) +{ + const unsigned int *prop = of_get_property(dev->of_node, "reset-bit", NULL); + unsigned int reset_bit; + + if (!prop) + return -ENODEV; + + reset_bit = be32_to_cpup(prop); + + mutex_lock(&rstc_lock); + + /* + * Writing 1 to this bit resets corresponding block. Writing 0 to this + * bit de-asserts reset signal of the corresponding block. + * datasheet doesn't require explicit delay between the set and clear + * of reset bit. it could be shorter if tests pass. + */ + writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) | reset_bit, + sirfsoc_rstc_base + (reset_bit / 32) * 4); + msleep(10); + writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) & ~reset_bit, + sirfsoc_rstc_base + (reset_bit / 32) * 4); + + mutex_unlock(&rstc_lock); + + return 0; +} diff --git a/arch/arm/mach-prima2/timer.c b/arch/arm/mach-prima2/timer.c new file mode 100644 index 0000000..cc30bc6 --- /dev/null +++ b/arch/arm/mach-prima2/timer.c @@ -0,0 +1,219 @@ +/* + * System timer for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/clockchips.h> +#include <linux/clocksource.h> +#include <linux/bitops.h> +#include <linux/irq.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <mach/map.h> +#include <asm/mach/time.h> + +#define SIRFSOC_TIMER_COUNTER_LO 0x0000 +#define SIRFSOC_TIMER_COUNTER_HI 0x0004 +#define SIRFSOC_TIMER_MATCH_0 0x0008 +#define SIRFSOC_TIMER_MATCH_1 0x000C +#define SIRFSOC_TIMER_MATCH_2 0x0010 +#define SIRFSOC_TIMER_MATCH_3 0x0014 +#define SIRFSOC_TIMER_MATCH_4 0x0018 +#define SIRFSOC_TIMER_MATCH_5 0x001C +#define SIRFSOC_TIMER_STATUS 0x0020 +#define SIRFSOC_TIMER_INT_EN 0x0024 +#define SIRFSOC_TIMER_WATCHDOG_EN 0x0028 +#define SIRFSOC_TIMER_DIV 0x002C +#define SIRFSOC_TIMER_LATCH 0x0030 +#define SIRFSOC_TIMER_LATCHED_LO 0x0034 +#define SIRFSOC_TIMER_LATCHED_HI 0x0038 + +#define SIRFSOC_TIMER_WDT_INDEX 5 + +#define SIRFSOC_TIMER_LATCH_BIT BIT(0) + +static void __iomem *sirfsoc_timer_base; +static void __init sirfsoc_of_timer_map(void); + +/* timer0 interrupt handler */ +static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *ce = dev_id; + + WARN_ON(!(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_STATUS) & BIT(0))); + + /* clear timer0 interrupt */ + writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS); + + ce->event_handler(ce); + + return IRQ_HANDLED; +} + +/* read 64-bit timer counter */ +static cycle_t sirfsoc_timer_read(struct clocksource *cs) +{ + u64 cycles; + + /* latch the 64-bit timer counter */ + writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); + cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_HI); + cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO); + + return cycles; +} + +static int sirfsoc_timer_set_next_event(unsigned long delta, + struct clock_event_device *ce) +{ + unsigned long now, next; + + writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); + now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO); + do { + next = now + delta; + writel_relaxed(next, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0); + writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH); + now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO); + } while ((next - now) > delta); + + return 0; +} + +static void sirfsoc_timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *ce) +{ + u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + WARN_ON(1); + break; + case CLOCK_EVT_MODE_ONESHOT: + writel_relaxed(val | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); + break; + case CLOCK_EVT_MODE_SHUTDOWN: + writel_relaxed(val & ~BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_RESUME: + break; + } +} + +static struct clock_event_device sirfsoc_clockevent = { + .name = "sirfsoc_clockevent", + .rating = 200, + .features = CLOCK_EVT_FEAT_ONESHOT, + .set_mode = sirfsoc_timer_set_mode, + .set_next_event = sirfsoc_timer_set_next_event, +}; + +static struct clocksource sirfsoc_clocksource = { + .name = "sirfsoc_clocksource", + .rating = 200, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .read = sirfsoc_timer_read, +}; + +static struct irqaction sirfsoc_timer_irq = { + .name = "sirfsoc_timer0", + .flags = IRQF_TIMER, + .irq = 0, + .handler = sirfsoc_timer_interrupt, + .dev_id = &sirfsoc_clockevent, +}; + +/* Overwrite weak default sched_clock with more precise one */ +unsigned long long notrace sched_clock(void) +{ + static int is_mapped = 0; + + /* + * sched_clock is called earlier than .init of sys_timer + * if we map timer memory in .init of sys_timer, system + * will panic due to illegal memory access + */ + if(!is_mapped) { + sirfsoc_of_timer_map(); + is_mapped = 1; + } + + return sirfsoc_timer_read(NULL) * (NSEC_PER_SEC / CLOCK_TICK_RATE); +} + +static void __init sirfsoc_clockevent_init(void) +{ + clockevents_calc_mult_shift(&sirfsoc_clockevent, CLOCK_TICK_RATE, 60); + + sirfsoc_clockevent.max_delta_ns = + clockevent_delta2ns(-2, &sirfsoc_clockevent); + sirfsoc_clockevent.min_delta_ns = + clockevent_delta2ns(2, &sirfsoc_clockevent); + + sirfsoc_clockevent.cpumask = cpumask_of(0); + clockevents_register_device(&sirfsoc_clockevent); +} + +/* initialize the kernel jiffy timer source */ +static void __init sirfsoc_timer_init(void) +{ + unsigned long rate; + + /* timer's input clock is io clock */ + struct clk *clk = clk_get_sys("io", NULL); + + BUG_ON(IS_ERR(clk)); + + rate = clk_get_rate(clk); + + BUG_ON(rate < CLOCK_TICK_RATE); + BUG_ON(rate % CLOCK_TICK_RATE); + + writel_relaxed(rate / CLOCK_TICK_RATE / 2 - 1, sirfsoc_timer_base + SIRFSOC_TIMER_DIV); + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO); + writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI); + writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS); + + BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE)); + + BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq)); + + sirfsoc_clockevent_init(); +} + +static struct of_device_id timer_ids[] = { + { .compatible = "sirf,prima2-tick" }, +}; + +static void __init sirfsoc_of_timer_map(void) +{ + struct device_node *np; + const unsigned int *intspec; + + np = of_find_matching_node(NULL, timer_ids); + if (!np) + panic("unable to find compatible timer node in dtb\n"); + sirfsoc_timer_base = of_iomap(np, 0); + if (!sirfsoc_timer_base) + panic("unable to map timer cpu registers\n"); + + /* Get the interrupts property */ + intspec = of_get_property(np, "interrupts", NULL); + BUG_ON(!intspec); + sirfsoc_timer_irq.irq = be32_to_cpup(intspec); + + of_node_put(np); +} + +struct sys_timer sirfsoc_timer = { + .init = sirfsoc_timer_init, +}; diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 0074b8d..edf0681 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -821,7 +821,7 @@ config CACHE_L2X0 depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || \ REALVIEW_EB_A9MP || SOC_IMX35 || SOC_IMX31 || MACH_REALVIEW_PBX || \ ARCH_NOMADIK || ARCH_OMAP4 || ARCH_EXYNOS4 || ARCH_TEGRA || \ - ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || ARCH_SHMOBILE + ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || ARCH_SHMOBILE || ARCH_PRIMA2 default y select OUTER_CACHE select OUTER_CACHE_SYNC