* [PATCH 3/3] clocksource/drivers: integrator-ap: parse the chosen node
From: Alexandre Belloni @ 2017-12-13 18:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171213185313.20017-1-alexandre.belloni@free-electrons.com>
The driver currently uses aliases to know whether the timer is the
clocksource or the clockevent. Add the /chosen/linux,clocksource and
/chosen/linux,clockevent parsing while keeping backward compatibility.
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
drivers/clocksource/Kconfig | 1 +
drivers/clocksource/timer-integrator-ap.c | 11 +++++++++++
2 files changed, 12 insertions(+)
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 9a22d1048fcf..053aca99caf7 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -212,6 +212,7 @@ config KEYSTONE_TIMER
config INTEGRATOR_AP_TIMER
bool "Integrator-ap timer driver" if COMPILE_TEST
select CLKSRC_MMIO
+ select TIMER_OF
help
Enables support for the Integrator-ap timer.
diff --git a/drivers/clocksource/timer-integrator-ap.c b/drivers/clocksource/timer-integrator-ap.c
index 62d24690ba02..8f38be724aff 100644
--- a/drivers/clocksource/timer-integrator-ap.c
+++ b/drivers/clocksource/timer-integrator-ap.c
@@ -197,6 +197,17 @@ static int __init integrator_ap_timer_init_of(struct device_node *node)
rate = clk_get_rate(clk);
writel(0, base + TIMER_CTRL);
+ if (timer_of_is_clocksource(node))
+ /* The primary timer lacks IRQ, use as clocksource */
+ return integrator_clocksource_init(rate, base);
+
+ if (timer_of_is_clockevent(node)) {
+ /* The secondary timer will drive the clock event */
+ irq = irq_of_parse_and_map(node, 0);
+ return integrator_clockevent_init(rate, base, irq);
+ }
+
+ /* DT ABI compatibility below */
err = of_property_read_string(of_aliases,
"arm,timer-primary", &path);
if (err) {
--
2.15.1
^ permalink raw reply related
* [PATCH 2/3] clocksource/drivers: timer-of: parse the chosen node
From: Alexandre Belloni @ 2017-12-13 18:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171213185313.20017-1-alexandre.belloni@free-electrons.com>
Add a way for drivers to know whether the timer they are currently handling
is a clocksource or a clockevent.
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
drivers/clocksource/timer-of.c | 22 ++++++++++++++++++++++
drivers/clocksource/timer-of.h | 3 +++
2 files changed, 25 insertions(+)
diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c
index a31990408153..71680eacd390 100644
--- a/drivers/clocksource/timer-of.c
+++ b/drivers/clocksource/timer-of.c
@@ -195,3 +195,25 @@ void __init timer_of_cleanup(struct timer_of *to)
if (to->flags & TIMER_OF_BASE)
timer_base_exit(&to->of_base);
}
+
+int __init timer_of_is_type(struct device_node *np, char *type)
+{
+ struct device_node *node, *timer;
+
+ if (!of_chosen)
+ return 0;
+
+ node = of_get_child_by_name(of_chosen, type);
+ if (!node)
+ return 0;
+
+ timer = of_parse_phandle(node, "timer", 0);
+ of_node_put(node);
+ if (!timer)
+ return 0;
+
+ if (timer == np)
+ return 1;
+
+ return 0;
+}
diff --git a/drivers/clocksource/timer-of.h b/drivers/clocksource/timer-of.h
index 3f708f1be43d..24923cfe748d 100644
--- a/drivers/clocksource/timer-of.h
+++ b/drivers/clocksource/timer-of.h
@@ -70,4 +70,7 @@ extern int __init timer_of_init(struct device_node *np,
extern void __init timer_of_cleanup(struct timer_of *to);
+extern int __init timer_of_is_type(struct device_node *np, char *type);
+#define timer_of_is_clocksource(np) timer_of_is_type(np, "linux,clocksource")
+#define timer_of_is_clockevent(np) timer_of_is_type(np, "linux,clockevent")
#endif
--
2.15.1
^ permalink raw reply related
* [PATCH 1/3] dt-bindings: chosen: Add clocksource and clockevent selection
From: Alexandre Belloni @ 2017-12-13 18:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171213185313.20017-1-alexandre.belloni@free-electrons.com>
The clocksource and clockevent timer are probed early in the boot process.
At that time it is difficult for linux to know whether a particular timer
can be used as the clocksource or the clockevent or by another driver,
especially when they are all identical or have similar features.
Until now, multiple strategies have been used to solve that:
- use Kconfig option as MXC_USE_EPIT or ATMEL_TCB_CLKSRC_BLOCK
- use a kernel parameter as the "clocksource" early_param in mach-omap2
- registering the first seen timer as a clockevent and the second one as
a clocksource as in rk_timer_init or dw_apb_timer_init
Add a linux,clocksource and a linux,clockevent node in chosen with a timer
property pointing to the timer to use. Other properties, like the targeted
precision may be added later.
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
Documentation/devicetree/bindings/chosen.txt | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/Documentation/devicetree/bindings/chosen.txt b/Documentation/devicetree/bindings/chosen.txt
index e3b13ea7d2ae..c7ee3ecb5276 100644
--- a/Documentation/devicetree/bindings/chosen.txt
+++ b/Documentation/devicetree/bindings/chosen.txt
@@ -120,3 +120,23 @@ e.g.
While this property does not represent a real hardware, the address
and the size are expressed in #address-cells and #size-cells,
respectively, of the root node.
+
+linux,clocksource and linux,clockevent
+--------------------------------------
+
+Those nodes have a timer property. This property is a phandle to the timer to be
+chosen as the clocksource or clockevent. This is only useful when the platform
+has multiple identical timers and it is not possible to let linux make the
+correct choice.
+
+/ {
+ chosen {
+ linux,clocksource {
+ timer = <&timer0>;
+ };
+
+ linux,clockevent {
+ timer = <&timer1>;
+ };
+ };
+};
--
2.15.1
^ permalink raw reply related
* [PATCH 0/3] clocksource/drivers: introduce DT based selection
From: Alexandre Belloni @ 2017-12-13 18:53 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
Currently, many drivers implement their own strategy when trying to find
which timer to use as the clocksource or the clockevent.
The main issue is that this selection is happen early in the boot
process and the kernel doesn't always have all the information to take
that decision.
So we end up with suboptimal solutions, especially in a multiplatform
kernel setting, as the MXC_USE_EPIT or ATMEL_TCB_CLKSRC_BLOCK kernel
config option.
There is also the clocksource kernel parameter only implemented in
mach-omap2.
Other drivers are registering the first seen timer as a clockevent, the
other one as a clocksource.
Also, this will help in the goal of separating clocksource and
clockevent drivers (see 376bc27150f180d9f5eddec6a14117780177589d)
Patch 1 documents the binding, patch 2 implements the parsing of the
chosen node and finally, patch 3 makes use of the parsing in a driver to
give an overview of how it is working.
Alexandre Belloni (3):
dt-bindings: chosen: Add clocksource and clockevent selection
clocksource/drivers: timer-of: parse the chosen node
clocksource/drivers: integrator-ap: parse the chosen node
Documentation/devicetree/bindings/chosen.txt | 20 ++++++++++++++++++++
drivers/clocksource/Kconfig | 1 +
drivers/clocksource/timer-integrator-ap.c | 11 +++++++++++
drivers/clocksource/timer-of.c | 22 ++++++++++++++++++++++
drivers/clocksource/timer-of.h | 3 +++
5 files changed, 57 insertions(+)
--
2.15.1
^ permalink raw reply
* [PATCH 3/3] [v6] pinctrl: qcom: qdf2xxx: add support for new ACPI HID QCOM8002
From: Timur Tabi @ 2017-12-13 18:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513189818-7384-1-git-send-email-timur@codeaurora.org>
Newer versions of the firmware for the Qualcomm Datacenter Technologies
QDF2400 restricts access to a subset of the GPIOs on the TLMM. To
prevent older kernels from accidentally accessing the restricted GPIOs,
we change the ACPI HID for the TLMM block from QCOM8001 to QCOM8002,
and introduce a new property "gpios". This property is an array of
specific GPIOs that are accessible. When an older kernel boots on
newer (restricted) firmware, it will fail to probe.
To implement the sparse GPIO map, we register all of the GPIOs, but set
the pin count for the unavailable GPIOs to zero. The pinctrl-msm
driver will block those unavailable GPIOs from being accessed.
To allow newer kernels to support older firmware, the driver retains
support for QCOM8001.
Signed-off-by: Timur Tabi <timur@codeaurora.org>
---
drivers/pinctrl/qcom/pinctrl-qdf2xxx.c | 134 +++++++++++++++++++++++++--------
1 file changed, 103 insertions(+), 31 deletions(-)
diff --git a/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c b/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c
index bb3ce5c3e18b..deb08e08e86d 100644
--- a/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c
+++ b/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c
@@ -38,68 +38,139 @@
/* maximum size of each gpio name (enough room for "gpioXXX" + null) */
#define NAME_SIZE 8
+enum {
+ QDF2XXX_V1,
+ QDF2XXX_V2,
+};
+
static int qdf2xxx_pinctrl_probe(struct platform_device *pdev)
{
+ const struct acpi_device_id *id;
struct pinctrl_pin_desc *pins;
struct msm_pingroup *groups;
char (*names)[NAME_SIZE];
unsigned int i;
u32 num_gpios;
+ unsigned int avail_gpios; /* The number of GPIOs we support */
+ u16 *gpios; /* An array of supported GPIOs */
int ret;
/* Query the number of GPIOs from ACPI */
ret = device_property_read_u32(&pdev->dev, "num-gpios", &num_gpios);
if (ret < 0) {
- dev_warn(&pdev->dev, "missing num-gpios property\n");
+ dev_err(&pdev->dev, "missing 'num-gpios' property\n");
return ret;
}
-
if (!num_gpios || num_gpios > MAX_GPIOS) {
- dev_warn(&pdev->dev, "invalid num-gpios property\n");
+ dev_err(&pdev->dev, "invalid 'num-gpios' property\n");
return -ENODEV;
}
+ /*
+ * The QCOM8001 HID contains only the number of GPIOs, and assumes
+ * that all of them are available. avail_gpios is the same as num_gpios.
+ *
+ * The QCOM8002 HID introduces the 'gpios' DSD, which lists
+ * specific GPIOs that the driver is allowed to access.
+ *
+ * The make the common code simpler, in both cases we create an
+ * array of GPIOs that are accessible. So for QCOM8001, that would
+ * be all of the GPIOs.
+ */
+ id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
+
+ if (id->driver_data == QDF2XXX_V1) {
+ avail_gpios = num_gpios;
+
+ gpios = devm_kmalloc_array(&pdev->dev, avail_gpios,
+ sizeof(gpios[0]), GFP_KERNEL);
+ if (!gpios)
+ return -ENOMEM;
+
+ for (i = 0; i < avail_gpios; i++)
+ gpios[i] = i;
+ } else {
+ /* The number of GPIOs in the approved list */
+ ret = device_property_read_u16_array(&pdev->dev, "gpios",
+ NULL, 0);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "missing 'gpios' property\n");
+ return ret;
+ }
+ /*
+ * The number of available GPIOs should be non-zero, and no
+ * more than the total number of GPIOS.
+ */
+ if (!ret || ret > num_gpios) {
+ dev_err(&pdev->dev, "invalid 'gpios' property\n");
+ return -ENODEV;
+ }
+ avail_gpios = ret;
+
+ gpios = devm_kmalloc_array(&pdev->dev, avail_gpios,
+ sizeof(gpios[0]), GFP_KERNEL);
+ if (!gpios)
+ return -ENOMEM;
+
+ ret = device_property_read_u16_array(&pdev->dev, "gpios", gpios,
+ avail_gpios);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "could not read list of GPIOs\n");
+ return ret;
+ }
+ }
+
pins = devm_kcalloc(&pdev->dev, num_gpios,
sizeof(struct pinctrl_pin_desc), GFP_KERNEL);
groups = devm_kcalloc(&pdev->dev, num_gpios,
sizeof(struct msm_pingroup), GFP_KERNEL);
- names = devm_kcalloc(&pdev->dev, num_gpios, NAME_SIZE, GFP_KERNEL);
+ names = devm_kcalloc(&pdev->dev, avail_gpios, NAME_SIZE, GFP_KERNEL);
if (!pins || !groups || !names)
return -ENOMEM;
+ /*
+ * Initialize the array. GPIOs not listed in the 'gpios' array
+ * still need a number, but nothing else.
+ */
for (i = 0; i < num_gpios; i++) {
- snprintf(names[i], NAME_SIZE, "gpio%u", i);
-
pins[i].number = i;
- pins[i].name = names[i];
-
- groups[i].npins = 1;
- groups[i].name = names[i];
groups[i].pins = &pins[i].number;
+ }
- groups[i].ctl_reg = 0x10000 * i;
- groups[i].io_reg = 0x04 + 0x10000 * i;
- groups[i].intr_cfg_reg = 0x08 + 0x10000 * i;
- groups[i].intr_status_reg = 0x0c + 0x10000 * i;
- groups[i].intr_target_reg = 0x08 + 0x10000 * i;
-
- groups[i].mux_bit = 2;
- groups[i].pull_bit = 0;
- groups[i].drv_bit = 6;
- groups[i].oe_bit = 9;
- groups[i].in_bit = 0;
- groups[i].out_bit = 1;
- groups[i].intr_enable_bit = 0;
- groups[i].intr_status_bit = 0;
- groups[i].intr_target_bit = 5;
- groups[i].intr_target_kpss_val = 1;
- groups[i].intr_raw_status_bit = 4;
- groups[i].intr_polarity_bit = 1;
- groups[i].intr_detection_bit = 2;
- groups[i].intr_detection_width = 2;
+ /* Populate the entries that are meant to be exposes as GPIOs. */
+ for (i = 0; i < avail_gpios; i++) {
+ unsigned int gpio = gpios[i];
+
+ groups[gpio].npins = 1;
+ snprintf(names[i], NAME_SIZE, "gpio%u", gpio);
+ pins[gpio].name = names[i];
+ groups[gpio].name = names[i];
+
+ groups[gpio].ctl_reg = 0x10000 * gpio;
+ groups[gpio].io_reg = 0x04 + 0x10000 * gpio;
+ groups[gpio].intr_cfg_reg = 0x08 + 0x10000 * gpio;
+ groups[gpio].intr_status_reg = 0x0c + 0x10000 * gpio;
+ groups[gpio].intr_target_reg = 0x08 + 0x10000 * gpio;
+
+ groups[gpio].mux_bit = 2;
+ groups[gpio].pull_bit = 0;
+ groups[gpio].drv_bit = 6;
+ groups[gpio].oe_bit = 9;
+ groups[gpio].in_bit = 0;
+ groups[gpio].out_bit = 1;
+ groups[gpio].intr_enable_bit = 0;
+ groups[gpio].intr_status_bit = 0;
+ groups[gpio].intr_target_bit = 5;
+ groups[gpio].intr_target_kpss_val = 1;
+ groups[gpio].intr_raw_status_bit = 4;
+ groups[gpio].intr_polarity_bit = 1;
+ groups[gpio].intr_detection_bit = 2;
+ groups[gpio].intr_detection_width = 2;
}
+ devm_kfree(&pdev->dev, gpios);
+
qdf2xxx_pinctrl.pins = pins;
qdf2xxx_pinctrl.groups = groups;
qdf2xxx_pinctrl.npins = num_gpios;
@@ -110,7 +181,8 @@ static int qdf2xxx_pinctrl_probe(struct platform_device *pdev)
}
static const struct acpi_device_id qdf2xxx_acpi_ids[] = {
- {"QCOM8001"},
+ {"QCOM8001", QDF2XXX_V1},
+ {"QCOM8002", QDF2XXX_V2},
{},
};
MODULE_DEVICE_TABLE(acpi, qdf2xxx_acpi_ids);
--
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm
Technologies, Inc. Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.
^ permalink raw reply related
* [PATCH 2/3] [v8] pinctrl: qcom: disable GPIO groups with no pins
From: Timur Tabi @ 2017-12-13 18:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513189818-7384-1-git-send-email-timur@codeaurora.org>
pinctrl-msm only accepts an array of GPIOs from 0 to n-1, and it expects
each group to support have only one pin (npins == 1).
We can support "sparse" GPIO maps if we allow for some groups to have zero
pins (npins == 0). These pins are "hidden" from the rest of the driver
and gpiolib.
Access to unavailable GPIOs is blocked via a request callback. If the
requested GPIO is unavailable, -EACCES is returned, which prevents
further access to that GPIO.
Signed-off-by: Timur Tabi <timur@codeaurora.org>
---
drivers/pinctrl/qcom/pinctrl-msm.c | 28 +++++++++++++++++++++++-----
1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index 7a960590ecaa..d45b4c2b5af1 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -507,6 +507,11 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
};
g = &pctrl->soc->groups[offset];
+
+ /* If the GPIO group has no pins, then don't show it. */
+ if (!g->npins)
+ return;
+
ctl_reg = readl(pctrl->regs + g->ctl_reg);
is_out = !!(ctl_reg & BIT(g->oe_bit));
@@ -516,7 +521,7 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
seq_printf(s, " %-8s: %-3s %d", g->name, is_out ? "out" : "in", func);
seq_printf(s, " %dmA", msm_regval_to_drive(drive));
- seq_printf(s, " %s", pulls[pull]);
+ seq_printf(s, " %s\n", pulls[pull]);
}
static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
@@ -524,23 +529,36 @@ static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
unsigned gpio = chip->base;
unsigned i;
- for (i = 0; i < chip->ngpio; i++, gpio++) {
+ for (i = 0; i < chip->ngpio; i++, gpio++)
msm_gpio_dbg_show_one(s, NULL, chip, i, gpio);
- seq_puts(s, "\n");
- }
}
#else
#define msm_gpio_dbg_show NULL
#endif
+/*
+ * If the requested GPIO has no pins, then treat it as unavailable.
+ * Otherwise, call the standard request function.
+ */
+static int msm_gpio_request(struct gpio_chip *chip, unsigned int offset)
+{
+ struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
+ const struct msm_pingroup *g = &pctrl->soc->groups[offset];
+
+ if (!g->npins)
+ return -EACCES;
+
+ return gpiochip_generic_request(chip, offset);
+}
+
static const struct gpio_chip msm_gpio_template = {
.direction_input = msm_gpio_direction_input,
.direction_output = msm_gpio_direction_output,
.get_direction = msm_gpio_get_direction,
.get = msm_gpio_get,
.set = msm_gpio_set,
- .request = gpiochip_generic_request,
+ .request = msm_gpio_request,
.free = gpiochip_generic_free,
.dbg_show = msm_gpio_dbg_show,
};
--
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm
Technologies, Inc. Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.
^ permalink raw reply related
* [PATCH 1/3] [v2] Revert "gpio: set up initial state from .get_direction()"
From: Timur Tabi @ 2017-12-13 18:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513189818-7384-1-git-send-email-timur@codeaurora.org>
This reverts commit 72d3200061776264941be1b5a9bb8e926b3b30a5.
We cannot blindly query the direction of all GPIOs when the pins are
first registered. The get_direction callback normally triggers a
read/write to hardware, but we shouldn't be touching the hardware for
an individual GPIO until after it's been properly claimed.
Signed-off-by: Timur Tabi <timur@codeaurora.org>
---
drivers/gpio/gpiolib.c | 31 +++++++------------------------
1 file changed, 7 insertions(+), 24 deletions(-)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 641a5eb552cb..168dd831551d 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1207,31 +1207,14 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
struct gpio_desc *desc = &gdev->descs[i];
desc->gdev = gdev;
- /*
- * REVISIT: most hardware initializes GPIOs as inputs
- * (often with pullups enabled) so power usage is
- * minimized. Linux code should set the gpio direction
- * first thing; but until it does, and in case
- * chip->get_direction is not set, we may expose the
- * wrong direction in sysfs.
- */
-
- if (chip->get_direction) {
- /*
- * If we have .get_direction, set up the initial
- * direction flag from the hardware.
- */
- int dir = chip->get_direction(chip, i);
- if (!dir)
- set_bit(FLAG_IS_OUT, &desc->flags);
- } else if (!chip->direction_input) {
- /*
- * If the chip lacks the .direction_input callback
- * we logically assume all lines are outputs.
- */
- set_bit(FLAG_IS_OUT, &desc->flags);
- }
+ /* REVISIT: most hardware initializes GPIOs as inputs (often
+ * with pullups enabled) so power usage is minimized. Linux
+ * code should set the gpio direction first thing; but until
+ * it does, and in case chip->get_direction is not set, we may
+ * expose the wrong direction in sysfs.
+ */
+ desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0;
}
#ifdef CONFIG_PINCTRL
--
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm
Technologies, Inc. Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.
^ permalink raw reply related
* [PATCH 0/3] [v10] pinctrl: qcom: add support for sparse GPIOs
From: Timur Tabi @ 2017-12-13 18:30 UTC (permalink / raw)
To: linux-arm-kernel
A series of patches that add support for GPIO maps that have holes in
them. That is, even though a client driver has N consecutive GPIOs,
some are just unavailable for whatever reason, and the hardware should
not be accessed for those GPIOs.
Patch 1 reverts an old patch that triggers a get_direction of every
pin upon init, without attempting to request the pins first. The
direction is already being queried when the pin is requested.
Patch 2 adds support to pinctrl-msm for "unavailable" GPIOs.
Patch 3 extends that support to pinctrl-qdf2xxx. A recent ACPI change
on QDF2400 platforms blocks access to most pins, so the driver can only
register a subset.
This version drops the availability check in gpiolib, because it's no
necessary. Instead, just having pinctrl-msm return -EACCES is enough
to block all unavailable GPIOs. Patch 1 removes the only instance where
an unrequested GPIO is being accessed.
v10:
Use driver_stuct to obtain ACPI match table entry
Timur Tabi (3):
[v2] Revert "gpio: set up initial state from .get_direction()"
[v8] pinctrl: qcom: disable GPIO groups with no pins
[v6] pinctrl: qcom: qdf2xxx: add support for new ACPI HID QCOM8002
drivers/gpio/gpiolib.c | 31 ++------
drivers/pinctrl/qcom/pinctrl-msm.c | 28 +++++--
drivers/pinctrl/qcom/pinctrl-qdf2xxx.c | 134 +++++++++++++++++++++++++--------
3 files changed, 133 insertions(+), 60 deletions(-)
--
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm
Technologies, Inc. Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.
^ permalink raw reply
* [PATCH v5 8/9] arm64: topology: Enable ACPI/PPTT based CPU topology.
From: Lorenzo Pieralisi @ 2017-12-13 18:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171201222330.18863-9-jeremy.linton@arm.com>
Nit: remove the period in $SUBJECT and capitalize with a coherent
policy for the patches touching the same code.
On Fri, Dec 01, 2017 at 04:23:29PM -0600, Jeremy Linton wrote:
> Propagate the topology information from the PPTT tree to the
> cpu_topology array. We can get the thread id, core_id and
> cluster_id by assuming certain levels of the PPTT tree correspond
> to those concepts. The package_id is flagged in the tree and can be
> found by calling find_acpi_cpu_topology_package() which terminates
> its search when it finds an ACPI node flagged as the physical
> package. If the tree doesn't contain enough levels to represent
> all of the requested levels then the root node will be returned
> for all subsequent levels.
>
> Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
> ---
> arch/arm64/kernel/topology.c | 47 +++++++++++++++++++++++++++++++++++++++++++-
> include/linux/topology.h | 2 ++
> 2 files changed, 48 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
> index 74a8a5173a35..198714aca9e8 100644
> --- a/arch/arm64/kernel/topology.c
> +++ b/arch/arm64/kernel/topology.c
> @@ -11,6 +11,7 @@
> * for more details.
> */
>
> +#include <linux/acpi.h>
> #include <linux/arch_topology.h>
> #include <linux/cpu.h>
> #include <linux/cpumask.h>
> @@ -22,6 +23,7 @@
> #include <linux/sched.h>
> #include <linux/sched/topology.h>
> #include <linux/slab.h>
> +#include <linux/smp.h>
> #include <linux/string.h>
>
> #include <asm/cpu.h>
> @@ -300,6 +302,47 @@ static void __init reset_cpu_topology(void)
> }
> }
>
> +#ifdef CONFIG_ACPI
> +/*
> + * Propagate the topology information of the processor_topology_node tree to the
> + * cpu_topology array.
> + */
> +static int __init parse_acpi_topology(void)
> +{
> + u64 is_threaded;
Nit: a bool would be preferable.
> + int cpu;
> + int topology_id;
int cpu, topology_id;
> + is_threaded = read_cpuid_mpidr() & MPIDR_MT_BITMASK;
> + for_each_possible_cpu(cpu) {
> + topology_id = find_acpi_cpu_topology(cpu, 0);
> + if (topology_id < 0)
> + return topology_id;
> +
> + if (is_threaded) {
> + cpu_topology[cpu].thread_id = topology_id;
> + topology_id = find_acpi_cpu_topology(cpu, 1);
> + cpu_topology[cpu].core_id = topology_id;
> + topology_id = find_acpi_cpu_topology_package(cpu);
> + cpu_topology[cpu].physical_id = topology_id;
> + } else {
> + cpu_topology[cpu].thread_id = -1;
> + cpu_topology[cpu].core_id = topology_id;
> + topology_id = find_acpi_cpu_topology_package(cpu);
> + cpu_topology[cpu].physical_id = topology_id;
> + }
> + }
Add a space.
It is probably my fault so apologies if that's the case. The
find_acpi_cpu_topology()
API is a bit strange since it behaves differently according to the
level passed in.
I think it is better to define two calls (it might well have been like
that in one of the previous series versions):
- find_acpi_cpu_package_level() (returns: package level if success, <0 on
failure)
- acpi_cpu_topology_id()
It would even be better to lump the two calls together but you do not
know how many topology levels are there so it becomes a bit complicated
to handle.
> + return 0;
> +}
> +
> +#else
> +static int __init parse_acpi_topology(void)
static inline ?
> +{
> + /*ACPI kernels should be built with PPTT support*/
I think you can remove this comment.
> + return -EINVAL;
> +}
> +#endif
>
> void __init init_cpu_topology(void)
> {
> @@ -309,6 +352,8 @@ void __init init_cpu_topology(void)
> * Discard anything that was parsed if we hit an error so we
> * don't use partial information.
> */
> - if (of_have_populated_dt() && parse_dt_topology())
> + if ((!acpi_disabled) && parse_acpi_topology())
> + reset_cpu_topology();
> + else if (of_have_populated_dt() && parse_dt_topology())
> reset_cpu_topology();
> }
> diff --git a/include/linux/topology.h b/include/linux/topology.h
> index cb0775e1ee4b..170ce87edd88 100644
> --- a/include/linux/topology.h
> +++ b/include/linux/topology.h
> @@ -43,6 +43,8 @@
> if (nr_cpus_node(node))
>
> int arch_update_cpu_topology(void);
> +int find_acpi_cpu_topology(unsigned int cpu, int level);
> +int find_acpi_cpu_topology_package(unsigned int cpu);
I do not think these two declarations:
a) belong in this patch
b) belong in include/linux/topology.h (should be acpi.h)
Lorenzo
^ permalink raw reply
* [PATCH v5 7/9] arm64: Topology, rename cluster_id
From: Lorenzo Pieralisi @ 2017-12-13 18:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171201222330.18863-8-jeremy.linton@arm.com>
[+Morten, Dietmar]
$SUBJECT should be:
arm64: topology: rename cluster_id
On Fri, Dec 01, 2017 at 04:23:28PM -0600, Jeremy Linton wrote:
> Lets match the name of the arm64 topology field
> to the kernel macro that uses it.
>
> Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
> ---
> arch/arm64/include/asm/topology.h | 4 ++--
> arch/arm64/kernel/topology.c | 27 ++++++++++++++-------------
> 2 files changed, 16 insertions(+), 15 deletions(-)
>
> diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h
> index c4f2d50491eb..118136268f66 100644
> --- a/arch/arm64/include/asm/topology.h
> +++ b/arch/arm64/include/asm/topology.h
> @@ -7,14 +7,14 @@
> struct cpu_topology {
> int thread_id;
> int core_id;
> - int cluster_id;
> + int physical_id;
package_id ?
It has been debated before, I know. Should we keep the cluster_id too
(even if it would be 1:1 mapped to package_id - for now) ?
There is also arch/arm to take into account, again, this patch is
just renaming (as it should have named since the beginning) a
topology level but we should consider everything from a legacy
perspective.
Lorenzo
> cpumask_t thread_sibling;
> cpumask_t core_sibling;
> };
>
> extern struct cpu_topology cpu_topology[NR_CPUS];
>
> -#define topology_physical_package_id(cpu) (cpu_topology[cpu].cluster_id)
> +#define topology_physical_package_id(cpu) (cpu_topology[cpu].physical_id)
> #define topology_core_id(cpu) (cpu_topology[cpu].core_id)
> #define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling)
> #define topology_sibling_cpumask(cpu) (&cpu_topology[cpu].thread_sibling)
> diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
> index 8d48b233e6ce..74a8a5173a35 100644
> --- a/arch/arm64/kernel/topology.c
> +++ b/arch/arm64/kernel/topology.c
> @@ -51,7 +51,7 @@ static int __init get_cpu_for_node(struct device_node *node)
> return -1;
> }
>
> -static int __init parse_core(struct device_node *core, int cluster_id,
> +static int __init parse_core(struct device_node *core, int physical_id,
> int core_id)
> {
> char name[10];
> @@ -67,7 +67,7 @@ static int __init parse_core(struct device_node *core, int cluster_id,
> leaf = false;
> cpu = get_cpu_for_node(t);
> if (cpu >= 0) {
> - cpu_topology[cpu].cluster_id = cluster_id;
> + cpu_topology[cpu].physical_id = physical_id;
> cpu_topology[cpu].core_id = core_id;
> cpu_topology[cpu].thread_id = i;
> } else {
> @@ -89,7 +89,7 @@ static int __init parse_core(struct device_node *core, int cluster_id,
> return -EINVAL;
> }
>
> - cpu_topology[cpu].cluster_id = cluster_id;
> + cpu_topology[cpu].physical_id = physical_id;
> cpu_topology[cpu].core_id = core_id;
> } else if (leaf) {
> pr_err("%pOF: Can't get CPU for leaf core\n", core);
> @@ -105,7 +105,7 @@ static int __init parse_cluster(struct device_node *cluster, int depth)
> bool leaf = true;
> bool has_cores = false;
> struct device_node *c;
> - static int cluster_id __initdata;
> + static int physical_id __initdata;
> int core_id = 0;
> int i, ret;
>
> @@ -144,7 +144,7 @@ static int __init parse_cluster(struct device_node *cluster, int depth)
> }
>
> if (leaf) {
> - ret = parse_core(c, cluster_id, core_id++);
> + ret = parse_core(c, physical_id, core_id++);
> } else {
> pr_err("%pOF: Non-leaf cluster with core %s\n",
> cluster, name);
> @@ -162,7 +162,7 @@ static int __init parse_cluster(struct device_node *cluster, int depth)
> pr_warn("%pOF: empty cluster\n", cluster);
>
> if (leaf)
> - cluster_id++;
> + physical_id++;
>
> return 0;
> }
> @@ -198,7 +198,7 @@ static int __init parse_dt_topology(void)
> * only mark cores described in the DT as possible.
> */
> for_each_possible_cpu(cpu)
> - if (cpu_topology[cpu].cluster_id == -1)
> + if (cpu_topology[cpu].physical_id == -1)
> ret = -EINVAL;
>
> out_map:
> @@ -228,7 +228,7 @@ static void update_siblings_masks(unsigned int cpuid)
> for_each_possible_cpu(cpu) {
> cpu_topo = &cpu_topology[cpu];
>
> - if (cpuid_topo->cluster_id != cpu_topo->cluster_id)
> + if (cpuid_topo->physical_id != cpu_topo->physical_id)
> continue;
>
> cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
> @@ -249,7 +249,7 @@ void store_cpu_topology(unsigned int cpuid)
> struct cpu_topology *cpuid_topo = &cpu_topology[cpuid];
> u64 mpidr;
>
> - if (cpuid_topo->cluster_id != -1)
> + if (cpuid_topo->physical_id != -1)
> goto topology_populated;
>
> mpidr = read_cpuid_mpidr();
> @@ -263,19 +263,19 @@ void store_cpu_topology(unsigned int cpuid)
> /* Multiprocessor system : Multi-threads per core */
> cpuid_topo->thread_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
> - cpuid_topo->cluster_id = MPIDR_AFFINITY_LEVEL(mpidr, 2) |
> + cpuid_topo->physical_id = MPIDR_AFFINITY_LEVEL(mpidr, 2) |
> MPIDR_AFFINITY_LEVEL(mpidr, 3) << 8;
> } else {
> /* Multiprocessor system : Single-thread per core */
> cpuid_topo->thread_id = -1;
> cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> - cpuid_topo->cluster_id = MPIDR_AFFINITY_LEVEL(mpidr, 1) |
> + cpuid_topo->physical_id = MPIDR_AFFINITY_LEVEL(mpidr, 1) |
> MPIDR_AFFINITY_LEVEL(mpidr, 2) << 8 |
> MPIDR_AFFINITY_LEVEL(mpidr, 3) << 16;
> }
>
> pr_debug("CPU%u: cluster %d core %d thread %d mpidr %#016llx\n",
> - cpuid, cpuid_topo->cluster_id, cpuid_topo->core_id,
> + cpuid, cpuid_topo->physical_id, cpuid_topo->core_id,
> cpuid_topo->thread_id, mpidr);
>
> topology_populated:
> @@ -291,7 +291,7 @@ static void __init reset_cpu_topology(void)
>
> cpu_topo->thread_id = -1;
> cpu_topo->core_id = 0;
> - cpu_topo->cluster_id = -1;
> + cpu_topo->physical_id = -1;
>
> cpumask_clear(&cpu_topo->core_sibling);
> cpumask_set_cpu(cpu, &cpu_topo->core_sibling);
> @@ -300,6 +300,7 @@ static void __init reset_cpu_topology(void)
> }
> }
>
> +
> void __init init_cpu_topology(void)
> {
> reset_cpu_topology();
> --
> 2.13.5
>
^ permalink raw reply
* [PATCH v2 05/19] arm64: alternatives: Add dynamic patching feature
From: Catalin Marinas @ 2017-12-13 17:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171211144937.4537-6-marc.zyngier@arm.com>
On Mon, Dec 11, 2017 at 02:49:23PM +0000, Marc Zyngier wrote:
> We've so far relied on a patching infrastructure that only gave us
> a single alternative, without any way to finely control what gets
> patched. For a single feature, this is an all or nothing thing.
>
> It would be interesting to have a more fine grained way of patching
> the kernel though, where we could dynamically tune the code that gets
> injected.
>
> In order to achive this, let's introduce a new form of alternative
> that is associated with a callback. This callback gets the instruction
> sequence number and the old instruction as a parameter, and returns
> the new instruction. This callback is always called, as the patching
> decision is now done at runtime (not patching is equivalent to returning
> the same instruction).
>
> Patching with a callback is declared with the new ALTERNATIVE_CB
> and alternative_cb directives:
>
> asm volatile(ALTERNATIVE_CB("mov %0, #0\n", callback)
> : "r" (v));
> or
> alternative_cb callback
> mov x0, #0
> alternative_else_nop_endif
Could we have a new "alternative_cb_endif" instead of
alternative_else_no_endif? IIUC, the nops generated in the
.altinstr_replacement section wouldn't be used, so I think it makes the
code clearer that there is no other alternative instruction set, just an
update in-place of the given instruction.
> diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h
> index 395befde7595..ce612e10a2c9 100644
> --- a/arch/arm64/include/asm/alternative.h
> +++ b/arch/arm64/include/asm/alternative.h
[...]
> -.macro altinstruction_entry orig_offset alt_offset feature orig_len alt_len
> +.macro altinstruction_entry orig_offset, alt_offset, feature, orig_len, alt_len, cb = 0
> .align ALTINSTR_ALIGN
> .word \orig_offset - .
> + .if \cb == 0
> .word \alt_offset - .
> + .else
> + .word \cb - .
> + .endif
> .hword \feature
> .byte \orig_len
> .byte \alt_len
> .endm
>
> -.macro alternative_insn insn1, insn2, cap, enable = 1
> +.macro alternative_insn insn1, insn2, cap, enable = 1, cb = 0
> .if \enable
> 661: \insn1
> 662: .pushsection .altinstructions, "a"
> - altinstruction_entry 661b, 663f, \cap, 662b-661b, 664f-663f
> + altinstruction_entry 661b, 663f, \cap, 662b-661b, 664f-663f, \cb
> .popsection
> .pushsection .altinstr_replacement, "ax"
> 663: \insn2
So here we could skip .pushsection .altinstr_replacement if cb. We could
even pass \cb directly to altinstruction_entry instead of 663f so that
we keep altinstruction_entry unmodified.
> @@ -109,10 +119,10 @@ void apply_alternatives(void *start, size_t length);
> /*
> * Begin an alternative code sequence.
> */
> -.macro alternative_if_not cap
> +.macro alternative_if_not cap, cb = 0
> .set .Lasm_alt_mode, 0
> .pushsection .altinstructions, "a"
> - altinstruction_entry 661f, 663f, \cap, 662f-661f, 664f-663f
> + altinstruction_entry 661f, 663f, \cap, 662f-661f, 664f-663f, \cb
> .popsection
> 661:
> .endm
> @@ -120,13 +130,17 @@ void apply_alternatives(void *start, size_t length);
> .macro alternative_if cap
> .set .Lasm_alt_mode, 1
> .pushsection .altinstructions, "a"
> - altinstruction_entry 663f, 661f, \cap, 664f-663f, 662f-661f
> + altinstruction_entry 663f, 661f, \cap, 664f-663f, 662f-661f, 0
> .popsection
> .pushsection .altinstr_replacement, "ax"
> .align 2 /* So GAS knows label 661 is suitably aligned */
> 661:
> .endm
and here we wouldn't need this hunk for alternative_if.
> --- a/arch/arm64/kernel/alternative.c
> +++ b/arch/arm64/kernel/alternative.c
> @@ -110,12 +110,15 @@ static void __apply_alternatives(void *alt_region, bool use_linear_alias)
> struct alt_instr *alt;
> struct alt_region *region = alt_region;
> __le32 *origptr, *replptr, *updptr;
> + alternative_cb_t alt_cb;
>
> for (alt = region->begin; alt < region->end; alt++) {
> u32 insn;
> int i, nr_inst;
>
> - if (!cpus_have_cap(alt->cpufeature))
> + /* Use ARM64_NCAPS as an unconditional patch */
> + if (alt->cpufeature != ARM64_NCAPS &&
Nitpick (personal preference): alt->cpufeature < ARM64_NCAPS.
> + !cpus_have_cap(alt->cpufeature))
> continue;
>
> BUG_ON(alt->alt_len != alt->orig_len);
> @@ -124,11 +127,18 @@ static void __apply_alternatives(void *alt_region, bool use_linear_alias)
>
> origptr = ALT_ORIG_PTR(alt);
> replptr = ALT_REPL_PTR(alt);
> + alt_cb = ALT_REPL_PTR(alt);
> updptr = use_linear_alias ? lm_alias(origptr) : origptr;
> nr_inst = alt->alt_len / sizeof(insn);
>
> for (i = 0; i < nr_inst; i++) {
> - insn = get_alt_insn(alt, origptr + i, replptr + i);
> + if (alt->cpufeature == ARM64_NCAPS) {
> + insn = le32_to_cpu(updptr[i]);
> + insn = alt_cb(alt, i, insn);
I wonder whether we'd need the origptr + i as well at some point (e.g.
to generate some relative relocations).
--
Catalin
^ permalink raw reply
* [PATCH v3 4/4] arm64: dts: marvell: armada-37xx: add nodes allowing cpufreq support
From: Gregory CLEMENT @ 2017-12-13 17:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171213175119.9441-1-gregory.clement@free-electrons.com>
In order to be able to use cpu freq, we need to associate a clock to each
CPU and to expose the power management registers.
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
arch/arm64/boot/dts/marvell/armada-372x.dtsi | 1 +
arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 7 +++++++
2 files changed, 8 insertions(+)
diff --git a/arch/arm64/boot/dts/marvell/armada-372x.dtsi b/arch/arm64/boot/dts/marvell/armada-372x.dtsi
index 59d7557d3b1b..2554e0baea6b 100644
--- a/arch/arm64/boot/dts/marvell/armada-372x.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-372x.dtsi
@@ -56,6 +56,7 @@
device_type = "cpu";
compatible = "arm,cortex-a53","arm,armv8";
reg = <0x1>;
+ clocks = <&nb_periph_clk 16>;
enable-method = "psci";
};
};
diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index 90c26d616a54..3056d7168e0b 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -65,6 +65,7 @@
device_type = "cpu";
compatible = "arm,cortex-a53", "arm,armv8";
reg = <0>;
+ clocks = <&nb_periph_clk 16>;
enable-method = "psci";
};
};
@@ -234,6 +235,12 @@
};
};
+ nb_pm: syscon at 14000 {
+ compatible = "marvell,armada-3700-nb-pm",
+ "syscon";
+ reg = <0x14000 0x60>;
+ };
+
pinctrl_sb: pinctrl at 18800 {
compatible = "marvell,armada3710-sb-pinctrl",
"syscon", "simple-mfd";
--
2.15.1
^ permalink raw reply related
* [PATCH v3 3/4] cpufreq: Add DVFS support for Armada 37xx
From: Gregory CLEMENT @ 2017-12-13 17:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171213175119.9441-1-gregory.clement@free-electrons.com>
This patch adds DVFS support for the Armada 37xx SoCs
There are up to four CPU frequency loads for Armada 37xx controlled by
the hardware.
This driver associates the CPU load level to a frequency, then the
hardware will switch while selecting a load level.
The hardware also can associate a voltage for each level (AVS support)
but it is not yet supported
Tested-by: Andre Heider <a.heider@gmail.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
drivers/cpufreq/Kconfig.arm | 7 +
drivers/cpufreq/Makefile | 1 +
drivers/cpufreq/armada-37xx-cpufreq.c | 241 ++++++++++++++++++++++++++++++++++
3 files changed, 249 insertions(+)
create mode 100644 drivers/cpufreq/armada-37xx-cpufreq.c
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index beb8826afbb1..3a88e33b0cfe 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -18,6 +18,13 @@ config ACPI_CPPC_CPUFREQ
If in doubt, say N.
+config ARM_ARMADA_37XX_CPUFREQ
+ tristate "Armada 37xx CPUFreq support"
+ depends on ARCH_MVEBU
+ help
+ This adds the CPUFreq driver support for Marvell Armada 37xx SoCs.
+ The Armada 37xx PMU supports 4 frequency and VDD levels.
+
# big LITTLE core layer and glue drivers
config ARM_BIG_LITTLE_CPUFREQ
tristate "Generic ARM big LITTLE CPUfreq driver"
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index d762e76887e7..e07715ce8844 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ) += arm_big_little.o
# LITTLE drivers, so that it is probed last.
obj-$(CONFIG_ARM_DT_BL_CPUFREQ) += arm_big_little_dt.o
+obj-$(CONFIG_ARM_ARMADA_37XX_CPUFREQ) += armada-37xx-cpufreq.o
obj-$(CONFIG_ARM_BRCMSTB_AVS_CPUFREQ) += brcmstb-avs-cpufreq.o
obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o
obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o
diff --git a/drivers/cpufreq/armada-37xx-cpufreq.c b/drivers/cpufreq/armada-37xx-cpufreq.c
new file mode 100644
index 000000000000..b819e5159a4b
--- /dev/null
+++ b/drivers/cpufreq/armada-37xx-cpufreq.c
@@ -0,0 +1,241 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * CPU frequency scaling support for Armada 37xx platform.
+ *
+ * Copyright (C) 2017 Marvell
+ *
+ * Gregory CLEMENT <gregory.clement@free-electrons.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+/* Power management in North Bridge register set */
+#define ARMADA_37XX_NB_L0L1 0x18
+#define ARMADA_37XX_NB_L2L3 0x1C
+#define ARMADA_37XX_NB_TBG_DIV_OFF 13
+#define ARMADA_37XX_NB_TBG_DIV_MASK 0x7
+#define ARMADA_37XX_NB_CLK_SEL_OFF 11
+#define ARMADA_37XX_NB_CLK_SEL_MASK 0x1
+#define ARMADA_37XX_NB_CLK_SEL_TBG 0x1
+#define ARMADA_37XX_NB_TBG_SEL_OFF 9
+#define ARMADA_37XX_NB_TBG_SEL_MASK 0x3
+#define ARMADA_37XX_NB_VDD_SEL_OFF 6
+#define ARMADA_37XX_NB_VDD_SEL_MASK 0x3
+#define ARMADA_37XX_NB_CONFIG_SHIFT 16
+#define ARMADA_37XX_NB_DYN_MOD 0x24
+#define ARMADA_37XX_NB_CLK_SEL_EN BIT(26)
+#define ARMADA_37XX_NB_TBG_EN BIT(28)
+#define ARMADA_37XX_NB_DIV_EN BIT(29)
+#define ARMADA_37XX_NB_VDD_EN BIT(30)
+#define ARMADA_37XX_NB_DFS_EN BIT(31)
+#define ARMADA_37XX_NB_CPU_LOAD 0x30
+#define ARMADA_37XX_NB_CPU_LOAD_MASK 0x3
+#define ARMADA_37XX_DVFS_LOAD_0 0
+#define ARMADA_37XX_DVFS_LOAD_1 1
+#define ARMADA_37XX_DVFS_LOAD_2 2
+#define ARMADA_37XX_DVFS_LOAD_3 3
+
+/*
+ * On Armada 37xx the Power management manages 4 level of CPU load,
+ * each level can be associated with a CPU clock source, a CPU
+ * divider, a VDD level, etc...
+ */
+#define LOAD_LEVEL_NR 4
+
+struct armada_37xx_dvfs {
+ u32 cpu_freq_max;
+ u8 divider[LOAD_LEVEL_NR];
+};
+
+static struct armada_37xx_dvfs armada_37xx_dvfs[] = {
+ {.cpu_freq_max = 1200*1000*1000, .divider = {1, 2, 4, 6} },
+ {.cpu_freq_max = 1000*1000*1000, .divider = {1, 2, 4, 5} },
+ {.cpu_freq_max = 800*1000*1000, .divider = {1, 2, 3, 4} },
+ {.cpu_freq_max = 600*1000*1000, .divider = {2, 4, 5, 6} },
+};
+
+static struct armada_37xx_dvfs *armada_37xx_cpu_freq_info_get(u32 freq)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(armada_37xx_dvfs); i++) {
+ if (freq == armada_37xx_dvfs[i].cpu_freq_max)
+ return &armada_37xx_dvfs[i];
+ }
+
+ pr_err("Unsupported CPU frequency %d MHz\n", freq/1000000);
+ return NULL;
+}
+
+/*
+ * Setup the four level managed by the hardware. Once the four level
+ * will be configured then the DVFS will be enabled.
+ */
+static void __init armada37xx_cpufreq_dvfs_setup(struct regmap *base,
+ struct clk *clk, u8 *divider)
+{
+ int load_lvl;
+ struct clk *parent;
+
+ for (load_lvl = 0; load_lvl < LOAD_LEVEL_NR; load_lvl++) {
+ unsigned int reg, mask, val, offset = 0;
+
+ if (load_lvl <= ARMADA_37XX_DVFS_LOAD_1)
+ reg = ARMADA_37XX_NB_L0L1;
+ else
+ reg = ARMADA_37XX_NB_L2L3;
+
+ if (load_lvl == ARMADA_37XX_DVFS_LOAD_0 ||
+ load_lvl == ARMADA_37XX_DVFS_LOAD_2)
+ offset += ARMADA_37XX_NB_CONFIG_SHIFT;
+
+ /* Set cpu clock source, for all the level we use TBG */
+ val = ARMADA_37XX_NB_CLK_SEL_TBG << ARMADA_37XX_NB_CLK_SEL_OFF;
+ mask = (ARMADA_37XX_NB_CLK_SEL_MASK
+ << ARMADA_37XX_NB_CLK_SEL_OFF);
+
+ /*
+ * Set cpu divider based on the pre-computed array in
+ * order to have balanced step.
+ */
+ val |= divider[load_lvl] << ARMADA_37XX_NB_TBG_DIV_OFF;
+ mask |= (ARMADA_37XX_NB_TBG_DIV_MASK
+ << ARMADA_37XX_NB_TBG_DIV_OFF);
+
+ /* Set VDD divider which is actually the load level. */
+ val |= load_lvl << ARMADA_37XX_NB_VDD_SEL_OFF;
+ mask |= (ARMADA_37XX_NB_VDD_SEL_MASK
+ << ARMADA_37XX_NB_VDD_SEL_OFF);
+
+ val <<= offset;
+ mask <<= offset;
+
+ regmap_update_bits(base, reg, mask, val);
+ }
+
+ /*
+ * Set cpu clock source, for all the level we keep the same
+ * clock source that the one already configured. For this one
+ * we need to use the clock framework
+ */
+ parent = clk_get_parent(clk);
+ clk_set_parent(clk, parent);
+}
+
+static void __init armada37xx_cpufreq_disable_dvfs(struct regmap *base)
+{
+ unsigned int reg = ARMADA_37XX_NB_DYN_MOD,
+ mask = ARMADA_37XX_NB_DFS_EN;
+
+ regmap_update_bits(base, reg, mask, 0);
+}
+
+static void __init armada37xx_cpufreq_enable_dvfs(struct regmap *base)
+{
+ unsigned int val, reg = ARMADA_37XX_NB_CPU_LOAD,
+ mask = ARMADA_37XX_NB_CPU_LOAD_MASK;
+
+ /* Start with the highest load (0) */
+ val = ARMADA_37XX_DVFS_LOAD_0;
+ regmap_update_bits(base, reg, mask, val);
+
+ /* Now enable DVFS for the CPUs */
+ reg = ARMADA_37XX_NB_DYN_MOD;
+ mask = ARMADA_37XX_NB_CLK_SEL_EN | ARMADA_37XX_NB_TBG_EN |
+ ARMADA_37XX_NB_DIV_EN | ARMADA_37XX_NB_VDD_EN |
+ ARMADA_37XX_NB_DFS_EN;
+
+ regmap_update_bits(base, reg, mask, mask);
+}
+
+static int __init armada37xx_cpufreq_driver_init(void)
+{
+ struct armada_37xx_dvfs *dvfs;
+ struct platform_device *pdev;
+ unsigned int cur_frequency;
+ struct regmap *nb_pm_base;
+ struct device *cpu_dev;
+ int load_lvl, ret;
+ struct clk *clk;
+
+ nb_pm_base =
+ syscon_regmap_lookup_by_compatible("marvell,armada-3700-nb-pm");
+
+ if (IS_ERR(nb_pm_base))
+ return -ENODEV;
+
+ /* Before doing any configuration on the DVFS first, disable it */
+ armada37xx_cpufreq_disable_dvfs(nb_pm_base);
+
+ /*
+ * On CPU 0 register the operating points supported (which are
+ * the nominal CPU frequency and full integer divisions of
+ * it).
+ */
+ cpu_dev = get_cpu_device(0);
+ if (!cpu_dev) {
+ dev_err(cpu_dev, "Cannot get CPU\n");
+ return -ENODEV;
+ }
+
+ clk = clk_get(cpu_dev, 0);
+ if (IS_ERR(clk)) {
+ dev_err(cpu_dev, "Cannot get clock for CPU0\n");
+ return PTR_ERR(clk);
+ }
+
+ /* Get nominal (current) CPU frequency */
+ cur_frequency = clk_get_rate(clk);
+ if (!cur_frequency) {
+ dev_err(cpu_dev, "Failed to get clock rate for CPU\n");
+ return -EINVAL;
+ }
+
+ dvfs = armada_37xx_cpu_freq_info_get(cur_frequency);
+ if (!dvfs)
+ return -EINVAL;
+
+ armada37xx_cpufreq_dvfs_setup(nb_pm_base, clk, dvfs->divider);
+
+ for (load_lvl = ARMADA_37XX_DVFS_LOAD_0; load_lvl < LOAD_LEVEL_NR;
+ load_lvl++) {
+ unsigned long freq = cur_frequency / dvfs->divider[load_lvl];
+
+ ret = dev_pm_opp_add(cpu_dev, freq, 0);
+ if (ret) {
+ /* clean-up the already added opp before leaving */
+ while (load_lvl-- > ARMADA_37XX_DVFS_LOAD_0) {
+ freq = cur_frequency / dvfs->divider[load_lvl];
+ dev_pm_opp_remove(cpu_dev, freq);
+ }
+ return ret;
+ }
+ }
+
+ /* Now that everything is setup, enable the DVFS at hardware level */
+ armada37xx_cpufreq_enable_dvfs(nb_pm_base);
+
+ pdev = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
+
+ return PTR_ERR_OR_ZERO(pdev);
+}
+/* late_initcall, to guarantee the driver is loaded after A37xx clock driver */
+late_initcall(armada37xx_cpufreq_driver_init);
+
+MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
+MODULE_DESCRIPTION("Armada 37xx cpufreq driver");
+MODULE_LICENSE("GPL");
--
2.15.1
^ permalink raw reply related
* [PATCH v3 2/4] MAINTAINERS: add new entries for Armada 37xx cpufreq driver
From: Gregory CLEMENT @ 2017-12-13 17:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171213175119.9441-1-gregory.clement@free-electrons.com>
This new driver belongs to the mvebu family, update the MAINTAINER file
to document it.
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
MAINTAINERS | 1 +
1 file changed, 1 insertion(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index aa71ab52fd76..98dcee849481 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1582,6 +1582,7 @@ F: arch/arm/boot/dts/kirkwood*
F: arch/arm/configs/mvebu_*_defconfig
F: arch/arm/mach-mvebu/
F: arch/arm64/boot/dts/marvell/armada*
+F: drivers/cpufreq/armada-37xx-cpufreq.c
F: drivers/cpufreq/mvebu-cpufreq.c
F: drivers/irqchip/irq-armada-370-xp.c
F: drivers/irqchip/irq-mvebu-*
--
2.15.1
^ permalink raw reply related
* [PATCH v3 1/4] dt-bindings: marvell: Add documentation for the North Bridge PM on Armada 37xx
From: Gregory CLEMENT @ 2017-12-13 17:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171213175119.9441-1-gregory.clement@free-electrons.com>
Extend the documentation of the Armada 37xx SoC with the the North
Bridge Power Management component.
Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
.../devicetree/bindings/arm/marvell/armada-37xx.txt | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/marvell/armada-37xx.txt b/Documentation/devicetree/bindings/arm/marvell/armada-37xx.txt
index 51336e5fc761..35c3c3460d17 100644
--- a/Documentation/devicetree/bindings/arm/marvell/armada-37xx.txt
+++ b/Documentation/devicetree/bindings/arm/marvell/armada-37xx.txt
@@ -14,3 +14,22 @@ following property before the previous one:
Example:
compatible = "marvell,armada-3720-db", "marvell,armada3720", "marvell,armada3710";
+
+
+Power management
+----------------
+
+For power management (particularly DVFS and AVS), the North Bridge
+Power Management component is needed:
+
+Required properties:
+- compatible : should contain "marvell,armada-3700-nb-pm", "syscon";
+- reg : the register start and length for the North Bridge
+ Power Management
+
+Example:
+
+nb_pm: syscon at 14000 {
+ compatible = "marvell,armada-3700-nb-pm", "syscon";
+ reg = <0x14000 0x60>;
+}
--
2.15.1
^ permalink raw reply related
* [PATCH v3 0/4] Add CPU Frequency scaling support on Armada 37xx
From: Gregory CLEMENT @ 2017-12-13 17:51 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
This is the third version of a series adding the CPU Frequency support
on Armada 37xx using DVFS. It is based on the initial work of Evan
Wang and Victor Gu.
As requested all the patches not directly related to the Armada 37xx
support had been sent in separate series.
The only other changes is replacing tab by space in the define as it
should have be already done in the v2.
The last patch is for arm-soc the arm-soc subsystem through mvebu and
update the device tree to support the CPU frequency scaling.
An update on the CPU clock driver is needed in order to take into
account the DVFS setting. It's the purpose of an other series already
sent, but is no dependencies between the series (for building or at
runtime).
Thanks,
Gregory
Changelog:
v1 -> v2:
- using syscon instead of nb_pm for the binding of the North bridge
power management unit: reported by Rob Herring
- fix sorting inside the big LITTLE section for the Kconfig: reported
by Viresh Kumar
- fix the bogus freq calculation in armada37xx_cpufreq_driver_init,
bug reported by Andre Heider
- use dev_pm_opp_remove() on the previous opp if dev_pm_opp_add()
failed, reported by Viresh Kumar
- add the Tested-by flag from Andre Heider on "cpufreq: Add DVFS
support for Armada 37xx" patch
v2 -> v3:
- move patches "cpufreq: ARM: sort the Kconfig menu", " cpufreq:
sort the drivers in ARM part", "cpufreq: mvebu: Use
dev_pm_opp_remove()" in separate series
- add reviewed-by and acked-by flags on the commits
- use space instead of tab in the #define in the armada-37xx-cpufreq.c file.
Gregory CLEMENT (4):
dt-bindings: marvell: Add documentation for the North Bridge PM on
Armada 37xx
MAINTAINERS: add new entries for Armada 37xx cpufreq driver
cpufreq: Add DVFS support for Armada 37xx
arm64: dts: marvell: armada-37xx: add nodes allowing cpufreq support
.../bindings/arm/marvell/armada-37xx.txt | 19 ++
MAINTAINERS | 1 +
arch/arm64/boot/dts/marvell/armada-372x.dtsi | 1 +
arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 7 +
drivers/cpufreq/Kconfig.arm | 7 +
drivers/cpufreq/Makefile | 1 +
drivers/cpufreq/armada-37xx-cpufreq.c | 241 +++++++++++++++++++++
7 files changed, 277 insertions(+)
create mode 100644 drivers/cpufreq/armada-37xx-cpufreq.c
--
2.15.1
^ permalink raw reply
* [PATCH v5 6/9] ACPI/PPTT: Add topology parsing code
From: Lorenzo Pieralisi @ 2017-12-13 17:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <fc12696c-15e1-cea4-42bf-db4b5daa45f2@arm.com>
On Tue, Dec 12, 2017 at 10:13:08AM -0600, Jeremy Linton wrote:
> Hi,
>
> First, thanks for taking a look at this.
>
> On 12/11/2017 07:12 PM, Rafael J. Wysocki wrote:
> >On Friday, December 1, 2017 11:23:27 PM CET Jeremy Linton wrote:
> >>The PPTT can be used to determine the groupings of CPU's at
> >>given levels in the system. Lets add a few routines to the PPTT
> >>parsing code to return a unique id for each unique level in the
> >>processor hierarchy. This can then be matched to build
> >>thread/core/cluster/die/package/etc mappings for each processing
> >>element in the system.
> >>
> >>Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
> >
> >Why can't this be folded into patch [2/9]?
>
> It can, and I will be happy squash it.
>
> It was requested that the topology portion of the parser be split
> out back in v3.
>
> https://www.spinics.net/lists/linux-acpi/msg78487.html
I asked to split cache/topology since I am not familiar with cache
code and Sudeep - who looks after the cache code - won't be able
to review this series in time for v4.16.
Lorenzo
^ permalink raw reply
* [PATCH 3/3] soc/fsl/qe: Use common error handling code in ucc_fast_init()
From: SF Markus Elfring @ 2017-12-13 17:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <07738369-a787-98b4-41a5-71b7d630c356@users.sourceforge.net>
From: Markus Elfring <elfring@users.sourceforge.net>
Date: Wed, 13 Dec 2017 18:18:56 +0100
Add jump targets so that a bit of exception handling can be better reused
at the end of this function.
Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
---
drivers/soc/fsl/qe/ucc_fast.c | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/drivers/soc/fsl/qe/ucc_fast.c b/drivers/soc/fsl/qe/ucc_fast.c
index 2092bfdcf1bc..268dfc5dc89b 100644
--- a/drivers/soc/fsl/qe/ucc_fast.c
+++ b/drivers/soc/fsl/qe/ucc_fast.c
@@ -269,8 +269,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc
printk(KERN_ERR "%s: cannot allocate MURAM for TX FIFO\n",
__func__);
uccf->ucc_fast_tx_virtual_fifo_base_offset = 0;
- ucc_fast_free(uccf);
- return -ENOMEM;
+ goto free_nomem;
}
/* Allocate memory for Rx Virtual Fifo */
@@ -282,8 +281,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc
printk(KERN_ERR "%s: cannot allocate MURAM for RX FIFO\n",
__func__);
uccf->ucc_fast_rx_virtual_fifo_base_offset = 0;
- ucc_fast_free(uccf);
- return -ENOMEM;
+ goto free_nomem;
}
/* Set Virtual Fifo registers */
@@ -312,8 +310,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc
COMM_DIR_RX)) {
printk(KERN_ERR "%s: illegal value for RX clock\n",
__func__);
- ucc_fast_free(uccf);
- return -EINVAL;
+ goto free_inval;
}
/* Tx clock routing */
if ((uf_info->tx_clock != QE_CLK_NONE) &&
@@ -321,8 +318,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc
COMM_DIR_TX)) {
printk(KERN_ERR "%s: illegal value for TX clock\n",
__func__);
- ucc_fast_free(uccf);
- return -EINVAL;
+ goto free_inval;
}
} else {
/* tdm Rx clock routing */
@@ -330,8 +326,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc
ucc_set_tdm_rxtx_clk(uf_info->tdm_num, uf_info->rx_clock,
COMM_DIR_RX)) {
pr_err("%s: illegal value for RX clock", __func__);
- ucc_fast_free(uccf);
- return -EINVAL;
+ goto free_inval;
}
/* tdm Tx clock routing */
@@ -339,8 +334,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc
ucc_set_tdm_rxtx_clk(uf_info->tdm_num, uf_info->tx_clock,
COMM_DIR_TX)) {
pr_err("%s: illegal value for TX clock", __func__);
- ucc_fast_free(uccf);
- return -EINVAL;
+ goto free_inval;
}
/* tdm Rx sync clock routing */
@@ -348,8 +342,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc
ucc_set_tdm_rxtx_sync(uf_info->tdm_num, uf_info->rx_sync,
COMM_DIR_RX)) {
pr_err("%s: illegal value for RX clock", __func__);
- ucc_fast_free(uccf);
- return -EINVAL;
+ goto free_inval;
}
/* tdm Tx sync clock routing */
@@ -357,8 +350,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc
ucc_set_tdm_rxtx_sync(uf_info->tdm_num, uf_info->tx_sync,
COMM_DIR_TX)) {
pr_err("%s: illegal value for TX clock", __func__);
- ucc_fast_free(uccf);
- return -EINVAL;
+ goto free_inval;
}
}
@@ -374,6 +366,14 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc
*uccf_ret = uccf;
return 0;
+
+free_nomem:
+ ucc_fast_free(uccf);
+ return -ENOMEM;
+
+free_inval:
+ ucc_fast_free(uccf);
+ return -EINVAL;
}
EXPORT_SYMBOL(ucc_fast_init);
--
2.15.1
^ permalink raw reply related
* [PATCH 2/3] soc/fsl/qe: Improve a size determination in two functions
From: SF Markus Elfring @ 2017-12-13 17:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <07738369-a787-98b4-41a5-71b7d630c356@users.sourceforge.net>
From: Markus Elfring <elfring@users.sourceforge.net>
Date: Wed, 13 Dec 2017 17:51:21 +0100
Replace the specification of data structures by pointer dereferences
as the parameter for the operator "sizeof" to make the corresponding size
determination a bit safer according to the Linux coding style convention.
This issue was detected by using the Coccinelle software.
Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
---
drivers/soc/fsl/qe/ucc_fast.c | 2 +-
drivers/soc/fsl/qe/ucc_slow.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/soc/fsl/qe/ucc_fast.c b/drivers/soc/fsl/qe/ucc_fast.c
index 59b68bf4aebb..2092bfdcf1bc 100644
--- a/drivers/soc/fsl/qe/ucc_fast.c
+++ b/drivers/soc/fsl/qe/ucc_fast.c
@@ -194,7 +194,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc
return -EINVAL;
}
- uccf = kzalloc(sizeof(struct ucc_fast_private), GFP_KERNEL);
+ uccf = kzalloc(sizeof(*uccf), GFP_KERNEL);
if (!uccf)
return -ENOMEM;
diff --git a/drivers/soc/fsl/qe/ucc_slow.c b/drivers/soc/fsl/qe/ucc_slow.c
index fc91412e2300..c21a42c11080 100644
--- a/drivers/soc/fsl/qe/ucc_slow.c
+++ b/drivers/soc/fsl/qe/ucc_slow.c
@@ -152,7 +152,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc
return -EINVAL;
}
- uccs = kzalloc(sizeof(struct ucc_slow_private), GFP_KERNEL);
+ uccs = kzalloc(sizeof(*uccs), GFP_KERNEL);
if (!uccs)
return -ENOMEM;
--
2.15.1
^ permalink raw reply related
* [PATCH 1/3] soc/fsl/qe: Delete an error message for a failed memory allocation in three functions
From: SF Markus Elfring @ 2017-12-13 17:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <07738369-a787-98b4-41a5-71b7d630c356@users.sourceforge.net>
From: Markus Elfring <elfring@users.sourceforge.net>
Date: Wed, 13 Dec 2017 17:45:23 +0100
Omit an extra message for a memory allocation failure in these functions.
This issue was detected by using the Coccinelle software.
Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
---
drivers/soc/fsl/qe/gpio.c | 4 +---
drivers/soc/fsl/qe/ucc_fast.c | 5 +----
drivers/soc/fsl/qe/ucc_slow.c | 5 +----
3 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/drivers/soc/fsl/qe/gpio.c b/drivers/soc/fsl/qe/gpio.c
index 3b27075c21a7..9239cf176e67 100644
--- a/drivers/soc/fsl/qe/gpio.c
+++ b/drivers/soc/fsl/qe/gpio.c
@@ -143,10 +143,8 @@ struct qe_pin *qe_pin_request(struct device_node *np, int index)
unsigned long flags;
qe_pin = kzalloc(sizeof(*qe_pin), GFP_KERNEL);
- if (!qe_pin) {
- pr_debug("%s: can't allocate memory\n", __func__);
+ if (!qe_pin)
return ERR_PTR(-ENOMEM);
- }
err = of_get_gpio(np, index);
if (err < 0)
diff --git a/drivers/soc/fsl/qe/ucc_fast.c b/drivers/soc/fsl/qe/ucc_fast.c
index 83d8d16e3a69..59b68bf4aebb 100644
--- a/drivers/soc/fsl/qe/ucc_fast.c
+++ b/drivers/soc/fsl/qe/ucc_fast.c
@@ -195,11 +195,8 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc
}
uccf = kzalloc(sizeof(struct ucc_fast_private), GFP_KERNEL);
- if (!uccf) {
- printk(KERN_ERR "%s: Cannot allocate private data\n",
- __func__);
+ if (!uccf)
return -ENOMEM;
- }
/* Fill fast UCC structure */
uccf->uf_info = uf_info;
diff --git a/drivers/soc/fsl/qe/ucc_slow.c b/drivers/soc/fsl/qe/ucc_slow.c
index 9334bdbd9b30..fc91412e2300 100644
--- a/drivers/soc/fsl/qe/ucc_slow.c
+++ b/drivers/soc/fsl/qe/ucc_slow.c
@@ -153,11 +153,8 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc
}
uccs = kzalloc(sizeof(struct ucc_slow_private), GFP_KERNEL);
- if (!uccs) {
- printk(KERN_ERR "%s: Cannot allocate private data\n",
- __func__);
+ if (!uccs)
return -ENOMEM;
- }
/* Fill slow UCC structure */
uccs->us_info = us_info;
--
2.15.1
^ permalink raw reply related
* [PATCH 0/3] SoC/FSL/QE: Adjustments for three function implementations
From: SF Markus Elfring @ 2017-12-13 17:32 UTC (permalink / raw)
To: linux-arm-kernel
From: Markus Elfring <elfring@users.sourceforge.net>
Date: Wed, 13 Dec 2017 18:28:38 +0100
Three update suggestions were taken into account
from static source code analysis.
Markus Elfring (3):
Delete an error message for a failed memory allocation in three functions
Improve a size determination in two functions
Use common error handling code in ucc_fast_init()
drivers/soc/fsl/qe/gpio.c | 4 +---
drivers/soc/fsl/qe/ucc_fast.c | 39 ++++++++++++++++++---------------------
drivers/soc/fsl/qe/ucc_slow.c | 7 ++-----
3 files changed, 21 insertions(+), 29 deletions(-)
--
2.15.1
^ permalink raw reply
* [PATCH 2/2] cpufreq: mvebu: Free opp if registering failed
From: Gregory CLEMENT @ 2017-12-13 17:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171213172914.6148-1-gregory.clement@free-electrons.com>
Since the introduction of this driver, the functions to remove the opp
were added. So stop claiming we can't remove opp and use one of them in
case of failure.
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
drivers/cpufreq/mvebu-cpufreq.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/drivers/cpufreq/mvebu-cpufreq.c b/drivers/cpufreq/mvebu-cpufreq.c
index c043aad8e3a0..31513bd42705 100644
--- a/drivers/cpufreq/mvebu-cpufreq.c
+++ b/drivers/cpufreq/mvebu-cpufreq.c
@@ -76,12 +76,6 @@ static int __init armada_xp_pmsu_cpufreq_init(void)
return PTR_ERR(clk);
}
- /*
- * In case of a failure of dev_pm_opp_add(), we don't
- * bother with cleaning up the registered OPP (there's
- * no function to do so), and simply cancel the
- * registration of the cpufreq device.
- */
ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk), 0);
if (ret) {
clk_put(clk);
@@ -91,7 +85,8 @@ static int __init armada_xp_pmsu_cpufreq_init(void)
ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk) / 2, 0);
if (ret) {
clk_put(clk);
- return ret;
+ dev_err(cpu_dev, "Failed to register OPPs\n");
+ goto opp_register_failed;
}
ret = dev_pm_opp_set_sharing_cpus(cpu_dev,
@@ -104,5 +99,11 @@ static int __init armada_xp_pmsu_cpufreq_init(void)
platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
return 0;
+
+opp_register_failed:
+ /* As registering has failed remove all the opp for all cpus */
+ dev_pm_opp_cpumask_remove_table(cpu_possible_mask);
+
+ return ret;
}
device_initcall(armada_xp_pmsu_cpufreq_init);
--
2.15.1
^ permalink raw reply related
* [PATCH 1/2] cpufreq: mvebu: Free the clock reference in the normal path
From: Gregory CLEMENT @ 2017-12-13 17:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171213172914.6148-1-gregory.clement@free-electrons.com>
In case of error the clock reference was freed but not in normal path
once it was nor more used. This patch fixes it.
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
drivers/cpufreq/mvebu-cpufreq.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/cpufreq/mvebu-cpufreq.c b/drivers/cpufreq/mvebu-cpufreq.c
index ed915ee85dd9..c043aad8e3a0 100644
--- a/drivers/cpufreq/mvebu-cpufreq.c
+++ b/drivers/cpufreq/mvebu-cpufreq.c
@@ -99,6 +99,7 @@ static int __init armada_xp_pmsu_cpufreq_init(void)
if (ret)
dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n",
__func__, ret);
+ clk_put(clk);
}
platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
--
2.15.1
^ permalink raw reply related
* [PATCH 0/2] cpufreq: few fix on mvebu driver
From: Gregory CLEMENT @ 2017-12-13 17:29 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
The second patch of this series was originally part of the series "Add CPU
Frequency scaling support on Armada 37xx" [1].
As requested by Viresh Kumar, it is extracted in a independent series.
In the meantime, Thomas Petazzoni pointed an issue on the first
version that I fixed in this series.
While I was on this driver I found an aother issue that I fixed with
the first patch.
Thanks,
Gregory
[1]: http://lists.infradead.org/pipermail/linux-arm-kernel/2017-December/547650.html
Gregory CLEMENT (2):
cpufreq: mvebu: Free the clock reference in the normal path
cpufreq: mvebu: Free opp if registering failed
drivers/cpufreq/mvebu-cpufreq.c | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
--
2.15.1
^ permalink raw reply
* [PATCH v5 3/9] ACPI: Enable PPTT support on ARM64
From: Lorenzo Pieralisi @ 2017-12-13 17:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171201222330.18863-4-jeremy.linton@arm.com>
On Fri, Dec 01, 2017 at 04:23:24PM -0600, Jeremy Linton wrote:
> Now that we have a PPTT parser, in preparation for its use
> on arm64, lets build it.
>
> Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
> ---
> arch/arm64/Kconfig | 1 +
> drivers/acpi/Kconfig | 3 +++
> drivers/acpi/Makefile | 1 +
> 3 files changed, 5 insertions(+)
>
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index a93339f5178f..e62fd1e08c1f 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -7,6 +7,7 @@ config ARM64
> select ACPI_REDUCED_HARDWARE_ONLY if ACPI
> select ACPI_MCFG if ACPI
> select ACPI_SPCR_TABLE if ACPI
> + select ACPI_PPTT if ACPI
> select ARCH_CLOCKSOURCE_DATA
> select ARCH_HAS_DEBUG_VIRTUAL
> select ARCH_HAS_DEVMEM_IS_ALLOWED
> diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
> index 46505396869e..df7aebf0af0e 100644
> --- a/drivers/acpi/Kconfig
> +++ b/drivers/acpi/Kconfig
> @@ -545,6 +545,9 @@ config ACPI_CONFIGFS
>
> if ARM64
> source "drivers/acpi/arm64/Kconfig"
> +
> +config ACPI_PPTT
> + bool
We need to make a choice here. Either PPTT is considered ARM64 only and
we move code and config to drivers/acpi/arm64/Kconfig or we leave it in
drivers/acpi/pptt.c and we add a Kconfig entry in drivers/acpi/Kconfig
(and we make pptt.c compile on !ARM64 - which is what it should be given
that there is nothing ARM64 specific in it).
Lorenzo
> endif
>
> config TPS68470_PMIC_OPREGION
> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> index 41954a601989..b6056b566df4 100644
> --- a/drivers/acpi/Makefile
> +++ b/drivers/acpi/Makefile
> @@ -87,6 +87,7 @@ obj-$(CONFIG_ACPI_BGRT) += bgrt.o
> obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o
> obj-$(CONFIG_ACPI_SPCR_TABLE) += spcr.o
> obj-$(CONFIG_ACPI_DEBUGGER_USER) += acpi_dbg.o
> +obj-$(CONFIG_ACPI_PPTT) += pptt.o
>
> # processor has its own "processor." module_param namespace
> processor-y := processor_driver.o
> --
> 2.13.5
>
^ permalink raw reply
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