2015-11-25 10:36:04

by Vladimir Murzin

[permalink] [raw]
Subject: [RFC PATCH 00/10] Support for Cortex-M Prototyping System

Hi,

This patch series provide the basic support for running ucLinux on V2M-MPS2
platform.

With these patches applied ucLinux can be run on both HW and FVP models
with Cortex-M3/M4/M7 configurations.

Board description:

http://infocenter.arm.com/help/topic/com.arm.doc.100112_0100_03_en/arm_versatile_express_cortex_m_prototyping_system_(v2m_mps2)_technical_reference_manual_100112_0100_03_en.pdf

Application notes (cover Cortex-M3/M4/M7):

http://infocenter.arm.com/help/topic/com.arm.doc.dai0385a/DAI0385A_cortex_m3_on_v2m_mps2.pdf
http://infocenter.arm.com/help/topic/com.arm.doc.dai0386a/DAI0386A_cortex_m4_on_v2m_mps2.pdf
http://infocenter.arm.com/help/topic/com.arm.doc.dai0399a/DAI0399A_cortex_m7_on_v2m_mps2.pdf
http://infocenter.arm.com/help/topic/com.arm.doc.dai0400a/DAI0400A_cortex_m7_on_v2m_mps2.pdf

Cortex-M System Design Kit (referenced as CMDK from documents above):

http://infocenter.arm.com/help/topic/com.arm.doc.ddi0479c/DDI0479C_cortex_m_system_design_kit_r1p0_trm.pdf

I'd be happy to hear any feedback/comments on this series!

Remain questions:

- Application notes 399/400 have PSRAM located at address different to what
we have for AN385/AN386, so I'm wondering what is the best practice to handle
CONFIG_DRAM_BASE? Different defconfig or there is better place?

- I'm not sure about naming of dts files: Application Notes (mps2-an*) vs Cortex-M (mps2-cm*);
any preference?

P.S.

This series is against 4.4-rc1.

Thanks!

Vladimir Murzin (10):
dt-bindings: document the MPS2 timer bindings
clockevents/drivers: add MPS2 Timer driver
dt-bindings: document the MPS2 UART bindings
serial: mps2-uart: add MPS2 UART driver
serial: mps2-uart: add support for early console
ARM: mps2: introduce MPS2 platform
ARM: mps2: add low-level debug support
ARM: configs: add MPS2 defconfig
ARM: dts: introduce MPS2 AN385/AN386
ARM: dts: introduce MPS2 AN399/AN400

.../devicetree/bindings/serial/arm,mps2-uart.txt | 22 +
.../devicetree/bindings/timer/arm,mps2-timer.txt | 28 +
arch/arm/Kconfig | 8 +
arch/arm/Kconfig.debug | 12 +-
arch/arm/Makefile | 1 +
arch/arm/boot/dts/Makefile | 3 +
arch/arm/boot/dts/mps2-an385.dts | 90 +++
arch/arm/boot/dts/mps2-an399.dts | 92 +++
arch/arm/boot/dts/mps2.dtsi | 227 +++++++
arch/arm/configs/mps2_defconfig | 112 ++++
arch/arm/include/debug/mps2.S | 27 +
arch/arm/mach-mps2/Makefile | 1 +
arch/arm/mach-mps2/Makefile.boot | 3 +
arch/arm/mach-mps2/dtmachine.c | 21 +
drivers/clocksource/Kconfig | 5 +
drivers/clocksource/Makefile | 1 +
drivers/clocksource/mps2-timer.c | 280 +++++++++
drivers/tty/serial/Kconfig | 13 +
drivers/tty/serial/Makefile | 1 +
drivers/tty/serial/mps2-uart.c | 626 ++++++++++++++++++++
include/uapi/linux/serial_core.h | 3 +
21 files changed, 1575 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/serial/arm,mps2-uart.txt
create mode 100644 Documentation/devicetree/bindings/timer/arm,mps2-timer.txt
create mode 100644 arch/arm/boot/dts/mps2-an385.dts
create mode 100644 arch/arm/boot/dts/mps2-an399.dts
create mode 100644 arch/arm/boot/dts/mps2.dtsi
create mode 100644 arch/arm/configs/mps2_defconfig
create mode 100644 arch/arm/include/debug/mps2.S
create mode 100644 arch/arm/mach-mps2/Makefile
create mode 100644 arch/arm/mach-mps2/Makefile.boot
create mode 100644 arch/arm/mach-mps2/dtmachine.c
create mode 100644 drivers/clocksource/mps2-timer.c
create mode 100644 drivers/tty/serial/mps2-uart.c

--
1.7.9.5


2015-11-25 10:36:08

by Vladimir Murzin

[permalink] [raw]
Subject: [RFC PATCH 01/10] dt-bindings: document the MPS2 timer bindings

This adds documentation of device tree bindings for the
timers found on ARM MPS2 platform.

Signed-off-by: Vladimir Murzin <[email protected]>
---
.../devicetree/bindings/timer/arm,mps2-timer.txt | 28 ++++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 Documentation/devicetree/bindings/timer/arm,mps2-timer.txt

diff --git a/Documentation/devicetree/bindings/timer/arm,mps2-timer.txt b/Documentation/devicetree/bindings/timer/arm,mps2-timer.txt
new file mode 100644
index 0000000..48f84d7
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/arm,mps2-timer.txt
@@ -0,0 +1,28 @@
+ARM MPS2 timer
+
+The MPS2 platform has simple general-purpose 32 bits timers.
+
+Required properties:
+- compatible : Should be "arm,mps2-timer"
+- reg : Address and length of the register set
+- interrupts : Reference to the timer interrupt
+
+Required clocking property, have to be one of:
+- clocks : The input clock of the timer
+- clock-frequency : The rate in HZ in input of the ARM MPS2 timer
+
+Examples:
+
+timer1: mps2-timer@40000000 {
+ compatible = "arm,mps2-timer";
+ reg = <0x40000000 0x1000>;
+ interrupts = <8>;
+ clocks = <&sysclk>;
+};
+
+timer2: mps2-timer@40001000 {
+ compatible = "arm,mps2-timer";
+ reg = <0x40001000 0x1000>;
+ interrupts = <9>;
+ clock-frequency = <25000000>;
+};
--
1.7.9.5

2015-11-25 10:36:13

by Vladimir Murzin

[permalink] [raw]
Subject: [RFC PATCH 02/10] clockevents/drivers: add MPS2 Timer driver

MPS2 platform has simple 32 bits general purpose countdown timers.

The driver uses the first detected timer as a clocksource and the rest
of the timers as a clockevent

Signed-off-by: Vladimir Murzin <[email protected]>
---
drivers/clocksource/Kconfig | 5 +
drivers/clocksource/Makefile | 1 +
drivers/clocksource/mps2-timer.c | 280 ++++++++++++++++++++++++++++++++++++++
3 files changed, 286 insertions(+)
create mode 100644 drivers/clocksource/mps2-timer.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 71cfdf7..552ab54 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -136,6 +136,11 @@ config CLKSRC_STM32
depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST)
select CLKSRC_MMIO

+config CLKSRC_MPS2
+ bool "Clocksource for MPS2 SoCs"
+ depends on OF && (ARM || COMPILE_TEST)
+ select CLKSRC_MMIO
+
config ARM_ARCH_TIMER
bool
select CLKSRC_OF if OF
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 56bd16e..7033b9c 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -39,6 +39,7 @@ 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_LPC32XX) += time-lpc32xx.o
+obj-$(CONFIG_CLKSRC_MPS2) += mps2-timer.o
obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o
obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o
obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o
diff --git a/drivers/clocksource/mps2-timer.c b/drivers/clocksource/mps2-timer.c
new file mode 100644
index 0000000..77befe2
--- /dev/null
+++ b/drivers/clocksource/mps2-timer.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2015 ARM Limited
+ *
+ * Author: Vladimir Murzin <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of_address.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/sched_clock.h>
+#include <linux/slab.h>
+
+#define TIMER_CTRL 0x0
+#define TIMER_CTRL_ENABLE BIT(0)
+#define TIMER_CTRL_IE BIT(3)
+
+#define TIMER_VALUE 0x4
+#define TIMER_RELOAD 0x8
+#define TIMER_INT 0xc
+
+struct clockevent_mps2 {
+ void __iomem *reg;
+ u32 clock_count_per_tick;
+ struct clock_event_device clkevt;
+};
+
+static void __iomem *sched_clock_base;
+
+static u64 notrace mps2_sched_read(void)
+{
+ return ~readl_relaxed(sched_clock_base + TIMER_VALUE);
+}
+
+
+static inline struct clockevent_mps2 *to_mps2_clkevt(struct clock_event_device *c)
+{
+ return container_of(c, struct clockevent_mps2, clkevt);
+}
+
+static void clockevent_mps2_writel(u32 val, struct clock_event_device *c, u32 offset)
+{
+ writel(val, to_mps2_clkevt(c)->reg + offset);
+}
+
+static int mps2_timer_shutdown(struct clock_event_device *ce)
+{
+ clockevent_mps2_writel(0, ce, TIMER_RELOAD);
+ clockevent_mps2_writel(0, ce, TIMER_CTRL);
+
+ return 0;
+}
+
+static int mps2_timer_set_next_event(unsigned long next, struct clock_event_device *ce)
+{
+ clockevent_mps2_writel(next, ce, TIMER_VALUE);
+ clockevent_mps2_writel(TIMER_CTRL_IE | TIMER_CTRL_ENABLE, ce, TIMER_CTRL);
+
+ return 0;
+}
+
+static int mps2_timer_set_periodic(struct clock_event_device *ce)
+{
+ u32 clock_count_per_tick = to_mps2_clkevt(ce)->clock_count_per_tick;
+
+ clockevent_mps2_writel(clock_count_per_tick, ce, TIMER_RELOAD);
+ clockevent_mps2_writel(clock_count_per_tick, ce, TIMER_VALUE);
+ clockevent_mps2_writel(TIMER_CTRL_IE | TIMER_CTRL_ENABLE, ce, TIMER_CTRL);
+
+ return 0;
+}
+
+static irqreturn_t mps2_timer_interrupt(int irq, void *dev_id)
+{
+ struct clockevent_mps2 *ce = dev_id;
+ u32 status = readl(ce->reg + TIMER_INT);
+
+ if (!status)
+ return IRQ_NONE;
+
+ writel(1, ce->reg + TIMER_INT);
+
+ ce->clkevt.event_handler(&ce->clkevt);
+
+ return IRQ_HANDLED;
+}
+
+static int __init mps2_clockevents_init(struct device_node *np)
+{
+ void __iomem *base;
+ struct clk *clk;
+ struct irqaction *ia;
+ struct clockevent_mps2 *ce;
+ u32 rate;
+ int irq, ret;
+ const char *name = "mps2-clkevt";
+
+ ret = of_property_read_u32(np, "clock-frequency", &rate);
+
+ if (ret) {
+ 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 clock for clockevent: %d\n", ret);
+ clk_put(clk);
+ goto err_clk_enable;
+ }
+
+ rate = clk_get_rate(clk);
+ }
+
+ base = of_iomap(np, 0);
+ if (!base) {
+ ret = -EADDRNOTAVAIL;
+ pr_err("failed to map register for clockevent: %d\n", ret);
+ goto err_iomap;
+ }
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (!irq) {
+ ret = -ENOENT;
+ pr_err("failed to get irq for clockevent: %d\n", ret);
+ goto err_get_irq;
+ }
+
+ ce = kzalloc(sizeof(struct clockevent_mps2), GFP_KERNEL);
+ if (!ce) {
+ ret = -ENOMEM;
+ pr_err("failed to allocate clockevent: %d\n", ret);
+ goto err_ce_alloc;
+ }
+
+ ce->reg = base;
+ ce->clock_count_per_tick = DIV_ROUND_CLOSEST(rate, HZ);
+ ce->clkevt.irq = irq;
+ ce->clkevt.name = name;
+ ce->clkevt.rating = 200;
+ ce->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+ ce->clkevt.cpumask = cpu_possible_mask;
+ ce->clkevt.set_state_shutdown = mps2_timer_shutdown,
+ ce->clkevt.set_state_periodic = mps2_timer_set_periodic,
+ ce->clkevt.set_state_oneshot = mps2_timer_shutdown,
+ ce->clkevt.set_next_event = mps2_timer_set_next_event;
+
+ ia = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
+ if (!ia) {
+ ret = -ENOMEM;
+ pr_err("failed to allocate irqaction: %d\n", ret);
+ goto err_ia_alloc;
+ }
+
+ ia->name = name;
+ ia->flags = IRQF_TIMER;
+ ia->handler = mps2_timer_interrupt;
+ ia->dev_id = ce;
+
+ writel(0, base + TIMER_CTRL);
+
+ ret = setup_irq(irq, ia);
+
+ if (ret) {
+ pr_err("failed to setup irq: %d\n", ret);
+ goto err_setup_irq;
+ }
+
+ clockevents_config_and_register(&ce->clkevt, rate, 0xf, 0xffffffff);
+
+ return 0;
+
+err_setup_irq:
+ kfree(ia);
+err_ia_alloc:
+ kfree(ce);
+err_ce_alloc:
+err_get_irq:
+ iounmap(base);
+err_iomap:
+ clk_disable_unprepare(clk);
+err_clk_enable:
+ clk_put(clk);
+err_clk_get:
+ return ret;
+}
+
+static int mps2_clocksource_init(struct device_node *np)
+{
+ void __iomem *base;
+ struct clk *clk;
+ u32 rate;
+ int ret;
+ const char *name = "mps2-clksrc";
+
+ ret = of_property_read_u32(np, "clock-frequency", &rate);
+
+ if (ret) {
+ clk = of_clk_get(np, 0);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ pr_err("failed to get clock for clocksource: %d\n", ret);
+ goto err_clk_get;
+ }
+
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ pr_err("failed to enable clock for clocksource: %d\n", ret);
+ clk_put(clk);
+ goto err_clk_enable;
+ }
+
+ rate = clk_get_rate(clk);
+ }
+
+ base = of_iomap(np, 0);
+ if (!base) {
+ ret = -EADDRNOTAVAIL;
+ pr_err("failed to map register for clocksource: %d\n", ret);
+ goto err_iomap;
+ }
+
+ writel(0, base + TIMER_CTRL);
+
+ writel(0xffffffff, base + TIMER_VALUE);
+ writel(0xffffffff, base + TIMER_RELOAD);
+
+ writel(TIMER_CTRL_ENABLE, base + TIMER_CTRL);
+
+ ret = clocksource_mmio_init(base + TIMER_VALUE, name,
+ rate, 200, 32,
+ clocksource_mmio_readl_down);
+ if (ret) {
+ pr_err("failed to init clocksource: %d\n", ret);
+ goto err_clocksource_init;
+ }
+
+ sched_clock_base = base;
+ sched_clock_register(mps2_sched_read, 32, rate);
+
+ return 0;
+
+err_clocksource_init:
+ iounmap(base);
+err_iomap:
+ clk_disable_unprepare(clk);
+err_clk_enable:
+ clk_put(clk);
+err_clk_get:
+ return ret;
+
+}
+
+static void __init mps2_timer_init(struct device_node *np)
+{
+ static int clksrc;
+
+ if (!clksrc && !mps2_clocksource_init(np))
+ clksrc = 1;
+ else
+ mps2_clockevents_init(np);
+}
+
+CLOCKSOURCE_OF_DECLARE(mps2_timer, "arm,mps2-timer", mps2_timer_init);
--
1.7.9.5

2015-11-25 10:38:52

by Vladimir Murzin

[permalink] [raw]
Subject: [RFC PATCH 03/10] dt-bindings: document the MPS2 UART bindings

This adds documentation of device tree bindings for the
UART found on ARM MPS2 platform

Signed-off-by: Vladimir Murzin <[email protected]>
---
.../devicetree/bindings/serial/arm,mps2-uart.txt | 22 ++++++++++++++++++++
1 file changed, 22 insertions(+)
create mode 100644 Documentation/devicetree/bindings/serial/arm,mps2-uart.txt

diff --git a/Documentation/devicetree/bindings/serial/arm,mps2-uart.txt b/Documentation/devicetree/bindings/serial/arm,mps2-uart.txt
new file mode 100644
index 0000000..b3f7cb1
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/arm,mps2-uart.txt
@@ -0,0 +1,22 @@
+ARM MPS2 UART
+
+Required properties:
+- compatible : Should be "arm,mps2-uart"
+- reg : Address and length of the register set
+- interrupts : Reference to the UART RX, TX and overrun interrupts
+
+Required clocking property:
+- clocks : The input clock of the UART
+
+
+Examples:
+
+uart0: serial@40004000 {
+ compatible = "arm,mps2-uart";
+ reg = <0x40004000 0x1000>;
+ interrupts = <0 1 12>;
+ clocks = <&sysclk>;
+};
+
+
+
--
1.7.9.5

2015-11-25 10:36:20

by Vladimir Murzin

[permalink] [raw]
Subject: [RFC PATCH 04/10] serial: mps2-uart: add MPS2 UART driver

This driver adds support to the UART controller found on ARM MPS2
platform.

Signed-off-by: Vladimir Murzin <[email protected]>
---
drivers/tty/serial/Kconfig | 12 +
drivers/tty/serial/Makefile | 1 +
drivers/tty/serial/mps2-uart.c | 596 ++++++++++++++++++++++++++++++++++++++
include/uapi/linux/serial_core.h | 3 +
4 files changed, 612 insertions(+)
create mode 100644 drivers/tty/serial/mps2-uart.c

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 1aec440..b47f8fc 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1473,6 +1473,18 @@ config SERIAL_EFM32_UART
This driver support the USART and UART ports on
Energy Micro's efm32 SoCs.

+config SERIAL_MPS2_UART_CONSOLE
+ bool "MPS2 UART console support"
+ depends on SERIAL_MPS2_UART
+ select SERIAL_CORE_CONSOLE
+
+config SERIAL_MPS2_UART
+ tristate "MPS2 UART port"
+ depends on ARM || COMPILE_TEST
+ select SERIAL_CORE
+ help
+ This driver support the UART ports on ARM MPS2.
+
config SERIAL_EFM32_UART_CONSOLE
bool "EFM32 UART/USART console support"
depends on SERIAL_EFM32_UART=y
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 5ab4111..7f589f5 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -93,6 +93,7 @@ obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR) += digicolor-usart.o
obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o
obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o
+obj-$(CONFIG_SERIAL_MPS2_UART) += mps2-uart.o

# GPIOLIB helpers for modem control lines
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/mps2-uart.c b/drivers/tty/serial/mps2-uart.c
new file mode 100644
index 0000000..00e882e
--- /dev/null
+++ b/drivers/tty/serial/mps2-uart.c
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2015 ARM Limited
+ *
+ * Author: Vladimir Murzin <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * TODO: support for SysRq
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/tty_flip.h>
+#include <linux/types.h>
+
+#define SERIAL_NAME "ttyMPS"
+#define DRIVER_NAME "mps2-uart"
+#define MAKE_NAME(x) (DRIVER_NAME # x)
+
+#define UARTn_DATA 0x0
+
+#define UARTn_STATE 0x4
+#define UARTn_STATE_TX_FULL BIT(0)
+#define UARTn_STATE_RX_FULL BIT(1)
+#define UARTn_STATE_TX_OVERRUN BIT(2)
+#define UARTn_STATE_RX_OVERRUN BIT(3)
+
+#define UARTn_CTRL 0x8
+#define UARTn_CTRL_TX_ENABLE BIT(0)
+#define UARTn_CTRL_RX_ENABLE BIT(1)
+#define UARTn_CTRL_TX_INT_ENABLE BIT(2)
+#define UARTn_CTRL_RX_INT_ENABLE BIT(3)
+#define UARTn_CTRL_TX_OVERRUN_INT_ENABLE BIT(4)
+#define UARTn_CTRL_RX_OVERRUN_INT_ENABLE BIT(5)
+
+#define UARTn_INT 0xc
+#define UARTn_INT_TX BIT(0)
+#define UARTn_INT_RX BIT(1)
+#define UARTn_INT_TX_OVERRUN BIT(2)
+#define UARTn_INT_RX_OVERRUN BIT(3)
+
+#define UARTn_BAUDDIV 0x10
+#define UARTn_BAUDDIV_MASK GENMASK(20, 0)
+
+#define MPS2_MAX_PORTS 3
+
+struct mps2_uart_port {
+ struct uart_port port;
+ struct clk *clk;
+ unsigned int tx_irq;
+ unsigned int rx_irq;
+};
+
+static inline struct mps2_uart_port *to_mps2_port(struct uart_port *port)
+{
+ return container_of(port, struct mps2_uart_port, port);
+}
+
+static void mps2_uart_write8(struct uart_port *port, u8 val, unsigned off)
+{
+ struct mps2_uart_port *mps_port = to_mps2_port(port);
+
+ writeb(val, mps_port->port.membase + off);
+}
+
+static u8 mps2_uart_read8(struct uart_port *port, unsigned off)
+{
+ struct mps2_uart_port *mps_port = to_mps2_port(port);
+
+ return readb(mps_port->port.membase + off);
+}
+
+static void mps2_uart_write32(struct uart_port *port, u32 val, unsigned off)
+{
+ struct mps2_uart_port *mps_port = to_mps2_port(port);
+
+ writel_relaxed(val, mps_port->port.membase + off);
+}
+
+static unsigned int mps2_uart_tx_empty(struct uart_port *port)
+{
+ u8 status = mps2_uart_read8(port, UARTn_STATE);
+
+ return (status & UARTn_STATE_TX_FULL) ? 0 : TIOCSER_TEMT;
+}
+
+static void mps2_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static unsigned int mps2_uart_get_mctrl(struct uart_port *port)
+{
+ return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR;
+}
+
+static void mps2_uart_stop_tx(struct uart_port *port)
+{
+ u8 control = mps2_uart_read8(port, UARTn_CTRL);
+
+ control &= ~(UARTn_CTRL_TX_ENABLE |
+ UARTn_CTRL_TX_INT_ENABLE |
+ UARTn_CTRL_TX_OVERRUN_INT_ENABLE);
+
+ mps2_uart_write8(port, control, UARTn_CTRL);
+}
+
+static void mps2_uart_tx_chars(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+
+ while (!(mps2_uart_read8(port, UARTn_STATE) & UARTn_STATE_TX_FULL)) {
+ if (port->x_char) {
+ mps2_uart_write8(port, port->x_char, UARTn_DATA);
+ port->x_char = 0;
+ port->icount.tx++;
+ continue;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+ break;
+
+ mps2_uart_write8(port, xmit->buf[xmit->tail], UARTn_DATA);
+ 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))
+ mps2_uart_stop_tx(port);
+}
+
+static void mps2_uart_start_tx(struct uart_port *port)
+{
+ u8 control = mps2_uart_read8(port, UARTn_CTRL);
+
+ control |= (UARTn_CTRL_TX_ENABLE |
+ UARTn_CTRL_TX_INT_ENABLE |
+ UARTn_CTRL_TX_OVERRUN_INT_ENABLE);
+
+ mps2_uart_write8(port, control, UARTn_CTRL);
+ mps2_uart_tx_chars(port);
+}
+
+static void mps2_uart_stop_rx(struct uart_port *port)
+{
+ u8 control = mps2_uart_read8(port, UARTn_CTRL);
+
+ control &= ~(UARTn_CTRL_RX_ENABLE |
+ UARTn_CTRL_RX_INT_ENABLE |
+ UARTn_CTRL_RX_OVERRUN_INT_ENABLE);
+
+ mps2_uart_write8(port, control, UARTn_CTRL);
+}
+
+static void mps2_uart_enable_ms(struct uart_port *port)
+{
+}
+
+static void mps2_uart_break_ctl(struct uart_port *port, int ctl)
+{
+}
+
+static void mps2_uart_rx_chars(struct uart_port *port)
+{
+ struct tty_port *tport = &port->state->port;
+
+ while (mps2_uart_read8(port, UARTn_STATE) & UARTn_STATE_RX_FULL) {
+ u8 rxdata = mps2_uart_read8(port, UARTn_DATA);
+
+ port->icount.rx++;
+ tty_insert_flip_char(&port->state->port, rxdata, TTY_NORMAL);
+ };
+
+ spin_unlock(&port->lock);
+ tty_flip_buffer_push(tport);
+ spin_lock(&port->lock);
+}
+
+static irqreturn_t mps2_uart_rxirq(int irq, void *data)
+{
+
+ struct uart_port *port = data;
+ u8 irqflag = mps2_uart_read8(port, UARTn_INT);
+
+ if (unlikely(!(irqflag & UARTn_INT_RX)))
+ return IRQ_NONE;
+
+ spin_lock(&port->lock);
+
+ mps2_uart_write8(port, UARTn_INT_RX, UARTn_INT);
+ mps2_uart_rx_chars(port);
+
+ spin_unlock(&port->lock);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mps2_uart_txirq(int irq, void *data)
+{
+ struct uart_port *port = data;
+ u8 irqflag = mps2_uart_read8(port, UARTn_INT);
+
+ if (unlikely(!(irqflag & UARTn_INT_TX)))
+ return IRQ_NONE;
+
+ mps2_uart_write8(port, UARTn_INT_TX, UARTn_INT);
+ mps2_uart_tx_chars(port);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mps2_uart_oerrirq(int irq, void *data)
+{
+ irqreturn_t handled = IRQ_NONE;
+ struct uart_port *port = data;
+ u8 irqflag = mps2_uart_read8(port, UARTn_INT);
+
+ spin_lock(&port->lock);
+
+ if (irqflag & UARTn_INT_RX_OVERRUN) {
+ struct tty_port *tport = &port->state->port;
+
+ mps2_uart_write8(port, UARTn_INT_RX_OVERRUN, UARTn_INT);
+ tty_insert_flip_char(tport, 0, TTY_OVERRUN);
+ port->icount.overrun++;
+ handled = IRQ_HANDLED;
+ }
+
+ /* XXX: this shouldn't happen? */
+ if (irqflag & UARTn_INT_TX_OVERRUN) {
+ mps2_uart_write8(port, UARTn_INT_TX_OVERRUN, UARTn_INT);
+ handled = IRQ_HANDLED;
+ }
+
+ spin_unlock(&port->lock);
+
+ return handled;
+}
+
+static int mps2_uart_startup(struct uart_port *port)
+{
+ struct mps2_uart_port *mps_port = to_mps2_port(port);
+ u8 control = mps2_uart_read8(port, UARTn_CTRL);
+ int ret;
+
+ control &= ~(UARTn_CTRL_RX_ENABLE |
+ UARTn_CTRL_TX_ENABLE |
+ UARTn_CTRL_RX_INT_ENABLE |
+ UARTn_CTRL_TX_INT_ENABLE |
+ UARTn_CTRL_RX_OVERRUN_INT_ENABLE |
+ UARTn_CTRL_TX_OVERRUN_INT_ENABLE);
+
+ mps2_uart_write8(port, control, UARTn_CTRL);
+
+ ret = request_irq(mps_port->rx_irq, mps2_uart_rxirq, 0,
+ MAKE_NAME(-rx), mps_port);
+ if (ret) {
+ pr_info("failed to register rxirq (%d)\n", ret);
+ goto err_no_rxirq;
+ }
+
+ ret = request_irq(mps_port->tx_irq, mps2_uart_txirq, 0,
+ MAKE_NAME(-tx), mps_port);
+ if (ret) {
+ pr_info("failed to register txirq (%d)\n", ret);
+ goto err_no_txirq;
+ }
+
+ ret = request_irq(port->irq, mps2_uart_oerrirq, IRQF_SHARED,
+ MAKE_NAME(-overrun), mps_port);
+
+ if (ret)
+ pr_info("failed to register oerrirq (%d)\n", ret);
+ else {
+ control |= UARTn_CTRL_RX_ENABLE |
+ UARTn_CTRL_TX_ENABLE |
+ UARTn_CTRL_RX_INT_ENABLE |
+ UARTn_CTRL_TX_INT_ENABLE |
+ UARTn_CTRL_RX_OVERRUN_INT_ENABLE |
+ UARTn_CTRL_TX_OVERRUN_INT_ENABLE;
+
+ mps2_uart_write8(port, control, UARTn_CTRL);
+
+ return 0;
+ }
+
+ free_irq(mps_port->tx_irq, mps_port);
+err_no_txirq:
+ free_irq(mps_port->rx_irq, mps_port);
+err_no_rxirq:
+ return ret;
+}
+
+static void mps2_uart_shutdown(struct uart_port *port)
+{
+ struct mps2_uart_port *mps_port = to_mps2_port(port);
+ u8 control = mps2_uart_read8(port, UARTn_CTRL);
+
+ control &= ~(UARTn_CTRL_RX_ENABLE |
+ UARTn_CTRL_TX_ENABLE |
+ UARTn_CTRL_RX_INT_ENABLE |
+ UARTn_CTRL_TX_INT_ENABLE |
+ UARTn_CTRL_RX_OVERRUN_INT_ENABLE |
+ UARTn_CTRL_TX_OVERRUN_INT_ENABLE);
+
+ mps2_uart_write8(port, control, UARTn_CTRL);
+
+ free_irq(mps_port->rx_irq, mps_port);
+ free_irq(mps_port->tx_irq, mps_port);
+ free_irq(port->irq, mps_port);
+}
+
+static void mps2_uart_set_termios(struct uart_port *port,
+ struct ktermios *new, struct ktermios *old)
+{
+ unsigned long flags;
+ unsigned int baud, bauddiv;
+
+ new->c_cflag &= ~(CRTSCTS | CMSPAR);
+ new->c_cflag &= ~CSIZE;
+ new->c_cflag |= CS8;
+ new->c_cflag &= ~PARENB;
+ new->c_cflag &= ~CSTOPB;
+
+ baud = uart_get_baud_rate(port, new, old,
+ DIV_ROUND_CLOSEST(port->uartclk, UARTn_BAUDDIV_MASK),
+ DIV_ROUND_CLOSEST(port->uartclk, 16));
+
+ bauddiv = DIV_ROUND_CLOSEST(port->uartclk, baud);
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ uart_update_timeout(port, new->c_cflag, baud);
+ mps2_uart_write32(port, bauddiv, UARTn_BAUDDIV);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *mps2_uart_type(struct uart_port *port)
+{
+ return (port->type == PORT_MPS2UART) ? DRIVER_NAME : NULL;
+}
+
+static void mps2_uart_release_port(struct uart_port *port)
+{
+}
+
+static int mps2_uart_request_port(struct uart_port *port)
+{
+ return 0;
+}
+
+static void mps2_uart_config_port(struct uart_port *port, int type)
+{
+ if (type & UART_CONFIG_TYPE && !mps2_uart_request_port(port))
+ port->type = PORT_MPS2UART;
+}
+
+static int mps2_uart_verify_port(struct uart_port *port, struct serial_struct *serinfo)
+{
+ return -EINVAL;
+}
+
+static const struct uart_ops mps2_uart_pops = {
+ .tx_empty = mps2_uart_tx_empty,
+ .set_mctrl = mps2_uart_set_mctrl,
+ .get_mctrl = mps2_uart_get_mctrl,
+ .stop_tx = mps2_uart_stop_tx,
+ .start_tx = mps2_uart_start_tx,
+ .stop_rx = mps2_uart_stop_rx,
+ .enable_ms = mps2_uart_enable_ms,
+ .break_ctl = mps2_uart_break_ctl,
+ .startup = mps2_uart_startup,
+ .shutdown = mps2_uart_shutdown,
+ .set_termios = mps2_uart_set_termios,
+ .type = mps2_uart_type,
+ .release_port = mps2_uart_release_port,
+ .request_port = mps2_uart_request_port,
+ .config_port = mps2_uart_config_port,
+ .verify_port = mps2_uart_verify_port,
+};
+
+static struct mps2_uart_port mps2_uart_ports[MPS2_MAX_PORTS];
+
+#ifdef CONFIG_SERIAL_MPS2_UART_CONSOLE
+static void mps2_uart_console_putchar(struct uart_port *port, int ch)
+{
+ while (mps2_uart_read8(port, UARTn_STATE) & UARTn_STATE_TX_FULL)
+ cpu_relax();
+
+ mps2_uart_write8(port, ch, UARTn_DATA);
+}
+
+static void mps2_uart_console_write(struct console *co, const char *s, unsigned int cnt)
+{
+ struct uart_port *port = &mps2_uart_ports[co->index].port;
+
+ uart_console_write(port, s, cnt, mps2_uart_console_putchar);
+}
+
+static int mps2_uart_console_setup(struct console *co, char *options)
+{
+ struct mps2_uart_port *mps_port;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (co->index < 0 || co->index >= MPS2_MAX_PORTS)
+ return -ENODEV;
+
+ mps_port = &mps2_uart_ports[co->index];
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(&mps_port->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver mps2_uart_driver;
+
+static struct console mps2_uart_console = {
+ .name = SERIAL_NAME,
+ .device = uart_console_device,
+ .write = mps2_uart_console_write,
+ .setup = mps2_uart_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &mps2_uart_driver,
+};
+
+#define MPS2_SERIAL_CONSOLE (&mps2_uart_console)
+
+#else
+#define MPS2_SERIAL_CONSOLE NULL
+#endif
+
+static struct uart_driver mps2_uart_driver = {
+ .driver_name = DRIVER_NAME,
+ .dev_name = SERIAL_NAME,
+ .nr = MPS2_MAX_PORTS,
+ .cons = MPS2_SERIAL_CONSOLE,
+};
+
+static struct mps2_uart_port *mps2_of_get_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, "serial");
+ if (id < 0)
+ id = 0;
+
+ if (WARN_ON(id >= MPS2_MAX_PORTS))
+ return NULL;
+
+ mps2_uart_ports[id].port.line = id;
+ return &mps2_uart_ports[id];
+}
+
+static int mps2_init_port(struct mps2_uart_port *mps_port,
+ struct platform_device *pdev)
+{
+ int ret = 0;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mps_port->port.membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mps_port->port.membase))
+ return PTR_ERR(mps_port->port.membase);
+
+ mps_port->port.mapbase = res->start;
+ mps_port->port.mapsize = resource_size(res);
+
+ mps_port->rx_irq = platform_get_irq(pdev, 0);
+ mps_port->tx_irq = platform_get_irq(pdev, 1);
+ mps_port->port.irq = platform_get_irq(pdev, 2);
+
+ mps_port->port.iotype = UPIO_MEM;
+ mps_port->port.flags = UPF_BOOT_AUTOCONF;
+ mps_port->port.fifosize = 1;
+ mps_port->port.ops = &mps2_uart_pops;
+ mps_port->port.dev = &pdev->dev;
+
+ mps_port->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(mps_port->clk))
+ return PTR_ERR(mps_port->clk);
+
+ ret = clk_prepare_enable(mps_port->clk);
+ if (ret)
+ return ret;
+
+ mps_port->port.uartclk = clk_get_rate(mps_port->clk);
+ if (!mps_port->port.uartclk)
+ ret = -EINVAL;
+
+ clk_disable_unprepare(mps_port->clk);
+
+ return ret;
+}
+
+static int mps2_serial_probe(struct platform_device *pdev)
+{
+ struct mps2_uart_port *mps_port;
+ int ret;
+
+ mps_port = mps2_of_get_port(pdev);
+ if (!mps_port)
+ return -ENODEV;
+
+ ret = mps2_init_port(mps_port, pdev);
+ if (ret)
+ return ret;
+
+ ret = uart_add_one_port(&mps2_uart_driver, &mps_port->port);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, mps_port);
+
+ return 0;
+}
+
+static int mps2_serial_remove(struct platform_device *pdev)
+{
+ struct mps2_uart_port *mps_port = platform_get_drvdata(pdev);
+
+ uart_remove_one_port(&mps2_uart_driver, &mps_port->port);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mps2_match[] = {
+ { .compatible = "arm,mps2-uart", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mps2_match);
+#endif
+
+static struct platform_driver mps2_serial_driver = {
+ .probe = mps2_serial_probe,
+ .remove = mps2_serial_remove,
+
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = of_match_ptr(mps2_match),
+ },
+};
+
+static int __init mps2_uart_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&mps2_uart_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&mps2_serial_driver);
+ if (ret)
+ uart_unregister_driver(&mps2_uart_driver);
+
+ pr_info("MPS2 UART driver initialized\n");
+
+ return ret;
+}
+module_init(mps2_uart_init);
+
+static void __exit mps2_uart_exit(void)
+{
+ platform_driver_unregister(&mps2_serial_driver);
+ uart_unregister_driver(&mps2_uart_driver);
+}
+module_exit(mps2_uart_exit);
+
+MODULE_AUTHOR("Vladimir Murzin <[email protected]>");
+MODULE_DESCRIPTION("MPS2 UART driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index 93ba148..f097fe9 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -261,4 +261,7 @@
/* STM32 USART */
#define PORT_STM32 113

+/* MPS2 UART */
+#define PORT_MPS2UART 114
+
#endif /* _UAPILINUX_SERIAL_CORE_H */
--
1.7.9.5

2015-11-25 10:38:29

by Vladimir Murzin

[permalink] [raw]
Subject: [RFC PATCH 05/10] serial: mps2-uart: add support for early console

This adds support early console for MPS2 UART which can be enabled via
earlycon=mps2,0x40004000

Signed-off-by: Vladimir Murzin <[email protected]>
---
drivers/tty/serial/Kconfig | 1 +
drivers/tty/serial/mps2-uart.c | 30 ++++++++++++++++++++++++++++++
2 files changed, 31 insertions(+)

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index b47f8fc..bb8c66b 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1477,6 +1477,7 @@ config SERIAL_MPS2_UART_CONSOLE
bool "MPS2 UART console support"
depends on SERIAL_MPS2_UART
select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON

config SERIAL_MPS2_UART
tristate "MPS2 UART port"
diff --git a/drivers/tty/serial/mps2-uart.c b/drivers/tty/serial/mps2-uart.c
index 00e882e..c2f530e 100644
--- a/drivers/tty/serial/mps2-uart.c
+++ b/drivers/tty/serial/mps2-uart.c
@@ -445,6 +445,36 @@ static struct console mps2_uart_console = {

#define MPS2_SERIAL_CONSOLE (&mps2_uart_console)

+static void mps2_early_putchar(struct uart_port *port, int ch)
+{
+
+ while (readb(port->membase + UARTn_STATE) & UARTn_STATE_TX_FULL)
+ cpu_relax();
+
+ writeb((unsigned char)ch, port->membase + UARTn_DATA);
+}
+
+
+static void mps2_early_write(struct console *con, const char *s, unsigned n)
+{
+ struct earlycon_device *dev = con->data;
+
+ uart_console_write(&dev->port, s, n, mps2_early_putchar);
+}
+
+static int __init mps2_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->con->write = mps2_early_write;
+
+ return 0;
+}
+EARLYCON_DECLARE(mps2, mps2_early_console_setup);
+OF_EARLYCON_DECLARE(mps2, "arm,mps2-uart", mps2_early_console_setup);
+
#else
#define MPS2_SERIAL_CONSOLE NULL
#endif
--
1.7.9.5

2015-11-25 10:37:39

by Vladimir Murzin

[permalink] [raw]
Subject: [RFC PATCH 06/10] ARM: mps2: introduce MPS2 platform

The Cortex-M Prototyping System (or V2M-MPS2) is designed for
prototyping and evaluation Cortex-M family of processors including the
latest Cortex-M7.

It comes with a range of useful peripherals including 8MB single cycle
SRAM, 16MB PSRAM, Ethernet, QSVGA touch screen panel, 4bit RGB VGA
connector, Audio, SPI and GPIO.

Signed-off-by: Vladimir Murzin <[email protected]>
---
arch/arm/Kconfig | 8 ++++++++
arch/arm/Makefile | 1 +
arch/arm/mach-mps2/Makefile | 1 +
arch/arm/mach-mps2/Makefile.boot | 3 +++
arch/arm/mach-mps2/dtmachine.c | 21 +++++++++++++++++++++
5 files changed, 34 insertions(+)
create mode 100644 arch/arm/mach-mps2/Makefile
create mode 100644 arch/arm/mach-mps2/Makefile.boot
create mode 100644 arch/arm/mach-mps2/dtmachine.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 0365cbb..28db2b2 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -967,6 +967,14 @@ config ARCH_STM32
help
Support for STMicroelectronics STM32 processors.

+config ARCH_MPS2
+ bool "ARM MPS2 paltform"
+ depends on ARM_SINGLE_ARMV7M
+ select ARM_AMBA
+ select CLKSRC_MPS2
+ help
+ Support for ARM MPS2 Cortex-M platform.
+
# Definitions to make life easier
config ARCH_ACORN
bool
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 2c2b28e..dbe06fd 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -183,6 +183,7 @@ machine-$(CONFIG_ARCH_LPC18XX) += lpc18xx
machine-$(CONFIG_ARCH_LPC32XX) += lpc32xx
machine-$(CONFIG_ARCH_MESON) += meson
machine-$(CONFIG_ARCH_MMP) += mmp
+machine-$(CONFIG_ARCH_MPS2) += mps2
machine-$(CONFIG_ARCH_MOXART) += moxart
machine-$(CONFIG_ARCH_MV78XX0) += mv78xx0
machine-$(CONFIG_ARCH_MVEBU) += mvebu
diff --git a/arch/arm/mach-mps2/Makefile b/arch/arm/mach-mps2/Makefile
new file mode 100644
index 0000000..3a74af7
--- /dev/null
+++ b/arch/arm/mach-mps2/Makefile
@@ -0,0 +1 @@
+obj-y += dtmachine.o
diff --git a/arch/arm/mach-mps2/Makefile.boot b/arch/arm/mach-mps2/Makefile.boot
new file mode 100644
index 0000000..eacfc3f
--- /dev/null
+++ b/arch/arm/mach-mps2/Makefile.boot
@@ -0,0 +1,3 @@
+# Empty file waiting for deletion once Makefile.boot isn't needed any more.
+# Patch waits for application at
+# http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=7889/1 .
diff --git a/arch/arm/mach-mps2/dtmachine.c b/arch/arm/mach-mps2/dtmachine.c
new file mode 100644
index 0000000..e7ad9c2
--- /dev/null
+++ b/arch/arm/mach-mps2/dtmachine.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2015 ARM Limited
+ *
+ * Author: Vladimir Murzin <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <asm/mach/arch.h>
+
+static const char *const mps2_compat[] __initconst = {
+ "arm,mps2",
+ NULL
+};
+
+DT_MACHINE_START(MPS2DT, "MPS2 (Device Tree Support)")
+ .dt_compat = mps2_compat,
+MACHINE_END
--
1.7.9.5

2015-11-25 10:37:10

by Vladimir Murzin

[permalink] [raw]
Subject: [RFC PATCH 07/10] ARM: mps2: add low-level debug support

Add low-level debug support for MPS2, so that earlyprintk can be enabled
for debugging early boot issues.

Signed-off-by: Vladimir Murzin <[email protected]>
---
arch/arm/Kconfig.debug | 12 +++++++++++-
arch/arm/include/debug/mps2.S | 27 +++++++++++++++++++++++++++
2 files changed, 38 insertions(+), 1 deletion(-)
create mode 100644 arch/arm/include/debug/mps2.S

diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 259c0ca..cfbf09a 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -479,6 +479,13 @@ choice
Say Y here if you want kernel low-level debugging support
on MMP UART3.

+ config DEBUG_MPS2_UART
+ bool "Kernel low-level debugging message via MPS2 UART0"
+ depends on ARCH_MPS2
+ help
+ Say Y here if you want kernel low-level debugging support
+ on MPS2 based platforms.
+
config DEBUG_QCOM_UARTDM
bool "Kernel low-level debugging messages via QCOM UARTDM"
depends on ARCH_QCOM
@@ -1350,6 +1357,7 @@ config DEBUG_LL_INCLUDE
default "debug/zynq.S" if DEBUG_ZYNQ_UART0 || DEBUG_ZYNQ_UART1
default "debug/bcm63xx.S" if DEBUG_UART_BCM63XX
default "debug/digicolor.S" if DEBUG_DIGICOLOR_UA0
+ default "debug/mps2.S" if DEBUG_MPS2_UART
default "mach/debug-macro.S"

# Compatibility options for PL01x
@@ -1403,6 +1411,7 @@ config DEBUG_UART_PHYS
default 0x20068000 if DEBUG_RK29_UART2 || DEBUG_RK3X_UART3
default 0x20201000 if DEBUG_BCM2835
default 0x3e000000 if DEBUG_BCM_KONA_UART
+ default 0x40004000 if DEBUG_MPS2_UART
default 0x4000e400 if DEBUG_LL_UART_EFM32
default 0x40081000 if DEBUG_LPC18XX_UART0
default 0x40090000 if ARCH_LPC32XX
@@ -1476,7 +1485,8 @@ config DEBUG_UART_PHYS
DEBUG_RMOBILE_SCIFA4 || DEBUG_S3C24XX_UART || \
DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART || \
DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0 || \
- DEBUG_AT91_UART
+ DEBUG_AT91_UART || \
+ DEBUG_MPS2_UART

config DEBUG_UART_VIRT
hex "Virtual base address of debug UART"
diff --git a/arch/arm/include/debug/mps2.S b/arch/arm/include/debug/mps2.S
new file mode 100644
index 0000000..0ced0ce
--- /dev/null
+++ b/arch/arm/include/debug/mps2.S
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 ARM Limited
+ *
+ * Author: Vladimir Murzin <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+ .macro addruart, rp, tmp1, tmp2
+ ldr \rp, =CONFIG_DEBUG_UART_PHYS
+ .endm
+
+ .macro senduart, rd, rx
+ strb \rd, [\rx] @ Data Register
+ .endm
+
+ .macro busyuart, rd, rx
+1001: ldrb \rd, [\rx, #0x4] @ State Register
+ tst \rd, #1 @ busy
+ bne 1001b @ wait until transmit done
+ .endm
+
+ .macro waituart,rd,rx
+ .endm
--
1.7.9.5

2015-11-25 10:37:40

by Vladimir Murzin

[permalink] [raw]
Subject: [RFC PATCH 08/10] ARM: configs: add MPS2 defconfig

This patch adds a new config for MPS2 platform.

Signed-off-by: Vladimir Murzin <[email protected]>
---
arch/arm/configs/mps2_defconfig | 112 +++++++++++++++++++++++++++++++++++++++
1 file changed, 112 insertions(+)
create mode 100644 arch/arm/configs/mps2_defconfig

diff --git a/arch/arm/configs/mps2_defconfig b/arch/arm/configs/mps2_defconfig
new file mode 100644
index 0000000..c36c519
--- /dev/null
+++ b/arch/arm/configs/mps2_defconfig
@@ -0,0 +1,112 @@
+# CONFIG_USELIB is not set
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_LOG_BUF_SHIFT=16
+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_BLOCK is not set
+# CONFIG_MMU is not set
+CONFIG_ARM_SINGLE_ARMV7M=y
+CONFIG_ARCH_MPS2=y
+CONFIG_SET_MEM_PARAM=y
+CONFIG_DRAM_BASE=0x21000000
+CONFIG_DRAM_SIZE=0x1000000
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_ATAGS is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_SHARED_FLAT=y
+# CONFIG_COREDUMP is not set
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FW_LOADER is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_CORE is not set
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_EZCHIP is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_HISILICON is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_QUALCOMM is not set
+# CONFIG_NET_VENDOR_RENESAS is not set
+# CONFIG_NET_VENDOR_ROCKER is not set
+# CONFIG_NET_VENDOR_SAMSUNG is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+CONFIG_SMSC911X=y
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+# CONFIG_WLAN is not set
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_MPS2_UART_CONSOLE=y
+CONFIG_SERIAL_MPS2_UART=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_ARM_SP805_WATCHDOG=y
+CONFIG_MFD_SYSCON=y
+# CONFIG_USB_SUPPORT is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_SYSCON=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_ONESHOT=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_ARM_TIMER_SP804=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_V4_2=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_MEMTEST=y
--
1.7.9.5

2015-11-25 10:36:34

by Vladimir Murzin

[permalink] [raw]
Subject: [RFC PATCH 09/10] ARM: dts: introduce MPS2 AN385/AN386

Application Notes 385 and 386 shares the same memory map and features
except the CPU is used. AN385 is supplied with Cortex-M3 CPU and AN386
is supplied with Cortex-M4.

Signed-off-by: Vladimir Murzin <[email protected]>
---
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/mps2-an385.dts | 90 +++++++++++++++
arch/arm/boot/dts/mps2.dtsi | 227 ++++++++++++++++++++++++++++++++++++++
3 files changed, 318 insertions(+)
create mode 100644 arch/arm/boot/dts/mps2-an385.dts
create mode 100644 arch/arm/boot/dts/mps2.dtsi

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 30bbc37..4ef3720 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -237,6 +237,7 @@ dtb-$(CONFIG_ARCH_MMP) += \
dtb-$(CONFIG_MACH_MESON8B) += \
meson8b-mxq.dtb \
meson8b-odroidc1.dtb
+dtb-$(CONFIG_ARCH_MPS2) += mps2-an385.dtb
dtb-$(CONFIG_ARCH_MOXART) += \
moxart-uc7112lx.dtb
dtb-$(CONFIG_SOC_IMX1) += \
diff --git a/arch/arm/boot/dts/mps2-an385.dts b/arch/arm/boot/dts/mps2-an385.dts
new file mode 100644
index 0000000..ddb03d3
--- /dev/null
+++ b/arch/arm/boot/dts/mps2-an385.dts
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2015 ARM Limited
+ *
+ * Author: Vladimir Murzin <[email protected]>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "mps2.dtsi"
+
+/ {
+ model = "ARM MPS2 Application Note 385/386";
+ compatible = "arm,mps2";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ bootargs = "init=/sbin/init earlycon";
+ stdout-path = "serial0:9600n8";
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x21000000 0x1000000>;
+ };
+
+ ethernet@40200000 {
+ compatible = "smsc,lan9220", "smsc,lan9115";
+ reg = <0x40200000 0x10000>;
+ interrupts = <13>;
+ interrupt-parent = <&nvic>;
+ smsc,irq-active-high;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&timer0 {
+ status = "okay";
+};
+
+&timer1 {
+ status = "okay";
+};
+
+&wdt {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/mps2.dtsi b/arch/arm/boot/dts/mps2.dtsi
new file mode 100644
index 0000000..5d2c539
--- /dev/null
+++ b/arch/arm/boot/dts/mps2.dtsi
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2015 ARM Limited
+ *
+ * Author: Vladimir Murzin <[email protected]>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "armv7-m.dtsi"
+
+/ {
+ oscclk0: clk-osc0 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ };
+
+ oscclk1: clk-osc1 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24576000>;
+ };
+
+ oscclk2: clk-osc2 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <25000000>;
+ };
+
+ cfgclk: clk-cfg {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <5000000>;
+ };
+
+ spicfgclk: clk-spicfg {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <75000000>;
+ };
+
+ sysclk: clk-sys {
+ compatible = "fixed-factor-clock";
+ clocks = <&oscclk0>;
+ #clock-cells = <0>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+
+ audmclk: clk-audm {
+ compatible = "fixed-factor-clock";
+ clocks = <&oscclk1>;
+ #clock-cells = <0>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+
+ audsclk: clk-auds {
+ compatible = "fixed-factor-clock";
+ clocks = <&oscclk1>;
+ #clock-cells = <0>;
+ clock-div = <8>;
+ clock-mult = <1>;
+ };
+
+ spiclcd: clk-cpiclcd {
+ compatible = "fixed-factor-clock";
+ clocks = <&oscclk0>;
+ #clock-cells = <0>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+
+ spicon: clk-spicon {
+ compatible = "fixed-factor-clock";
+ clocks = <&oscclk0>;
+ #clock-cells = <0>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+
+ i2cclcd: clk-i2cclcd {
+ compatible = "fixed-factor-clock";
+ clocks = <&oscclk0>;
+ #clock-cells = <0>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+
+ i2caud: clk-i2caud {
+ compatible = "fixed-factor-clock";
+ clocks = <&oscclk0>;
+ #clock-cells = <0>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ ranges;
+
+ apb {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x40000000 0x10000>;
+
+ timer0: mps2-timer0@0 {
+ compatible = "arm,mps2-timer";
+ reg = <0x0 0x1000>;
+ interrupts = <8>;
+ clocks = <&sysclk>;
+ status = "disabled";
+ };
+
+ timer1: mps2-timer1@1000 {
+ compatible = "arm,mps2-timer";
+ reg = <0x1000 0x1000>;
+ interrupts = <9>;
+ clocks = <&sysclk>;
+ status = "disabled";
+ };
+
+ timer2: dual-timer@2000 {
+ compatible = "arm,sp804";
+ reg = <0x2000 0x1000>;
+ clocks = <&sysclk>;
+ interrupts = <10>;
+ status = "disabled";
+ };
+
+
+ uart0: serial@4000 {
+ compatible = "arm,mps2-uart";
+ reg = <0x4000 0x1000>;
+ interrupts = <0 1 12>;
+ clocks = <&sysclk>;
+ status = "disabled";
+ };
+
+ uart1: serial@5000 {
+ compatible = "arm,mps2-uart";
+ reg = <0x5000 0x1000>;
+ interrupts = <2 3 12>;
+ clocks = <&sysclk>;
+ status = "disabled";
+ };
+
+ uart2: serial@6000 {
+ compatible = "arm,mps2-uart";
+ reg = <0x6000 0x1000>;
+ interrupts = <4 5 12>;
+ clocks = <&sysclk>;
+ status = "disabled";
+ };
+
+ wdt: watchdog@8000 {
+ compatible = "arm,sp805", "arm,primecell";
+ arm,primecell-periphid = <0x00141805>;
+ reg = <0x8000 0x1000>;
+ interrupts = <0>;
+ clocks = <&sysclk>;
+ clock-names = "apb_pclk";
+ status = "disabled";
+ };
+ };
+
+ fpgaio {
+ compatible = "syscon", "simple-mfd";
+ reg = <0x40028000 0x10>;
+
+ led@0 {
+ compatible = "register-bit-led";
+ offset = <0x0>;
+ mask = <0x01>;
+ label = "userled:0";
+ linux,default-trigger = "heartbeat";
+ default-state = "on";
+ };
+
+ led@1 {
+ compatible = "register-bit-led";
+ offset = <0x0>;
+ mask = <0x02>;
+ label = "userled:1";
+ linux,default-trigger = "usr";
+ default-state = "off";
+ };
+ };
+ };
+};
--
1.7.9.5

2015-11-25 10:36:33

by Vladimir Murzin

[permalink] [raw]
Subject: [RFC PATCH 10/10] ARM: dts: introduce MPS2 AN399/AN400

Application Notes 399 and 400 shares the same memory map and
features. Both are shipped with Cortex-M7 and have the same peripheral
as AN385/AN386, but with different location of PSRAM and Ethernet
controller.

Signed-off-by: Vladimir Murzin <[email protected]>
---
arch/arm/boot/dts/Makefile | 4 +-
arch/arm/boot/dts/mps2-an399.dts | 92 ++++++++++++++++++++++++++++++++++++++
2 files changed, 95 insertions(+), 1 deletion(-)
create mode 100644 arch/arm/boot/dts/mps2-an399.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 4ef3720..6603a1f 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -237,7 +237,9 @@ dtb-$(CONFIG_ARCH_MMP) += \
dtb-$(CONFIG_MACH_MESON8B) += \
meson8b-mxq.dtb \
meson8b-odroidc1.dtb
-dtb-$(CONFIG_ARCH_MPS2) += mps2-an385.dtb
+dtb-$(CONFIG_ARCH_MPS2) += \
+ mps2-an385.dtb \
+ mps2-an399.dtb
dtb-$(CONFIG_ARCH_MOXART) += \
moxart-uc7112lx.dtb
dtb-$(CONFIG_SOC_IMX1) += \
diff --git a/arch/arm/boot/dts/mps2-an399.dts b/arch/arm/boot/dts/mps2-an399.dts
new file mode 100644
index 0000000..e591d75
--- /dev/null
+++ b/arch/arm/boot/dts/mps2-an399.dts
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2015 ARM Limited
+ *
+ * Author: Vladimir Murzin <[email protected]>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "mps2.dtsi"
+
+/ {
+ model = "ARM MPS2 Application Note 399/400";
+ compatible = "arm,mps2";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ bootargs = "rdinit=/sbin/init earlycon";
+ stdout-path = "serial0:9600n8";
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x60000000 0x1000000>;
+ };
+
+
+ ethernet@a0000000 {
+ compatible = "smsc,lan9220", "smsc,lan9115";
+ reg = <0xa0000000 0x10000>;
+ interrupts = <13>;
+ interrupt-parent = <&nvic>;
+ smsc,irq-active-high;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+
+&timer0 {
+ status = "okay";
+};
+
+&timer1 {
+ status = "okay";
+};
+
+&wdt {
+ status = "okay";
+};
--
1.7.9.5

2015-11-25 11:23:25

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [RFC PATCH 00/10] Support for Cortex-M Prototyping System

On Wednesday 25 November 2015 10:33:31 Vladimir Murzin wrote:
> Hi,
>
> This patch series provide the basic support for running ucLinux on V2M-MPS2
> platform.
>
> With these patches applied ucLinux can be run on both HW and FVP models
> with Cortex-M3/M4/M7 configurations.
>
> Board description:
>
> http://infocenter.arm.com/help/topic/com.arm.doc.100112_0100_03_en/arm_versatile_express_cortex_m_prototyping_system_(v2m_mps2)_technical_reference_manual_100112_0100_03_en.pdf
>
> Application notes (cover Cortex-M3/M4/M7):
>
> http://infocenter.arm.com/help/topic/com.arm.doc.dai0385a/DAI0385A_cortex_m3_on_v2m_mps2.pdf
> http://infocenter.arm.com/help/topic/com.arm.doc.dai0386a/DAI0386A_cortex_m4_on_v2m_mps2.pdf
> http://infocenter.arm.com/help/topic/com.arm.doc.dai0399a/DAI0399A_cortex_m7_on_v2m_mps2.pdf
> http://infocenter.arm.com/help/topic/com.arm.doc.dai0400a/DAI0400A_cortex_m7_on_v2m_mps2.pdf
>
> Cortex-M System Design Kit (referenced as CMDK from documents above):
>
> http://infocenter.arm.com/help/topic/com.arm.doc.ddi0479c/DDI0479C_cortex_m_system_design_kit_r1p0_trm.pdf
>
> I'd be happy to hear any feedback/comments on this series!

Looks pretty good overall, I didn't have any specific concerns.

> Remain questions:
>
> - Application notes 399/400 have PSRAM located at address different to what
> we have for AN385/AN386, so I'm wondering what is the best practice to handle
> CONFIG_DRAM_BASE? Different defconfig or there is better place?

I would not want to add more than one defconfig for a relatively simple
platform. Most actual users would have to modify their config anyway, so
I think it's best to just have one config file for the most common machine
here and let users change the dram base if they have the other one.

We can also look at using the Kconfig fragments infrastructure more here.

> - I'm not sure about naming of dts files: Application Notes (mps2-an*) vs Cortex-M (mps2-cm*);
> any preference?

I don't mind either way.

Arnd

2015-11-25 13:40:12

by Daniel Lezcano

[permalink] [raw]
Subject: Re: [RFC PATCH 02/10] clockevents/drivers: add MPS2 Timer driver

On 11/25/2015 11:33 AM, Vladimir Murzin wrote:
> MPS2 platform has simple 32 bits general purpose countdown timers.
>
> The driver uses the first detected timer as a clocksource and the rest
> of the timers as a clockevent
>
> Signed-off-by: Vladimir Murzin <[email protected]>
> ---
> drivers/clocksource/Kconfig | 5 +
> drivers/clocksource/Makefile | 1 +
> drivers/clocksource/mps2-timer.c | 280 ++++++++++++++++++++++++++++++++++++++
> 3 files changed, 286 insertions(+)
> create mode 100644 drivers/clocksource/mps2-timer.c
>
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index 71cfdf7..552ab54 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -136,6 +136,11 @@ config CLKSRC_STM32
> depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST)
> select CLKSRC_MMIO
>
> +config CLKSRC_MPS2
> + bool "Clocksource for MPS2 SoCs"
> + depends on OF && (ARM || COMPILE_TEST)

bool "Clocksource for MPS2 SoCs" if COMPILE_TEST
depends on OF && ARM

> + select CLKSRC_MMIO
> +
> config ARM_ARCH_TIMER
> bool
> select CLKSRC_OF if OF
> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> index 56bd16e..7033b9c 100644
> --- a/drivers/clocksource/Makefile
> +++ b/drivers/clocksource/Makefile
> @@ -39,6 +39,7 @@ 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_LPC32XX) += time-lpc32xx.o
> +obj-$(CONFIG_CLKSRC_MPS2) += mps2-timer.o
> obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o
> obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o
> obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o
> diff --git a/drivers/clocksource/mps2-timer.c b/drivers/clocksource/mps2-timer.c
> new file mode 100644
> index 0000000..77befe2
> --- /dev/null
> +++ b/drivers/clocksource/mps2-timer.c
> @@ -0,0 +1,280 @@
> +/*
> + * Copyright (C) 2015 ARM Limited
> + *
> + * Author: Vladimir Murzin <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/clk.h>
> +#include <linux/clockchips.h>
> +#include <linux/clocksource.h>
> +#include <linux/err.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/of_address.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
> +#include <linux/sched_clock.h>
> +#include <linux/slab.h>
> +
> +#define TIMER_CTRL 0x0
> +#define TIMER_CTRL_ENABLE BIT(0)
> +#define TIMER_CTRL_IE BIT(3)
> +
> +#define TIMER_VALUE 0x4
> +#define TIMER_RELOAD 0x8
> +#define TIMER_INT 0xc
> +
> +struct clockevent_mps2 {
> + void __iomem *reg;
> + u32 clock_count_per_tick;
> + struct clock_event_device clkevt;
> +};
> +
> +static void __iomem *sched_clock_base;
> +
> +static u64 notrace mps2_sched_read(void)
> +{
> + return ~readl_relaxed(sched_clock_base + TIMER_VALUE);
> +}
> +
> +

extra line.

> +static inline struct clockevent_mps2 *to_mps2_clkevt(struct clock_event_device *c)
> +{
> + return container_of(c, struct clockevent_mps2, clkevt);
> +}
> +
> +static void clockevent_mps2_writel(u32 val, struct clock_event_device *c, u32 offset)
> +{
> + writel(val, to_mps2_clkevt(c)->reg + offset);
> +}
> +
> +static int mps2_timer_shutdown(struct clock_event_device *ce)
> +{
> + clockevent_mps2_writel(0, ce, TIMER_RELOAD);
> + clockevent_mps2_writel(0, ce, TIMER_CTRL);
> +
> + return 0;
> +}
> +
> +static int mps2_timer_set_next_event(unsigned long next, struct clock_event_device *ce)
> +{
> + clockevent_mps2_writel(next, ce, TIMER_VALUE);
> + clockevent_mps2_writel(TIMER_CTRL_IE | TIMER_CTRL_ENABLE, ce, TIMER_CTRL);
> +
> + return 0;
> +}
> +
> +static int mps2_timer_set_periodic(struct clock_event_device *ce)
> +{
> + u32 clock_count_per_tick = to_mps2_clkevt(ce)->clock_count_per_tick;
> +
> + clockevent_mps2_writel(clock_count_per_tick, ce, TIMER_RELOAD);
> + clockevent_mps2_writel(clock_count_per_tick, ce, TIMER_VALUE);
> + clockevent_mps2_writel(TIMER_CTRL_IE | TIMER_CTRL_ENABLE, ce, TIMER_CTRL);
> +
> + return 0;
> +}
> +
> +static irqreturn_t mps2_timer_interrupt(int irq, void *dev_id)
> +{
> + struct clockevent_mps2 *ce = dev_id;
> + u32 status = readl(ce->reg + TIMER_INT);
> +
> + if (!status)
> + return IRQ_NONE;

Why that could happen ? Add a comment.

> +
> + writel(1, ce->reg + TIMER_INT);
> +
> + ce->clkevt.event_handler(&ce->clkevt);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int __init mps2_clockevents_init(struct device_node *np)
> +{
> + void __iomem *base;
> + struct clk *clk;
> + struct irqaction *ia;
> + struct clockevent_mps2 *ce;
> + u32 rate;
> + int irq, ret;
> + const char *name = "mps2-clkevt";
> +
> + ret = of_property_read_u32(np, "clock-frequency", &rate);
> +

extra line.

> + if (ret) {
> + 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 clock for clockevent: %d\n", ret);
> + clk_put(clk);
> + goto err_clk_enable;
> + }
> +
> + rate = clk_get_rate(clk);
> + }
> +
> + base = of_iomap(np, 0);
> + if (!base) {
> + ret = -EADDRNOTAVAIL;
> + pr_err("failed to map register for clockevent: %d\n", ret);
> + goto err_iomap;
> + }
> +
> + irq = irq_of_parse_and_map(np, 0);
> + if (!irq) {
> + ret = -ENOENT;
> + pr_err("failed to get irq for clockevent: %d\n", ret);
> + goto err_get_irq;
> + }
> +
> + ce = kzalloc(sizeof(struct clockevent_mps2), GFP_KERNEL);
> + if (!ce) {
> + ret = -ENOMEM;
> + pr_err("failed to allocate clockevent: %d\n", ret);
> + goto err_ce_alloc;
> + }
> +
> + ce->reg = base;
> + ce->clock_count_per_tick = DIV_ROUND_CLOSEST(rate, HZ);
> + ce->clkevt.irq = irq;
> + ce->clkevt.name = name;
> + ce->clkevt.rating = 200;
> + ce->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
> + ce->clkevt.cpumask = cpu_possible_mask;
> + ce->clkevt.set_state_shutdown = mps2_timer_shutdown,
> + ce->clkevt.set_state_periodic = mps2_timer_set_periodic,
> + ce->clkevt.set_state_oneshot = mps2_timer_shutdown,
> + ce->clkevt.set_next_event = mps2_timer_set_next_event;
> +
> + ia = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
> + if (!ia) {
> + ret = -ENOMEM;
> + pr_err("failed to allocate irqaction: %d\n", ret);
> + goto err_ia_alloc;
> + }
> +
> + ia->name = name;
> + ia->flags = IRQF_TIMER;
> + ia->handler = mps2_timer_interrupt;
> + ia->dev_id = ce;
> +
> + writel(0, base + TIMER_CTRL);
> +
> + ret = setup_irq(irq, ia);

Use request_irq here, that will save some extra code in this driver.

> + if (ret) {
> + pr_err("failed to setup irq: %d\n", ret);
> + goto err_setup_irq;
> + }
> +
> + clockevents_config_and_register(&ce->clkevt, rate, 0xf, 0xffffffff);
> +
> + return 0;
> +
> +err_setup_irq:
> + kfree(ia);
> +err_ia_alloc:
> + kfree(ce);
> +err_ce_alloc:
> +err_get_irq:
> + iounmap(base);
> +err_iomap:
> + clk_disable_unprepare(clk);
> +err_clk_enable:
> + clk_put(clk);
> +err_clk_get:
> + return ret;
> +}
> +
> +static int mps2_clocksource_init(struct device_node *np)

__init annotation.

> +{
> + void __iomem *base;
> + struct clk *clk;
> + u32 rate;
> + int ret;
> + const char *name = "mps2-clksrc";
> +
> + ret = of_property_read_u32(np, "clock-frequency", &rate);
> +

extra line.

> + if (ret) {
> + clk = of_clk_get(np, 0);
> + if (IS_ERR(clk)) {
> + ret = PTR_ERR(clk);
> + pr_err("failed to get clock for clocksource: %d\n", ret);
> + goto err_clk_get;
> + }
> +
> + ret = clk_prepare_enable(clk);
> + if (ret) {
> + pr_err("failed to enable clock for clocksource: %d\n", ret);
> + clk_put(clk);
> + goto err_clk_enable;
> + }
> +
> + rate = clk_get_rate(clk);
> + }
> +
> + base = of_iomap(np, 0);
> + if (!base) {
> + ret = -EADDRNOTAVAIL;
> + pr_err("failed to map register for clocksource: %d\n", ret);
> + goto err_iomap;
> + }
> +
> + writel(0, base + TIMER_CTRL);
> +
> + writel(0xffffffff, base + TIMER_VALUE);
> + writel(0xffffffff, base + TIMER_RELOAD);
> +
> + writel(TIMER_CTRL_ENABLE, base + TIMER_CTRL);

A comment would help to understand the above 4 lines.

> + ret = clocksource_mmio_init(base + TIMER_VALUE, name,
> + rate, 200, 32,
> + clocksource_mmio_readl_down);
> + if (ret) {
> + pr_err("failed to init clocksource: %d\n", ret);
> + goto err_clocksource_init;
> + }
> +
> + sched_clock_base = base;
> + sched_clock_register(mps2_sched_read, 32, rate);
> +
> + return 0;
> +
> +err_clocksource_init:
> + iounmap(base);
> +err_iomap:
> + clk_disable_unprepare(clk);
> +err_clk_enable:
> + clk_put(clk);
> +err_clk_get:
> + return ret;
> +

extra line.

> +}
> +
> +static void __init mps2_timer_init(struct device_node *np)
> +{
> + static int clksrc;
> +
> + if (!clksrc && !mps2_clocksource_init(np))
> + clksrc = 1;
> + else
> + mps2_clockevents_init(np);

That assumes the clocksource is defined before the clockevents in the
DT. If it is not the case, the mps2_clocksource_init will fail (and spit
errors) and mps2_clockevents_init() won't be called.

> +}
> +
> +CLOCKSOURCE_OF_DECLARE(mps2_timer, "arm,mps2-timer", mps2_timer_init);
>


--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

2015-11-25 14:40:00

by Vladimir Murzin

[permalink] [raw]
Subject: Re: [RFC PATCH 00/10] Support for Cortex-M Prototyping System

On 25/11/15 11:22, Arnd Bergmann wrote:
>> I'd be happy to hear any feedback/comments on this series!
> Looks pretty good overall, I didn't have any specific concerns.

Thanks for your time!

>
>> > Remain questions:
>> >
>> > - Application notes 399/400 have PSRAM located at address different to what
>> > we have for AN385/AN386, so I'm wondering what is the best practice to handle
>> > CONFIG_DRAM_BASE? Different defconfig or there is better place?
> I would not want to add more than one defconfig for a relatively simple
> platform. Most actual users would have to modify their config anyway, so
> I think it's best to just have one config file for the most common machine
> here and let users change the dram base if they have the other one.
>

I think the same, just wanted to check that I didn't misunderstand
something.

> We can also look at using the Kconfig fragments infrastructure more here.
>
>> > - I'm not sure about naming of dts files: Application Notes (mps2-an*) vs Cortex-M (mps2-cm*);
>> > any preference?
> I don't mind either way.

Ok, I'll leave things as they are till anybody has different opinion on
that.

Cheers
Vladimir

>
> Arnd
>
>
>

2015-11-25 14:51:14

by Vladimir Murzin

[permalink] [raw]
Subject: Re: [RFC PATCH 02/10] clockevents/drivers: add MPS2 Timer driver

Hi Daniel,

Thanks for you review, I agree on all concerns raised and address them
in the next version. Just some points to confirm below (I left only
relevant parts).

>> +static irqreturn_t mps2_timer_interrupt(int irq, void *dev_id)
>> +{
>> + struct clockevent_mps2 *ce = dev_id;
>> + u32 status = readl(ce->reg + TIMER_INT);
>> +
>> + if (!status)
>> + return IRQ_NONE;
>
> Why that could happen ? Add a comment.
>

Sort of defensive programming, I never seen it happens, but just in case
of spurious interrupts... Do you prefer to get rid of this check or

/* spurious interrupt? */
if (!status)
return IRQ_NONE;

would be fine to you?

>> +}
>> +
>> +static void __init mps2_timer_init(struct device_node *np)
>> +{
>> + static int clksrc;
>> +
>> + if (!clksrc && !mps2_clocksource_init(np))
>> + clksrc = 1;
>> + else
>> + mps2_clockevents_init(np);
>
> That assumes the clocksource is defined before the clockevents in the
> DT. If it is not the case, the mps2_clocksource_init will fail (and spit
> errors) and mps2_clockevents_init() won't be called.
>

Does following (stolen from efm32) look better to you?

static void __init mps2_timer_init(struct device_node *np)
{
static int has_clocksource, has_clockevent;
int ret;

if (!has_clocksource) {
ret = mps2_clocksource_init(np);
if (!ret) {
has_clocksource = 1;
return;
}
}

if (!has_clockevent) {
ret = mps2_clockevent_init(np);
if (!ret) {
has_clockevent = 1;
return;
}
}
}

Thanks
Vladimir

>> +}
>> +
>> +CLOCKSOURCE_OF_DECLARE(mps2_timer, "arm,mps2-timer", mps2_timer_init);
>>
>
>

2015-11-25 15:10:27

by Daniel Lezcano

[permalink] [raw]
Subject: Re: [RFC PATCH 02/10] clockevents/drivers: add MPS2 Timer driver

On 11/25/2015 03:51 PM, Vladimir Murzin wrote:
> Hi Daniel,
>
> Thanks for you review, I agree on all concerns raised and address them
> in the next version. Just some points to confirm below (I left only
> relevant parts).
>
>>> +static irqreturn_t mps2_timer_interrupt(int irq, void *dev_id)
>>> +{
>>> + struct clockevent_mps2 *ce = dev_id;
>>> + u32 status = readl(ce->reg + TIMER_INT);
>>> +
>>> + if (!status)
>>> + return IRQ_NONE;
>>
>> Why that could happen ? Add a comment.
>>
>
> Sort of defensive programming, I never seen it happens, but just in case
> of spurious interrupts... Do you prefer to get rid of this check or
>
> /* spurious interrupt? */
> if (!status)
> return IRQ_NONE;
>
> would be fine to you?

Yes, that would be fine, but if it does never happen, we don't really
need this check. If you prefer to make sure there isn't a spurious
interrupt and considering it shouldn't happen, a pr_info trace may help
to spot this misbehavior.

>>> +}
>>> +
>>> +static void __init mps2_timer_init(struct device_node *np)
>>> +{
>>> + static int clksrc;
>>> +
>>> + if (!clksrc && !mps2_clocksource_init(np))
>>> + clksrc = 1;
>>> + else
>>> + mps2_clockevents_init(np);
>>
>> That assumes the clocksource is defined before the clockevents in the
>> DT. If it is not the case, the mps2_clocksource_init will fail (and spit
>> errors) and mps2_clockevents_init() won't be called.
>>
>
> Does following (stolen from efm32) look better to you?
>
> static void __init mps2_timer_init(struct device_node *np)
> {
> static int has_clocksource, has_clockevent;
> int ret;
>
> if (!has_clocksource) {
> ret = mps2_clocksource_init(np);
> if (!ret) {
> has_clocksource = 1;
> return;
> }
> }
>
> if (!has_clockevent) {
> ret = mps2_clockevent_init(np);
> if (!ret) {
> has_clockevent = 1;
> return;
> }
> }
> }

Yes.

I don't like to have a "CLOCKSOURCE_OF_DECLARE" to initialize a
clockevent but I can't blame you, this is what is done in the other drivers.

>>> +}
>>> +
>>> +CLOCKSOURCE_OF_DECLARE(mps2_timer, "arm,mps2-timer", mps2_timer_init);
>>>
>>
>>
>


--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

2015-11-25 15:21:36

by Vladimir Murzin

[permalink] [raw]
Subject: Re: [RFC PATCH 02/10] clockevents/drivers: add MPS2 Timer driver

On 25/11/15 15:10, Daniel Lezcano wrote:
> On 11/25/2015 03:51 PM, Vladimir Murzin wrote:
>> Hi Daniel,
>>
>> Thanks for you review, I agree on all concerns raised and address them
>> in the next version. Just some points to confirm below (I left only
>> relevant parts).
>>
>>>> +static irqreturn_t mps2_timer_interrupt(int irq, void *dev_id)
>>>> +{
>>>> + struct clockevent_mps2 *ce = dev_id;
>>>> + u32 status = readl(ce->reg + TIMER_INT);
>>>> +
>>>> + if (!status)
>>>> + return IRQ_NONE;
>>>
>>> Why that could happen ? Add a comment.
>>>
>>
>> Sort of defensive programming, I never seen it happens, but just in case
>> of spurious interrupts... Do you prefer to get rid of this check or
>>
>> /* spurious interrupt? */
>> if (!status)
>> return IRQ_NONE;
>>
>> would be fine to you?
>
> Yes, that would be fine, but if it does never happen, we don't really
> need this check. If you prefer to make sure there isn't a spurious
> interrupt and considering it shouldn't happen, a pr_info trace may help
> to spot this misbehavior.
>

Good, I'll put pr_warn("spurious interrupt\n") then.

>>>> +}
>>>> +
>>>> +static void __init mps2_timer_init(struct device_node *np)
>>>> +{
>>>> + static int clksrc;
>>>> +
>>>> + if (!clksrc && !mps2_clocksource_init(np))
>>>> + clksrc = 1;
>>>> + else
>>>> + mps2_clockevents_init(np);
>>>
>>> That assumes the clocksource is defined before the clockevents in the
>>> DT. If it is not the case, the mps2_clocksource_init will fail (and spit
>>> errors) and mps2_clockevents_init() won't be called.
>>>
>>
>> Does following (stolen from efm32) look better to you?
>>
>> static void __init mps2_timer_init(struct device_node *np)
>> {
>> static int has_clocksource, has_clockevent;
>> int ret;
>>
>> if (!has_clocksource) {
>> ret = mps2_clocksource_init(np);
>> if (!ret) {
>> has_clocksource = 1;
>> return;
>> }
>> }
>>
>> if (!has_clockevent) {
>> ret = mps2_clockevent_init(np);
>> if (!ret) {
>> has_clockevent = 1;
>> return;
>> }
>> }
>> }
>
> Yes.
>
> I don't like to have a "CLOCKSOURCE_OF_DECLARE" to initialize a
> clockevent but I can't blame you, this is what is done in the other
> drivers.

Thanks for your time!

Vladimir

>
>>>> +}
>>>> +
>>>> +CLOCKSOURCE_OF_DECLARE(mps2_timer, "arm,mps2-timer", mps2_timer_init);
>>>>
>>>
>>>
>>
>
>

2015-11-25 20:05:03

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [RFC PATCH 01/10] dt-bindings: document the MPS2 timer bindings

On Wed, Nov 25, 2015 at 10:33:32AM +0000, Vladimir Murzin wrote:
> This adds documentation of device tree bindings for the
> timers found on ARM MPS2 platform.
>
> Signed-off-by: Vladimir Murzin <[email protected]>

Acked-by: Rob Herring <[email protected]>

> ---
> .../devicetree/bindings/timer/arm,mps2-timer.txt | 28 ++++++++++++++++++++
> 1 file changed, 28 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/timer/arm,mps2-timer.txt
>
> diff --git a/Documentation/devicetree/bindings/timer/arm,mps2-timer.txt b/Documentation/devicetree/bindings/timer/arm,mps2-timer.txt
> new file mode 100644
> index 0000000..48f84d7
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/timer/arm,mps2-timer.txt
> @@ -0,0 +1,28 @@
> +ARM MPS2 timer
> +
> +The MPS2 platform has simple general-purpose 32 bits timers.
> +
> +Required properties:
> +- compatible : Should be "arm,mps2-timer"
> +- reg : Address and length of the register set
> +- interrupts : Reference to the timer interrupt
> +
> +Required clocking property, have to be one of:
> +- clocks : The input clock of the timer
> +- clock-frequency : The rate in HZ in input of the ARM MPS2 timer
> +
> +Examples:
> +
> +timer1: mps2-timer@40000000 {
> + compatible = "arm,mps2-timer";
> + reg = <0x40000000 0x1000>;
> + interrupts = <8>;
> + clocks = <&sysclk>;
> +};
> +
> +timer2: mps2-timer@40001000 {
> + compatible = "arm,mps2-timer";
> + reg = <0x40001000 0x1000>;
> + interrupts = <9>;
> + clock-frequency = <25000000>;
> +};
> --
> 1.7.9.5
>

2015-11-25 20:07:35

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [RFC PATCH 03/10] dt-bindings: document the MPS2 UART bindings

On Wed, Nov 25, 2015 at 10:33:34AM +0000, Vladimir Murzin wrote:
> This adds documentation of device tree bindings for the
> UART found on ARM MPS2 platform
>
> Signed-off-by: Vladimir Murzin <[email protected]>

Why did ARM invent a new UART?

Acked-by: Rob Herring <[email protected]

> ---
> .../devicetree/bindings/serial/arm,mps2-uart.txt | 22 ++++++++++++++++++++
> 1 file changed, 22 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/serial/arm,mps2-uart.txt
>
> diff --git a/Documentation/devicetree/bindings/serial/arm,mps2-uart.txt b/Documentation/devicetree/bindings/serial/arm,mps2-uart.txt
> new file mode 100644
> index 0000000..b3f7cb1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/serial/arm,mps2-uart.txt
> @@ -0,0 +1,22 @@
> +ARM MPS2 UART
> +
> +Required properties:
> +- compatible : Should be "arm,mps2-uart"
> +- reg : Address and length of the register set
> +- interrupts : Reference to the UART RX, TX and overrun interrupts
> +
> +Required clocking property:
> +- clocks : The input clock of the UART
> +
> +
> +Examples:
> +
> +uart0: serial@40004000 {
> + compatible = "arm,mps2-uart";
> + reg = <0x40004000 0x1000>;
> + interrupts = <0 1 12>;
> + clocks = <&sysclk>;
> +};
> +
> +
> +
> --
> 1.7.9.5
>

2015-12-01 11:35:42

by Vladimir Murzin

[permalink] [raw]
Subject: Re: [RFC PATCH 03/10] dt-bindings: document the MPS2 UART bindings

On 25/11/15 20:07, Rob Herring wrote:
> On Wed, Nov 25, 2015 at 10:33:34AM +0000, Vladimir Murzin wrote:
>> This adds documentation of device tree bindings for the
>> UART found on ARM MPS2 platform
>>
>> Signed-off-by: Vladimir Murzin <[email protected]>
>
> Why did ARM invent a new UART?

It is not something new and it was inherited from MPS (version 1) and I
can only guess why it was there in a first place ;)

>
> Acked-by: Rob Herring <[email protected]

Thanks for your time.

Vladimir