Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [GIT PULL 5/7] ARM: create a cros-ec-keyboard DT fragment
From: Thierry Reding @ 2014-07-18 14:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405694740-4090-1-git-send-email-thierry.reding@gmail.com>

The following changes since commit 7171511eaec5bf23fb06078f59784a3a0626b38f:

  Linux 3.16-rc1 (2014-06-15 17:45:28 -1000)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git tags/tegra-for-3.17-dt-cros-ec-kbd

for you to fetch changes up to 1a395e3b4f2e9038964c9eec392ed5300a4b5b83:

  ARM: dts: Use the cros-ec-keyboard fragment in exynos5250-snow (2014-06-16 12:11:32 -0600)

----------------------------------------------------------------
ARM: create a cros-ec-keyboard DT fragment

This branch contains a series from Doug Anderson that creates a DT
include file to share some common DT content between Tegra and Exynos
boards that use cros-ec. I'll be pulling this into Tegra's for-3.17/dt
branch, and I assume the Samsung maintainers will do something similar.

----------------------------------------------------------------
Doug Anderson (3):
      ARM: dts: Create a cros-ec-keyboard fragment
      ARM: tegra: Use the cros-ec-keyboard fragment in venice2
      ARM: dts: Use the cros-ec-keyboard fragment in exynos5250-snow

 arch/arm/boot/dts/cros-ec-keyboard.dtsi | 105 ++++++++++++++++++++++++++++++++
 arch/arm/boot/dts/exynos5250-snow.dts   |  93 +---------------------------
 arch/arm/boot/dts/tegra124-venice2.dts  |  96 +----------------------------
 3 files changed, 111 insertions(+), 183 deletions(-)
 create mode 100644 arch/arm/boot/dts/cros-ec-keyboard.dtsi

^ permalink raw reply

* [GIT PULL 6/7] ARM: tegra: device tree changes for 3.17
From: Thierry Reding @ 2014-07-18 14:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405694740-4090-1-git-send-email-thierry.reding@gmail.com>

The following changes since commit 69c018268b3bbebbd0d9013a1b72831a8ae9e790:

  Merge branch 'for-3.17/xusb-padctl' into for-3.17/dt (2014-07-17 15:01:57 +0200)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git tags/tegra-for-3.17-dt

for you to fetch changes up to 2236927d9820199bb6f29f2a89b1783c4513d34f:

  ARM: tegra: roth: add display DT node (2014-07-17 15:02:14 +0200)

----------------------------------------------------------------
ARM: tegra: device tree changes for 3.17

- New board support:
  - Apalis T30
- HDA support for Tegra124 and Venice2
- Display on Medcom Wide and Roth
- GK20A support on Tegra124
- XUSB pad controller for Tegra124 and Jetson TK1
- Various cleanups

This pulls in the for-3.17/fuse-move, for-3.17/dt-cros-ec-kbd and
for-3.17/xusb-padctl branches to resolve dependencies.

Note that the Apalis T30 support has a runtime dependency on the
for-3.17/pcie-regulators branch, so they should preferably be applied
in that order. I didn't merge that branch into this because Apalis T30
support is new, therefore can't regress, and because the dependency
exists only at runtime.

----------------------------------------------------------------
Alban Bedel (2):
      ARM: tegra: tamonten: add the base board regulators
      ARM: tegra: tamonten: add the display to the Medcom Wide

Alexandre Courbot (4):
      ARM: tegra: roth: fix unsupported pinmux properties
      ARM: tegra: roth: enable input on mmc clock pins
      ARM: tegra: of: add GK20A device tree binding
      ARM: tegra: roth: add display DT node

Doug Anderson (1):
      ARM: tegra: Add the EC i2c tunnel to tegra124-venice2

Dylan Reid (2):
      ARM: tegra: Add Tegra124 HDA support
      ARM: tegra: venice2 - Enable HDA

Lucas Stach (1):
      ARM: tegra: jetson-tk1: mark eMMC as non-removable

Marcel Ziswiler (2):
      ARM: tegra: initial support for apalis t30
      ARM: tegra: Migrate Apalis T30 PCIe power supply scheme

Thierry Reding (3):
      ARM: tegra: add GK20A GPU to Tegra124 DT
      ARM: tegra: tegra124: Add XUSB pad controller
      ARM: tegra: jetson-tk1: Add XUSB pad controller

Tuomas Tynkkynen (1):
      ARM: tegra: Fix typoed ams,ext-control properties

 Documentation/devicetree/bindings/arm/tegra.txt    |   2 +
 .../devicetree/bindings/gpu/nvidia,gk20a.txt       |  43 ++
 arch/arm/boot/dts/Makefile                         |   1 +
 arch/arm/boot/dts/tegra114-roth.dts                |  32 +-
 arch/arm/boot/dts/tegra124-jetson-tk1.dts          |  33 +-
 arch/arm/boot/dts/tegra124-venice2.dts             |  36 +-
 arch/arm/boot/dts/tegra124.dtsi                    |  40 ++
 arch/arm/boot/dts/tegra20-medcom-wide.dts          |  61 +-
 arch/arm/boot/dts/tegra20-plutux.dts               |  41 ++
 arch/arm/boot/dts/tegra20-tamonten.dtsi            |  10 +-
 arch/arm/boot/dts/tegra20-tec.dts                  |  41 ++
 arch/arm/boot/dts/tegra30-apalis-eval.dts          | 260 ++++++++
 arch/arm/boot/dts/tegra30-apalis.dtsi              | 678 +++++++++++++++++++++
 13 files changed, 1252 insertions(+), 26 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/gpu/nvidia,gk20a.txt
 create mode 100644 arch/arm/boot/dts/tegra30-apalis-eval.dts
 create mode 100644 arch/arm/boot/dts/tegra30-apalis.dtsi

^ permalink raw reply

* [GIT PULL 7/7] ARM: tegra: defconfig updates for 3.17
From: Thierry Reding @ 2014-07-18 14:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405694740-4090-1-git-send-email-thierry.reding@gmail.com>

The following changes since commit 7171511eaec5bf23fb06078f59784a3a0626b38f:

  Linux 3.16-rc1 (2014-06-15 17:45:28 -1000)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git tags/tegra-for-3.17-defconfig

for you to fetch changes up to dff15d4c2b1a4f3992a670b445e2131a400aef76:

  ARM: tegra: enable igb, stmpe, i2c chardev, lm95245, pwm leds (2014-06-16 12:55:49 -0600)

----------------------------------------------------------------
ARM: tegra: defconfig updates for 3.17

This set of patches update the tegra_defconfig by first regenerating on
top of v3.16-rc1 to prune all non-existent symbols or symbols which are
now selected by default.

----------------------------------------------------------------
Marcel Ziswiler (1):
      ARM: tegra: enable igb, stmpe, i2c chardev, lm95245, pwm leds

Stephen Warren (1):
      ARM: tegra: rebuild tegra_defconfig

 arch/arm/configs/tegra_defconfig | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

^ permalink raw reply

* [GIT PULL 5/7] ARM: create a cros-ec-keyboard DT fragment
From: Thierry Reding @ 2014-07-18 14:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405694740-4090-5-git-send-email-thierry.reding@gmail.com>

On Fri, Jul 18, 2014 at 04:45:38PM +0200, Thierry Reding wrote:
> The following changes since commit 7171511eaec5bf23fb06078f59784a3a0626b38f:
> 
>   Linux 3.16-rc1 (2014-06-15 17:45:28 -1000)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git tags/tegra-for-3.17-dt-cros-ec-kbd
> 
> for you to fetch changes up to 1a395e3b4f2e9038964c9eec392ed5300a4b5b83:
> 
>   ARM: dts: Use the cros-ec-keyboard fragment in exynos5250-snow (2014-06-16 12:11:32 -0600)
> 
> ----------------------------------------------------------------
> ARM: create a cros-ec-keyboard DT fragment
> 
> This branch contains a series from Doug Anderson that creates a DT
> include file to share some common DT content between Tegra and Exynos
> boards that use cros-ec. I'll be pulling this into Tegra's for-3.17/dt
> branch, and I assume the Samsung maintainers will do something similar.
> 
> ----------------------------------------------------------------
> Doug Anderson (3):
>       ARM: dts: Create a cros-ec-keyboard fragment
>       ARM: tegra: Use the cros-ec-keyboard fragment in venice2
>       ARM: dts: Use the cros-ec-keyboard fragment in exynos5250-snow
> 
>  arch/arm/boot/dts/cros-ec-keyboard.dtsi | 105 ++++++++++++++++++++++++++++++++
>  arch/arm/boot/dts/exynos5250-snow.dts   |  93 +---------------------------
>  arch/arm/boot/dts/tegra124-venice2.dts  |  96 +----------------------------
>  3 files changed, 111 insertions(+), 183 deletions(-)
>  create mode 100644 arch/arm/boot/dts/cros-ec-keyboard.dtsi

Note that Olof already mentioned that he had pulled this, but he also
said that he hadn't pulled it into anything that feeds into linux-next
so I thought I'd better send it again to make sure it's not forgotten.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140718/6dc736ea/attachment.sig>

^ permalink raw reply

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
From: Boris BREZILLON @ 2014-07-18 14:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140715103136.GA6616@ulmo>

Hi Thierry,

Oops, I missed this reply.

On Tue, 15 Jul 2014 12:31:37 +0200
Thierry Reding <thierry.reding@gmail.com> wrote:

> On Tue, Jul 15, 2014 at 12:06:19PM +0200, Boris BREZILLON wrote:
> > On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding <thierry.reding@gmail.com> wrote:
> > > On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> [...]
> > > > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > [...]
> > > > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> > > > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
> > > 
> > > I think it's better to refer to these using relative filenames. When the
> > > device tree bindings are moved out of the kernel tree, they may no
> > > longer use the same hierarchy.
> > 
> > Sure.
> > By relative path you mean ../../mfd/atmel-hlcdc.txt or just
> > mfd/atmel-hlcdc.txt ?
> 
> I think the former is more explicit.

Okay.

> 
> > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > +   The first cell is a phandle to a DRM panel device
> > > > +   The second cell encodes the RGB mode, which can take the following values:
> > > > +   * 0: RGB444
> > > > +   * 1: RGB565
> > > > +   * 2: RGB666
> > > > +   * 3: RGB888
> > > 
> > > These are properties of the panel and should be obtained from the panel
> > > directly rather than an additional cell in this specifier.
> > 
> > Okay.
> > What's the preferred way of doing this ?
> > What about defining an rgb-mode property in the panel node.
> 
> There's .bpc in struct drm_display_info, I suspect that it could be used
> for this. Alternatively, maybe we could extend the list of color formats
> that go into drm_display_info.color_formats? RGB444 is already covered.

I don't think this color_formats field is intended to represent data
stream format going through the bus.
Moreover, AFAIU, RGB444 in this definition represent RGB 4:4:4 (chroma
subsampling rate) and not 12 bits signals (4 bits for each color).

Anyway I'll propose a patch series adding a new field to
drm_display_info to encode the mediabus format (as discussed with
Laurent and you).

> 
> Also, like Laurent said, this shouldn't go into the device tree, since
> it's already implied by the panel's compatible value, so we'd be
> duplicating information.

Again, this is not necessarily true (depending on your board design).
One can decide to connect an RGB888 panel on an RGB666 bus and connect
the missing pins to ground.

> 
> > BTW, have you received this series [1] adding support for the LCD panel
> > I'm testing this driver with.
> > 
> > [1] https://lkml.org/lkml/2014/6/5/612
> 
> I don't think I've seen it in my inbox, let me check my archives.
> 
> > > > +   The third cell encodes specific flags describing LCD signals configuration
> > > > +   (see Atmel's datasheet for a full description of these fields):
> > > > +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> > > > +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> > > > +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> > > > +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> > > > +   * bit 4: DISPPOL: Display Signal Polarity
> > > > +   * bit 7: DISPDLY: LCD Controller Display Power Signal Synchronization
> > > > +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup Configuration
> > > > +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold Configuration
> > > > +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
> > > 
> > > Similarly for most of these: HSPOL and VSPOL seem to correspond to the
> > > DRM_MODE_FLAG_{{P,N},{H,V}}SYNC flags in struct drm_display_mode. And
> > > VSPDLYS as well as VSPDLYE sound like they may be vsync_start and
> > > vsync_end of the same structure.
> > 
> > I agree with HSPOL and VSPOL.
> > 
> > > 
> > > As for the others, maybe if you could explain what exactly they are we
> > > may be able to find a better fit.
> > 
> > Atmel datasheets include several timing diagrams [2] (chapter "32.6.17
> > Output Timing Generation" page 603), and I think you will get more
> > informations from these diagrams than if I try to explain what I
> > understood ;-).
> 
> These look like knobs to tune the signal in a very fine-grained manner.
> To be honest, maybe the best way to solve this would be by omitting them
> for now and choose some default that's likely to work on most devices.
> Does the panel that you use specify how it expects HSYNC to be timed vs.
> VSYNC?


No it doesn't, and I agree that we should leave these specific timing
tweaks unimplemented until we really need them.

Regards,

Boris


-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply

* [PATCH v13 6/8] arm: add pmd_[dirty|mkclean] for THP
From: Steve Capper @ 2014-07-18 14:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405666386-15095-7-git-send-email-minchan@kernel.org>

On Fri, Jul 18, 2014 at 03:53:04PM +0900, Minchan Kim wrote:
> MADV_FREE needs pmd_dirty and pmd_mkclean for detecting recent
> overwrite of the contents since MADV_FREE syscall is called for
> THP page.
> 
> This patch adds pmd_dirty and pmd_mkclean for THP page MADV_FREE
> support.
> 
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: Steve Capper <steve.capper@linaro.org>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: linux-arm-kernel at lists.infradead.org
> Signed-off-by: Minchan Kim <minchan@kernel.org>

This patch looks good to me:
Acked-by: Steve Capper <steve.capper@linaro.org>

There is another patch that introduces a helper function to test for
pmd bits, please see below.

> ---
>  arch/arm/include/asm/pgtable-3level.h | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h
> index 85c60adc8b60..830f84f2d277 100644
> --- a/arch/arm/include/asm/pgtable-3level.h
> +++ b/arch/arm/include/asm/pgtable-3level.h
> @@ -220,6 +220,8 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
>  #define pmd_trans_splitting(pmd) (pmd_val(pmd) & PMD_SECT_SPLITTING)
>  #endif
>  
> +#define pmd_dirty(pmd)		(pmd_val(pmd) & PMD_SECT_DIRTY)

Russell,
Should this be folded into my {pte|pmd}_isset patch?
http://lists.infradead.org/pipermail/linux-arm-kernel/2014-July/268979.html

Cheers,
-- 
Steve


> +
>  #define PMD_BIT_FUNC(fn,op) \
>  static inline pmd_t pmd_##fn(pmd_t pmd) { pmd_val(pmd) op; return pmd; }
>  
> @@ -228,6 +230,7 @@ PMD_BIT_FUNC(mkold,	&= ~PMD_SECT_AF);
>  PMD_BIT_FUNC(mksplitting, |= PMD_SECT_SPLITTING);
>  PMD_BIT_FUNC(mkwrite,   &= ~PMD_SECT_RDONLY);
>  PMD_BIT_FUNC(mkdirty,   |= PMD_SECT_DIRTY);
> +PMD_BIT_FUNC(mkclean,   &= ~PMD_SECT_DIRTY);
>  PMD_BIT_FUNC(mkyoung,   |= PMD_SECT_AF);
>  
>  #define pmd_mkhuge(pmd)		(__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
> -- 
> 2.0.0
> 

^ permalink raw reply

* [PATCH v13 7/8] arm64: add pmd_[dirty|mkclean] for THP
From: Steve Capper @ 2014-07-18 14:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405666386-15095-8-git-send-email-minchan@kernel.org>

On Fri, Jul 18, 2014 at 03:53:05PM +0900, Minchan Kim wrote:
> MADV_FREE needs pmd_dirty and pmd_mkclean for detecting recent
> overwrite of the contents since MADV_FREE syscall is called for
> THP page.
> 
> This patch adds pmd_dirty and pmd_mkclean for THP page MADV_FREE
> support.
> 
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: Steve Capper <steve.capper@linaro.org>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: linux-arm-kernel at lists.infradead.org
> Acked-by: Catalin Marinas <catalin.marinas@arm.com>
> Signed-off-by: Minchan Kim <minchan@kernel.org>

Acked-by: Steve Capper <steve.capper@linaro.org> 

^ permalink raw reply

* [PATCH] arm64: make CONFIG_ZONE_DMA user settable
From: Catalin Marinas @ 2014-07-18 14:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CALrVBkvWejppnR2+Qwc__LT2d=0bQtEwF325kMSmQ=7BeUBrdw@mail.gmail.com>

On Fri, Jul 18, 2014 at 12:58:31PM +0100, Anup Patel wrote:
> On 18 July 2014 16:37, Catalin Marinas <catalin.marinas@arm.com> wrote:
> > From 133656f8378dbb838ad5f12ea29aa9303d7ca922 Mon Sep 17 00:00:00 2001
> > From: Catalin Marinas <catalin.marinas@arm.com>
> > Date: Fri, 18 Jul 2014 11:54:37 +0100
> > Subject: [PATCH] arm64: Create non-empty ZONE_DMA when DRAM starts above 4GB
> >
> > ZONE_DMA is created to allow 32-bit only devices to access memory in the
> > absence of an IOMMU. On systems where the memory starts above 4GB, it is
> > expected that some devices have a DMA offset hardwired to be able to
> > access the bottom of the memory. Linux currently supports DT bindings
> > for the DMA offsets but they are not (easily) available early during
> > boot.
> >
> > This patch tries to guess a DMA offset and assumes that ZONE_DMA
> > corresponds to the 32-bit mask above the start of DRAM.
> >
> > Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
> > Cc: Mark Salter <msalter@redhat.com>
[...]
> Linux-3.16-rcX is broken on X-Gene Mustang because
> on X-Gene Mustang the DRAM starts at 0x4000000000.
> 
> I have tested your patch and the original patch from
> this thread. Both patches fixes the issue for X-Gene
> Mustang and Linux-3.16-rc5 happily boots on X-Gene.
> 
> Can you to send your patch as Linux-3.16-rcX fix?

It needs some more testing and if there is time, yes, otherwise it will
just be cc stable.

> For your patch, you can have:
> Tested-by: Anup Patel <anup.patel@linaro.org>

Thanks.

-- 
Catalin

^ permalink raw reply

* [PATCH v5 1/8] of: Add NVIDIA Tegra SATA controller binding
From: Thierry Reding @ 2014-07-18 15:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <53C8F6E6.6020901@redhat.com>

On Fri, Jul 18, 2014 at 12:28:54PM +0200, Hans de Goede wrote:
> Hi,
> 
> On 07/18/2014 09:16 AM, Mikko Perttunen wrote:
> > So here's v5: this time, as suggested, I handle the sata clock myself and let ahci_platform handle it too, leading it to be prepared+enabled twice. This works fine, and allows us to remove the DT ordering requirement.
> > 
> > I also have in the works a patchset that adds the name-based ahci_platform_get_resources function, but that is not quite ready yet, even if it is quite far along. Also, I am going on vacation and returning on 28.7., so if this v5 is acceptable maybe it could be merged for 3.17 and I could work on the new get_resources scheme after I get back from vacation?
> 
> Yes that works for me v3 of all the patches with no newer version +
> v5 of patch 1 and 7 are pretty clean and can go into 3.17 from my pov,
> Tejun can you pick these up for 3.17 please?

Tejun,

I think the following patches can go through your tree without causing
breakage through unresolved dependencies:

	[PATCH v5 1/8] of: Add NVIDIA Tegra SATA controller binding
	[PATCH v3 6/8] ata: ahci_platform: Increase AHCI_MAX_CLKS to 4
	[PATCH v5 7/8] ata: Add support for the Tegra124 SATA controller

Peter, you should probably pick up

	[PATCH v3 4/8] clk: tegra: Enable hardware control of SATA PLL
	[PATCH v3 5/8] clk: tegra: Add SATA clocks to Tegra124 initialization table

and send them off to Mike for 3.17 if there's still time.

Stephen, the rest of the patches would probably best go through the
Tegra tree so that we can handle the dependencies there. I've already
sent out pull requests for 3.17 today, but maybe Arnd and Olof can be
convinced to take one more.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140718/d894eea2/attachment.sig>

^ permalink raw reply

* [PATCH] arm64: Fix barriers used for page table modifications
From: Catalin Marinas @ 2014-07-18 15:08 UTC (permalink / raw)
  To: linux-arm-kernel

The architecture specification states that both DSB and ISB are required
between page table modifications and subsequent memory accesses using the
corresponding virtual address. When TLB invalidation takes place, the
tlb_flush_* functions already have the necessary barriers. However, there are
other functions like create_mapping() for which this is not the case.

The patch adds the DSB+ISB instructions in the set_pte() function for
valid kernel mappings. The invalid pte case is handled by tlb_flush_*
and the user mappings in general have a corresponding update_mmu_cache()
call containing a DSB. Even when update_mmu_cache() isn't called, the
kernel can still cope with an unlikely spurious page fault by
re-executing the instruction.

In addition, the set_pmd, set_pud() functions gain an ISB for
architecture compliance when block mappings are created.

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Reported-by: Leif Lindholm <leif.lindholm@linaro.org>
Acked-by: Steve Capper <steve.capper@linaro.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
---

I'll do a similar patch for arch/arm but since there is no failure
currently, it's not urgent. For arm64 it fails with fixmap mappings on
some platforms during boot (Leif knows the details).

 arch/arm64/include/asm/cacheflush.h | 11 +----------
 arch/arm64/include/asm/pgtable.h    | 13 +++++++++++++
 arch/arm64/include/asm/tlbflush.h   |  5 +++--
 3 files changed, 17 insertions(+), 12 deletions(-)

diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
index a5176cf32dad..f2defe1c380c 100644
--- a/arch/arm64/include/asm/cacheflush.h
+++ b/arch/arm64/include/asm/cacheflush.h
@@ -138,19 +138,10 @@ static inline void __flush_icache_all(void)
 #define flush_icache_page(vma,page)	do { } while (0)
 
 /*
- * flush_cache_vmap() is used when creating mappings (eg, via vmap,
- * vmalloc, ioremap etc) in kernel space for pages.  On non-VIPT
- * caches, since the direct-mappings of these pages may contain cached
- * data, we need to do a full cache flush to ensure that writebacks
- * don't corrupt data placed into these pages via the new mappings.
+ * Not required on AArch64 (PIPT or VIPT non-aliasing D-cache).
  */
 static inline void flush_cache_vmap(unsigned long start, unsigned long end)
 {
-	/*
-	 * set_pte_at() called from vmap_pte_range() does not
-	 * have a DSB after cleaning the cache line.
-	 */
-	dsb(ish);
 }
 
 static inline void flush_cache_vunmap(unsigned long start, unsigned long end)
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index d7455fa83bc7..627b5080a4cc 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -138,6 +138,8 @@ extern struct page *empty_zero_page;
 
 #define pte_valid_user(pte) \
 	((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER))
+#define pte_valid_not_user(pte) \
+	((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
 
 static inline pte_t pte_wrprotect(pte_t pte)
 {
@@ -184,6 +186,15 @@ static inline pte_t pte_mkspecial(pte_t pte)
 static inline void set_pte(pte_t *ptep, pte_t pte)
 {
 	*ptep = pte;
+
+	/*
+	 * Only if the new pte is valid and kernel, otherwise TLB maintenance
+	 * or update_mmu_cache() have the necessary barriers.
+	 */
+	if (pte_valid_not_user(pte)) {
+		dsb(ishst);
+		isb();
+	}
 }
 
 extern void __sync_icache_dcache(pte_t pteval, unsigned long addr);
@@ -303,6 +314,7 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
 {
 	*pmdp = pmd;
 	dsb(ishst);
+	isb();
 }
 
 static inline void pmd_clear(pmd_t *pmdp)
@@ -333,6 +345,7 @@ static inline void set_pud(pud_t *pudp, pud_t pud)
 {
 	*pudp = pud;
 	dsb(ishst);
+	isb();
 }
 
 static inline void pud_clear(pud_t *pudp)
diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index b9349c4513ea..3796ea6bb734 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -122,6 +122,7 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
 	for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12))
 		asm("tlbi vaae1is, %0" : : "r"(addr));
 	dsb(ish);
+	isb();
 }
 
 /*
@@ -131,8 +132,8 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
 				    unsigned long addr, pte_t *ptep)
 {
 	/*
-	 * set_pte() does not have a DSB, so make sure that the page table
-	 * write is visible.
+	 * set_pte() does not have a DSB for user mappings, so make sure that
+	 * the page table write is visible.
 	 */
 	dsb(ishst);
 }

^ permalink raw reply related

* [PATCH v6 0/5] Add Keystone PCIe controller driver
From: Murali Karicheri @ 2014-07-18 15:14 UTC (permalink / raw)
  To: linux-arm-kernel

This patch series add PCIe controller driver for keystone SoCs. This is
based on v4 of the series posted to the mailing list. Keystone PCI controller
is based on version 3.65 of the DW hardware. This driver uses the DW core
functions to implement the PCI controller driver for keystone.

Testing:
=======

Testing of the driver is done on TI's K2HK EVM inserted to a Elma blu!eco
MicroTCA chassis AMC slot with JumpGen SEM-200 AMC SATA Storage and Dual
Ethernet Card Express inserted on another AMC slot. The e1000e driver available
on intel's website is patched to the kernel source tree and build. e1000e.ko
is dynamically loaded and executed ping and iperf tests to test the
functionality.

Thanks to all of you who have contributed by reviewing and offering valuable
comments. If you want me to add your "Reviewed-by", please let me know so that
I can add it to the commit log and re-send. Patch 1-3 has Acks from maintainers
and I believe this can be merged to upstream branch. Patch 4 is waiting for
Ack from DT maintainer. Please provide the same at the earliest.

Thanks

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>

CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Pratyush Anand <pratyush.anand@st.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org>

Changelog:

v6
 - Added Ack from Maintainer for patch 3. Patch 1-3 now have the
   Acks from maintainer and can be merged to upstream branch.
   Patch 4 is waiting ack from DT maintainer.
v5
 - Rebased to upstream kernel v3.16-rc5
 - Reworked Patch 3/6 and 4/6 into a single patch based on
   maintainer comment to use a API callback model to support
   the v3.65 h/w.
v4
 - Addressed comments against 5/5.
 - Added a patch 6/6 for Maintainer information
 - Added couple of Acked-By:
 - Rebased to latest Linux 3.16-rc4
v3
 - DW application register handling code is now part of
   Keystone PCI driver. RFC had this code part of Keystone
   PCI driver, then V1 moved this to a separate file to
   re-use on other platforms that uses this version of the
   DW h/w. Then based on comments against v2, this is moved
   back to Keystone driver.
 - Keystone SerDes phy driver is removed from this series so that
   this can be merged independent of that patch
 - added msi_set_irq()/clear_irq() API's to support Keystone

V2
 - Split the designware pcie enhancement patch to multiple
   patches based on functionality added
 - Remove the quirk code and add a patch to fix mps/mrss
   tuning for ARM. Use kernel command line parameter
   pci=pcie_bus_perf to work with Keystone PCI Controller.
   Following patch addressed this.
     [PATCH v1] ARM: pci: add call to pcie_bus_configure_settings()
 - Add documentation for device tree bindings
 - Add separate interrupt controller nodes for MSI and Legacy
   IRQs and use irq map for legacy IRQ
 - Use compatibility to identify v3.65 version of the DW hardware
   and use it to customize the designware common code.
 - Use reg property for configuration space instead of range
 - Other minor updates based on code inspection. 

V1
 - Add an interrupt controller node for Legacy irq chip and use
   interrupt map/map-mask property to map legacy IRQs A/B/C/D
 - Add a Phy driver to replace the original serdes driver
 - Move common application register handling code to a separate
   file to allow re-use across other platforms that use older
   DW PCIe h/w
 - PCI quirk for maximum read request size. Check and override only
   if the maximum is higher than what controller can handle.
 - Converted to a module platform driver.

Murali Karicheri (5):
  PCI: designware: add rd[wr]_other_conf API
  PCI: designware: refactor MSI code to work with v3.65 dw hardware
  PCI: designware: enhance dw_pcie_host_init() to support v3.65 DW
    hardware
  PCI: add PCI controller for keystone PCIe h/w
  PCI: keystone: Update maintainer information

 .../devicetree/bindings/pci/pci-keystone.txt       |   71 +++
 MAINTAINERS                                        |    7 +
 drivers/pci/host/Kconfig                           |    5 +
 drivers/pci/host/Makefile                          |    1 +
 drivers/pci/host/pci-keystone-dw.c                 |  516 ++++++++++++++++++++
 drivers/pci/host/pci-keystone.c                    |  385 +++++++++++++++
 drivers/pci/host/pci-keystone.h                    |   59 +++
 drivers/pci/host/pcie-designware.c                 |  116 +++--
 drivers/pci/host/pcie-designware.h                 |    9 +
 9 files changed, 1133 insertions(+), 36 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pci/pci-keystone.txt
 create mode 100644 drivers/pci/host/pci-keystone-dw.c
 create mode 100644 drivers/pci/host/pci-keystone.c
 create mode 100644 drivers/pci/host/pci-keystone.h

-- 
1.7.9.5

^ permalink raw reply

* [PATCH v6 1/5] PCI: designware: add rd[wr]_other_conf API
From: Murali Karicheri @ 2014-07-18 15:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405696469-7172-1-git-send-email-m-karicheri2@ti.com>

v3.65 version of the designware h/w, requires application space
registers to be configured to access the remote EP config space.
To support this, add rd[wr]_other_conf API in the pcie_host_opts

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Reviewed-by: Pratyush Anand <pratyush.anand@st.com>
Acked-by: Mohit Kumar <mohit.kumar@st.com>
Acked-by: Jingoo Han <jg1.han@samsung.com>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>

CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org> 

---
 drivers/pci/host/pcie-designware.c |   12 ++++++++++--
 drivers/pci/host/pcie-designware.h |    4 ++++
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 1eaf4df..d8f3af7 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -656,7 +656,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
 	}
 
 	if (bus->number != pp->root_bus_nr)
-		ret = dw_pcie_rd_other_conf(pp, bus, devfn,
+		if (pp->ops->rd_other_conf)
+			ret = pp->ops->rd_other_conf(pp, bus, devfn,
+						where, size, val);
+		else
+			ret = dw_pcie_rd_other_conf(pp, bus, devfn,
 						where, size, val);
 	else
 		ret = dw_pcie_rd_own_conf(pp, where, size, val);
@@ -679,7 +683,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
 	if (bus->number != pp->root_bus_nr)
-		ret = dw_pcie_wr_other_conf(pp, bus, devfn,
+		if (pp->ops->wr_other_conf)
+			ret = pp->ops->wr_other_conf(pp, bus, devfn,
+						where, size, val);
+		else
+			ret = dw_pcie_wr_other_conf(pp, bus, devfn,
 						where, size, val);
 	else
 		ret = dw_pcie_wr_own_conf(pp, where, size, val);
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index 77f592f..8121901 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -61,6 +61,10 @@ struct pcie_host_ops {
 			u32 val, void __iomem *dbi_base);
 	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
 	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
+	int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
+			unsigned int devfn, int where, int size, u32 *val);
+	int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
+			unsigned int devfn, int where, int size, u32 val);
 	int (*link_up)(struct pcie_port *pp);
 	void (*host_init)(struct pcie_port *pp);
 };
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v6 2/5] PCI: designware: refactor MSI code to work with v3.65 dw hardware
From: Murali Karicheri @ 2014-07-18 15:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405696469-7172-1-git-send-email-m-karicheri2@ti.com>

Keystone PCI controller is based on v3.65 version of the DW
PCI h/w that implements MSI controller registers in application
space compared to the newer version. This requires updates to
the DW core API to support the PCI controller driver based on
this old DW hardware. Add msi_irq_set()/clear() API functions to
allow Set/Clear MSI IRQ enable bit in the application register.
Also the old h/w uses MSI_IRQ register in application register
space to raise MSI IRQ to the RC from EP. Current code uses the
standard mechanism as per PCI spec. So add another API get_msi_data()
to get the address of this register so that common code can be
re-used on old h/w.

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Reviewed-by: Pratyush Anand <pratyush.anand@st.com>
Acked-by: Mohit Kumar <mohit.kumar@st.com>
Acked-by: Jingoo Han <jg1.han@samsung.com>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>

CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org>
---
 drivers/pci/host/pcie-designware.c |   50 ++++++++++++++++++++++++++----------
 drivers/pci/host/pcie-designware.h |    3 +++
 2 files changed, 39 insertions(+), 14 deletions(-)

diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index d8f3af7..905941c 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -217,27 +217,47 @@ static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0)
 	return 0;
 }
 
+static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
+{
+	unsigned int res, bit, val;
+
+	res = (irq / 32) * 12;
+	bit = irq % 32;
+	dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+	val &= ~(1 << bit);
+	dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+}
+
 static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
 			    unsigned int nvec, unsigned int pos)
 {
-	unsigned int i, res, bit, val;
+	unsigned int i;
 
 	for (i = 0; i < nvec; i++) {
 		irq_set_msi_desc_off(irq_base, i, NULL);
 		clear_bit(pos + i, pp->msi_irq_in_use);
 		/* Disable corresponding interrupt on MSI controller */
-		res = ((pos + i) / 32) * 12;
-		bit = (pos + i) % 32;
-		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
-		val &= ~(1 << bit);
-		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+		if (pp->ops->msi_clear_irq)
+			pp->ops->msi_clear_irq(pp, pos + i);
+		else
+			dw_pcie_msi_clear_irq(pp, pos + i);
 	}
 }
 
+static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
+{
+	unsigned int res, bit, val;
+
+	res = (irq / 32) * 12;
+	bit = irq % 32;
+	dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+	val |= 1 << bit;
+	dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+}
+
 static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
 {
-	int res, bit, irq, pos0, pos1, i;
-	u32 val;
+	int irq, pos0, pos1, i;
 	struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata);
 
 	if (!pp) {
@@ -281,11 +301,10 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
 		}
 		set_bit(pos0 + i, pp->msi_irq_in_use);
 		/*Enable corresponding interrupt in MSI interrupt controller */
-		res = ((pos0 + i) / 32) * 12;
-		bit = (pos0 + i) % 32;
-		dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
-		val |= 1 << bit;
-		dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+		if (pp->ops->msi_set_irq)
+			pp->ops->msi_set_irq(pp, pos0 + i);
+		else
+			dw_pcie_msi_set_irq(pp, pos0 + i);
 	}
 
 	*pos = pos0;
@@ -353,7 +372,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
 	 */
 	desc->msi_attrib.multiple = msgvec;
 
-	msg.address_lo = virt_to_phys((void *)pp->msi_data);
+	if (pp->ops->get_msi_data)
+		msg.address_lo = pp->ops->get_msi_data(pp);
+	else
+		msg.address_lo = virt_to_phys((void *)pp->msi_data);
 	msg.address_hi = 0x0;
 	msg.data = pos;
 	write_msi_msg(irq, &msg);
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index 8121901..387f69e 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -67,6 +67,9 @@ struct pcie_host_ops {
 			unsigned int devfn, int where, int size, u32 val);
 	int (*link_up)(struct pcie_port *pp);
 	void (*host_init)(struct pcie_port *pp);
+	void (*msi_set_irq)(struct pcie_port *pp, int irq);
+	void (*msi_clear_irq)(struct pcie_port *pp, int irq);
+	u32 (*get_msi_data)(struct pcie_port *pp);
 };
 
 int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v6 3/5] PCI: designware: enhance dw_pcie_host_init() to support v3.65 DW hardware
From: Murali Karicheri @ 2014-07-18 15:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405696469-7172-1-git-send-email-m-karicheri2@ti.com>

keystone PCI controller is based on v3.65 designware hardware. This
version differs from newer versions of the hardware in few functional
areas discussed below that makes it necessary to change dw_pcie_host_init()
to support v3.65 based PCI controller.

 1. No support for ATU port. So any ATU specific resource handling code
    is to be bypassed for v3.65 h/w.
 2. MSI controller uses Application space to implement MSI and 32 MSI
    interrupts are multiplexed over 8 IRQs to the host. Hence the code
    to process MSI IRQ needs to be different. This patch allows platform
    driver to provide its own irq_domain_ops ptr to irq_domain_add_linear()
    through an API callback from the designware core driver.
 3. MSI interrupt generation requires EP to write to the RC's application
    register. So enhance the driver to allow setup of inbound access to
    MSI irq register as a post scan bus API callback.

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Reviewed-by: Pratyush Anand <pratyush.anand@st.com>
Acked-by: Mohit KUMAR <mohit.kumar@st.com>

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org>

---
 drivers/pci/host/pcie-designware.c |   54 +++++++++++++++++++++++-------------
 drivers/pci/host/pcie-designware.h |    2 ++
 2 files changed, 36 insertions(+), 20 deletions(-)

diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 905941c..35bb4af 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -420,8 +420,8 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
 	struct device_node *np = pp->dev->of_node;
 	struct of_pci_range range;
 	struct of_pci_range_parser parser;
+	int i, ret;
 	u32 val;
-	int i;
 
 	if (of_pci_range_parser_init(&parser, np)) {
 		dev_err(pp->dev, "missing ranges property\n");
@@ -467,21 +467,26 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
 		}
 	}
 
-	pp->cfg0_base = pp->cfg.start;
-	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
 	pp->mem_base = pp->mem.start;
 
-	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
-					pp->config.cfg0_size);
 	if (!pp->va_cfg0_base) {
-		dev_err(pp->dev, "error with ioremap in function\n");
-		return -ENOMEM;
+		pp->cfg0_base = pp->cfg.start;
+		pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
+						pp->config.cfg0_size);
+		if (!pp->va_cfg0_base) {
+			dev_err(pp->dev, "error with ioremap in function\n");
+			return -ENOMEM;
+		}
 	}
-	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
-					pp->config.cfg1_size);
+
 	if (!pp->va_cfg1_base) {
-		dev_err(pp->dev, "error with ioremap\n");
-		return -ENOMEM;
+		pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
+		pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
+						pp->config.cfg1_size);
+		if (!pp->va_cfg1_base) {
+			dev_err(pp->dev, "error with ioremap\n");
+			return -ENOMEM;
+		}
 	}
 
 	if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
@@ -490,16 +495,22 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
 	}
 
 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
-		pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
-					MAX_MSI_IRQS, &msi_domain_ops,
-					&dw_pcie_msi_chip);
-		if (!pp->irq_domain) {
-			dev_err(pp->dev, "irq domain init failed\n");
-			return -ENXIO;
-		}
+		if (!pp->ops->msi_host_init) {
+			pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
+						MAX_MSI_IRQS, &msi_domain_ops,
+						&dw_pcie_msi_chip);
+			if (!pp->irq_domain) {
+				dev_err(pp->dev, "irq domain init failed\n");
+				return -ENXIO;
+			}
 
-		for (i = 0; i < MAX_MSI_IRQS; i++)
-			irq_create_mapping(pp->irq_domain, i);
+			for (i = 0; i < MAX_MSI_IRQS; i++)
+				irq_create_mapping(pp->irq_domain, i);
+		} else {
+			ret = pp->ops->msi_host_init(pp, &dw_pcie_msi_chip);
+			if (ret < 0)
+				return ret;
+		}
 	}
 
 	if (pp->ops->host_init)
@@ -759,6 +770,9 @@ static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
 		BUG();
 	}
 
+	if (bus && pp->ops->scan_bus)
+		pp->ops->scan_bus(pp);
+
 	return bus;
 }
 
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index 387f69e..080c649 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -70,6 +70,8 @@ struct pcie_host_ops {
 	void (*msi_set_irq)(struct pcie_port *pp, int irq);
 	void (*msi_clear_irq)(struct pcie_port *pp, int irq);
 	u32 (*get_msi_data)(struct pcie_port *pp);
+	void (*scan_bus)(struct pcie_port *pp);
+	int (*msi_host_init)(struct pcie_port *pp, struct msi_chip *chip);
 };
 
 int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v6 4/5] PCI: add PCI controller for keystone PCIe h/w
From: Murali Karicheri @ 2014-07-18 15:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405696469-7172-1-git-send-email-m-karicheri2@ti.com>

keystone PCIe controller is based on v3.65 version of the
designware h/w. Main differences are
	1. No ATU support
	2. Legacy and MSI irq functions are implemented in
	   application register space
	3. MSI interrupts are multiplexed over 8 IRQ lines to the Host
	   side.
All of the Application register space handing code are organized into
pci-keystone-dw.c and the functions are called from pci-keystone.c
to implement PCI controller driver. Also add necessary DT documentation
for the driver.

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>

CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Pratyush Anand <pratyush.anand@st.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org>
---
 .../devicetree/bindings/pci/pci-keystone.txt       |   71 +++
 drivers/pci/host/Kconfig                           |    5 +
 drivers/pci/host/Makefile                          |    1 +
 drivers/pci/host/pci-keystone-dw.c                 |  516 ++++++++++++++++++++
 drivers/pci/host/pci-keystone.c                    |  385 +++++++++++++++
 drivers/pci/host/pci-keystone.h                    |   59 +++
 6 files changed, 1037 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/pci-keystone.txt
 create mode 100644 drivers/pci/host/pci-keystone-dw.c
 create mode 100644 drivers/pci/host/pci-keystone.c
 create mode 100644 drivers/pci/host/pci-keystone.h

diff --git a/Documentation/devicetree/bindings/pci/pci-keystone.txt b/Documentation/devicetree/bindings/pci/pci-keystone.txt
new file mode 100644
index 0000000..9c96164
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/pci-keystone.txt
@@ -0,0 +1,71 @@
+TI Keystone PCIe interface
+
+Keystone PCI host Controller is based on Designware PCI h/w version 3.65.
+It shares common functions with PCIE Designware core driver and inherit
+common properties defined in
+Documentation/devicetree/bindings/pci/designware-pci.txt
+
+Please refer to Documentation/devicetree/bindings/pci/designware-pci.txt
+for the details of designware DT bindings. Additional properties are
+described here as well propeties that are not applicable.
+
+Required Properties:-
+
+compatibility: "ti,keystone-pcie"
+reg:	index 1 is the base address and length of DW application registers.
+	index 2 is the base address and length of PCI mode configuration
+	register.
+	index 3 is the base address and length of PCI device ID register.
+
+pcie_msi_intc : Interrupt controller device node for MSI irq chip
+	interrupt-cells: should be set to 1
+	interrupt-parent: Parent interrupt controller phandle
+	interrupts: GIC interrupt lines connected to PCI MSI interrupt lines
+
+ Example:
+	pcie_msi_intc: msi-interrupt-controller {
+			interrupt-controller;
+			#interrupt-cells = <1>;
+			interrupt-parent = <&gic>;
+			interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 37 IRQ_TYPE_EDGE_RISING>;
+	};
+
+pcie_intc: Interrupt controller device node for Legacy irq chip
+	interrupt-cells: should be set to 1
+	interrupt-parent: Parent interrupt controller phandle
+	interrupts: GIC interrupt lines connected to PCI Legacy interrupt lines
+
+ Example:
+	pcie_intc: legacy-interrupt-controller {
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>,
+			<GIC_SPI 27 IRQ_TYPE_EDGE_RISING>,
+			<GIC_SPI 28 IRQ_TYPE_EDGE_RISING>,
+			<GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
+	};
+
+Optional properties:-
+	phys: phandle to Generic Keystone SerDes phy for PCI
+	phy-names: name of the Generic Keystine SerDes phy for PCI
+	  - If boot loader already does PCI link establishment, then phys and
+	    phy-names shouldn't be present.
+	ti,enable-linktrain - Enable Link training.
+	  - If boot loader already does PCI link establishment, then this
+	    shouldn't be present.
+
+Designware DT Properties not applicable for Keystone PCI
+
+1. pcie_bus clock-names not used. Instead, a phandle to phys is used.
+
+Note for PCI driver usage
+=========================
+Driver requires pci=pcie_bus_perf in the bootargs for proper functioning.
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 21df477..f8bc475 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -46,4 +46,9 @@ config PCI_HOST_GENERIC
 	  Say Y here if you want to support a simple generic PCI host
 	  controller, such as the one emulated by kvmtool.
 
+config PCI_KEYSTONE
+	bool "TI Keystone PCIe controller"
+	depends on ARCH_KEYSTONE
+	select PCIE_DW
+	select PCIEPORTBUS
 endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 611ba4b..d1b6ce1 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
 obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
 obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o
 obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o
+obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o
diff --git a/drivers/pci/host/pci-keystone-dw.c b/drivers/pci/host/pci-keystone-dw.c
new file mode 100644
index 0000000..b75582c
--- /dev/null
+++ b/drivers/pci/host/pci-keystone-dw.c
@@ -0,0 +1,516 @@
+/*
+ * Designware application register space functions for Keystone PCI controller
+ *
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ *		http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@ti.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_pci.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+#include "pcie-designware.h"
+#include "pci-keystone.h"
+
+/* Application register defines */
+#define LTSSM_EN_VAL		        1
+#define LTSSM_STATE_MASK		0x1f
+#define LTSSM_STATE_L0			0x11
+#define DBI_CS2_EN_VAL			0x20
+#define OB_XLAT_EN_VAL		        2
+
+/* Application registers */
+#define CMD_STATUS			0x004
+#define CFG_SETUP			0x008
+#define OB_SIZE				0x030
+#define CFG_PCIM_WIN_SZ_IDX		3
+#define CFG_PCIM_WIN_CNT		32
+#define SPACE0_REMOTE_CFG_OFFSET	0x1000
+#define OB_OFFSET_INDEX(n)		(0x200 + (8 * n))
+#define OB_OFFSET_HI(n)			(0x204 + (8 * n))
+
+/* IRQ register defines */
+#define IRQ_EOI				0x050
+#define IRQ_STATUS			0x184
+#define IRQ_ENABLE_SET			0x188
+#define IRQ_ENABLE_CLR			0x18c
+
+#define MSI_IRQ				0x054
+#define MSI0_IRQ_STATUS			0x104
+#define MSI0_IRQ_ENABLE_SET		0x108
+#define MSI0_IRQ_ENABLE_CLR		0x10c
+#define IRQ_STATUS			0x184
+#define MSI_IRQ_OFFSET			4
+
+/* Config space registers */
+#define DEBUG0				0x728
+
+#define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
+
+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
+{
+	return sys->private_data;
+}
+
+static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
+					u32 *bit_pos)
+{
+	*reg_offset = offset % 8;
+	*bit_pos = offset >> 3;
+}
+
+u32 ks_dw_pcie_get_msi_data(struct pcie_port *pp)
+{
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+
+	return ks_pcie->app.start + MSI_IRQ;
+}
+
+void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie , int offset)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	u32 pending, vector;
+	int src, virq;
+
+	pending = readl(ks_pcie->va_app_base + MSI0_IRQ_STATUS + (offset << 4));
+	/*
+	 * MSI0, Status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit
+	 * shows 1, 9, 17, 25 and so forth
+	 */
+	for (src = 0; src < 4; src++) {
+		if (BIT(src) & pending) {
+			vector = offset + (src << 3);
+			virq = irq_linear_revmap(pp->irq_domain, vector);
+			dev_dbg(pp->dev,
+				"irq: bit %d, vector %d, virq %d\n",
+				 src, vector, virq);
+			generic_handle_irq(virq);
+		}
+	}
+}
+
+static void ks_dw_pcie_msi_irq_ack(struct irq_data *d)
+{
+	u32 offset, reg_offset, bit_pos;
+	struct keystone_pcie *ks_pcie;
+	unsigned int irq = d->irq;
+	struct msi_desc *msi;
+	struct pcie_port *pp;
+
+	msi = irq_get_msi_desc(irq);
+	pp = sys_to_pcie(msi->dev->bus->sysdata);
+	ks_pcie = to_keystone_pcie(pp);
+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
+	update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
+
+	writel(BIT(bit_pos),
+		ks_pcie->va_app_base + MSI0_IRQ_STATUS + (reg_offset << 4));
+	writel(reg_offset + MSI_IRQ_OFFSET, ks_pcie->va_app_base + IRQ_EOI);
+}
+
+void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
+{
+	u32 reg_offset, bit_pos;
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+
+	update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
+	writel(BIT(bit_pos),
+		ks_pcie->va_app_base + MSI0_IRQ_ENABLE_SET + (reg_offset << 4));
+}
+
+void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
+{
+	u32 reg_offset, bit_pos;
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+
+	update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
+	writel(BIT(bit_pos),
+		ks_pcie->va_app_base + MSI0_IRQ_ENABLE_CLR + (reg_offset << 4));
+}
+
+static void ks_dw_pcie_msi_irq_mask(struct irq_data *d)
+{
+	struct keystone_pcie *ks_pcie;
+	unsigned int irq = d->irq;
+	struct msi_desc *msi;
+	struct pcie_port *pp;
+	u32 offset;
+
+	msi = irq_get_msi_desc(irq);
+	pp = sys_to_pcie(msi->dev->bus->sysdata);
+	ks_pcie = to_keystone_pcie(pp);
+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
+
+	/* mask the end point if PVM implemented */
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		if (msi->msi_attrib.maskbit)
+			mask_msi_irq(d);
+	}
+
+	ks_dw_pcie_msi_clear_irq(pp, offset);
+}
+
+static void ks_dw_pcie_msi_irq_unmask(struct irq_data *d)
+{
+	struct keystone_pcie *ks_pcie;
+	unsigned int irq = d->irq;
+	struct msi_desc *msi;
+	struct pcie_port *pp;
+	u32 offset;
+
+	msi = irq_get_msi_desc(irq);
+	pp = sys_to_pcie(msi->dev->bus->sysdata);
+	ks_pcie = to_keystone_pcie(pp);
+	offset = irq - irq_linear_revmap(pp->irq_domain, 0);
+
+	/* mask the end point if PVM implemented */
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		if (msi->msi_attrib.maskbit)
+			unmask_msi_irq(d);
+	}
+
+	ks_dw_pcie_msi_set_irq(pp, offset);
+}
+
+static struct irq_chip ks_dw_pcie_msi_irq_chip = {
+	.name = "Keystone-PCIe-MSI-IRQ",
+	.irq_ack = ks_dw_pcie_msi_irq_ack,
+	.irq_mask = ks_dw_pcie_msi_irq_mask,
+	.irq_unmask = ks_dw_pcie_msi_irq_unmask,
+};
+
+static int ks_dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
+			irq_hw_number_t hwirq)
+{
+	irq_set_chip_and_handler(irq, &ks_dw_pcie_msi_irq_chip,
+				 handle_level_irq);
+	irq_set_chip_data(irq, domain->host_data);
+	set_irq_flags(irq, IRQF_VALID);
+
+	return 0;
+}
+
+const struct irq_domain_ops ks_dw_pcie_msi_domain_ops = {
+	.map = ks_dw_pcie_msi_map,
+};
+
+int ks_dw_pcie_msi_host_init(struct pcie_port *pp,
+					struct msi_chip *chip)
+{
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+	int i;
+
+	pp->irq_domain = irq_domain_add_linear(ks_pcie->msi_intc_np,
+					MAX_MSI_IRQS,
+					&ks_dw_pcie_msi_domain_ops,
+					chip);
+	if (!pp->irq_domain) {
+		dev_err(pp->dev, "irq domain init failed\n");
+		return -ENXIO;
+	}
+
+	for (i = 0; i < MAX_MSI_IRQS; i++)
+		irq_create_mapping(pp->irq_domain, i);
+
+	return 0;
+}
+
+void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie)
+{
+	int i;
+
+	for (i = 0; i < MAX_LEGACY_IRQS; i++)
+		writel(0x1, ks_pcie->va_app_base + IRQ_ENABLE_SET + (i << 4));
+}
+
+void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	u32 pending;
+	int virq;
+
+	pending = readl(ks_pcie->va_app_base + IRQ_STATUS + (offset << 4));
+
+	if (BIT(0) & pending) {
+		virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset);
+		dev_dbg(pp->dev,
+			": irq: irq_offset %d, virq %d\n", offset, virq);
+		generic_handle_irq(virq);
+	}
+
+	/* EOI the INTx interrupt */
+	writel(offset, ks_pcie->va_app_base + IRQ_EOI);
+}
+
+static void ks_dw_pcie_ack_legacy_irq(struct irq_data *d)
+{
+}
+
+static void ks_dw_pcie_mask_legacy_irq(struct irq_data *d)
+{
+}
+
+static void ks_dw_pcie_unmask_legacy_irq(struct irq_data *d)
+{
+}
+
+static struct irq_chip ks_dw_pcie_legacy_irq_chip = {
+	.name = "Keystone-PCI-Legacy-IRQ",
+	.irq_ack = ks_dw_pcie_ack_legacy_irq,
+	.irq_mask = ks_dw_pcie_mask_legacy_irq,
+	.irq_unmask = ks_dw_pcie_unmask_legacy_irq,
+};
+
+static int ks_dw_pcie_init_legacy_irq_map(struct irq_domain *d,
+				unsigned int irq, irq_hw_number_t hw_irq)
+{
+	irq_set_chip_and_handler(irq, &ks_dw_pcie_legacy_irq_chip,
+				handle_level_irq);
+	irq_set_chip_data(irq, d->host_data);
+	set_irq_flags(irq, IRQF_VALID);
+
+	return 0;
+}
+
+static const struct irq_domain_ops ks_dw_pcie_legacy_irq_domian_ops = {
+	.map = ks_dw_pcie_init_legacy_irq_map,
+	.xlate = irq_domain_xlate_onetwocell,
+};
+
+/**
+ * ks_dw_pcie_set_dbi_mode() - Set DBI mode to access overlaid BAR mask registers
+ *
+ * Since modification of dbi_cs2 involves different clock domain, read the
+ * status back to ensure the transition is complete.
+ */
+static void ks_dw_pcie_set_dbi_mode(void __iomem *reg_virt)
+{
+	u32 val;
+
+	writel(DBI_CS2_EN_VAL | readl(reg_virt + CMD_STATUS),
+		     reg_virt + CMD_STATUS);
+
+	do {
+		val = readl(reg_virt + CMD_STATUS);
+	} while (!(val & DBI_CS2_EN_VAL));
+}
+
+/**
+ * ks_dw_pcie_clear_dbi_mode() - Disable DBI mode
+ *
+ * Since modification of dbi_cs2 involves different clock domain, read the
+ * status back to ensure the transition is complete.
+ */
+static void ks_dw_pcie_clear_dbi_mode(void __iomem *reg_virt)
+{
+	u32 val;
+
+	writel(~DBI_CS2_EN_VAL & readl(reg_virt + CMD_STATUS),
+		     reg_virt + CMD_STATUS);
+
+	do {
+		val = readl(reg_virt + CMD_STATUS);
+	} while (val & DBI_CS2_EN_VAL);
+}
+
+void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	u32 start = pp->mem.start, end = pp->mem.end;
+	int i, tr_size;
+
+	/* disable BARS for inbound access */
+	ks_dw_pcie_set_dbi_mode(ks_pcie->va_app_base);
+	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_0);
+	writel(0, pp->dbi_base + PCI_BASE_ADDRESS_1);
+	ks_dw_pcie_clear_dbi_mode(ks_pcie->va_app_base);
+
+	/* Set outbound translation size per window division */
+	writel(CFG_PCIM_WIN_SZ_IDX & 0x7, ks_pcie->va_app_base + OB_SIZE);
+
+	tr_size = (1 << (CFG_PCIM_WIN_SZ_IDX & 0x7)) * SZ_1M;
+
+	/* Using Direct 1:1 mapping of RC <-> PCI memory space */
+	for (i = 0; (i < CFG_PCIM_WIN_CNT) && (start < end); i++) {
+		writel(start | 1, ks_pcie->va_app_base + OB_OFFSET_INDEX(i));
+		writel(0, ks_pcie->va_app_base + OB_OFFSET_HI(i));
+		start += tr_size;
+	}
+
+	/* Enable OB translation */
+	writel(OB_XLAT_EN_VAL | readl(ks_pcie->va_app_base + CMD_STATUS),
+		ks_pcie->va_app_base + CMD_STATUS);
+}
+
+/**
+ * ks_pcie_cfg_setup() - Set up configuration space address for a
+ * device
+ *
+ * @ks_pcie: ptr to keystone_pcie structure
+ * @bus: Bus number the device is residing on
+ * @devfn: device, function number info
+ *
+ * Forms and returns the address of configuration space mapped in PCIESS
+ * address space 0. Also configures CFG_SETUP for remote configuration space
+ * access.
+ *
+ * The address space has two regions to access configuration - local and remote.
+ * We access local region for bus 0 (as RC is attached on bus 0) and remote
+ * region for others with TYPE 1 access when bus > 1. As for device on bus = 1,
+ * we will do TYPE 0 access as it will be on our secondary bus (logical).
+ * CFG_SETUP is needed only for remote configuration access.
+ */
+static void __iomem *ks_pcie_cfg_setup(struct keystone_pcie *ks_pcie, u8 bus,
+					unsigned int devfn)
+{
+	u8 device = PCI_SLOT(devfn), function = PCI_FUNC(devfn);
+	struct pcie_port *pp = &ks_pcie->pp;
+	u32 regval;
+
+	if (bus == 0)
+		return pp->dbi_base;
+
+	regval = (bus << 16) | (device << 8) | function;
+	/*
+	 * Since Bus#1 will be a virtual bus, we need to have TYPE0
+	 * access only.
+	 * TYPE 1
+	 */
+	if (bus != 1)
+		regval |= BIT(24);
+
+	writel(regval, ks_pcie->va_app_base + CFG_SETUP);
+	return pp->va_cfg0_base;
+}
+
+int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+		unsigned int devfn, int where, int size, u32 *val)
+{
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+	u8 bus_num = bus->number;
+	void __iomem *addr;
+	int ret;
+
+	addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn);
+	ret = dw_pcie_cfg_read(addr + (where & ~0x3), where, size, val);
+
+	return ret;
+}
+
+int ks_dw_pcie_wr_other_conf(struct pcie_port *pp,
+		struct pci_bus *bus, unsigned int devfn, int where,
+		int size, u32 val)
+{
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+	u8 bus_num = bus->number;
+	void __iomem *addr;
+
+	addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn);
+
+	return dw_pcie_cfg_write(addr + (where & ~0x3), where, size, val);
+}
+
+/**
+ * ks_dw_pcie_v3_65_scan_bus() - keystone scan_bus post initialization
+ *
+ * This sets BAR0 to enable inbound access for MSI_IRQ register
+ */
+void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp)
+{
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+
+	/* Configure and set up BAR0 */
+	ks_dw_pcie_set_dbi_mode(ks_pcie->va_app_base);
+
+	/* Enable BAR0 */
+	writel(1, pp->dbi_base + PCI_BASE_ADDRESS_0);
+	writel(SZ_4K - 1, pp->dbi_base + PCI_BASE_ADDRESS_0);
+
+	ks_dw_pcie_clear_dbi_mode(ks_pcie->va_app_base);
+
+	 /*
+	  * For BAR0, just setting bus address for inbound writes (MSI) should
+	  * be sufficient. Use physical address to avoid any conflicts.
+	  */
+	writel(ks_pcie->app.start, pp->dbi_base + PCI_BASE_ADDRESS_0);
+}
+
+/**
+ * ks_dw_pcie_link_up() - Check if link up
+ *
+ */
+int ks_dw_pcie_link_up(struct pcie_port *pp)
+{
+	u32 val = readl(pp->dbi_base + DEBUG0);
+
+	return (val & LTSSM_STATE_MASK) == LTSSM_STATE_L0;
+}
+
+void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie)
+{
+	u32 val;
+
+	/* Initiate Link Training.  */
+	val = readl(ks_pcie->va_app_base + CMD_STATUS);
+	writel(LTSSM_EN_VAL | val,  ks_pcie->va_app_base + CMD_STATUS);
+}
+
+/**
+ * ks_dw_pcie_host_init() - initialize host for v3_65 dw hardware
+ *
+ * It ioremap the register resources, initialize legacy irq domain
+ * and then call dw_pcie_v3_65_host_init() API to intialize the Keystone
+ * PCI host controller.
+ *
+ */
+int __init ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie,
+				struct device_node *msi_intc_np)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	struct platform_device *pdev = to_platform_device(pp->dev);
+	struct resource *res;
+
+	/* index 0 is the config reg. space address */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	pp->dbi_base = devm_ioremap_resource(pp->dev, res);
+	if (IS_ERR(pp->dbi_base))
+		return PTR_ERR(pp->dbi_base);
+
+	/*
+	 * we set these same and is used in pcie rd/wr_other_conf
+	 * functions
+	 */
+	pp->va_cfg0_base = pp->dbi_base + SPACE0_REMOTE_CFG_OFFSET;
+	pp->va_cfg1_base = pp->va_cfg0_base;
+
+	/* index 1 is the application reg. space address */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	ks_pcie->app = *res;
+	ks_pcie->va_app_base = devm_ioremap_resource(pp->dev, res);
+	if (IS_ERR(ks_pcie->va_app_base))
+		return PTR_ERR(ks_pcie->va_app_base);
+
+	/* create legacy irq domain */
+	ks_pcie->legacy_irq_domain =
+			irq_domain_add_linear(ks_pcie->legacy_intc_np,
+					MAX_LEGACY_IRQS,
+					&ks_dw_pcie_legacy_irq_domian_ops,
+					NULL);
+	if (!ks_pcie->legacy_irq_domain) {
+		dev_err(pp->dev, "Failed to add irq domain for legacy irqs\n");
+		return -EINVAL;
+	}
+
+	return dw_pcie_host_init(pp);
+}
diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c
new file mode 100644
index 0000000..341ced8
--- /dev/null
+++ b/drivers/pci/host/pci-keystone.c
@@ -0,0 +1,385 @@
+/*
+ * PCIe host controller driver for Texas Instruments Keystone SoCs
+ *
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ *		http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@ti.com>
+ * Implementation based on pci-exynos.c and pcie-designware.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/irqchip/chained_irq.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of_irq.h>
+#include <linux/of.h>
+#include <linux/of_pci.h>
+#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
+#include <linux/resource.h>
+#include <linux/signal.h>
+
+#include "pcie-designware.h"
+#include "pci-keystone.h"
+
+#define DRIVER_NAME	"keystone-pcie"
+
+/* driver specific constants */
+#define MAX_MSI_HOST_IRQS		8
+#define MAX_LEGACY_HOST_IRQS		4
+
+/* RC mode settings masks */
+#define PCIE_RC_MODE		BIT(2)
+#define PCIE_MODE_MASK		(BIT(1) | BIT(2))
+
+/* DEV_STAT_CTRL */
+#define PCIE_CAP_BASE		0x70
+
+#define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
+
+static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	int count = 200;
+
+	dw_pcie_setup_rc(pp);
+	if (ks_pcie->link_train)
+		ks_dw_pcie_initiate_link_train(ks_pcie);
+
+	/* check if the link is up or not */
+	while (!dw_pcie_link_up(pp)) {
+		usleep_range(100, 1000);
+		if (--count)
+			continue;
+		dev_err(pp->dev, "phy link never came up\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
+	u32 offset = irq - ks_pcie->msi_host_irqs[0];
+	struct pcie_port *pp = &ks_pcie->pp;
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+
+	dev_dbg(pp->dev, "ks_pci_msi_irq_handler, irq %d\n", irq);
+
+	/*
+	 * The chained irq handler installation would have replaced normal
+	 * interrupt driver handler so we need to take care of mask/unmask and
+	 * ack operation.
+	 */
+	chained_irq_enter(chip, desc);
+	ks_dw_pcie_handle_msi_irq(ks_pcie, offset);
+	chained_irq_exit(chip, desc);
+}
+
+/**
+ * ks_pcie_legacy_irq_handler() - Handle legacy interrupt
+ * @irq: IRQ line for legacy interrupts
+ * @desc: Pointer to irq descriptor
+ *
+ * Traverse through pending legacy interrupts and invoke handler for each. Also
+ * takes care of interrupt controller level mask/ack operation.
+ */
+static void ks_pcie_legacy_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
+	struct pcie_port *pp = &ks_pcie->pp;
+	u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0];
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+
+	dev_dbg(pp->dev, ": Handling legacy irq %d\n", irq);
+
+	/*
+	 * The chained irq handler installation would have replaced normal
+	 * interrupt driver handler so we need to take care of mask/unmask and
+	 * ack operation.
+	 */
+	chained_irq_enter(chip, desc);
+	ks_dw_pcie_handle_legacy_irq(ks_pcie, irq_offset);
+	chained_irq_exit(chip, desc);
+}
+
+static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie,
+					   char *controller, int *num_irqs)
+{
+	int temp, max_host_irqs, legacy = 1, *host_irqs, ret = -EINVAL;
+	struct device *dev = ks_pcie->pp.dev;
+	struct device_node *np_pcie = dev->of_node, **np_temp;
+
+	if (!strcmp(controller, "msi-interrupt-controller"))
+		legacy = 0;
+
+	if (legacy) {
+		np_temp = &ks_pcie->legacy_intc_np;
+		max_host_irqs = MAX_LEGACY_HOST_IRQS;
+		host_irqs = &ks_pcie->legacy_host_irqs[0];
+	} else {
+		np_temp = &ks_pcie->msi_intc_np;
+		max_host_irqs = MAX_MSI_HOST_IRQS;
+		host_irqs =  &ks_pcie->msi_host_irqs[0];
+	}
+
+	/* interrupt controller is in a child node */
+	*np_temp = of_find_node_by_name(np_pcie, controller);
+	if (!(*np_temp)) {
+		dev_err(dev, "Node for %s is absent\n", controller);
+		goto out;
+	}
+	temp = of_irq_count(*np_temp);
+	if (!temp)
+		goto out;
+	if (temp > max_host_irqs)
+		dev_warn(dev, "Too many %s interrupts defined %u\n",
+			(legacy ? "legacy" : "MSI"), temp);
+
+	/*
+	 * support upto max_host_irqs. In dt from index 0 to 3 (legacy) or 0 to
+	 * 7 (MSI)
+	 */
+	for (temp = 0; temp < max_host_irqs; temp++) {
+		host_irqs[temp] = irq_of_parse_and_map(*np_temp, temp);
+		if (host_irqs[temp] < 0)
+			break;
+	}
+	if (temp) {
+		*num_irqs = temp;
+		ret = 0;
+	}
+out:
+	return ret;
+}
+
+static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie)
+{
+	int i;
+
+	/* Legacy IRQ */
+	for (i = 0; i < ks_pcie->num_legacy_host_irqs; i++) {
+		irq_set_handler_data(ks_pcie->legacy_host_irqs[i], ks_pcie);
+		irq_set_chained_handler(ks_pcie->legacy_host_irqs[i],
+					ks_pcie_legacy_irq_handler);
+	}
+	ks_dw_pcie_enable_legacy_irqs(ks_pcie);
+
+	/* MSI IRQ */
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		for (i = 0; i < ks_pcie->num_msi_host_irqs; i++) {
+			irq_set_chained_handler(ks_pcie->msi_host_irqs[i],
+						ks_pcie_msi_irq_handler);
+			irq_set_handler_data(ks_pcie->msi_host_irqs[i],
+					     ks_pcie);
+		}
+	}
+}
+
+/*
+ * When a PCI device does not exist during config cycles, keystone host gets a
+ * bus error instead of returning 0xffffffff. This handler always returns 0
+ * for this kind of faults.
+ */
+static int keystone_pcie_fault(unsigned long addr, unsigned int fsr,
+				struct pt_regs *regs)
+{
+	unsigned long instr = *(unsigned long *) instruction_pointer(regs);
+
+	if ((instr & 0x0e100090) == 0x00100090) {
+		int reg = (instr >> 12) & 15;
+
+		regs->uregs[reg] = -1;
+		regs->ARM_pc += 4;
+	}
+
+	return 0;
+}
+
+static void __init ks_pcie_host_init(struct pcie_port *pp)
+{
+	u32 vendor_device_id, val;
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+
+	ks_pcie_establish_link(ks_pcie);
+	ks_dw_pcie_setup_rc_app_regs(ks_pcie);
+	ks_pcie_setup_interrupts(ks_pcie);
+	writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8),
+			pp->dbi_base + PCI_IO_BASE);
+
+	/* update the Vendor ID */
+	vendor_device_id = readl(ks_pcie->va_reg_pciid);
+	writew((vendor_device_id >> 16), pp->dbi_base + PCI_DEVICE_ID);
+
+	/* update the DEV_STAT_CTRL to publish right mrrs */
+	val = readl(pp->dbi_base + PCIE_CAP_BASE + PCI_EXP_DEVCTL);
+	val &= ~PCI_EXP_DEVCTL_READRQ;
+	/* set the mrrs to 256 bytes */
+	val |= BIT(12);
+	writel(val, pp->dbi_base + PCIE_CAP_BASE + PCI_EXP_DEVCTL);
+
+	/*
+	 * PCIe access errors that result into OCP errors are caught by ARM as
+	 * "External aborts"
+	 */
+	hook_fault_code(17, keystone_pcie_fault, SIGBUS, 0,
+			"Asynchronous external abort");
+}
+
+static struct pcie_host_ops keystone_pcie_host_ops = {
+	.rd_other_conf = ks_dw_pcie_rd_other_conf,
+	.wr_other_conf = ks_dw_pcie_wr_other_conf,
+	.link_up = ks_dw_pcie_link_up,
+	.host_init = ks_pcie_host_init,
+	.msi_set_irq = ks_dw_pcie_msi_set_irq,
+	.msi_clear_irq = ks_dw_pcie_msi_clear_irq,
+	.get_msi_data = ks_dw_pcie_get_msi_data,
+	.msi_host_init = ks_dw_pcie_msi_host_init,
+	.scan_bus = ks_dw_pcie_v3_65_scan_bus,
+};
+
+static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie,
+			 struct platform_device *pdev)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	int ret;
+
+	ret = ks_pcie_get_irq_controller_info(ks_pcie,
+					"legacy-interrupt-controller",
+					&ks_pcie->num_legacy_host_irqs);
+	if (ret)
+		return ret;
+
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		ret = ks_pcie_get_irq_controller_info(ks_pcie,
+						"msi-interrupt-controller",
+						&ks_pcie->num_msi_host_irqs);
+		if (ret)
+			return ret;
+	}
+
+	pp->root_bus_nr = -1;
+	pp->ops = &keystone_pcie_host_ops;
+	ret = ks_dw_pcie_host_init(ks_pcie, ks_pcie->msi_intc_np);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to initialize host\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+static const struct of_device_id ks_pcie_of_match[] = {
+	{
+		.type = "pci",
+		.compatible = "ti,keystone-pcie",
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ks_pcie_of_match);
+
+static int __exit ks_pcie_remove(struct platform_device *pdev)
+{
+	struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(ks_pcie->clk);
+
+	return 0;
+}
+
+static int __init ks_pcie_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	struct keystone_pcie *ks_pcie;
+	struct pcie_port *pp;
+	struct resource *res;
+	void __iomem *reg_p;
+	struct phy *phy;
+	int ret = 0;
+	u32 val;
+
+	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
+				GFP_KERNEL);
+	if (!ks_pcie) {
+		dev_err(dev, "no memory for keystone pcie\n");
+		return -ENOMEM;
+	}
+	pp = &ks_pcie->pp;
+
+	/* initialize SerDes Phy if present */
+	phy = devm_phy_get(dev, "pcie-phy");
+	if (!IS_ERR_OR_NULL(phy)) {
+		ret = phy_init(phy);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* index 2 is the devcfg register for RC mode settings */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	reg_p = devm_ioremap_resource(dev, res);
+	if (IS_ERR(reg_p))
+		return PTR_ERR(reg_p);
+
+	/* enable RC mode in devcfg */
+	val = readl(reg_p);
+	val &= ~PCIE_MODE_MASK;
+	val |= PCIE_RC_MODE;
+	writel(val, reg_p);
+
+	/* index 3 is to read PCI DEVICE_ID */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+	reg_p = devm_ioremap_resource(dev, res);
+	if (IS_ERR(reg_p))
+		return PTR_ERR(reg_p);
+	ks_pcie->va_reg_pciid = reg_p;
+
+	/* check if we need to enable link training */
+	ks_pcie->link_train =
+		(of_get_property(np, "ti,enable-linktrain", NULL) != NULL);
+
+	pp->dev = dev;
+	platform_set_drvdata(pdev, ks_pcie);
+	ks_pcie->clk = devm_clk_get(dev, "pcie");
+	if (IS_ERR(ks_pcie->clk)) {
+		dev_err(dev, "Failed to get pcie rc clock\n");
+		return PTR_ERR(ks_pcie->clk);
+	}
+	ret = clk_prepare_enable(ks_pcie->clk);
+	if (ret)
+		return ret;
+
+	ret = ks_add_pcie_port(ks_pcie, pdev);
+	if (ret < 0)
+		goto fail_clk;
+
+	return 0;
+fail_clk:
+	clk_disable_unprepare(ks_pcie->clk);
+
+	return ret;
+}
+
+static struct platform_driver ks_pcie_driver __refdata = {
+	.probe  = ks_pcie_probe,
+	.remove = __exit_p(ks_pcie_remove),
+	.driver = {
+		.name	= "keystone-pcie",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(ks_pcie_of_match),
+	},
+};
+
+module_platform_driver(ks_pcie_driver);
+
+MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
+MODULE_DESCRIPTION("Keystone PCIe host controller driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/host/pci-keystone.h b/drivers/pci/host/pci-keystone.h
new file mode 100644
index 0000000..0bedfc5
--- /dev/null
+++ b/drivers/pci/host/pci-keystone.h
@@ -0,0 +1,59 @@
+/*
+ * Keystone PCI Controller's common includes
+ *
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ *		http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@ti.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define MAX_LEGACY_IRQS			4
+#define MAX_MSI_HOST_IRQS		8
+#define MAX_LEGACY_HOST_IRQS		4
+
+struct keystone_pcie {
+	struct	clk		*clk;
+	int			link_train;
+	struct	pcie_port	pp;
+	void __iomem		*va_reg_pciid;
+
+	int			num_legacy_host_irqs;
+	int			legacy_host_irqs[MAX_LEGACY_HOST_IRQS];
+	struct			device_node *legacy_intc_np;
+
+	int			num_msi_host_irqs;
+	int			msi_host_irqs[MAX_MSI_HOST_IRQS];
+	struct			device_node *msi_intc_np;
+	struct irq_domain	*legacy_irq_domain;
+
+	/* Application register space */
+	void __iomem		*va_app_base;
+	struct resource		app;
+};
+
+/* Keystone DW specific MSI controller APIs/definitions */
+void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset);
+u32 ks_dw_pcie_get_msi_data(struct pcie_port *pp);
+
+/* Keystone specific PCI controller APIs */
+void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie);
+void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset);
+int  ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie,
+			struct device_node *msi_intc_np);
+int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+		unsigned int devfn, int where, int size, u32 val);
+int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+		unsigned int devfn, int where, int size, u32 *val);
+void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie);
+int ks_dw_pcie_link_up(struct pcie_port *pp);
+void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie);
+void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq);
+void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq);
+void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp);
+int ks_dw_pcie_msi_host_init(struct pcie_port *pp,
+		struct msi_chip *chip);
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v6 5/5] PCI: keystone: Update maintainer information
From: Murali Karicheri @ 2014-07-18 15:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1405696469-7172-1-git-send-email-m-karicheri2@ti.com>

