Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Applied "spi: meson: Add GXBB Compatible string" to the spi tree
From: Mark Brown @ 2016-09-12 19:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473261223-15412-6-git-send-email-jbrunet@baylibre.com>

The patch

   spi: meson: Add GXBB Compatible string

has been applied to the spi tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 164c5cd5ffabfa7a060999f8184927017287c39b Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Thu, 8 Sep 2016 09:53:25 +0200
Subject: [PATCH] spi: meson: Add GXBB Compatible string

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Acked-by: Kevin Hilman <khilman@baylibre.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 Documentation/devicetree/bindings/spi/spi-meson.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/spi/spi-meson.txt b/Documentation/devicetree/bindings/spi/spi-meson.txt
index bb52a86f3365..dc6d0313324a 100644
--- a/Documentation/devicetree/bindings/spi/spi-meson.txt
+++ b/Documentation/devicetree/bindings/spi/spi-meson.txt
@@ -7,7 +7,7 @@ NOR memories, without DMA support and a 64-byte unified transmit /
 receive buffer.
 
 Required properties:
- - compatible: should be "amlogic,meson6-spifc"
+ - compatible: should be "amlogic,meson6-spifc" or "amlogic,meson-gxbb-spifc"
  - reg: physical base address and length of the controller registers
  - clocks: phandle of the input clock for the baud rate generator
  - #address-cells: should be 1
-- 
2.8.1

^ permalink raw reply related

* Applied "spi: meson: Add GXBB compatible" to the spi tree
From: Mark Brown @ 2016-09-12 19:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473261223-15412-5-git-send-email-jbrunet@baylibre.com>

The patch

   spi: meson: Add GXBB compatible

has been applied to the spi tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 2f58ea64bd8931bd7709732fe0a96e0bfb44a00b Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Thu, 8 Sep 2016 09:53:26 +0200
Subject: [PATCH] spi: meson: Add GXBB compatible

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Acked-by: Kevin Hilman <khilman@baylibre.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 drivers/spi/spi-meson-spifc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/spi/spi-meson-spifc.c b/drivers/spi/spi-meson-spifc.c
index 2465259f6241..616566e793c6 100644
--- a/drivers/spi/spi-meson-spifc.c
+++ b/drivers/spi/spi-meson-spifc.c
@@ -442,6 +442,7 @@ static const struct dev_pm_ops meson_spifc_pm_ops = {
 
 static const struct of_device_id meson_spifc_dt_match[] = {
 	{ .compatible = "amlogic,meson6-spifc", },
+	{ .compatible = "amlogic,meson-gxbb-spifc", },
 	{ },
 };
 MODULE_DEVICE_TABLE(of, meson_spifc_dt_match);
-- 
2.8.1

^ permalink raw reply related

* [PATCH 1/2] dt-bindings: spi-meson: Add GXBB Compatible string
From: Mark Brown @ 2016-09-12 19:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473321206-32284-2-git-send-email-narmstrong@baylibre.com>

On Thu, Sep 08, 2016 at 09:53:25AM +0200, Neil Armstrong wrote:
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>

Please use subject lines matching the style for the subsystem.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160912/1cc4abbd/attachment.sig>

^ permalink raw reply

* Applied "ASoC: rockchip: i2s: restore register during runtime_suspend/resume cycle" to the asoc tree
From: Mark Brown @ 2016-09-12 19:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473229653-53789-1-git-send-email-sugar.zhang@rock-chips.com>

The patch

   ASoC: rockchip: i2s: restore register during runtime_suspend/resume cycle

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From f0447f6cbb202e1be8244d15aee390a96d65e490 Mon Sep 17 00:00:00 2001
From: Sugar Zhang <sugar.zhang@rock-chips.com>
Date: Wed, 7 Sep 2016 14:27:33 +0800
Subject: [PATCH] ASoC: rockchip: i2s: restore register during
 runtime_suspend/resume cycle

when step into runtime_suspend, i2s pd will be disabled and loss state.
so need to restore register when runtime_resume.

Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/rockchip/rockchip_i2s.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 652e8c5ea166..974915cb4c4f 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -57,6 +57,7 @@ static int i2s_runtime_suspend(struct device *dev)
 {
 	struct rk_i2s_dev *i2s = dev_get_drvdata(dev);
 
+	regcache_cache_only(i2s->regmap, true);
 	clk_disable_unprepare(i2s->mclk);
 
 	return 0;
@@ -73,7 +74,14 @@ static int i2s_runtime_resume(struct device *dev)
 		return ret;
 	}
 
-	return 0;
+	regcache_cache_only(i2s->regmap, false);
+	regcache_mark_dirty(i2s->regmap);
+
+	ret = regcache_sync(i2s->regmap);
+	if (ret)
+		clk_disable_unprepare(i2s->mclk);
+
+	return ret;
 }
 
 static inline struct rk_i2s_dev *to_info(struct snd_soc_dai *dai)
-- 
2.8.1

^ permalink raw reply related

* Applied "ASoC: rockchip: spdif: restore register during runtime_suspend/resume cycle" to the asoc tree
From: Mark Brown @ 2016-09-12 19:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473229821-54139-1-git-send-email-sugar.zhang@rock-chips.com>

The patch

   ASoC: rockchip: spdif: restore register during runtime_suspend/resume cycle

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 3628c6987fb45d719cd963805bbba9f15017290e Mon Sep 17 00:00:00 2001
From: Sugar Zhang <sugar.zhang@rock-chips.com>
Date: Wed, 7 Sep 2016 14:30:21 +0800
Subject: [PATCH] ASoC: rockchip: spdif: restore register during
 runtime_suspend/resume cycle

when step into runtime_suspend, spdif pd will be disabled and loss state.
so need to restore register when runtime_resume.

Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/rockchip/rockchip_spdif.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c
index 4ca265737eda..fa8101d1e16f 100644
--- a/sound/soc/rockchip/rockchip_spdif.c
+++ b/sound/soc/rockchip/rockchip_spdif.c
@@ -65,6 +65,7 @@ static int __maybe_unused rk_spdif_runtime_suspend(struct device *dev)
 {
 	struct rk_spdif_dev *spdif = dev_get_drvdata(dev);
 
+	regcache_cache_only(spdif->regmap, true);
 	clk_disable_unprepare(spdif->mclk);
 	clk_disable_unprepare(spdif->hclk);
 
@@ -88,7 +89,16 @@ static int __maybe_unused rk_spdif_runtime_resume(struct device *dev)
 		return ret;
 	}
 
-	return 0;
+	regcache_cache_only(spdif->regmap, false);
+	regcache_mark_dirty(spdif->regmap);
+
+	ret = regcache_sync(spdif->regmap);
+	if (ret) {
+		clk_disable_unprepare(spdif->mclk);
+		clk_disable_unprepare(spdif->hclk);
+	}
+
+	return ret;
 }
 
 static int rk_spdif_hw_params(struct snd_pcm_substream *substream,
-- 
2.8.1

^ permalink raw reply related

* [PATCH v2 2/6] ARM: dts: bcm283x: Define standard pinctrl groups in the gpio node.
From: Stefan Wahren @ 2016-09-12 19:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1273800480.83718.15854341-2f8e-4e20-95f4-e76f81e6fd56.open-xchange@email.1und1.de>

Hi Gerd,

> Stefan Wahren <stefan.wahren@i2se.com> hat am 12. September 2016 um 20:19
> geschrieben:
> 
> 
> Hi Gerd,
> 
> > Gerd Hoffmann <kraxel@redhat.com> hat am 12. September 2016 um 10:22
> > geschrieben:
> > 
> > 
> > From: Eric Anholt <eric@anholt.net>
> > 
> > The BCM2835-ARM-Peripherals.pdf documentation specifies what the
> > function selects do for the pins, and there are a bunch of obvious
> > groupings to be made.  With these created, we'll be able to replace
> > bcm2835-rpi.dtsi's main "set all of these pins to alt0" with
> > references to specific groups we want enabled.
> > 
> > Signed-off-by: Eric Anholt <eric@anholt.net>
> > 
> > squashed in:
> >   ARM: dts: bcm283x: Add the emmc pin group to bcm283x.dtsi.
> >   ARM: dts: bcm283x: Add a group for mapping pins 48-53 to sdhost.
> >   ARM: dts: bcm283x: Add a new EMMC pin group from the downstream tree.
> > 
> > fixups by kraxel:
> >   * fix spi0 name
> >   * sort & group entries
> >   * use pull defines
> >   * add dpi group
> 
> this looks like a changelog. Please move this at the proper place before the
> first "diff" and specify the version.
> 
> > 
> > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> > ---
> >  arch/arm/boot/dts/bcm283x.dtsi | 203
> > +++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 203 insertions(+)
> > 
> > diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
> > index 4d9f3ab..7b03b63 100644
> > --- a/arch/arm/boot/dts/bcm283x.dtsi
> > +++ b/arch/arm/boot/dts/bcm283x.dtsi
> > @@ -131,6 +131,209 @@
> >  
> >  			interrupt-controller;
> >  			#interrupt-cells = <2>;
> > +
> > +			/* Defines pin muxing groups according to
> > +			 * BCM2835-ARM-Peripherals.pdf page 102.
> > +			 *
> > +			 * While each pin can have its mux selected
> > +			 * for various functions individually, some
> > +			 * groups only make sense to switch to a
> > +			 * particular function together.
> > +			 */
> > +			dpi_gpio4: dpi_gpio4 {
> > +				brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11
> > +					     12 13 14 15 16 17 18 19
> > +					     20 21 22 23 24 25 26 27>;
> > +				brcm,function = <BCM2835_FSEL_ALT2>;
> > +			};
> 
> s/dpi_gpio4/dpi_gpio0
> 
> > +			emmc_gpio22: emmc_gpio22 {
> > +				brcm,pins = <22 23 24 25 26 27>;
> > +				brcm,function = <BCM2835_FSEL_ALT3>;
> > +			};
> > +			emmc_gpio34: emmc_gpio34 {
> > +				brcm,pins = <34 35 36 37 38 39>;
> > +				brcm,function = <BCM2835_FSEL_ALT3>;
> > +				brcm,pull = <BCM2835_PUD_OFF
> > +					     BCM2835_PUD_UP
> > +					     BCM2835_PUD_UP
> > +					     BCM2835_PUD_UP
> > +					     BCM2835_PUD_UP
> > +					     BCM2835_PUD_UP>;
> > +			};
> > +			emmc_gpio48: emmc_gpio48 {
> > +				brcm,pins = <48 49 50 51 52 53>;
> > +				brcm,function = <BCM2835_FSEL_ALT3>;
> > +			};
> 
> Sorry, i didn't notice this before. The naming of these groups suggest 3 muxes
> for the same eMMC interface. I thought there is a eMMC interface and a SD host
> interface with different DMA channels.
> 
> > +
> > ...
> > +
> > +			sdhost_gpio48: sdhost_gpio48 {
> > +				brcm,pins = <48 49 50 51 52 53>;
> > +				brcm,function = <BCM2835_FSEL_ALT0>;
> > +			};
> 
> I think this incorrect. There is no function ALT0 for these pins, only ALT3.

please forget my last 2 comments. According to this page [1] eMMC is selected by
ALT3 and sdhost is selected by ALT0.

Do you know a reliable source where all muxes for both interface are documented?
The datasheet isn't very helpful here.

Regards
Stefan

[1] - http://pinout.xyz/pinout/sdio

> 
> Regards
> Stefan

^ permalink raw reply

* [UPDATE PATCH V11 1/8] ACPI: I/O Remapping Table (IORT) initial support
From: Tomasz Nowicki @ 2016-09-12 18:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473706460-9037-1-git-send-email-tn@semihalf.com>

On 12.09.2016 20:54, Tomasz Nowicki wrote:
> IORT shows representation of IO topology for ARM based systems.
> It describes how various components are connected together on
> parent-child basis e.g. PCI RC -> SMMU -> ITS. Also see IORT spec.
> http://infocenter.arm.com/help/topic/com.arm.doc.den0049b/DEN0049B_IO_Remapping_Table.pdf
>
> Initial support allows to detect IORT table presence and save its
> root pointer obtained through acpi_get_table(). The pointer validity
> depends on acpi_gbl_permanent_mmap because if acpi_gbl_permanent_mmap
> is not set while using IORT nodes we would dereference unmapped pointers.
>
> For the aforementioned reason call acpi_iort_init() from acpi_init()
> which guarantees acpi_gbl_permanent_mmap to be set at that point.
>
> Add generic helpers which are helpful for scanning and retrieving
> information from IORT table content. List of the most important helpers:
> - iort_find_dev_node() finds IORT node for a given device
> - iort_node_map_rid() maps device RID and returns IORT node which provides
>   final translation
>
> IORT support is placed under drivers/acpi/arm64/ new directory due to its
> ARM64 specific nature. The code there is considered only for ARM64.
> The long term plan is to keep all ARM64 specific tables support
> in this place e.g. GTDT table.
>
> Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
> Acked-by: Rafael J. Wysocki <rjw@rjwysocki.net>
> Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>
> Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>

Hi Marc,

Series with updated patch 1 can be found:
https://github.com/semihalf-nowicki-tomasz/linux.git (its-acpi-v11)

Sorry for zillions of patch updates...

Thanks,
Tomasz

^ permalink raw reply

* [PATCHv3 1/3] devicetree: bindings for Ion
From: Frank Rowand @ 2016-09-12 18:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1472601869-19469-2-git-send-email-labbott@redhat.com>

On 08/30/16 17:04, Laura Abbott wrote:
> This adds a base set of devicetree bindings for the Ion memory
> manager. This supports setting up the generic set of heaps and
> their properties.
> 
> Signed-off-by: Laura Abbott <labbott@redhat.com>
> ---
>  drivers/staging/android/ion/devicetree.txt | 51 ++++++++++++++++++++++++++++++
>  1 file changed, 51 insertions(+)
>  create mode 100644 drivers/staging/android/ion/devicetree.txt
> 
> diff --git a/drivers/staging/android/ion/devicetree.txt b/drivers/staging/android/ion/devicetree.txt
> new file mode 100644
> index 0000000..16871527
> --- /dev/null
> +++ b/drivers/staging/android/ion/devicetree.txt
> @@ -0,0 +1,51 @@
> +Ion Memory Manager
> +
> +Ion is a memory manager that allows for sharing of buffers via dma-buf.
> +Ion allows for different types of allocation via an abstraction called
> +a 'heap'. A heap represents a specific type of memory. Each heap has
> +a different type. There can be multiple instances of the same heap
> +type.
> +
> +Specific heap instances are tied to heap IDs. Heap IDs are not to be specified
> +in the devicetree.
> +
> +Required properties for Ion
> +
> +- compatible: "linux,ion" PLUS a compatible property for the device
> +
> +All child nodes of a linux,ion node are interpreted as heaps
> +
> +required properties for heaps
> +
> +- compatible: compatible string for a heap type PLUS a compatible property
> +for the specific instance of the heap. Current heap types
> +-- linux,ion-heap-system
> +-- linux,ion-heap-system-contig
> +-- linux,ion-heap-carveout
> +-- linux,ion-heap-chunk
> +-- linux,ion-heap-dma
> +-- linux,ion-heap-custom
> +
> +Optional properties
> +- memory-region: A phandle to a memory region. Required for DMA heap type
> +(see reserved-memory.txt for details on the reservation)
> +
> +Example:
> +
> +	ion {
> +		compatbile = "hisilicon,ion", "linux,ion";
> +
> +		ion-system-heap {
> +			compatbile = "hisilicon,system-heap", "linux,ion-heap-system"
> +		};
> +
> +		ion-camera-region {
> +			compatible = "hisilicon,camera-heap", "linux,ion-heap-dma"
> +			memory-region = <&camera_region>;
> +		};
> +
> +		ion-fb-region {
> +			compatbile = "hisilicon,fb-heap", "linux,ion-heap-dma"
> +			memory-region = <&fb_region>;
> +		};
> +	}
> 

This is extra complexity that does not appear to be needed.  As pointed out
in comments to earlier versions, the indirection pointing to memory regions
does not seem to be needed.  Why not just look for the ion memory regions in
the reserved-memory node?

The example in reserved-memory.txt does provide an example with the extra level
of indirection, but that is a different model where the nodes with references
to the reserved memory nodes are actually devices.  In the case of ion, the
heaps are not additional devices.

-Frank

^ permalink raw reply

* [PATCH 1/3] misc: Add Aspeed BT IPMI host driver
From: Corey Minyard @ 2016-09-12 18:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <c06a8afb-9143-6aef-3425-ad1e50cae35d@kaod.org>

On 09/02/2016 08:22 AM, C?dric Le Goater wrote:
> Hello,
>
> Adding Corey in cc: . I guess I should have done that in the first place.

Yes, probably so.  I've been travelling and didn't see it on the mailing
lists until now.

There is already a BT driver in the kernel, in drivers/char/ipmi, why
won't that work?

-corey

>
> Arnd is suggesting to put this IPMI BT driver under drivers/char/ipmi
> which is indeed a better place than drivers/misc.
>
> Below some comments,
>
> On 08/31/2016 09:57 PM, Arnd Bergmann wrote:
>> On Wednesday, August 31, 2016 7:24:17 PM CEST C?dric Le Goater wrote:
>>> From: Alistair Popple <alistair@popple.id.au>
>>>
>>> This patch adds a simple device driver to expose the iBT interface on
>>> Aspeed chips as a character device (/dev/bt).
>>>
>>> The iBT interface is used to perform in-band IPMI communication from a
>>> BMC to the host.
>>>
>>> Signed-off-by: Alistair Popple <alistair@popple.id.au>
>>> Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
>>> Signed-off-by: Joel Stanley <joel@jms.id.au>
>>> [clg: checkpatch fixes
>>>        devicetree binding documentation]
>>> Signed-off-by: C?dric Le Goater <clg@kaod.org>
>>> ---
>>>   .../devicetree/bindings/misc/aspeed,bt-host.txt    |  19 +
>>>   drivers/misc/Kconfig                               |   5 +
>>>   drivers/misc/Makefile                              |   1 +
>>>   drivers/misc/bt-host.c                             | 433 +++++++++++++++++++++
>>>   include/uapi/linux/Kbuild                          |   1 +
>>>   include/uapi/linux/bt-host.h                       |  18 +
>>>   6 files changed, 477 insertions(+)
>>>   create mode 100644 Documentation/devicetree/bindings/misc/aspeed,bt-host.txt
>>>   create mode 100644 drivers/misc/bt-host.c
>>>   create mode 100644 include/uapi/linux/bt-host.h
>>>
>>> diff --git a/Documentation/devicetree/bindings/misc/aspeed,bt-host.txt b/Documentation/devicetree/bindings/misc/aspeed,bt-host.txt
>>> new file mode 100644
>>> index 000000000000..938c5998c331
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/misc/aspeed,bt-host.txt
>> "misc" seems like a bad category here. Does this fit nowhere else?
>>
>>> @@ -0,0 +1,19 @@
>>> +* Aspeed BT IPMI interface
>> What does "BT" stand for? IPMI is a more commonly known acronym,
>> but maybe list both with their full name as well.
> "Block Transfer" which is described in the IPMI specs.
>
> yes, I need to rephrase the commit log a bit and put some references
> to the specs.
>
>>> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
>>> index 7410c6d9a34d..71a7b9feb0f0 100644
>>> --- a/drivers/misc/Makefile
>>> +++ b/drivers/misc/Makefile
>>> @@ -57,6 +57,7 @@ obj-$(CONFIG_ECHO)		+= echo/
>>>   obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
>>>   obj-$(CONFIG_CXL_BASE)		+= cxl/
>>>   obj-$(CONFIG_PANEL)             += panel.o
>>> +obj-$(CONFIG_ASPEED_BT_IPMI_HOST)	+= bt-host.o
>>>   
>>>   lkdtm-$(CONFIG_LKDTM)		+= lkdtm_core.o
>>>   lkdtm-$(CONFIG_LKDTM)		+= lkdtm_bugs.o
>> Maybe put this in a subdirectory of drivers/char/ipmi?
>> I understand that this is the other end of the protocol,
>> but they are closely related after all.
> I agree. There are also some definitions we could make common.
>
> Let's see what Corey thinks about it.
>
>>> +#define DEVICE_NAME	"bt-host"
>> here maybe "ipmi/bt-host" or "ipmi-bt-host"?
> yes. a name containing 'ipmi' is certainly wanted.
>    
>>> +static ssize_t bt_host_read(struct file *file, char __user *buf,
>>> +				size_t count, loff_t *ppos)
>>> +{
>>> +	struct bt_host *bt_host = file_bt_host(file);
>>> +	char __user *p = buf;
>>> +	u8 len;
>>> +
>>> +	if (!access_ok(VERIFY_WRITE, buf, count))
>>> +		return -EFAULT;
>>> +
>>> +	WARN_ON(*ppos);
>>> +
>>> +	if (wait_event_interruptible(bt_host->queue,
>>> +				bt_inb(bt_host, BT_CTRL) & BT_CTRL_H2B_ATN))
>>> +		return -ERESTARTSYS;
>>> +
>>> +	set_b_busy(bt_host);
>>> +	clr_h2b_atn(bt_host);
>>> +	clr_rd_ptr(bt_host);
>>> +
>>> +	len = bt_read(bt_host);
>>> +	__put_user(len, p++);
>>> +
>>> +	/* We pass the length back as well */
>>> +	if (len + 1 > count)
>>> +		len = count - 1;
>>> +
>>> +	while (len) {
>>> +		if (__put_user(bt_read(bt_host), p))
>>> +			return -EFAULT;
>>> +		len--; p++;
>>> +	}
>> If there are larger chunks of data to be transferred,
>> using a temporary buffer with copy_from_user/copy_to_user
>> would be more efficient. Since the size appears to
>> be limited to 256 bytes anyway, that easily fits on the stack.
> ok. I will change that.
>
>>> +
>>> +	clr_b_busy(bt_host);
>>> +
>>> +	return p - buf;
>>> +}
>> What is the motivation for only allowing complete messages
>> to be transferred or truncated for short buffers?
>>
>> Have you considered reading the message into a device specific
>> buffer and allowing continued reads?
>>
>> I don't see an obvious reason one way or another, and I suppose
>> you had an idea of what you were doing, so maybe explain it
>> in a comment.
> The interface is not byte oriented. It is called 'Block Transfer'
> because an entire message is buffered and then the host or the bmc
> is notified that there is data to be read.
>
> I will add a comment on that.
>
>>> +static long bt_host_ioctl(struct file *file, unsigned int cmd,
>>> +		unsigned long param)
>>> +{
>>> +	struct bt_host *bt_host = file_bt_host(file);
>>> +
>>> +	switch (cmd) {
>>> +	case BT_HOST_IOCTL_SMS_ATN:
>>> +		set_sms_atn(bt_host);
>>> +		return 0;
>>> +	}
>>> +	return -EINVAL;
>>> +}
>> Is this ioctl interface defined in a way that makes sense on
>> any IPMI host hardware, or did you just do it like this because
>> it is the easiest way  on the hardware.
> This platform runs OpenBMC on which a dbus daemon acts as a proxy
> between the IPMI BT char device and the rest of the system. So yes,
> the ioctl is relatively easy to use.
>
>> I think it's important for the user interface to be extensible
>> to other implementations if we ever add any.
> I agree but I don't know of any other BMC side implementations.
> May be others ?
>
>>> +static int bt_host_config_irq(struct bt_host *bt_host,
>>> +		struct platform_device *pdev)
>>> +{
>>> +	struct device *dev = &pdev->dev;
>>> +	uint32_t reg;
>>> +	int rc;
>>> +
>>> +	bt_host->irq = irq_of_parse_and_map(dev->of_node, 0);
>>> +	if (!bt_host->irq)
>>> +		return -ENODEV;
>> I think platform_get_irq() is the preferred interface here.
> OK.
>
> Thanks,
>
> C.
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [UPDATE PATCH V11 1/8] ACPI: I/O Remapping Table (IORT) initial support
From: Tomasz Nowicki @ 2016-09-12 18:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473705147-6588-2-git-send-email-tn@semihalf.com>

IORT shows representation of IO topology for ARM based systems.
It describes how various components are connected together on
parent-child basis e.g. PCI RC -> SMMU -> ITS. Also see IORT spec.
http://infocenter.arm.com/help/topic/com.arm.doc.den0049b/DEN0049B_IO_Remapping_Table.pdf

Initial support allows to detect IORT table presence and save its
root pointer obtained through acpi_get_table(). The pointer validity
depends on acpi_gbl_permanent_mmap because if acpi_gbl_permanent_mmap
is not set while using IORT nodes we would dereference unmapped pointers.

For the aforementioned reason call acpi_iort_init() from acpi_init()
which guarantees acpi_gbl_permanent_mmap to be set at that point.

Add generic helpers which are helpful for scanning and retrieving
information from IORT table content. List of the most important helpers:
- iort_find_dev_node() finds IORT node for a given device
- iort_node_map_rid() maps device RID and returns IORT node which provides
  final translation

IORT support is placed under drivers/acpi/arm64/ new directory due to its
ARM64 specific nature. The code there is considered only for ARM64.
The long term plan is to keep all ARM64 specific tables support
in this place e.g. GTDT table.

Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
Acked-by: Rafael J. Wysocki <rjw@rjwysocki.net>
Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>
Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
---
 drivers/acpi/Kconfig        |   4 +
 drivers/acpi/Makefile       |   2 +
 drivers/acpi/arm64/Kconfig  |   6 ++
 drivers/acpi/arm64/Makefile |   1 +
 drivers/acpi/arm64/iort.c   | 216 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/acpi/bus.c          |   2 +
 include/linux/acpi_iort.h   |  30 ++++++
 7 files changed, 261 insertions(+)
 create mode 100644 drivers/acpi/arm64/Kconfig
 create mode 100644 drivers/acpi/arm64/Makefile
 create mode 100644 drivers/acpi/arm64/iort.c
 create mode 100644 include/linux/acpi_iort.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 445ce28..d5c0614 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -521,4 +521,8 @@ config ACPI_CONFIGFS
 	  userspace. The configurable ACPI groups will be visible under
 	  /config/acpi, assuming configfs is mounted under /config.
 
+if ARM64
+source "drivers/acpi/arm64/Kconfig"
+endif
+
 endif	# ACPI
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 5ae9d85..e5ada78 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -105,3 +105,5 @@ obj-$(CONFIG_ACPI_CONFIGFS)	+= acpi_configfs.o
 
 video-objs			+= acpi_video.o video_detect.o
 obj-y				+= dptf/
+
+obj-$(CONFIG_ARM64)		+= arm64/
diff --git a/drivers/acpi/arm64/Kconfig b/drivers/acpi/arm64/Kconfig
new file mode 100644
index 0000000..4616da4
--- /dev/null
+++ b/drivers/acpi/arm64/Kconfig
@@ -0,0 +1,6 @@
+#
+# ACPI Configuration for ARM64
+#
+
+config ACPI_IORT
+	bool
diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile
new file mode 100644
index 0000000..72331f2
--- /dev/null
+++ b/drivers/acpi/arm64/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ACPI_IORT) 	+= iort.o
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
new file mode 100644
index 0000000..5279a35
--- /dev/null
+++ b/drivers/acpi/arm64/iort.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2016, Semihalf
+ *	Author: Tomasz Nowicki <tn@semihalf.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * This file implements early detection/parsing of I/O mapping
+ * reported to OS through firmware via I/O Remapping Table (IORT)
+ * IORT document number: ARM DEN 0049A
+ */
+
+#define pr_fmt(fmt)	"ACPI: IORT: " fmt
+
+#include <linux/acpi_iort.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+typedef acpi_status (*iort_find_node_callback)
+	(struct acpi_iort_node *node, void *context);
+
+/* Root pointer to the mapped IORT table */
+static struct acpi_table_header *iort_table;
+
+static LIST_HEAD(iort_msi_chip_list);
+static DEFINE_SPINLOCK(iort_msi_chip_lock);
+
+static struct acpi_iort_node *iort_scan_node(enum acpi_iort_node_type type,
+					     iort_find_node_callback callback,
+					     void *context)
+{
+	struct acpi_iort_node *iort_node, *iort_end;
+	struct acpi_table_iort *iort;
+	int i;
+
+	if (!iort_table)
+		return NULL;
+
+	/* Get the first IORT node */
+	iort = (struct acpi_table_iort *)iort_table;
+	iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort,
+				 iort->node_offset);
+	iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+				iort_table->length);
+
+	for (i = 0; i < iort->node_count; i++) {
+		if (WARN_TAINT(iort_node >= iort_end, TAINT_FIRMWARE_WORKAROUND,
+			       "IORT node pointer overflows, bad table!\n"))
+			return NULL;
+
+		if (iort_node->type == type &&
+		    ACPI_SUCCESS(callback(iort_node, context)))
+				return iort_node;
+
+		iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
+					 iort_node->length);
+	}
+
+	return NULL;
+}
+
+static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
+					    void *context)
+{
+	struct device *dev = context;
+	acpi_status status;
+
+	if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
+		struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
+		struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
+		struct acpi_iort_named_component *ncomp;
+
+		if (!adev) {
+			status = AE_NOT_FOUND;
+			goto out;
+		}
+
+		status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &buf);
+		if (ACPI_FAILURE(status)) {
+			dev_warn(dev, "Can't get device full path name\n");
+			goto out;
+		}
+
+		ncomp = (struct acpi_iort_named_component *)node->node_data;
+		status = !strcmp(ncomp->device_name, buf.pointer) ?
+							AE_OK : AE_NOT_FOUND;
+		acpi_os_free(buf.pointer);
+	} else if (node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
+		struct acpi_iort_root_complex *pci_rc;
+		struct pci_bus *bus;
+
+		bus = to_pci_bus(dev);
+		pci_rc = (struct acpi_iort_root_complex *)node->node_data;
+
+		/*
+		 * It is assumed that PCI segment numbers maps one-to-one
+		 * with root complexes. Each segment number can represent only
+		 * one root complex.
+		 */
+		status = pci_rc->pci_segment_number == pci_domain_nr(bus) ?
+							AE_OK : AE_NOT_FOUND;
+	} else {
+		status = AE_NOT_FOUND;
+	}
+out:
+	return status;
+}
+
+static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
+		       u32 *rid_out)
+{
+	/* Single mapping does not care for input id */
+	if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) {
+		if (type == ACPI_IORT_NODE_NAMED_COMPONENT ||
+		    type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
+			*rid_out = map->output_base;
+			return 0;
+		}
+
+		pr_warn(FW_BUG "[map %p] SINGLE MAPPING flag not allowed for node type %d, skipping ID map\n",
+			map, type);
+		return -ENXIO;
+	}
+
+	if (rid_in < map->input_base ||
+	    (rid_in >= map->input_base + map->id_count))
+		return -ENXIO;
+
+	*rid_out = map->output_base + (rid_in - map->input_base);
+	return 0;
+}
+
+static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
+						u32 rid_in, u32 *rid_out,
+						u8 type)
+{
+	u32 rid = rid_in;
+
+	/* Parse the ID mapping tree to find specified node type */
+	while (node) {
+		struct acpi_iort_id_mapping *map;
+		int i;
+
+		if (node->type == type) {
+			if (rid_out)
+				*rid_out = rid;
+			return node;
+		}
+
+		if (!node->mapping_offset || !node->mapping_count)
+			goto fail_map;
+
+		map = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
+				   node->mapping_offset);
+
+		/* Firmware bug! */
+		if (!map->output_reference) {
+			pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
+			       node, node->type);
+			goto fail_map;
+		}
+
+		/* Do the RID translation */
+		for (i = 0; i < node->mapping_count; i++, map++) {
+			if (!iort_id_map(map, node->type, rid, &rid))
+				break;
+		}
+
+		if (i == node->mapping_count)
+			goto fail_map;
+
+		node = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+				    map->output_reference);
+	}
+
+fail_map:
+	/* Map input RID to output RID unchanged on mapping failure*/
+	if (rid_out)
+		*rid_out = rid_in;
+
+	return NULL;
+}
+
+static struct acpi_iort_node *iort_find_dev_node(struct device *dev)
+{
+	struct pci_bus *pbus;
+
+	if (!dev_is_pci(dev))
+		return iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
+				      iort_match_node_callback, dev);
+
+	/* Find a PCI root bus */
+	pbus = to_pci_dev(dev)->bus;
+	while (!pci_is_root_bus(pbus))
+		pbus = pbus->parent;
+
+	return iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
+			      iort_match_node_callback, &pbus->dev);
+}
+
+void __init acpi_iort_init(void)
+{
+	acpi_status status;
+
+	status = acpi_get_table(ACPI_SIG_IORT, 0, &iort_table);
+	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+		const char *msg = acpi_format_exception(status);
+		pr_err("Failed to get table, %s\n", msg);
+	}
+}
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 85b7d07..e56e643 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -36,6 +36,7 @@
 #ifdef CONFIG_X86
 #include <asm/mpspec.h>
 #endif
+#include <linux/acpi_iort.h>
 #include <linux/pci.h>
 #include <acpi/apei.h>
 #include <linux/dmi.h>
@@ -1186,6 +1187,7 @@ static int __init acpi_init(void)
 	}
 
 	pci_mmcfg_late_init();
+	acpi_iort_init();
 	acpi_scan_init();
 	acpi_ec_init();
 	acpi_debugfs_init();
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
new file mode 100644
index 0000000..fcacaf7
--- /dev/null
+++ b/include/linux/acpi_iort.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016, Semihalf
+ *	Author: Tomasz Nowicki <tn@semihalf.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef __ACPI_IORT_H__
+#define __ACPI_IORT_H__
+
+#include <linux/acpi.h>
+
+#ifdef CONFIG_ACPI_IORT
+void acpi_iort_init(void);
+#else
+static inline void acpi_iort_init(void) { }
+#endif
+
+#endif /* __ACPI_IORT_H__ */
-- 
1.9.1

^ permalink raw reply related

* [PATCH] Revert "Input: bma150 - extend chip detection for bma180"
From: Hans de Goede @ 2016-09-12 18:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4809E76B-7BFE-4D95-8631-079262E958E2@goldelico.com>

HI,

On 12-09-16 19:20, H. Nikolaus Schaller wrote:
> Hi,
>
>> Am 12.09.2016 um 16:44 schrieb Hans de Goede <hdegoede@redhat.com>:
>>
>> Hi,
>>
>> On 12-09-16 16:31, H. Nikolaus Schaller wrote:
>>> Hi,
>>>
>>>> Am 11.09.2016 um 18:43 schrieb Hans de Goede <hdegoede@redhat.com>:
>>>>
>>>> This reverts commit ef3714fdbc8d ("Input: bma150 - extend chip
>>>> detection for bma180").
>>>>
>>>> The bma180 is not compatible with the bma150 at all, it has 14 bits
>>>> resolution instead of 10, and it has quite different control registers.
>>>>
>>>> Treating the bma180 as a bma150 wrt its data registers will just result
>>>> in throwing away the lowest 4 bits, which is not too bad. But the ctrl
>>>> registers are a different story.
>>>>
>>>> It may be that things happen to just work (I don't have a bma180 to
>>>> test with) but that certainly does not make this right.
>>>
>>> Yes, looks as if your observation is right. Thanks for pointing this out!
>>>
>>> This did need me some research to find an answer...
>>>
>>> If I remember correctly, the original patch was based on a recommendation
>>> from someone I don't remember, who said that the chips are the same in a
>>> different package. So we added the chip_id and it worked immediately as
>>> expected. It looks as if we did not check the data sheets. So we did not
>>> question this recommendation.
>>>
>>>>
>>>> Removing the bma180 id also removes overlap wrt the ids in the iio
>>>> bma180 driver which does treat the bma180 properly.
>>>
>>> Nack.
>>>
>>> The problem we get is that an iio driver is not an input driver and can't
>>> easily replace it.
>>
>> Actually almost all accelerometer drivers in the Linux kernel are
>> iio drivers,
>
> Yes, that is a good move indeed to make them more general.
>
>> the bma150 driver is the odd duck out,
>
> Indeed it seems to be in /misc for some reason.
>
>> that is why
>> we've iio-sensor-proxy for apps which want the accelerometer
>> to behave as an input device:
>>
>> https://github.com/hadess/iio-sensor-proxy
>
> Does this provide an input device /dev/input/event?
> From a first look it seems to provide a D-Bus abstraction which is
> not the same as an /dev/input/event.

It also provides a /dev/input/event node through uinput:

https://github.com/hadess/iio-sensor-proxy/blob/master/src/fake-input-accelerometer.c


> What about latency?
> A kernel driver can react on a sensor interrupt, queue results
> and sleep.
>
> Isn't a user-space process more resource hungry than a kernel thread?
>
>>
>>> An input driver can be used for gesture applications (e.g. detecting
>>> the device has been turned upside down) and can report X/Y/Z coordinates
>>> to e.g. X11 for games similar to a mouse or joystick (which the iio driver
>>> doesn't).
>>
>> See above.
>>
>>> So it should remain configurable which of both driver options is loaded,
>>> to match user space API needs.
>>>
>>> BTW: id overlap is only a problem if both drivers are configured in parallel.
>>
>> Right, so it is "only" a problem to any generic distro which tries to
>> support both bma150 and bma250 accelerometers, as both the input
>> bma150 as well as the iio bma250 driver claim to be bma180 compatible.
>
> Well, it is only a problem if such a generic distro is really run on a device
> which has a bma180 defined in DT. There do not seem to exist many of these.

True, still the bma180 compatible is simply just wrong here, and as such
it really should be removed (it really should never have been added).

>>> Next, I have tried to find out which devices really use the bma150 and bma180.
>>>
>>> It appears that no in-tree device uses the bma150 while the GTA04 uses
>>> the bma180 (in DT), but not in any defconfig (the GTA04 specific config
>>> is not upstreamable since omap2plus_defconfig exists).
>>>
>>> In user-space the GTA04 requires and actively uses this input driver for Replicant.
>>>
>>> So I would conclude that this revert does not improve/fix any device using a
>>> bma150 (if it exists at all), but breaks an existing device.
>>>
>>> What options do we have?
>>>
>>> a) add proper register number constants and choose conditionally (where they differ)
>>> b) drop bma150 support completely and change registers for bma180
>>> c) clone the bma150 input driver into an bma180 input driver and fix registers
>>> d) extend the bma180 iio driver to optionally provide an input device
>>> e) write a generic input/iio-accel wrapper (which should work with any iio accelerometer)
>>>
>>> I would favour approach e)
>>
>> Good, because that solution already exists :) See:
>> https://github.com/hadess/iio-sensor-proxy
>
> No, it is yet another option. I would formulate it as:
>
> f) break user-space compatibility for existing systems and write / require
>    a user-space workaround.
>
> This is something which is the least favorite in my view.

I'm pretty sure that no-one, really no-one wants to do
evdev emulation for iio devices in the kernel; and there
is nothing wrong with doing it in userspace.

> Since we have no control over the user space people have installed and IMHO
> a kernel shouldn't break APIs too often or only for really good reasons
> (e.g. completely new functions).
>
> And we have no means to force user-space developers to integrate such daemons :(
>
> So we break a device by upgrading to 4.9-kernel but can't give a solution.

The only user of this seems to be the gta04, and I believe gta04 users
will not just jump to 4.9 without getting that through some sort
of central distribution point which can make sure userland gets
fixed first.

>>> but it has an issue I have no solution for:
>>>
>>> 	how to define in DT (or CONFIG?) which iio accelerometer(s) should
>>> 	be wrapped and presented as input device(s).
>>
>> I believe currently iio-sensor-proxy simply wraps all accelerometers
>> it can find, which seems the right thing to do. Usually we're running
>> a generic desktop-ish OS / distro which wants these devices
>> to be available as input devices;
>> for special cases like actual
>> robots and stuff running Linux, iio-sensor-proxy can simply be
>> disabled; or not installed at all.
>
> Well, the GTA04 we talk about falls into a third category: a mobile device.
>
> Which is not running a desktop-ish OS / distro. It is running Replicant,

For replicant there is:

https://github.com/01org/android-iio-sensors-hal

> QtMoko, SHR, FSO or other user spaces which partially rely on /dev/input/event
> without starting a daemon.

So either these have a gta04 specific version, which can then
be fixed in parallel with the kernel, like one would do
with normal distros in a case like this. Or these are generic
in which case having them work with iio accelerometers is
a good thing in general, and they may even already work.

> At least in current releases and we have little
> influence to have them use a new daemon.
>
> So I would strongly prefer if we can solve this in the kernel and keep the
> user-space API for the bma180 input driver stable.
>
>>
>> So all in all I believe that this is a solved problem, since
>> solution e. from above is already implemented.
>
> Well it is also solved if we do not revert the patch at all, because it
> works in practice (even if not exactly correct) and is compatible to
> existing user-space.
>
> In summary I don't like option f) because it creates more problems than
> it solves.
>
> If e) is ruled out, IMHO the second best option seems to be d) to add a
> CONFIG_BMA180_INPUT_DEVICE and make it present some additional /dev/input/event
> in parallel to the iio interface.

Ugh, no we don't need more hacks here. I would greatly prefer to
just keep the "bma180" is in the bma150 input driver over adding
evdev event generation to iio drivers (either at the driver level
or the core).

I think that the best solution might be to do do something like this
in drivers/input/misc/bma150.c

static const struct i2c_device_id bma150_id[] = {
         { "bma150", 0 },
#ifndef CONFIG_BMA180 /* Avoid conflict with iio bma180 driver */
         { "bma180", 0 },
#endif
         { "smb380", 0 },
         { "bma023", 0 },
         { }
};

Then people relying on this can keep using it, and iio user
do not have to worry about it.

Regards,

Hans



> I already have a similar approach in my to-be-upstreamed queue for the tsc2007
> touch screen driver to provide additional iio channels for raw values, chip
> temperature and the auxiliary general purpose ADC (which is used as ambient
> light sensor in the GTA04).
>
> So let's develop some patch for drivers/iio/accel/bma180.c before we revert
> this bma150 patch and have nothing.
>
> BR,
> Nikolaus Schaller
>
>>
>> Regards,
>>
>> Hans
>>
>>
>>
>>>
>>> Well, it could be as simple as defining a virtual "input-iio-accel" wrapper
>>> driver with no real hardware behind and provide a reference to the iio DT node.
>>> But I think such virtual devices are against DT style.
>>>
>>> So I don't know how to implement it in an acceptable way.
>>>
>>> Ideas?
>>>
>>> BR and thanks,
>>> Nikolaus Schaller
>>>
>>>>
>>>> Cc: Dr. H. Nikolaus Schaller <hns@goldelico.com>
>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>>>> ---
>>>> drivers/input/misc/bma150.c | 4 +---
>>>> 1 file changed, 1 insertion(+), 3 deletions(-)
>>>>
>>>> diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c
>>>> index b0d4453..cae4832 100644
>>>> --- a/drivers/input/misc/bma150.c
>>>> +++ b/drivers/input/misc/bma150.c
>>>> @@ -70,7 +70,6 @@
>>>> #define BMA150_CFG_5_REG	0x11
>>>>
>>>> #define BMA150_CHIP_ID		2
>>>> -#define BMA180_CHIP_ID		3
>>>> #define BMA150_CHIP_ID_REG	BMA150_DATA_0_REG
>>>>
>>>> #define BMA150_ACC_X_LSB_REG	BMA150_DATA_2_REG
>>>> @@ -539,7 +538,7 @@ static int bma150_probe(struct i2c_client *client,
>>>> 	}
>>>>
>>>> 	chip_id = i2c_smbus_read_byte_data(client, BMA150_CHIP_ID_REG);
>>>> -	if (chip_id != BMA150_CHIP_ID && chip_id != BMA180_CHIP_ID) {
>>>> +	if (chip_id != BMA150_CHIP_ID) {
>>>> 		dev_err(&client->dev, "BMA150 chip id error: %d\n", chip_id);
>>>> 		return -EINVAL;
>>>> 	}
>>>> @@ -643,7 +642,6 @@ static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL);
>>>>
>>>> static const struct i2c_device_id bma150_id[] = {
>>>> 	{ "bma150", 0 },
>>>> -	{ "bma180", 0 },
>>>> 	{ "smb380", 0 },
>>>> 	{ "bma023", 0 },
>>>> 	{ }
>>>> --
>>>> 2.9.3
>>>>
>>>
>

^ permalink raw reply

* [PATCH v2 00/17] Make rpmsg a framework
From: Bjorn Andersson @ 2016-09-12 18:49 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <bc618ac9-13c8-e9bf-c7e9-fe5b7309a585@codeaurora.org>

On Mon 12 Sep 11:13 PDT 2016, Jeffrey Hugo wrote:

> On 9/12/2016 12:00 PM, Bjorn Andersson wrote:
> >On Mon 12 Sep 09:52 PDT 2016, Lina Iyer wrote:
> >
> >>Hi Bjorn,
> >>
> >>On Thu, Sep 01 2016 at 16:28 -0600, Bjorn Andersson wrote:
> >>>This series splits the virtio rpmsg bus driver into a rpmsg bus and a virtio
> >>>backend/wireformat.
> >>>
> >>>
> >>>As we discussed the Qualcomm SMD implementation a couple of years back people
> >>>suggested that I should make it "a rpmsg thingie". With the introduction of the
> >>>Qualcomm 8996 platform, we must support a variant of the communication
> >>>mechanism that share many of the characteristics of SMD, but are different
> >>>enough that it can't be done in a single implementation. As such there is
> >>>enough benefit to do the necessary work and being able to make SMD a "rpmsg
> >>>thingie".
> >>>
> >>>On-top of this series I have patches to switch the current smd clients over to
> >>>rpmsg (and by that drop the existing SMD implementation).
> >>>
> >>>All this allows me to implement the new backend and reuse all existing SMD
> >>>drivers with the new mechanism.
> >>>
> >>
> >>RPM Communication has to supported even when IRQs are disabled. The most
> >>important use of this communication is to set the wake up time for the
> >>CPU subsystem when all the CPUs are powered off.
> >
> >Can you point me to the downstream code where this is implemented so I
> >can have a look? Do you expect to get the response on that request?
> 
> Have a look at -
> smd_mask_receive_interrupt()
> smd_is_pkt_avail()
> 

In msm-3.18 these still seems to only come from either
msm_rpm_enter_sleep() and the rpm-clock driver, related to flushing
cached sleep state requests.

> Every request to the RPM generates a response.  The Linux RPM driver may
> decide to let the response sit in the fifo, or it may need to read and
> process it.
> 

Right, I presume we save some time by not waiting for these responses as
we want to reach sleep as soon as possible. The answer I got last time
this was discussed was that it was an optimization, not a functional
requirement.


I'm not at all against having the rpm driver cache the state
information and the smd driver process read/writes from the rpm driver
in IRQ context. I do however not know how to trigger the flush in a sane
way.

> >
> >>In addition to that,
> >>"sleep" votes that are sent by the application processor subsystem to
> >>allow system to go into deep sleep modes can only be triggered when the
> >>CPU PM domains are power collapsed, drivers do not have a knowledge of
> >>when that happens.
> >
> >Do you mean the actual sleep votes can only be with the CPU PM domains
> >collapsed?
> >
> >It's been a while since I dug through that code, but there was several
> >cases where sleep votes would be sent out during normal execution as
> >well, and then there's the optimization of flushing out all cached sleep
> >votes when we're on the way down.
> >
> >>This has to be done by a platform code that registers
> >>for CPU PM domain power_off/on callbacks.
> >>
> >
> >Ok, sounds like we have a legit use case for improving this.
> >
> >>Using rpmsg may be nice for RPM SMD communication, but mutexes need to
> >>go away for this driver to be any useful than bare bones active mode
> >>resource requests for QCOM SoCs. By not doing that now, we lock
> >>ourselves out of using this SMD driver in the near future when CPU PM
> >>domains are available in the kernel with an ability to do system low
> >>power modes.
> >>
> >
> >The last time I looked at this there where no cases when it was
> >_required_ to support transmitting requests to the rpm from IRQ context.
> 
> I no longer work on SMD, but when I did this was in fact a strict
> requirement.

When I dissected all the users of the API I came to the conclusion that
this requirement (on the SMD driver) came from above mentioned
optimization.

> If I recall correctly, there was a parameter in the RPM driver
> for the transmit function that indicated if the request was being made in
> atomic context or not, which would change the behavior of how the transmit
> was handled.
> 

You're correct, the question is still which of these code paths are
actually needed and to motivate the endless maintenance of the extra
code.


Nice to see you on the mailing list again Jeff.

Regards,
Bjorn

^ permalink raw reply

* [PATCH V11 8/8] irqchip/gicv3-its: Use MADT ITS subtable to do PCI/MSI domain initialization
From: Tomasz Nowicki @ 2016-09-12 18:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473705147-6588-1-git-send-email-tn@semihalf.com>

Let ACPI build ITS PCI MSI domain. ACPI code is responsible for retrieving
inner domain token and passing it on to its_pci_msi_init_one generic
init call.

IORT maintains list of registered domain tokens and allows to find
corresponding domain based on MADT ITS subtable ID info.

Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 drivers/irqchip/irq-gic-v3-its-pci-msi.c | 44 ++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c
index d2c2496..aee1c60 100644
--- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c
@@ -15,6 +15,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/acpi_iort.h>
 #include <linux/msi.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
@@ -144,9 +145,52 @@ static int __init its_pci_of_msi_init(void)
 	return 0;
 }
 
+#ifdef CONFIG_ACPI
+
+static int __init
+its_pci_msi_parse_madt(struct acpi_subtable_header *header,
+		       const unsigned long end)
+{
+	struct acpi_madt_generic_translator *its_entry;
+	struct fwnode_handle *dom_handle;
+	const char *node_name;
+	int err = -ENXIO;
+
+	its_entry = (struct acpi_madt_generic_translator *)header;
+	node_name = kasprintf(GFP_KERNEL, "ITS at 0x%lx",
+			      (long)its_entry->base_address);
+	dom_handle = iort_find_domain_token(its_entry->translation_id);
+	if (!dom_handle) {
+		pr_err("%s: Unable to locate ITS domain handle\n", node_name);
+		goto out;
+	}
+
+	err = its_pci_msi_init_one(dom_handle, node_name);
+	if (!err)
+		pr_info("PCI/MSI: %s domain created\n", node_name);
+
+out:
+	kfree(node_name);
+	return err;
+}
+
+static int __init its_pci_acpi_msi_init(void)
+{
+	acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
+			      its_pci_msi_parse_madt, 0);
+	return 0;
+}
+#else
+static int __init its_pci_acpi_msi_init(void)
+{
+	return 0;
+}
+#endif
+
 static int __init its_pci_msi_init(void)
 {
 	its_pci_of_msi_init();
+	its_pci_acpi_msi_init();
 
 	return 0;
 }
-- 
1.9.1

^ permalink raw reply related

* [PATCH V11 7/8] irqchip/gicv3-its: Factor out PCI-MSI part that might be reused for ACPI
From: Tomasz Nowicki @ 2016-09-12 18:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473705147-6588-1-git-send-email-tn@semihalf.com>

Firmware agnostic code lands in common functions which do necessary
domain initialization based on unique domain handler. DT specific
code goes to DT specific init call.

Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/irqchip/irq-gic-v3-its-pci-msi.c | 44 +++++++++++++++++++++-----------
 1 file changed, 29 insertions(+), 15 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c
index aee60ed..d2c2496 100644
--- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c
@@ -106,34 +106,48 @@ static struct of_device_id its_device_id[] = {
 	{},
 };
 
-static int __init its_pci_msi_init(void)
+static int __init its_pci_msi_init_one(struct fwnode_handle *handle,
+				       const char *name)
 {
-	struct device_node *np;
 	struct irq_domain *parent;
 
+	parent = irq_find_matching_fwnode(handle, DOMAIN_BUS_NEXUS);
+	if (!parent || !msi_get_domain_info(parent)) {
+		pr_err("%s: Unable to locate ITS domain\n", name);
+		return -ENXIO;
+	}
+
+	if (!pci_msi_create_irq_domain(handle, &its_pci_msi_domain_info,
+				       parent)) {
+		pr_err("%s: Unable to create PCI domain\n", name);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static int __init its_pci_of_msi_init(void)
+{
+	struct device_node *np;
+
 	for (np = of_find_matching_node(NULL, its_device_id); np;
 	     np = of_find_matching_node(np, its_device_id)) {
 		if (!of_property_read_bool(np, "msi-controller"))
 			continue;
 
-		parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS);
-		if (!parent || !msi_get_domain_info(parent)) {
-			pr_err("%s: unable to locate ITS domain\n",
-			       np->full_name);
+		if (its_pci_msi_init_one(of_node_to_fwnode(np), np->full_name))
 			continue;
-		}
-
-		if (!pci_msi_create_irq_domain(of_node_to_fwnode(np),
-					       &its_pci_msi_domain_info,
-					       parent)) {
-			pr_err("%s: unable to create PCI domain\n",
-			       np->full_name);
-			continue;
-		}
 
 		pr_info("PCI/MSI: %s domain created\n", np->full_name);
 	}
 
 	return 0;
 }
+
+static int __init its_pci_msi_init(void)
+{
+	its_pci_of_msi_init();
+
+	return 0;
+}
 early_initcall(its_pci_msi_init);
-- 
1.9.1

^ permalink raw reply related

* [PATCH V11 6/8] irqchip/gicv3-its: Probe ITS in the ACPI way
From: Tomasz Nowicki @ 2016-09-12 18:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473705147-6588-1-git-send-email-tn@semihalf.com>

ITS is prepared for being initialized different than DT,
therefore we can initialize it in ACPI way. We collect register base
address from MADT table and pass mandatory info to firmware-agnostic
ITS init call.

Use here IORT lib to register ITS domain which then can be found and
used on to build another PCI MSI domain in hierarchical stack domain.

NOTE: Waiting for proper ITS and NUMA node relation description in IORT
table, we pass around NUMA_NO_NODE to the its_probe_one init call.
This means that Cavium ThunderX erratum 23144 (pass1.1 only)
is not supported for ACPI boot method yet.

Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 drivers/irqchip/Kconfig          |  1 +
 drivers/irqchip/irq-gic-v3-its.c | 61 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 7f87289..9aeea1d 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -39,6 +39,7 @@ config ARM_GIC_V3_ITS
 	bool
 	depends on PCI
 	depends on PCI_MSI
+	select ACPI_IORT if ACPI
 
 config ARM_NVIC
 	bool
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index c7518c7..35c851c 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -15,10 +15,13 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/acpi.h>
 #include <linux/bitmap.h>
 #include <linux/cpu.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/acpi_iort.h>
 #include <linux/log2.h>
 #include <linux/mm.h>
 #include <linux/msi.h>
@@ -1438,6 +1441,11 @@ static int its_irq_gic_domain_alloc(struct irq_domain *domain,
 		fwspec.param[0] = GIC_IRQ_TYPE_LPI;
 		fwspec.param[1] = hwirq;
 		fwspec.param[2] = IRQ_TYPE_EDGE_RISING;
+	} else if (is_fwnode_irqchip(domain->parent->fwnode)) {
+		fwspec.fwnode = domain->parent->fwnode;
+		fwspec.param_count = 2;
+		fwspec.param[0] = hwirq;
+		fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
 	} else {
 		return -EINVAL;
 	}
@@ -1797,6 +1805,57 @@ static int __init its_of_probe(struct device_node *node)
 	return 0;
 }
 
+#ifdef CONFIG_ACPI
+
+#define ACPI_GICV3_ITS_MEM_SIZE (SZ_128K)
+
+static int __init gic_acpi_parse_madt_its(struct acpi_subtable_header *header,
+					  const unsigned long end)
+{
+	struct acpi_madt_generic_translator *its_entry;
+	struct fwnode_handle *dom_handle;
+	struct resource res;
+	int err;
+
+	its_entry = (struct acpi_madt_generic_translator *)header;
+	memset(&res, 0, sizeof(res));
+	res.start = its_entry->base_address;
+	res.end = its_entry->base_address + ACPI_GICV3_ITS_MEM_SIZE - 1;
+	res.flags = IORESOURCE_MEM;
+
+	dom_handle = irq_domain_alloc_fwnode((void *)its_entry->base_address);
+	if (!dom_handle) {
+		pr_err("ITS@%pa: Unable to allocate GICv3 ITS domain token\n",
+		       &res.start);
+		return -ENOMEM;
+	}
+
+	err = iort_register_domain_token(its_entry->translation_id, dom_handle);
+	if (err) {
+		pr_err("ITS@%pa: Unable to register GICv3 ITS domain token (ITS ID %d) to IORT\n",
+		       &res.start, its_entry->translation_id);
+		goto dom_err;
+	}
+
+	err = its_probe_one(&res, dom_handle, NUMA_NO_NODE);
+	if (!err)
+		return 0;
+
+	iort_deregister_domain_token(its_entry->translation_id);
+dom_err:
+	irq_domain_free_fwnode(dom_handle);
+	return err;
+}
+
+static void __init its_acpi_probe(void)
+{
+	acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
+			      gic_acpi_parse_madt_its, 0);
+}
+#else
+static void __init its_acpi_probe(void) { }
+#endif
+
 int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
 		    struct irq_domain *parent_domain)
 {
@@ -1807,7 +1866,7 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
 	if (of_node)
 		its_of_probe(of_node);
 	else
-		return -ENODEV;
+		its_acpi_probe();
 
 	if (list_empty(&its_nodes)) {
 		pr_warn("ITS: No ITS available, not enabling LPIs\n");
-- 
1.9.1

^ permalink raw reply related

* [PATCH V11 5/8] irqchip/gicv3-its: Refactor ITS DT init code to prepare for ACPI
From: Tomasz Nowicki @ 2016-09-12 18:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473705147-6588-1-git-send-email-tn@semihalf.com>

In order to add ACPI support we need to isolate ACPI&DT common code and
move DT logic to corresponding functions. To achieve this we are using
firmware agnostic handle which can be unpacked to either DT or ACPI node.

No functional changes other than a very minor one:
1. Terminate its_init call with -ENODEV for non-DT case which allows
to remove hack from its-gic-v3.c.
2. Fix ITS base register address type (from 'unsigned long' to 'phys_addr_t'),
as a bonus we get nice string formatting.
3. Since there is only one of ITS parent domain convert it to static global
variable and drop the parameter from its_probe_one. Users can refer to it
in more convenient way then.

Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
---
 drivers/irqchip/irq-gic-v3-its.c   | 65 ++++++++++++++++++++++----------------
 drivers/irqchip/irq-gic-v3.c       |  7 ++--
 include/linux/irqchip/arm-gic-v3.h |  4 +--
 3 files changed, 42 insertions(+), 34 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 943442d..c7518c7 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -75,7 +75,7 @@ struct its_node {
 	raw_spinlock_t		lock;
 	struct list_head	entry;
 	void __iomem		*base;
-	unsigned long		phys_base;
+	phys_addr_t		phys_base;
 	struct its_cmd_block	*cmd_base;
 	struct its_cmd_block	*cmd_write;
 	struct its_baser	tables[GITS_BASER_NR_REGS];
@@ -115,6 +115,7 @@ struct its_device {
 static LIST_HEAD(its_nodes);
 static DEFINE_SPINLOCK(its_lock);
 static struct rdists *gic_rdists;
+static struct irq_domain *its_parent;
 
 #define gic_data_rdist()		(raw_cpu_ptr(gic_rdists->rdist))
 #define gic_data_rdist_rd_base()	(gic_data_rdist()->rd_base)
@@ -1614,8 +1615,7 @@ static void its_enable_quirks(struct its_node *its)
 	gic_enable_quirks(iidr, its_quirks, its);
 }
 
-static int its_init_domain(struct device_node *node, struct its_node *its,
-			   struct irq_domain *parent)
+static int its_init_domain(struct fwnode_handle *handle, struct its_node *its)
 {
 	struct irq_domain *inner_domain;
 	struct msi_domain_info *info;
@@ -1624,13 +1624,13 @@ static int its_init_domain(struct device_node *node, struct its_node *its,
 	if (!info)
 		return -ENOMEM;
 
-	inner_domain = irq_domain_add_tree(node, &its_domain_ops, its);
+	inner_domain = irq_domain_create_tree(handle, &its_domain_ops, its);
 	if (!inner_domain) {
 		kfree(info);
 		return -ENOMEM;
 	}
 
-	inner_domain->parent = parent;
+	inner_domain->parent = its_parent;
 	inner_domain->bus_token = DOMAIN_BUS_NEXUS;
 	info->ops = &its_msi_domain_ops;
 	info->data = its;
@@ -1639,43 +1639,35 @@ static int its_init_domain(struct device_node *node, struct its_node *its,
 	return 0;
 }
 
-static int __init its_probe(struct device_node *node,
-			    struct irq_domain *parent)
+static int __init its_probe_one(struct resource *res,
+				struct fwnode_handle *handle, int numa_node)
 {
-	struct resource res;
 	struct its_node *its;
 	void __iomem *its_base;
 	u32 val;
 	u64 baser, tmp;
 	int err;
 
-	err = of_address_to_resource(node, 0, &res);
-	if (err) {
-		pr_warn("%s: no regs?\n", node->full_name);
-		return -ENXIO;
-	}
-
-	its_base = ioremap(res.start, resource_size(&res));
+	its_base = ioremap(res->start, resource_size(res));
 	if (!its_base) {
-		pr_warn("%s: unable to map registers\n", node->full_name);
+		pr_warn("ITS@%pa: Unable to map ITS registers\n", &res->start);
 		return -ENOMEM;
 	}
 
 	val = readl_relaxed(its_base + GITS_PIDR2) & GIC_PIDR2_ARCH_MASK;
 	if (val != 0x30 && val != 0x40) {
-		pr_warn("%s: no ITS detected, giving up\n", node->full_name);
+		pr_warn("ITS@%pa: No ITS detected, giving up\n", &res->start);
 		err = -ENODEV;
 		goto out_unmap;
 	}
 
 	err = its_force_quiescent(its_base);
 	if (err) {
-		pr_warn("%s: failed to quiesce, giving up\n",
-			node->full_name);
+		pr_warn("ITS@%pa: Failed to quiesce, giving up\n", &res->start);
 		goto out_unmap;
 	}
 
-	pr_info("ITS: %s\n", node->full_name);
+	pr_info("ITS %pR\n", res);
 
 	its = kzalloc(sizeof(*its), GFP_KERNEL);
 	if (!its) {
@@ -1687,9 +1679,9 @@ static int __init its_probe(struct device_node *node,
 	INIT_LIST_HEAD(&its->entry);
 	INIT_LIST_HEAD(&its->its_device_list);
 	its->base = its_base;
-	its->phys_base = res.start;
+	its->phys_base = res->start;
 	its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1;
-	its->numa_node = of_node_to_nid(node);
+	its->numa_node = numa_node;
 
 	its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL);
 	if (!its->cmd_base) {
@@ -1736,7 +1728,7 @@ static int __init its_probe(struct device_node *node,
 	writeq_relaxed(0, its->base + GITS_CWRITER);
 	writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR);
 
-	err = its_init_domain(node, its, parent);
+	err = its_init_domain(handle, its);
 	if (err)
 		goto out_free_tables;
 
@@ -1754,7 +1746,7 @@ out_free_its:
 	kfree(its);
 out_unmap:
 	iounmap(its_base);
-	pr_err("ITS: failed probing %s (%d)\n", node->full_name, err);
+	pr_err("ITS@%pa: failed probing (%d)\n", &res->start, err);
 	return err;
 }
 
@@ -1782,10 +1774,10 @@ static struct of_device_id its_device_id[] = {
 	{},
 };
 
-int __init its_init(struct device_node *node, struct rdists *rdists,
-	     struct irq_domain *parent_domain)
+static int __init its_of_probe(struct device_node *node)
 {
 	struct device_node *np;
+	struct resource res;
 
 	for (np = of_find_matching_node(node, its_device_id); np;
 	     np = of_find_matching_node(np, its_device_id)) {
@@ -1795,8 +1787,27 @@ int __init its_init(struct device_node *node, struct rdists *rdists,
 			continue;
 		}
 
-		its_probe(np, parent_domain);
+		if (of_address_to_resource(np, 0, &res)) {
+			pr_warn("%s: no regs?\n", np->full_name);
+			continue;
+		}
+
+		its_probe_one(&res, &np->fwnode, of_node_to_nid(np));
 	}
+	return 0;
+}
+
+int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
+		    struct irq_domain *parent_domain)
+{
+	struct device_node *of_node;
+
+	its_parent = parent_domain;
+	of_node = to_of_node(handle);
+	if (of_node)
+		its_of_probe(of_node);
+	else
+		return -ENODEV;
 
 	if (list_empty(&its_nodes)) {
 		pr_warn("ITS: No ITS available, not enabling LPIs\n");
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index ede5672..1efc02a 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -910,7 +910,6 @@ static int __init gic_init_bases(void __iomem *dist_base,
 				 u64 redist_stride,
 				 struct fwnode_handle *handle)
 {
-	struct device_node *node;
 	u32 typer;
 	int gic_irqs;
 	int err;
@@ -951,10 +950,8 @@ static int __init gic_init_bases(void __iomem *dist_base,
 
 	set_handle_irq(gic_handle_irq);
 
-	node = to_of_node(handle);
-	if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis() &&
-	    node) /* Temp hack to prevent ITS init for ACPI */
-		its_init(node, &gic_data.rdists, gic_data.domain);
+	if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis())
+		its_init(handle, &gic_data.rdists, gic_data.domain);
 
 	gic_smp_init();
 	gic_dist_init();
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 99ac022..8361c8d 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -430,9 +430,9 @@ struct rdists {
 };
 
 struct irq_domain;
-struct device_node;
+struct fwnode_handle;
 int its_cpu_init(void);
-int its_init(struct device_node *node, struct rdists *rdists,
+int its_init(struct fwnode_handle *handle, struct rdists *rdists,
 	     struct irq_domain *domain);
 
 static inline bool gic_enable_sre(void)
-- 
1.9.1

^ permalink raw reply related

* [PATCH V11 4/8] irqchip/gicv3-its: Cleanup for ITS domain initialization
From: Tomasz Nowicki @ 2016-09-12 18:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473705147-6588-1-git-send-email-tn@semihalf.com>

There is no point to initialize ITS without having msi-controller
property in corresponding DT node. However, its_probe is checking
msi-controller presence at the end, so we can save our time and do that
check prior to its_probe call. Also, for the code clarity purpose,
we put domain initialization to separate function.

Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 drivers/irqchip/irq-gic-v3-its.c | 57 ++++++++++++++++++++++++----------------
 1 file changed, 34 insertions(+), 23 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 36b9c28..943442d 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -1614,13 +1614,37 @@ static void its_enable_quirks(struct its_node *its)
 	gic_enable_quirks(iidr, its_quirks, its);
 }
 
+static int its_init_domain(struct device_node *node, struct its_node *its,
+			   struct irq_domain *parent)
+{
+	struct irq_domain *inner_domain;
+	struct msi_domain_info *info;
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	inner_domain = irq_domain_add_tree(node, &its_domain_ops, its);
+	if (!inner_domain) {
+		kfree(info);
+		return -ENOMEM;
+	}
+
+	inner_domain->parent = parent;
+	inner_domain->bus_token = DOMAIN_BUS_NEXUS;
+	info->ops = &its_msi_domain_ops;
+	info->data = its;
+	inner_domain->host_data = info;
+
+	return 0;
+}
+
 static int __init its_probe(struct device_node *node,
 			    struct irq_domain *parent)
 {
 	struct resource res;
 	struct its_node *its;
 	void __iomem *its_base;
-	struct irq_domain *inner_domain;
 	u32 val;
 	u64 baser, tmp;
 	int err;
@@ -1712,28 +1736,9 @@ static int __init its_probe(struct device_node *node,
 	writeq_relaxed(0, its->base + GITS_CWRITER);
 	writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR);
 
-	if (of_property_read_bool(node, "msi-controller")) {
-		struct msi_domain_info *info;
-
-		info = kzalloc(sizeof(*info), GFP_KERNEL);
-		if (!info) {
-			err = -ENOMEM;
-			goto out_free_tables;
-		}
-
-		inner_domain = irq_domain_add_tree(node, &its_domain_ops, its);
-		if (!inner_domain) {
-			err = -ENOMEM;
-			kfree(info);
-			goto out_free_tables;
-		}
-
-		inner_domain->parent = parent;
-		inner_domain->bus_token = DOMAIN_BUS_NEXUS;
-		info->ops = &its_msi_domain_ops;
-		info->data = its;
-		inner_domain->host_data = info;
-	}
+	err = its_init_domain(node, its, parent);
+	if (err)
+		goto out_free_tables;
 
 	spin_lock(&its_lock);
 	list_add(&its->entry, &its_nodes);
@@ -1784,6 +1789,12 @@ int __init its_init(struct device_node *node, struct rdists *rdists,
 
 	for (np = of_find_matching_node(node, its_device_id); np;
 	     np = of_find_matching_node(np, its_device_id)) {
+		if (!of_property_read_bool(np, "msi-controller")) {
+			pr_warn("%s: no msi-controller property, ITS ignored\n",
+				np->full_name);
+			continue;
+		}
+
 		its_probe(np, parent_domain);
 	}
 
-- 
1.9.1

^ permalink raw reply related

* [PATCH V11 3/8] PCI/MSI: Setup MSI domain on a per-device basis using IORT ACPI table
From: Tomasz Nowicki @ 2016-09-12 18:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473705147-6588-1-git-send-email-tn@semihalf.com>

It is possible to provide information about which MSI controller to
use on a per-device basis for DT. This patch supply this with ACPI support.

Currently, IORT is the only one ACPI table which can provide such mapping.
In order to plug IORT into MSI infrastructure we are adding ACPI
equivalents for finding PCI device domain and its RID translation
(pci_msi_domain_get_msi_rid and pci_msi_domain_get_msi_rid calls).

Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
---
 drivers/pci/msi.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 98f1222..137b4c5 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -19,6 +19,7 @@
 #include <linux/smp.h>
 #include <linux/errno.h>
 #include <linux/io.h>
+#include <linux/acpi_iort.h>
 #include <linux/slab.h>
 #include <linux/irqdomain.h>
 #include <linux/of_irq.h>
@@ -1502,8 +1503,8 @@ u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev)
 	pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
 
 	of_node = irq_domain_get_of_node(domain);
-	if (of_node)
-		rid = of_msi_map_rid(&pdev->dev, of_node, rid);
+	rid = of_node ? of_msi_map_rid(&pdev->dev, of_node, rid) :
+			iort_msi_map_rid(&pdev->dev, rid);
 
 	return rid;
 }
@@ -1519,9 +1520,13 @@ u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev)
  */
 struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev)
 {
+	struct irq_domain *dom;
 	u32 rid = 0;
 
 	pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
-	return of_msi_map_get_device_domain(&pdev->dev, rid);
+	dom = of_msi_map_get_device_domain(&pdev->dev, rid);
+	if (!dom)
+		dom = iort_get_device_domain(&pdev->dev, rid);
+	return dom;
 }
 #endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
-- 
1.9.1

^ permalink raw reply related

* [PATCH V11 2/8] ACPI: Add new IORT functions to support MSI domain handling
From: Tomasz Nowicki @ 2016-09-12 18:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473705147-6588-1-git-send-email-tn@semihalf.com>

For ITS, MSI functionality consists on building domain stack and
during that process we need to reference to domain stack components
e.g. before we create new DOMAIN_BUS_PCI_MSI domain we need to specify
its DOMAIN_BUS_NEXUS parent domain. In order to manage that process
properly, maintain list which elements contain domain token
(unique for MSI domain stack) and ITS ID: iort_register_domain_token()
and iort_deregister_domain_token(). Then retrieve domain token
any time later with ITS ID being key off: iort_find_domain_token().
With domain token and domain type we are able to find corresponding
IRQ domain.

Since IORT is prepared to describe MSI domain on a per-device basis,
use existing IORT helpers and implement two calls:
1. iort_msi_map_rid() to map MSI RID for a device
2. iort_get_device_domain() to find domain token for a device

Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
Acked-by: Rafael J. Wysocki <rjw@rjwysocki.net>
Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>
---
 drivers/acpi/arm64/iort.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/acpi_iort.h |  12 ++++
 2 files changed, 164 insertions(+)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 3eaeb66..c669fdab 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -22,6 +22,12 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 
+struct iort_its_msi_chip {
+	struct list_head	list;
+	struct fwnode_handle	*fw_node;
+	u32			translation_id;
+};
+
 typedef acpi_status (*iort_find_node_callback)
 	(struct acpi_iort_node *node, void *context);
 
@@ -31,6 +37,76 @@ static struct acpi_table_header *iort_table;
 static LIST_HEAD(iort_msi_chip_list);
 static DEFINE_SPINLOCK(iort_msi_chip_lock);
 
+/**
+ * iort_register_domain_token() - register domain token and related ITS ID
+ * to the list from where we can get it back later on.
+ * @trans_id: ITS ID.
+ * @fw_node: Domain token.
+ *
+ * Returns: 0 on success, -ENOMEM if no memory when allocating list element
+ */
+int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node)
+{
+	struct iort_its_msi_chip *its_msi_chip;
+
+	its_msi_chip = kzalloc(sizeof(*its_msi_chip), GFP_KERNEL);
+	if (!its_msi_chip)
+		return -ENOMEM;
+
+	its_msi_chip->fw_node = fw_node;
+	its_msi_chip->translation_id = trans_id;
+
+	spin_lock(&iort_msi_chip_lock);
+	list_add(&its_msi_chip->list, &iort_msi_chip_list);
+	spin_unlock(&iort_msi_chip_lock);
+
+	return 0;
+}
+
+/**
+ * iort_deregister_domain_token() - Deregister domain token based on ITS ID
+ * @trans_id: ITS ID.
+ *
+ * Returns: none.
+ */
+void iort_deregister_domain_token(int trans_id)
+{
+	struct iort_its_msi_chip *its_msi_chip, *t;
+
+	spin_lock(&iort_msi_chip_lock);
+	list_for_each_entry_safe(its_msi_chip, t, &iort_msi_chip_list, list) {
+		if (its_msi_chip->translation_id == trans_id) {
+			list_del(&its_msi_chip->list);
+			kfree(its_msi_chip);
+			break;
+		}
+	}
+	spin_unlock(&iort_msi_chip_lock);
+}
+
+/**
+ * iort_find_domain_token() - Find domain token based on given ITS ID
+ * @trans_id: ITS ID.
+ *
+ * Returns: domain token when find on the list, NULL otherwise
+ */
+struct fwnode_handle *iort_find_domain_token(int trans_id)
+{
+	struct fwnode_handle *fw_node = NULL;
+	struct iort_its_msi_chip *its_msi_chip;
+
+	spin_lock(&iort_msi_chip_lock);
+	list_for_each_entry(its_msi_chip, &iort_msi_chip_list, list) {
+		if (its_msi_chip->translation_id == trans_id) {
+			fw_node = its_msi_chip->fw_node;
+			break;
+		}
+	}
+	spin_unlock(&iort_msi_chip_lock);
+
+	return fw_node;
+}
+
 static struct acpi_iort_node *iort_scan_node(enum acpi_iort_node_type type,
 					     iort_find_node_callback callback,
 					     void *context)
@@ -202,6 +278,82 @@ static struct acpi_iort_node *iort_find_dev_node(struct device *dev)
 			      iort_match_node_callback, &pbus->dev);
 }
 
+/**
+ * iort_msi_map_rid() - Map a MSI requester ID for a device
+ * @dev: The device for which the mapping is to be done.
+ * @req_id: The device requester ID.
+ *
+ * Returns: mapped MSI RID on success, input requester ID otherwise
+ */
+u32 iort_msi_map_rid(struct device *dev, u32 req_id)
+{
+	struct acpi_iort_node *node;
+	u32 dev_id;
+
+	node = iort_find_dev_node(dev);
+	if (!node)
+		return req_id;
+
+	iort_node_map_rid(node, req_id, &dev_id, ACPI_IORT_NODE_ITS_GROUP);
+	return dev_id;
+}
+
+/**
+ * iort_dev_find_its_id() - Find the ITS identifier for a device
+ * @dev: The device.
+ * @idx: Index of the ITS identifier list.
+ * @its_id: ITS identifier.
+ *
+ * Returns: 0 on success, appropriate error value otherwise
+ */
+static int iort_dev_find_its_id(struct device *dev, u32 req_id,
+				unsigned int idx, int *its_id)
+{
+	struct acpi_iort_its_group *its;
+	struct acpi_iort_node *node;
+
+	node = iort_find_dev_node(dev);
+	if (!node)
+		return -ENXIO;
+
+	node = iort_node_map_rid(node, req_id, NULL, ACPI_IORT_NODE_ITS_GROUP);
+	if (!node)
+		return -ENXIO;
+
+	/* Move to ITS specific data */
+	its = (struct acpi_iort_its_group *)node->node_data;
+	if (idx > its->its_count) {
+		dev_err(dev, "requested ITS ID index [%d] is greater than available [%d]\n",
+			idx, its->its_count);
+		return -ENXIO;
+	}
+
+	*its_id = its->identifiers[idx];
+	return 0;
+}
+
+/**
+ * iort_get_device_domain() - Find MSI domain related to a device
+ * @dev: The device.
+ * @req_id: Requester ID for the device.
+ *
+ * Returns: the MSI domain for this device, NULL otherwise
+ */
+struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
+{
+	struct fwnode_handle *handle;
+	int its_id;
+
+	if (iort_dev_find_its_id(dev, req_id, 0, &its_id))
+		return NULL;
+
+	handle = iort_find_domain_token(its_id);
+	if (!handle)
+		return NULL;
+
+	return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
+}
+
 void __init acpi_iort_init(void)
 {
 	acpi_status status;
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index fcacaf7..0e32dac 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -20,11 +20,23 @@
 #define __ACPI_IORT_H__
 
 #include <linux/acpi.h>
+#include <linux/fwnode.h>
+#include <linux/irqdomain.h>
 
+int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
+void iort_deregister_domain_token(int trans_id);
+struct fwnode_handle *iort_find_domain_token(int trans_id);
 #ifdef CONFIG_ACPI_IORT
 void acpi_iort_init(void);
+u32 iort_msi_map_rid(struct device *dev, u32 req_id);
+struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
 #else
 static inline void acpi_iort_init(void) { }
+static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
+{ return req_id; }
+static inline struct irq_domain *iort_get_device_domain(struct device *dev,
+							u32 req_id)
+{ return NULL; }
 #endif
 
 #endif /* __ACPI_IORT_H__ */
-- 
1.9.1

^ permalink raw reply related

* [PATCH V11 1/8] ACPI: I/O Remapping Table (IORT) initial support
From: Tomasz Nowicki @ 2016-09-12 18:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473705147-6588-1-git-send-email-tn@semihalf.com>

IORT shows representation of IO topology for ARM based systems.
It describes how various components are connected together on
parent-child basis e.g. PCI RC -> SMMU -> ITS. Also see IORT spec.
http://infocenter.arm.com/help/topic/com.arm.doc.den0049b/DEN0049B_IO_Remapping_Table.pdf

Initial support allows to detect IORT table presence and save its
root pointer obtained through acpi_get_table(). The pointer validity
depends on acpi_gbl_permanent_mmap because if acpi_gbl_permanent_mmap
is not set while using IORT nodes we would dereference unmapped pointers.

For the aforementioned reason call acpi_iort_init() from acpi_init()
which guarantees acpi_gbl_permanent_mmap to be set at that point.

Add generic helpers which are helpful for scanning and retrieving
information from IORT table content. List of the most important helpers:
- iort_find_dev_node() finds IORT node for a given device
- iort_node_map_rid() maps device RID and returns IORT node which provides
  final translation

IORT support is placed under drivers/acpi/arm64/ new directory due to its
ARM64 specific nature. The code there is considered only for ARM64.
The long term plan is to keep all ARM64 specific tables support
in this place e.g. GTDT table.

Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
Acked-by: Rafael J. Wysocki <rjw@rjwysocki.net>
Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>
Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
---
 drivers/acpi/Kconfig        |   4 +
 drivers/acpi/Makefile       |   2 +
 drivers/acpi/arm64/Kconfig  |   6 ++
 drivers/acpi/arm64/Makefile |   1 +
 drivers/acpi/arm64/iort.c   | 214 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/acpi/bus.c          |   2 +
 include/linux/acpi_iort.h   |  30 +++++++
 7 files changed, 259 insertions(+)
 create mode 100644 drivers/acpi/arm64/Kconfig
 create mode 100644 drivers/acpi/arm64/Makefile
 create mode 100644 drivers/acpi/arm64/iort.c
 create mode 100644 include/linux/acpi_iort.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 445ce28..d5c0614 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -521,4 +521,8 @@ config ACPI_CONFIGFS
 	  userspace. The configurable ACPI groups will be visible under
 	  /config/acpi, assuming configfs is mounted under /config.
 
+if ARM64
+source "drivers/acpi/arm64/Kconfig"
+endif
+
 endif	# ACPI
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 5ae9d85..e5ada78 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -105,3 +105,5 @@ obj-$(CONFIG_ACPI_CONFIGFS)	+= acpi_configfs.o
 
 video-objs			+= acpi_video.o video_detect.o
 obj-y				+= dptf/
+
+obj-$(CONFIG_ARM64)		+= arm64/
diff --git a/drivers/acpi/arm64/Kconfig b/drivers/acpi/arm64/Kconfig
new file mode 100644
index 0000000..4616da4
--- /dev/null
+++ b/drivers/acpi/arm64/Kconfig
@@ -0,0 +1,6 @@
+#
+# ACPI Configuration for ARM64
+#
+
+config ACPI_IORT
+	bool
diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile
new file mode 100644
index 0000000..72331f2
--- /dev/null
+++ b/drivers/acpi/arm64/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ACPI_IORT) 	+= iort.o
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
new file mode 100644
index 0000000..3eaeb66
--- /dev/null
+++ b/drivers/acpi/arm64/iort.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2016, Semihalf
+ *	Author: Tomasz Nowicki <tn@semihalf.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * This file implements early detection/parsing of I/O mapping
+ * reported to OS through firmware via I/O Remapping Table (IORT)
+ * IORT document number: ARM DEN 0049A
+ */
+
+#define pr_fmt(fmt)	"ACPI: IORT: " fmt
+
+#include <linux/acpi_iort.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+typedef acpi_status (*iort_find_node_callback)
+	(struct acpi_iort_node *node, void *context);
+
+/* Root pointer to the mapped IORT table */
+static struct acpi_table_header *iort_table;
+
+static LIST_HEAD(iort_msi_chip_list);
+static DEFINE_SPINLOCK(iort_msi_chip_lock);
+
+static struct acpi_iort_node *iort_scan_node(enum acpi_iort_node_type type,
+					     iort_find_node_callback callback,
+					     void *context)
+{
+	struct acpi_iort_node *iort_node, *iort_end;
+	struct acpi_table_iort *iort;
+	int i;
+
+	if (!iort_table)
+		return NULL;
+
+	/* Get the first IORT node */
+	iort = (struct acpi_table_iort *)iort_table;
+	iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort,
+				 iort->node_offset);
+	iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+				iort_table->length);
+
+	for (i = 0; i < iort->node_count; i++) {
+		if (WARN_TAINT(iort_node >= iort_end, TAINT_FIRMWARE_WORKAROUND,
+			       "IORT node pointer overflows, bad table!\n"))
+			return NULL;
+
+		if (iort_node->type == type &&
+		    ACPI_SUCCESS(callback(iort_node, context)))
+				return iort_node;
+
+		iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
+					 iort_node->length);
+	}
+
+	return NULL;
+}
+
+static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
+					    void *context)
+{
+	struct device *dev = context;
+	acpi_status status;
+
+	if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
+		struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
+		struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
+		struct acpi_iort_named_component *ncomp;
+
+		if (!adev) {
+			status = AE_NOT_FOUND;
+			goto out;
+		}
+
+		status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &buf);
+		if (ACPI_FAILURE(status)) {
+			dev_warn(dev, "Can't get device full path name\n");
+			goto out;
+		}
+
+		ncomp = (struct acpi_iort_named_component *)node->node_data;
+		status = !strcmp(ncomp->device_name, buf.pointer) ?
+							AE_OK : AE_NOT_FOUND;
+		acpi_os_free(buf.pointer);
+	} else if (node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
+		struct acpi_iort_root_complex *pci_rc;
+		struct pci_bus *bus;
+
+		bus = to_pci_bus(dev);
+		pci_rc = (struct acpi_iort_root_complex *)node->node_data;
+
+		/*
+		 * It is assumed that PCI segment numbers maps one-to-one
+		 * with root complexes. Each segment number can represent only
+		 * one root complex.
+		 */
+		status = pci_rc->pci_segment_number == pci_domain_nr(bus) ?
+							AE_OK : AE_NOT_FOUND;
+	}
+out:
+	return status;
+}
+
+static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
+		       u32 *rid_out)
+{
+	/* Single mapping does not care for input id */
+	if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) {
+		if (type == ACPI_IORT_NODE_NAMED_COMPONENT ||
+		    type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
+			*rid_out = map->output_base;
+			return 0;
+		}
+
+		pr_warn(FW_BUG "[map %p] SINGLE MAPPING flag not allowed for node type %d, skipping ID map\n",
+			map, type);
+		return -ENXIO;
+	}
+
+	if (rid_in < map->input_base ||
+	    (rid_in >= map->input_base + map->id_count))
+		return -ENXIO;
+
+	*rid_out = map->output_base + (rid_in - map->input_base);
+	return 0;
+}
+
+static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
+						u32 rid_in, u32 *rid_out,
+						u8 type)
+{
+	u32 rid = rid_in;
+
+	/* Parse the ID mapping tree to find specified node type */
+	while (node) {
+		struct acpi_iort_id_mapping *map;
+		int i;
+
+		if (node->type == type) {
+			if (rid_out)
+				*rid_out = rid;
+			return node;
+		}
+
+		if (!node->mapping_offset || !node->mapping_count)
+			goto fail_map;
+
+		map = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
+				   node->mapping_offset);
+
+		/* Firmware bug! */
+		if (!map->output_reference) {
+			pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
+			       node, node->type);
+			goto fail_map;
+		}
+
+		/* Do the RID translation */
+		for (i = 0; i < node->mapping_count; i++, map++) {
+			if (!iort_id_map(map, node->type, rid, &rid))
+				break;
+		}
+
+		if (i == node->mapping_count)
+			goto fail_map;
+
+		node = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+				    map->output_reference);
+	}
+
+fail_map:
+	/* Map input RID to output RID unchanged on mapping failure*/
+	if (rid_out)
+		*rid_out = rid_in;
+
+	return NULL;
+}
+
+static struct acpi_iort_node *iort_find_dev_node(struct device *dev)
+{
+	struct pci_bus *pbus;
+
+	if (!dev_is_pci(dev))
+		return iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
+				      iort_match_node_callback, dev);
+
+	/* Find a PCI root bus */
+	pbus = to_pci_dev(dev)->bus;
+	while (!pci_is_root_bus(pbus))
+		pbus = pbus->parent;
+
+	return iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
+			      iort_match_node_callback, &pbus->dev);
+}
+
+void __init acpi_iort_init(void)
+{
+	acpi_status status;
+
+	status = acpi_get_table(ACPI_SIG_IORT, 0, &iort_table);
+	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+		const char *msg = acpi_format_exception(status);
+		pr_err("Failed to get table, %s\n", msg);
+	}
+}
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 85b7d07..e56e643 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -36,6 +36,7 @@
 #ifdef CONFIG_X86
 #include <asm/mpspec.h>
 #endif
+#include <linux/acpi_iort.h>
 #include <linux/pci.h>
 #include <acpi/apei.h>
 #include <linux/dmi.h>
@@ -1186,6 +1187,7 @@ static int __init acpi_init(void)
 	}
 
 	pci_mmcfg_late_init();
+	acpi_iort_init();
 	acpi_scan_init();
 	acpi_ec_init();
 	acpi_debugfs_init();
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
new file mode 100644
index 0000000..fcacaf7
--- /dev/null
+++ b/include/linux/acpi_iort.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016, Semihalf
+ *	Author: Tomasz Nowicki <tn@semihalf.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef __ACPI_IORT_H__
+#define __ACPI_IORT_H__
+
+#include <linux/acpi.h>
+
+#ifdef CONFIG_ACPI_IORT
+void acpi_iort_init(void);
+#else
+static inline void acpi_iort_init(void) { }
+#endif
+
+#endif /* __ACPI_IORT_H__ */
-- 
1.9.1

^ permalink raw reply related

* [PATCH V11 0/8] Introduce ACPI world to ITS irqchip
From: Tomasz Nowicki @ 2016-09-12 18:32 UTC (permalink / raw)
  To: linux-arm-kernel

The series builds the PCI/MSI domain stack based on initial IORT driver
which is added in first place. As a reference please see IORT spec:
http://infocenter.arm.com/help/topic/com.arm.doc.den0049b/DEN0049B_IO_Remapping_Table.pdf

Tested on Cavium ThunderX server and Qualcomm Technologies server platform QDF2XXX.
The patches can be found here:
https://github.com/semihalf-nowicki-tomasz/linux.git (its-acpi-v11)

v10 -> v11
- rebased against v4.8-rc6
- bug fix for iort_match_node_callback() error handling
- patch 1-2 changelog updates

v9 -> v10
- error handling improvements for iort_match_node_callback() but no functional changes
- iort.h -> acpi_iort.h header name change
- style improvements

v8 -> v9
- rebased against v4.8-rc4
- move root IORT pointer validation to one place iort_scan_node()
- function names & Kconfig option name improvements
- remove annoying dev_err() appearances for non-IORT users
- for debug purpose print full ITS resource range

v7 -> v8
- rebased against v4.8-rc1
- move IORT support under new drivers/acpi/arm64 directory
- memory leak fix for iort_match_node_callback()
- iort_node_map_rid() algorithm improvements
- fix RID match check in iort_id_map()
- fix typos and white spaces

v6 -> v7
- rebased against irq/irqchip-4.8
- improvements for IORT ID mapping
- call IORT init call from acpi_init() instead of arch_initcall()
- split IORT driver in to two parts: core and ITS/MSI

v5 -> v6
- added locking mechanism for IORT list with domain token
- IORT function name improvements
- extended IORT RID mapping helper
- reworked IORT to be more SMMU friendly
- IORT functions which map RID and find corresponding domain are not
  PCI specific any more (struct pci_dev -> struct device)
- bug fixes

v4 -> v5
- rebased against v4.7-rc1
- drop generic layer and call IORT functions directly
- improve resource abstraction and string formatting

v3 -> v4
- rebased against v4.5
- add ACPI support for IRQ domain handling on a per-device basis
- reorder domain setup step
- improve error handling
- code style improvements

v2 -> v3
- rebased on top of 4.4
- fixes and improvements for redistributor init via GICC structures
- fixes as per kbuild reports

v1 -> v2
- rebased on top of 4.4-rc4
- use pci_msi_domain_get_msi_rid for requester ID to device ID translation

Tomasz Nowicki (8):
  ACPI: I/O Remapping Table (IORT) initial support
  ACPI: Add new IORT functions to support MSI domain handling
  PCI/MSI: Setup MSI domain on a per-device basis using IORT ACPI table
  irqchip/gicv3-its: Cleanup for ITS domain initialization
  irqchip/gicv3-its: Refactor ITS DT init code to prepare for ACPI
  irqchip/gicv3-its: Probe ITS in the ACPI way
  irqchip/gicv3-its: Factor out PCI-MSI part that might be reused for
    ACPI
  irqchip/gicv3-its: Use MADT ITS subtable to do PCI/MSI domain
    initialization

 drivers/acpi/Kconfig                     |   4 +
 drivers/acpi/Makefile                    |   2 +
 drivers/acpi/arm64/Kconfig               |   6 +
 drivers/acpi/arm64/Makefile              |   1 +
 drivers/acpi/arm64/iort.c                | 366 +++++++++++++++++++++++++++++++
 drivers/acpi/bus.c                       |   2 +
 drivers/irqchip/Kconfig                  |   1 +
 drivers/irqchip/irq-gic-v3-its-pci-msi.c |  88 ++++++--
 drivers/irqchip/irq-gic-v3-its.c         | 171 +++++++++++----
 drivers/irqchip/irq-gic-v3.c             |   7 +-
 drivers/pci/msi.c                        |  11 +-
 include/linux/acpi_iort.h                |  42 ++++
 include/linux/irqchip/arm-gic-v3.h       |   4 +-
 13 files changed, 635 insertions(+), 70 deletions(-)
 create mode 100644 drivers/acpi/arm64/Kconfig
 create mode 100644 drivers/acpi/arm64/Makefile
 create mode 100644 drivers/acpi/arm64/iort.c
 create mode 100644 include/linux/acpi_iort.h

-- 
1.9.1

^ permalink raw reply

* [PATCH v5] i2c: imx: make bus recovery through pinctrl optional
From: Leo Li @ 2016-09-12 18:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CADRPPNSLZ-Ck+40LZLdpEXPaBm+61AtrpRPgAcTCojWSsTBQDw@mail.gmail.com>

On Mon, Sep 12, 2016 at 11:35 AM, Leo Li <pku.leo@gmail.com> wrote:
> On Wed, Sep 7, 2016 at 5:07 AM, Tracy Smith <tlsmith3777@gmail.com> wrote:
>> Hello, bus recovery is needed generally speaking because of potential
>> protocol errors that might cause a failure condition hanging the bus.
>>
>> It happens frequently during bring-up of new I2C devices because firmware in
>> I2C controllers fail to handle properly protocol errors.
>>
>> Can NXP add bus recovery for the LS1021A and LS1043A in a separate patch--
>> unless there is no HW bus recovery mechanism?
>>
>> The concern is while fixing I.MX, NXP will fail to fix the driver bus
>> recovery for the LS1021A and LS1043A and the bus will hang.
>>
>> If bus recovery is supported on the LS1021A and the LS1043A, a patch should
>> be provided or added in this patch instead of simply disabling bus recovery.
>> Request NXP to consider the patch if there is HW support for bus recovery.
>
> FYI.  http://patchwork.ozlabs.org/patch/573879/

Hi Gao Pan,

Do you think the operations in the proposed patch is also usable on
the I.MX SoC for bus recovery?  If so, would it be better to align the
bus recovery implementation for both I.MX and QorIQ to use the same
logic inside the IP?

Regards,
Leo

^ permalink raw reply

* [PATCH v2 6/6] ARM: dts: bcm283x: add pinctrl group to &sdhci, drop pins from &gpio
From: Stefan Wahren @ 2016-09-12 18:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473668576-22256-7-git-send-email-kraxel@redhat.com>

Hi Gerd,

> Gerd Hoffmann <kraxel@redhat.com> hat am 12. September 2016 um 10:22
> geschrieben:
> 
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  arch/arm/boot/dts/bcm2835-rpi.dtsi | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi
> b/arch/arm/boot/dts/bcm2835-rpi.dtsi
> index 8688204..3f0ce61 100644
> --- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
> +++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
> @@ -43,7 +43,7 @@
>  	};
>  
>  	alt3: alt3 {
> -		brcm,pins = <48 49 50 51 52 53>;
> +		brcm,pins = <>;

after dropping all pins from the group alt3 doesn't make sense anymore. I think
this should be removed completely.

>  		brcm,function = <BCM2835_FSEL_ALT3>;
>  	};
>  };
> @@ -67,6 +67,8 @@
>  };
>  
>  &sdhci {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&emmc_gpio48>;
>  	status = "okay";
>  	bus-width = <4>;
>  };
> -- 
> 1.8.3.1
> 
> 
> _______________________________________________
> linux-rpi-kernel mailing list
> linux-rpi-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rpi-kernel

^ permalink raw reply

* [PATCH v3 3/3] arm64: dts: xgene: Add DT node for APM X-Gene 2 CPU clocks
From: Hoan Tran @ 2016-09-12 18:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473704605-28126-1-git-send-email-hotran@apm.com>

Add DT nodes to enable APM X-Gene 2 CPU clocks.

Signed-off-by: Hoan Tran <hotran@apm.com>
---
 arch/arm64/boot/dts/apm/apm-shadowcat.dtsi | 56 ++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi b/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi
index 1425ed4..7b31895 100644
--- a/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi
+++ b/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi
@@ -26,6 +26,8 @@
 			enable-method = "spin-table";
 			cpu-release-addr = <0x1 0x0000fff8>;
 			next-level-cache = <&xgene_L2_0>;
+			#clock-cells = <1>;
+			clocks = <&pmd0clk 0>;
 		};
 		cpu at 001 {
 			device_type = "cpu";
@@ -34,6 +36,8 @@
 			enable-method = "spin-table";
 			cpu-release-addr = <0x1 0x0000fff8>;
 			next-level-cache = <&xgene_L2_0>;
+			#clock-cells = <1>;
+			clocks = <&pmd0clk 0>;
 		};
 		cpu at 100 {
 			device_type = "cpu";
@@ -42,6 +46,8 @@
 			enable-method = "spin-table";
 			cpu-release-addr = <0x1 0x0000fff8>;
 			next-level-cache = <&xgene_L2_1>;
+			#clock-cells = <1>;
+			clocks = <&pmd1clk 0>;
 		};
 		cpu at 101 {
 			device_type = "cpu";
@@ -50,6 +56,8 @@
 			enable-method = "spin-table";
 			cpu-release-addr = <0x1 0x0000fff8>;
 			next-level-cache = <&xgene_L2_1>;
+			#clock-cells = <1>;
+			clocks = <&pmd1clk 0>;
 		};
 		cpu at 200 {
 			device_type = "cpu";
@@ -58,6 +66,8 @@
 			enable-method = "spin-table";
 			cpu-release-addr = <0x1 0x0000fff8>;
 			next-level-cache = <&xgene_L2_2>;
+			#clock-cells = <1>;
+			clocks = <&pmd2clk 0>;
 		};
 		cpu at 201 {
 			device_type = "cpu";
@@ -66,6 +76,8 @@
 			enable-method = "spin-table";
 			cpu-release-addr = <0x1 0x0000fff8>;
 			next-level-cache = <&xgene_L2_2>;
+			#clock-cells = <1>;
+			clocks = <&pmd2clk 0>;
 		};
 		cpu at 300 {
 			device_type = "cpu";
@@ -74,6 +86,8 @@
 			enable-method = "spin-table";
 			cpu-release-addr = <0x1 0x0000fff8>;
 			next-level-cache = <&xgene_L2_3>;
+			#clock-cells = <1>;
+			clocks = <&pmd3clk 0>;
 		};
 		cpu at 301 {
 			device_type = "cpu";
@@ -82,6 +96,8 @@
 			enable-method = "spin-table";
 			cpu-release-addr = <0x1 0x0000fff8>;
 			next-level-cache = <&xgene_L2_3>;
+			#clock-cells = <1>;
+			clocks = <&pmd3clk 0>;
 		};
 		xgene_L2_0: l2-cache-0 {
 			compatible = "cache";
@@ -223,6 +239,46 @@
 				clock-output-names = "refclk";
 			};
 
+			pmdpll: pmdpll at 170000f0 {
+				compatible = "apm,xgene-pcppll-v2-clock";
+				#clock-cells = <1>;
+				clocks = <&refclk 0>;
+				reg = <0x0 0x170000f0 0x0 0x10>;
+				clock-output-names = "pmdpll";
+			};
+
+			pmd0clk: pmd0clk at 7e200200 {
+				compatible = "apm,xgene-pmd-clock";
+				#clock-cells = <1>;
+				clocks = <&pmdpll 0>;
+				reg = <0x0 0x7e200200 0x0 0x10>;
+				clock-output-names = "pmd0clk";
+			};
+
+			pmd1clk: pmd1clk at 7e200210 {
+				compatible = "apm,xgene-pmd-clock";
+				#clock-cells = <1>;
+				clocks = <&pmdpll 0>;
+				reg = <0x0 0x7e200210 0x0 0x10>;
+				clock-output-names = "pmd1clk";
+			};
+
+			pmd2clk: pmd2clk at 7e200220 {
+				compatible = "apm,xgene-pmd-clock";
+				#clock-cells = <1>;
+				clocks = <&pmdpll 0>;
+				reg = <0x0 0x7e200220 0x0 0x10>;
+				clock-output-names = "pmd2clk";
+			};
+
+			pmd3clk: pmd3clk at 7e200230 {
+				compatible = "apm,xgene-pmd-clock";
+				#clock-cells = <1>;
+				clocks = <&pmdpll 0>;
+				reg = <0x0 0x7e200230 0x0 0x10>;
+				clock-output-names = "pmd3clk";
+			};
+
 			socpll: socpll at 17000120 {
 				compatible = "apm,xgene-socpll-v2-clock";
 				#clock-cells = <1>;
-- 
1.9.1

^ permalink raw reply related

* [PATCH v3 2/3] clk: xgene: Add PMD clock
From: Hoan Tran @ 2016-09-12 18:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473704605-28126-1-git-send-email-hotran@apm.com>

Add X-Gene PMD clock support.

PMD clock is implemented for a single register field.
  Output rate = parent_rate * (denominator - scale) / denominator
with
  - denominator = bitmask of register field + 1
  - scale = values of register field

For example, for bitmask is 0x7, denominator will be 8 and scale
will be computed and programmed accordingly.

Signed-off-by: Hoan Tran <hotran@apm.com>
---
 drivers/clk/clk-xgene.c | 221 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 221 insertions(+)

diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c
index 3433132..5daddf5 100644
--- a/drivers/clk/clk-xgene.c
+++ b/drivers/clk/clk-xgene.c
@@ -217,6 +217,226 @@ static void xgene_pcppllclk_init(struct device_node *np)
 	xgene_pllclk_init(np, PLL_TYPE_PCP);
 }
 
+/**
+ * struct xgene_clk_pmd - PMD clock
+ *
+ * @hw:		handle between common and hardware-specific interfaces
+ * @reg:	register containing the fractional scale multiplier (scaler)
+ * @shift:	shift to the unit bit field
+ * @denom:	1/denominator unit
+ * @lock:	register lock
+ * Flags:
+ * XGENE_CLK_PMD_SCALE_INVERTED - By default the scaler is the value read
+ *	from the register plus one. For example,
+ *		0 for (0 + 1) / denom,
+ *		1 for (1 + 1) / denom and etc.
+ *	If this flag is set, it is
+ *		0 for (denom - 0) / denom,
+ *		1 for (denom - 1) / denom and etc.
+ *
+ */
+struct xgene_clk_pmd {
+	struct clk_hw	hw;
+	void __iomem	*reg;
+	u8		shift;
+	u32		mask;
+	u64		denom;
+	u32		flags;
+	spinlock_t	*lock;
+};
+
+#define to_xgene_clk_pmd(_hw) container_of(_hw, struct xgene_clk_pmd, hw)
+
+#define XGENE_CLK_PMD_SCALE_INVERTED	BIT(0)
+#define XGENE_CLK_PMD_SHIFT		8
+#define XGENE_CLK_PMD_WIDTH		3
+
+static unsigned long xgene_clk_pmd_recalc_rate(struct clk_hw *hw,
+					       unsigned long parent_rate)
+{
+	struct xgene_clk_pmd *fd = to_xgene_clk_pmd(hw);
+	unsigned long flags = 0;
+	u64 ret, scale;
+	u32 val;
+
+	if (fd->lock)
+		spin_lock_irqsave(fd->lock, flags);
+	else
+		__acquire(fd->lock);
+
+	val = clk_readl(fd->reg);
+
+	if (fd->lock)
+		spin_unlock_irqrestore(fd->lock, flags);
+	else
+		__release(fd->lock);
+
+	ret = (u64)parent_rate;
+
+	scale = (val & fd->mask) >> fd->shift;
+	if (fd->flags & XGENE_CLK_PMD_SCALE_INVERTED)
+		scale = fd->denom - scale;
+	else
+		scale++;
+
+	/* freq = parent_rate * scaler / denom */
+	do_div(ret, fd->denom);
+	ret *= scale;
+	if (ret == 0)
+		ret = (u64)parent_rate;
+
+	return ret;
+}
+
+static long xgene_clk_pmd_round_rate(struct clk_hw *hw, unsigned long rate,
+				     unsigned long *parent_rate)
+{
+	struct xgene_clk_pmd *fd = to_xgene_clk_pmd(hw);
+	u64 ret, scale;
+
+	if (!rate || rate >= *parent_rate)
+		return *parent_rate;
+
+	/* freq = parent_rate * scaler / denom */
+	ret = rate * fd->denom;
+	scale = DIV_ROUND_UP_ULL(ret, *parent_rate);
+
+	ret = (u64)*parent_rate * scale;
+	do_div(ret, fd->denom);
+
+	return ret;
+}
+
+static int xgene_clk_pmd_set_rate(struct clk_hw *hw, unsigned long rate,
+				  unsigned long parent_rate)
+{
+	struct xgene_clk_pmd *fd = to_xgene_clk_pmd(hw);
+	unsigned long flags = 0;
+	u64 scale, ret;
+	u32 val;
+
+	/*
+	 * Compute the scaler:
+	 *
+	 * freq = parent_rate * scaler / denom, or
+	 * scaler = freq * denom / parent_rate
+	 */
+	ret = rate * fd->denom;
+	scale = DIV_ROUND_UP_ULL(ret, (u64)parent_rate);
+
+	/* Check if inverted */
+	if (fd->flags & XGENE_CLK_PMD_SCALE_INVERTED)
+		scale = fd->denom - scale;
+	else
+		scale--;
+
+	if (fd->lock)
+		spin_lock_irqsave(fd->lock, flags);
+	else
+		__acquire(fd->lock);
+
+	val = clk_readl(fd->reg);
+	val &= ~fd->mask;
+	val |= (scale << fd->shift);
+	clk_writel(val, fd->reg);
+
+	if (fd->lock)
+		spin_unlock_irqrestore(fd->lock, flags);
+	else
+		__release(fd->lock);
+
+	return 0;
+}
+
+static const struct clk_ops xgene_clk_pmd_ops = {
+	.recalc_rate = xgene_clk_pmd_recalc_rate,
+	.round_rate = xgene_clk_pmd_round_rate,
+	.set_rate = xgene_clk_pmd_set_rate,
+};
+
+static struct clk *
+xgene_register_clk_pmd(struct device *dev,
+		       const char *name, const char *parent_name,
+		       unsigned long flags, void __iomem *reg, u8 shift,
+		       u8 width, u64 denom, u32 clk_flags, spinlock_t *lock)
+{
+	struct xgene_clk_pmd *fd;
+	struct clk_init_data init;
+	struct clk *clk;
+
+	fd = kzalloc(sizeof(*fd), GFP_KERNEL);
+	if (!fd)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &xgene_clk_pmd_ops;
+	init.flags = flags;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	init.num_parents = parent_name ? 1 : 0;
+
+	fd->reg = reg;
+	fd->shift = shift;
+	fd->mask = (BIT(width) - 1) << shift;
+	fd->denom = denom;
+	fd->flags = clk_flags;
+	fd->lock = lock;
+	fd->hw.init = &init;
+
+	clk = clk_register(dev, &fd->hw);
+	if (IS_ERR(clk)) {
+		pr_err("%s: could not register clk %s\n", __func__, name);
+		kfree(fd);
+		return NULL;
+	}
+
+	return clk;
+}
+
+static void xgene_pmdclk_init(struct device_node *np)
+{
+	const char *clk_name = np->full_name;
+	void __iomem *csr_reg;
+	struct resource res;
+	struct clk *clk;
+	u64 denom;
+	u32 flags = 0;
+	int rc;
+
+	/* Check if the entry is disabled */
+	if (!of_device_is_available(np))
+		return;
+
+	/* Parse the DTS register for resource */
+	rc = of_address_to_resource(np, 0, &res);
+	if (rc != 0) {
+		pr_err("no DTS register for %s\n", np->full_name);
+		return;
+	}
+	csr_reg = of_iomap(np, 0);
+	if (!csr_reg) {
+		pr_err("Unable to map resource for %s\n", np->full_name);
+		return;
+	}
+	of_property_read_string(np, "clock-output-names", &clk_name);
+
+	denom = BIT(XGENE_CLK_PMD_WIDTH);
+	flags |= XGENE_CLK_PMD_SCALE_INVERTED;
+
+	clk = xgene_register_clk_pmd(NULL, clk_name,
+				     of_clk_get_parent_name(np, 0), 0,
+				     csr_reg, XGENE_CLK_PMD_SHIFT,
+				     XGENE_CLK_PMD_WIDTH, denom,
+				     flags, &clk_lock);
+	if (!IS_ERR(clk)) {
+		of_clk_add_provider(np, of_clk_src_simple_get, clk);
+		clk_register_clkdev(clk, clk_name, NULL);
+		pr_debug("Add %s clock\n", clk_name);
+	} else {
+		if (csr_reg)
+			iounmap(csr_reg);
+	}
+}
+
 /* IP Clock */
 struct xgene_dev_parameters {
 	void __iomem *csr_reg;		/* CSR for IP clock */
@@ -543,6 +763,7 @@ err:
 
 CLK_OF_DECLARE(xgene_socpll_clock, "apm,xgene-socpll-clock", xgene_socpllclk_init);
 CLK_OF_DECLARE(xgene_pcppll_clock, "apm,xgene-pcppll-clock", xgene_pcppllclk_init);
+CLK_OF_DECLARE(xgene_pmd_clock, "apm,xgene-pmd-clock", xgene_pmdclk_init);
 CLK_OF_DECLARE(xgene_socpll_v2_clock, "apm,xgene-socpll-v2-clock",
 	       xgene_socpllclk_init);
 CLK_OF_DECLARE(xgene_pcppll_v2_clock, "apm,xgene-pcppll-v2-clock",
-- 
1.9.1

^ permalink raw reply related


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