* [PATCH v3 13/15] ARM: kirkwood: Add RSTOUT 'reg' entry to devicetree
From: Ezequiel Garcia @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390310774-20781-1-git-send-email-ezequiel.garcia@free-electrons.com>
In order to support multiplatform builds the watchdog devicetree binding
was modified and now the 'reg' property is specified to need two
entries. This commit adds the second entry as-per the new specification.
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
arch/arm/boot/dts/kirkwood.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/kirkwood.dtsi b/arch/arm/boot/dts/kirkwood.dtsi
index 8b73c80..80a56b0 100644
--- a/arch/arm/boot/dts/kirkwood.dtsi
+++ b/arch/arm/boot/dts/kirkwood.dtsi
@@ -165,7 +165,7 @@
wdt: watchdog-timer at 20300 {
compatible = "marvell,orion-wdt";
- reg = <0x20300 0x28>;
+ reg = <0x20300 0x28>, <0x20108 0x4>;
interrupt-parent = <&bridge_intc>;
interrupts = <3>;
clocks = <&gate_clk 7>;
--
1.8.1.5
^ permalink raw reply related
* [PATCH v3 12/15] ARM: mvebu: Enable Armada 370/XP watchdog in the devicetree
From: Ezequiel Garcia @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390310774-20781-1-git-send-email-ezequiel.garcia@free-electrons.com>
Add the DT nodes to enable watchdog support available in Armada 370
and Armada XP SoCs.
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
arch/arm/boot/dts/armada-370-xp.dtsi | 4 ++++
arch/arm/boot/dts/armada-370.dtsi | 5 +++++
arch/arm/boot/dts/armada-xp.dtsi | 6 ++++++
3 files changed, 15 insertions(+)
diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi
index 7f10f62..96e0389 100644
--- a/arch/arm/boot/dts/armada-370-xp.dtsi
+++ b/arch/arm/boot/dts/armada-370-xp.dtsi
@@ -151,6 +151,10 @@
interrupts = <37>, <38>, <39>, <40>, <5>, <6>;
};
+ watchdog at 20300 {
+ reg = <0x20300 0x34>, <0x20704 0x4>;
+ };
+
sata at a0000 {
compatible = "marvell,orion-sata";
reg = <0xa0000 0x5000>;
diff --git a/arch/arm/boot/dts/armada-370.dtsi b/arch/arm/boot/dts/armada-370.dtsi
index 7a4b82e..aebed9e 100644
--- a/arch/arm/boot/dts/armada-370.dtsi
+++ b/arch/arm/boot/dts/armada-370.dtsi
@@ -168,6 +168,11 @@
clocks = <&coreclk 2>;
};
+ watchdog at 20300 {
+ compatible = "marvell,armada-370-wdt";
+ clocks = <&coreclk 2>;
+ };
+
coreclk: mvebu-sar at 18230 {
compatible = "marvell,armada-370-core-clock";
reg = <0x18230 0x08>;
diff --git a/arch/arm/boot/dts/armada-xp.dtsi b/arch/arm/boot/dts/armada-xp.dtsi
index 281c644..8c6c06c 100644
--- a/arch/arm/boot/dts/armada-xp.dtsi
+++ b/arch/arm/boot/dts/armada-xp.dtsi
@@ -74,6 +74,12 @@
clock-names = "nbclk", "fixed";
};
+ watchdog at 20300 {
+ compatible = "marvell,armada-xp-wdt";
+ clocks = <&coreclk 2>, <&refclk>;
+ clock-names = "nbclk", "fixed";
+ };
+
coreclk: mvebu-sar at 18230 {
compatible = "marvell,armada-xp-core-clock";
reg = <0x18230 0x08>;
--
1.8.1.5
^ permalink raw reply related
* [PATCH v3 11/15] watchdog: orion: Add support for Armada 370 and Armada XP SoC
From: Ezequiel Garcia @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390310774-20781-1-git-send-email-ezequiel.garcia@free-electrons.com>
Using the added infrastructure for handling SoC differences,
this commit adds support for the watchdog controller available
in Armada 370 and Armada XP SoCs.
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
drivers/watchdog/orion_wdt.c | 93 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 93 insertions(+)
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index c2beb9f..a5e157c 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -30,6 +30,7 @@
* Watchdog timer block registers.
*/
#define TIMER_CTRL 0x0000
+#define TIMER_A370_STATUS 0x04
#define WDT_MAX_CYCLE_COUNT 0xffffffff
#define WDT_IN_USE 0
@@ -41,6 +42,12 @@
#define WDT_AXP_FIXED_ENABLE_BIT BIT(10)
+#define WDT_A370_RATIO_MASK(v) ((v) << 16)
+#define WDT_A370_RATIO_SHIFT 5
+#define WDT_A370_RATIO (1 << WDT_A370_RATIO_SHIFT)
+
+#define WDT_A370_EXPIRED BIT(31)
+
static bool nowayout = WATCHDOG_NOWAYOUT;
static int heartbeat = -1; /* module parameter (seconds) */
@@ -80,6 +87,48 @@ static int orion_wdt_clock_init(struct platform_device *pdev,
return 0;
}
+static int armada370_wdt_clock_init(struct platform_device *pdev,
+ struct orion_watchdog *dev)
+{
+ int ret;
+
+ dev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dev->clk))
+ return PTR_ERR(dev->clk);
+ ret = clk_prepare_enable(dev->clk);
+ if (ret)
+ return ret;
+
+ /* Setup watchdog input clock */
+ atomic_io_modify(dev->reg + TIMER_CTRL,
+ WDT_A370_RATIO_MASK(WDT_A370_RATIO_SHIFT),
+ WDT_A370_RATIO_MASK(WDT_A370_RATIO_SHIFT));
+
+ dev->clk_rate = clk_get_rate(dev->clk) / WDT_A370_RATIO;
+ return 0;
+}
+
+static int armadaxp_wdt_clock_init(struct platform_device *pdev,
+ struct orion_watchdog *dev)
+{
+ int ret;
+
+ dev->clk = of_clk_get_by_name(pdev->dev.of_node, "fixed");
+ if (IS_ERR(dev->clk))
+ return PTR_ERR(dev->clk);
+ ret = clk_prepare_enable(dev->clk);
+ if (ret)
+ return ret;
+
+ /* Enable the fixed watchdog clock input */
+ atomic_io_modify(dev->reg + TIMER_CTRL,
+ WDT_AXP_FIXED_ENABLE_BIT,
+ WDT_AXP_FIXED_ENABLE_BIT);
+
+ dev->clk_rate = clk_get_rate(dev->clk);
+ return 0;
+}
+
static int orion_wdt_ping(struct watchdog_device *wdt_dev)
{
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
@@ -89,6 +138,26 @@ static int orion_wdt_ping(struct watchdog_device *wdt_dev)
return 0;
}
+static int armada370_start(struct watchdog_device *wdt_dev)
+{
+ struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+
+ /* Set watchdog duration */
+ writel(dev->clk_rate * wdt_dev->timeout,
+ dev->reg + dev->data->wdt_counter_offset);
+
+ /* Clear the watchdog expiration bit */
+ atomic_io_modify(dev->reg + TIMER_A370_STATUS, WDT_A370_EXPIRED, 0);
+
+ /* Enable watchdog timer */
+ atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit,
+ dev->data->wdt_enable_bit);
+
+ atomic_io_modify(dev->rstout, dev->data->rstout_enable_bit,
+ dev->data->rstout_enable_bit);
+ return 0;
+}
+
static int orion_start(struct watchdog_device *wdt_dev)
{
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
@@ -170,11 +239,35 @@ static const struct orion_watchdog_data orion_data = {
.start = orion_start,
};
+static const struct orion_watchdog_data armada370_data = {
+ .rstout_enable_bit = BIT(8),
+ .wdt_enable_bit = BIT(8),
+ .wdt_counter_offset = 0x34,
+ .clock_init = armada370_wdt_clock_init,
+ .start = armada370_start,
+};
+
+static const struct orion_watchdog_data armadaxp_data = {
+ .rstout_enable_bit = BIT(8),
+ .wdt_enable_bit = BIT(8),
+ .wdt_counter_offset = 0x34,
+ .clock_init = armadaxp_wdt_clock_init,
+ .start = armada370_start,
+};
+
static const struct of_device_id orion_wdt_of_match_table[] = {
{
.compatible = "marvell,orion-wdt",
.data = &orion_data,
},
+ {
+ .compatible = "marvell,armada-370-wdt",
+ .data = &armada370_data,
+ },
+ {
+ .compatible = "marvell,armada-xp-wdt",
+ .data = &armadaxp_data,
+ },
{},
};
MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table);
--
1.8.1.5
^ permalink raw reply related
* [PATCH v3 10/15] watchdog: orion: Add per-compatible watchdog start implementation
From: Ezequiel Garcia @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390310774-20781-1-git-send-email-ezequiel.garcia@free-electrons.com>
To handle differences between SoCs this commit adds per-compatible
string start() function for the watchdog kick-off. This is preparation
work and makes no functionality changes to the current driver.
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
drivers/watchdog/orion_wdt.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index b8d0f87..c2beb9f 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -52,6 +52,7 @@ struct orion_watchdog_data {
int rstout_enable_bit;
int (*clock_init) (struct platform_device *,
struct orion_watchdog *);
+ int (*start) (struct watchdog_device *);
};
struct orion_watchdog {
@@ -88,7 +89,7 @@ static int orion_wdt_ping(struct watchdog_device *wdt_dev)
return 0;
}
-static int orion_wdt_start(struct watchdog_device *wdt_dev)
+static int orion_start(struct watchdog_device *wdt_dev)
{
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
@@ -107,6 +108,14 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
return 0;
}
+static int orion_wdt_start(struct watchdog_device *wdt_dev)
+{
+ struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+
+ /* There are some per-SoC quirks to handle */
+ return dev->data->start(wdt_dev);
+}
+
static int orion_wdt_stop(struct watchdog_device *wdt_dev)
{
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
@@ -158,6 +167,7 @@ static const struct orion_watchdog_data orion_data = {
.wdt_enable_bit = BIT(4),
.wdt_counter_offset = 0x24,
.clock_init = orion_wdt_clock_init,
+ .start = orion_start,
};
static const struct of_device_id orion_wdt_of_match_table[] = {
--
1.8.1.5
^ permalink raw reply related
* [PATCH v3 09/15] watchdog: orion: Add per-compatible clock initialization
From: Ezequiel Garcia @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390310774-20781-1-git-send-email-ezequiel.garcia@free-electrons.com>
Following the introduction of the compatible-data field,
it's now possible to further abstract the clock initialization.
This will allow to support SoC with a different clock setup.
While we're at it, let's fix the clock error handling by returning
PTR_ERR and checking clk_prepare_enable().
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
drivers/watchdog/orion_wdt.c | 35 +++++++++++++++++++++++++++--------
1 file changed, 27 insertions(+), 8 deletions(-)
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index 5108496..b8d0f87 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -44,10 +44,14 @@
static bool nowayout = WATCHDOG_NOWAYOUT;
static int heartbeat = -1; /* module parameter (seconds) */
+struct orion_watchdog;
+
struct orion_watchdog_data {
int wdt_counter_offset;
int wdt_enable_bit;
int rstout_enable_bit;
+ int (*clock_init) (struct platform_device *,
+ struct orion_watchdog *);
};
struct orion_watchdog {
@@ -59,6 +63,22 @@ struct orion_watchdog {
struct orion_watchdog_data *data;
};
+static int orion_wdt_clock_init(struct platform_device *pdev,
+ struct orion_watchdog *dev)
+{
+ int ret;
+
+ dev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dev->clk))
+ return PTR_ERR(dev->clk);
+ ret = clk_prepare_enable(dev->clk);
+ if (ret)
+ return ret;
+
+ dev->clk_rate = clk_get_rate(dev->clk);
+ return 0;
+}
+
static int orion_wdt_ping(struct watchdog_device *wdt_dev)
{
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
@@ -137,6 +157,7 @@ static const struct orion_watchdog_data orion_data = {
.rstout_enable_bit = BIT(1),
.wdt_enable_bit = BIT(4),
.wdt_counter_offset = 0x24,
+ .clock_init = orion_wdt_clock_init,
};
static const struct of_device_id orion_wdt_of_match_table[] = {
@@ -171,14 +192,6 @@ static int orion_wdt_probe(struct platform_device *pdev)
dev->wdt.min_timeout = 1;
dev->data = (struct orion_watchdog_data *)match->data;
- dev->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(dev->clk)) {
- dev_err(&pdev->dev, "Orion Watchdog missing clock\n");
- return -ENODEV;
- }
- clk_prepare_enable(dev->clk);
- dev->clk_rate = clk_get_rate(dev->clk);
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
@@ -194,6 +207,12 @@ static int orion_wdt_probe(struct platform_device *pdev)
if (!dev->rstout)
return -ENOMEM;
+ ret = dev->data->clock_init(pdev, dev);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot initialize clock\n");
+ return ret;
+ }
+
irq = platform_get_irq(pdev, 0);
if (irq > 0) {
/*
--
1.8.1.5
^ permalink raw reply related
* [PATCH v3 08/15] watchdog: orion: Introduce per-compatible of_device_id data
From: Ezequiel Garcia @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390310774-20781-1-git-send-email-ezequiel.garcia@free-electrons.com>
This commit adds an orion_watchdog_data structure to holda compatible-data
information. This allows to remove the driver-wide definition and to
future add support for multiple compatible-strings.
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
drivers/watchdog/orion_wdt.c | 62 ++++++++++++++++++++++++++++++++------------
1 file changed, 46 insertions(+), 16 deletions(-)
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index 9a904be..5108496 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -24,36 +24,47 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/of.h>
+#include <linux/of_device.h>
/*
* Watchdog timer block registers.
*/
#define TIMER_CTRL 0x0000
-#define WDT_EN 0x0010
-#define WDT_VAL 0x0024
#define WDT_MAX_CYCLE_COUNT 0xffffffff
#define WDT_IN_USE 0
#define WDT_OK_TO_CLOSE 1
-#define WDT_RESET_OUT_EN BIT(1)
+#define WDT_A370_RATIO_MASK(v) ((v) << 16)
+#define WDT_A370_RATIO_SHIFT 5
+#define WDT_A370_RATIO (1 << WDT_A370_RATIO_SHIFT)
+
+#define WDT_AXP_FIXED_ENABLE_BIT BIT(10)
static bool nowayout = WATCHDOG_NOWAYOUT;
static int heartbeat = -1; /* module parameter (seconds) */
+struct orion_watchdog_data {
+ int wdt_counter_offset;
+ int wdt_enable_bit;
+ int rstout_enable_bit;
+};
+
struct orion_watchdog {
struct watchdog_device wdt;
void __iomem *reg;
void __iomem *rstout;
unsigned long clk_rate;
struct clk *clk;
+ struct orion_watchdog_data *data;
};
static int orion_wdt_ping(struct watchdog_device *wdt_dev)
{
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
/* Reload watchdog duration */
- writel(dev->clk_rate * wdt_dev->timeout, dev->reg + WDT_VAL);
+ writel(dev->clk_rate * wdt_dev->timeout,
+ dev->reg + dev->data->wdt_counter_offset);
return 0;
}
@@ -62,13 +73,16 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
/* Set watchdog duration */
- writel(dev->clk_rate * wdt_dev->timeout, dev->reg + WDT_VAL);
+ writel(dev->clk_rate * wdt_dev->timeout,
+ dev->reg + dev->data->wdt_counter_offset);
/* Enable watchdog timer */
- atomic_io_modify(dev->reg + TIMER_CTRL, WDT_EN, WDT_EN);
+ atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit,
+ dev->data->wdt_enable_bit);
/* Enable reset on watchdog */
- atomic_io_modify(dev->rstout, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
+ atomic_io_modify(dev->rstout, dev->data->rstout_enable_bit,
+ dev->data->rstout_enable_bit);
return 0;
}
@@ -78,10 +92,10 @@ static int orion_wdt_stop(struct watchdog_device *wdt_dev)
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
/* Disable reset on watchdog */
- atomic_io_modify(dev->rstout, WDT_RESET_OUT_EN, 0);
+ atomic_io_modify(dev->rstout, dev->data->rstout_enable_bit, 0);
/* Disable watchdog timer */
- atomic_io_modify(dev->reg + TIMER_CTRL, WDT_EN, 0);
+ atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit, 0);
return 0;
}
@@ -89,7 +103,7 @@ static int orion_wdt_stop(struct watchdog_device *wdt_dev)
static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev)
{
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
- return readl(dev->reg + WDT_VAL) / dev->clk_rate;
+ return readl(dev->reg + dev->data->wdt_counter_offset) / dev->clk_rate;
}
static int orion_wdt_set_timeout(struct watchdog_device *wdt_dev,
@@ -119,9 +133,25 @@ static irqreturn_t orion_wdt_irq(int irq, void *devid)
return IRQ_HANDLED;
}
+static const struct orion_watchdog_data orion_data = {
+ .rstout_enable_bit = BIT(1),
+ .wdt_enable_bit = BIT(4),
+ .wdt_counter_offset = 0x24,
+};
+
+static const struct of_device_id orion_wdt_of_match_table[] = {
+ {
+ .compatible = "marvell,orion-wdt",
+ .data = &orion_data,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table);
+
static int orion_wdt_probe(struct platform_device *pdev)
{
struct orion_watchdog *dev;
+ const struct of_device_id *match;
unsigned int wdt_max_duration; /* (seconds) */
struct resource *res;
int ret, irq;
@@ -131,9 +161,15 @@ static int orion_wdt_probe(struct platform_device *pdev)
if (!dev)
return -ENOMEM;
+ match = of_match_device(orion_wdt_of_match_table, &pdev->dev);
+ if (!match)
+ /* Default legacy match */
+ match = &orion_wdt_of_match_table[0];
+
dev->wdt.info = &orion_wdt_info;
dev->wdt.ops = &orion_wdt_ops;
dev->wdt.min_timeout = 1;
+ dev->data = (struct orion_watchdog_data *)match->data;
dev->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(dev->clk)) {
@@ -207,12 +243,6 @@ static void orion_wdt_shutdown(struct platform_device *pdev)
orion_wdt_stop(wdt_dev);
}
-static const struct of_device_id orion_wdt_of_match_table[] = {
- { .compatible = "marvell,orion-wdt", },
- {},
-};
-MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table);
-
static struct platform_driver orion_wdt_driver = {
.probe = orion_wdt_probe,
.remove = orion_wdt_remove,
--
1.8.1.5
^ permalink raw reply related
* [PATCH v3 07/15] watchdog: orion: Introduce an orion_watchdog device structure
From: Ezequiel Garcia @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390310774-20781-1-git-send-email-ezequiel.garcia@free-electrons.com>
In order to prepare to support multiple compatible-strings, this
commit adds a device structure to hold the driver's state.
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
drivers/watchdog/orion_wdt.c | 97 +++++++++++++++++++++++++++-----------------
1 file changed, 60 insertions(+), 37 deletions(-)
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index 7889309..9a904be 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -40,45 +40,56 @@
static bool nowayout = WATCHDOG_NOWAYOUT;
static int heartbeat = -1; /* module parameter (seconds) */
-static unsigned int wdt_max_duration; /* (seconds) */
-static struct clk *clk;
-static unsigned int wdt_tclk;
-static void __iomem *wdt_reg;
-static void __iomem *wdt_rstout;
+
+struct orion_watchdog {
+ struct watchdog_device wdt;
+ void __iomem *reg;
+ void __iomem *rstout;
+ unsigned long clk_rate;
+ struct clk *clk;
+};
static int orion_wdt_ping(struct watchdog_device *wdt_dev)
{
+ struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
/* Reload watchdog duration */
- writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);
+ writel(dev->clk_rate * wdt_dev->timeout, dev->reg + WDT_VAL);
return 0;
}
static int orion_wdt_start(struct watchdog_device *wdt_dev)
{
+ struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+
/* Set watchdog duration */
- writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);
+ writel(dev->clk_rate * wdt_dev->timeout, dev->reg + WDT_VAL);
/* Enable watchdog timer */
- atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, WDT_EN);
+ atomic_io_modify(dev->reg + TIMER_CTRL, WDT_EN, WDT_EN);
/* Enable reset on watchdog */
- atomic_io_modify(wdt_rstout, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
+ atomic_io_modify(dev->rstout, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
+
return 0;
}
static int orion_wdt_stop(struct watchdog_device *wdt_dev)
{
+ struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+
/* Disable reset on watchdog */
- atomic_io_modify(wdt_rstout, WDT_RESET_OUT_EN, 0);
+ atomic_io_modify(dev->rstout, WDT_RESET_OUT_EN, 0);
/* Disable watchdog timer */
- atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, 0);
+ atomic_io_modify(dev->reg + TIMER_CTRL, WDT_EN, 0);
+
return 0;
}
static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev)
{
- return readl(wdt_reg + WDT_VAL) / wdt_tclk;
+ struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+ return readl(dev->reg + WDT_VAL) / dev->clk_rate;
}
static int orion_wdt_set_timeout(struct watchdog_device *wdt_dev,
@@ -102,12 +113,6 @@ static const struct watchdog_ops orion_wdt_ops = {
.get_timeleft = orion_wdt_get_timeleft,
};
-static struct watchdog_device orion_wdt = {
- .info = &orion_wdt_info,
- .ops = &orion_wdt_ops,
- .min_timeout = 1,
-};
-
static irqreturn_t orion_wdt_irq(int irq, void *devid)
{
panic("Watchdog Timeout");
@@ -116,29 +121,41 @@ static irqreturn_t orion_wdt_irq(int irq, void *devid)
static int orion_wdt_probe(struct platform_device *pdev)
{
+ struct orion_watchdog *dev;
+ unsigned int wdt_max_duration; /* (seconds) */
struct resource *res;
int ret, irq;
- clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(clk)) {
+ dev = devm_kzalloc(&pdev->dev, sizeof(struct orion_watchdog),
+ GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->wdt.info = &orion_wdt_info;
+ dev->wdt.ops = &orion_wdt_ops;
+ dev->wdt.min_timeout = 1;
+
+ dev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dev->clk)) {
dev_err(&pdev->dev, "Orion Watchdog missing clock\n");
return -ENODEV;
}
- clk_prepare_enable(clk);
- wdt_tclk = clk_get_rate(clk);
+ clk_prepare_enable(dev->clk);
+ dev->clk_rate = clk_get_rate(dev->clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
- wdt_reg = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!wdt_reg)
+ dev->reg = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!dev->reg)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res)
return -ENODEV;
- wdt_rstout = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!wdt_rstout)
+ dev->rstout = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!dev->rstout)
return -ENOMEM;
irq = platform_get_irq(pdev, 0);
@@ -154,34 +171,40 @@ static int orion_wdt_probe(struct platform_device *pdev)
}
}
- wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk;
+ wdt_max_duration = WDT_MAX_CYCLE_COUNT / dev->clk_rate;
- orion_wdt.timeout = wdt_max_duration;
- orion_wdt.max_timeout = wdt_max_duration;
- watchdog_init_timeout(&orion_wdt, heartbeat, &pdev->dev);
+ dev->wdt.timeout = wdt_max_duration;
+ dev->wdt.max_timeout = wdt_max_duration;
+ watchdog_init_timeout(&dev->wdt, heartbeat, &pdev->dev);
- watchdog_set_nowayout(&orion_wdt, nowayout);
- ret = watchdog_register_device(&orion_wdt);
+ platform_set_drvdata(pdev, &dev->wdt);
+ watchdog_set_drvdata(&dev->wdt, dev);
+ watchdog_set_nowayout(&dev->wdt, nowayout);
+ ret = watchdog_register_device(&dev->wdt);
if (ret) {
- clk_disable_unprepare(clk);
+ clk_disable_unprepare(dev->clk);
return ret;
}
pr_info("Initial timeout %d sec%s\n",
- orion_wdt.timeout, nowayout ? ", nowayout" : "");
+ dev->wdt.timeout, nowayout ? ", nowayout" : "");
return 0;
}
static int orion_wdt_remove(struct platform_device *pdev)
{
- watchdog_unregister_device(&orion_wdt);
- clk_disable_unprepare(clk);
+ struct watchdog_device *wdt_dev = platform_get_drvdata(pdev);
+ struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+
+ watchdog_unregister_device(wdt_dev);
+ clk_disable_unprepare(dev->clk);
return 0;
}
static void orion_wdt_shutdown(struct platform_device *pdev)
{
- orion_wdt_stop(&orion_wdt);
+ struct watchdog_device *wdt_dev = platform_get_drvdata(pdev);
+ orion_wdt_stop(wdt_dev);
}
static const struct of_device_id orion_wdt_of_match_table[] = {
--
1.8.1.5
^ permalink raw reply related
* [PATCH v3 06/15] watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
From: Ezequiel Garcia @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390310774-20781-1-git-send-email-ezequiel.garcia@free-electrons.com>
After adding the IRQ request, the BRIDGE_CAUSE bit should be cleared by the
bridge interrupt controller. There's no longer a need to do it in the watchdog
driver, so we can simply remove it.
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
drivers/watchdog/orion_wdt.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index 19e4adc..7889309 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -24,7 +24,6 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/of.h>
-#include <mach/bridge-regs.h>
/*
* Watchdog timer block registers.
@@ -38,7 +37,6 @@
#define WDT_OK_TO_CLOSE 1
#define WDT_RESET_OUT_EN BIT(1)
-#define WDT_INT_REQ BIT(3)
static bool nowayout = WATCHDOG_NOWAYOUT;
static int heartbeat = -1; /* module parameter (seconds) */
@@ -60,9 +58,6 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
/* Set watchdog duration */
writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);
- /* Clear watchdog timer interrupt */
- writel(~WDT_INT_REQ, BRIDGE_CAUSE);
-
/* Enable watchdog timer */
atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, WDT_EN);
--
1.8.1.5
^ permalink raw reply related
* [PATCH v3 05/15] watchdog: orion: Make RSTOUT register a separate resource
From: Ezequiel Garcia @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390310774-20781-1-git-send-email-ezequiel.garcia@free-electrons.com>
In order to support other SoC, it's required to distinguish
the 'control' timer register, from the 'rstout' register
that enables system reset on watchdog expiration.
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
Documentation/devicetree/bindings/watchdog/marvel.txt | 6 ++++--
arch/arm/mach-dove/include/mach/bridge-regs.h | 1 +
arch/arm/mach-kirkwood/include/mach/bridge-regs.h | 1 +
arch/arm/mach-mv78xx0/include/mach/bridge-regs.h | 1 +
arch/arm/mach-orion5x/include/mach/bridge-regs.h | 1 +
arch/arm/plat-orion/common.c | 10 ++++++----
drivers/watchdog/orion_wdt.c | 12 ++++++++++--
7 files changed, 24 insertions(+), 8 deletions(-)
diff --git a/Documentation/devicetree/bindings/watchdog/marvel.txt b/Documentation/devicetree/bindings/watchdog/marvel.txt
index 0731fbd..1544fe9 100644
--- a/Documentation/devicetree/bindings/watchdog/marvel.txt
+++ b/Documentation/devicetree/bindings/watchdog/marvel.txt
@@ -3,7 +3,9 @@
Required Properties:
- Compatibility : "marvell,orion-wdt"
-- reg : Address of the timer registers
+- reg : Should contain two entries: first one with the
+ timer control address, second one with the
+ rstout enable address.
Optional properties:
@@ -14,7 +16,7 @@ Example:
wdt at 20300 {
compatible = "marvell,orion-wdt";
- reg = <0x20300 0x28>;
+ reg = <0x20300 0x28>, <0x20108 0x4>;
interrupts = <3>;
timeout-sec = <10>;
status = "okay";
diff --git a/arch/arm/mach-dove/include/mach/bridge-regs.h b/arch/arm/mach-dove/include/mach/bridge-regs.h
index 5362df3..f4a5b34 100644
--- a/arch/arm/mach-dove/include/mach/bridge-regs.h
+++ b/arch/arm/mach-dove/include/mach/bridge-regs.h
@@ -21,6 +21,7 @@
#define CPU_CTRL_PCIE1_LINK 0x00000008
#define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108)
+#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108)
#define SOFT_RESET_OUT_EN 0x00000004
#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c)
diff --git a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h
index 8b9d1c9..60f6421 100644
--- a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h
+++ b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h
@@ -21,6 +21,7 @@
#define CPU_RESET 0x00000002
#define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108)
+#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108)
#define SOFT_RESET_OUT_EN 0x00000004
#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c)
diff --git a/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h b/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h
index 5f03484..e20d6da 100644
--- a/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h
+++ b/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h
@@ -15,6 +15,7 @@
#define L2_WRITETHROUGH 0x00020000
#define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108)
+#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108)
#define SOFT_RESET_OUT_EN 0x00000004
#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c)
diff --git a/arch/arm/mach-orion5x/include/mach/bridge-regs.h b/arch/arm/mach-orion5x/include/mach/bridge-regs.h
index f727d03..5766e3f 100644
--- a/arch/arm/mach-orion5x/include/mach/bridge-regs.h
+++ b/arch/arm/mach-orion5x/include/mach/bridge-regs.h
@@ -18,6 +18,7 @@
#define CPU_CTRL (ORION5X_BRIDGE_VIRT_BASE + 0x104)
#define RSTOUTn_MASK (ORION5X_BRIDGE_VIRT_BASE + 0x108)
+#define RSTOUTn_MASK_PHYS (ORION5X_BRIDGE_PHYS_BASE + 0x108)
#define CPU_SOFT_RESET (ORION5X_BRIDGE_VIRT_BASE + 0x10c)
diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c
index c66d163..3375037 100644
--- a/arch/arm/plat-orion/common.c
+++ b/arch/arm/plat-orion/common.c
@@ -594,14 +594,16 @@ void __init orion_spi_1_init(unsigned long mapbase)
/*****************************************************************************
* Watchdog
****************************************************************************/
-static struct resource orion_wdt_resource =
- DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x28);
+static struct resource orion_wdt_resource[] = {
+ DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x04),
+ DEFINE_RES_MEM(RSTOUTn_MASK_PHYS, 0x04),
+};
static struct platform_device orion_wdt_device = {
.name = "orion_wdt",
.id = -1,
- .num_resources = 1,
- .resource = &orion_wdt_resource,
+ .num_resources = ARRAY_SIZE(orion_wdt_resource),
+ .resource = orion_wdt_resource,
};
void __init orion_wdt_init(void)
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index c8ab377..19e4adc 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -46,6 +46,7 @@ static unsigned int wdt_max_duration; /* (seconds) */
static struct clk *clk;
static unsigned int wdt_tclk;
static void __iomem *wdt_reg;
+static void __iomem *wdt_rstout;
static int orion_wdt_ping(struct watchdog_device *wdt_dev)
{
@@ -66,14 +67,14 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, WDT_EN);
/* Enable reset on watchdog */
- atomic_io_modify(RSTOUTn_MASK, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
+ atomic_io_modify(wdt_rstout, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
return 0;
}
static int orion_wdt_stop(struct watchdog_device *wdt_dev)
{
/* Disable reset on watchdog */
- atomic_io_modify(RSTOUTn_MASK, WDT_RESET_OUT_EN, 0);
+ atomic_io_modify(wdt_rstout, WDT_RESET_OUT_EN, 0);
/* Disable watchdog timer */
atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, 0);
@@ -138,6 +139,13 @@ static int orion_wdt_probe(struct platform_device *pdev)
if (!wdt_reg)
return -ENOMEM;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res)
+ return -ENODEV;
+ wdt_rstout = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!wdt_rstout)
+ return -ENOMEM;
+
irq = platform_get_irq(pdev, 0);
if (irq > 0) {
/*
--
1.8.1.5
^ permalink raw reply related
* [PATCH v3 04/15] watchdog: orion: Handle IRQ
From: Ezequiel Garcia @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390310774-20781-1-git-send-email-ezequiel.garcia@free-electrons.com>
DT-enabled where an irqchip driver for the brigde interrupt controller is
available can handle the watchdog IRQ properly. Therefore, we request
the interruption and add a dummy handler that merely calls panic().
This is done in order to have an initial 'ack' of the interruption,
which clears the watchdog state.
Furthermore, since some platforms don't have such IRQ, this commit
makes the interruption specification optional.
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
.../devicetree/bindings/watchdog/marvel.txt | 2 ++
drivers/watchdog/orion_wdt.c | 22 +++++++++++++++++++++-
2 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/watchdog/marvel.txt b/Documentation/devicetree/bindings/watchdog/marvel.txt
index 5dc8d30..0731fbd 100644
--- a/Documentation/devicetree/bindings/watchdog/marvel.txt
+++ b/Documentation/devicetree/bindings/watchdog/marvel.txt
@@ -7,6 +7,7 @@ Required Properties:
Optional properties:
+- interrupts : Contains the IRQ for watchdog expiration
- timeout-sec : Contains the watchdog timeout in seconds
Example:
@@ -14,6 +15,7 @@ Example:
wdt at 20300 {
compatible = "marvell,orion-wdt";
reg = <0x20300 0x28>;
+ interrupts = <3>;
timeout-sec = <10>;
status = "okay";
};
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index 0433ea8..c8ab377 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -19,6 +19,7 @@
#include <linux/platform_device.h>
#include <linux/watchdog.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/err.h>
@@ -111,10 +112,16 @@ static struct watchdog_device orion_wdt = {
.min_timeout = 1,
};
+static irqreturn_t orion_wdt_irq(int irq, void *devid)
+{
+ panic("Watchdog Timeout");
+ return IRQ_HANDLED;
+}
+
static int orion_wdt_probe(struct platform_device *pdev)
{
struct resource *res;
- int ret;
+ int ret, irq;
clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(clk)) {
@@ -131,6 +138,19 @@ static int orion_wdt_probe(struct platform_device *pdev)
if (!wdt_reg)
return -ENOMEM;
+ irq = platform_get_irq(pdev, 0);
+ if (irq > 0) {
+ /*
+ * Not all supported platforms specify an interruption for the
+ * watchdog, so let's make it optional.
+ */
+ ret = request_irq(irq, orion_wdt_irq, 0, pdev->name, NULL);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to request IRQ\n");
+ return ret;
+ }
+ }
+
wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk;
orion_wdt.timeout = wdt_max_duration;
--
1.8.1.5
^ permalink raw reply related
* [PATCH v3 03/15] watchdog: orion: Use atomic access for shared registers
From: Ezequiel Garcia @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390310774-20781-1-git-send-email-ezequiel.garcia@free-electrons.com>
Since the timer control register is shared with the clocksource driver,
use the recently introduced atomic_io_clear_set() to access such register.
Given the watchdog core already provides serialization for all the
watchdog ops, this commit allows to remove the spinlock entirely.
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
drivers/watchdog/orion_wdt.c | 42 +++++-------------------------------------
1 file changed, 5 insertions(+), 37 deletions(-)
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index f7722a4..0433ea8 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -20,7 +20,6 @@
#include <linux/watchdog.h>
#include <linux/init.h>
#include <linux/io.h>
-#include <linux/spinlock.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/of.h>
@@ -46,25 +45,16 @@ static unsigned int wdt_max_duration; /* (seconds) */
static struct clk *clk;
static unsigned int wdt_tclk;
static void __iomem *wdt_reg;
-static DEFINE_SPINLOCK(wdt_lock);
static int orion_wdt_ping(struct watchdog_device *wdt_dev)
{
- spin_lock(&wdt_lock);
-
/* Reload watchdog duration */
writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);
-
- spin_unlock(&wdt_lock);
return 0;
}
static int orion_wdt_start(struct watchdog_device *wdt_dev)
{
- u32 reg;
-
- spin_lock(&wdt_lock);
-
/* Set watchdog duration */
writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);
@@ -72,48 +62,26 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
writel(~WDT_INT_REQ, BRIDGE_CAUSE);
/* Enable watchdog timer */
- reg = readl(wdt_reg + TIMER_CTRL);
- reg |= WDT_EN;
- writel(reg, wdt_reg + TIMER_CTRL);
+ atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, WDT_EN);
/* Enable reset on watchdog */
- reg = readl(RSTOUTn_MASK);
- reg |= WDT_RESET_OUT_EN;
- writel(reg, RSTOUTn_MASK);
-
- spin_unlock(&wdt_lock);
+ atomic_io_modify(RSTOUTn_MASK, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
return 0;
}
static int orion_wdt_stop(struct watchdog_device *wdt_dev)
{
- u32 reg;
-
- spin_lock(&wdt_lock);
-
/* Disable reset on watchdog */
- reg = readl(RSTOUTn_MASK);
- reg &= ~WDT_RESET_OUT_EN;
- writel(reg, RSTOUTn_MASK);
+ atomic_io_modify(RSTOUTn_MASK, WDT_RESET_OUT_EN, 0);
/* Disable watchdog timer */
- reg = readl(wdt_reg + TIMER_CTRL);
- reg &= ~WDT_EN;
- writel(reg, wdt_reg + TIMER_CTRL);
-
- spin_unlock(&wdt_lock);
+ atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, 0);
return 0;
}
static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev)
{
- unsigned int time_left;
-
- spin_lock(&wdt_lock);
- time_left = readl(wdt_reg + WDT_VAL) / wdt_tclk;
- spin_unlock(&wdt_lock);
-
- return time_left;
+ return readl(wdt_reg + WDT_VAL) / wdt_tclk;
}
static int orion_wdt_set_timeout(struct watchdog_device *wdt_dev,
--
1.8.1.5
^ permalink raw reply related
* [PATCH v3 02/15] clocksource: orion: Use atomic access for shared registers
From: Ezequiel Garcia @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390310774-20781-1-git-send-email-ezequiel.garcia@free-electrons.com>
Replace the driver-specific thread-safe shared register API
by the recently introduced atomic_io_clear_set().
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
drivers/clocksource/time-orion.c | 28 ++++++++++------------------
1 file changed, 10 insertions(+), 18 deletions(-)
diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/time-orion.c
index 9c7f018..3f14e56 100644
--- a/drivers/clocksource/time-orion.c
+++ b/drivers/clocksource/time-orion.c
@@ -35,20 +35,6 @@
#define ORION_ONESHOT_MAX 0xfffffffe
static void __iomem *timer_base;
-static DEFINE_SPINLOCK(timer_ctrl_lock);
-
-/*
- * Thread-safe access to TIMER_CTRL register
- * (shared with watchdog timer)
- */
-void orion_timer_ctrl_clrset(u32 clr, u32 set)
-{
- spin_lock(&timer_ctrl_lock);
- writel((readl(timer_base + TIMER_CTRL) & ~clr) | set,
- timer_base + TIMER_CTRL);
- spin_unlock(&timer_ctrl_lock);
-}
-EXPORT_SYMBOL(orion_timer_ctrl_clrset);
/*
* Free-running clocksource handling.
@@ -68,7 +54,8 @@ static int orion_clkevt_next_event(unsigned long delta,
{
/* setup and enable one-shot timer */
writel(delta, timer_base + TIMER1_VAL);
- orion_timer_ctrl_clrset(TIMER1_RELOAD_EN, TIMER1_EN);
+ atomic_io_modify(timer_base + TIMER_CTRL,
+ TIMER1_RELOAD_EN | TIMER1_EN, TIMER1_EN);
return 0;
}
@@ -80,10 +67,13 @@ static void orion_clkevt_mode(enum clock_event_mode mode,
/* setup and enable periodic timer at 1/HZ intervals */
writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD);
writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL);
- orion_timer_ctrl_clrset(0, TIMER1_RELOAD_EN | TIMER1_EN);
+ atomic_io_modify(timer_base + TIMER_CTRL,
+ TIMER1_RELOAD_EN | TIMER1_EN,
+ TIMER1_RELOAD_EN | TIMER1_EN);
} else {
/* disable timer */
- orion_timer_ctrl_clrset(TIMER1_RELOAD_EN | TIMER1_EN, 0);
+ atomic_io_modify(timer_base + TIMER_CTRL,
+ TIMER1_RELOAD_EN | TIMER1_EN, 0);
}
}
@@ -131,7 +121,9 @@ static void __init orion_timer_init(struct device_node *np)
/* setup timer0 as free-running clocksource */
writel(~0, timer_base + TIMER0_VAL);
writel(~0, timer_base + TIMER0_RELOAD);
- orion_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | TIMER0_EN);
+ atomic_io_modify(timer_base + TIMER_CTRL,
+ TIMER0_RELOAD_EN | TIMER0_EN,
+ TIMER0_RELOAD_EN | TIMER0_EN);
clocksource_mmio_init(timer_base + TIMER0_VAL, "orion_clocksource",
clk_get_rate(clk), 300, 32,
clocksource_mmio_readl_down);
--
1.8.1.5
^ permalink raw reply related
* [PATCH v3 01/15] ARM: Introduce atomic MMIO modify
From: Ezequiel Garcia @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390310774-20781-1-git-send-email-ezequiel.garcia@free-electrons.com>
Some SoC have MMIO regions that are shared across orthogonal
subsystems. This commit implements a possible solution for the
thread-safe access of such regions through a spinlock-protected API.
Concurrent access is protected with a single spinlock for the
entire MMIO address space. While this protects shared-registers,
it also serializes access to unrelated/unshared registers.
We add relaxed and non-relaxed variants, by using writel_relaxed and writel,
respectively. The rationale for this is that some users may not require
register write completion but only thread-safe access to a register.
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
Submitted to ARM patch tracker:
http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=7930/1
arch/arm/include/asm/io.h | 6 ++++++
arch/arm/kernel/io.c | 35 +++++++++++++++++++++++++++++++++++
2 files changed, 41 insertions(+)
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index fbeb39c..8aa4cca 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -38,6 +38,12 @@
#define isa_bus_to_virt phys_to_virt
/*
+ * Atomic MMIO-wide IO modify
+ */
+extern void atomic_io_modify(void __iomem *reg, u32 mask, u32 set);
+extern void atomic_io_modify_relaxed(void __iomem *reg, u32 mask, u32 set);
+
+/*
* Generic IO read/write. These perform native-endian accesses. Note
* that some architectures will want to re-define __raw_{read,write}w.
*/
diff --git a/arch/arm/kernel/io.c b/arch/arm/kernel/io.c
index dcd5b4d..9203cf8 100644
--- a/arch/arm/kernel/io.c
+++ b/arch/arm/kernel/io.c
@@ -1,6 +1,41 @@
#include <linux/export.h>
#include <linux/types.h>
#include <linux/io.h>
+#include <linux/spinlock.h>
+
+static DEFINE_RAW_SPINLOCK(__io_lock);
+
+/*
+ * Generic atomic MMIO modify.
+ *
+ * Allows thread-safe access to registers shared by unrelated subsystems.
+ * The access is protected by a single MMIO-wide lock.
+ */
+void atomic_io_modify_relaxed(void __iomem *reg, u32 mask, u32 set)
+{
+ unsigned long flags;
+ u32 value;
+
+ raw_spin_lock_irqsave(&__io_lock, flags);
+ value = readl_relaxed(reg) & ~mask;
+ value |= (set & mask);
+ writel_relaxed(value, reg);
+ raw_spin_unlock_irqrestore(&__io_lock, flags);
+}
+EXPORT_SYMBOL(atomic_io_modify_relaxed);
+
+void atomic_io_modify(void __iomem *reg, u32 mask, u32 set)
+{
+ unsigned long flags;
+ u32 value;
+
+ raw_spin_lock_irqsave(&__io_lock, flags);
+ value = readl_relaxed(reg) & ~mask;
+ value |= (set & mask);
+ writel(value, reg);
+ raw_spin_unlock_irqrestore(&__io_lock, flags);
+}
+EXPORT_SYMBOL(atomic_io_modify);
/*
* Copy data from IO memory space to "real" memory space.
--
1.8.1.5
^ permalink raw reply related
* [PATCH v3 00/15] Armada 370/XP watchdog support
From: Ezequiel Garcia @ 2014-01-21 13:25 UTC (permalink / raw)
To: linux-arm-kernel
Third patchset to extend Orion watchdog driver adding support for
Armada 370/XP SoC. This consists on a small incremental series.
Please take a look at the previous version and the discussion raised:
http://www.spinics.net/lists/arm-kernel/msg302104.html
Changes from v2:
* Add proper error checking on clk_prepare_enable() and return
PTR_ERR instead of ENODEV. Suggested by Fabio Estevam.
* After the usage of the atomic I/O and considering the watchdog core
does its own serialization, the driver's spinlock was completely
redundant and was removed. Also suggested by Fabio.
* Instead of making the driver dependent on PLAT_ORION, added a dependency
to ARCH_MVEBU. This was proposed by Sebastian and Andrew, given
we're working on PLAT_ORION removal.
This series is based on v3.13-rc8 and has been tested on:
* Marvell's Armada XP GP board
Ezequiel Garcia (15):
ARM: Introduce atomic MMIO modify
clocksource: orion: Use atomic access for shared registers
watchdog: orion: Use atomic access for shared registers
watchdog: orion: Handle IRQ
watchdog: orion: Make RSTOUT register a separate resource
watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
watchdog: orion: Introduce an orion_watchdog device structure
watchdog: orion: Introduce per-compatible of_device_id data
watchdog: orion: Add per-compatible clock initialization
watchdog: orion: Add per-compatible watchdog start implementation
watchdog: orion: Add support for Armada 370 and Armada XP SoC
ARM: mvebu: Enable Armada 370/XP watchdog in the devicetree
ARM: kirkwood: Add RSTOUT 'reg' entry to devicetree
watchdog: orion: Enable the build on ARCH_MVEBU
ARM: mvebu: Enable watchdog support in defconfig
.../devicetree/bindings/watchdog/marvel.txt | 8 +-
arch/arm/boot/dts/armada-370-xp.dtsi | 4 +
arch/arm/boot/dts/armada-370.dtsi | 5 +
arch/arm/boot/dts/armada-xp.dtsi | 6 +
arch/arm/boot/dts/kirkwood.dtsi | 2 +-
arch/arm/configs/mvebu_defconfig | 2 +
arch/arm/include/asm/io.h | 6 +
arch/arm/kernel/io.c | 35 +++
arch/arm/mach-dove/include/mach/bridge-regs.h | 1 +
arch/arm/mach-kirkwood/include/mach/bridge-regs.h | 1 +
arch/arm/mach-mv78xx0/include/mach/bridge-regs.h | 1 +
arch/arm/mach-orion5x/include/mach/bridge-regs.h | 1 +
arch/arm/plat-orion/common.c | 10 +-
drivers/clocksource/time-orion.c | 28 +-
drivers/watchdog/Kconfig | 2 +-
drivers/watchdog/orion_wdt.c | 320 ++++++++++++++++-----
16 files changed, 329 insertions(+), 103 deletions(-)
--
1.8.1.5
^ permalink raw reply
* [RFC PATCH 3/3] KVM: Documentation: Add info regarding KVM_ARM_VCPU_PSCI_0_2 feature
From: Anup Patel @ 2014-01-21 13:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390309301-28424-1-git-send-email-anup.patel@linaro.org>
We have in-kernel emulation of PSCI v0.2 in KVM ARM/ARM64. To provide
PSCI v0.2 interface to VCPUs, we have to enable KVM_ARM_VCPU_PSCI_0_2
feature when doing KVM_ARM_VCPU_INIT ioctl.
The patch updates documentation of KVM_ARM_VCPU_INIT ioctl to provide
info regarding KVM_ARM_VCPU_PSCI_0_2 feature.
Signed-off-by: Anup Patel <anup.patel@linaro.org>
Signed-off-by: Pranavkumar Sawargaonkar <pranavkumar@linaro.org>
---
Documentation/virtual/kvm/api.txt | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index aad3244..a15fcdd 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2346,6 +2346,8 @@ Possible features:
Depends on KVM_CAP_ARM_PSCI.
- KVM_ARM_VCPU_EL1_32BIT: Starts the CPU in a 32bit mode.
Depends on KVM_CAP_ARM_EL1_32BIT (arm64 only).
+ - KVM_ARM_VCPU_PSCI_0_2: Emulate PSCI v0.2 for CPU.
+ Depends on KVM_CAP_ARM_PSCI_0_2.
4.83 KVM_ARM_PREFERRED_TARGET
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH 2/3] ARM/ARM64: KVM: Add support for PSCI v0.2 emulation
From: Anup Patel @ 2014-01-21 13:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390309301-28424-1-git-send-email-anup.patel@linaro.org>
Currently, the in-kernel PSCI emulation provides PSCI v0.1 interface to
VCPUs. This patch extends current in-kernel PSCI emulation to provide
PSCI v0.2 interface to VCPUs.
By default, ARM/ARM64 KVM will always provide PSCI v0.1 interface for
keeping the ABI backward-compatible.
To select PSCI v0.2 interface for VCPUs, the user space (i.e. QEMU or
KVMTOOL) will have to set KVM_ARM_VCPU_PSCI_0_2 feature when doing VCPU
init using KVM_ARM_VCPU_INIT ioctl.
Signed-off-by: Anup Patel <anup.patel@linaro.org>
Signed-off-by: Pranavkumar Sawargaonkar <pranavkumar@linaro.org>
---
arch/arm/include/asm/kvm_host.h | 2 +-
arch/arm/include/uapi/asm/kvm.h | 39 ++++++++++++++++--
arch/arm/kvm/arm.c | 6 ++-
arch/arm/kvm/psci.c | 79 ++++++++++++++++++++++++++++++-------
arch/arm64/include/asm/kvm_host.h | 2 +-
arch/arm64/include/uapi/asm/kvm.h | 39 ++++++++++++++++--
6 files changed, 143 insertions(+), 24 deletions(-)
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 8a6f6db..0239ac5 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -36,7 +36,7 @@
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
#define KVM_HAVE_ONE_REG
-#define KVM_VCPU_MAX_FEATURES 1
+#define KVM_VCPU_MAX_FEATURES 2
#include <kvm/arm_vgic.h>
diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index c498b60..d9eb74c 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -83,6 +83,7 @@ struct kvm_regs {
#define KVM_VGIC_V2_CPU_SIZE 0x2000
#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */
+#define KVM_ARM_VCPU_PSCI_0_2 1 /* CPU uses PSCI v0.2 */
struct kvm_vcpu_init {
__u32 target;
@@ -164,7 +165,7 @@ struct kvm_arch_memory_slot {
/* Highest supported SPI, from VGIC_NR_IRQS */
#define KVM_ARM_IRQ_GIC_MAX 127
-/* PSCI interface */
+/* PSCI v0.1 interface */
#define KVM_PSCI_FN_BASE 0x95c1ba5e
#define KVM_PSCI_FN(n) (KVM_PSCI_FN_BASE + (n))
@@ -173,9 +174,41 @@ struct kvm_arch_memory_slot {
#define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2)
#define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3)
+/* PSCI v0.2 interface */
+#define KVM_PSCI_0_2_FN_BASE 0x84000000
+#define KVM_PSCI_0_2_FN(n) (KVM_PSCI_0_2_FN_BASE + (n))
+#define KVM_PSCI_0_2_FN64_BASE 0xC4000000
+#define KVM_PSCI_0_2_FN64(n) (KVM_PSCI_0_2_FN64_BASE + (n))
+
+#define KVM_PSCI_0_2_FN_PSCI_VERSION KVM_PSCI_0_2_FN(0)
+#define KVM_PSCI_0_2_FN_CPU_SUSPEND KVM_PSCI_0_2_FN(1)
+#define KVM_PSCI_0_2_FN_CPU_OFF KVM_PSCI_0_2_FN(2)
+#define KVM_PSCI_0_2_FN_CPU_ON KVM_PSCI_0_2_FN(3)
+#define KVM_PSCI_0_2_FN_AFFINITY_INFO KVM_PSCI_0_2_FN(4)
+#define KVM_PSCI_0_2_FN_MIGRATE KVM_PSCI_0_2_FN(5)
+#define KVM_PSCI_0_2_FN_MIGRATE_INFO_TYPE \
+ KVM_PSCI_0_2_FN(6)
+#define KVM_PSCI_0_2_FN_MIGRATE_INFO_UP_CPU \
+ KVM_PSCI_0_2_FN(7)
+#define KVM_PSCI_0_2_FN_SYSTEM_OFF KVM_PSCI_0_2_FN(8)
+#define KVM_PSCI_0_2_FN_SYSTEM_RESET KVM_PSCI_0_2_FN(9)
+
+#define KVM_PSCI_0_2_FN64_CPU_SUSPEND KVM_PSCI_0_2_FN64(1)
+#define KVM_PSCI_0_2_FN64_CPU_ON KVM_PSCI_0_2_FN64(3)
+#define KVM_PSCI_0_2_FN64_AFFINITY_INFO KVM_PSCI_0_2_FN64(4)
+#define KVM_PSCI_0_2_FN64_MIGRATE KVM_PSCI_0_2_FN64(5)
+#define KVM_PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU \
+ KVM_PSCI_0_2_FN64(7)
+
+/* PSCI return values */
#define KVM_PSCI_RET_SUCCESS 0
-#define KVM_PSCI_RET_NI ((unsigned long)-1)
-#define KVM_PSCI_RET_INVAL ((unsigned long)-2)
+#define KVM_PSCI_RET_NOT_SUPPORTED ((unsigned long)-1)
+#define KVM_PSCI_RET_INVALID_PARAMS ((unsigned long)-2)
#define KVM_PSCI_RET_DENIED ((unsigned long)-3)
+#define KVM_PSCI_RET_ALREADY_ON ((unsigned long)-4)
+#define KVM_PSCI_RET_ON_PENDING ((unsigned long)-5)
+#define KVM_PSCI_RET_INTERNAL_FAILURE ((unsigned long)-6)
+#define KVM_PSCI_RET_NOT_PRESENT ((unsigned long)-7)
+#define KVM_PSCI_RET_DISABLED ((unsigned long)-8)
#endif /* __ARM_KVM_H__ */
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 2a700e0..0b7817a 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -193,6 +193,7 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
case KVM_CAP_ONE_REG:
case KVM_CAP_ARM_PSCI:
+ case KVM_CAP_ARM_PSCI_0_2:
r = 1;
break;
case KVM_CAP_COALESCED_MMIO:
@@ -483,7 +484,10 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
* PSCI code.
*/
if (test_and_clear_bit(KVM_ARM_VCPU_POWER_OFF, vcpu->arch.features)) {
- *vcpu_reg(vcpu, 0) = KVM_PSCI_FN_CPU_OFF;
+ if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
+ *vcpu_reg(vcpu, 0) = KVM_PSCI_0_2_FN_CPU_OFF;
+ else
+ *vcpu_reg(vcpu, 0) = KVM_PSCI_FN_CPU_OFF;
kvm_psci_call(vcpu);
}
diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c
index 0881bf1..ee044a3 100644
--- a/arch/arm/kvm/psci.c
+++ b/arch/arm/kvm/psci.c
@@ -55,13 +55,13 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
}
if (!vcpu)
- return KVM_PSCI_RET_INVAL;
+ return KVM_PSCI_RET_INVALID_PARAMS;
target_pc = *vcpu_reg(source_vcpu, 2);
wq = kvm_arch_vcpu_wq(vcpu);
if (!waitqueue_active(wq))
- return KVM_PSCI_RET_INVAL;
+ return KVM_PSCI_RET_INVALID_PARAMS;
kvm_reset_vcpu(vcpu);
@@ -84,17 +84,49 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
return KVM_PSCI_RET_SUCCESS;
}
-/**
- * kvm_psci_call - handle PSCI call if r0 value is in range
- * @vcpu: Pointer to the VCPU struct
- *
- * Handle PSCI calls from guests through traps from HVC instructions.
- * The calling convention is similar to SMC calls to the secure world where
- * the function number is placed in r0 and this function returns true if the
- * function number specified in r0 is withing the PSCI range, and false
- * otherwise.
- */
-bool kvm_psci_call(struct kvm_vcpu *vcpu)
+static bool kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
+{
+ unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0);
+ unsigned long val;
+
+ switch (psci_fn) {
+ case KVM_PSCI_0_2_FN_PSCI_VERSION:
+ /*
+ * Bits[31:16] = Major Version = 0
+ * Bits[15:0] = Minor Version = 2
+ */
+ val = 2;
+ break;
+ case KVM_PSCI_0_2_FN_CPU_OFF:
+ kvm_psci_vcpu_off(vcpu);
+ val = KVM_PSCI_RET_SUCCESS;
+ break;
+ case KVM_PSCI_0_2_FN_CPU_ON:
+ case KVM_PSCI_0_2_FN64_CPU_ON:
+ val = kvm_psci_vcpu_on(vcpu);
+ break;
+ case KVM_PSCI_0_2_FN_CPU_SUSPEND:
+ case KVM_PSCI_0_2_FN_AFFINITY_INFO:
+ case KVM_PSCI_0_2_FN_MIGRATE:
+ case KVM_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
+ case KVM_PSCI_0_2_FN_MIGRATE_INFO_UP_CPU:
+ case KVM_PSCI_0_2_FN_SYSTEM_OFF:
+ case KVM_PSCI_0_2_FN_SYSTEM_RESET:
+ case KVM_PSCI_0_2_FN64_CPU_SUSPEND:
+ case KVM_PSCI_0_2_FN64_AFFINITY_INFO:
+ case KVM_PSCI_0_2_FN64_MIGRATE:
+ case KVM_PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU:
+ val = KVM_PSCI_RET_NOT_SUPPORTED;
+ break;
+ default:
+ return false;
+ }
+
+ *vcpu_reg(vcpu, 0) = val;
+ return true;
+}
+
+static bool kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
{
unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0);
unsigned long val;
@@ -109,9 +141,8 @@ bool kvm_psci_call(struct kvm_vcpu *vcpu)
break;
case KVM_PSCI_FN_CPU_SUSPEND:
case KVM_PSCI_FN_MIGRATE:
- val = KVM_PSCI_RET_NI;
+ val = KVM_PSCI_RET_NOT_SUPPORTED;
break;
-
default:
return false;
}
@@ -119,3 +150,21 @@ bool kvm_psci_call(struct kvm_vcpu *vcpu)
*vcpu_reg(vcpu, 0) = val;
return true;
}
+
+/**
+ * kvm_psci_call - handle PSCI call if r0 value is in range
+ * @vcpu: Pointer to the VCPU struct
+ *
+ * Handle PSCI calls from guests through traps from HVC instructions.
+ * The calling convention is similar to SMC calls to the secure world where
+ * the function number is placed in r0 and this function returns true if the
+ * function number specified in r0 is withing the PSCI range, and false
+ * otherwise.
+ */
+bool kvm_psci_call(struct kvm_vcpu *vcpu)
+{
+ if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
+ return kvm_psci_0_2_call(vcpu);
+
+ return kvm_psci_0_1_call(vcpu);
+}
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 0a1d697..92242ce 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -39,7 +39,7 @@
#include <kvm/arm_vgic.h>
#include <kvm/arm_arch_timer.h>
-#define KVM_VCPU_MAX_FEATURES 2
+#define KVM_VCPU_MAX_FEATURES 3
struct kvm_vcpu;
int kvm_target_cpu(void);
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index d9f026b..0eb254d 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -77,6 +77,7 @@ struct kvm_regs {
#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */
#define KVM_ARM_VCPU_EL1_32BIT 1 /* CPU running a 32bit VM */
+#define KVM_ARM_VCPU_PSCI_0_2 2 /* CPU uses PSCI v0.2 */
struct kvm_vcpu_init {
__u32 target;
@@ -150,7 +151,7 @@ struct kvm_arch_memory_slot {
/* Highest supported SPI, from VGIC_NR_IRQS */
#define KVM_ARM_IRQ_GIC_MAX 127
-/* PSCI interface */
+/* PSCI v0.1 interface */
#define KVM_PSCI_FN_BASE 0x95c1ba5e
#define KVM_PSCI_FN(n) (KVM_PSCI_FN_BASE + (n))
@@ -159,10 +160,42 @@ struct kvm_arch_memory_slot {
#define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2)
#define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3)
+/* PSCI v0.2 interface */
+#define KVM_PSCI_0_2_FN_BASE 0x84000000
+#define KVM_PSCI_0_2_FN(n) (KVM_PSCI_0_2_FN_BASE + (n))
+#define KVM_PSCI_0_2_FN64_BASE 0xC4000000
+#define KVM_PSCI_0_2_FN64(n) (KVM_PSCI_0_2_FN64_BASE + (n))
+
+#define KVM_PSCI_0_2_FN_PSCI_VERSION KVM_PSCI_0_2_FN(0)
+#define KVM_PSCI_0_2_FN_CPU_SUSPEND KVM_PSCI_0_2_FN(1)
+#define KVM_PSCI_0_2_FN_CPU_OFF KVM_PSCI_0_2_FN(2)
+#define KVM_PSCI_0_2_FN_CPU_ON KVM_PSCI_0_2_FN(3)
+#define KVM_PSCI_0_2_FN_AFFINITY_INFO KVM_PSCI_0_2_FN(4)
+#define KVM_PSCI_0_2_FN_MIGRATE KVM_PSCI_0_2_FN(5)
+#define KVM_PSCI_0_2_FN_MIGRATE_INFO_TYPE \
+ KVM_PSCI_0_2_FN(6)
+#define KVM_PSCI_0_2_FN_MIGRATE_INFO_UP_CPU \
+ KVM_PSCI_0_2_FN(7)
+#define KVM_PSCI_0_2_FN_SYSTEM_OFF KVM_PSCI_0_2_FN(8)
+#define KVM_PSCI_0_2_FN_SYSTEM_RESET KVM_PSCI_0_2_FN(9)
+
+#define KVM_PSCI_0_2_FN64_CPU_SUSPEND KVM_PSCI_0_2_FN64(1)
+#define KVM_PSCI_0_2_FN64_CPU_ON KVM_PSCI_0_2_FN64(3)
+#define KVM_PSCI_0_2_FN64_AFFINITY_INFO KVM_PSCI_0_2_FN64(4)
+#define KVM_PSCI_0_2_FN64_MIGRATE KVM_PSCI_0_2_FN64(5)
+#define KVM_PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU \
+ KVM_PSCI_0_2_FN64(7)
+
+/* PSCI return values */
#define KVM_PSCI_RET_SUCCESS 0
-#define KVM_PSCI_RET_NI ((unsigned long)-1)
-#define KVM_PSCI_RET_INVAL ((unsigned long)-2)
+#define KVM_PSCI_RET_NOT_SUPPORTED ((unsigned long)-1)
+#define KVM_PSCI_RET_INVALID_PARAMS ((unsigned long)-2)
#define KVM_PSCI_RET_DENIED ((unsigned long)-3)
+#define KVM_PSCI_RET_ALREADY_ON ((unsigned long)-4)
+#define KVM_PSCI_RET_ON_PENDING ((unsigned long)-5)
+#define KVM_PSCI_RET_INTERNAL_FAILURE ((unsigned long)-6)
+#define KVM_PSCI_RET_NOT_PRESENT ((unsigned long)-7)
+#define KVM_PSCI_RET_DISABLED ((unsigned long)-8)
#endif
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH 1/3] KVM: Add capability to advertise PSCI v0.2 support
From: Anup Patel @ 2014-01-21 13:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390309301-28424-1-git-send-email-anup.patel@linaro.org>
User space (i.e. QEMU or KVMTOOL) should be able to check whether KVM
ARM/ARM64 supports in-kernel PSCI v0.2 emulation. For this purpose, we
define KVM_CAP_ARM_PSCI_0_2 in KVM user space interface header.
Signed-off-by: Anup Patel <anup.patel@linaro.org>
Signed-off-by: Pranavkumar Sawargaonkar <pranavkumar@linaro.org>
---
include/uapi/linux/kvm.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 902f124..d64349e 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -674,6 +674,7 @@ struct kvm_ppc_smmu_info {
#define KVM_CAP_ARM_EL1_32BIT 93
#define KVM_CAP_SPAPR_MULTITCE 94
#define KVM_CAP_EXT_EMUL_CPUID 95
+#define KVM_CAP_ARM_PSCI_0_2 96
#ifdef KVM_CAP_IRQ_ROUTING
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH 0/3] In-kernel PSCI v0.2 emulation for KVM ARM/ARM64
From: Anup Patel @ 2014-01-21 13:01 UTC (permalink / raw)
To: linux-arm-kernel
Currently, KVM ARM/ARM64 only provides in-kernel emulation of Power State
and Coordination Interface (PSCI) v0.1.
This patchset aims at providing newer PSCI v0.2 for KVM ARM/ARM64 VCPUs
such that it does not break current KVM ARM/ARM64 ABI. Also, the patchset
provides emulation of only few PSCI v0.2 functions such as PSCI_VERSION,
CPU_ON, and CPU_OFF. Emulation of other PSCI v0.2 functions will be added
later.
The user space tools (i.e. QEMU or KVMTOOL) will have to explicitly enable
KVM_ARM_VCPU_PSCI_0_2 feature using KVM_ARM_VCPU_INIT ioctl for providing
PSCI v0.2 to VCPUs.
Anup Patel (3):
KVM: Add capability to advertise PSCI v0.2 support
ARM/ARM64: KVM: Add support for PSCI v0.2 emulation
KVM: Documentation: Add info regarding KVM_ARM_VCPU_PSCI_0_2 feature
Documentation/virtual/kvm/api.txt | 2 +
arch/arm/include/asm/kvm_host.h | 2 +-
arch/arm/include/uapi/asm/kvm.h | 39 ++++++++++++++++--
arch/arm/kvm/arm.c | 6 ++-
arch/arm/kvm/psci.c | 79 ++++++++++++++++++++++++++++++-------
arch/arm64/include/asm/kvm_host.h | 2 +-
arch/arm64/include/uapi/asm/kvm.h | 39 ++++++++++++++++--
include/uapi/linux/kvm.h | 1 +
8 files changed, 146 insertions(+), 24 deletions(-)
--
1.7.9.5
^ permalink raw reply
* [PATCH 0/2] clk: shmobile rcar-gen2 fixes
From: Laurent Pinchart @ 2014-01-21 13:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1591253.8BzYfubhGS@avalon>
Hi Mike,
On Wednesday 08 January 2014 00:06:39 Laurent Pinchart wrote:
> On Tuesday 07 January 2014 17:59:01 Geert Uytterhoeven wrote:
> > On Tue, Jan 7, 2014 at 5:47 PM, Laurent Pinchart wrote:
> > > Geert, could you please verify that the series fixes your QSPI clock
> > > issues with the Koelsch board ?
> > >
> > > Laurent Pinchart (2):
> > > clk: shmobile: rcar-gen2: Fix clock parent all non-PLL clocks
> > > clk: shmobile: rcar-gen2: Fix qspi divisor
> >
> > Thanks, both:
> >
> > Tested-by: Geert Uytterhoeven <geert@linux-m68k.org>
>
> Thank you.
>
> Mike, could you please pick those patches up for v3.14 ?
Ping ?
--
Regards,
Laurent Pinchart
^ permalink raw reply
* [PATCH v2 15/15] ARM: mvebu: Enable watchdog support in defconfig
From: Jason Cooper @ 2014-01-21 12:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140121125339.GH13396@lunn.ch>
On Tue, Jan 21, 2014 at 01:53:39PM +0100, Andrew Lunn wrote:
> On Tue, Jan 21, 2014 at 07:47:46AM -0500, Jason Cooper wrote:
> > On Tue, Jan 21, 2014 at 06:12:41AM -0300, Ezequiel Garcia wrote:
> > > Now that we have proper support for Armada 370/XP watchdog
> > > let's enable it in the defconfig.
> > >
> > > Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
> > > ---
> > > arch/arm/configs/mvebu_defconfig | 2 ++
> > > 1 file changed, 2 insertions(+)
> >
> > Just a note to myself more than anything: I need to square up multi_v7
> > with mvebu. As we make these changes next cycle, we need to be able to
> > easily test that we aren't breaking multiplat build or boot.
>
> Hi Jason
>
> Hopefully you can also tackle multi_v5 as well, once DT kirkwood moves
> into mach-mvebu.
Yes.
> To check for breaking boot, you need some other hardware
> platform. Nomadik was breaking kirkwood multi_v5, and you would not
> see the problem on Nomadik.
Yes, I was more specifically looking to leverage arm-buildbot...
thx,
Jason.
^ permalink raw reply
* [PATCH v2 15/15] ARM: mvebu: Enable watchdog support in defconfig
From: Andrew Lunn @ 2014-01-21 12:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140121124746.GZ29184@titan.lakedaemon.net>
On Tue, Jan 21, 2014 at 07:47:46AM -0500, Jason Cooper wrote:
> On Tue, Jan 21, 2014 at 06:12:41AM -0300, Ezequiel Garcia wrote:
> > Now that we have proper support for Armada 370/XP watchdog
> > let's enable it in the defconfig.
> >
> > Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
> > ---
> > arch/arm/configs/mvebu_defconfig | 2 ++
> > 1 file changed, 2 insertions(+)
>
> Just a note to myself more than anything: I need to square up multi_v7
> with mvebu. As we make these changes next cycle, we need to be able to
> easily test that we aren't breaking multiplat build or boot.
Hi Jason
Hopefully you can also tackle multi_v5 as well, once DT kirkwood moves
into mach-mvebu.
To check for breaking boot, you need some other hardware
platform. Nomadik was breaking kirkwood multi_v5, and you would not
see the problem on Nomadik.
Andrew
^ permalink raw reply
* [RFC] dt-bindings: configuration of parent clocks and clock frequency
From: Sylwester Nawrocki @ 2014-01-21 12:48 UTC (permalink / raw)
To: linux-arm-kernel
Hi All,
During LCE13 there was a discussion regarding initial configuration
of clocks from consumer perspective and the related device tree bindings.
It seems no one started working on this, at least I couldn't see any
related posts/patches on the mailing list, so I thought I'd give a try
the initial binding proposal [1].
As it turns out, by adding only a single property with a list of parent
clock specifiers or clock frequencies corresponding to clocks listed in
the 'clocks' property it is difficult to specify parent clocks or
frequencies only for selected clocks of a device.
So I modified the proposed binding and there are some variants below
it would be nice to get a feedback for.
Let's assume a clock provider and an UART device:
clk {
#clock-cells = <1>;
};
uart: uart {
clocks = <&clk 10>, <&clk 11>, <&clk 12>;
clock-names = "sclk_0", "sclk_1", "gate";
...
};
1. The first version I actually tried in practice is
'assigned-clk-parents' and assigned-clk-rates properties listing
<clk clk_parent> and <clk clk_rate> pairs respectively:
uart {
clocks = <&clk 10>, <&clk 11>, <&clk 12>;
clock-names = "sclk_0", "sclk_1", "gate";
assigned-clk-parents = <&clk_a 10 &clk_a 20>,
<&clk_a 11 &clk_a 100>;
assigned-clk-rates = <&clk_a 10 600000>,
<&clk_a 100 100000>;
};
Parsing assigned-clk-parents is straightforward, only assigned-clk-rates
requires a bit more exercise.
2. A different option would be to list all the required clocks in clock/
clock-names properties and use properties as below to refer to the
clocks by name:
uart {
clocks = <&clk 10>, <&clk 11>, <&clk 12>, &clk 100> /* PLL */;
clock-names = "sclk_0", "sclk_1", "gate", "pll";
assigned-clk-parent-clocks = "sclk_0";
assigned-clk-parent-parents = "pll";
assigned-clk-rate-clocks = "pll";
assigned-clk-rate-values = <600000>;
};
It might be more readable and would allow configuring things more
consciously. However it adds an additional indirection and introduces
specifiers of clocks potentially unrelated to a device in clocks/
clock-names properties.
3. A simplified variant of 2., with indexes to 'clocks' property rather
than values from the clock-names property:
uart: uart {
clocks = <&clk 10>, <&clk 11>, <&clk 12>, &clk 100> /* PLL */;
clock-names = "sclk_0", "sclk_1", "gate", "pll";
assigned-clk-parent-clocks = 0;
assigned-clk-parent-parents = 3;
assigned-clk-rate-clocks = 3;
assigned-clk-rate-values = <600000>;
};
4. With phandle + clock specifier instead of device clock names:
uart: uart {
clocks = <&clk 10>, <&clk 11>, <&clk 12>, &clk 100> /* PLL */;
clock-names = "sclk_0", "sclk_1", "gate", "pll";
assigned-clk-parent-clocks = <&clk 10>;
assigned-clk-parent-parents = <&clk 100>;
assigned-clk-rate-clocks = <&clk 100>;
assigned-clk-rate-values = <600000>;
};
5. Similarly to the regulator bindings the clock names could be appended
to name of a DT property:
[clk_name]-assigned-clock-parent = <...>;
[clk_name]-assigned-clock-rate = <...>;
It has an issue though that length of a DT property name is limited
to 31 characters and there may not be enough room for the clock name.
uart: uart {
clocks = <&clk 10>, <&clk 11>, <&clk 12>;
clock-names = "sclk_0", "sclk_1", "gate";
sclk_0-assigned-clk-parent = <&clk 100>;
pll-assigned-clk-rate = <600000>;
};
Does any of these look reasonable ? Perhaps someone could suggest
a better approach ?
[1] https://lkml.org/lkml/2013/8/22/2
--
Regards,
Sylwester
^ permalink raw reply
* [PATCH v2 15/15] ARM: mvebu: Enable watchdog support in defconfig
From: Jason Cooper @ 2014-01-21 12:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390295561-3466-16-git-send-email-ezequiel.garcia@free-electrons.com>
On Tue, Jan 21, 2014 at 06:12:41AM -0300, Ezequiel Garcia wrote:
> Now that we have proper support for Armada 370/XP watchdog
> let's enable it in the defconfig.
>
> Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
> ---
> arch/arm/configs/mvebu_defconfig | 2 ++
> 1 file changed, 2 insertions(+)
Just a note to myself more than anything: I need to square up multi_v7
with mvebu. As we make these changes next cycle, we need to be able to
easily test that we aren't breaking multiplat build or boot.
Hopefully I can get some defconfig changes in for -rc1? :)
thx,
Jason.
> diff --git a/arch/arm/configs/mvebu_defconfig b/arch/arm/configs/mvebu_defconfig
> index 594d706..84ec924 100644
> --- a/arch/arm/configs/mvebu_defconfig
> +++ b/arch/arm/configs/mvebu_defconfig
> @@ -60,6 +60,8 @@ CONFIG_GPIOLIB=y
> CONFIG_GPIO_SYSFS=y
> CONFIG_THERMAL=y
> CONFIG_ARMADA_THERMAL=y
> +CONFIG_WATCHDOG=y
> +CONFIG_ORION_WATCHDOG=y
> CONFIG_USB_SUPPORT=y
> CONFIG_USB=y
> CONFIG_USB_EHCI_HCD=y
> --
> 1.8.1.5
>
^ permalink raw reply
* [RFC PATCH 1/1] of/irq: create interrupts-extended-2 property
From: Jean-Christophe PLAGNIOL-VILLARD @ 2014-01-21 12:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140121120214.GK28747@e106331-lin.cambridge.arm.com>
On 12:02 Tue 21 Jan , Mark Rutland wrote:
> On Tue, Jan 21, 2014 at 01:03:23AM +0000, Olof Johansson wrote:
> > On Mon, Jan 20, 2014 at 2:47 PM, Grant Likely <grant.likely@linaro.org> wrote:
> > > On Wed, 15 Jan 2014 16:12:24 +0000, Mark Rutland <mark.rutland@arm.com> wrote:
> > >> >
> > >> > Another, more invasive option would be extend the dts syntax and teach
> > >> > dtc to handle property appending. Then the soc dts could stay as it is,
> > >> > and the board dts could have something like:
> > >> >
> > >> > /append-property/ interrupts = <&intc1 6 1>;
> > >> > /append-property/ interrupt-names = "board-specific-irq";
> > >> >
> > >> > Both these options solve the issue at the source, are general to other
> > >> > properties, and allow more than one level of hierarchy (the proposed
> > >> > interrupts-extended-2 only allows one level).
> > >>
> > >> I've just had a go at implementing the append-property mechanism above
> > >> in dtc, and it was far easier than I expected (patch below).
> > >>
> > >> Does anyone have any issues with the /append-property/ idea?
> > >
> > > I think that is reasonable.
> >
> >
> > The main problem with this (same for clocks) is if you need to append
> > something with a name when the original didn't have any.
>
> Can you not just add a name in the original file? I assume we're not
> going to use this to adjust dts files we're not already in full control
> of.
>
> >
> > Reordering entries might not work for interrupts, since the bindings
> > might have requirements on order.
>
> That's a fair point.
>
> Do we currently have any optional/board-specific interrupts which must
> appear at the start or middle of the list?
>
> For those, could we add names? The kernel should be abel to fall back to
> ordering if names aren't present, and we can recommend a particular
> ordering for compatiblity with older kernels.
>
> As a general preventative measure it would be nice to have named
> elements whenever elements can be optional.
I never was a fanof index search I do agree the names irq is the best way
>
> >
> > I'm not aware of a good solution for this. Suggestions welcome.
>
> Me neither. Prepending and appending is easy.
>
> Inserting and/or modifying the list requires knowledge of the size of
> each element (and for variable-sized entries requires knowledge of the
> particular binding, which we cannot embed in dtc).
>
> I suspect adding richer syntax for modifying properties in arbitrary
> ways will devolve into a turing tarpit.
no this need to stay simple if too much complexe => mess up, unmaintainable
if you really have complex stuff duplicate the info
Best Regards,
J.
>
> Thanks,
> Mark.
^ permalink raw reply
* [PATCH v10] clk: add MOXA ART SoCs clock driver
From: Jonas Jensen @ 2014-01-21 12:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1389971035-17781-1-git-send-email-jonas.jensen@gmail.com>
MOXA ART SoCs allow to determine PLL output and APB frequencies
by reading registers holding multiplier and divisor information.
Add a clock driver for this SoC.
Signed-off-by: Jonas Jensen <jonas.jensen@gmail.com>
---
Notes:
Thanks for the reply Sudeep, changes are in v10.
Changes since v9:
1. rebase drivers/clk/Makefile to next-20140121
2. remove unnecessary switch
3. use a more elaborate commit message
Applies to next-20140121
.../bindings/clock/moxa,moxart-clock.txt | 48 +++++++++++
drivers/clk/Makefile | 1 +
drivers/clk/clk-moxart.c | 99 ++++++++++++++++++++++
3 files changed, 148 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/moxa,moxart-clock.txt
create mode 100644 drivers/clk/clk-moxart.c
diff --git a/Documentation/devicetree/bindings/clock/moxa,moxart-clock.txt b/Documentation/devicetree/bindings/clock/moxa,moxart-clock.txt
new file mode 100644
index 0000000..242e3fc
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/moxa,moxart-clock.txt
@@ -0,0 +1,48 @@
+Device Tree Clock bindings for arch-moxart
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+MOXA ART SoCs allow to determine PLL output and APB frequencies
+by reading registers holding multiplier and divisor information.
+
+
+PLL:
+
+Required properties:
+- compatible : Must be "moxa,moxart-pll-clock"
+- #clock-cells : Should be 0
+- reg : Should contain registers location and length
+- clocks : Should contain phandle to parent clock
+
+Optional properties:
+- clock-output-names : Should contain clock name
+
+
+APB:
+
+Required properties:
+- compatible : Must be "moxa,moxart-apb-clock"
+- #clock-cells : Should be 0
+- reg : Should contain registers location and length
+- clocks : Should contain phandle to parent clock
+
+Optional properties:
+- clock-output-names : Should contain clock name
+
+
+For example:
+
+ clk_pll: clk_pll at 98100000 {
+ compatible = "moxa,moxart-pll-clock";
+ #clock-cells = <0>;
+ reg = <0x98100000 0x34>;
+ };
+
+ clk_apb: clk_apb at 98100000 {
+ compatible = "moxa,moxart-apb-clock";
+ #clock-cells = <0>;
+ reg = <0x98100000 0x34>;
+ clocks = <&clk_pll>;
+ };
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 58b2d72..24361bf 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-composite.o
# SoCs specific
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
+obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
diff --git a/drivers/clk/clk-moxart.c b/drivers/clk/clk-moxart.c
new file mode 100644
index 0000000..7021748
--- /dev/null
+++ b/drivers/clk/clk-moxart.c
@@ -0,0 +1,99 @@
+/*
+ * MOXA ART SoCs clock driver.
+ *
+ * Copyright (C) 2013 Jonas Jensen
+ *
+ * Jonas Jensen <jonas.jensen@gmail.com>
+ *
+ * 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 <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/clkdev.h>
+
+void __init moxart_of_pll_clk_init(struct device_node *node)
+{
+ static void __iomem *base;
+ struct clk *clk, *ref_clk;
+ unsigned long rate;
+ unsigned int mul;
+ const char *name = node->name;
+
+ of_property_read_string(node, "clock-output-names", &name);
+
+ base = of_iomap(node, 0);
+ if (!base) {
+ pr_err("%s: of_iomap failed\n", node->full_name);
+ return;
+ }
+
+ mul = readl(base + 0x30) >> 3 & 0x3f;
+ iounmap(base);
+
+ ref_clk = of_clk_get(node, 0);
+ if (IS_ERR(ref_clk)) {
+ pr_err("%s: of_clk_get failed\n", node->full_name);
+ return;
+ }
+
+ rate = mul * clk_get_rate(ref_clk);
+
+ clk = clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate);
+ if (IS_ERR(clk)) {
+ pr_err("%s: clk_register_fixed_rate failed\n", node->full_name);
+ return;
+ }
+
+ clk_register_clkdev(clk, NULL, name);
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock",
+ moxart_of_pll_clk_init);
+
+void __init moxart_of_apb_clk_init(struct device_node *node)
+{
+ static void __iomem *base;
+ struct clk *clk, *pll_clk;
+ unsigned long rate;
+ unsigned int div, val;
+ unsigned int div_idx[] = { 2, 3, 4, 6, 8};
+ const char *name = node->name;
+
+ of_property_read_string(node, "clock-output-names", &name);
+
+ base = of_iomap(node, 0);
+ if (!base) {
+ pr_err("%s: of_iomap failed\n", node->full_name);
+ return;
+ }
+
+ val = readl(base + 0xc) >> 4 & 0x7;
+ iounmap(base);
+
+ if (val > 4)
+ val = 0;
+ div = div_idx[val];
+
+ pll_clk = of_clk_get(node, 0);
+ if (IS_ERR(pll_clk)) {
+ pr_err("%s: of_clk_get failed\n", node->full_name);
+ return;
+ }
+
+ rate = clk_get_rate(pll_clk) / (div * 2);
+
+ clk = clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate);
+ if (IS_ERR(clk)) {
+ pr_err("%s: clk_register_fixed_rate failed\n", node->full_name);
+ return;
+ }
+
+ clk_register_clkdev(clk, NULL, name);
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(moxart_apb_clock, "moxa,moxart-apb-clock",
+ moxart_of_apb_clk_init);
--
1.8.2.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox