Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Question: Way to add missing pads & pins into pinctrl driver
From: Alexander Shiyan @ 2013-01-31 13:15 UTC (permalink / raw)
  To: linux-arm-kernel

Hello.

I have found some missing pads and pins definitions in the pinctrl-imx51 driver.
Appending in sort order will break current devicetree configurations, so I want
to know better way for add these definitions. Of course I can just append
at the end, but this will break sort order. How to do it better?
Thanks.

---

^ permalink raw reply

* Failure to boot...
From: Russell King - ARM Linux @ 2013-01-31 13:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <510A6877.9080307@ti.com>

On Thu, Jan 31, 2013 at 06:19:59PM +0530, Santosh Shilimkar wrote:
> On Thursday 31 January 2013 04:10 PM, Russell King - ARM Linux wrote:
>> On Thu, Jan 31, 2013 at 09:20:24AM +0000, Russell King - ARM Linux wrote:
>>> On Wed, Jan 30, 2013 at 11:19:40PM -0500, Nicolas Pitre wrote:
>>>> Better yet (IMHO): just enable the zboot command in U-Boot to let you
>>>> boot a zImage binary directly.
>>>
>>> I wish it were that easy but it isn't.  I've no idea where to get a
>>> version of uboot for my boards which supports that; TI have always
>>> supplied updates to uboot for me, and with the current state of TI
>>> being afaict in chaos.
>>>
>>> TI have always supplied a replacement X-Loader with each uboot update.
>>> I've no idea what X-Loader is or why both get updated together, but...
>>>
>>> Moreover, I doubt that the 3430LDP, of which there are multiple versions,
>>> will ever see a uboot update.  It already suffers from a lack of correct
>>> kernel support due to random wiring changes between these versions (the
>>> keypad doesn't work correctly) and I've yet to indentify which version
>>> it is despite downloading the circuits.  So trying to locate the right
>>> uboot will be impossible there.
>>>
>>> So, I'm _stuck_ with uImages for these platforms.
>>
>> Right, so I'm now passing LOADADDR= which allows this to work - and the
>> latest OMAP4430SDP boot result shows almost the same sad broken story.
>>
> I just tried latest mainline (commit: 04c2eee5) and default config
> just boots fine.

Please read the notes at the bottom of the page, specifically:
 *?Build tree is currently created on an ad-hoc basis from Linus' tip, rmk's
   development tip and arm-soc for-next branches.

This system does *not* build and boot vanilla mainline kernels.  It is
(as the above says):

- Linus' tip
- My for-next plus a few other bits
- arm-soc for-next

all merged together.

Here's the diffstat between my for-next and the remainder of other stuff
that gets built:

 arch/arm/mach-realview/core.c                   |  212 ++++++++
 arch/arm/mach-realview/core.h                   |    2 +
 arch/arm/mach-realview/include/mach/platform.h  |    2 +
 arch/arm/mach-realview/realview_eb.c            |   37 ++-
 arch/arm/mach-realview/realview_pb11mp.c        |   33 ++-
 arch/arm/mach-realview/realview_pba8.c          |    3 +-
 arch/arm/mach-realview/realview_pbx.c           |    3 +-
 arch/arm/mach-versatile/core.c                  |  482 ++++++++++++++++++-
 arch/arm/mach-versatile/include/mach/platform.h |    6 +
 arch/arm/mach-versatile/versatile_pb.c          |   17 +-
 drivers/dma/amba-pl08x.c                        |   26 +-
 drivers/tty/serial/omap-serial.c                |   30 ++
 drivers/tty/serial/serial_core.c                |   23 +-
 include/linux/serial_core.h                     |    2 +
 include/sound/soc-dmaengine.h                   |   26 +
 sound/soc/Kconfig                               |    5 +
 sound/soc/Makefile                              |    3 +
 sound/soc/sa11x0/Kconfig                        |   14 +
 sound/soc/sa11x0/Makefile                       |    5 +
 sound/soc/sa11x0/sa11x0-assabet.c               |  432 +++++++++++++++++
 sound/soc/sa11x0/sa11x0-ssp.c                   |  345 +++++++++++++
 sound/soc/sa11x0/sa11x0-ssp.h                   |   11 +
 sound/soc/soc-dmaengine.c                       |  591 +++++++++++++++++++++++
 23 files changed, 2283 insertions(+), 27 deletions(-)

As far as OMAP goes, that's basically additional bits for serial DMA
support that I was working on, best pieced back together before the
serial driver was majorly reworked a couple of merge windows ago.
These have been there for at least the last three months.

The rest are for SA11x0 Assabet sound support, and DMA support on
Versatile/Realview platforms.

> I was looking at your build system output which shows the boot
> state "OMAP4430 SDP: fail". Your config seems to be with
> CONFIG_ARCH_MULTIPLATFORM=y and indeed this kernel doesn't
> boot. Seems to abort very early in boot. Am looking at it.

Thanks.

> P.S Btw, the load address issue with multi-platform build
> was highlighted on the list in past by Tony [1]
>
> [1] http://www.spinics.net/lists/linux-omap/msg84146.html

That's no good to me if it only goes to linux-omap.

^ permalink raw reply

* [PATCH v4 3/3] ASoC: davinci: remove __dev* attributes
From: Hebbar Gururaja @ 2013-01-31 12:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359636786-7056-1-git-send-email-gururaja.hebbar@ti.com>

CONFIG_HOTPLUG is going away as an option.  As result the __dev*
markings will be going away.

Remove use of __devexit_p and __devexit.

Signed-off-by: Hebbar Gururaja <gururaja.hebbar@ti.com>
---
Changes in v4
	 - No change

Changes in v3
	 - New patch

:100644 100644 e6009a4... 37b8e78... M	sound/soc/davinci/davinci-evm.c
 sound/soc/davinci/davinci-evm.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index e6009a4..37b8e78 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -390,7 +390,7 @@ static int davinci_evm_probe(struct platform_device *pdev)
 	return ret;
 }
 
-static int __devexit davinci_evm_remove(struct platform_device *pdev)
+static int davinci_evm_remove(struct platform_device *pdev)
 {
 	struct snd_soc_card *card = platform_get_drvdata(pdev);
 
@@ -401,7 +401,7 @@ static int __devexit davinci_evm_remove(struct platform_device *pdev)
 
 static struct platform_driver davinci_evm_driver = {
 	.probe		= davinci_evm_probe,
-	.remove		= __devexit_p(davinci_evm_remove),
+	.remove		= davinci_evm_remove,
 	.driver		= {
 		.name	= "davinci_evm",
 		.owner	= THIS_MODULE,
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v4 2/3] ASoC: davinci: machine: Add device tree binding
From: Hebbar Gururaja @ 2013-01-31 12:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359636786-7056-1-git-send-email-gururaja.hebbar@ti.com>

From: "Hebbar, Gururaja" <gururaja.hebbar@ti.com>

Device tree support for Davinci Machine driver

When the board boots with device tree, the driver will receive card,
codec, dai interface details (like the card name, DAPM routing map,
phandle for the audio components described in the dts file, codec mclk
speed).
The card will be set up based on this information.
Since the routing is provided via DT we can mark the card fully routed
so core can take care of disconnecting the unused pins.

Signed-off-by: Hebbar, Gururaja <gururaja.hebbar@ti.com>
---
Changes in v4
	 - No change

Changes in v3
	 - No change

Changes in v2
	 - Remove reference to Linux & software details from DT binding

:000000 100644 0000000... 92ad4c7... A	Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
:100644 100644 484b22c... e6009a4... M	sound/soc/davinci/davinci-evm.c
 .../bindings/sound/davinci-evm-audio.txt           |   53 ++++++
 sound/soc/davinci/davinci-evm.c                    |  179 +++++++++++++++++---
 2 files changed, 212 insertions(+), 20 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
new file mode 100644
index 0000000..92ad4c7
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
@@ -0,0 +1,53 @@
+* Texas Instruments SoC audio setups with TLV320AIC3X Codec
+
+Required properties:
+- compatible :
+	"ti,dm365-voice-codec-audio"	: for DM365 platforms with Voice Codec
+	"ti,da830-evm-audio"		: for DM365/DA8xx/OMAPL1x/AM33xx
+
+- ti,model : The user-visible name of this sound complex.
+- ti,audio-codec : The phandle of the TLV320AIC3x audio codec
+- ti,mcasp-controller : The phandle of the McASP controller
+- ti,codec-clock-rate : The Codec Clock rate (in Hz) applied to the Codec
+- ti,audio-routing : A list of the connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source. Valid names for sources and
+  sinks are the codec's pins, and the jacks on the board:
+
+  Codec pins:
+
+  * MIC3L
+  * MIC3R
+  * LINE1L
+  * LINE2L
+  * LINE1R
+  * LINE2R
+
+  Board connectors:
+
+  * Headphone Jack
+  * Line Out
+  * Mic Jack
+
+
+Example:
+
+sound {
+	compatible = "ti,da830-evm-audio";
+	ti,model = "DA830 EVM";
+	ti,audio-codec = <&tlv320aic3x>;
+	ti,mcasp-controller = <&mcasp1>;
+	ti,codec-clock-rate = <12000000>;
+	ti,audio-routing =
+		"Headphone Jack",       "HPLOUT",
+		"Headphone Jack",       "HPROUT",
+		"Line Out",             "LLOUT",
+		"Line Out",             "RLOUT",
+		"MIC3L",                "Mic Bias",
+		"MIC3R",                "Mic Bias",
+		"Mic Bias",             "Mic Jack",
+		"LINE1L",               "Line In",
+		"LINE2L",               "Line In",
+		"LINE1R",               "Line In",
+		"LINE2R",               "Line In";
+};
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 484b22c..e6009a4 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -15,6 +15,7 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
+#include <linux/of_platform.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
@@ -34,27 +35,38 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_card *soc_card = codec->card;
+	struct device_node *np = soc_card->dev->of_node;
 	int ret = 0;
 	unsigned sysclk;
 
-	/* ASP1 on DM355 EVM is clocked by an external oscillator */
-	if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm() ||
-	    machine_is_davinci_dm365_evm())
-		sysclk = 27000000;
-
-	/* ASP0 in DM6446 EVM is clocked by U55, as configured by
-	 * board-dm644x-evm.c using GPIOs from U18.  There are six
-	 * options; here we "know" we use a 48 KHz sample rate.
-	 */
-	else if (machine_is_davinci_evm())
-		sysclk = 12288000;
-
-	else if (machine_is_davinci_da830_evm() ||
-				machine_is_davinci_da850_evm())
-		sysclk = 24576000;
-
-	else
-		return -EINVAL;
+	if (np) {
+		ret = of_property_read_u32(np, "ti,codec-clock-rate", &sysclk);
+		if (ret < 0)
+			return ret;
+	} else {
+		/* ASP1 on DM355 EVM is clocked by an external oscillator */
+		if (machine_is_davinci_dm355_evm() ||
+			machine_is_davinci_dm6467_evm() ||
+			machine_is_davinci_dm365_evm())
+			sysclk = 27000000;
+
+		/*
+		 * ASP0 in DM6446 EVM is clocked by U55, as configured by
+		 * board-dm644x-evm.c using GPIOs from U18.  There are six
+		 * options; here we "know" we use a 48 KHz sample rate.
+		 */
+		else if (machine_is_davinci_evm())
+			sysclk = 12288000;
+
+		else if (machine_is_davinci_da830_evm() ||
+					machine_is_davinci_da850_evm())
+			sysclk = 24576000;
+
+		else
+			return -EINVAL;
+	}
 
 	/* set codec DAI configuration */
 	ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT);
@@ -132,13 +144,22 @@ static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_soc_codec *codec = rtd->codec;
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct device_node *np = codec->card->dev->of_node;
+	int ret;
 
 	/* Add davinci-evm specific widgets */
 	snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets,
 				  ARRAY_SIZE(aic3x_dapm_widgets));
 
-	/* Set up davinci-evm specific audio path audio_map */
-	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+	if (np) {
+		ret = snd_soc_of_parse_audio_routing(codec->card,
+							"ti,audio-routing");
+		if (ret)
+			return ret;
+	} else {
+		/* Set up davinci-evm specific audio path audio_map */
+		snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+	}
 
 	/* not connected */
 	snd_soc_dapm_disable_pin(dapm, "MONO_LOUT");
@@ -287,6 +308,108 @@ static struct snd_soc_card da850_snd_soc_card = {
 	.num_links = 1,
 };
 
+#if defined(CONFIG_OF)
+
+enum {
+	MACHINE_VERSION_1 = 0,	/* DM365 with Voice Codec */
+	MACHINE_VERSION_2,	/* DM365/DA8xx/OMAPL1x/AM33xx */
+};
+
+static const struct of_device_id davinci_evm_dt_ids[] = {
+	{
+		.compatible = "ti,dm365-voice-codec-audio",
+		.data = (void *)MACHINE_VERSION_1,
+	},
+	{
+		.compatible = "ti,da830-evm-audio",
+		.data = (void *)MACHINE_VERSION_2,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, davinci_mcasp_dt_ids);
+
+/*
+ * This struct is just used as place holder. It will be filled with
+ * data from dt node
+ */
+static struct snd_soc_dai_link evm_dai = {
+	.name		= "TLV320AIC3X",
+	.stream_name	= "AIC3X",
+	.codec_dai_name	= "tlv320aic3x-hifi",
+};
+
+/* davinci evm audio machine driver */
+static struct snd_soc_card evm_soc_card = {
+	.owner = THIS_MODULE,
+	.dai_link = &evm_dai,
+	.num_links = 1,
+};
+
+static int davinci_evm_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	const struct of_device_id *match =
+		of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev);
+	u32 machine_ver;
+	int ret = 0;
+
+	machine_ver = (u32)match->data;
+	switch (machine_ver) {
+	case MACHINE_VERSION_1:
+		evm_dai.name		= "Voice Codec - CQ93VC";
+		evm_dai.stream_name	= "CQ93";
+		evm_dai.codec_dai_name	= "cq93vc-hifi";
+		break;
+
+	case MACHINE_VERSION_2:
+		evm_dai.ops = &evm_ops;
+		evm_dai.init = evm_aic3x_init;
+		break;
+	}
+
+	evm_dai.codec_of_node = of_parse_phandle(np, "ti,audio-codec", 0);
+	if (!evm_dai.codec_of_node)
+		return -EINVAL;
+
+	evm_dai.cpu_of_node = of_parse_phandle(np,
+						"ti,mcasp-controller", 0);
+	if (!evm_dai.cpu_of_node)
+		return -EINVAL;
+
+	evm_dai.platform_of_node = evm_dai.cpu_of_node;
+
+	evm_soc_card.dev = &pdev->dev;
+	ret = snd_soc_of_parse_card_name(&evm_soc_card, "ti,model");
+	if (ret)
+		return ret;
+
+	ret = snd_soc_register_card(&evm_soc_card);
+	if (ret)
+		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+
+	return ret;
+}
+
+static int __devexit davinci_evm_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_card(card);
+
+	return 0;
+}
+
+static struct platform_driver davinci_evm_driver = {
+	.probe		= davinci_evm_probe,
+	.remove		= __devexit_p(davinci_evm_remove),
+	.driver		= {
+		.name	= "davinci_evm",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(davinci_evm_dt_ids),
+	},
+};
+#endif
+
 static struct platform_device *evm_snd_device;
 
 static int __init evm_init(void)
@@ -295,6 +418,15 @@ static int __init evm_init(void)
 	int index;
 	int ret;
 
+#if defined(CONFIG_OF)
+	/*
+	 * If dtb is there, the devices will be created dynamically.
+	 * Only register platfrom driver structure.
+	 */
+	if (of_have_populated_dt())
+		return platform_driver_register(&davinci_evm_driver);
+#endif
+
 	if (machine_is_davinci_evm()) {
 		evm_snd_dev_data = &dm6446_snd_soc_card_evm;
 		index = 0;
@@ -330,6 +462,13 @@ static int __init evm_init(void)
 
 static void __exit evm_exit(void)
 {
+#if defined(CONFIG_OF)
+	if (of_have_populated_dt()) {
+		platform_driver_unregister(&davinci_evm_driver);
+		return;
+	}
+#endif
+
 	platform_device_unregister(evm_snd_device);
 }
 
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v4 1/3] ASoC: tlv320aic3x: Convert mic bias to a supply widget
From: Hebbar Gururaja @ 2013-01-31 12:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359636786-7056-1-git-send-email-gururaja.hebbar@ti.com>

Convert MicBias widgets to supply widget.

On tlv320aic3x, Mic bias power on/off shares the same register bits
with output mic bias voltage.  So, when power on mic bias, we need
reclaim it to voltage value.

Provide a new platform data so that the micbias voltage can be sent
according to board requirement. Now since tlv320aic3x codec driver
is DT aware, update dt files and functions to handle this new
"micbias-vg"  platform data.

Because of sharing of bits, when enabling the micbias, voltage also
needs to be updated. So use SND_SOC_DAPM_POST_PMU & SND_SOC_DAPM_PRE_PMD
macro to create an event to handle this.

Since micbias is converted to supply widget, updated machine drivers as
well.

This change is runtime tested on da850-evm with audio loopback
(arecord|aplay) for confirmation.

Signed-off-by: Hebbar Gururaja <gururaja.hebbar@ti.com>
---
Changes in v4
	 - updated pending machine driver to change in micbias -> supply widget
	 - merge codec & machine driver change into a single commit

Changes in v3
	 - New patch

:100644 100644 e7b98f4... f47c3f5... M	Documentation/devicetree/bindings/sound/tlv320aic3x.txt
:100644 100644 ffd9bc7... 9407fd0... M	include/sound/tlv320aic3x.h
:100644 100644 4989143... 65d09d6... M	sound/soc/codecs/tlv320aic3x.c
:100644 100644 6db3c41... e521ac3... M	sound/soc/codecs/tlv320aic3x.h
:100644 100644 d55e647... 484b22c... M	sound/soc/davinci/davinci-evm.c
:100644 100644 230b8c1... ee7cd53... M	sound/soc/omap/n810.c
:100644 100644 d921ddb... 3cd5257... M	sound/soc/omap/rx51.c
 .../devicetree/bindings/sound/tlv320aic3x.txt      |    6 ++
 include/sound/tlv320aic3x.h                        |   10 +++
 sound/soc/codecs/tlv320aic3x.c                     |   83 ++++++++++++++++++--
 sound/soc/codecs/tlv320aic3x.h                     |    4 +
 sound/soc/davinci/davinci-evm.c                    |    6 +-
 sound/soc/omap/n810.c                              |    4 +-
 sound/soc/omap/rx51.c                              |    8 +-
 7 files changed, 106 insertions(+), 15 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
index e7b98f4..f47c3f5 100644
--- a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
+++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
@@ -11,6 +11,12 @@ Optional properties:
 
 - gpio-reset - gpio pin number used for codec reset
 - ai3x-gpio-func - <array of 2 int> - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality
+- ai3x-micbias-vg - MicBias Voltage required.
+	1 - MICBIAS output is powered to 2.0V,
+	2 - MICBIAS output is powered to 2.5V,
+	3 - MICBIAS output is connected to AVDD,
+	If this node is not mentioned or if the value is incorrect, then MicBias
+	is powered down.
 
 Example:
 
diff --git a/include/sound/tlv320aic3x.h b/include/sound/tlv320aic3x.h
index ffd9bc7..9407fd0 100644
--- a/include/sound/tlv320aic3x.h
+++ b/include/sound/tlv320aic3x.h
@@ -46,6 +46,13 @@ enum {
 	AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ	= 15
 };
 
+enum aic3x_micbias_voltage {
+	AIC3X_MICBIAS_OFF = 0,
+	AIC3X_MICBIAS_2_0V = 1,
+	AIC3X_MICBIAS_2_5V = 2,
+	AIC3X_MICBIAS_AVDDV = 3,
+};
+
 struct aic3x_setup_data {
 	unsigned int gpio_func[2];
 };
@@ -53,6 +60,9 @@ struct aic3x_setup_data {
 struct aic3x_pdata {
 	int gpio_reset; /* < 0 if not used */
 	struct aic3x_setup_data *setup;
+
+	/* Selects the micbias voltage */
+	enum aic3x_micbias_voltage micbias_vg;
 };
 
 #endif
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 4989143..65d09d6 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -85,6 +85,9 @@ struct aic3x_priv {
 #define AIC3X_MODEL_33 1
 #define AIC3X_MODEL_3007 2
 	u16 model;
+
+	/* Selects the micbias voltage */
+	enum aic3x_micbias_voltage micbias_vg;
 };
 
 /*
@@ -195,6 +198,37 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
 	return ret;
 }
 
+/*
+ * mic bias power on/off share the same register bits with
+ * output voltage of mic bias. when power on mic bias, we
+ * need reclaim it to voltage value.
+ * 0x0 = Powered off
+ * 0x1 = MICBIAS output is powered to 2.0V,
+ * 0x2 = MICBIAS output is powered to 2.5V
+ * 0x3 = MICBIAS output is connected to AVDD
+ */
+static int mic_bias_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* change mic bias voltage to user defined */
+		snd_soc_update_bits(codec, MICBIAS_CTRL,
+				MICBIAS_LEVEL_MASK,
+				aic3x->micbias_vg << MICBIAS_LEVEL_SHIFT);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, MICBIAS_CTRL,
+				MICBIAS_LEVEL_MASK, 0);
+		break;
+	}
+	return 0;
+}
+
 static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" };
 static const char *aic3x_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" };
 static const char *aic3x_left_hpcom_mux[] =
@@ -596,12 +630,9 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
 			 AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0),
 
 	/* Mic Bias */
-	SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2V",
-			 MICBIAS_CTRL, 6, 3, 1, 0),
-	SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2.5V",
-			 MICBIAS_CTRL, 6, 3, 2, 0),
-	SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD",
-			 MICBIAS_CTRL, 6, 3, 3, 0),
+	SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0,
+			 mic_bias_event,
+			 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 
 	/* Output mixers */
 	SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0,
@@ -1386,6 +1417,24 @@ static int aic3x_probe(struct snd_soc_codec *codec)
 	if (aic3x->model == AIC3X_MODEL_3007)
 		snd_soc_add_codec_controls(codec, &aic3x_classd_amp_gain_ctrl, 1);
 
+	/* set mic bias voltage */
+	switch (aic3x->micbias_vg) {
+	case AIC3X_MICBIAS_2_0V:
+	case AIC3X_MICBIAS_2_5V:
+	case AIC3X_MICBIAS_AVDDV:
+		snd_soc_update_bits(codec, MICBIAS_CTRL,
+				    MICBIAS_LEVEL_MASK,
+				    (aic3x->micbias_vg) << MICBIAS_LEVEL_SHIFT);
+		break;
+	case AIC3X_MICBIAS_OFF:
+		/*
+		 * noting to do. target won't enter here. This is just to avoid
+		 * compile time warning "warning: enumeration value
+		 * 'AIC3X_MICBIAS_OFF' not handled in switch"
+		 */
+		break;
+	}
+
 	aic3x_add_widgets(codec);
 	list_add(&aic3x->list, &reset_list);
 
@@ -1461,6 +1510,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
 	struct aic3x_setup_data *ai3x_setup;
 	struct device_node *np = i2c->dev.of_node;
 	int ret;
+	u32 value;
 
 	aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL);
 	if (aic3x == NULL) {
@@ -1474,6 +1524,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
 	if (pdata) {
 		aic3x->gpio_reset = pdata->gpio_reset;
 		aic3x->setup = pdata->setup;
+		aic3x->micbias_vg = pdata->micbias_vg;
 	} else if (np) {
 		ai3x_setup = devm_kzalloc(&i2c->dev, sizeof(*ai3x_setup),
 								GFP_KERNEL);
@@ -1493,6 +1544,26 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
 			aic3x->setup = ai3x_setup;
 		}
 
+		if (!of_property_read_u32(np, "ai3x-micbias-vg", &value)) {
+			switch (value) {
+			case 1 :
+				aic3x->micbias_vg = AIC3X_MICBIAS_2_0V;
+				break;
+			case 2 :
+				aic3x->micbias_vg = AIC3X_MICBIAS_2_5V;
+				break;
+			case 3 :
+				aic3x->micbias_vg = AIC3X_MICBIAS_AVDDV;
+				break;
+			default :
+				aic3x->micbias_vg = AIC3X_MICBIAS_OFF;
+				dev_err(&i2c->dev, "Unsuitable MicBias voltage "
+							"found in DT\n");
+			}
+		} else {
+			aic3x->micbias_vg = AIC3X_MICBIAS_OFF;
+		}
+
 	} else {
 		aic3x->gpio_reset = -1;
 	}
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h
index 6db3c41..e521ac3 100644
--- a/sound/soc/codecs/tlv320aic3x.h
+++ b/sound/soc/codecs/tlv320aic3x.h
@@ -238,6 +238,10 @@
 /* Default input volume */
 #define DEFAULT_GAIN    0x20
 
+/* MICBIAS Control Register */
+#define MICBIAS_LEVEL_SHIFT	(6)
+#define MICBIAS_LEVEL_MASK	(3 << 6)
+
 /* headset detection / button API */
 
 /* The AIC3x supports detection of stereo headsets (GND + left + right signal)
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index d55e647..484b22c 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -116,9 +116,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	{"Line Out", NULL, "RLOUT"},
 
 	/* Mic connected to (MIC3L | MIC3R) */
-	{"MIC3L", NULL, "Mic Bias 2V"},
-	{"MIC3R", NULL, "Mic Bias 2V"},
-	{"Mic Bias 2V", NULL, "Mic Jack"},
+	{"MIC3L", NULL, "Mic Bias"},
+	{"MIC3R", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Mic Jack"},
 
 	/* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */
 	{"LINE1L", NULL, "Line In"},
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index 230b8c1..ee7cd53 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -230,8 +230,8 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	{"Ext Spk", NULL, "LLOUT"},
 	{"Ext Spk", NULL, "RLOUT"},
 
-	{"DMic Rate 64", NULL, "Mic Bias 2V"},
-	{"Mic Bias 2V", NULL, "DMic"},
+	{"DMic Rate 64", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "DMic"},
 };
 
 static const char *spk_function[] = {"Off", "On"};
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index d921ddb..3cd5257 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -248,16 +248,16 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	{"FM Transmitter", NULL, "LLOUT"},
 	{"FM Transmitter", NULL, "RLOUT"},
 
-	{"DMic Rate 64", NULL, "Mic Bias 2V"},
-	{"Mic Bias 2V", NULL, "DMic"},
+	{"DMic Rate 64", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "DMic"},
 };
 
 static const struct snd_soc_dapm_route audio_mapb[] = {
 	{"b LINE2R", NULL, "MONO_LOUT"},
 	{"Earphone", NULL, "b HPLOUT"},
 
-	{"LINE1L", NULL, "b Mic Bias 2.5V"},
-	{"b Mic Bias 2.5V", NULL, "HS Mic"}
+	{"LINE1L", NULL, "b Mic Bias"},
+	{"b Mic Bias", NULL, "HS Mic"}
 };
 
 static const char *spk_function[] = {"Off", "On"};
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v4 0/3] ASoC davinci/tlv320aic3x updates, fixes & DT support
From: Hebbar Gururaja @ 2013-01-31 12:53 UTC (permalink / raw)
  To: linux-arm-kernel

1. Convert tlv320aic3x mic bias to a supply widget and related machine driver
2. Add DT support for Davinci machine platform
3. Remove __dev* attributes

This patch-set is tested on Davinci platform (DA850 EVM). This series applies on
top of tag next-20130128 git tree
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git

These patches cannot be tested directly on mainline kernel (DT based).
This is because dma is not yet completely ported to Davinci ASoC. I had to add
few hacks to get Audio working on Davinci DA850 platform.

For reference, I have placed the entire working tree @
Tree :  https://github.com/ghebbar/linux.git
Branch : dev_next-20130128_davinci_asoc_dt_v3

Changes in v4
	 - updated pending machine driver to change in micbias -> supply widget
	 - merge codec & machine driver change into a single commit

Changes in v3
	- drop mcasp pinctrl handler patch from series as it is now handled
	  centrally.
	- Convert tlv320aic3x mic bias to a supply widget and related machine
	  driver
	- remove __dev* attributes

Changes in v2
	 - Remove reference to Linux & software details from DT binding

Hebbar Gururaja (2):
  ASoC: tlv320aic3x: Convert mic bias to a supply widget
  ASoC: davinci: remove __dev* attributes

Hebbar, Gururaja (1):
  ASoC: davinci: machine: Add device tree binding

 .../bindings/sound/davinci-evm-audio.txt           |   53 ++++++
 .../devicetree/bindings/sound/tlv320aic3x.txt      |    6 +
 include/sound/tlv320aic3x.h                        |   10 ++
 sound/soc/codecs/tlv320aic3x.c                     |   83 ++++++++-
 sound/soc/codecs/tlv320aic3x.h                     |    4 +
 sound/soc/davinci/davinci-evm.c                    |  185 +++++++++++++++++---
 sound/soc/omap/n810.c                              |    4 +-
 sound/soc/omap/rx51.c                              |    8 +-
 8 files changed, 318 insertions(+), 35 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/davinci-evm-audio.txt

-- 
1.7.9.5

^ permalink raw reply

* [PATCH] arm: mvebu: support for the new Armada XP evaluation board(DB-MV784MP-GP)
From: Jason Cooper @ 2013-01-31 12:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <510A689B.6040407@free-electrons.com>

On Thu, Jan 31, 2013 at 01:50:35PM +0100, Gregory CLEMENT wrote:
> On 01/31/2013 01:45 PM, Jason Cooper wrote:
> > On Thu, Jan 31, 2013 at 01:07:35PM +0100, Gregory CLEMENT wrote:
> >> Well on this board there is no soldered memory at all.
> > 
> > So it has two slots? 1GB and 2GB?
> 
> Well in fact it is 4GB RAM but we can only use 3GB (we need the last GB
> of address space for peripheral, CPU registers and IOmem).
> 
> There is only one slot.

Ok, thanks.

Jason.

^ permalink raw reply

* [GIT PULL] ARM: mvebu cleanup for v3.9 round2
From: Jason Cooper @ 2013-01-31 12:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359495436.F88c4680.7559@triton>

Arnd, Olof,

Please don't pull this yet.  The nsa310 patch built fine at the tip of
my for-next, but didn't do so well when applied to mvebu/cleanup.

I'll redo and resubmit the whole series of pr's.

thx,

Jason.

On Tue, Jan 29, 2013 at 09:37:16PM +0000, Jason Cooper wrote:
> The following changes since commit b96e1b1c3c5319294edb0970b6d5bf099c0e85eb:
> 
>   ARM: Kirkwood: Cleanup unneeded include files (2013-01-12 21:50:10 +0000)
> 
> are available in the git repository at:
> 
>   git://git.infradead.org/users/jcooper/linux.git tags/cleanup_for_v3.9_round2
> 
> for you to fetch changes up to 63a069739a5826ab4007da88b7ec71eb9909271c:
> 
>   ARM: dove: cleanup includes (2013-01-29 21:31:36 +0000)
> 
> ----------------------------------------------------------------
> cleanup for v3.9 round2
>  - remove unneeded #includes for mach-dove
>  - remove unneeded #includes and code for the nsa310
> 
> ----------------------------------------------------------------
> Jason Cooper (1):
>       ARM: kirkwood: nsa310: cleanup includes and unneeded code
> 
> Sebastian Hesselbarth (1):
>       ARM: dove: cleanup includes
> 
>  arch/arm/mach-dove/common.c           | 29 +++++++++--------------------
>  arch/arm/mach-kirkwood/board-nsa310.c |  9 +--------
>  2 files changed, 10 insertions(+), 28 deletions(-)
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH] arm: mvebu: support for the new Armada XP evaluation board(DB-MV784MP-GP)
From: Gregory CLEMENT @ 2013-01-31 12:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130131124542.GB7717@titan.lakedaemon.net>

On 01/31/2013 01:45 PM, Jason Cooper wrote:
> On Thu, Jan 31, 2013 at 01:07:35PM +0100, Gregory CLEMENT wrote:
>> On 01/30/2013 07:10 PM, Jason Cooper wrote:
>>>
>>> Gregory,
>>>
>>> Adding devicetree-discuss.
>>
>> I should have added it in in CC in my first version
>>
>>>
>>> Guys, how do you prefer to handle plug-in RAM modules?  describe the
>>> soldered-in amount, or?
>>>
>>> On Wed, Jan 30, 2013 at 06:35:17PM +0100, Gregory CLEMENT wrote:
>>>> On 01/30/2013 06:33 PM, Jason Cooper wrote:
>>>>> On Wed, Jan 30, 2013 at 06:26:14PM +0100, Gregory CLEMENT wrote:
>>>>>> This is the new Armada XP evaluation board from Marvell. It comes with
>>>>>> a RS232 port over USB, a SATA link, an internal SSD, 4 Ethernet
>>>>>> Gigabit links.
>>>>>>
>>>>>> Support for USB (Host and device), SDIO, PCIe will be added as drivers
>>>>>> when they become available for Armada XP in mainline.
>>>>>>
>>>>>> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
>>>>>> ---
>>>>>>  arch/arm/boot/dts/Makefile         |    1 +
>>>>>>  arch/arm/boot/dts/armada-xp-gp.dts |   94 ++++++++++++++++++++++++++++++++++++
>>>>>>  2 files changed, 95 insertions(+)
>>>>>>  create mode 100644 arch/arm/boot/dts/armada-xp-gp.dts
>>>>>>
>>> ...
>>>>>> +	memory {
>>>>>> +		device_type = "memory";
>>>>>> +		reg = <0x00000000 0xC0000000>; /* 3 GB */
>>>>>
>>>>> Is this the soldered on the board amount, or the amount with an
>>>>> expandable slot filled?
>>>>
>>>> It is not soldered, so you can change the amount of memory
>>>
>>> Well, there's something we don't encounter too much in the embedded
>>> world.  ;-)  I'm inclined to think the entry here should be the soldered
>>> on amount, and the bootloader would (hypothetically) change the DT to
>>> the probed amount.  But I haven't seen a precedent set yet...
>>
>> Well on this board there is no soldered memory at all.
> 
> So it has two slots? 1GB and 2GB?

Well in fact it is 4GB RAM but we can only use 3GB (we need the last GB
of address space for peripheral, CPU registers and IOmem).

There is only one slot.

> 
> thx,
> 
> Jason.
> 


-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply

* Failure to boot...
From: Santosh Shilimkar @ 2013-01-31 12:49 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130131104044.GO2637@n2100.arm.linux.org.uk>

On Thursday 31 January 2013 04:10 PM, Russell King - ARM Linux wrote:
> On Thu, Jan 31, 2013 at 09:20:24AM +0000, Russell King - ARM Linux wrote:
>> On Wed, Jan 30, 2013 at 11:19:40PM -0500, Nicolas Pitre wrote:
>>> Better yet (IMHO): just enable the zboot command in U-Boot to let you
>>> boot a zImage binary directly.
>>
>> I wish it were that easy but it isn't.  I've no idea where to get a
>> version of uboot for my boards which supports that; TI have always
>> supplied updates to uboot for me, and with the current state of TI
>> being afaict in chaos.
>>
>> TI have always supplied a replacement X-Loader with each uboot update.
>> I've no idea what X-Loader is or why both get updated together, but...
>>
>> Moreover, I doubt that the 3430LDP, of which there are multiple versions,
>> will ever see a uboot update.  It already suffers from a lack of correct
>> kernel support due to random wiring changes between these versions (the
>> keypad doesn't work correctly) and I've yet to indentify which version
>> it is despite downloading the circuits.  So trying to locate the right
>> uboot will be impossible there.
>>
>> So, I'm _stuck_ with uImages for these platforms.
>
> Right, so I'm now passing LOADADDR= which allows this to work - and the
> latest OMAP4430SDP boot result shows almost the same sad broken story.
>
I just tried latest mainline (commit: 04c2eee5) and default config
just boots fine.

I was looking at your build system output which shows the boot
state "OMAP4430 SDP: fail". Your config seems to be with
CONFIG_ARCH_MULTIPLATFORM=y and indeed this kernel doesn't
boot. Seems to abort very early in boot. Am looking at it.

Regards,
Santosh

P.S Btw, the load address issue with multi-platform build
was highlighted on the list in past by Tony [1]

[1] http://www.spinics.net/lists/linux-omap/msg84146.html

^ permalink raw reply

* [PATCH] arm: mvebu: support for the new Armada XP evaluation board(DB-MV784MP-GP)
From: Jason Cooper @ 2013-01-31 12:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <510A5E87.60509@free-electrons.com>

On Thu, Jan 31, 2013 at 01:07:35PM +0100, Gregory CLEMENT wrote:
> On 01/30/2013 07:10 PM, Jason Cooper wrote:
> > 
> > Gregory,
> > 
> > Adding devicetree-discuss.
> 
> I should have added it in in CC in my first version
> 
> > 
> > Guys, how do you prefer to handle plug-in RAM modules?  describe the
> > soldered-in amount, or?
> > 
> > On Wed, Jan 30, 2013 at 06:35:17PM +0100, Gregory CLEMENT wrote:
> >> On 01/30/2013 06:33 PM, Jason Cooper wrote:
> >>> On Wed, Jan 30, 2013 at 06:26:14PM +0100, Gregory CLEMENT wrote:
> >>>> This is the new Armada XP evaluation board from Marvell. It comes with
> >>>> a RS232 port over USB, a SATA link, an internal SSD, 4 Ethernet
> >>>> Gigabit links.
> >>>>
> >>>> Support for USB (Host and device), SDIO, PCIe will be added as drivers
> >>>> when they become available for Armada XP in mainline.
> >>>>
> >>>> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
> >>>> ---
> >>>>  arch/arm/boot/dts/Makefile         |    1 +
> >>>>  arch/arm/boot/dts/armada-xp-gp.dts |   94 ++++++++++++++++++++++++++++++++++++
> >>>>  2 files changed, 95 insertions(+)
> >>>>  create mode 100644 arch/arm/boot/dts/armada-xp-gp.dts
> >>>>
> > ...
> >>>> +	memory {
> >>>> +		device_type = "memory";
> >>>> +		reg = <0x00000000 0xC0000000>; /* 3 GB */
> >>>
> >>> Is this the soldered on the board amount, or the amount with an
> >>> expandable slot filled?
> >>
> >> It is not soldered, so you can change the amount of memory
> > 
> > Well, there's something we don't encounter too much in the embedded
> > world.  ;-)  I'm inclined to think the entry here should be the soldered
> > on amount, and the bootloader would (hypothetically) change the DT to
> > the probed amount.  But I haven't seen a precedent set yet...
> 
> Well on this board there is no soldered memory at all.

So it has two slots? 1GB and 2GB?

thx,

Jason.

^ permalink raw reply

* [PATCH] arm: mvebu: support for the new Armada XP evaluation board(DB-MV784MP-GP)
From: Jason Cooper @ 2013-01-31 12:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <510A5D38.9040608@free-electrons.com>

On Thu, Jan 31, 2013 at 01:02:00PM +0100, Gregory CLEMENT wrote:
> On 01/31/2013 11:07 AM, Thomas Petazzoni wrote:
> > Dear Andrew Lunn,
> > 
> > On Thu, 31 Jan 2013 10:50:25 +0100, Andrew Lunn wrote:
> > 
> >> We have the same issue with OpenBox AX3. All the devices we have in
> >> our hands have 1GB soldered down, plus 2GB on expansion. The DT
> >> currently has the full 3GB.
> >>
> >> However, there has been discussion of reducing this down to 1GB since
> >> both Thomas and Gregory have unstable systems with the full 3GB, but
> >> mine box is stable with the full 3GB. So i don't know how strong a
> >> precedent that sets....
> > 
> > It seems that if we have CONFIG_ARM_ATAG_DTB_COMPAT, then the code in
> > arch/arm/boot/compressed/atags_to_fdt.c will update the DT memory node
> > according to the ATAG_MEM passed by the bootloader.
> > 
> 
> From my point of view these dts file are just given as reference, and the
> bootloader should be able to modify them on the fly according the hardware
> configuration of the board.
> 
> And for old bootloader then we can use the CONFIG_ARM_ATAG_DTB_COMPAT as
> pointed by Thomas.
> 
> So I am not sure that the amount of memory is very important.
> 
> However I think that having a value by default is useful, so unless
> there is a strong argument against it, I would like to keep it, maybe with
> a comment in the dts to emphasize that it is just a default value and the
> amount of memory can be changed.

Let's go with the comment.  Upgradeable memory is still fairly uncommon
in embedded, it won't hurt to let folks know the bootloader will set it
(hopefully) correctly.

thx,

Jason.

^ permalink raw reply

* [PATCH 2/4] ARM: mach-shmobile: r8a7779: Allow initialisation of GIC by DT
From: Mark Rutland @ 2013-01-31 12:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359597051-32700-3-git-send-email-horms+renesas@verge.net.au>

Hi Simon,

On Thu, Jan 31, 2013 at 01:50:49AM +0000, Simon Horman wrote:
> This allows the GIC interrupt controller of the  r8a7779 SoC to be
> initialised using a flattened device tree blob.
> 
> Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
> ---
>  arch/arm/boot/dts/r8a7779.dtsi               |   40 ++++++++++++++++++++++++++
>  arch/arm/mach-shmobile/include/mach/common.h |    1 +
>  arch/arm/mach-shmobile/intc-r8a7779.c        |   27 +++++++++++++----
>  3 files changed, 62 insertions(+), 6 deletions(-)
>  create mode 100644 arch/arm/boot/dts/r8a7779.dtsi
> 
> diff --git a/arch/arm/boot/dts/r8a7779.dtsi b/arch/arm/boot/dts/r8a7779.dtsi
> new file mode 100644
> index 0000000..eadc12e
> --- /dev/null
> +++ b/arch/arm/boot/dts/r8a7779.dtsi
> @@ -0,0 +1,40 @@
> +/*
> + * Device Tree Source for Renesas r8a7740
> + *
> + * Copyright (C) 2013 Renesas Solutions Corp.
> + * Copyright (C) 2013 Simon Horman
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2.  This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + */
> +
> +/include/ "skeleton.dtsi"
> +
> +/ {
> +	compatible = "renesas,r8a7779";
> +
> +	cpus {
> +		cpu at 0 {
> +			compatible = "arm,cortex-a9";
> +		};
> +		cpu at 1 {
> +			compatible = "arm,cortex-a9";
> +		};
> +		cpu at 2 {
> +			compatible = "arm,cortex-a9";
> +		};
> +		cpu at 3 {
> +			compatible = "arm,cortex-a9";
> +		};
> +	};

Sorry to sound like a broken record, but it'd be good to see reg and
device_type set here.

> +
> +        gic: interrupt-controller at f0001000 {
> +                compatible = "arm,cortex-a9-gic";
> +                #interrupt-cells = <3>;
> +                #address-cells = <1>;

Why is #address-cells needed here (and without #size-cells)? I see it's in the
binding document example, but I can't figure out why.

> +                interrupt-controller;
> +                reg = <0xf0001000 0x1000>,
> +                      <0xf0000100 0x100>;
> +        };
> +};

[...]

Thanks,
Mark.

^ permalink raw reply

* [PATCH v2 0/4] Preparatory GIC patches for arm64 support
From: Catalin Marinas @ 2013-01-31 12:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130131114703.GX23505@n2100.arm.linux.org.uk>

On Thu, Jan 31, 2013 at 11:47:04AM +0000, Russell King - ARM Linux wrote:
> On Thu, Jan 31, 2013 at 10:30:44AM +0000, Catalin Marinas wrote:
> > On Tue, Jan 29, 2013 at 04:18:35PM +0000, Catalin Marinas wrote:
> > > That's the second version of the GIC clean-up patches to support arm64.
> > > The only change from v1 is that the second patch (chained_irq.h) also
> > > covers drivers/gpio and drivers/pinctrl (#include change).
> > 
> > Are you ok to merge this series via the arm-soc tree for 3.9-rc1? There
> > are no complaints so far (only acks ;). This would allow me to push GIC
> > support for arm64.
> 
> So I don't exist anymore to you?

You do ;) and you've been cc'ed on these patches. Just wasn't sure you
care about patches that have 'arm64' in the cover email ;).

Since Rob's series went through the arm-soc, I consider that further
changes should go the same route as there is a dependency and I'd like
to get them merged sooner. These patches touch primarily SoC code, apart
from some trivial code moving and the CPU notifier in irq-gic.c (you are
the original author of this driver) and I'm ok if you want to merge it.

I really don't mind if you or Olof merge the whole series as long as it
gets upstream at some point. As you expressed an opinion on these
patches and you want to merge them, they'll have to wait until after
3.9-rc1 for Rob's patches to get in.

> Catalin, it's already been suggested to you that this series is more
> core ARM stuff than SoC stuff, and it's also been suggested that you
> merge this through my tree.

No, it hasn't. Just Nico saying that he'd prefer *his* series was merged
by RMK (and I agree). A way to sort the dependency issue for Nico is to
at least push some of this series in 3.9-rc1. Otherwise we just postpone
the dependency issue.

> No, I guess this figures after all your excessively negative replies
> on all of my comments during the review of ARM64.

It's all relative - negative reply to negative reply would make it
positive ;).

-- 
Catalin

^ permalink raw reply

* [PATCH] ARM: omap2: register cpufreq-cpu0 device for am33xx
From: Shawn Guo @ 2013-01-31 12:31 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <331ABD5ECB02734CA317220B2BBEABC13EAF9DD9@DBDE01.ent.ti.com>

On Thu, Jan 31, 2013 at 09:40:43AM +0000, AnilKumar, Chimata wrote:
> On Wed, Jan 30, 2013 at 20:02:22, Shawn Guo wrote:
> > The cpufreq-cpu0 driver changes to instantiate use platform_driver
> > mechanism.  The patch is an am33xx platform level adaptation for it.
> 
> Tested-by: AnilKumar Ch <anilkumar@ti.com>
> 
Thanks, AnilKumar.

> Hi Shawn,
> 
> I have tested your patch on AM335x-EVM, no issues observed.
> 
> I think, better post v3 version which contains this patch
> and cpu0-cpufreq driver changes.
> 
> Or
> 
> Post v3 of cpufreq-cpu0 driver changes. 
> 
Sorry for forgetting copying you guys.  It's been posted as below.

http://www.spinics.net/lists/arm-kernel/msg221209.html

Shawn

^ permalink raw reply

* [PATCH 2/2] ARM: imx_v6_v7_defconfig: Add VPU support
From: Shawn Guo @ 2013-01-31 12:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130131095446.GP1906@pengutronix.de>

On Thu, Jan 31, 2013 at 10:54:46AM +0100, Sascha Hauer wrote:
> On Wed, Jan 30, 2013 at 09:04:55PM +0800, Shawn Guo wrote:
> > On Tue, Jan 29, 2013 at 01:49:13PM -0200, Fabio Estevam wrote:
> > > Let the VPU driver be built by default.
> > > 
> > Do we have any imx_v6_v7 platform supported by VPU driver today?
> 
> Does this matter? IMO it's good to keep the driver in a compilable state
> even if it ends up being unused for now.
> 
It's not really necessary since we will have imx_v4_v5_defconfig to
cover it.

Shawn

^ permalink raw reply

* [PATCH v4 5/8] MFD: ti_am335x_tscadc: Add DT support
From: Patil, Rachna @ 2013-01-31 12:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <79CD15C6BA57404B839C016229A409A83EBEFAE8@DBDE01.ent.ti.com>

Vaibhav,

<SNIP>
> > > > 
> > > > -	if (!pdata) {
> > > > +	if (!pdata && !pdev->dev.of_node) {
> > > > 		dev_err(&pdev->dev, "Could not find platform data\n");
> > > > 		return -EINVAL;
> > > > 	}
> > > > 
> > > > -	if (pdata->adc_init)
> > > > -		adc_channels = pdata->adc_init->adc_channels;
> > > > +	if (pdev->dev.platform_data) {
> > > > +		if (pdata->tsc_init)
> > > > +			tsc_wires = pdata->tsc_init->wires;
> > > > +
> > > > +		if (pdata->adc_init)
> > > > +			adc_channels = pdata->adc_init->adc_channels;
> > > > +	} else {
> > > > +		node = of_find_node_by_name(pdev->dev.of_node, "tsc");
> > > > +		of_property_read_u32(node, "ti,wires", &tsc_wires);
> > > > +
> > > > +		node = of_find_node_by_name(pdev->dev.of_node, "adc");
> > > > +		of_property_read_u32(node, "ti,adc-channels", &adc_channels);
> > > > +	}
> > > 
> > > Since AM335x is DT only, why is there a platform data codepath and why is it the first branch it tries? And I guess the next question is related to the first: why doesn't it work when used with DT? When I copy over the nodes from the evm.dts to my board I get "tsc tsc: Missing platform data" in dmesg.
> > 
> > This IP came up 1st on AM335x, but it is not platform dependent. The driver can be used on other platforms where-in DT is not supported.
> > According to the maintainers platform data takes precedence over DT. Hence the order.
> > 
> 
> Rachana,
> 
> I see no point adding support for platform_data when you know that none of older platforms are going to use this driver and all future platforms _must_ follow device-tree model.
> 
> So I agree that you should remove board file dependency from the driver.

Ok. I will remove support for platform data in the next version of patches.

> 
> 
> > I do not see "Missing platform data" error msg in the latest driver. I am not able to trace from where this got populated.
> > 
> 
> Can you share the branch which you have tested?

https://github.com/patilrachna/linux/tree/v3.8_rc3_MFD_TSCADC_DT-v2

Regards,
Rachna

^ permalink raw reply

* [PATCHv5 16/16] clocksource: arch_timer: use virtual counters
From: Mark Rutland @ 2013-01-31 12:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359634539-9580-1-git-send-email-mark.rutland@arm.com>

Switching between reading the virtual or physical counters is
problematic, as some core code wants a view of time before we're fully
set up. Using a function pointer and switching the source after the
first read can make time appear to go backwards, and having a check in
the read function is an unfortunate block on what we want to be a fast
path.

Instead, this patch makes us always use the virtual counters. If we're a
guest, or don't have hyp mode, we'll use the virtual timers, and as such
don't care about CNTVOFF as long as it doesn't change in such a way as
to make time travel backwards. If we do have hyp mode, and might be a
KVM host, we have to use the physical timers, and require CNTVOFF to be
zero so as to have a consistent view of time between the physical timers
and virtual counters.

Any code which may want to alter CNTVOFF (e.g. KVM) will need to ensure
that it is zeroed when entering the host.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
---
 drivers/clocksource/arm_arch_timer.c | 21 ++++-----------------
 include/clocksource/arm_arch_timer.h |  2 +-
 2 files changed, 5 insertions(+), 18 deletions(-)

diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index d7ad425..f0705fb 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -186,27 +186,19 @@ u32 arch_timer_get_rate(void)
 	return arch_timer_rate;
 }
 
-/*
- * Some external users of arch_timer_read_counter (e.g. sched_clock) may try to
- * call it before it has been initialised. Rather than incur a performance
- * penalty checking for initialisation, provide a default implementation that
- * won't lead to time appearing to jump backwards.
- */
-static u64 arch_timer_read_zero(void)
+u64 arch_timer_read_counter(void)
 {
-	return 0;
+	return arch_counter_get_cntvct();
 }
 
-u64 (*arch_timer_read_counter)(void) = arch_timer_read_zero;
-
 static cycle_t arch_counter_read(struct clocksource *cs)
 {
-	return arch_timer_read_counter();
+	return arch_counter_get_cntvct();
 }
 
 static cycle_t arch_counter_read_cc(const struct cyclecounter *cc)
 {
-	return arch_timer_read_counter();
+	return arch_counter_get_cntvct();
 }
 
 static struct clocksource clocksource_counter = {
@@ -382,10 +374,5 @@ int __init arch_timer_init(void)
 		}
 	}
 
-	if (arch_timer_use_virtual)
-		arch_timer_read_counter = arch_counter_get_cntvct;
-	else
-		arch_timer_read_counter = arch_counter_get_cntpct;
-
 	return arch_timer_register();
 }
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h
index b61f996..34dccbe 100644
--- a/include/clocksource/arm_arch_timer.h
+++ b/include/clocksource/arm_arch_timer.h
@@ -33,7 +33,7 @@
 
 extern int arch_timer_init(void);
 extern u32 arch_timer_get_rate(void);
-extern u64 (*arch_timer_read_counter)(void);
+extern u64 arch_timer_read_counter(void);
 extern struct timecounter *arch_timer_get_timecounter(void);
 
 #else
-- 
1.8.1.1

^ permalink raw reply related

* [PATCHv5 15/16] ARM: hyp: initialize CNTVOFF to zero
From: Mark Rutland @ 2013-01-31 12:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359634539-9580-1-git-send-email-mark.rutland@arm.com>

From: Marc Zyngier <Marc.Zyngier@arm.com>

In order to be able to use the virtual counter in a safe way,
make sure it is initialized to zero before dropping to SVC.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Dave Martin <dave.martin@arm.com>
---
 arch/arm/kernel/hyp-stub.S | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/kernel/hyp-stub.S b/arch/arm/kernel/hyp-stub.S
index 65b2417..455603a 100644
--- a/arch/arm/kernel/hyp-stub.S
+++ b/arch/arm/kernel/hyp-stub.S
@@ -152,6 +152,9 @@ THUMB(	orr	r7, #(1 << 30)	)	@ HSCTLR.TE
 	mrc	p15, 4, r7, c14, c1, 0	@ CNTHCTL
 	orr	r7, r7, #3		@ PL1PCEN | PL1PCTEN
 	mcr	p15, 4, r7, c14, c1, 0	@ CNTHCTL
+	mov	r6, #0
+	mov	r7, #0
+	mcrr	p15, 4, r6, r7, c14	@ CNTVOFF
 1:
 #endif
 
-- 
1.8.1.1

^ permalink raw reply related

* [PATCHv5 14/16] ARM: arch_timers: switch to physical timers if HYP mode is available
From: Mark Rutland @ 2013-01-31 12:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359634539-9580-1-git-send-email-mark.rutland@arm.com>

From: Marc Zyngier <Marc.Zyngier@arm.com>

If we're booted in HYP mode, it is possible that we'll run some
kind of virtualized environment. In this case, it is a better to
switch to the physical timers, and leave the virtual timers to
guests.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
---
 drivers/clocksource/arm_arch_timer.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index ec30a73..d7ad425 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -19,6 +19,7 @@
 #include <linux/io.h>
 
 #include <asm/arch_timer.h>
+#include <asm/virt.h>
 
 #include <clocksource/arm_arch_timer.h>
 
@@ -364,10 +365,14 @@ int __init arch_timer_init(void)
 	of_node_put(np);
 
 	/*
+	 * If HYP mode is available, we know that the physical timer
+	 * has been configured to be accessible from PL1. Use it, so
+	 * that a guest can use the virtual timer instead.
+	 *
 	 * If no interrupt provided for virtual timer, we'll have to
 	 * stick to the physical timer. It'd better be accessible...
 	 */
-	if (!arch_timer_ppi[VIRT_PPI]) {
+	if (is_hyp_mode_available() || !arch_timer_ppi[VIRT_PPI]) {
 		arch_timer_use_virtual = false;
 
 		if (!arch_timer_ppi[PHYS_SECURE_PPI] ||
-- 
1.8.1.1

^ permalink raw reply related

* [PATCHv5 13/16] Documentation: Add ARMv8 to arch_timer devicetree
From: Mark Rutland @ 2013-01-31 12:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359634539-9580-1-git-send-email-mark.rutland@arm.com>

Currently the documentation for the arch_timer devicetree binding only
lists "arm,armv7-timer".

Add "arm,armv8-timer" to the list of compatible strings.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
 Documentation/devicetree/bindings/arm/arch_timer.txt | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/arch_timer.txt b/Documentation/devicetree/bindings/arm/arch_timer.txt
index 52478c8..20746e5 100644
--- a/Documentation/devicetree/bindings/arm/arch_timer.txt
+++ b/Documentation/devicetree/bindings/arm/arch_timer.txt
@@ -1,13 +1,14 @@
 * ARM architected timer
 
-ARM Cortex-A7 and Cortex-A15 have a per-core architected timer, which
-provides per-cpu timers.
+ARM cores may have a per-core architected timer, which provides per-cpu timers.
 
 The timer is attached to a GIC to deliver its per-processor interrupts.
 
 ** Timer node properties:
 
-- compatible : Should at least contain "arm,armv7-timer".
+- compatible : Should at least contain one of
+	"arm,armv7-timer"
+	"arm,armv8-timer"
 
 - interrupts : Interrupt list for secure, non-secure, virtual and
   hypervisor timers, in that order.
-- 
1.8.1.1

^ permalink raw reply related

* [PATCHv5 12/16] arm64: move from arm_generic to arm_arch_timer
From: Mark Rutland @ 2013-01-31 12:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359634539-9580-1-git-send-email-mark.rutland@arm.com>

The arch_timer driver supports a superset of the functionality of the
arm_generic driver, and is not tied to a particular arch.

This patch moves arm64 to use the arch_timer driver, gaining additional
functionality in doing so, and removes the (now unused) arm_generic
driver. Timer-related hooks specific to arm64 are moved into
arch/arm64/kernel/time.c.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
 arch/arm64/Kconfig                   |   1 +
 arch/arm64/include/asm/arch_timer.h  | 133 ++++++++++++++++++++
 arch/arm64/include/asm/arm_generic.h | 102 ---------------
 arch/arm64/kernel/time.c             |  29 ++++-
 drivers/clocksource/Kconfig          |   5 -
 drivers/clocksource/Makefile         |   1 -
 drivers/clocksource/arm_arch_timer.c |   1 +
 drivers/clocksource/arm_generic.c    | 232 -----------------------------------
 include/clocksource/arm_generic.h    |  21 ----
 9 files changed, 162 insertions(+), 363 deletions(-)
 create mode 100644 arch/arm64/include/asm/arch_timer.h
 delete mode 100644 arch/arm64/include/asm/arm_generic.h
 delete mode 100644 drivers/clocksource/arm_generic.c
 delete mode 100644 include/clocksource/arm_generic.h

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index f8f362a..2b6cef6 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -3,6 +3,7 @@ config ARM64
 	select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
 	select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
 	select ARM_AMBA
+	select ARM_ARCH_TIMER
 	select CLONE_BACKWARDS
 	select COMMON_CLK
 	select GENERIC_CLOCKEVENTS
diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h
new file mode 100644
index 0000000..91e2a6a
--- /dev/null
+++ b/arch/arm64/include/asm/arch_timer.h
@@ -0,0 +1,133 @@
+/*
+ * arch/arm64/include/asm/arch_timer.h
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_ARCH_TIMER_H
+#define __ASM_ARCH_TIMER_H
+
+#include <asm/barrier.h>
+
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <clocksource/arm_arch_timer.h>
+
+static inline void arch_timer_reg_write(int access, int reg, u32 val)
+{
+	if (access == ARCH_TIMER_PHYS_ACCESS) {
+		switch (reg) {
+		case ARCH_TIMER_REG_CTRL:
+			asm volatile("msr cntp_ctl_el0,  %0" : : "r" (val));
+			break;
+		case ARCH_TIMER_REG_TVAL:
+			asm volatile("msr cntp_tval_el0, %0" : : "r" (val));
+			break;
+		default:
+			BUILD_BUG();
+		}
+	} else if (access == ARCH_TIMER_VIRT_ACCESS) {
+		switch (reg) {
+		case ARCH_TIMER_REG_CTRL:
+			asm volatile("msr cntv_ctl_el0,  %0" : : "r" (val));
+			break;
+		case ARCH_TIMER_REG_TVAL:
+			asm volatile("msr cntv_tval_el0, %0" : : "r" (val));
+			break;
+		default:
+			BUILD_BUG();
+		}
+	} else {
+		BUILD_BUG();
+	}
+
+	isb();
+}
+
+static inline u32 arch_timer_reg_read(int access, int reg)
+{
+	u32 val;
+
+	if (access == ARCH_TIMER_PHYS_ACCESS) {
+		switch (reg) {
+		case ARCH_TIMER_REG_CTRL:
+			asm volatile("mrs %0,  cntp_ctl_el0" : "=r" (val));
+			break;
+		case ARCH_TIMER_REG_TVAL:
+			asm volatile("mrs %0, cntp_tval_el0" : "=r" (val));
+			break;
+		default:
+			BUILD_BUG();
+		}
+	} else if (access == ARCH_TIMER_VIRT_ACCESS) {
+		switch (reg) {
+		case ARCH_TIMER_REG_CTRL:
+			asm volatile("mrs %0,  cntv_ctl_el0" : "=r" (val));
+			break;
+		case ARCH_TIMER_REG_TVAL:
+			asm volatile("mrs %0, cntv_tval_el0" : "=r" (val));
+			break;
+		default:
+			BUILD_BUG();
+		}
+	} else {
+		BUILD_BUG();
+	}
+
+	return val;
+}
+
+static inline u32 arch_timer_get_cntfrq(void)
+{
+	u32 val;
+	asm volatile("mrs %0,   cntfrq_el0" : "=r" (val));
+	return val;
+}
+
+static inline void __cpuinit arch_counter_set_user_access(void)
+{
+	u32 cntkctl;
+
+	/* Disable user access to the timers and the physical counter. */
+	asm volatile("mrs	%0, cntkctl_el1" : "=r" (cntkctl));
+	cntkctl &= ~((3 << 8) | (1 << 0));
+
+	/* Enable user access to the virtual counter and frequency. */
+	cntkctl |= (1 << 1);
+	asm volatile("msr	cntkctl_el1, %0" : : "r" (cntkctl));
+}
+
+static inline u64 arch_counter_get_cntpct(void)
+{
+	u64 cval;
+
+	isb();
+	asm volatile("mrs %0, cntpct_el0" : "=r" (cval));
+
+	return cval;
+}
+
+static inline u64 arch_counter_get_cntvct(void)
+{
+	u64 cval;
+
+	isb();
+	asm volatile("mrs %0, cntvct_el0" : "=r" (cval));
+
+	return cval;
+}
+
+#endif
diff --git a/arch/arm64/include/asm/arm_generic.h b/arch/arm64/include/asm/arm_generic.h
deleted file mode 100644
index 6ece2f1..0000000
--- a/arch/arm64/include/asm/arm_generic.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * arch/arm64/include/asm/arm_generic.h
- *
- * Copyright (C) 2012 ARM Ltd.
- * Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef __ASM_ARM_GENERIC_H
-#define __ASM_ARM_GENERIC_H
-
-#include <linux/clocksource.h>
-
-#define ARCH_TIMER_CTRL_ENABLE		(1 << 0)
-#define ARCH_TIMER_CTRL_IMASK		(1 << 1)
-#define ARCH_TIMER_CTRL_ISTATUS		(1 << 2)
-
-#define ARCH_TIMER_REG_CTRL		0
-#define ARCH_TIMER_REG_FREQ		1
-#define ARCH_TIMER_REG_TVAL		2
-
-static inline void arch_timer_reg_write(int reg, u32 val)
-{
-	switch (reg) {
-	case ARCH_TIMER_REG_CTRL:
-		asm volatile("msr cntp_ctl_el0,  %0" : : "r" (val));
-		break;
-	case ARCH_TIMER_REG_TVAL:
-		asm volatile("msr cntp_tval_el0, %0" : : "r" (val));
-		break;
-	default:
-		BUILD_BUG();
-	}
-
-	isb();
-}
-
-static inline u32 arch_timer_reg_read(int reg)
-{
-	u32 val;
-
-	switch (reg) {
-	case ARCH_TIMER_REG_CTRL:
-		asm volatile("mrs %0,  cntp_ctl_el0" : "=r" (val));
-		break;
-	case ARCH_TIMER_REG_FREQ:
-		asm volatile("mrs %0,   cntfrq_el0" : "=r" (val));
-		break;
-	case ARCH_TIMER_REG_TVAL:
-		asm volatile("mrs %0, cntp_tval_el0" : "=r" (val));
-		break;
-	default:
-		BUILD_BUG();
-	}
-
-	return val;
-}
-
-static inline void __cpuinit arch_counter_enable_user_access(void)
-{
-	u32 cntkctl;
-
-	/* Disable user access to the timers and the physical counter. */
-	asm volatile("mrs	%0, cntkctl_el1" : "=r" (cntkctl));
-	cntkctl &= ~((3 << 8) | (1 << 0));
-
-	/* Enable user access to the virtual counter and frequency. */
-	cntkctl |= (1 << 1);
-	asm volatile("msr	cntkctl_el1, %0" : : "r" (cntkctl));
-}
-
-static inline cycle_t arch_counter_get_cntpct(void)
-{
-	cycle_t cval;
-
-	isb();
-	asm volatile("mrs %0, cntpct_el0" : "=r" (cval));
-
-	return cval;
-}
-
-static inline cycle_t arch_counter_get_cntvct(void)
-{
-	cycle_t cval;
-
-	isb();
-	asm volatile("mrs %0, cntvct_el0" : "=r" (cval));
-
-	return cval;
-}
-
-#endif
diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c
index 3b4b725..b0ef18d 100644
--- a/arch/arm64/kernel/time.c
+++ b/arch/arm64/kernel/time.c
@@ -31,8 +31,9 @@
 #include <linux/syscore_ops.h>
 #include <linux/timer.h>
 #include <linux/irq.h>
+#include <linux/delay.h>
 
-#include <clocksource/arm_generic.h>
+#include <clocksource/arm_arch_timer.h>
 
 #include <asm/thread_info.h>
 #include <asm/stacktrace.h>
@@ -59,7 +60,31 @@ unsigned long profile_pc(struct pt_regs *regs)
 EXPORT_SYMBOL(profile_pc);
 #endif
 
+static u64 sched_clock_mult __read_mostly;
+
+unsigned long long notrace sched_clock(void)
+{
+	return arch_timer_read_counter() * sched_clock_mult;
+}
+
+int read_current_timer(unsigned long *timer_value)
+{
+	*timer_value = arch_timer_read_counter();
+	return 0;
+}
+
 void __init time_init(void)
 {
-	arm_generic_timer_init();
+	u32 arch_timer_rate;
+
+	if (arch_timer_init())
+		panic("Unable to initialise architected timer.\n");
+
+	arch_timer_rate = arch_timer_get_rate();
+
+	/* Cache the sched_clock multiplier to save a divide in the hot path. */
+	sched_clock_mult = NSEC_PER_SEC / arch_timer_rate;
+
+	/* Calibrate the delay loop directly */
+	lpj_fine = arch_timer_rate / HZ;
 }
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index dbb085a..6479842 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -54,10 +54,5 @@ config CLKSRC_DBX500_PRCMU_SCHED_CLOCK
 	help
 	  Use the always on PRCMU Timer as sched_clock
 
-config CLKSRC_ARM_GENERIC
-	def_bool y if ARM64
-	help
-	  This option enables support for the ARM generic timer.
-
 config ARM_ARCH_TIMER
 	bool
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 32f858c..e69511c 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -17,5 +17,4 @@ obj-$(CONFIG_ARMADA_370_XP_TIMER)	+= time-armada-370-xp.o
 obj-$(CONFIG_ARCH_BCM2835)	+= bcm2835_timer.o
 obj-$(CONFIG_SUNXI_TIMER)	+= sunxi_timer.o
 
-obj-$(CONFIG_CLKSRC_ARM_GENERIC)	+= arm_generic.o
 obj-$(CONFIG_ARM_ARCH_TIMER)		+= arm_arch_timer.o
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 3e4739d..ec30a73 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -338,6 +338,7 @@ out:
 
 static const struct of_device_id arch_timer_of_match[] __initconst = {
 	{ .compatible	= "arm,armv7-timer",	},
+	{ .compatible	= "arm,armv8-timer",	},
 	{},
 };
 
diff --git a/drivers/clocksource/arm_generic.c b/drivers/clocksource/arm_generic.c
deleted file mode 100644
index 8ae1a61..0000000
--- a/drivers/clocksource/arm_generic.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Generic timers support
- *
- * Copyright (C) 2012 ARM Ltd.
- * Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/smp.h>
-#include <linux/cpu.h>
-#include <linux/jiffies.h>
-#include <linux/interrupt.h>
-#include <linux/clockchips.h>
-#include <linux/of_irq.h>
-#include <linux/io.h>
-
-#include <clocksource/arm_generic.h>
-
-#include <asm/arm_generic.h>
-
-static u32 arch_timer_rate;
-static u64 sched_clock_mult __read_mostly;
-static DEFINE_PER_CPU(struct clock_event_device, arch_timer_evt);
-static int arch_timer_ppi;
-
-static irqreturn_t arch_timer_handle_irq(int irq, void *dev_id)
-{
-	struct clock_event_device *evt = dev_id;
-	unsigned long ctrl;
-
-	ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
-	if (ctrl & ARCH_TIMER_CTRL_ISTATUS) {
-		ctrl |= ARCH_TIMER_CTRL_IMASK;
-		arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
-		evt->event_handler(evt);
-		return IRQ_HANDLED;
-	}
-
-	return IRQ_NONE;
-}
-
-static void arch_timer_stop(void)
-{
-	unsigned long ctrl;
-
-	ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
-	ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
-	arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
-}
-
-static void arch_timer_set_mode(enum clock_event_mode mode,
-				struct clock_event_device *clk)
-{
-	switch (mode) {
-	case CLOCK_EVT_MODE_UNUSED:
-	case CLOCK_EVT_MODE_SHUTDOWN:
-		arch_timer_stop();
-		break;
-	default:
-		break;
-	}
-}
-
-static int arch_timer_set_next_event(unsigned long evt,
-				     struct clock_event_device *unused)
-{
-	unsigned long ctrl;
-
-	ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
-	ctrl |= ARCH_TIMER_CTRL_ENABLE;
-	ctrl &= ~ARCH_TIMER_CTRL_IMASK;
-
-	arch_timer_reg_write(ARCH_TIMER_REG_TVAL, evt);
-	arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
-
-	return 0;
-}
-
-static void __cpuinit arch_timer_setup(struct clock_event_device *clk)
-{
-	/* Let's make sure the timer is off before doing anything else */
-	arch_timer_stop();
-
-	clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP;
-	clk->name = "arch_sys_timer";
-	clk->rating = 400;
-	clk->set_mode = arch_timer_set_mode;
-	clk->set_next_event = arch_timer_set_next_event;
-	clk->irq = arch_timer_ppi;
-	clk->cpumask = cpumask_of(smp_processor_id());
-
-	clockevents_config_and_register(clk, arch_timer_rate,
-					0xf, 0x7fffffff);
-
-	enable_percpu_irq(clk->irq, 0);
-
-	/* Ensure the virtual counter is visible to userspace for the vDSO. */
-	arch_counter_enable_user_access();
-}
-
-static void __init arch_timer_calibrate(void)
-{
-	if (arch_timer_rate == 0) {
-		arch_timer_reg_write(ARCH_TIMER_REG_CTRL, 0);
-		arch_timer_rate = arch_timer_reg_read(ARCH_TIMER_REG_FREQ);
-
-		/* Check the timer frequency. */
-		if (arch_timer_rate == 0)
-			panic("Architected timer frequency is set to zero.\n"
-			      "You must set this in your .dts file\n");
-	}
-
-	/* Cache the sched_clock multiplier to save a divide in the hot path. */
-
-	sched_clock_mult = DIV_ROUND_CLOSEST(NSEC_PER_SEC, arch_timer_rate);
-
-	pr_info("Architected local timer running at %u.%02uMHz.\n",
-		 arch_timer_rate / 1000000, (arch_timer_rate / 10000) % 100);
-}
-
-static cycle_t arch_counter_read(struct clocksource *cs)
-{
-	return arch_counter_get_cntpct();
-}
-
-static struct clocksource clocksource_counter = {
-	.name	= "arch_sys_counter",
-	.rating	= 400,
-	.read	= arch_counter_read,
-	.mask	= CLOCKSOURCE_MASK(56),
-	.flags	= (CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_VALID_FOR_HRES),
-};
-
-int read_current_timer(unsigned long *timer_value)
-{
-	*timer_value = arch_counter_get_cntpct();
-	return 0;
-}
-
-unsigned long long notrace sched_clock(void)
-{
-	return arch_counter_get_cntvct() * sched_clock_mult;
-}
-
-static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self,
-					   unsigned long action, void *hcpu)
-{
-	int cpu = (long)hcpu;
-	struct clock_event_device *clk = per_cpu_ptr(&arch_timer_evt, cpu);
-
-	switch(action) {
-	case CPU_STARTING:
-	case CPU_STARTING_FROZEN:
-		arch_timer_setup(clk);
-		break;
-
-	case CPU_DYING:
-	case CPU_DYING_FROZEN:
-		pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
-			 clk->irq, cpu);
-		disable_percpu_irq(clk->irq);
-		arch_timer_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
-		break;
-	}
-
-	return NOTIFY_OK;
-}
-
-static struct notifier_block __cpuinitdata arch_timer_cpu_nb = {
-	.notifier_call = arch_timer_cpu_notify,
-};
-
-static const struct of_device_id arch_timer_of_match[] __initconst = {
-	{ .compatible = "arm,armv8-timer" },
-	{},
-};
-
-int __init arm_generic_timer_init(void)
-{
-	struct device_node *np;
-	int err;
-	u32 freq;
-
-	np = of_find_matching_node(NULL, arch_timer_of_match);
-	if (!np) {
-		pr_err("arch_timer: can't find DT node\n");
-		return -ENODEV;
-	}
-
-	/* Try to determine the frequency from the device tree or CNTFRQ */
-	if (!of_property_read_u32(np, "clock-frequency", &freq))
-		arch_timer_rate = freq;
-	arch_timer_calibrate();
-
-	arch_timer_ppi = irq_of_parse_and_map(np, 0);
-	pr_info("arch_timer: found %s irq %d\n", np->name, arch_timer_ppi);
-
-	err = request_percpu_irq(arch_timer_ppi, arch_timer_handle_irq,
-				 np->name, &arch_timer_evt);
-	if (err) {
-		pr_err("arch_timer: can't register interrupt %d (%d)\n",
-		       arch_timer_ppi, err);
-		return err;
-	}
-
-	clocksource_register_hz(&clocksource_counter, arch_timer_rate);
-
-	/* Calibrate the delay loop directly */
-	lpj_fine = DIV_ROUND_CLOSEST(arch_timer_rate, HZ);
-
-	/* Immediately configure the timer on the boot CPU */
-	arch_timer_setup(this_cpu_ptr(&arch_timer_evt));
-
-	register_cpu_notifier(&arch_timer_cpu_nb);
-
-	return 0;
-}
diff --git a/include/clocksource/arm_generic.h b/include/clocksource/arm_generic.h
deleted file mode 100644
index 5b41b0d..0000000
--- a/include/clocksource/arm_generic.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2012 ARM Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef __CLKSOURCE_ARM_GENERIC_H
-#define __CLKSOURCE_ARM_GENERIC_H
-
-extern int arm_generic_timer_init(void);
-
-#endif
-- 
1.8.1.1

^ permalink raw reply related

* [PATCHv5 11/16] arm64: arm_generic: prevent reading stale time
From: Mark Rutland @ 2013-01-31 12:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359634539-9580-1-git-send-email-mark.rutland@arm.com>

Currently arch_counter_get_cnt{p,v}ct can be speculated, allowing for
stale time values to be read. This could be problematic for the delay
loop and other sensitive functions, as the time delta could jump around
unexpectedly.

This patch adds isbs to arch_counter_get_cnt{p,v}ct, preventing this
possibility.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
---
 arch/arm64/include/asm/arm_generic.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/include/asm/arm_generic.h b/arch/arm64/include/asm/arm_generic.h
index df2aeb8..6ece2f1 100644
--- a/arch/arm64/include/asm/arm_generic.h
+++ b/arch/arm64/include/asm/arm_generic.h
@@ -83,6 +83,7 @@ static inline cycle_t arch_counter_get_cntpct(void)
 {
 	cycle_t cval;
 
+	isb();
 	asm volatile("mrs %0, cntpct_el0" : "=r" (cval));
 
 	return cval;
@@ -92,6 +93,7 @@ static inline cycle_t arch_counter_get_cntvct(void)
 {
 	cycle_t cval;
 
+	isb();
 	asm volatile("mrs %0, cntvct_el0" : "=r" (cval));
 
 	return cval;
-- 
1.8.1.1

^ permalink raw reply related

* [PATCHv5 10/16] arm: arch_timer: move core to drivers/clocksource
From: Mark Rutland @ 2013-01-31 12:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359634539-9580-1-git-send-email-mark.rutland@arm.com>

The core functionality of the arch_timer driver is not directly tied to
anything under arch/arm, and can be split out.

This patch factors out the core of the arch_timer driver, so it can be
shared with other architectures. A couple of functions are added so
that architecture-specific code can interact with the driver without
needing to touch its internals.

The ARM_ARCH_TIMER config variable is moved out to
drivers/clocksource/Kconfig, existing uses in arch/arm are replaced with
HAVE_ARM_ARCH_TIMER, which selects it.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/Kconfig                     |   3 +-
 arch/arm/include/asm/arch_timer.h    |  19 +-
 arch/arm/kernel/arch_timer.c         | 386 ++---------------------------------
 arch/arm/mach-omap2/Kconfig          |   2 +-
 drivers/clocksource/Kconfig          |   3 +
 drivers/clocksource/Makefile         |   1 +
 drivers/clocksource/arm_arch_timer.c | 385 ++++++++++++++++++++++++++++++++++
 include/clocksource/arm_arch_timer.h |  63 ++++++
 8 files changed, 476 insertions(+), 386 deletions(-)
 create mode 100644 drivers/clocksource/arm_arch_timer.c
 create mode 100644 include/clocksource/arm_arch_timer.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 67874b8..e1162f5 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1572,9 +1572,10 @@ config HAVE_ARM_SCU
 	help
 	  This option enables support for the ARM system coherency unit
 
-config ARM_ARCH_TIMER
+config HAVE_ARM_ARCH_TIMER
 	bool "Architected timer support"
 	depends on CPU_V7
+	select ARM_ARCH_TIMER
 	help
 	  This option enables support for the ARM architected timer
 
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
index 729f6d9..7ade91d 100644
--- a/arch/arm/include/asm/arch_timer.h
+++ b/arch/arm/include/asm/arch_timer.h
@@ -4,22 +4,14 @@
 #include <asm/barrier.h>
 #include <asm/errno.h>
 #include <linux/clocksource.h>
+#include <linux/init.h>
 #include <linux/types.h>
 
+#include <clocksource/arm_arch_timer.h>
+
 #ifdef CONFIG_ARM_ARCH_TIMER
 int arch_timer_of_register(void);
 int arch_timer_sched_clock_init(void);
-struct timecounter *arch_timer_get_timecounter(void);
-
-#define ARCH_TIMER_CTRL_ENABLE		(1 << 0)
-#define ARCH_TIMER_CTRL_IT_MASK		(1 << 1)
-#define ARCH_TIMER_CTRL_IT_STAT		(1 << 2)
-
-#define ARCH_TIMER_REG_CTRL		0
-#define ARCH_TIMER_REG_TVAL		1
-
-#define ARCH_TIMER_PHYS_ACCESS		0
-#define ARCH_TIMER_VIRT_ACCESS		1
 
 /*
  * These register accessors are marked inline so the compiler can
@@ -128,11 +120,6 @@ static inline int arch_timer_sched_clock_init(void)
 {
 	return -ENXIO;
 }
-
-static inline struct timecounter *arch_timer_get_timecounter(void)
-{
-	return NULL;
-}
 #endif
 
 #endif
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 94f5033..36ebcf4 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -9,402 +9,52 @@
  * published by the Free Software Foundation.
  */
 #include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/smp.h>
-#include <linux/cpu.h>
-#include <linux/jiffies.h>
-#include <linux/clockchips.h>
-#include <linux/interrupt.h>
-#include <linux/of_irq.h>
-#include <linux/io.h>
+#include <linux/types.h>
 
 #include <asm/delay.h>
-#include <asm/arch_timer.h>
 #include <asm/sched_clock.h>
 
-static u32 arch_timer_rate;
+#include <clocksource/arm_arch_timer.h>
 
-enum ppi_nr {
-	PHYS_SECURE_PPI,
-	PHYS_NONSECURE_PPI,
-	VIRT_PPI,
-	HYP_PPI,
-	MAX_TIMER_PPI
-};
-
-static int arch_timer_ppi[MAX_TIMER_PPI];
-
-static struct clock_event_device __percpu *arch_timer_evt;
-static struct delay_timer arch_delay_timer;
-
-static bool arch_timer_use_virtual = true;
-
-/*
- * Architected system timer support.
- */
-
-static irqreturn_t inline timer_handler(const int access,
-					struct clock_event_device *evt)
-{
-	unsigned long ctrl;
-	ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
-	if (ctrl & ARCH_TIMER_CTRL_IT_STAT) {
-		ctrl |= ARCH_TIMER_CTRL_IT_MASK;
-		arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
-		evt->event_handler(evt);
-		return IRQ_HANDLED;
-	}
-
-	return IRQ_NONE;
-}
-
-static irqreturn_t arch_timer_handler_virt(int irq, void *dev_id)
-{
-	struct clock_event_device *evt = dev_id;
-
-	return timer_handler(ARCH_TIMER_VIRT_ACCESS, evt);
-}
-
-static irqreturn_t arch_timer_handler_phys(int irq, void *dev_id)
-{
-	struct clock_event_device *evt = dev_id;
-
-	return timer_handler(ARCH_TIMER_PHYS_ACCESS, evt);
-}
-
-static inline void timer_set_mode(const int access, int mode)
-{
-	unsigned long ctrl;
-	switch (mode) {
-	case CLOCK_EVT_MODE_UNUSED:
-	case CLOCK_EVT_MODE_SHUTDOWN:
-		ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
-		ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
-		arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
-		break;
-	default:
-		break;
-	}
-}
-
-static void arch_timer_set_mode_virt(enum clock_event_mode mode,
-				     struct clock_event_device *clk)
-{
-	timer_set_mode(ARCH_TIMER_VIRT_ACCESS, mode);
-}
-
-static void arch_timer_set_mode_phys(enum clock_event_mode mode,
-				     struct clock_event_device *clk)
-{
-	timer_set_mode(ARCH_TIMER_PHYS_ACCESS, mode);
-}
-
-static inline void set_next_event(const int access, unsigned long evt)
-{
-	unsigned long ctrl;
-	ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
-	ctrl |= ARCH_TIMER_CTRL_ENABLE;
-	ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
-	arch_timer_reg_write(access, ARCH_TIMER_REG_TVAL, evt);
-	arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
-}
-
-static int arch_timer_set_next_event_virt(unsigned long evt,
-					  struct clock_event_device *unused)
-{
-	set_next_event(ARCH_TIMER_VIRT_ACCESS, evt);
-	return 0;
-}
-
-static int arch_timer_set_next_event_phys(unsigned long evt,
-					  struct clock_event_device *unused)
-{
-	set_next_event(ARCH_TIMER_PHYS_ACCESS, evt);
-	return 0;
-}
-
-static int __cpuinit arch_timer_setup(struct clock_event_device *clk)
-{
-	clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP;
-	clk->name = "arch_sys_timer";
-	clk->rating = 450;
-	if (arch_timer_use_virtual) {
-		clk->irq = arch_timer_ppi[VIRT_PPI];
-		clk->set_mode = arch_timer_set_mode_virt;
-		clk->set_next_event = arch_timer_set_next_event_virt;
-	} else {
-		clk->irq = arch_timer_ppi[PHYS_SECURE_PPI];
-		clk->set_mode = arch_timer_set_mode_phys;
-		clk->set_next_event = arch_timer_set_next_event_phys;
-	}
-
-	clk->cpumask = cpumask_of(smp_processor_id());
-
-	clk->set_mode(CLOCK_EVT_MODE_SHUTDOWN, NULL);
-
-	clockevents_config_and_register(clk, arch_timer_rate,
-					0xf, 0x7fffffff);
-
-	if (arch_timer_use_virtual)
-		enable_percpu_irq(arch_timer_ppi[VIRT_PPI], 0);
-	else {
-		enable_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI], 0);
-		if (arch_timer_ppi[PHYS_NONSECURE_PPI])
-			enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], 0);
-	}
-
-	arch_counter_set_user_access();
-
-	return 0;
-}
-
-static int arch_timer_available(void)
-{
-	u32 freq;
-
-	if (arch_timer_rate == 0) {
-		freq = arch_timer_get_cntfrq();
-
-		/* Check the timer frequency. */
-		if (freq == 0) {
-			pr_warn("Architected timer frequency not available\n");
-			return -EINVAL;
-		}
-
-		arch_timer_rate = freq;
-	}
-
-	pr_info_once("Architected local timer running at %lu.%02luMHz (%s).\n",
-		     (unsigned long)arch_timer_rate / 1000000,
-		     (unsigned long)(arch_timer_rate / 10000) % 100,
-		     arch_timer_use_virtual ? "virt" : "phys");
-	return 0;
-}
-
-/*
- * Some external users of arch_timer_read_counter (e.g. sched_clock) may try to
- * call it before it has been initialised. Rather than incur a performance
- * penalty checking for initialisation, provide a default implementation that
- * won't lead to time appearing to jump backwards.
- */
-static u64 arch_timer_read_zero(void)
-{
-	return 0;
-}
-
-u64 (*arch_timer_read_counter)(void) = arch_timer_read_zero;
-
-static u32 arch_timer_read_counter32(void)
-{
-	return arch_timer_read_counter();
-}
-
-static cycle_t arch_counter_read(struct clocksource *cs)
+static unsigned long arch_timer_read_counter_long(void)
 {
 	return arch_timer_read_counter();
 }
 
-static unsigned long arch_timer_read_current_timer(void)
+static u32 arch_timer_read_counter_u32(void)
 {
 	return arch_timer_read_counter();
 }
 
-static cycle_t arch_counter_read_cc(const struct cyclecounter *cc)
-{
-	return arch_timer_read_counter();
-}
-
-static struct clocksource clocksource_counter = {
-	.name	= "arch_sys_counter",
-	.rating	= 400,
-	.read	= arch_counter_read,
-	.mask	= CLOCKSOURCE_MASK(56),
-	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static struct cyclecounter cyclecounter = {
-	.read	= arch_counter_read_cc,
-	.mask	= CLOCKSOURCE_MASK(56),
-};
-
-static struct timecounter timecounter;
-
-struct timecounter *arch_timer_get_timecounter(void)
-{
-	return &timecounter;
-}
-
-static void __cpuinit arch_timer_stop(struct clock_event_device *clk)
-{
-	pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
-		 clk->irq, smp_processor_id());
-
-	if (arch_timer_use_virtual)
-		disable_percpu_irq(arch_timer_ppi[VIRT_PPI]);
-	else {
-		disable_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI]);
-		if (arch_timer_ppi[PHYS_NONSECURE_PPI])
-			disable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI]);
-	}
-
-	clk->set_mode(CLOCK_EVT_MODE_UNUSED, clk);
-}
-
-static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self,
-					   unsigned long action, void *hcpu)
-{
-	struct clock_event_device *evt = this_cpu_ptr(arch_timer_evt);
-
-	switch (action & ~CPU_TASKS_FROZEN) {
-	case CPU_STARTING:
-		arch_timer_setup(evt);
-		break;
-	case CPU_DYING:
-		arch_timer_stop(evt);
-		break;
-	}
-
-	return NOTIFY_OK;
-}
-
-static struct notifier_block arch_timer_cpu_nb __cpuinitdata = {
-	.notifier_call = arch_timer_cpu_notify,
-};
+static struct delay_timer arch_delay_timer;
 
-static int __init arch_timer_register(void)
+static void __init arch_timer_delay_timer_register(void)
 {
-	int err;
-	int ppi;
-
-	err = arch_timer_available();
-	if (err)
-		goto out;
-
-	arch_timer_evt = alloc_percpu(struct clock_event_device);
-	if (!arch_timer_evt) {
-		err = -ENOMEM;
-		goto out;
-	}
-
-	clocksource_register_hz(&clocksource_counter, arch_timer_rate);
-	cyclecounter.mult = clocksource_counter.mult;
-	cyclecounter.shift = clocksource_counter.shift;
-	timecounter_init(&timecounter, &cyclecounter,
-			 arch_counter_get_cntpct());
-
-	if (arch_timer_use_virtual) {
-		ppi = arch_timer_ppi[VIRT_PPI];
-		err = request_percpu_irq(ppi, arch_timer_handler_virt,
-					 "arch_timer", arch_timer_evt);
-	} else {
-		ppi = arch_timer_ppi[PHYS_SECURE_PPI];
-		err = request_percpu_irq(ppi, arch_timer_handler_phys,
-					 "arch_timer", arch_timer_evt);
-		if (!err && arch_timer_ppi[PHYS_NONSECURE_PPI]) {
-			ppi = arch_timer_ppi[PHYS_NONSECURE_PPI];
-			err = request_percpu_irq(ppi, arch_timer_handler_phys,
-						 "arch_timer", arch_timer_evt);
-			if (err)
-				free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI],
-						arch_timer_evt);
-		}
-	}
-
-	if (err) {
-		pr_err("arch_timer: can't register interrupt %d (%d)\n",
-		       ppi, err);
-		goto out_free;
-	}
-
-	err = register_cpu_notifier(&arch_timer_cpu_nb);
-	if (err)
-		goto out_free_irq;
-
-	/* Immediately configure the timer on the boot CPU */
-	arch_timer_setup(this_cpu_ptr(arch_timer_evt));
-
 	/* Use the architected timer for the delay loop. */
-	arch_delay_timer.read_current_timer = &arch_timer_read_current_timer;
-	arch_delay_timer.freq = arch_timer_rate;
+	arch_delay_timer.read_current_timer = arch_timer_read_counter_long;
+	arch_delay_timer.freq = arch_timer_get_rate();
 	register_current_timer_delay(&arch_delay_timer);
-	return 0;
-
-out_free_irq:
-	if (arch_timer_use_virtual)
-		free_percpu_irq(arch_timer_ppi[VIRT_PPI], arch_timer_evt);
-	else {
-		free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI],
-				arch_timer_evt);
-		if (arch_timer_ppi[PHYS_NONSECURE_PPI])
-			free_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI],
-					arch_timer_evt);
-	}
-
-out_free:
-	free_percpu(arch_timer_evt);
-out:
-	return err;
 }
 
-static const struct of_device_id arch_timer_of_match[] __initconst = {
-	{ .compatible	= "arm,armv7-timer",	},
-	{},
-};
-
 int __init arch_timer_of_register(void)
 {
-	struct device_node *np;
-	u32 freq;
-	int i;
-
-	np = of_find_matching_node(NULL, arch_timer_of_match);
-	if (!np) {
-		pr_err("arch_timer: can't find DT node\n");
-		return -ENODEV;
-	}
+	int ret;
 
-	/* Try to determine the frequency from the device tree or CNTFRQ */
-	if (!of_property_read_u32(np, "clock-frequency", &freq))
-		arch_timer_rate = freq;
+	ret = arch_timer_init();
+	if (ret)
+		return ret;
 
-	for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
-		arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
+	arch_timer_delay_timer_register();
 
-	of_node_put(np);
-
-	/*
-	 * If no interrupt provided for virtual timer, we'll have to
-	 * stick to the physical timer. It'd better be accessible...
-	 */
-	if (!arch_timer_ppi[VIRT_PPI]) {
-		arch_timer_use_virtual = false;
-
-		if (!arch_timer_ppi[PHYS_SECURE_PPI] ||
-		    !arch_timer_ppi[PHYS_NONSECURE_PPI]) {
-			pr_warn("arch_timer: No interrupt available, giving up\n");
-			return -EINVAL;
-		}
-	}
-
-	if (arch_timer_use_virtual)
-		arch_timer_read_counter = arch_counter_get_cntvct;
-	else
-		arch_timer_read_counter = arch_counter_get_cntpct;
-
-	return arch_timer_register();
+	return 0;
 }
 
 int __init arch_timer_sched_clock_init(void)
 {
-	int err;
-
-	err = arch_timer_available();
-	if (err)
-		return err;
+	if (arch_timer_get_rate() == 0)
+		return -ENXIO;
 
-	setup_sched_clock(arch_timer_read_counter32,
-			  32, arch_timer_rate);
+	setup_sched_clock(arch_timer_read_counter_u32,
+			  32, arch_timer_get_rate());
 	return 0;
 }
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 41b581f..9d7909e 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -76,12 +76,12 @@ config ARCH_OMAP4
 
 config SOC_OMAP5
 	bool "TI OMAP5"
-	select ARM_ARCH_TIMER
 	select ARM_CPU_SUSPEND if PM
 	select ARM_GIC
 	select CPU_V7
 	select HAVE_SMP
 	select COMMON_CLK
+	select HAVE_ARM_ARCH_TIMER
 
 comment "OMAP Core Type"
 	depends on ARCH_OMAP2
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 7fdcbd3..dbb085a 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -58,3 +58,6 @@ config CLKSRC_ARM_GENERIC
 	def_bool y if ARM64
 	help
 	  This option enables support for the ARM generic timer.
+
+config ARM_ARCH_TIMER
+	bool
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index f93453d..32f858c 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -18,3 +18,4 @@ obj-$(CONFIG_ARCH_BCM2835)	+= bcm2835_timer.o
 obj-$(CONFIG_SUNXI_TIMER)	+= sunxi_timer.o
 
 obj-$(CONFIG_CLKSRC_ARM_GENERIC)	+= arm_generic.o
+obj-$(CONFIG_ARM_ARCH_TIMER)		+= arm_arch_timer.o
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
new file mode 100644
index 0000000..3e4739d
--- /dev/null
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -0,0 +1,385 @@
+/*
+ *  linux/drivers/clocksource/arm_arch_timer.c
+ *
+ *  Copyright (C) 2011 ARM Ltd.
+ *  All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/smp.h>
+#include <linux/cpu.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+
+#include <asm/arch_timer.h>
+
+#include <clocksource/arm_arch_timer.h>
+
+static u32 arch_timer_rate;
+
+enum ppi_nr {
+	PHYS_SECURE_PPI,
+	PHYS_NONSECURE_PPI,
+	VIRT_PPI,
+	HYP_PPI,
+	MAX_TIMER_PPI
+};
+
+static int arch_timer_ppi[MAX_TIMER_PPI];
+
+static struct clock_event_device __percpu *arch_timer_evt;
+
+static bool arch_timer_use_virtual = true;
+
+/*
+ * Architected system timer support.
+ */
+
+static inline irqreturn_t timer_handler(const int access,
+					struct clock_event_device *evt)
+{
+	unsigned long ctrl;
+	ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
+	if (ctrl & ARCH_TIMER_CTRL_IT_STAT) {
+		ctrl |= ARCH_TIMER_CTRL_IT_MASK;
+		arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
+		evt->event_handler(evt);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static irqreturn_t arch_timer_handler_virt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = dev_id;
+
+	return timer_handler(ARCH_TIMER_VIRT_ACCESS, evt);
+}
+
+static irqreturn_t arch_timer_handler_phys(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = dev_id;
+
+	return timer_handler(ARCH_TIMER_PHYS_ACCESS, evt);
+}
+
+static inline void timer_set_mode(const int access, int mode)
+{
+	unsigned long ctrl;
+	switch (mode) {
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
+		ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
+		arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
+		break;
+	default:
+		break;
+	}
+}
+
+static void arch_timer_set_mode_virt(enum clock_event_mode mode,
+				     struct clock_event_device *clk)
+{
+	timer_set_mode(ARCH_TIMER_VIRT_ACCESS, mode);
+}
+
+static void arch_timer_set_mode_phys(enum clock_event_mode mode,
+				     struct clock_event_device *clk)
+{
+	timer_set_mode(ARCH_TIMER_PHYS_ACCESS, mode);
+}
+
+static inline void set_next_event(const int access, unsigned long evt)
+{
+	unsigned long ctrl;
+	ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
+	ctrl |= ARCH_TIMER_CTRL_ENABLE;
+	ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
+	arch_timer_reg_write(access, ARCH_TIMER_REG_TVAL, evt);
+	arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
+}
+
+static int arch_timer_set_next_event_virt(unsigned long evt,
+					  struct clock_event_device *unused)
+{
+	set_next_event(ARCH_TIMER_VIRT_ACCESS, evt);
+	return 0;
+}
+
+static int arch_timer_set_next_event_phys(unsigned long evt,
+					  struct clock_event_device *unused)
+{
+	set_next_event(ARCH_TIMER_PHYS_ACCESS, evt);
+	return 0;
+}
+
+static int __cpuinit arch_timer_setup(struct clock_event_device *clk)
+{
+	clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP;
+	clk->name = "arch_sys_timer";
+	clk->rating = 450;
+	if (arch_timer_use_virtual) {
+		clk->irq = arch_timer_ppi[VIRT_PPI];
+		clk->set_mode = arch_timer_set_mode_virt;
+		clk->set_next_event = arch_timer_set_next_event_virt;
+	} else {
+		clk->irq = arch_timer_ppi[PHYS_SECURE_PPI];
+		clk->set_mode = arch_timer_set_mode_phys;
+		clk->set_next_event = arch_timer_set_next_event_phys;
+	}
+
+	clk->cpumask = cpumask_of(smp_processor_id());
+
+	clk->set_mode(CLOCK_EVT_MODE_SHUTDOWN, NULL);
+
+	clockevents_config_and_register(clk, arch_timer_rate,
+					0xf, 0x7fffffff);
+
+	if (arch_timer_use_virtual)
+		enable_percpu_irq(arch_timer_ppi[VIRT_PPI], 0);
+	else {
+		enable_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI], 0);
+		if (arch_timer_ppi[PHYS_NONSECURE_PPI])
+			enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], 0);
+	}
+
+	arch_counter_set_user_access();
+
+	return 0;
+}
+
+static int arch_timer_available(void)
+{
+	u32 freq;
+
+	if (arch_timer_rate == 0) {
+		freq = arch_timer_get_cntfrq();
+
+		/* Check the timer frequency. */
+		if (freq == 0) {
+			pr_warn("Architected timer frequency not available\n");
+			return -EINVAL;
+		}
+
+		arch_timer_rate = freq;
+	}
+
+	pr_info_once("Architected local timer running at %lu.%02luMHz (%s).\n",
+		     (unsigned long)arch_timer_rate / 1000000,
+		     (unsigned long)(arch_timer_rate / 10000) % 100,
+		     arch_timer_use_virtual ? "virt" : "phys");
+	return 0;
+}
+
+u32 arch_timer_get_rate(void)
+{
+	return arch_timer_rate;
+}
+
+/*
+ * Some external users of arch_timer_read_counter (e.g. sched_clock) may try to
+ * call it before it has been initialised. Rather than incur a performance
+ * penalty checking for initialisation, provide a default implementation that
+ * won't lead to time appearing to jump backwards.
+ */
+static u64 arch_timer_read_zero(void)
+{
+	return 0;
+}
+
+u64 (*arch_timer_read_counter)(void) = arch_timer_read_zero;
+
+static cycle_t arch_counter_read(struct clocksource *cs)
+{
+	return arch_timer_read_counter();
+}
+
+static cycle_t arch_counter_read_cc(const struct cyclecounter *cc)
+{
+	return arch_timer_read_counter();
+}
+
+static struct clocksource clocksource_counter = {
+	.name	= "arch_sys_counter",
+	.rating	= 400,
+	.read	= arch_counter_read,
+	.mask	= CLOCKSOURCE_MASK(56),
+	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static struct cyclecounter cyclecounter = {
+	.read	= arch_counter_read_cc,
+	.mask	= CLOCKSOURCE_MASK(56),
+};
+
+static struct timecounter timecounter;
+
+struct timecounter *arch_timer_get_timecounter(void)
+{
+	return &timecounter;
+}
+
+static void __cpuinit arch_timer_stop(struct clock_event_device *clk)
+{
+	pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
+		 clk->irq, smp_processor_id());
+
+	if (arch_timer_use_virtual)
+		disable_percpu_irq(arch_timer_ppi[VIRT_PPI]);
+	else {
+		disable_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI]);
+		if (arch_timer_ppi[PHYS_NONSECURE_PPI])
+			disable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI]);
+	}
+
+	clk->set_mode(CLOCK_EVT_MODE_UNUSED, clk);
+}
+
+static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self,
+					   unsigned long action, void *hcpu)
+{
+	struct clock_event_device *evt = this_cpu_ptr(arch_timer_evt);
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_STARTING:
+		arch_timer_setup(evt);
+		break;
+	case CPU_DYING:
+		arch_timer_stop(evt);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block arch_timer_cpu_nb __cpuinitdata = {
+	.notifier_call = arch_timer_cpu_notify,
+};
+
+static int __init arch_timer_register(void)
+{
+	int err;
+	int ppi;
+
+	err = arch_timer_available();
+	if (err)
+		goto out;
+
+	arch_timer_evt = alloc_percpu(struct clock_event_device);
+	if (!arch_timer_evt) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	clocksource_register_hz(&clocksource_counter, arch_timer_rate);
+	cyclecounter.mult = clocksource_counter.mult;
+	cyclecounter.shift = clocksource_counter.shift;
+	timecounter_init(&timecounter, &cyclecounter,
+			 arch_counter_get_cntpct());
+
+	if (arch_timer_use_virtual) {
+		ppi = arch_timer_ppi[VIRT_PPI];
+		err = request_percpu_irq(ppi, arch_timer_handler_virt,
+					 "arch_timer", arch_timer_evt);
+	} else {
+		ppi = arch_timer_ppi[PHYS_SECURE_PPI];
+		err = request_percpu_irq(ppi, arch_timer_handler_phys,
+					 "arch_timer", arch_timer_evt);
+		if (!err && arch_timer_ppi[PHYS_NONSECURE_PPI]) {
+			ppi = arch_timer_ppi[PHYS_NONSECURE_PPI];
+			err = request_percpu_irq(ppi, arch_timer_handler_phys,
+						 "arch_timer", arch_timer_evt);
+			if (err)
+				free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI],
+						arch_timer_evt);
+		}
+	}
+
+	if (err) {
+		pr_err("arch_timer: can't register interrupt %d (%d)\n",
+		       ppi, err);
+		goto out_free;
+	}
+
+	err = register_cpu_notifier(&arch_timer_cpu_nb);
+	if (err)
+		goto out_free_irq;
+
+	/* Immediately configure the timer on the boot CPU */
+	arch_timer_setup(this_cpu_ptr(arch_timer_evt));
+
+	return 0;
+
+out_free_irq:
+	if (arch_timer_use_virtual)
+		free_percpu_irq(arch_timer_ppi[VIRT_PPI], arch_timer_evt);
+	else {
+		free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI],
+				arch_timer_evt);
+		if (arch_timer_ppi[PHYS_NONSECURE_PPI])
+			free_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI],
+					arch_timer_evt);
+	}
+
+out_free:
+	free_percpu(arch_timer_evt);
+out:
+	return err;
+}
+
+static const struct of_device_id arch_timer_of_match[] __initconst = {
+	{ .compatible	= "arm,armv7-timer",	},
+	{},
+};
+
+int __init arch_timer_init(void)
+{
+	struct device_node *np;
+	u32 freq;
+	int i;
+
+	np = of_find_matching_node(NULL, arch_timer_of_match);
+	if (!np) {
+		pr_err("arch_timer: can't find DT node\n");
+		return -ENODEV;
+	}
+
+	/* Try to determine the frequency from the device tree or CNTFRQ */
+	if (!of_property_read_u32(np, "clock-frequency", &freq))
+		arch_timer_rate = freq;
+
+	for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
+		arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
+
+	of_node_put(np);
+
+	/*
+	 * If no interrupt provided for virtual timer, we'll have to
+	 * stick to the physical timer. It'd better be accessible...
+	 */
+	if (!arch_timer_ppi[VIRT_PPI]) {
+		arch_timer_use_virtual = false;
+
+		if (!arch_timer_ppi[PHYS_SECURE_PPI] ||
+		    !arch_timer_ppi[PHYS_NONSECURE_PPI]) {
+			pr_warn("arch_timer: No interrupt available, giving up\n");
+			return -EINVAL;
+		}
+	}
+
+	if (arch_timer_use_virtual)
+		arch_timer_read_counter = arch_counter_get_cntvct;
+	else
+		arch_timer_read_counter = arch_counter_get_cntpct;
+
+	return arch_timer_register();
+}
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h
new file mode 100644
index 0000000..b61f996
--- /dev/null
+++ b/include/clocksource/arm_arch_timer.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __CLKSOURCE_ARM_ARCH_TIMER_H
+#define __CLKSOURCE_ARM_ARCH_TIMER_H
+
+#include <linux/clocksource.h>
+#include <linux/types.h>
+
+#define ARCH_TIMER_CTRL_ENABLE		(1 << 0)
+#define ARCH_TIMER_CTRL_IT_MASK		(1 << 1)
+#define ARCH_TIMER_CTRL_IT_STAT		(1 << 2)
+
+#define ARCH_TIMER_REG_CTRL		0
+#define ARCH_TIMER_REG_TVAL		1
+
+#define ARCH_TIMER_PHYS_ACCESS		0
+#define ARCH_TIMER_VIRT_ACCESS		1
+
+#ifdef CONFIG_ARM_ARCH_TIMER
+
+extern int arch_timer_init(void);
+extern u32 arch_timer_get_rate(void);
+extern u64 (*arch_timer_read_counter)(void);
+extern struct timecounter *arch_timer_get_timecounter(void);
+
+#else
+
+static inline int arch_timer_init(void)
+{
+	return -ENXIO;
+}
+
+static inline u32 arch_timer_get_rate(void)
+{
+	return 0;
+}
+
+static inline u64 arch_timer_read_counter(void)
+{
+	return 0;
+}
+
+static struct timecounter *arch_timer_get_timecounter(void)
+{
+	return NULL;
+}
+
+#endif
+
+#endif
-- 
1.8.1.1

^ permalink raw reply related

* [PATCHv5 09/16] arm: arch_timer: add arch_counter_set_user_access
From: Mark Rutland @ 2013-01-31 12:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359634539-9580-1-git-send-email-mark.rutland@arm.com>

Several bits in CNTKCTL reset to 0, including PL0VTEN. For architectures
using the generic timer which wish to have a fast gettimeofday vDSO
implementation, these bits must be set to 1 by the kernel. For
architectures without a vDSO, it's best to leave the bits set to 0 for
now to ensure that if and when support is added, it's implemented sanely
architecture wide.

As the bootloader might set PL0VTEN to a value that doesn't correspond
to that which the kernel prefers, we must explicitly set it to the
architecture port's preferred value.

This patch adds arch_counter_set_user_access, which sets the PL0 access
permissions to that required by the architecture. For arch/arm, this
currently means disabling all userspace access.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
---
 arch/arm/include/asm/arch_timer.h | 12 ++++++++++++
 arch/arm/kernel/arch_timer.c      |  2 ++
 2 files changed, 14 insertions(+)

diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
index 75975d9..729f6d9 100644
--- a/arch/arm/include/asm/arch_timer.h
+++ b/arch/arm/include/asm/arch_timer.h
@@ -106,6 +106,18 @@ static inline u64 arch_counter_get_cntvct(void)
 	asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cval));
 	return cval;
 }
+
+static inline void __cpuinit arch_counter_set_user_access(void)
+{
+	u32 cntkctl;
+
+	asm volatile("mrc p15, 0, %0, c14, c1, 0" : "=r" (cntkctl));
+
+	/* disable user access to everything */
+	cntkctl &= ~((3 << 8) | (7 << 0));
+
+	asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl));
+}
 #else
 static inline int arch_timer_of_register(void)
 {
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index c8dfec0..94f5033 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -155,6 +155,8 @@ static int __cpuinit arch_timer_setup(struct clock_event_device *clk)
 			enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], 0);
 	}
 
+	arch_counter_set_user_access();
+
 	return 0;
 }
 
-- 
1.8.1.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