* [PATCH v2 07/18] drivers: reset: Add STM32 reset driver
From: Maxime Coquelin @ 2015-02-20 18:01 UTC (permalink / raw)
To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
Jonathan Corbet, Maxime Coquelin, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
Arnd Bergmann, Andrew Morton, David S. Miller,
Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
Will
In-Reply-To: <1424455277-29983-1-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
The STM32 MCUs family IP can be reset by accessing some shared registers.
The specificity is that some reset lines are used by the timers.
At timer initialization time, the timer has to be reset, that's why
we cannot use a regular driver.
Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/reset/Makefile | 1 +
drivers/reset/reset-stm32.c | 124 +++++++++++++++++++++++++++++++
include/dt-bindings/reset/st,stm32f429.h | 85 +++++++++++++++++++++
3 files changed, 210 insertions(+)
create mode 100644 drivers/reset/reset-stm32.c
create mode 100644 include/dt-bindings/reset/st,stm32f429.h
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 157d421..aed12d1 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -1,5 +1,6 @@
obj-$(CONFIG_RESET_CONTROLLER) += core.o
obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
+obj-$(CONFIG_ARCH_STM32) += reset-stm32.o
obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
obj-$(CONFIG_ARCH_STI) += sti/
diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c
new file mode 100644
index 0000000..7a96677
--- /dev/null
+++ b/drivers/reset/reset-stm32.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Heavily based on sunxi driver from Maxime Ripard.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+struct stm32_reset_data {
+ spinlock_t lock;
+ void __iomem *membase;
+ struct reset_controller_dev rcdev;
+};
+
+static int stm32_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct stm32_reset_data *data = container_of(rcdev,
+ struct stm32_reset_data,
+ rcdev);
+ int bank = id / BITS_PER_LONG;
+ int offset = id % BITS_PER_LONG;
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&data->lock, flags);
+
+ reg = readl_relaxed(data->membase + (bank * 4));
+ writel_relaxed(reg | BIT(offset), data->membase + (bank * 4));
+
+ spin_unlock_irqrestore(&data->lock, flags);
+
+ return 0;
+}
+
+static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct stm32_reset_data *data = container_of(rcdev,
+ struct stm32_reset_data,
+ rcdev);
+ int bank = id / BITS_PER_LONG;
+ int offset = id % BITS_PER_LONG;
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&data->lock, flags);
+
+ reg = readl_relaxed(data->membase + (bank * 4));
+ writel_relaxed(reg & ~BIT(offset), data->membase + (bank * 4));
+
+ spin_unlock_irqrestore(&data->lock, flags);
+
+ return 0;
+}
+
+static struct reset_control_ops stm32_reset_ops = {
+ .assert = stm32_reset_assert,
+ .deassert = stm32_reset_deassert,
+};
+
+static void stm32_reset_init(struct device_node *np)
+{
+ struct stm32_reset_data *data;
+ struct resource res;
+ resource_size_t size;
+ int err;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return;
+
+ err = of_address_to_resource(np, 0, &res);
+ if (err)
+ goto err_alloc;
+
+ size = resource_size(&res);
+ if (!request_mem_region(res.start, size, np->name)) {
+ err = -EINVAL;
+ goto err_alloc;
+ }
+
+ data->membase = ioremap(res.start, size);
+ if (!data->membase) {
+ err = -ENOMEM;
+ goto err_alloc;
+ }
+
+ spin_lock_init(&data->lock);
+
+ data->rcdev.owner = THIS_MODULE;
+ data->rcdev.nr_resets = size * 8;
+ data->rcdev.ops = &stm32_reset_ops;
+ data->rcdev.of_node = np;
+
+ err = reset_controller_register(&data->rcdev);
+ if (err)
+ goto err_iomap;
+
+ pr_info("%s: %d reset lines registered\n", np->full_name,
+ data->rcdev.nr_resets);
+ return;
+
+err_iomap:
+ iounmap(data->membase);
+err_alloc:
+ kfree(data);
+ pr_err("%s: Reset ctrl registration failed (%d).\n",
+ np->full_name, err);
+}
+
+RESET_CONTROLLER_OF_DECLARE(stm32, "st,stm32-reset", stm32_reset_init);
+
diff --git a/include/dt-bindings/reset/st,stm32f429.h b/include/dt-bindings/reset/st,stm32f429.h
new file mode 100644
index 0000000..04f2ba8
--- /dev/null
+++ b/include/dt-bindings/reset/st,stm32f429.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#ifndef _DT_BINDINGS_RESET_STM32F429_H
+#define _DT_BINDINGS_RESET_STM32F429_H
+
+/* AHB1 */
+#define GPIOA_RESET 0
+#define GPIOB_RESET 1
+#define GPIOC_RESET 2
+#define GPIOD_RESET 3
+#define GPIOE_RESET 4
+#define GPIOF_RESET 5
+#define GPIOG_RESET 6
+#define GPIOH_RESET 7
+#define GPIOI_RESET 8
+#define GPIOJ_RESET 9
+#define GPIOK_RESET 10
+#define CRC_RESET 12
+#define DMA1_RESET 21
+#define DMA2_RESET 22
+#define DMA2D_RESET 23
+#define ETHMAC_RESET 25
+#define OTGHS_RESET 29
+
+/* AHB2 */
+#define DCMI_RESET 32
+#define CRYP_RESET 36
+#define HASH_RESET 37
+#define RNG_RESET 38
+#define OTGFS_RESET 39
+
+/* AHB3 */
+#define FMC_RESET 64
+
+/* APB1 */
+#define TIM2_RESET 128
+#define TIM3_RESET 129
+#define TIM4_RESET 130
+#define TIM5_RESET 131
+#define TIM6_RESET 132
+#define TIM7_RESET 133
+#define TIM12_RESET 134
+#define TIM13_RESET 135
+#define TIM14_RESET 136
+#define WWDG_RESET 139
+#define SPI2_RESET 142
+#define SPI3_RESET 143
+#define UART2_RESET 145
+#define UART3_RESET 146
+#define UART4_RESET 147
+#define UART5_RESET 148
+#define I2C1_RESET 149
+#define I2C2_RESET 150
+#define I2C3_RESET 151
+#define CAN1_RESET 153
+#define CAN2_RESET 154
+#define PWR_RESET 156
+#define DAC_RESET 157
+#define UART7_RESET 158
+#define UART8_RESET 159
+
+/* APB2 */
+#define TIM1_RESET 160
+#define TIM8_RESET 161
+#define USART1_RESET 164
+#define USART6_RESET 165
+#define ADC_RESET 168
+#define SDIO_RESET 171
+#define SPI1_RESET 172
+#define SPI4_RESET 173
+#define SYSCFG_RESET 174
+#define TIM9_RESET 176
+#define TIM10_RESET 177
+#define TIM11_RESET 178
+#define SPI5_RESET 180
+#define SPI6_RESET 181
+#define SAI1_RESET 182
+#define LTDC_RESET 186
+
+#endif /* _DT_BINDINGS_RESET_STM32F429_H */
+
--
1.9.1
^ permalink raw reply related
* [PATCH v2 08/18] dt-bindings: Document the STM32 timer bindings
From: Maxime Coquelin @ 2015-02-20 18:01 UTC (permalink / raw)
To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
Jonathan Corbet, Maxime Coquelin, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
Arnd Bergmann, Andrew Morton, David S. Miller,
Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
Will
In-Reply-To: <1424455277-29983-1-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
This adds documentation of device tree bindings for the
STM32 timer.
Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
.../devicetree/bindings/timer/st,stm32-timer.txt | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
create mode 100644 Documentation/devicetree/bindings/timer/st,stm32-timer.txt
diff --git a/Documentation/devicetree/bindings/timer/st,stm32-timer.txt b/Documentation/devicetree/bindings/timer/st,stm32-timer.txt
new file mode 100644
index 0000000..7fffcd8
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/st,stm32-timer.txt
@@ -0,0 +1,19 @@
+. STMicroelectronics STM32 timer
+
+The STM32 MCUs family has several general-purpose 16 and 32 bits timers.
+
+Required properties:
+- compatible : Should be st,stm32-timer"
+- reg : Address and length of the register set
+- clocks : Reference on the timer input clock
+- interrupts : Reference to the timer interrupt
+
+Example:
+
+timer5: timer@40000c00 {
+ compatible = "st,stm32-timer";
+ reg = <0x40000c00 0x400>;
+ interrupts = <50>;
+ resets = <&reset_apb1 3>;
+ clocks = <&clk_pmtr1>;
+};
--
1.9.1
^ permalink raw reply related
* [PATCH v2 09/18] clockevent: Add STM32 Timer driver
From: Maxime Coquelin @ 2015-02-20 18:01 UTC (permalink / raw)
To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
Jonathan Corbet, Maxime Coquelin, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
Arnd Bergmann, Andrew Morton, David S. Miller,
Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
Will
In-Reply-To: <1424455277-29983-1-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
STM32 MCUs feature 16 and 32 bits general purpose timers with prescalers.
The drivers detects whether the time is 16 or 32 bits, and applies a
1024 prescaler value if it is 16 bits.
Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/clocksource/Kconfig | 9 ++
drivers/clocksource/Makefile | 1 +
drivers/clocksource/timer-stm32.c | 187 ++++++++++++++++++++++++++++++++++++++
3 files changed, 197 insertions(+)
create mode 100644 drivers/clocksource/timer-stm32.c
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index fb6011e..f372329 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -91,6 +91,15 @@ config CLKSRC_EFM32
Support to use the timers of EFM32 SoCs as clock source and clock
event device.
+config CLKSRC_STM32
+ bool "Clocksource for STM32 SoCs" if !ARCH_STM32
+ depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST)
+ select CLKSRC_MMIO
+ default ARCH_STM32
+ help
+ Support to use the timers of STM32 SoCs as clock source and clock
+ event device.
+
config ARM_ARCH_TIMER
bool
select CLKSRC_OF if OF
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index eeea736..8078178 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_ARCH_NSPIRE) += zevio-timer.o
obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm_kona_timer.o
obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o
obj-$(CONFIG_CLKSRC_EFM32) += time-efm32.o
+obj-$(CONFIG_CLKSRC_STM32) += timer-stm32.o
obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o
obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o
obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o
diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
new file mode 100644
index 0000000..9839f57
--- /dev/null
+++ b/drivers/clocksource/timer-stm32.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Inspired by time-efm32.c from Uwe Kleine-Koenig
+ */
+
+#include <linux/kernel.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+
+#define TIM_CR1 0x00
+#define TIM_DIER 0x0c
+#define TIM_SR 0x10
+#define TIM_EGR 0x14
+#define TIM_PSC 0x28
+#define TIM_ARR 0x2c
+
+#define TIM_CR1_CEN BIT(0)
+#define TIM_CR1_OPM BIT(3)
+#define TIM_CR1_ARPE BIT(7)
+
+#define TIM_DIER_UIE BIT(0)
+
+#define TIM_SR_UIF BIT(0)
+
+#define TIM_EGR_UG BIT(0)
+
+struct stm32_clock_event_ddata {
+ struct clock_event_device evtdev;
+ unsigned periodic_top;
+ void __iomem *base;
+};
+
+static void stm32_clock_event_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evtdev)
+{
+ struct stm32_clock_event_ddata *data =
+ container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
+ void *base = data->base;
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ writel_relaxed(data->periodic_top, base + TIM_ARR);
+ writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, base + TIM_CR1);
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ default:
+ writel_relaxed(0, base + TIM_CR1);
+ break;
+ }
+}
+
+static int stm32_clock_event_set_next_event(unsigned long evt,
+ struct clock_event_device *evtdev)
+{
+ struct stm32_clock_event_ddata *data =
+ container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
+
+ writel_relaxed(evt, data->base + TIM_ARR);
+ writel_relaxed(TIM_CR1_ARPE | TIM_CR1_OPM | TIM_CR1_CEN,
+ data->base + TIM_CR1);
+
+ return 0;
+}
+
+static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id)
+{
+ struct stm32_clock_event_ddata *data = dev_id;
+
+ writel_relaxed(0, data->base + TIM_SR);
+
+ data->evtdev.event_handler(&data->evtdev);
+
+ return IRQ_HANDLED;
+}
+
+static struct stm32_clock_event_ddata clock_event_ddata = {
+ .evtdev = {
+ .name = "stm32 clockevent",
+ .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
+ .set_mode = stm32_clock_event_set_mode,
+ .set_next_event = stm32_clock_event_set_next_event,
+ .rating = 200,
+ },
+};
+
+static void __init stm32_clockevent_init(struct device_node *np)
+{
+ struct stm32_clock_event_ddata *data = &clock_event_ddata;
+ struct clk *clk;
+ struct reset_control *rstc;
+ unsigned long rate, max_delta;
+ int irq, ret, bits, prescaler = 1;
+
+ clk = of_clk_get(np, 0);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ pr_err("failed to get clock for clockevent (%d)\n", ret);
+ goto err_clk_get;
+ }
+
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ pr_err("failed to enable timer clock for clockevent (%d)\n",
+ ret);
+ goto err_clk_enable;
+ }
+
+ rate = clk_get_rate(clk);
+
+ rstc = of_reset_control_get(np, NULL);
+ if (IS_ERR(rstc)) {
+ pr_err("%s: Failed to get reset\n", np->full_name);
+ return;
+ }
+
+ reset_control_assert(rstc);
+ reset_control_deassert(rstc);
+
+ data->base = of_iomap(np, 0);
+ if (!data->base) {
+ pr_err("failed to map registers for clockevent\n");
+ goto err_iomap;
+ }
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (!irq) {
+ pr_err("%s: failed to get irq.\n", np->full_name);
+ goto err_get_irq;
+ }
+
+ /* Detect whether the timer is 16 or 32 bits */
+ writel_relaxed(~0UL, data->base + TIM_ARR);
+ max_delta = readl_relaxed(data->base + TIM_ARR);
+ if (max_delta == ~0UL) {
+ prescaler = 1;
+ bits = 32;
+ } else {
+ prescaler = 1024;
+ bits = 16;
+ }
+ writel_relaxed(0, data->base + TIM_ARR);
+
+ writel_relaxed(prescaler - 1, data->base + TIM_PSC);
+ writel_relaxed(TIM_EGR_UG, data->base + TIM_EGR);
+ writel_relaxed(TIM_DIER_UIE, data->base + TIM_DIER);
+ writel_relaxed(0, data->base + TIM_SR);
+
+ data->periodic_top = DIV_ROUND_CLOSEST(rate, prescaler * HZ);
+
+ clockevents_config_and_register(&data->evtdev,
+ DIV_ROUND_CLOSEST(rate, prescaler),
+ 0x1, max_delta);
+
+ ret = request_irq(irq, stm32_clock_event_handler, IRQF_TIMER,
+ "stm32 clockevent", data);
+ if (ret) {
+ pr_err("%s: failed to request irq.\n", np->full_name);
+ goto err_get_irq;
+ }
+
+ pr_info("%s: STM32 clockevent driver initialized (%d bits)\n",
+ np->full_name, bits);
+
+ return;
+
+err_get_irq:
+ iounmap(data->base);
+err_iomap:
+ clk_disable_unprepare(clk);
+err_clk_enable:
+ clk_put(clk);
+err_clk_get:
+ return;
+}
+
+CLOCKSOURCE_OF_DECLARE(stm32, "st,stm32-timer", stm32_clockevent_init);
--
1.9.1
^ permalink raw reply related
* [PATCH v2 10/18] dt-bindings: Document the STM32 pin controller
From: Maxime Coquelin @ 2015-02-20 18:01 UTC (permalink / raw)
To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
Jonathan Corbet, Maxime Coquelin, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
Arnd Bergmann, Andrew Morton, David S. Miller,
Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
Will
In-Reply-To: <1424455277-29983-1-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
This adds documentation of device tree bindings for the
STM32 pin controller.
Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
.../devicetree/bindings/pinctrl/pinctrl-stm32.txt | 99 ++++++++++++++++++++++
1 file changed, 99 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt
new file mode 100644
index 0000000..0fb5b24
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt
@@ -0,0 +1,99 @@
+* STM32 GPIO and Pin Mux/Config controller
+
+STMicroelectronics's STM32 MCUs intregrate a GPIO and Pin mux/config hardware
+controller. It controls the input/output settings on the available pins and
+also provides ability to multiplex and configure the output of various on-chip
+controllers onto these pads.
+
+Pin controller node:
+Required properies:
+- compatible : "st,stm32-pinctrl"
+- #address-cells: The value of this property must be 1
+- #size-cells : The value of this property must be 1
+- ranges : defines mapping between pin controller node (parent) to
+ gpio-bank node (children).
+
+GPIO controller/bank node:
+Required properties:
+- gpio-controller : Indicates this device is a GPIO controller
+- #gpio-cells : Should be two.
+ The first cell is the pin number
+ The second one is the polarity:
+ - 0 for active high
+ - 1 for active low
+- reg : The gpio address range, relative to the pinctrl range
+- st,bank-name : Should be a name string for this bank as specified in
+ the datasheet
+
+Optional properties:
+- reset: : Reference to the reset controller
+
+Example:
+#include <dt-bindings/pinctrl/pinctrl-stm32.h>
+...
+
+ pin-controller {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,stm32-pinctrl";
+ ranges = <0 0x40020000 0x3000>;
+
+ gpioa: gpio@40020000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x0 0x400>;
+ resets = <&reset_ahb1 0>;
+ st,bank-name = "GPIOA";
+ };
+ ...
+ pin-functions nodes follow...
+ };
+
+Contents of function subnode node:
+----------------------------------
+
+Required properties for pin configuration node:
+- st,pins : Child node with list of pins with configuration.
+
+Below is the format of how each pin conf should look like.
+
+<bank offset altmode pull type speed>
+
+Every PIO is represented with 4 to 6 parameters.
+Each parameter is explained as below.
+
+- bank : Should be bank phandle to which this PIO belongs.
+- offset : Offset in the PIO bank.
+- altmode : Should be mode or alternate function number associated this pin, as
+described in the datasheet (IN, OUT, ALT0...ALT15, ANALOG)
+- pull : Should be either NO_PULL, PULL_UP or PULL_DOWN
+- type : Should be either PUSH_PULL or OPEN_DRAIN.
+ Setting it is not needed for IN and ANALOG modes, or alternate
+ functions acting as inputs.
+- speed : Value taken from the datasheet, depending on the function
+(LOW_SPEED, MEDIUM_SPEED, FAST_SPEED, HIGH_SPEED)
+ Setting it is not needed for IN and ANALOG modes, or alternate
+ functions acting as inputs.
+
+usart1 {
+ pinctrl_usart1: usart1-0 {
+ st,pins {
+ tx = <&gpioa 9 ALT7 NO_PULL PUSH_PULL LOW_SPEED>;
+ rx = <&gpioa 10 ALT7 NO_PULL PUSH_PULL LOW_SPEED>;
+ };
+ };
+};
+
+adc2 {
+ pinctrl_adc2: adc2-0 {
+ st,pins {
+ adc0 = <&gpioe 4 ANALOG NO_PULL>;
+ };
+ };
+};
+
+usart1: usart@40011000 {
+ ...
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart1>;
+};
--
1.9.1
^ permalink raw reply related
* [PATCH v2 11/18] pinctrl: Add pinctrl driver for STM32 MCUs
From: Maxime Coquelin @ 2015-02-20 18:01 UTC (permalink / raw)
To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
Jonathan Corbet, Maxime Coquelin, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
Arnd Bergmann, Andrew Morton, David S. Miller,
Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
Will
In-Reply-To: <1424455277-29983-1-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
This driver adds pinctrl and GPIO support to STMicrolectronic's
STM32 family of MCUs.
Pin muxing and GPIO handling have been tested on STM32F429
based Discovery board.
Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/pinctrl/Kconfig | 10 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/pinctrl-stm32.c | 779 ++++++++++++++++++++++++++++
include/dt-bindings/pinctrl/pinctrl-stm32.h | 43 ++
4 files changed, 833 insertions(+)
create mode 100644 drivers/pinctrl/pinctrl-stm32.c
create mode 100644 include/dt-bindings/pinctrl/pinctrl-stm32.h
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index d014f22..84cd081 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -125,6 +125,16 @@ config PINCTRL_ST
select PINCONF
select GPIOLIB_IRQCHIP
+config PINCTRL_STM32
+ bool "STMicroelectronics STM32 pinctrl driver"
+ depends on OF
+ depends on ARCH_STM32 || COMPILE_TEST
+ select PINMUX
+ select PINCONF
+ select GPIOLIB_IRQCHIP
+ help
+ This selects the device tree based generic pinctrl driver for STM32.
+
config PINCTRL_TEGRA
bool
select PINMUX
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index c030b3d..06ef8ab 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o
obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o
obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o
obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o
+obj-$(CONFIG_PINCTRL_STM32) += pinctrl-stm32.o
obj-$(CONFIG_ARCH_BERLIN) += berlin/
obj-y += freescale/
diff --git a/drivers/pinctrl/pinctrl-stm32.c b/drivers/pinctrl/pinctrl-stm32.c
new file mode 100644
index 0000000..5c474b0
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-stm32.c
@@ -0,0 +1,779 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Heavily based on pinctrl-st.c from Srinivas Kandagatla
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_address.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include "core.h"
+
+#define STM32_GPIO_MODER 0x00
+#define STM32_GPIO_TYPER 0x04
+#define STM32_GPIO_SPEEDR 0x08
+#define STM32_GPIO_PUPDR 0x0c
+#define STM32_GPIO_IDR 0x10
+#define STM32_GPIO_ODR 0x14
+#define STM32_GPIO_BSRR 0x18
+#define STM32_GPIO_LCKR 0x1c
+#define STM32_GPIO_AFRL 0x20
+#define STM32_GPIO_AFRH 0x24
+
+#define STM32_GPIO_PINS_PER_BANK 16
+#define OF_GPIO_ARGS_MIN 4
+
+#define STM32_PINCONF_UNPACK(conf, param)\
+ ((conf >> STM32_PINCONF_ ##param ##_SHIFT) \
+ & STM32_PINCONF_ ##param ##_MASK)
+
+#define STM32_PINCONF_PACK(conf, val, param) (conf |=\
+ ((val & STM32_PINCONF_ ##param ##_MASK) << \
+ STM32_PINCONF_ ##param ##_SHIFT))
+
+#define STM32_PINCONF_SPEED_MASK 0x3
+#define STM32_PINCONF_SPEED_SHIFT 3
+#define STM32_PINCONF_UNPACK_SPEED(conf)\
+ STM32_PINCONF_UNPACK(conf, SPEED)
+#define STM32_PINCONF_PACK_SPEED(conf, val)\
+ STM32_PINCONF_PACK(conf, val, SPEED)
+
+#define STM32_PINCONF_TYPE_MASK 0x1
+#define STM32_PINCONF_TYPE_SHIFT 2
+#define STM32_PINCONF_UNPACK_TYPE(conf)\
+ STM32_PINCONF_UNPACK(conf, TYPE)
+#define STM32_PINCONF_PACK_TYPE(conf, val)\
+ STM32_PINCONF_PACK(conf, val, TYPE)
+
+#define STM32_PINCONF_PUPD_MASK 0x3
+#define STM32_PINCONF_PUPD_SHIFT 0
+#define STM32_PINCONF_UNPACK_PUPD(conf)\
+ STM32_PINCONF_UNPACK(conf, PUPD)
+#define STM32_PINCONF_PACK_PUPD(conf, val)\
+ STM32_PINCONF_PACK(conf, val, PUPD)
+
+
+#define STM32_PINCONF_ALT_MASK 0xf
+#define STM32_PINCONF_ALT_SHIFT 2
+#define STM32_PINCONF_UNPACK_ALT(conf)\
+ STM32_PINCONF_UNPACK(conf, ALT)
+#define STM32_PINCONF_PACK_ALT(conf, val)\
+ STM32_PINCONF_PACK(conf, val, ALT)
+
+#define STM32_PINCONF_MODE_MASK 0x3
+#define STM32_PINCONF_MODE_SHIFT 0
+#define STM32_PINCONF_UNPACK_MODE(conf)\
+ STM32_PINCONF_UNPACK(conf, MODE)
+#define STM32_PINCONF_PACK_MODE(conf, val)\
+ STM32_PINCONF_PACK(conf, val, MODE)
+
+
+
+#define gpio_range_to_bank(chip) \
+ container_of(chip, struct stm32_gpio_bank, range)
+
+#define gpio_chip_to_bank(chip) \
+ container_of(chip, struct stm32_gpio_bank, gpio_chip)
+
+struct stm32_pinconf {
+ int pin;
+ const char *name;
+ unsigned long config;
+ int altfunc;
+};
+
+struct stm32_pmx_func {
+ const char *name;
+ const char **groups;
+ unsigned ngroups;
+};
+
+struct stm32_pctl_group {
+ const char *name;
+ unsigned int *pins;
+ unsigned npins;
+ struct stm32_pinconf *pin_conf;
+};
+
+struct stm32_gpio_bank {
+ void __iomem *base;
+ struct gpio_chip gpio_chip;
+ struct pinctrl_gpio_range range;
+ spinlock_t lock;
+};
+
+struct stm32_pinctrl {
+ struct device *dev;
+ struct pinctrl_dev *pctl;
+ struct stm32_gpio_bank *banks;
+ int nbanks;
+ struct stm32_pmx_func *functions;
+ int nfunctions;
+ struct stm32_pctl_group *groups;
+ int ngroups;
+};
+
+static inline int stm32_gpio_pin(int gpio)
+{
+ return gpio % STM32_GPIO_PINS_PER_BANK;
+}
+
+/* Pinconf */
+static void stm32_pinconf_set_config(struct stm32_gpio_bank *bank,
+ int pin, unsigned long config)
+{
+ u32 type, speed, pupd, val;
+ unsigned long flags;
+
+ type = STM32_PINCONF_UNPACK_TYPE(config);
+ spin_lock_irqsave(&bank->lock, flags);
+ val = readl_relaxed(bank->base + STM32_GPIO_TYPER);
+ val &= ~BIT(pin);
+ val |= type << pin;
+ writel_relaxed(val, bank->base + STM32_GPIO_TYPER);
+ spin_unlock_irqrestore(&bank->lock, flags);
+
+ speed = STM32_PINCONF_UNPACK_SPEED(config);
+ spin_lock_irqsave(&bank->lock, flags);
+ val = readl_relaxed(bank->base + STM32_GPIO_SPEEDR);
+ val &= ~GENMASK(pin * 2 + 1, pin * 2);
+ val |= speed << (pin * 2);
+ writel_relaxed(val, bank->base + STM32_GPIO_SPEEDR);
+ spin_unlock_irqrestore(&bank->lock, flags);
+
+ pupd = STM32_PINCONF_UNPACK_PUPD(config);
+ spin_lock_irqsave(&bank->lock, flags);
+ val = readl_relaxed(bank->base + STM32_GPIO_PUPDR);
+ val &= ~GENMASK(pin * 2 + 1, pin * 2);
+ val |= pupd << (pin * 2);
+ writel_relaxed(val, bank->base + STM32_GPIO_PUPDR);
+ spin_unlock_irqrestore(&bank->lock, flags);
+}
+
+static void stm32_pinconf_get_config(struct stm32_gpio_bank *bank,
+ int pin, unsigned long *config)
+{
+ u32 val;
+
+ val = readl_relaxed(bank->base + STM32_GPIO_TYPER);
+ val = val >> pin;
+ STM32_PINCONF_PACK_TYPE(*config, val);
+
+ val = readl_relaxed(bank->base + STM32_GPIO_SPEEDR);
+ val = val >> (pin * 2);
+ STM32_PINCONF_PACK_SPEED(*config, val);
+
+ val = readl_relaxed(bank->base + STM32_GPIO_PUPDR);
+ val = val >> (pin * 2);
+ STM32_PINCONF_PACK_PUPD(*config, val);
+}
+
+static int stm32_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin_id,
+ unsigned long *configs, unsigned num_configs)
+{
+ struct pinctrl_gpio_range *range =
+ pinctrl_find_gpio_range_from_pin(pctldev, pin_id);
+ struct stm32_gpio_bank *bank = gpio_range_to_bank(range);
+ int pin = stm32_gpio_pin(pin_id);
+ int i;
+
+ for (i = 0; i < num_configs; i++)
+ stm32_pinconf_set_config(bank, pin, configs[i]);
+
+ return 0;
+}
+
+static int stm32_pinconf_get(struct pinctrl_dev *pctldev,
+ unsigned pin_id, unsigned long *config)
+{
+ struct pinctrl_gpio_range *range =
+ pinctrl_find_gpio_range_from_pin(pctldev, pin_id);
+ struct stm32_gpio_bank *bank = gpio_range_to_bank(range);
+ int pin = stm32_gpio_pin(pin_id);
+
+ *config = 0;
+ stm32_pinconf_get_config(bank, pin, config);
+
+ return 0;
+}
+
+static void stm32_pinconf_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned pin_id)
+{
+ unsigned long config;
+
+ stm32_pinconf_get(pctldev, pin_id, &config);
+
+ seq_printf(s, "[PUPD:%ld,TYPE:%ld,SPEED:%ld]\n",
+ STM32_PINCONF_UNPACK_PUPD(config),
+ STM32_PINCONF_UNPACK_TYPE(config),
+ STM32_PINCONF_UNPACK_SPEED(config));
+}
+
+static struct pinconf_ops stm32_confops = {
+ .pin_config_get = stm32_pinconf_get,
+ .pin_config_set = stm32_pinconf_set,
+ .pin_config_dbg_show = stm32_pinconf_dbg_show,
+};
+
+static void stm32_pctl_set_function(struct stm32_gpio_bank *bank,
+ int pin_id, int function)
+{
+ u32 mode, alt, val;
+ int pin = stm32_gpio_pin(pin_id);
+ int alt_shift = (pin % 8) * 4;
+ int alt_offset = STM32_GPIO_AFRL + (pin / 8) * 4;
+ unsigned long flags;
+
+ mode = STM32_PINCONF_UNPACK_MODE(function);
+ alt = STM32_PINCONF_UNPACK_ALT(function);
+
+ spin_lock_irqsave(&bank->lock, flags);
+
+ val = readl_relaxed(bank->base + alt_offset);
+ val &= ~GENMASK(alt_shift + 3, alt_shift);
+ val |= (alt << alt_shift);
+ writel_relaxed(val, bank->base + alt_offset);
+
+ val = readl_relaxed(bank->base + STM32_GPIO_MODER);
+ val &= ~GENMASK(pin * 2 + 1, pin * 2);
+ val |= mode << (pin * 2);
+ writel_relaxed(val, bank->base + STM32_GPIO_MODER);
+
+ spin_unlock_irqrestore(&bank->lock, flags);
+}
+
+/* Pinmux */
+static int stm32_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+ struct stm32_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ return info->nfunctions;
+}
+
+static const char *stm32_pmx_get_fname(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ struct stm32_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ return info->functions[selector].name;
+}
+
+static int stm32_pmx_get_groups(struct pinctrl_dev *pctldev,
+ unsigned selector, const char * const **grps, unsigned * const ngrps)
+{
+ struct stm32_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ *grps = info->functions[selector].groups;
+ *ngrps = info->functions[selector].ngroups;
+
+ return 0;
+}
+
+static int stm32_pmx_set_mux(struct pinctrl_dev *pctldev, unsigned fselector,
+ unsigned group)
+{
+ struct pinctrl_gpio_range *range;
+ struct stm32_gpio_bank *bank;
+ struct stm32_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ struct stm32_pinconf *conf = info->groups[group].pin_conf;
+ int i;
+
+ for (i = 0; i < info->groups[group].npins; i++) {
+ range = pinctrl_find_gpio_range_from_pin(pctldev, conf[i].pin);
+ bank = gpio_range_to_bank(range);
+ stm32_pctl_set_function(bank, conf[i].pin, conf[i].altfunc);
+ }
+
+ return 0;
+}
+
+static int stm32_pmx_set_gpio_direction(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, unsigned gpio,
+ bool input)
+{
+ struct stm32_gpio_bank *bank = gpio_range_to_bank(range);
+
+ stm32_pctl_set_function(bank, gpio, !input);
+
+ return 0;
+}
+
+static struct pinmux_ops stm32_pmxops = {
+ .get_functions_count = stm32_pmx_get_funcs_count,
+ .get_function_name = stm32_pmx_get_fname,
+ .get_function_groups = stm32_pmx_get_groups,
+ .set_mux = stm32_pmx_set_mux,
+ .gpio_set_direction = stm32_pmx_set_gpio_direction,
+};
+
+/* Pinctrl Groups */
+static int stm32_pctl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ struct stm32_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ return info->ngroups;
+}
+
+static const char *stm32_pctl_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ struct stm32_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ return info->groups[selector].name;
+}
+
+static int stm32_pctl_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned selector, const unsigned **pins, unsigned *npins)
+{
+ struct stm32_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ if (selector >= info->ngroups)
+ return -EINVAL;
+
+ *pins = info->groups[selector].pins;
+ *npins = info->groups[selector].npins;
+
+ return 0;
+}
+
+static const inline struct stm32_pctl_group *stm32_pctl_find_group_by_name(
+ const struct stm32_pinctrl *info, const char *name)
+{
+ int i;
+
+ for (i = 0; i < info->ngroups; i++) {
+ if (!strcmp(info->groups[i].name, name))
+ return &info->groups[i];
+ }
+
+ return NULL;
+}
+
+static int stm32_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np, struct pinctrl_map **map, unsigned *num_maps)
+{
+ struct stm32_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ const struct stm32_pctl_group *grp;
+ struct pinctrl_map *new_map;
+ struct device_node *parent;
+ int map_num, i;
+
+ grp = stm32_pctl_find_group_by_name(info, np->name);
+ if (!grp) {
+ dev_err(info->dev, "unable to find group for node %s\n",
+ np->name);
+ return -EINVAL;
+ }
+
+ map_num = grp->npins + 1;
+ new_map = devm_kzalloc(pctldev->dev,
+ sizeof(*new_map) * map_num, GFP_KERNEL);
+ if (!new_map)
+ return -ENOMEM;
+
+ parent = of_get_parent(np);
+ if (!parent) {
+ devm_kfree(pctldev->dev, new_map);
+ return -EINVAL;
+ }
+
+ *map = new_map;
+ *num_maps = map_num;
+ new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
+ new_map[0].data.mux.function = parent->name;
+ new_map[0].data.mux.group = np->name;
+ of_node_put(parent);
+
+ /* create config map per pin */
+ new_map++;
+ for (i = 0; i < grp->npins; i++) {
+ new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN;
+ new_map[i].data.configs.group_or_pin =
+ pin_get_name(pctldev, grp->pins[i]);
+ new_map[i].data.configs.configs = &grp->pin_conf[i].config;
+ new_map[i].data.configs.num_configs = 1;
+ }
+ dev_info(pctldev->dev, "maps: function %s group %s num %d\n",
+ (*map)->data.mux.function, grp->name, map_num);
+
+ return 0;
+}
+
+static void stm32_pctl_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map, unsigned num_maps)
+{
+}
+
+static struct pinctrl_ops stm32_pctlops = {
+ .get_groups_count = stm32_pctl_get_groups_count,
+ .get_group_pins = stm32_pctl_get_group_pins,
+ .get_group_name = stm32_pctl_get_group_name,
+ .dt_node_to_map = stm32_pctl_dt_node_to_map,
+ .dt_free_map = stm32_pctl_dt_free_map,
+};
+
+static void stm32_pctl_dt_child_count(struct stm32_pinctrl *info,
+ struct device_node *np)
+{
+ struct device_node *child;
+
+ for_each_child_of_node(np, child) {
+ if (of_property_read_bool(child, "gpio-controller")) {
+ info->nbanks++;
+ } else {
+ info->nfunctions++;
+ info->ngroups += of_get_child_count(child);
+ }
+ }
+}
+
+static int stm32_pctl_dt_parse_groups(struct device_node *np,
+ struct stm32_pctl_group *grp, struct stm32_pinctrl *info, int idx)
+{
+ const __be32 *list;
+ struct property *pp;
+ struct stm32_pinconf *conf;
+ struct device_node *pins;
+ int i = 0, npins = 0, nr_props;
+
+ pins = of_get_child_by_name(np, "st,pins");
+ if (!pins)
+ return -ENODATA;
+
+ for_each_property_of_node(pins, pp) {
+ /* Skip those we do not want to proceed */
+ if (!strcmp(pp->name, "name"))
+ continue;
+
+ if (pp && (pp->length / sizeof(__be32)) >= OF_GPIO_ARGS_MIN) {
+ npins++;
+ } else {
+ pr_warn("Invalid st,pins in %s node\n", np->name);
+ return -EINVAL;
+ }
+ }
+
+ grp->npins = npins;
+ grp->name = np->name;
+ grp->pins = devm_kzalloc(info->dev, npins * sizeof(u32), GFP_KERNEL);
+ grp->pin_conf = devm_kzalloc(info->dev,
+ npins * sizeof(*conf), GFP_KERNEL);
+
+ if (!grp->pins || !grp->pin_conf)
+ return -ENOMEM;
+
+ /* <bank offset mux pull type speed> */
+ for_each_property_of_node(pins, pp) {
+ if (!strcmp(pp->name, "name"))
+ continue;
+ nr_props = pp->length / sizeof(u32);
+ list = pp->value;
+ conf = &grp->pin_conf[i];
+
+ /* bank & offset */
+ be32_to_cpup(list++);
+ be32_to_cpup(list++);
+ conf->pin = of_get_named_gpio(pins, pp->name, 0);
+ conf->name = pp->name;
+ grp->pins[i] = conf->pin;
+ /* mux */
+ conf->altfunc = be32_to_cpup(list++);
+ conf->config = 0;
+ /* pull-up/down */
+ conf->config |= be32_to_cpup(list++);
+ if (nr_props > OF_GPIO_ARGS_MIN) {
+ /* push-pull/open-drain */
+ conf->config |= be32_to_cpup(list++);
+ /* speed */
+ conf->config |= be32_to_cpup(list++);
+ }
+ i++;
+ }
+ of_node_put(pins);
+
+ return 0;
+}
+
+static int stm32_pctl_parse_functions(struct device_node *np,
+ struct stm32_pinctrl *info, u32 index, int *grp_index)
+{
+ struct device_node *child;
+ struct stm32_pmx_func *func;
+ struct stm32_pctl_group *grp;
+ int i = 0, ret;
+
+ func = &info->functions[index];
+ func->name = np->name;
+ func->ngroups = of_get_child_count(np);
+ if (func->ngroups == 0) {
+ dev_err(info->dev, "No groups defined\n");
+ return -EINVAL;
+ }
+ func->groups = devm_kzalloc(info->dev,
+ func->ngroups * sizeof(char *), GFP_KERNEL);
+ if (!func->groups)
+ return -ENOMEM;
+
+ for_each_child_of_node(np, child) {
+ func->groups[i] = child->name;
+ grp = &info->groups[*grp_index];
+ *grp_index += 1;
+ ret = stm32_pctl_dt_parse_groups(child, grp, info, i++);
+ if (ret)
+ return ret;
+ }
+ dev_info(info->dev, "Function[%d\t name:%s,\tgroups:%d]\n",
+ index, func->name, func->ngroups);
+
+ return 0;
+}
+
+static inline void __stm32_gpio_set(struct stm32_gpio_bank *bank,
+ unsigned offset, int value)
+{
+ if (!value)
+ offset += STM32_GPIO_PINS_PER_BANK;
+
+ writel_relaxed(BIT(offset), bank->base + STM32_GPIO_BSRR);
+}
+
+static int stm32_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ return pinctrl_request_gpio(chip->base + offset);
+}
+
+static void stm32_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ pinctrl_free_gpio(chip->base + offset);
+}
+
+static int stm32_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
+
+ return !!(readl_relaxed(bank->base + STM32_GPIO_IDR) & BIT(offset));
+}
+
+static void stm32_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
+
+ __stm32_gpio_set(bank, offset, value);
+}
+
+static int stm32_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ pinctrl_gpio_direction_input(chip->base + offset);
+
+ return 0;
+}
+
+static int stm32_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct stm32_gpio_bank *bank = gpio_chip_to_bank(chip);
+
+ __stm32_gpio_set(bank, offset, value);
+ pinctrl_gpio_direction_output(chip->base + offset);
+
+ return 0;
+}
+
+static struct gpio_chip stm32_gpio_template = {
+ .request = stm32_gpio_request,
+ .free = stm32_gpio_free,
+ .get = stm32_gpio_get,
+ .set = stm32_gpio_set,
+ .direction_input = stm32_gpio_direction_input,
+ .direction_output = stm32_gpio_direction_output,
+ .ngpio = STM32_GPIO_PINS_PER_BANK,
+};
+
+static int stm32_gpiolib_register_bank(struct stm32_pinctrl *info,
+ int bank_nr, struct device_node *np)
+{
+ struct stm32_gpio_bank *bank = &info->banks[bank_nr];
+ struct pinctrl_gpio_range *range = &bank->range;
+ struct device *dev = info->dev;
+ struct resource res;
+ struct reset_control *rstc;
+ int bank_num = of_alias_get_id(np, "gpio");
+ int err;
+
+ rstc = of_reset_control_get(np, NULL);
+ if (!IS_ERR(rstc))
+ reset_control_deassert(rstc);
+
+ if (of_address_to_resource(np, 0, &res))
+ return -ENODEV;
+
+ bank->base = devm_ioremap_resource(dev, &res);
+ if (IS_ERR(bank->base))
+ return PTR_ERR(bank->base);
+
+ bank->gpio_chip = stm32_gpio_template;
+ bank->gpio_chip.base = bank_num * STM32_GPIO_PINS_PER_BANK;
+ bank->gpio_chip.of_node = np;
+ bank->gpio_chip.dev = dev;
+ spin_lock_init(&bank->lock);
+
+ of_property_read_string(np, "st,bank-name", &range->name);
+ bank->gpio_chip.label = range->name;
+
+ range->id = bank_num;
+ range->pin_base = range->base = range->id * STM32_GPIO_PINS_PER_BANK;
+ range->npins = bank->gpio_chip.ngpio;
+ range->gc = &bank->gpio_chip;
+ err = gpiochip_add(&bank->gpio_chip);
+ if (err) {
+ dev_err(dev, "Failed to add gpiochip(%d)!\n", bank_num);
+ return err;
+ }
+ dev_info(dev, "%s bank added.\n", range->name);
+
+ return 0;
+}
+
+static int stm32_pctl_probe_dt(struct platform_device *pdev,
+ struct pinctrl_desc *pctl_desc, struct stm32_pinctrl *info)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct pinctrl_pin_desc *pdesc;
+ struct device_node *child;
+ int grp_index = 0;
+ int i = 0, j = 0, k = 0, bank = 0, ret = 0;
+
+ stm32_pctl_dt_child_count(info, np);
+ if (!info->nbanks) {
+ dev_err(&pdev->dev, "you need atleast one gpio bank\n");
+ return -EINVAL;
+ }
+
+ dev_info(&pdev->dev, "nbanks = %d\n", info->nbanks);
+ dev_info(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
+ dev_info(&pdev->dev, "ngroups = %d\n", info->ngroups);
+
+ info->functions = devm_kzalloc(&pdev->dev,
+ info->nfunctions * sizeof(*info->functions), GFP_KERNEL);
+
+ info->groups = devm_kzalloc(&pdev->dev,
+ info->ngroups * sizeof(*info->groups), GFP_KERNEL);
+
+ info->banks = devm_kzalloc(&pdev->dev,
+ info->nbanks * sizeof(*info->banks), GFP_KERNEL);
+
+ if (!info->functions || !info->groups || !info->banks)
+ return -ENOMEM;
+
+ pctl_desc->npins = info->nbanks * STM32_GPIO_PINS_PER_BANK;
+ pdesc = devm_kzalloc(&pdev->dev,
+ sizeof(*pdesc) * pctl_desc->npins, GFP_KERNEL);
+ if (!pdesc)
+ return -ENOMEM;
+
+ pctl_desc->pins = pdesc;
+
+ for_each_child_of_node(np, child) {
+ if (of_property_read_bool(child, "gpio-controller")) {
+ const char *bank_name;
+
+ ret = stm32_gpiolib_register_bank(info, bank, child);
+ if (ret)
+ return ret;
+
+ k = info->banks[bank].range.pin_base;
+ bank_name = info->banks[bank].range.name;
+ for (j = 0; j < STM32_GPIO_PINS_PER_BANK; j++, k++) {
+ pdesc->number = k;
+ pdesc->name = kasprintf(GFP_KERNEL, "%s[%d]",
+ bank_name, j);
+ pdesc++;
+ }
+ bank++;
+ } else {
+ ret = stm32_pctl_parse_functions(child, info,
+ i++, &grp_index);
+ if (ret) {
+ dev_err(&pdev->dev, "No functions found.\n");
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int stm32_pctl_probe(struct platform_device *pdev)
+{
+ struct stm32_pinctrl *info;
+ struct pinctrl_desc *pctl_desc;
+ int ret, i;
+
+ if (!pdev->dev.of_node) {
+ dev_err(&pdev->dev, "device not found.\n");
+ return -EINVAL;
+ }
+
+ pctl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctl_desc), GFP_KERNEL);
+ if (!pctl_desc)
+ return -ENOMEM;
+
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->dev = &pdev->dev;
+ platform_set_drvdata(pdev, info);
+ ret = stm32_pctl_probe_dt(pdev, pctl_desc, info);
+ if (ret)
+ return ret;
+
+ pctl_desc->owner = THIS_MODULE;
+ pctl_desc->pctlops = &stm32_pctlops;
+ pctl_desc->pmxops = &stm32_pmxops;
+ pctl_desc->confops = &stm32_confops;
+ pctl_desc->name = dev_name(&pdev->dev);
+
+ info->pctl = pinctrl_register(pctl_desc, &pdev->dev, info);
+ if (!info->pctl) {
+ dev_err(&pdev->dev, "Failed pinctrl registration\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < info->nbanks; i++)
+ pinctrl_add_gpio_range(info->pctl, &info->banks[i].range);
+
+ return 0;
+}
+
+static struct of_device_id stm32_pctl_of_match[] = {
+ { .compatible = "st,stm32-pinctrl" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver stm32_pctl_driver = {
+ .driver = {
+ .name = "stm32-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = stm32_pctl_of_match,
+ },
+ .probe = stm32_pctl_probe,
+};
+
+static int __init stm32_pctl_init(void)
+{
+ return platform_driver_register(&stm32_pctl_driver);
+}
+arch_initcall(stm32_pctl_init);
diff --git a/include/dt-bindings/pinctrl/pinctrl-stm32.h b/include/dt-bindings/pinctrl/pinctrl-stm32.h
new file mode 100644
index 0000000..3e93a86
--- /dev/null
+++ b/include/dt-bindings/pinctrl/pinctrl-stm32.h
@@ -0,0 +1,43 @@
+#ifndef _DT_BINDINGS_PINCTRL_STM32_H
+#define _DT_BINDINGS_PINCTRL_STM32_H
+
+/* Modes */
+#define IN 0
+#define OUT 1
+#define ALT 2
+#define ANALOG 3
+
+/* Alternate functions */
+#define ALT0 ((0 << 2) | ALT)
+#define ALT1 ((1 << 2) | ALT)
+#define ALT2 ((2 << 2) | ALT)
+#define ALT3 ((3 << 2) | ALT)
+#define ALT4 ((4 << 2) | ALT)
+#define ALT5 ((5 << 2) | ALT)
+#define ALT6 ((6 << 2) | ALT)
+#define ALT7 ((7 << 2) | ALT)
+#define ALT8 ((8 << 2) | ALT)
+#define ALT9 ((9 << 2) | ALT)
+#define ALT10 ((10 << 2) | ALT)
+#define ALT11 ((11 << 2) | ALT)
+#define ALT12 ((12 << 2) | ALT)
+#define ALT13 ((13 << 2) | ALT)
+#define ALT14 ((14 << 2) | ALT)
+#define ALT15 ((15 << 2) | ALT)
+
+/* Pull-Up/Down */
+#define NO_PULL 0
+#define PULL_UP 1
+#define PULL_DOWN 2
+
+/* Type */
+#define PUSH_PULL (0 << 2)
+#define OPEN_DRAIN (1 << 2)
+
+/* Speed */
+#define LOW_SPEED (0 << 3)
+#define MEDIUM_SPEED (1 << 3)
+#define FAST_SPEED (2 << 3)
+#define HIGH_SPEED (3 << 3)
+
+#endif /* _DT_BINDINGS_PINCTRL_STM32_H */
--
1.9.1
^ permalink raw reply related
* [PATCH v2 12/18] dt-bindings: Document the STM32 USART bindings
From: Maxime Coquelin @ 2015-02-20 18:01 UTC (permalink / raw)
To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
Jonathan Corbet, Maxime Coquelin, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
Arnd Bergmann, Andrew Morton, David S. Miller,
Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
Will
In-Reply-To: <1424455277-29983-1-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
This adds documentation of device tree bindings for the
STM32 USART
Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
.../devicetree/bindings/serial/st,stm32-usart.txt | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
create mode 100644 Documentation/devicetree/bindings/serial/st,stm32-usart.txt
diff --git a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt
new file mode 100644
index 0000000..e49b75ad
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt
@@ -0,0 +1,18 @@
+* STMicroelectronics STM32 USART
+
+Required properties:
+- compatible: Should be "st,stm32-usart"
+- reg: The address and length of the peripheral registers space
+- interrupts: The interrupt line of the USART instance
+- clocks: The input clock of the USART instance
+- pinctrl: The reference on the pins configuration
+
+Example:
+usart1: usart@40011000 {
+ compatible = "st,stm32-usart";
+ reg = <0x40011000 0x400>;
+ interrupts = <37>;
+ clocks = <&clk_pclk2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart1>;
+};
--
1.9.1
^ permalink raw reply related
* [PATCH v2 13/18] serial: stm32-usart: Add STM32 USART Driver
From: Maxime Coquelin @ 2015-02-20 18:01 UTC (permalink / raw)
To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
Jonathan Corbet, Maxime Coquelin, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
Arnd Bergmann, Andrew Morton, David S. Miller,
Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
Will
In-Reply-To: <1424455277-29983-1-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
This drivers adds support to the STM32 USART controller, which is a
standard serial driver.
Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/tty/serial/Kconfig | 17 +
drivers/tty/serial/Makefile | 1 +
drivers/tty/serial/stm32-usart.c | 695 +++++++++++++++++++++++++++++++++++++++
include/uapi/linux/serial_core.h | 3 +
4 files changed, 716 insertions(+)
create mode 100644 drivers/tty/serial/stm32-usart.c
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index c79b43c..b990bd4 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1577,6 +1577,23 @@ config SERIAL_MEN_Z135
This driver can also be build as a module. If so, the module will be called
men_z135_uart.ko
+config SERIAL_STM32
+ tristate "STMicroelectronics STM32 serial port support"
+ select SERIAL_CORE
+ depends on ARM || COMPILE_TEST
+ help
+ This driver is for the on-chip Serial Controller on
+ STMicroelectronics STM32 MCUs.
+ USART supports Rx & Tx functionality.
+ It support all industry standard baud rates.
+
+ If unsure, say N.
+
+config SERIAL_STM32_CONSOLE
+ bool "Support for console on STM32"
+ depends on SERIAL_STM32=y
+ select SERIAL_CORE_CONSOLE
+
endmenu
config SERIAL_MCTRL_GPIO
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 9a548ac..a582831 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -93,6 +93,7 @@ obj-$(CONFIG_SERIAL_ARC) += arc_uart.o
obj-$(CONFIG_SERIAL_RP2) += rp2.o
obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o
obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o
+obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o
# GPIOLIB helpers for modem control lines
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
new file mode 100644
index 0000000..ef3c9fd
--- /dev/null
+++ b/drivers/tty/serial/stm32-usart.c
@@ -0,0 +1,695 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Inspired by st-asc.c from STMicroelectronics (c)
+ */
+
+#if defined(CONFIG_SERIAL_STM32_USART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/serial_core.h>
+#include <linux/clk.h>
+
+#define DRIVER_NAME "stm32-usart"
+
+/* Register offsets */
+#define USART_SR 0x00
+#define USART_DR 0x04
+#define USART_BRR 0x08
+#define USART_CR1 0x0c
+#define USART_CR2 0x10
+#define USART_CR3 0x14
+#define USART_GTPR 0x18
+
+/* USART_SR */
+#define USART_SR_PE BIT(0)
+#define USART_SR_FE BIT(1)
+#define USART_SR_NF BIT(2)
+#define USART_SR_ORE BIT(3)
+#define USART_SR_IDLE BIT(4)
+#define USART_SR_RXNE BIT(5)
+#define USART_SR_TC BIT(6)
+#define USART_SR_TXE BIT(7)
+#define USART_SR_LBD BIT(8)
+#define USART_SR_CTS BIT(9)
+#define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \
+ USART_SR_FE | USART_SR_PE)
+/* Dummy bits */
+#define USART_SR_DUMMY_RX BIT(16)
+
+/* USART_DR */
+#define USART_DR_MASK GENMASK(8, 0)
+
+/* USART_BRR */
+#define USART_BRR_DIV_F_MASK GENMASK(3, 0)
+#define USART_BRR_DIV_M_MASK GENMASK(15, 4)
+#define USART_BRR_DIV_M_SHIFT 4
+
+/* USART_CR1 */
+#define USART_CR1_SBK BIT(0)
+#define USART_CR1_RWU BIT(1)
+#define USART_CR1_RE BIT(2)
+#define USART_CR1_TE BIT(3)
+#define USART_CR1_IDLEIE BIT(4)
+#define USART_CR1_RXNEIE BIT(5)
+#define USART_CR1_TCIE BIT(6)
+#define USART_CR1_TXEIE BIT(7)
+#define USART_CR1_PEIE BIT(8)
+#define USART_CR1_PS BIT(9)
+#define USART_CR1_PCE BIT(10)
+#define USART_CR1_WAKE BIT(11)
+#define USART_CR1_M BIT(12)
+#define USART_CR1_UE BIT(13)
+#define USART_CR1_OVER8 BIT(15)
+#define USART_CR1_IE_MASK GENMASK(8, 4)
+
+/* USART_CR2 */
+#define USART_CR2_ADD_MASK GENMASK(3, 0)
+#define USART_CR2_LBDL BIT(5)
+#define USART_CR2_LBDIE BIT(6)
+#define USART_CR2_LBCL BIT(8)
+#define USART_CR2_CPHA BIT(9)
+#define USART_CR2_CPOL BIT(10)
+#define USART_CR2_CLKEN BIT(11)
+#define USART_CR2_STOP_2B BIT(13)
+#define USART_CR2_STOP_MASK GENMASK(13, 12)
+#define USART_CR2_LINEN BIT(14)
+
+/* USART_CR3 */
+#define USART_CR3_EIE BIT(0)
+#define USART_CR3_IREN BIT(1)
+#define USART_CR3_IRLP BIT(2)
+#define USART_CR3_HDSEL BIT(3)
+#define USART_CR3_NACK BIT(4)
+#define USART_CR3_SCEN BIT(5)
+#define USART_CR3_DMAR BIT(6)
+#define USART_CR3_DMAT BIT(7)
+#define USART_CR3_RTSE BIT(8)
+#define USART_CR3_CTSE BIT(9)
+#define USART_CR3_CTSIE BIT(10)
+#define USART_CR3_ONEBIT BIT(11)
+
+/* USART_GTPR */
+#define USART_GTPR_PSC_MASK GENMASK(7, 0)
+#define USART_GTPR_GT_MASK GENMASK(15, 8)
+
+#define DRIVER_NAME "stm32-usart"
+#define STM32_SERIAL_NAME "ttyS"
+#define STM32_MAX_PORTS 6
+
+struct stm32_port {
+ struct uart_port port;
+ struct clk *clk;
+};
+
+static struct stm32_port stm32_ports[STM32_MAX_PORTS];
+static struct uart_driver stm32_usart_driver;
+
+static void stm32_stop_tx(struct uart_port *port);
+
+static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits)
+{
+ u32 val;
+
+ val = readl_relaxed(port->membase + reg);
+ val |= bits;
+ writel_relaxed(val, port->membase + reg);
+}
+
+static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
+{
+ u32 val;
+
+ val = readl_relaxed(port->membase + reg);
+ val &= ~bits;
+ writel_relaxed(val, port->membase + reg);
+}
+
+static void stm32_receive_chars(struct uart_port *port)
+{
+ struct tty_port *tport = &port->state->port;
+ unsigned long c;
+ u32 sr;
+ char flag;
+
+ if (port->irq_wake)
+ pm_wakeup_event(tport->tty->dev, 0);
+
+ while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) {
+ sr |= USART_SR_DUMMY_RX;
+ c = readl_relaxed(port->membase + USART_DR);
+ flag = TTY_NORMAL;
+ port->icount.rx++;
+
+ if (sr & USART_SR_ERR_MASK) {
+ if (sr & USART_SR_LBD) {
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ continue;
+ } else if (sr & USART_SR_ORE) {
+ port->icount.overrun++;
+ } else if (sr & USART_SR_PE) {
+ port->icount.parity++;
+ } else if (sr & USART_SR_FE) {
+ port->icount.frame++;
+ }
+
+ sr &= port->read_status_mask;
+
+ if (sr & USART_SR_LBD)
+ flag = TTY_BREAK;
+ else if (sr & USART_SR_PE)
+ flag = TTY_PARITY;
+ else if (sr & USART_SR_FE)
+ flag = TTY_FRAME;
+ }
+
+ if (uart_handle_sysrq_char(port, c))
+ continue;
+ uart_insert_char(port, sr, USART_SR_ORE, c, flag);
+ }
+
+ spin_unlock(&port->lock);
+ tty_flip_buffer_push(tport);
+ spin_lock(&port->lock);
+}
+
+static void stm32_transmit_chars(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+
+ if (port->x_char) {
+ writel_relaxed(port->x_char, port->membase + USART_DR);
+ port->x_char = 0;
+ port->icount.tx++;
+ return;
+ }
+
+ if (uart_tx_stopped(port)) {
+ stm32_stop_tx(port);
+ return;
+ }
+
+ if (uart_circ_empty(xmit)) {
+ stm32_stop_tx(port);
+ return;
+ }
+
+ writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ if (uart_circ_empty(xmit))
+ stm32_stop_tx(port);
+}
+
+static irqreturn_t stm32_interrupt(int irq, void *ptr)
+{
+ struct uart_port *port = ptr;
+ u32 sr;
+
+ spin_lock(&port->lock);
+
+ sr = readl_relaxed(port->membase + USART_SR);
+
+ if (sr & USART_SR_RXNE)
+ stm32_receive_chars(port);
+
+ if (sr & USART_SR_TXE)
+ stm32_transmit_chars(port);
+
+ spin_unlock(&port->lock);
+
+ return IRQ_HANDLED;
+}
+
+static unsigned int stm32_tx_empty(struct uart_port *port)
+{
+ return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE;
+}
+
+static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ /*
+ * This routine is used for seting signals of: DTR, DCD, CTS/RTS
+ * We use USART's hardware for CTS/RTS, so don't need any for that.
+ * Some boards have DTR and DCD implemented using PIO pins,
+ * code to do this should be hooked in here.
+ */
+}
+
+static unsigned int stm32_get_mctrl(struct uart_port *port)
+{
+ /*
+ * This routine is used for geting signals of: DTR, DCD, DSR, RI,
+ * and CTS/RTS
+ */
+ return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/* There are probably characters waiting to be transmitted. */
+static void stm32_start_tx(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+
+ if (uart_circ_empty(xmit))
+ return;
+
+ stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE);
+}
+
+/* Transmit stop */
+static void stm32_stop_tx(struct uart_port *port)
+{
+ stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE);
+}
+
+/* Receive stop */
+static void stm32_stop_rx(struct uart_port *port)
+{
+ stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
+}
+
+/* Handle breaks - ignored by us */
+static void stm32_break_ctl(struct uart_port *port, int break_state)
+{
+ /* Nothing here yet .. */
+}
+
+static int stm32_startup(struct uart_port *port)
+{
+ const char *name = to_platform_device(port->dev)->name;
+ u32 val;
+
+ if (request_irq(port->irq, stm32_interrupt, IRQF_NO_SUSPEND,
+ name, port)) {
+ dev_err(port->dev, "cannot allocate irq %d\n", port->irq);
+ return -ENODEV;
+ }
+
+ val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+ stm32_set_bits(port, USART_CR1, val);
+
+ return 0;
+}
+
+static void stm32_shutdown(struct uart_port *port)
+{
+ u32 val;
+
+ val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+ stm32_set_bits(port, USART_CR1, val);
+
+ free_irq(port->irq, port);
+}
+
+static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned int baud;
+ u32 usardiv, mantissa, fraction;
+ tcflag_t cflag;
+ u32 cr1, cr2, cr3;
+ unsigned long flags;
+
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+ cflag = termios->c_cflag;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* Stop serial port and reset value */
+ writel_relaxed(0, port->membase + USART_CR1);
+
+ cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
+
+ if (cflag & CSTOPB)
+ cr2 = USART_CR2_STOP_2B;
+
+ if (cflag & PARENB) {
+ cr1 |= USART_CR1_PCE;
+ if ((cflag & CSIZE) == CS8)
+ cr1 |= USART_CR1_M;
+ }
+
+ if (cflag & PARODD)
+ cr1 |= USART_CR1_PS;
+
+ if (cflag & CRTSCTS)
+ cr3 = USART_CR3_RTSE | USART_CR3_CTSE;
+
+ usardiv = (port->uartclk * 25) / (baud * 4);
+ mantissa = (usardiv / 100) << USART_BRR_DIV_M_SHIFT;
+ fraction = DIV_ROUND_CLOSEST((usardiv % 100) * 16, 100);
+ if (fraction & ~USART_BRR_DIV_F_MASK) {
+ fraction = 0;
+ mantissa += (1 << USART_BRR_DIV_M_SHIFT);
+ }
+
+ writel_relaxed(mantissa | fraction, port->membase + USART_BRR);
+
+ uart_update_timeout(port, cflag, baud);
+
+ port->read_status_mask = USART_SR_ORE;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= USART_SR_PE | USART_SR_FE;
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
+ port->read_status_mask |= USART_SR_LBD;
+
+ /* Characters to ignore */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
+ if (termios->c_iflag & IGNBRK) {
+ port->ignore_status_mask |= USART_SR_LBD;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= USART_SR_ORE;
+ }
+
+ /*
+ * Ignore all characters if CREAD is not set.
+ */
+ if ((termios->c_cflag & CREAD) == 0)
+ port->ignore_status_mask |= USART_SR_DUMMY_RX;
+
+ writel_relaxed(cr3, port->membase + USART_CR3);
+ writel_relaxed(cr2, port->membase + USART_CR2);
+ writel_relaxed(cr1, port->membase + USART_CR1);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *stm32_type(struct uart_port *port)
+{
+ return (port->type == PORT_STM32) ? DRIVER_NAME : NULL;
+}
+
+static void stm32_release_port(struct uart_port *port)
+{
+}
+
+static int stm32_request_port(struct uart_port *port)
+{
+ return 0;
+}
+
+static void stm32_config_port(struct uart_port *port, int flags)
+{
+ if ((flags & UART_CONFIG_TYPE))
+ port->type = PORT_STM32;
+}
+
+static int
+stm32_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ /* No user changeable parameters */
+ return -EINVAL;
+}
+
+static void stm32_pm(struct uart_port *port, unsigned int state,
+ unsigned int oldstate)
+{
+ struct stm32_port *stm32port = container_of(port,
+ struct stm32_port, port);
+ unsigned long flags = 0;
+
+ switch (state) {
+ case UART_PM_STATE_ON:
+ clk_prepare_enable(stm32port->clk);
+ break;
+ case UART_PM_STATE_OFF:
+ spin_lock_irqsave(&port->lock, flags);
+ stm32_clr_bits(port, USART_CR1, USART_CR1_UE);
+ spin_unlock_irqrestore(&port->lock, flags);
+ clk_disable_unprepare(stm32port->clk);
+ break;
+ }
+}
+
+static struct uart_ops stm32_uart_ops = {
+ .tx_empty = stm32_tx_empty,
+ .set_mctrl = stm32_set_mctrl,
+ .get_mctrl = stm32_get_mctrl,
+ .start_tx = stm32_start_tx,
+ .stop_tx = stm32_stop_tx,
+ .stop_rx = stm32_stop_rx,
+ .break_ctl = stm32_break_ctl,
+ .startup = stm32_startup,
+ .shutdown = stm32_shutdown,
+ .set_termios = stm32_set_termios,
+ .type = stm32_type,
+ .release_port = stm32_release_port,
+ .request_port = stm32_request_port,
+ .config_port = stm32_config_port,
+ .verify_port = stm32_verify_port,
+ .pm = stm32_pm,
+};
+
+static int stm32_init_port(struct stm32_port *stm32port,
+ struct platform_device *pdev)
+{
+ struct uart_port *port = &stm32port->port;
+ struct resource *res;
+
+ port->iotype = UPIO_MEM;
+ port->flags = UPF_BOOT_AUTOCONF;
+ port->ops = &stm32_uart_ops;
+ port->dev = &pdev->dev;
+ port->irq = platform_get_irq(pdev, 0);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ port->membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(port->membase))
+ return PTR_ERR(port->membase);
+ port->mapbase = res->start;
+
+ spin_lock_init(&port->lock);
+
+ stm32port->clk = devm_clk_get(&pdev->dev, NULL);
+
+ if (WARN_ON(IS_ERR(stm32port->clk)))
+ return -EINVAL;
+
+ /* ensure that clk rate is correct by enabling the clk */
+ clk_prepare_enable(stm32port->clk);
+ stm32port->port.uartclk = clk_get_rate(stm32port->clk);
+ WARN_ON(stm32port->port.uartclk == 0);
+ clk_disable_unprepare(stm32port->clk);
+
+ return 0;
+}
+
+static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int id;
+
+ if (!np)
+ return NULL;
+
+ id = of_alias_get_id(np, STM32_SERIAL_NAME);
+
+ if (id < 0)
+ id = 0;
+
+ if (WARN_ON(id >= STM32_MAX_PORTS))
+ return NULL;
+
+ stm32_ports[id].port.line = id;
+ return &stm32_ports[id];
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id stm32_match[] = {
+ { .compatible = "st,stm32-usart", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, stm32_match);
+#endif
+
+static int stm32_serial_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct stm32_port *stm32port;
+
+ stm32port = stm32_of_get_stm32_port(pdev);
+ if (!stm32port)
+ return -ENODEV;
+
+ ret = stm32_init_port(stm32port, pdev);
+ if (ret)
+ return ret;
+
+ ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, &stm32port->port);
+
+ return 0;
+}
+
+static int stm32_serial_remove(struct platform_device *pdev)
+{
+ struct uart_port *port = platform_get_drvdata(pdev);
+
+ return uart_remove_one_port(&stm32_usart_driver, port);
+}
+
+
+#ifdef CONFIG_SERIAL_STM32_CONSOLE
+static void stm32_console_putchar(struct uart_port *port, int ch)
+{
+ while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE))
+ cpu_relax();
+
+ writel_relaxed(ch, port->membase + USART_DR);
+}
+
+static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
+{
+ struct uart_port *port = &stm32_ports[co->index].port;
+ unsigned long flags;
+ u32 old_cr1, new_cr1;
+ int locked = 1;
+
+ if (oops_in_progress) {
+ locked = spin_trylock_irqsave(&port->lock, flags);
+ } else {
+ locked = 1;
+ spin_lock_irqsave(&port->lock, flags);
+ }
+
+ /* Save and disable interrupts */
+ old_cr1 = readl_relaxed(port->membase + USART_CR1);
+ new_cr1 = old_cr1 & ~USART_CR1_IE_MASK;
+ writel_relaxed(new_cr1, port->membase + USART_CR1);
+
+ uart_console_write(port, s, cnt, stm32_console_putchar);
+
+ /* Restore interrupt state */
+ writel_relaxed(old_cr1, port->membase + USART_CR1);
+
+ if (locked)
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int stm32_console_setup(struct console *co, char *options)
+{
+ struct stm32_port *stm32port;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (co->index >= STM32_MAX_PORTS)
+ return -ENODEV;
+
+ stm32port = &stm32_ports[co->index];
+
+ /*
+ * This driver does not support early console initialization
+ * (use ARM early printk support instead), so we only expect
+ * this to be called during the uart port registration when the
+ * driver gets probed and the port should be mapped at that point.
+ */
+ if (stm32port->port.mapbase == 0 || stm32port->port.membase == NULL)
+ return -ENXIO;
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(&stm32port->port, co, baud, parity, bits, flow);
+}
+
+static struct console stm32_console = {
+ .name = STM32_SERIAL_NAME,
+ .device = uart_console_device,
+ .write = stm32_console_write,
+ .setup = stm32_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &stm32_usart_driver,
+};
+
+#define STM32_SERIAL_CONSOLE (&stm32_console)
+
+#else
+#define STM32_SERIAL_CONSOLE NULL
+#endif /* CONFIG_SERIAL_STM32_CONSOLE */
+
+static struct uart_driver stm32_usart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = DRIVER_NAME,
+ .dev_name = STM32_SERIAL_NAME,
+ .major = 0,
+ .minor = 0,
+ .nr = STM32_MAX_PORTS,
+ .cons = STM32_SERIAL_CONSOLE,
+};
+
+static struct platform_driver stm32_serial_driver = {
+ .probe = stm32_serial_probe,
+ .remove = stm32_serial_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(stm32_match),
+ },
+};
+
+static int __init usart_init(void)
+{
+ int ret;
+ static char banner[] __initdata =
+ KERN_INFO "STM32 USART driver initialized\n";
+
+ printk(banner);
+
+ ret = uart_register_driver(&stm32_usart_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&stm32_serial_driver);
+ if (ret)
+ uart_unregister_driver(&stm32_usart_driver);
+
+ return ret;
+}
+
+static void __exit usart_exit(void)
+{
+ platform_driver_unregister(&stm32_serial_driver);
+ uart_unregister_driver(&stm32_usart_driver);
+}
+
+module_init(usart_init);
+module_exit(usart_exit);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index c172180..14ba8c4 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -248,4 +248,7 @@
/* MESON */
#define PORT_MESON 109
+/* STM32 USART */
+#define PORT_STM32 110
+
#endif /* _UAPILINUX_SERIAL_CORE_H */
--
1.9.1
^ permalink raw reply related
* [PATCH v2 14/18] ARM: Add STM32 family machine
From: Maxime Coquelin @ 2015-02-20 18:01 UTC (permalink / raw)
To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
Jonathan Corbet, Maxime Coquelin, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
Arnd Bergmann, Andrew Morton, David S. Miller,
Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
Will
In-Reply-To: <1424455277-29983-1-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
STMicrolectronics's STM32 series is a family of Cortex-M
microcontrollers. It is used in various applications, and
proposes a wide range of peripherals.
Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
Documentation/arm/stm32/overview.txt | 32 ++++++++++++++++++++++++++
Documentation/arm/stm32/stm32f429-overview.txt | 22 ++++++++++++++++++
arch/arm/Kconfig | 22 ++++++++++++++++++
arch/arm/Makefile | 1 +
arch/arm/mach-stm32/Makefile | 1 +
arch/arm/mach-stm32/Makefile.boot | 0
arch/arm/mach-stm32/board-dt.c | 31 +++++++++++++++++++++++++
7 files changed, 109 insertions(+)
create mode 100644 Documentation/arm/stm32/overview.txt
create mode 100644 Documentation/arm/stm32/stm32f429-overview.txt
create mode 100644 arch/arm/mach-stm32/Makefile
create mode 100644 arch/arm/mach-stm32/Makefile.boot
create mode 100644 arch/arm/mach-stm32/board-dt.c
diff --git a/Documentation/arm/stm32/overview.txt b/Documentation/arm/stm32/overview.txt
new file mode 100644
index 0000000..d8bf6bb
--- /dev/null
+++ b/Documentation/arm/stm32/overview.txt
@@ -0,0 +1,32 @@
+ STM32 ARM Linux Overview
+ ==========================
+
+Introduction
+------------
+
+ The STMicroelectronics family of Cortex-M based MCUs are supported by the
+ 'STM32' platform of ARM Linux. Currently only the STM32F429 is supported.
+
+
+Configuration
+-------------
+
+ A generic configuration is provided for STM32 family, and can be used as the
+ default by
+ make stm32_defconfig
+
+Layout
+------
+
+ All the files for multiple machine families are located in the platform code
+ contained in arch/arm/mach-stm32
+
+ There is a generic board board-dt.c in the mach folder which support
+ Flattened Device Tree, which means, It works with any compatible board with
+ Device Trees.
+
+
+Document Author
+---------------
+
+ Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
diff --git a/Documentation/arm/stm32/stm32f429-overview.txt b/Documentation/arm/stm32/stm32f429-overview.txt
new file mode 100644
index 0000000..5206822
--- /dev/null
+++ b/Documentation/arm/stm32/stm32f429-overview.txt
@@ -0,0 +1,22 @@
+ STM32F429 Overview
+ ==================
+
+ Introduction
+ ------------
+ The STM32F429 is a Cortex-M4 MCU aimed at various applications.
+ It features:
+ - ARM Cortex-M4 up to 180MHz with FPU
+ - 2MB internal Flash Memory
+ - External memory support through FMC controller (PSRAM, SDRAM, NOR, NAND)
+ - I2C, SPI, SAI, CAN, USB OTG, Ethernet controllers
+ - LCD controller & Camera interface
+ - Cryptographic processor
+
+ Resources
+ ---------
+ Datasheet and reference manual are publicly available on ST website:
+ - http://www.st.com/web/en/catalog/mmc/FM141/SC1169/SS1577/LN1806?ecmp=stm32f429-439_pron_pr-ces2014_nov2013
+
+ Document Author
+ ---------------
+ Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 97d07ed..cfd9532 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -774,6 +774,28 @@ config ARCH_OMAP1
help
Support for older TI OMAP1 (omap7xx, omap15xx or omap16xx)
+config ARCH_STM32
+ bool "STMicrolectronics STM32"
+ depends on !MMU
+ select ARCH_REQUIRE_GPIOLIB
+ select ARM_NVIC
+ select AUTO_ZRELADDR
+ select ARCH_HAS_RESET_CONTROLLER
+ select RESET_CONTROLLER
+ select PINCTRL
+ select PINCTRL_STM32
+ select CLKSRC_OF
+ select ARMV7M_SYSTICK
+ select COMMON_CLK
+ select CPU_V7M
+ select GENERIC_CLOCKEVENTS
+ select NO_DMA
+ select NO_IOPORT_MAP
+ select SPARSE_IRQ
+ select USE_OF
+ help
+ Support for STMicorelectronics STM32 processors.
+
endchoice
menu "Multiple platform selection"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index c1785ee..7d00659 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -196,6 +196,7 @@ machine-$(CONFIG_ARCH_SHMOBILE) += shmobile
machine-$(CONFIG_ARCH_SIRF) += prima2
machine-$(CONFIG_ARCH_SOCFPGA) += socfpga
machine-$(CONFIG_ARCH_STI) += sti
+machine-$(CONFIG_ARCH_STM32) += stm32
machine-$(CONFIG_ARCH_SUNXI) += sunxi
machine-$(CONFIG_ARCH_TEGRA) += tegra
machine-$(CONFIG_ARCH_U300) += u300
diff --git a/arch/arm/mach-stm32/Makefile b/arch/arm/mach-stm32/Makefile
new file mode 100644
index 0000000..bd0b7b5
--- /dev/null
+++ b/arch/arm/mach-stm32/Makefile
@@ -0,0 +1 @@
+obj-y += board-dt.o
diff --git a/arch/arm/mach-stm32/Makefile.boot b/arch/arm/mach-stm32/Makefile.boot
new file mode 100644
index 0000000..e69de29
diff --git a/arch/arm/mach-stm32/board-dt.c b/arch/arm/mach-stm32/board-dt.c
new file mode 100644
index 0000000..1d681b3
--- /dev/null
+++ b/arch/arm/mach-stm32/board-dt.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/clocksource.h>
+#include <linux/reset-controller.h>
+#include <asm/v7m.h>
+#include <asm/mach/arch.h>
+
+static const char *const stm32_compat[] __initconst = {
+ "st,stm32f429",
+ NULL
+};
+
+static void __init stm32_timer_init(void)
+{
+ of_clk_init(NULL);
+ reset_controller_of_init();
+ clocksource_of_init();
+
+}
+
+DT_MACHINE_START(STM32DT, "STM32 (Device Tree Support)")
+ .init_time = stm32_timer_init,
+ .dt_compat = stm32_compat,
+ .restart = armv7m_restart,
+MACHINE_END
--
1.9.1
^ permalink raw reply related
* [PATCH v2 15/18] ARM: dts: Add ARM System timer as clockevent in armv7m
From: Maxime Coquelin @ 2015-02-20 18:01 UTC (permalink / raw)
To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
Jonathan Corbet, Maxime Coquelin, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
Arnd Bergmann, Andrew Morton, David S. Miller,
Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
Will
In-Reply-To: <1424455277-29983-1-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
arch/arm/boot/dts/armv7-m.dtsi | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/arm/boot/dts/armv7-m.dtsi b/arch/arm/boot/dts/armv7-m.dtsi
index 5a660d0..78a0549 100644
--- a/arch/arm/boot/dts/armv7-m.dtsi
+++ b/arch/arm/boot/dts/armv7-m.dtsi
@@ -8,6 +8,13 @@
reg = <0xe000e100 0xc00>;
};
+ systick: timer@e000e010 {
+ compatible = "arm,armv7m-systick";
+ reg = <0xe000e010 0x10>;
+
+ status = "disabled";
+ };
+
soc {
#address-cells = <1>;
#size-cells = <1>;
--
1.9.1
^ permalink raw reply related
* [PATCH v2 16/18] ARM: dts: Introduce STM32F429 MCU
From: Maxime Coquelin @ 2015-02-20 18:01 UTC (permalink / raw)
To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
Jonathan Corbet, Maxime Coquelin, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
Arnd Bergmann, Andrew Morton, David S. Miller,
Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
Will
In-Reply-To: <1424455277-29983-1-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
The STMicrolectornics's STM32F419 MCU has the following main features:
- Cortex-M4 core running up to @180MHz
- 2MB internal flash, 256KBytes internal RAM
- FMC controller to connect SDRAM, NOR and NAND memories
- SD/MMC/SDIO support
- Ethernet controller
- USB OTFG FS & HS controllers
- I2C, SPI, CAN busses support
- Several 16 & 32 bits general purpose timers
- Serial Audio interface
- LCD controller
Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/stm32f429-disco.dts | 41 ++++
arch/arm/boot/dts/stm32f429.dtsi | 396 ++++++++++++++++++++++++++++++++++
3 files changed, 438 insertions(+)
create mode 100644 arch/arm/boot/dts/stm32f429-disco.dts
create mode 100644 arch/arm/boot/dts/stm32f429.dtsi
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 91bd5bd..d7da0ef 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -442,6 +442,7 @@ dtb-$(CONFIG_ARCH_STI)+= stih407-b2120.dtb \
stih416-b2000.dtb \
stih416-b2020.dtb \
stih416-b2020e.dtb
+dtb-$(CONFIG_ARCH_STM32)+= stm32f429-disco.dtb
dtb-$(CONFIG_MACH_SUN4I) += \
sun4i-a10-a1000.dtb \
sun4i-a10-ba10-tvbox.dtb \
diff --git a/arch/arm/boot/dts/stm32f429-disco.dts b/arch/arm/boot/dts/stm32f429-disco.dts
new file mode 100644
index 0000000..0e79cc1
--- /dev/null
+++ b/arch/arm/boot/dts/stm32f429-disco.dts
@@ -0,0 +1,41 @@
+/dts-v1/;
+#include "stm32f429.dtsi"
+
+/ {
+ model = "STMicroelectronics's STM32F429i-DISCO board";
+ compatible = "st,stm32f429i-disco", "st,stm32f429";
+
+ chosen {
+ bootargs = "console=ttyS0,115200 root=/dev/ram rdinit=/linuxrc";
+ linux,stdout-path = &usart1;
+ };
+
+ memory {
+ reg = <0xd0000000 0x800000>;
+ };
+
+ aliases {
+ ttyS0 = &usart1;
+ };
+
+ soc {
+ usart1: usart@40011000 {
+ status = "okay";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ red {
+ #gpio-cells = <2>;
+ label = "Front Panel LED";
+ gpios = <&gpiog 14 0>;
+ linux,default-trigger = "heartbeat";
+ };
+ green {
+ #gpio-cells = <2>;
+ gpios = <&gpiog 13 0>;
+ default-state = "off";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
new file mode 100644
index 0000000..5b3442a
--- /dev/null
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -0,0 +1,396 @@
+/*
+ * Device tree for STM32F429
+ */
+#include "armv7-m.dtsi"
+#include <dt-bindings/pinctrl/pinctrl-stm32.h>
+#include <dt-bindings/reset/st,stm32f429.h>
+
+/ {
+
+ aliases {
+ gpio0 = &gpioa;
+ gpio1 = &gpiob;
+ gpio2 = &gpioc;
+ gpio3 = &gpiod;
+ gpio4 = &gpioe;
+ gpio5 = &gpiof;
+ gpio6 = &gpiog;
+ gpio7 = &gpioh;
+ gpio8 = &gpioi;
+ gpio9 = &gpioj;
+ gpio10 = &gpiok;
+ };
+
+ clocks {
+ clk_sysclk: clk-sysclk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <180000000>;
+ };
+
+ clk_hclk: clk-hclk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <180000000>;
+ };
+
+ clk_pclk1: clk-pclk1 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <45000000>;
+ };
+
+ clk_pclk2: clk-pclk2 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <90000000>;
+ };
+
+ clk_pmtr1: clk-pmtr1 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <90000000>;
+ };
+
+ clk_pmtr2: clk-pmtr2 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <180000000>;
+ };
+
+ clk_systick: clk-systick {
+ compatible = "fixed-factor-clock";
+ clocks = <&clk_hclk>;
+ #clock-cells = <0>;
+ clock-div = <8>;
+ clock-mult = <1>;
+ };
+ };
+
+ systick: timer@e000e010 {
+ clocks = <&clk_systick>;
+
+ status = "okay";
+ };
+
+ soc {
+ reset: reset@40023810 {
+ #reset-cells = <1>;
+ compatible = "st,stm32-reset";
+ reg = <0x40023810 0x18>;
+ };
+
+ pin-controller {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,stm32-pinctrl";
+ ranges = <0 0x40020000 0x3000>;
+
+ gpioa: gpio@40020000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x0 0x400>;
+ resets = <&reset GPIOA_RESET>;
+ st,bank-name = "GPIOA";
+ };
+
+ gpiob: gpio@40020400 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x400 0x400>;
+ resets = <&reset GPIOB_RESET>;
+ st,bank-name = "GPIOB";
+ };
+
+ gpioc: gpio@40020800 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x800 0x400>;
+ resets = <&reset GPIOC_RESET>;
+ st,bank-name = "GPIOC";
+ };
+
+ gpiod: gpio@40020c00 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0xc00 0x400>;
+ resets = <&reset GPIOD_RESET>;
+ st,bank-name = "GPIOD";
+ };
+
+ gpioe: gpio@40021000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x1000 0x400>;
+ resets = <&reset GPIOE_RESET>;
+ st,bank-name = "GPIOE";
+ };
+
+ gpiof: gpio@40021400 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x1400 0x400>;
+ resets = <&reset GPIOF_RESET>;
+ st,bank-name = "GPIOF";
+ };
+
+ gpiog: gpio@40021800 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x1800 0x400>;
+ resets = <&reset GPIOG_RESET>;
+ st,bank-name = "GPIOG";
+ };
+
+ gpioh: gpio@40021c00 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x1c00 0x400>;
+ resets = <&reset GPIOH_RESET>;
+ st,bank-name = "GPIOH";
+ };
+
+ gpioi: gpio@40022000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x2000 0x400>;
+ resets = <&reset GPIOI_RESET>;
+ st,bank-name = "GPIOI";
+ };
+
+ gpioj: gpio@40022400 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x2400 0x400>;
+ resets = <&reset GPIOJ_RESET>;
+ st,bank-name = "GPIOJ";
+ };
+
+ gpiok: gpio@40022800 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x2800 0x400>;
+ resets = <&reset GPIOK_RESET>;
+ st,bank-name = "GPIOK";
+ };
+
+ usart1 {
+ pinctrl_usart1: usart1-0 {
+ st,pins {
+ tx = <&gpioa 9 ALT7 NO_PULL PUSH_PULL LOW_SPEED>;
+ rx = <&gpioa 10 ALT7 NO_PULL>;
+ };
+ };
+ };
+
+ usart2 {
+ pinctrl_usart2: usart2-0 {
+ st,pins {
+ tx = <&gpioa 2 ALT7 NO_PULL PUSH_PULL LOW_SPEED>;
+ rx = <&gpioa 3 ALT7 NO_PULL>;
+ };
+ };
+ };
+
+ usart3 {
+ pinctrl_usart3: usart3-0 {
+ st,pins {
+ tx = <&gpiob 10 ALT7 NO_PULL PUSH_PULL LOW_SPEED>;
+ rx = <&gpiob 11 ALT7 NO_PULL>;
+ };
+ };
+ };
+
+ usart4 {
+ pinctrl_usart4: usart4-0 {
+ st,pins {
+ tx = <&gpioa 0 ALT8 NO_PULL PUSH_PULL LOW_SPEED>;
+ rx = <&gpioa 1 ALT8 NO_PULL>;
+ };
+ };
+ };
+
+ usart5 {
+ pinctrl_usart5: usart5-0 {
+ st,pins {
+ tx = <&gpioc 12 ALT8 NO_PULL PUSH_PULL LOW_SPEED>;
+ rx = <&gpiod 2 ALT8 NO_PULL>;
+ };
+ };
+ };
+
+ usart6 {
+ pinctrl_usart6: usart6-0 {
+ st,pins {
+ tx = <&gpioc 6 ALT8 NO_PULL PUSH_PULL LOW_SPEED>;
+ rx = <&gpioc 7 ALT8 NO_PULL>;
+ };
+ };
+ };
+
+ usart7 {
+ pinctrl_usart7: usart7-0 {
+ st,pins {
+ tx = <&gpioe 8 ALT8 NO_PULL PUSH_PULL LOW_SPEED>;
+ rx = <&gpioe 7 ALT8 NO_PULL>;
+ };
+ };
+ };
+
+ usart8 {
+ pinctrl_usart8: usart8-0 {
+ st,pins {
+ tx = <&gpioe 1 ALT8 NO_PULL PUSH_PULL LOW_SPEED>;
+ rx = <&gpioe 0 ALT8 NO_PULL>;
+ };
+ };
+ };
+ };
+
+ timer2: timer@40000000 {
+ compatible = "st,stm32-timer";
+ reg = <0x40000000 0x400>;
+ interrupts = <28>;
+ resets = <&reset TIM2_RESET>;
+ clocks = <&clk_pmtr1>;
+
+ status = "disabled";
+ };
+
+ timer3: timer@40000400 {
+ compatible = "st,stm32-timer";
+ reg = <0x40000400 0x400>;
+ interrupts = <29>;
+ resets = <&reset TIM3_RESET>;
+ clocks = <&clk_pmtr1>;
+
+ status = "disabled";
+ };
+
+ timer4: timer@40000800 {
+ compatible = "st,stm32-timer";
+ reg = <0x40000800 0x400>;
+ interrupts = <30>;
+ resets = <&reset TIM4_RESET>;
+ clocks = <&clk_pmtr1>;
+
+ status = "disabled";
+ };
+
+ timer5: timer@40000c00 {
+ compatible = "st,stm32-timer";
+ reg = <0x40000c00 0x400>;
+ interrupts = <50>;
+ resets = <&reset TIM5_RESET>;
+ clocks = <&clk_pmtr1>;
+ };
+
+ timer6: timer@40001000 {
+ compatible = "st,stm32-timer";
+ reg = <0x40001000 0x400>;
+ interrupts = <54>;
+ resets = <&reset TIM6_RESET>;
+ clocks = <&clk_pmtr1>;
+
+ status = "disabled";
+ };
+
+ timer7: timer@40001400 {
+ compatible = "st,stm32-timer";
+ reg = <0x40001400 0x400>;
+ interrupts = <55>;
+ resets = <&reset TIM7_RESET>;
+ clocks = <&clk_pmtr1>;
+
+ status = "disabled";
+ };
+
+ usart1: usart@40011000 {
+ compatible = "st,stm32-usart";
+ reg = <0x40011000 0x400>;
+ interrupts = <37>;
+ clocks = <&clk_pclk2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart1>;
+
+ status = "disabled";
+ };
+
+ usart2: usart@40004400 {
+ compatible = "st,stm32-usart";
+ reg = <0x40004400 0x400>;
+ interrupts = <38>;
+ clocks = <&clk_pclk1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart1>;
+
+ status = "disabled";
+ };
+
+ usart3: usart@40004800 {
+ compatible = "st,stm32-usart";
+ reg = <0x40004800 0x400>;
+ interrupts = <39>;
+ clocks = <&clk_pclk1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart1>;
+
+ status = "disabled";
+ };
+
+ usart4: usart@40004c00 {
+ compatible = "st,stm32-usart";
+ reg = <0x40004c00 0x400>;
+ interrupts = <52>;
+ clocks = <&clk_pclk1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart1>;
+
+ status = "disabled";
+ };
+
+ usart5: usart@40005000 {
+ compatible = "st,stm32-usart";
+ reg = <0x40005000 0x400>;
+ interrupts = <53>;
+ clocks = <&clk_pclk1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart1>;
+
+ status = "disabled";
+ };
+
+ usart6: usart@40011400 {
+ compatible = "st,stm32-usart";
+ reg = <0x40011400 0x400>;
+ interrupts = <71>;
+ clocks = <&clk_pclk2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart1>;
+
+ status = "disabled";
+ };
+
+ usart7: usart@40007800 {
+ compatible = "st,stm32-usart";
+ reg = <0x40007800 0x400>;
+ interrupts = <82>;
+ clocks = <&clk_pclk1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart1>;
+
+ status = "disabled";
+ };
+
+ usart8: usart@40007c00 {
+ compatible = "st,stm32-usart";
+ reg = <0x40007c00 0x400>;
+ interrupts = <83>;
+ clocks = <&clk_pclk1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart1>;
+
+ status = "disabled";
+ };
+ };
+};
--
1.9.1
^ permalink raw reply related
* [PATCH v2 17/18] ARM: configs: Add STM32 defconfig
From: Maxime Coquelin @ 2015-02-20 18:01 UTC (permalink / raw)
To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
Jonathan Corbet, Maxime Coquelin, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
Arnd Bergmann, Andrew Morton, David S. Miller,
Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
Will
In-Reply-To: <1424455277-29983-1-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
This patch adds a new config for STM32 MCUs.
STM32F429 Discovery board boots successfully with this config applied.
Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
arch/arm/configs/stm32_defconfig | 72 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 72 insertions(+)
create mode 100644 arch/arm/configs/stm32_defconfig
diff --git a/arch/arm/configs/stm32_defconfig b/arch/arm/configs/stm32_defconfig
new file mode 100644
index 0000000..3d7802a
--- /dev/null
+++ b/arch/arm/configs/stm32_defconfig
@@ -0,0 +1,72 @@
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="./rootfs.cpio"
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_UID16 is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_MMU is not set
+CONFIG_ARCH_STM32=y
+CONFIG_SET_MEM_PARAM=y
+CONFIG_DRAM_BASE=0xd0000000
+CONFIG_FLASH_MEM_BASE=0x08000000
+CONFIG_FLASH_SIZE=0x00200000
+CONFIG_PREEMPT=y
+# CONFIG_ATAGS is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_XIP_KERNEL=y
+CONFIG_XIP_PHYS_ADDR=0x08020000
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_SHARED_FLAT=y
+# CONFIG_COREDUMP is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_BLK_DEV is not set
+CONFIG_EEPROM_93CX6=y
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_STM32=y
+CONFIG_SERIAL_STM32_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_GPIO_SYSFS=y
+# CONFIG_HWMON is not set
+CONFIG_USB=y
+CONFIG_USB_DWC2=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_IOMMU_SUPPORT is not set
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_FTRACE is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC7=y
--
1.9.1
^ permalink raw reply related
* [PATCH v2 18/18] MAINTAINERS: Add entry for STM32 MCUs
From: Maxime Coquelin @ 2015-02-20 18:01 UTC (permalink / raw)
To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
Jonathan Corbet, Maxime Coquelin, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
Arnd Bergmann, Andrew Morton, David S. Miller,
Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
Will
In-Reply-To: <1424455277-29983-1-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Add a MAINTAINER entry covering all STM32 machine and drivers files.
Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
MAINTAINERS | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index d66a97d..559cd45 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1448,6 +1448,13 @@ F: drivers/usb/host/ehci-st.c
F: drivers/usb/host/ohci-st.c
F: drivers/ata/ahci_st.c
+ARM/STM32 ARCHITECTURE
+M: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+L: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org (moderated for non-subscribers)
+S: Maintained
+N: stm32
+F: drivers/clocksource/armv7m_systick.c
+
ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
M: Lennert Buytenhek <kernel-OLH4Qvv75CYX/NnBR394Jw@public.gmane.org>
L: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org (moderated for non-subscribers)
--
1.9.1
^ permalink raw reply related
* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
From: Srinivas Kandagatla @ 2015-02-20 19:00 UTC (permalink / raw)
To: Russell King - ARM Linux
Cc: linux-arm-kernel, devicetree, Arnd Bergmann, Pawel Moll,
Greg Kroah-Hartman, linux-api, broonie, Stephen Boyd,
linux-kernel, Rob Herring, Kumar Gala, Maxime Ripard
In-Reply-To: <20150220174641.GI8656@n2100.arm.linux.org.uk>
On 20/02/15 17:46, Russell King - ARM Linux wrote:
> On Thu, Feb 19, 2015 at 05:08:28PM +0000, Srinivas Kandagatla wrote:
>> +static struct class eeprom_class = {
>> + .name = "eeprom",
>> + .dev_groups = eeprom_dev_groups,
>> +};
>> +
>> +int eeprom_register(struct eeprom_device *eeprom)
>> +{
>> + int rval;
>> +
>> + if (!eeprom->regmap || !eeprom->size) {
>> + dev_err(eeprom->dev, "Regmap not found\n");
>> + return -EINVAL;
>> + }
>> +
>> + eeprom->id = ida_simple_get(&eeprom_ida, 0, 0, GFP_KERNEL);
>> + if (eeprom->id < 0)
>> + return eeprom->id;
>> +
>> + eeprom->edev.class = &eeprom_class;
>> + eeprom->edev.parent = eeprom->dev;
>> + eeprom->edev.of_node = eeprom->dev ? eeprom->dev->of_node : NULL;
>> + dev_set_name(&eeprom->edev, "eeprom%d", eeprom->id);
>> +
>> + device_initialize(&eeprom->edev);
>> +
>> + dev_dbg(&eeprom->edev, "Registering eeprom device %s\n",
>> + dev_name(&eeprom->edev));
>> +
>> + rval = device_add(&eeprom->edev);
>> + if (rval)
>> + return rval;
>> +
>> + mutex_lock(&eeprom_list_mutex);
>> + list_add(&eeprom->list, &eeprom_list);
>> + mutex_unlock(&eeprom_list_mutex);
>> +
>> + return 0;
>> +}
>> +EXPORT_SYMBOL(eeprom_register);
>> +
>> +int eeprom_unregister(struct eeprom_device *eeprom)
>> +{
>> + device_del(&eeprom->edev);
>> +
>> + mutex_lock(&eeprom_list_mutex);
>> + list_del(&eeprom->list);
>> + mutex_unlock(&eeprom_list_mutex);
>> +
>> + return 0;
>
> There's problems with this. "edev" is embedded into eeprom, and "edev"
> is a refcounted structure - it has a lifetime, and the lifetime of
> eeprom is thus determined by edev.
>
> What this means is that calling eeprom_unregister() and then freeing
> the eeprom structure is a potentially unsafe operation - the memory
> backing edev must only be freed when the release method for the
> struct device has been called.
Thats a good catch, Yes I see the issue.
Moving the struct eeprom_device allocation to eeprom core.c should
address this issue. This makes eeprom self contained and can safely free
the eeprom_device memory in eeprom_class.eeprom_release().
Will fix this in next version.
>
>> +struct eeprom_device {
>> + struct regmap *regmap;
>> + int stride;
>> + size_t size;
>> + struct device *dev;
>
> Failing to understand and address the driver model life time issues is
> a major blocker for this patch. Sorry.
>
^ permalink raw reply
* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
From: Srinivas Kandagatla @ 2015-02-20 19:25 UTC (permalink / raw)
To: Rob Herring
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala,
linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Stephen Boyd,
Arnd Bergmann, Mark Brown, Greg Kroah-Hartman
In-Reply-To: <CAL_Jsq+SeuoojgTpv1y_aPJ_jzDr3HqZhYEBQ3_vYGBHvcccug-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On 20/02/15 17:21, Rob Herring wrote:
> On Thu, Feb 19, 2015 at 11:08 AM, Srinivas Kandagatla
> <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
>> From: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
>>
>> Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
>> duplicate pretty much the same code to register a sysfs file, allow in-kernel
>> users to access the content of the devices they were driving, etc.
>>
>> This was also a problem as far as other in-kernel users were involved, since
>> the solutions used were pretty much different from on driver to another, there
>> was a rather big abstraction leak.
>>
>> This introduction of this framework aims at solving this. It also introduces DT
>> representation for consumer devices to go get the data they require (MAC
>> Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.
>>
>> Having regmap interface to this framework would give much better
>> abstraction for eeproms on different buses.
>>
>> Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
>> [srinivas.kandagatla: Moved to regmap based and cleanedup apis]
>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>> ---
>> .../devicetree/bindings/eeprom/eeprom.txt | 48 ++++
>> drivers/Kconfig | 2 +
>> drivers/Makefile | 1 +
>> drivers/eeprom/Kconfig | 19 ++
>> drivers/eeprom/Makefile | 9 +
>> drivers/eeprom/core.c | 290 +++++++++++++++++++++
>> include/linux/eeprom-consumer.h | 73 ++++++
>> include/linux/eeprom-provider.h | 51 ++++
>
> Who is going to be the maintainer for this?
Am happy to be one.
>
>> 8 files changed, 493 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
>> create mode 100644 drivers/eeprom/Kconfig
>> create mode 100644 drivers/eeprom/Makefile
>> create mode 100644 drivers/eeprom/core.c
>> create mode 100644 include/linux/eeprom-consumer.h
>> create mode 100644 include/linux/eeprom-provider.h
>>
>> diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
>> new file mode 100644
>> index 0000000..9ec1ec2
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
>
> Please make bindings a separate patch.
Sure, Will do it in next version.
>
>> @@ -0,0 +1,48 @@
>> += EEPROM Data Device Tree Bindings =
>> +
>> +This binding is intended to represent the location of hardware
>> +configuration data stored in EEPROMs.
>> +
>> +On a significant proportion of boards, the manufacturer has stored
>> +some data on an EEPROM-like device, for the OS to be able to retrieve
>> +these information and act upon it. Obviously, the OS has to know
>> +about where to retrieve these data from, and where they are stored on
>> +the storage device.
>> +
>> +This document is here to document this.
>> +
>> += Data providers =
>> +
>> +Required properties:
>> +#eeprom-cells: Number of cells in an eeprom specifier; The common
>> + case is 2.
>
> We already have eeproms in DTs, it would be nice to be able to support
> them with this framework as well.
Yes, I can see more than 60% of them are atmel,at24* eeproms in DT. We
have some plans to migrate at24 and at25 eeproms to this framework once
the the framework itself is accepted.
>
>> +
>> +For example:
>> +
>> + at24: eeprom@42 {
>> + #eeprom-cells = <2>;
>> + };
>> +
>> += Data consumers =
>> +
>> +Required properties:
>> +
>> +eeproms: List of phandle and data cell specifier triplet, one triplet
>> + for each data cell the device might be interested in. The
>> + triplet consists of the phandle to the eeprom provider, then
>> + the offset in byte within that storage device, and the length
>> + in byte of the data we care about.
>
> The problem with this is it assumes you know who the consumer is and
> that it is a DT node. For example, how would you describe a serial
> number?
Correct me if I miss understood.
Is serial number any different?
Am hoping that the eeprom consumer would be aware of offset and size of
serial number in the eeprom
Cant the consumer do:
eeprom-consumer {
eeproms = <&at24 0 4>;
eeprom-names = "device-serial-number";
};
--srini
>
> Rob
>
^ permalink raw reply
* Re: [PATCH v2 02/18] ARM: ARMv7M: Enlarge vector table to 256 entries
From: Uwe Kleine-König @ 2015-02-20 19:47 UTC (permalink / raw)
To: Maxime Coquelin
Cc: afaerber, geert, Rob Herring, Philipp Zabel, Jonathan Corbet,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
Daniel Lezcano, Thomas Gleixner, Linus Walleij,
Greg Kroah-Hartman, Jiri Slaby, Arnd Bergmann, Andrew Morton,
David S. Miller, Mauro Carvalho Chehab, Joe Perches,
Antti Palosaari, Tejun Heo, Will Deacon, Nikolay Borisov, Rust
In-Reply-To: <1424455277-29983-3-git-send-email-mcoquelin.stm32@gmail.com>
On Fri, Feb 20, 2015 at 07:01:01PM +0100, Maxime Coquelin wrote:
> From Cortex-M reference manuals, the nvic supports up to 240 interrupts.
> So the number of entries in vectors table is up to 256.
>
> This patch adds a new config flag to specify the number of external interrupts.
> Some ifdeferies are added in order to respect the natural alignment without
> wasting too much space on smaller systems.
>
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
> arch/arm/kernel/entry-v7m.S | 13 +++++++++----
> arch/arm/mm/Kconfig | 15 +++++++++++++++
> 2 files changed, 24 insertions(+), 4 deletions(-)
>
> diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S
> index 8944f49..68cde36 100644
> --- a/arch/arm/kernel/entry-v7m.S
> +++ b/arch/arm/kernel/entry-v7m.S
> @@ -117,9 +117,14 @@ ENTRY(__switch_to)
> ENDPROC(__switch_to)
>
> .data
> - .align 8
> +#if CONFIG_CPUV7M_NUM_IRQ <= 112
I would have called this CONFIG_CPU_V7M_NUM_IRQ to match the already
existing CPU_V7M symbol.
> + .align 9
> +#else
> + .align 10
> +#endif
> +
Other than that:
Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Who do you target to apply this series?
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-König |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply
* Re: [PATCH v2 04/18] clocksource: Add ARM System timer driver
From: Uwe Kleine-König @ 2015-02-20 19:54 UTC (permalink / raw)
To: Maxime Coquelin
Cc: afaerber, geert, Rob Herring, Philipp Zabel, Jonathan Corbet,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
Daniel Lezcano, Thomas Gleixner, Linus Walleij,
Greg Kroah-Hartman, Jiri Slaby, Arnd Bergmann, Andrew Morton,
David S. Miller, Mauro Carvalho Chehab, Joe Perches,
Antti Palosaari, Tejun Heo, Will Deacon, Nikolay Borisov, Rust
In-Reply-To: <1424455277-29983-5-git-send-email-mcoquelin.stm32@gmail.com>
Hello,
On Fri, Feb 20, 2015 at 07:01:03PM +0100, Maxime Coquelin wrote:
> This patch adds clocksource support for ARMv7-M's System timer,
> also known as SysTick.
>
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
> drivers/clocksource/Kconfig | 7 ++++
> drivers/clocksource/Makefile | 1 +
> drivers/clocksource/armv7m_systick.c | 78 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 86 insertions(+)
> create mode 100644 drivers/clocksource/armv7m_systick.c
>
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index fc01ec2..fb6011e 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -124,6 +124,13 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
> help
> Use ARM global timer clock source as sched_clock
>
> +config ARMV7M_SYSTICK
> + bool
I assume this symbol is enabled later in the series. Would it make sense
to allow enabing the symbol for compile test coverage?
> + select CLKSRC_OF if OF
What happens if ARMV7M_SYSTICK=y but OF=n? Doesn't the driver fail to
compile?
> + select CLKSRC_MMIO
> + help
> + This options enables support for the ARMv7M system timer unit
the right spelling is ARMv7-M.
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-König |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply
* Re: [PATCH v2 14/18] ARM: Add STM32 family machine
From: Uwe Kleine-König @ 2015-02-20 20:00 UTC (permalink / raw)
To: Maxime Coquelin
Cc: afaerber, geert, Rob Herring, Philipp Zabel, Jonathan Corbet,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Russell King,
Daniel Lezcano, Thomas Gleixner, Linus Walleij,
Greg Kroah-Hartman, Jiri Slaby, Arnd Bergmann, Andrew Morton,
David S. Miller, Mauro Carvalho Chehab, Joe Perches,
Antti Palosaari, Tejun Heo, Will Deacon, Nikolay Borisov, Rust
In-Reply-To: <1424455277-29983-15-git-send-email-mcoquelin.stm32@gmail.com>
Hello,
On Fri, Feb 20, 2015 at 07:01:13PM +0100, Maxime Coquelin wrote:
> STMicrolectronics's STM32 series is a family of Cortex-M
> microcontrollers. It is used in various applications, and
> proposes a wide range of peripherals.
>
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> ---
> Documentation/arm/stm32/overview.txt | 32 ++++++++++++++++++++++++++
> Documentation/arm/stm32/stm32f429-overview.txt | 22 ++++++++++++++++++
> arch/arm/Kconfig | 22 ++++++++++++++++++
> arch/arm/Makefile | 1 +
> arch/arm/mach-stm32/Makefile | 1 +
> arch/arm/mach-stm32/Makefile.boot | 0
> arch/arm/mach-stm32/board-dt.c | 31 +++++++++++++++++++++++++
> 7 files changed, 109 insertions(+)
> create mode 100644 Documentation/arm/stm32/overview.txt
> create mode 100644 Documentation/arm/stm32/stm32f429-overview.txt
> create mode 100644 arch/arm/mach-stm32/Makefile
> create mode 100644 arch/arm/mach-stm32/Makefile.boot
> create mode 100644 arch/arm/mach-stm32/board-dt.c
>
> diff --git a/Documentation/arm/stm32/overview.txt b/Documentation/arm/stm32/overview.txt
> new file mode 100644
> index 0000000..d8bf6bb
> --- /dev/null
> +++ b/Documentation/arm/stm32/overview.txt
> @@ -0,0 +1,32 @@
> + STM32 ARM Linux Overview
> + ==========================
> +
> +Introduction
> +------------
> +
> + The STMicroelectronics family of Cortex-M based MCUs are supported by the
> + 'STM32' platform of ARM Linux. Currently only the STM32F429 is supported.
> +
> +
> +Configuration
> +-------------
> +
> + A generic configuration is provided for STM32 family, and can be used as the
> + default by
> + make stm32_defconfig
> +
> +Layout
> +------
> +
> + All the files for multiple machine families are located in the platform code
> + contained in arch/arm/mach-stm32
> +
> + There is a generic board board-dt.c in the mach folder which support
> + Flattened Device Tree, which means, It works with any compatible board with
> + Device Trees.
> +
> +
> +Document Author
> +---------------
> +
> + Maxime Coquelin <mcoquelin.stm32@gmail.com>
> diff --git a/Documentation/arm/stm32/stm32f429-overview.txt b/Documentation/arm/stm32/stm32f429-overview.txt
> new file mode 100644
> index 0000000..5206822
> --- /dev/null
> +++ b/Documentation/arm/stm32/stm32f429-overview.txt
> @@ -0,0 +1,22 @@
> + STM32F429 Overview
> + ==================
> +
> + Introduction
> + ------------
> + The STM32F429 is a Cortex-M4 MCU aimed at various applications.
> + It features:
> + - ARM Cortex-M4 up to 180MHz with FPU
> + - 2MB internal Flash Memory
> + - External memory support through FMC controller (PSRAM, SDRAM, NOR, NAND)
> + - I2C, SPI, SAI, CAN, USB OTG, Ethernet controllers
> + - LCD controller & Camera interface
> + - Cryptographic processor
> +
> + Resources
> + ---------
> + Datasheet and reference manual are publicly available on ST website:
> + - http://www.st.com/web/en/catalog/mmc/FM141/SC1169/SS1577/LN1806?ecmp=stm32f429-439_pron_pr-ces2014_nov2013
> +
> + Document Author
> + ---------------
> + Maxime Coquelin <mcoquelin.stm32@gmail.com>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 97d07ed..cfd9532 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -774,6 +774,28 @@ config ARCH_OMAP1
> help
> Support for older TI OMAP1 (omap7xx, omap15xx or omap16xx)
>
> +config ARCH_STM32
> + bool "STMicrolectronics STM32"
> + depends on !MMU
> + select ARCH_REQUIRE_GPIOLIB
> + select ARM_NVIC
> + select AUTO_ZRELADDR
> + select ARCH_HAS_RESET_CONTROLLER
> + select RESET_CONTROLLER
> + select PINCTRL
> + select PINCTRL_STM32
> + select CLKSRC_OF
> + select ARMV7M_SYSTICK
> + select COMMON_CLK
> + select CPU_V7M
> + select GENERIC_CLOCKEVENTS
> + select NO_DMA
> + select NO_IOPORT_MAP
> + select SPARSE_IRQ
> + select USE_OF
Please sort this list alphabetically.
> + help
> + Support for STMicorelectronics STM32 processors.
> +
> endchoice
>
> menu "Multiple platform selection"
> diff --git a/arch/arm/Makefile b/arch/arm/Makefile
> index c1785ee..7d00659 100644
> --- a/arch/arm/Makefile
> +++ b/arch/arm/Makefile
> @@ -196,6 +196,7 @@ machine-$(CONFIG_ARCH_SHMOBILE) += shmobile
> machine-$(CONFIG_ARCH_SIRF) += prima2
> machine-$(CONFIG_ARCH_SOCFPGA) += socfpga
> machine-$(CONFIG_ARCH_STI) += sti
> +machine-$(CONFIG_ARCH_STM32) += stm32
> machine-$(CONFIG_ARCH_SUNXI) += sunxi
> machine-$(CONFIG_ARCH_TEGRA) += tegra
> machine-$(CONFIG_ARCH_U300) += u300
> diff --git a/arch/arm/mach-stm32/Makefile b/arch/arm/mach-stm32/Makefile
> new file mode 100644
> index 0000000..bd0b7b5
> --- /dev/null
> +++ b/arch/arm/mach-stm32/Makefile
> @@ -0,0 +1 @@
> +obj-y += board-dt.o
> diff --git a/arch/arm/mach-stm32/Makefile.boot b/arch/arm/mach-stm32/Makefile.boot
> new file mode 100644
> index 0000000..e69de29
Maybe note there why this file exists and can be empty. Feel free to
copy the content of efm32's Makefile.boot.
> diff --git a/arch/arm/mach-stm32/board-dt.c b/arch/arm/mach-stm32/board-dt.c
> new file mode 100644
> index 0000000..1d681b3
> --- /dev/null
> +++ b/arch/arm/mach-stm32/board-dt.c
> @@ -0,0 +1,31 @@
> +/*
> + * Copyright (C) Maxime Coquelin 2015
> + * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> + * License terms: GNU General Public License (GPL), version 2
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/clk-provider.h>
> +#include <linux/clocksource.h>
> +#include <linux/reset-controller.h>
> +#include <asm/v7m.h>
> +#include <asm/mach/arch.h>
> +
> +static const char *const stm32_compat[] __initconst = {
> + "st,stm32f429",
> + NULL
> +};
> +
> +static void __init stm32_timer_init(void)
> +{
> + of_clk_init(NULL);
> + reset_controller_of_init();
> + clocksource_of_init();
Hmm, if reset_controller_of_init was called automatically you wouldn't
need that, right? Maybe arange for that instead?
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-König |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply
* Re: [PATCH 0/7] [RFC] kernel: add a netlink interface to get information about processes
From: Andy Lutomirski @ 2015-02-20 20:33 UTC (permalink / raw)
To: Andrew Vagin
Cc: Pavel Emelyanov, Roger Luethi, Oleg Nesterov, Cyrill Gorcunov,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Andrew Morton, Linux API, Andrey Vagin
In-Reply-To: <20150219213929.GA16250-yYYamFZzV1regbzhZkK2zA@public.gmane.org>
On Thu, Feb 19, 2015 at 1:39 PM, Andrew Vagin <avagin-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org> wrote:
> On Wed, Feb 18, 2015 at 05:18:38PM -0800, Andy Lutomirski wrote:
>> > > I don't suppose this could use real syscalls instead of netlink. If
>> > > nothing else, netlink seems to conflate pid and net namespaces.
>> >
>> > What do you mean by "conflate pid and net namespaces"?
>>
>> A netlink socket is bound to a network namespace, but you should be
>> returning data specific to a pid namespace.
>
> Here is a good question. When we mount a procfs instance, the current
> pidns is saved on a superblock. Then if we read data from
> this procfs from another pidns, we will see pid-s from the pidns where
> this procfs has been mounted.
>
> $ unshare -p -- bash -c '(bash)'
> $ cat /proc/self/status | grep ^Pid:
> Pid: 15770
> $ echo $$
> 1
>
> A similar situation with socket_diag. A socket_diag socket is bound to a
> network namespace. If we open a socket_diag socket and change a network
> namespace, it will return infromation about the initial netns.
>
> In this version I always use a current pid namespace.
> But to be consistant with other kernel logic, a socket diag has to be
> linked with a pidns where it has been created.
>
Attaching a pidns to every freshly created netlink socket seems odd,
but I don't see a better solution that still uses netlink.
>>
>> On a related note, how does this interact with hidepid? More
>
> Currently it always work as procfs with hidepid = 2 (highest level of
> security).
>
>> generally, what privileges are you requiring to obtain what data?
>
> It dumps information only if ptrace_may_access(tsk, PTRACE_MODE_READ) returns true
Sounds good to me.
>
>>
>> >
>> > >
>> > > Also, using an asynchronous interface (send, poll?, recv) for
>> > > something that's inherently synchronous (as the kernel a local
>> > > question) seems awkward to me.
>> >
>> > Actually all requests are handled synchronously. We call sendmsg to send
>> > a request and it is handled in this syscall.
>> > 2) | netlink_sendmsg() {
>> > 2) | netlink_unicast() {
>> > 2) | taskdiag_doit() {
>> > 2) 2.153 us | task_diag_fill();
>> > 2) | netlink_unicast() {
>> > 2) 0.185 us | netlink_attachskb();
>> > 2) 0.291 us | __netlink_sendskb();
>> > 2) 2.452 us | }
>> > 2) + 33.625 us | }
>> > 2) + 54.611 us | }
>> > 2) + 76.370 us | }
>> > 2) | netlink_recvmsg() {
>> > 2) 1.178 us | skb_recv_datagram();
>> > 2) + 46.953 us | }
>> >
>> > If we request information for a group of tasks (NLM_F_DUMP), a first
>> > portion of data is filled from the sendmsg syscall. And then when we read
>> > it, the kernel fills the next portion.
>> >
>> > 3) | netlink_sendmsg() {
>> > 3) | __netlink_dump_start() {
>> > 3) | netlink_dump() {
>> > 3) | taskdiag_dumpid() {
>> > 3) 0.685 us | task_diag_fill();
>> > ...
>> > 3) 0.224 us | task_diag_fill();
>> > 3) + 74.028 us | }
>> > 3) + 88.757 us | }
>> > 3) + 89.296 us | }
>> > 3) + 98.705 us | }
>> > 3) | netlink_recvmsg() {
>> > 3) | netlink_dump() {
>> > 3) | taskdiag_dumpid() {
>> > 3) 0.594 us | task_diag_fill();
>> > ...
>> > 3) 0.242 us | task_diag_fill();
>> > 3) + 60.634 us | }
>> > 3) + 72.803 us | }
>> > 3) + 88.005 us | }
>> > 3) | netlink_recvmsg() {
>> > 3) | netlink_dump() {
>> > 3) 2.403 us | taskdiag_dumpid();
>> > 3) + 26.236 us | }
>> > 3) + 40.522 us | }
>> > 0) + 20.407 us | netlink_recvmsg();
>> >
>> >
>> > netlink is really good for this type of tasks. It allows to create an
>> > extendable interface which can be easy customized for different needs.
>> >
>> > I don't think that we would want to create another similar interface
>> > just to be independent from network subsystem.
>>
>> I guess this is a bit streamy in that you ask one question and get
>> multiple answers.
>
> It's like seq_file in procfs. The kernel allocates a buffer then fills
> it, copies it into userspace, fills it again, ... repeats these actions.
> And we can read data from file by portions.
>
> Actually here is one more analogy. When we open a file in procfs,
> we sends a request to the kernel and a file path is a request body in
> this case. But in case of procfs, we can't construct requests, we only
> have a set of predefined requests.
Fair enough. Procfs is also a bit absurd and only makes sense because
it's compatible with lots of tools. In a totally sane world, I would
argue that you should issue one syscall asking questions about a bit
and you should get answers immediately.
--Andy
^ permalink raw reply
* Re: [PATCH v2 14/18] ARM: Add STM32 family machine
From: Paul Bolle @ 2015-02-20 21:37 UTC (permalink / raw)
To: Maxime Coquelin
Cc: Uwe Kleine-König, afaerber, geert, Rob Herring,
Philipp Zabel, Jonathan Corbet, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
Arnd Bergmann, Andrew Morton, David S. Miller,
Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo
In-Reply-To: <20150220200019.GU19388@pengutronix.de>
On Fri, 2015-02-20 at 21:00 +0100, Uwe Kleine-König wrote:
> On Fri, Feb 20, 2015 at 07:01:13PM +0100, Maxime Coquelin wrote:
> > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > index 97d07ed..cfd9532 100644
> > --- a/arch/arm/Kconfig
> > +++ b/arch/arm/Kconfig
> > @@ -774,6 +774,28 @@ config ARCH_OMAP1
> > help
> > Support for older TI OMAP1 (omap7xx, omap15xx or omap16xx)
> >
> > +config ARCH_STM32
> > + bool "STMicrolectronics STM32"
> > + depends on !MMU
> > + select ARCH_REQUIRE_GPIOLIB
> > + select ARM_NVIC
> > + select AUTO_ZRELADDR
> > + select ARCH_HAS_RESET_CONTROLLER
> > + select RESET_CONTROLLER
> > + select PINCTRL
> > + select PINCTRL_STM32
> > + select CLKSRC_OF
> > + select ARMV7M_SYSTICK
> > + select COMMON_CLK
> > + select CPU_V7M
> > + select GENERIC_CLOCKEVENTS
> > + select NO_DMA
> > + select NO_IOPORT_MAP
> > + select SPARSE_IRQ
> > + select USE_OF
> Please sort this list alphabetically.
And drop
select NO_DMA
You copied that from ARCH_EFM32, but it's pointless on arm (as arch/arm/
doesn't provide a NO_DMA Kconfig symbol).
I submitted a patch last year to drop it from ARCH_EFM32, which Uwe
Acked, but then nothing happened. I'm to blame, as I should have sent a
reminder.
> > + help
> > + Support for STMicorelectronics STM32 processors.
> > +
> > endchoice
> >
> > menu "Multiple platform selection"
Paul Bolle
^ permalink raw reply
* Re: [PATCH v2 04/18] clocksource: Add ARM System timer driver
From: Paul Bolle @ 2015-02-20 21:48 UTC (permalink / raw)
To: Uwe Kleine-König
Cc: Maxime Coquelin, afaerber, geert, Rob Herring, Philipp Zabel,
Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
Linus Walleij, Greg Kroah-Hartman, Jiri Slaby, Arnd Bergmann,
Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
Joe Perches, Antti Palosaari, Tejun Heo, Will Deacon, Nik
In-Reply-To: <20150220195437.GT19388@pengutronix.de>
On Fri, 2015-02-20 at 20:54 +0100, Uwe Kleine-König wrote:
> On Fri, Feb 20, 2015 at 07:01:03PM +0100, Maxime Coquelin wrote:
> > This patch adds clocksource support for ARMv7-M's System timer,
> > also known as SysTick.
> >
> > Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> > ---
> > drivers/clocksource/Kconfig | 7 ++++
> > drivers/clocksource/Makefile | 1 +
> > drivers/clocksource/armv7m_systick.c | 78 ++++++++++++++++++++++++++++++++++++
> > 3 files changed, 86 insertions(+)
> > create mode 100644 drivers/clocksource/armv7m_systick.c
> >
> > diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> > index fc01ec2..fb6011e 100644
> > --- a/drivers/clocksource/Kconfig
> > +++ b/drivers/clocksource/Kconfig
> > @@ -124,6 +124,13 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
> > help
> > Use ARM global timer clock source as sched_clock
> >
> > +config ARMV7M_SYSTICK
> > + bool
> I assume this symbol is enabled later in the series.
Yes, I noticed it was selected in 14/18 ("ARM: Add STM32 family
machine").
> Would it make sense
> to allow enabing the symbol for compile test coverage?
>
> > + select CLKSRC_OF if OF
> What happens if ARMV7M_SYSTICK=y but OF=n? Doesn't the driver fail to
> compile?
>
> > + select CLKSRC_MMIO
> > + help
> > + This options enables support for the ARMv7M system timer unit
> the right spelling is ARMv7-M.
This Kconfig entry has no prompt, so no one is going to see this text
during make *config. Perhaps this should be made a comment. In that case
the right spelling should still be used.
Thanks,
Paul Bolle
^ permalink raw reply
* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
From: Rob Herring @ 2015-02-20 22:01 UTC (permalink / raw)
To: Srinivas Kandagatla
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala,
linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Stephen Boyd,
Arnd Bergmann, Mark Brown, Greg Kroah-Hartman
In-Reply-To: <54E78A31.9020306-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
On Fri, Feb 20, 2015 at 1:25 PM, Srinivas Kandagatla
<srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
>
>
> On 20/02/15 17:21, Rob Herring wrote:
>>
>> On Thu, Feb 19, 2015 at 11:08 AM, Srinivas Kandagatla
>> <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
>>>
>>> From: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
>>>
>>> Up until now, EEPROM drivers were stored in drivers/misc, where they all
>>> had to
>>> duplicate pretty much the same code to register a sysfs file, allow
>>> in-kernel
>>> users to access the content of the devices they were driving, etc.
>>>
>>> This was also a problem as far as other in-kernel users were involved,
>>> since
>>> the solutions used were pretty much different from on driver to another,
>>> there
>>> was a rather big abstraction leak.
>>>
>>> This introduction of this framework aims at solving this. It also
>>> introduces DT
>>> representation for consumer devices to go get the data they require (MAC
>>> Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.
>>>
>>> Having regmap interface to this framework would give much better
>>> abstraction for eeproms on different buses.
>>>
>>> Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
>>> [srinivas.kandagatla: Moved to regmap based and cleanedup apis]
>>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>>> ---
>>> .../devicetree/bindings/eeprom/eeprom.txt | 48 ++++
>>> drivers/Kconfig | 2 +
>>> drivers/Makefile | 1 +
>>> drivers/eeprom/Kconfig | 19 ++
>>> drivers/eeprom/Makefile | 9 +
>>> drivers/eeprom/core.c | 290
>>> +++++++++++++++++++++
>>> include/linux/eeprom-consumer.h | 73 ++++++
>>> include/linux/eeprom-provider.h | 51 ++++
>>
>>
>> Who is going to be the maintainer for this?
>
>
> Am happy to be one.
So please add a MAINTAINERS entry.
[...]
>>> += Data consumers =
>>> +
>>> +Required properties:
>>> +
>>> +eeproms: List of phandle and data cell specifier triplet, one triplet
>>> + for each data cell the device might be interested in. The
>>> + triplet consists of the phandle to the eeprom provider, then
>>> + the offset in byte within that storage device, and the length
>>> + in byte of the data we care about.
>>
>>
>> The problem with this is it assumes you know who the consumer is and
>> that it is a DT node. For example, how would you describe a serial
>> number?
>
> Correct me if I miss understood.
> Is serial number any different?
> Am hoping that the eeprom consumer would be aware of offset and size of
> serial number in the eeprom
>
> Cant the consumer do:
>
> eeprom-consumer {
> eeproms = <&at24 0 4>;
> eeprom-names = "device-serial-number";
Yes, but who is "eeprom-consumer"? DT nodes generally describe a h/w
block, but it this case, the consumer depends on the OS, not the h/w.
I'm not saying you can't describe where things are, but I don't think
you should imply who is the consumer and doing so is unnecessarily
complicated.
Also, the layout of EEPROM is likely very much platform specific. Some
could have a more complex structure perhaps with key ids and linked
list structure.
I would do something more simple that is just a list of keys and their
location like this:
device-serial-number = <start size>;
key1 = <start size>;
key2 = <start size>;
Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: Documenting MS_LAZYTIME
From: Theodore Ts'o @ 2015-02-21 2:56 UTC (permalink / raw)
To: Eric Sandeen
Cc: Michael Kerrisk, Ext4 Developers List,
Linux btrfs Developers List, XFS Developers, linux-man,
Linux-Fsdevel, Linux API
In-Reply-To: <54E7578E.4090809@redhat.com>
On Fri, Feb 20, 2015 at 09:49:34AM -0600, Eric Sandeen wrote:
>
> > This mount option significantly reduces writes to the
> > inode table for workloads that perform frequent random
> > writes to preallocated files.
>
> This seems like an overly specific description of a single workload out
> of many which may benefit, but what do others think? "inode table" is also
> fairly extN-specific.
How about somethign like "This mount significantly reduces writes
needed to update the inode's timestamps, especially mtime and actime.
Examples of workloads where this could be a large win include frequent
random writes to preallocated files, as well as cases where the
MS_STRICTATIME mount option is enabled."?
(The advantage of MS_STRICTATIME | MS_LAZYTIME is that stat system
calls will return the correctly updated atime, but those atime updates
won't get flushed to disk unless the inode needs to be updated for
file system / data consistency reasons, or when the inode is pushed
out of memory, or when the file system is unmounted.)
- Ted
^ permalink raw reply
* Re: Documenting MS_LAZYTIME
From: Michael Kerrisk (man-pages) @ 2015-02-21 7:57 UTC (permalink / raw)
To: Eric Sandeen, Theodore Ts'o
Cc: linux-man, Linux API, XFS Developers, mtk.manpages, Linux-Fsdevel,
Ext4 Developers List, Linux btrfs Developers List
In-Reply-To: <54E7578E.4090809@redhat.com>
On 02/20/2015 04:49 PM, Eric Sandeen wrote:
> On 2/20/15 2:50 AM, Michael Kerrisk wrote:
>> Hello Ted,
>>
>> Based on your commit message 0ae45f63d4e, I I wrote the documentation
>> below for MS_LAZYTIME, to go into the mount(2) man page. Could you
>> please check it over and let me know if it's accurate. In particular,
>> I added pieces marked with "*" below that were not part of the commit
>> message and I'd like confirmation that they're accurate.
>>
>> Thanks,
>>
>> Michael
>>
>> [[
>> MS_LAZYTIME (since Linux 3.20)
>> Only update filetimes (atime, mtime, ctime) on the in-
>> memory version of the file inode. The on-disk time‐
>> stamps are updated only when:
>
> "filetimes" and "file inode" seems a bit awkward. How about:
>
>> MS_LAZYTIME (since Linux 3.20)
>> Reduce on-disk updates of inode timestamps (atime, mtime, ctime)
>> by maintaining these changes only in memory, unless:
>
> (maybe I'm bike-shedding too much, if so, sorry).
Nah it''s the good sort of bikeshedding ;-). "filetimes" was a wordo--I
meant "timestamps". I've taken your wording mostly.
>
>> (a) the inode needs to be updated for some change unre‐
>> lated to file timestamps;
>>
>> (b) the application employs fsync(2), syncfs(2), or
>> sync(2);
>>
>> (c) an undeleted inode is evicted from memory; or
>>
>> * (d) more than 24 hours have passed since the i-node was
>> * written to disk.
>
> Please don't use "i-node" - simply "inode" is much more common in the manpages
> AFAICT.
Yup, that was a typo. Fixed.
>> This mount option significantly reduces writes to the
>> inode table for workloads that perform frequent random
>> writes to preallocated files.
>
> This seems like an overly specific description of a single workload out
> of many which may benefit, but what do others think?
Fair enough. I reworded that to note it as an example.
> "inode table" is also fairly extN-specific.
I'll await further input on that point.
Now we have:
MS_LAZYTIME (since Linux 3.20)
Reduce on-disk updates of inode timestamps (atime,
mtime, ctime) by maintaining these changes only in mem‐
ory. The on-disk timestamps are updated only when:
(a) the inode needs to be updated for some change unre‐
lated to file timestamps;
(b) the application employs fsync(2), syncfs(2), or
sync(2);
(c) an undeleted inode is evicted from memory; or
(d) more than 24 hours have passed since the inode was
written to disk.
This mount option significantly reduces writes to the
inode table for some workloads (e.g., when performing
frequent random writes to preallocated files).
Cheers,
Michael
--
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply
* Re: [PATCH 1/2] proc.5: Document /proc/[pid]/setgroups
From: Michael Kerrisk (man-pages) @ 2015-02-21 7:57 UTC (permalink / raw)
To: Eric W. Biederman
Cc: linux-man, Kees Cook, Linux API, Linux Containers, Josh Triplett,
stable, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Kenton Varda, LSM, mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w,
Richard Weinberger, Casey Schaufler, Andrew Morton,
Andy Lutomirski
In-Reply-To: <54DCB059.2020305-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Hi Eric,
Ping!
Cheers,
Michael
On 02/12/2015 02:53 PM, Michael Kerrisk (man-pages) wrote:
> Hello Eric,
>
> On 02/11/2015 02:51 PM, Eric W. Biederman wrote:
>> "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com> writes:
>>
>>> Hi Eric,
>>>
>>> Ping!
>>>
>>> Cheers,
>>>
>>> Michael
>>
>> My apologies. You description wasn't wrong but it may be a bit
>> misleading, explanation below. You will have to figure out how to work
>> that into your proposed text.
>>
>>> On 2 February 2015 at 16:36, Michael Kerrisk (man-pages)
>>> <mtk.manpages@gmail.com> wrote:
>>>> [Adding Josh to CC in case he has anything to add.]
>>>>
>>>> On 12/12/2014 10:54 PM, Eric W. Biederman wrote:
>>>>>
>>>>> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
>>>>> ---
>>>>> man5/proc.5 | 15 +++++++++++++++
>>>>> 1 file changed, 15 insertions(+)
>>>>>
>>>>> diff --git a/man5/proc.5 b/man5/proc.5
>>>>> index 96077d0dd195..d661e8cfeac9 100644
>>>>> --- a/man5/proc.5
>>>>> +++ b/man5/proc.5
>>>>> @@ -1097,6 +1097,21 @@ are not available if the main thread has already terminated
>>>>> .\" Added in 2.6.9
>>>>> .\" CONFIG_SCHEDSTATS
>>>>> .TP
>>>>> +.IR /proc/[pid]/setgroups " (since Linux 3.19-rc1)"
>>>>> +This file reports
>>>>> +.BR allow
>>>>> +if the setgroups system call is allowed in the current user namespace.
>>>>> +This file reports
>>>>> +.BR deny
>>>>> +if the setgroups system call is not allowed in the current user namespace.
>>>>> +This file may be written to with values of
>>>>> +.BR allow
>>>>> +and
>>>>> +.BR deny
>>>>> +before
>>>>> +.IR /proc/[pid]/gid_map
>>>>> +is written to (enabling setgroups) in a user namespace.
>>>>> +.TP
>>>>> .IR /proc/[pid]/smaps " (since Linux 2.6.14)"
>>>>> This file shows memory consumption for each of the process's mappings.
>>>>> (The
>>>>
>>>> Hi Eric,
>>>>
>>>> Thanks for this patch. I applied it, and then tried to work in
>>>> quite a few other details gleaned from the source code and commit
>>>> message, and Jon Corbet's article at http://lwn.net/Articles/626665/.
>>>> Could you please let me know if the following is correct:
>>
>> It is close but it may be misleading.
>>
>>>> /proc/[pid]/setgroups (since Linux 3.19)
>>>> This file displays the string "allow" if processes in
>>>> the user namespace that contains the process pid are
>>>> permitted to employ the setgroups(2) system call, and
>>>> "deny" if setgroups(2) is not permitted in that user
>>>> namespace.
>>
>> With the caveat that when gid_map is not set that setgroups is also not
>> allowed.
>
> Okay -- Iadded that point.
>
>>>> A privileged process (one with the CAP_SYS_ADMIN capa‐
>>>> bility in the namespace) may write either of the strings
>>>> "allow" or "deny" to this file before writing a group ID
>>>> mapping for this user namespace to the file
>>>> /proc/[pid]/gid_map. Writing the string "deny" prevents
>>>> any process in the user namespace from employing set‐
>>>> groups(2).
>>
>> Or more succintly. You are allowed to write to /proc/[pid]/setgroups
>> when calling setgroups is not allowed because gid_map is unset. This
>> ensures we do not have any transitions from a state where setgroups
>> is allowed to a state where setgroups is denied. There are only
>> transitions from setgroups not-allowed to setgroups allowed.
>
> And I've worked in the above point, rewording a bit along the way.
> So, how does the following look (only the first two paragraphs have
> changed)?
>
> /proc/[pid]/setgroups (since Linux 3.19)
> This file displays the string "allow" if processes in
> the user namespace that contains the process pid are
> permitted to employ the setgroups(2) system call, and
> "deny" if setgroups(2) is not permitted in that user
> namespace. (Note, however, that calls to setgroups(2)
> are also not permitted if /proc/[pid]/gid_map has not
> yet been set.)
>
> A privileged process (one with the CAP_SYS_ADMIN capa‐
> bility in the namespace) may write either of the strings
> "allow" or "deny" to this file before writing a group ID
> mapping for this user namespace to the file
> /proc/[pid]/gid_map. Writing the string "deny" prevents
> any process in the user namespace from employing set‐
> groups(2). In other words, it is permitted to write to
> /proc/[pid]/setgroups so long as calling setgroups(2) is
> not allowed because /proc/[pid]gid_map has not been set.
> This ensures that a process cannot transition from a
> state where setgroups(2) is allowed to a state where
> setgroups(2) is denied; a process can only trabsition
> from setgroups(2) being disallowed to setgroups(2) being
> allowed.
>
> The default value of this file in the initial user
> namespace is "allow".
>
> Once /proc/[pid]/gid_map has been written to (which has
> the effect of enabling setgroups(2) in the user names‐
> pace), it is no longer possible to deny setgroups(2) by
> writing to /proc/[pid]/setgroups.
>
> A child user namespace inherits the /proc/[pid]/gid_map
> setting from its parent.
>
> If the setgroups file has the value "deny", then the
> setgroups(2) system call can't subsequently be reenabled
> (by writing "allow" to the file) in this user namespace.
> This restriction also propagates down to all child user
> namespaces of this user namespace.
>
> Cheers,
>
> Michael
>
>
>
--
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/
_______________________________________________
Containers mailing list
Containers@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/containers
^ permalink raw reply
* Re: [PATCH 2/2] ASoC: pcm512x: Allow independently overclocking PLL, DAC and DSP
From: Mark Brown @ 2015-02-21 9:33 UTC (permalink / raw)
To: Peter Rosin
Cc: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw, Peter Rosin, Liam Girdwood,
Jaroslav Kysela, Takashi Iwai, Lars-Peter Clausen,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1424120568-24648-4-git-send-email-peda-SamgB31n2u5IcsJQ0EH25Q@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 503 bytes --]
On Mon, Feb 16, 2015 at 10:02:48PM +0100, Peter Rosin wrote:
> From: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
>
> When using non-standard rates, a relatively small amount of overclocking
> can make a big difference to a number of cases.
This is all basically fine but I'm wondering why this is being
configured via sysfs and not via ALSA controls? It's going to be more
fiddly for people to have to work with both control methods when they
need to configure these things.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]
^ 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