Update the MAINTAINERS file for the keystone PCIe driver

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Pratyush Anand <pratyush.anand@st.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org>
---
 MAINTAINERS |    7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index e31c874..8158f82 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6807,6 +6807,13 @@ L:	linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 F:	drivers/pci/host/*imx6*
 
+PCI DRIVER FOR keystone
+M:	Murali Karicheri <m-karicheri2@ti.com>
+L:	linux-pci at vger.kernel.org
+L:	linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
+S:	Maintained
+F:	drivers/pci/host/*keystone*
+
 PCI DRIVER FOR MVEBU (Marvell Armada 370 and Armada XP SOC support)
 M:	Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
 M:	Jason Cooper <jason@lakedaemon.net>
-- 
1.7.9.5

^ permalink raw reply related

* [PATCHv6 2/4] iio: adc: exynos_adc: Control special clock of ADC to support Exynos3250 ADC
From: Chanwoo Choi @ 2014-07-18 15:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <6917971.QKItNU3coA@wuerfel>

On Fri, Jul 18, 2014 at 8:14 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Friday 18 July 2014 19:00:48 Chanwoo Choi wrote:
>> On 07/18/2014 06:47 PM, Arnd Bergmann wrote:
>> >
>> > Further, why is it called "sclk_adc" rather than just "sclk"?
>>
>> The sclk means 'special clock' in Exynos TRM. Exynos SoC has varisou sclk clocks.
>> 'sclk_adc' is only used for ADC IP.
>
> But that sounds like sclk_adc is the name of the global name
> of the clock signal coming out of the clock controller.
>
> I still think it would be best to name it 'sclk' as the input
> for the adc. It shouldn't rely on a particular name of the
> clock controller.

I think 'sclk' is too common name. 'sclk' don't include specific device name.
As I know, usual clock name includes the name of IP or includes the
specific meaning for each IP.

In my opinion, I think sclk_adc is better than 'sclk'.

Thanks,
Chanwoo Choi

^ permalink raw reply

* [PATCHv6 2/4] iio: adc: exynos_adc: Control special clock of ADC to support Exynos3250 ADC
From: Arnd Bergmann @ 2014-07-18 15:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAGTfZH1EHiTpo2Abua=+kDfNoOQx+ydPHU51=+qW8mgCL4Lwvg@mail.gmail.com>

On Saturday 19 July 2014 00:15:35 Chanwoo Choi wrote:
> On Fri, Jul 18, 2014 at 8:14 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> > On Friday 18 July 2014 19:00:48 Chanwoo Choi wrote:
> >> On 07/18/2014 06:47 PM, Arnd Bergmann wrote:
> >> >
> >> > Further, why is it called "sclk_adc" rather than just "sclk"?
> >>
> >> The sclk means 'special clock' in Exynos TRM. Exynos SoC has varisou sclk clocks.
> >> 'sclk_adc' is only used for ADC IP.
> >
> > But that sounds like sclk_adc is the name of the global name
> > of the clock signal coming out of the clock controller.
> >
> > I still think it would be best to name it 'sclk' as the input
> > for the adc. It shouldn't rely on a particular name of the
> > clock controller.
> 
> I think 'sclk' is too common name. 'sclk' don't include specific device name.
> As I know, usual clock name includes the name of IP or includes the
> specific meaning for each IP.

No, normally it does not include the name of the IP, that's my whole point.
Including the name of the IP is completely pointless because that is
implied by the fact that it's being used by that particular IP.

Ideally you would find the data sheet for the ADC IP block and figure
out what this clock is used for, then find the right name for that.
In a lot of cases, we are actually better off not naming the clocks
at all but simply enumerating them if nobody knows what they are good
for. In that case, you would simply have the first clock and the second
clock of the ADC part and enable them both.

	Arnd

^ permalink raw reply

* [PATCH 4/5] tty: serial: 8250 core: add runtime pm
From: Felipe Balbi @ 2014-07-18 15:31 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <53C8DC3E.3020701@linutronix.de>

On Fri, Jul 18, 2014 at 10:35:10AM +0200, Sebastian Andrzej Siewior wrote:
> On 07/17/2014 06:18 PM, Felipe Balbi wrote:
> 
> >> No, this is okay. If you look, it checks for "up->ier & 
> >> UART_IER_THRI". On the second invocation it will see that this
> >> bit is already set and therefore won't call get_sync() for the
> >> second time. That bit is removed in the _stop_tx() path.
> > 
> > oh, right. But that's actually unnecessary. Calling
> > pm_runtime_get() multiple times will just increment the usage
> > counter multiple times, which means you can call __stop_tx()
> > multiple times too and everything gets balanced, right ?
> 
> No. start_tx() will be called multiple times but only the first
> invocation invoke pm_runtime_get(). Now I noticed that I forgot to

right, but that's unnecessary. You can pm_runtime_get() every time
start_tx() is called. Just make sure to put everytime stop_tx() is
called too.

> remove pm_runtime_put_autosuspend() at the bottom of it. But you get
> the idea right?
> pm_get() on the while the UART_IER_THRI is not yet set. pm_put() once
> the fifo is completely empty.
> 
> >> Do you have other ideas? It doesn't look like this is exported at
> >> all. If we call _stop_tx() right away, then we have 64 bytes in
> >> the TX fifo in the worst case. They should be gone "soon" but the
> >> HW-flow control may delay it (in theory for a long time)).
> > 
> > this can be problematic, specially for OMAP which can go into OFF
> > while idle. Whatever is in the FIFO would get lost. It seems like
> > omap-serial solved this within transmit_chars().
> 
> No, it didn't.
> 
> > See how transmit_chars() is called from within IRQ handler with
> > clocks enabled then it conditionally calls serial_omap_stop_tx()
> > which will pm_runtime_get_sync() -> do_the_harlem_shake() -> 
> > pm_runtime_put_autosuspend(). That leaves one unbalanced 
> > pm_runtime_get() which is balanced when we're exitting the IRQ
> > handler.
> 
> omap-serial and the 8250 do the following on tx path:
> - start_tx()
>   -> sets UART_IER_THRI. This will generate an interrupt once the FIFO
>      is empty.
> - interrupt, notices the empty fifo, invokes serial8250_start_tx()/
>   transmit_chars().
>   Both have a while loop that fills the FIFO. This loop is left once
>   the tty-buffer is empty (uart_circ_empty() is true) or the FIFO full.
> 
> Lets say you filled 64 bytes into the FIFO and then left because your
> FIFO is full and tty-buffer is empty. That means you will invoke
> serial_omap_stop_tx() and remove UART_IER_THRI bit.
> This is okay because you are not interested in further FIFO empty
> interrupts because you don't have any TX-bytes to be sent. However,
> once you leave the transmit_chars() you leave serial_omap_irq() which
> does the last pm_put(). That means you have data in the TX FIFO that is
> about to be sent and the device is in auto-suspend.
> This is "fine" as long as the timeout is greater then the time required
> for the data be sent (plus assuming HW-float control does not stall it
> for too long) so nobody notices a thing.

the time is set to -1 by default. I guess this only works because nobody
has ever tested long transfers with slow baud rates :-p

> For that reason I added the hack / #if0 block in the 8250 driver. To
> ensure we do not disable the TX-FIFO-empty interrupt even if there is
> nothing to send. Instead we enter serial8250_tx_chars() once again with
> empty FIFO and empty tty-buffer and will invoke _stop_tx() which also
> finally does the pm_put().
> That is the plan. The problem I have is how to figure out that the
> device is using auto-suspend. If I don't then I would have to remove
> the #if0 block and that would mean for everybody an extra interrupt
> (which I wanted to avoid).

looks like the closest you have is:

if (pm_runtime_autosuspend_expiration(dev) > 0)
	foo();

Another possibility would be to implement the ->runtime_idle() callback
and only return 0 if fifo is empty, otherwise return -EAGAIN ? then, if
the autosuspend timer expires, ->runtime_idle gets called and you can do
the right thing depending on fifo empty or not.

Take a look at
drivers/usb/core/driver.c::usb_runtime_{idle,resume,suspend} for
examples. That seems to work pretty well.

> > This seems work fine and dandy without DMA, but for DMA work, I
> > think we need to make sure this IP stays powered until we get DMA
> > completion callback. But that's future, I guess.
> 
> Yes, probably. That means one get at dma start, one put at dma complete
> callback. And I assume we get that callbacks once the DMA transfer is
> complete, not when the FIFO is empty :) So lets leave it to the future
> for now?

k

-- 
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140718/6299a783/attachment-0001.sig>

^ permalink raw reply

* [PATCH 4/6] net/macb: add RX checksum offload feature
From: Eric Dumazet @ 2014-07-18 15:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <f29965fee23dc0de99b388373017efeffa1aac10.1405689937.git.cyrille.pitchen@atmel.com>

On Fri, 2014-07-18 at 16:21 +0200, Cyrille Pitchen wrote:
> Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
> ---
>  drivers/net/ethernet/cadence/macb.c | 29 ++++++++++++++++++++++++++++-
>  drivers/net/ethernet/cadence/macb.h |  2 ++
>  2 files changed, 30 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
> index 9bdcd1b..6acd6e2 100644
> --- a/drivers/net/ethernet/cadence/macb.c
> +++ b/drivers/net/ethernet/cadence/macb.c
> @@ -766,6 +766,8 @@ static int gem_rx(struct macb *bp, int budget)
>  
>  		skb->protocol = eth_type_trans(skb, bp->dev);
>  		skb_checksum_none_assert(skb);
> +		if (bp->dev->features & NETIF_F_RXCSUM)
> +			skb->ip_summed = CHECKSUM_UNNECESSARY;
>  


Really ?

If this is what you meant, this deserves a big and fat comment.

^ permalink raw reply

* [RESEND PATCH v3 06/11] drm: add DT bindings documentation for atmel-hlcdc-dc driver
From: Boris BREZILLON @ 2014-07-18 15:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140718165152.0a9fde09@bbrezillon>

On Fri, 18 Jul 2014 16:51:52 +0200
Boris BREZILLON <boris.brezillon@free-electrons.com> wrote:

> Hi Thierry,
> 
> Oops, I missed this reply.
> 
> On Tue, 15 Jul 2014 12:31:37 +0200
> Thierry Reding <thierry.reding@gmail.com> wrote:
> 
> > On Tue, Jul 15, 2014 at 12:06:19PM +0200, Boris BREZILLON wrote:
> > > On Mon, 14 Jul 2014 12:05:43 +0200 Thierry Reding <thierry.reding@gmail.com> wrote:
> > > > On Mon, Jul 07, 2014 at 06:42:59PM +0200, Boris BREZILLON wrote:
> > [...]
> > > > > diff --git a/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel-hlcdc-dc.txt
> > > > [...]
> > > > > +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
> > > > > +See Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt for more details.
> > > > 
> > > > I think it's better to refer to these using relative filenames. When the
> > > > device tree bindings are moved out of the kernel tree, they may no
> > > > longer use the same hierarchy.
> > > 
> > > Sure.
> > > By relative path you mean ../../mfd/atmel-hlcdc.txt or just
> > > mfd/atmel-hlcdc.txt ?
> > 
> > I think the former is more explicit.
> 
> Okay.
> 
> > 
> > > > > + - atmel,panel: Should contain a phandle with 2 parameters.
> > > > > +   The first cell is a phandle to a DRM panel device
> > > > > +   The second cell encodes the RGB mode, which can take the following values:
> > > > > +   * 0: RGB444
> > > > > +   * 1: RGB565
> > > > > +   * 2: RGB666
> > > > > +   * 3: RGB888
> > > > 
> > > > These are properties of the panel and should be obtained from the panel
> > > > directly rather than an additional cell in this specifier.
> > > 
> > > Okay.
> > > What's the preferred way of doing this ?
> > > What about defining an rgb-mode property in the panel node.
> > 
> > There's .bpc in struct drm_display_info, I suspect that it could be used
> > for this. Alternatively, maybe we could extend the list of color formats
> > that go into drm_display_info.color_formats? RGB444 is already covered.
> 

I forgot to ask about bpc meaning. If, as I think, it means "bits per
color" then it cannot be used to encode RGB565 where green color is
encoded on 6 bits and red and blue are encoded on 5 bits. 

> I don't think this color_formats field is intended to represent data
> stream format going through the bus.
> Moreover, AFAIU, RGB444 in this definition represent RGB 4:4:4 (chroma
> subsampling rate) and not 12 bits signals (4 bits for each color).
> 
> Anyway I'll propose a patch series adding a new field to
> drm_display_info to encode the mediabus format (as discussed with
> Laurent and you).
> 
> > 
> > Also, like Laurent said, this shouldn't go into the device tree, since
> > it's already implied by the panel's compatible value, so we'd be
> > duplicating information.
> 
> Again, this is not necessarily true (depending on your board design).
> One can decide to connect an RGB888 panel on an RGB666 bus and connect
> the missing pins to ground.
> 
> > 
> > > BTW, have you received this series [1] adding support for the LCD panel
> > > I'm testing this driver with.
> > > 
> > > [1] https://lkml.org/lkml/2014/6/5/612
> > 
> > I don't think I've seen it in my inbox, let me check my archives.
> > 
> > > > > +   The third cell encodes specific flags describing LCD signals configuration
> > > > > +   (see Atmel's datasheet for a full description of these fields):
> > > > > +   * bit 0: HSPOL: Horizontal Synchronization Pulse Polarity
> > > > > +   * bit 1: VSPOL: Vertical Synchronization Pulse Polarity
> > > > > +   * bit 2: VSPDLYS: Vertical Synchronization Pulse Start
> > > > > +   * bit 3: VSPDLYE: Vertical Synchronization Pulse End
> > > > > +   * bit 4: DISPPOL: Display Signal Polarity
> > > > > +   * bit 7: DISPDLY: LCD Controller Display Power Signal Synchronization
> > > > > +   * bit 12: VSPSU: LCD Controller Vertical synchronization Pulse Setup Configuration
> > > > > +   * bit 13: VSPHO: LCD Controller Vertical synchronization Pulse Hold Configuration
> > > > > +   * bit 16-20: GUARDTIME: LCD DISPLAY Guard Time
> > > > 
> > > > Similarly for most of these: HSPOL and VSPOL seem to correspond to the
> > > > DRM_MODE_FLAG_{{P,N},{H,V}}SYNC flags in struct drm_display_mode. And
> > > > VSPDLYS as well as VSPDLYE sound like they may be vsync_start and
> > > > vsync_end of the same structure.
> > > 
> > > I agree with HSPOL and VSPOL.
> > > 
> > > > 
> > > > As for the others, maybe if you could explain what exactly they are we
> > > > may be able to find a better fit.
> > > 
> > > Atmel datasheets include several timing diagrams [2] (chapter "32.6.17
> > > Output Timing Generation" page 603), and I think you will get more
> > > informations from these diagrams than if I try to explain what I
> > > understood ;-).
> > 
> > These look like knobs to tune the signal in a very fine-grained manner.
> > To be honest, maybe the best way to solve this would be by omitting them
> > for now and choose some default that's likely to work on most devices.
> > Does the panel that you use specify how it expects HSYNC to be timed vs.
> > VSYNC?
> 
> 
> No it doesn't, and I agree that we should leave these specific timing
> tweaks unimplemented until we really need them.
> 
> Regards,
> 
> Boris
> 
> 



-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply

* [PATCH v3 3/3] arm64: Use include/asm-generic/io.h
From: Catalin Marinas @ 2014-07-18 15:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140717122649.GA1006@ulmo>

On Thu, Jul 17, 2014 at 01:26:51PM +0100, Thierry Reding wrote:
> On Thu, Jul 17, 2014 at 01:04:41PM +0100, Catalin Marinas wrote:
> > On Wed, Jul 16, 2014 at 12:01:24PM +0100, Thierry Reding wrote:
> > > From: Thierry Reding <treding@nvidia.com>
> > > 
> > > Include the generic I/O header file so that duplicate implementations
> > > can be removed. This will also help to establish consistency across more
> > > architectures regarding which accessors they support.
> > > 
> > > Acked-by: Catalin Marinas <catalin.marinas@arm.com>
> > > Signed-off-by: Thierry Reding <treding@nvidia.com>
> > > ---
> > > Changes in v3:
> > > - add io{read,write}{16,32}be() to match what 32-bit ARM does
> > 
> > It looks fine. Thanks.
> 
> Great. Russell hasn't commented on this yet, anyone know how to get his
> attention?

Given he dependency on the first patch, they should either go in
together or first patch in 3.17 and the rest later (but I would prefer
that they all go in at the same time).

I don't mind how they are merged (the arm32 tree, arm-soc or arm64). If
Russell doesn't have an opinion, I can take the 1st and 3rd patches via
the arm64 tree.

-- 
Catalin

^ permalink raw reply

* [PATCHv4 5/5] arm64: cpuinfo: print info for all CPUs
From: Peter Maydell @ 2014-07-18 15:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140718135738.GA17328@leverpostej>

On 18 July 2014 14:57, Mark Rutland <mark.rutland@arm.com> wrote:
> Comments are added to guide userspace developers in the right direction
> (using the hwcaps provided in auxval). Hopefully where userspace
> applications parse /proc/cpuinfo rather than using the readily available
> hwcaps, they limit themselves to reading said first line.

Comments in the kernel sources aren't going to guide
anybody except kernel developers. I was expecting from
this commit message that you were going to emit actual
comments in /proc/cpuinfo...

-- PMM

^ permalink raw reply

* [PATCH 4/5] tty: serial: 8250 core: add runtime pm
From: Peter Hurley @ 2014-07-18 15:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140718153116.GN24914@saruman.home>

On 07/18/2014 11:31 AM, Felipe Balbi wrote:
> On Fri, Jul 18, 2014 at 10:35:10AM +0200, Sebastian Andrzej Siewior wrote:
>> >On 07/17/2014 06:18 PM, Felipe Balbi wrote:
>> >
>>>> > >>No, this is okay. If you look, it checks for "up->ier &
>>>> > >>UART_IER_THRI". On the second invocation it will see that this
>>>> > >>bit is already set and therefore won't call get_sync() for the
>>>> > >>second time. That bit is removed in the _stop_tx() path.
>>> > >
>>> > >oh, right. But that's actually unnecessary. Calling
>>> > >pm_runtime_get() multiple times will just increment the usage
>>> > >counter multiple times, which means you can call __stop_tx()
>>> > >multiple times too and everything gets balanced, right ?
>> >
>> >No. start_tx() will be called multiple times but only the first
>> >invocation invoke pm_runtime_get(). Now I noticed that I forgot to
> right, but that's unnecessary. You can pm_runtime_get() every time
> start_tx() is called. Just make sure to put everytime stop_tx() is
> called too.

The interface is asymmetric.

start_tx() may be invoked multiple times for which only 1 interrupt
will occur, and thus only invoke __stop_tx() once.

Regards,
Peter Hurley

^ permalink raw reply

* [PATCHv4 5/5] arm64: cpuinfo: print info for all CPUs
From: Mark Rutland @ 2014-07-18 15:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAFEAcA-jdVxgUY03j12HDWzKwtVaxsmL-AarD5QyNb1jmYEa2g@mail.gmail.com>

On Fri, Jul 18, 2014 at 04:52:37PM +0100, Peter Maydell wrote:
> On 18 July 2014 14:57, Mark Rutland <mark.rutland@arm.com> wrote:
> > Comments are added to guide userspace developers in the right direction
> > (using the hwcaps provided in auxval). Hopefully where userspace
> > applications parse /proc/cpuinfo rather than using the readily available
> > hwcaps, they limit themselves to reading said first line.
> 
> Comments in the kernel sources aren't going to guide
> anybody except kernel developers.

That's not entirely true, some people skim the kernel sources to figure
out how they're meant to use syscalls and such (though admitedly this
isn't all that common).

> I was expecting from this commit message that you were going to emit
> actual comments in /proc/cpuinfo...

I don't think that's a good idea, and I can only see that reading when I
squint quite hard. ;)

Thanks,
Mark

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox