2013-06-10 09:23:19

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: [PATCH v2 00/11] ARM:STixxxx: Add STixxxx platform and board support

From: Srinivas Kandagatla <[email protected]>

Here is new patch-set incorporating all the review comments.

This patch-set adds basic support for STMicroelectronics STixxxx SOCs
which includes STiH415 and STiH416 with B2000 and B2020 board support.

STiH415 and STiH416 are dual-core ARM Cortex-A9 CPU, designed for use in
Set-top-boxes. The SOC support is available in mach-stixxxx which contains
support code for STiH415, STiH416 SOCs including the generic board support.

Only device drivers included in this patch set are UART and pinctrl, other
drivers will be added in future.

The reason for adding two SOCs at this patch set is to show that no new
C code is required for second SOC(STiH416) support.

Thankyou all for reviewing the first set of RFC patches.
I would appreciate any feedback on these patches.

Changes since RFC:
- st-asc Serial driver:
- modified kconfig to remove default y
- removed all the forward declaration.
- use dynamic major numbering.
- merge header-file in to driver.

- ARM Global timer:
- moved to drivers/clocksource.
- added revision check in driver.
- removed unused header file.
- moved to u64 from union gt_counter
- comments added in get_counter
- removed leftover debug code.
- moved code to use __raw_readl/writel.
- used DIV_ROUND_CLOSEST
- added check in interrupt handler.
- expanded CE and CS acronyms usage.
- Fixed minimum clock ticks value.
- move to use clocksource_register_hz
- added arch sched_clock support.
- added ERRATA 740657 workaround.

- ST-System Configuration Registers:
- moved from syscon usage to st specific driver.

- ST Pinctrl support:
- fixed few typos in the documentation.
- moved some of the retime offset information to driver.

- STixxxx Support:
- all the SOC support code is moved to mach-stixxxx
- seperated DEBUG_LL code to new patch.
- removed unnecessary #interrupt-cells
- renamed uart to serial
- moved to multi_v7_defconfig
- used menuconfig in mach-stixxx/Kconfig
- removed of_platform_populate as generic code does it for you.
- scu address is ioremaped.

Thanks,
srini

Srinivas Kandagatla (10):
serial:st-asc: Add ST ASC driver.
regmap: Add regmap_field APIs
mfd:stixxxx-syscfg: Add ST System Configuration support.
pinctrl:stixxxx: Add pinctrl and pinconf support.
ARM:stixxxx: Add STiH415 SOC support
ARM:stixxxx: Add STiH416 SOC support
ARM:stixxxx: Add DEBUG_LL console support
ARM:stixxxx: Add stixxxx options to multi_v7_defconfig
ARM:stih41x: Add B2000 board support
ARM:stih41x: Add B2020 board support

Stuart Menefy (1):
clocksource:global_timer: Add ARM global timer support.

Documentation/arm/stixxxx/overview.txt | 33 +
Documentation/arm/stixxxx/stih415-overview.txt | 12 +
Documentation/arm/stixxxx/stih416-overview.txt | 12 +
.../devicetree/bindings/arm/global_timer.txt | 21 +
.../devicetree/bindings/mfd/stixxxx-syscfg.txt | 18 +
.../bindings/pinctrl/pinctrl-stixxxx.txt | 116 ++
.../devicetree/bindings/tty/serial/st-asc.txt | 18 +
MAINTAINERS | 11 +
arch/arm/Kconfig | 2 +
arch/arm/Kconfig.debug | 38 +
arch/arm/Makefile | 1 +
arch/arm/boot/dts/Makefile | 4 +
arch/arm/boot/dts/stih415-b2000.dts | 15 +
arch/arm/boot/dts/stih415-b2020.dts | 15 +
arch/arm/boot/dts/stih415-clock.dtsi | 38 +
arch/arm/boot/dts/stih415-pinctrl.dtsi | 326 ++++++
arch/arm/boot/dts/stih415.dtsi | 102 ++
arch/arm/boot/dts/stih416-b2000.dts | 16 +
arch/arm/boot/dts/stih416-b2020.dts | 16 +
arch/arm/boot/dts/stih416-clock.dtsi | 41 +
arch/arm/boot/dts/stih416-pinctrl.dtsi | 377 ++++++
arch/arm/boot/dts/stih416.dtsi | 111 ++
arch/arm/boot/dts/stih41x-b2000.dtsi | 41 +
arch/arm/boot/dts/stih41x-b2020.dtsi | 42 +
arch/arm/boot/dts/stih41x.dtsi | 38 +
arch/arm/boot/dts/stixxxx-pincfg.h | 94 ++
arch/arm/configs/multi_v7_defconfig | 32 +-
arch/arm/include/debug/stixxxx.S | 61 +
arch/arm/mach-stixxxx/Kconfig | 45 +
arch/arm/mach-stixxxx/Makefile | 2 +
arch/arm/mach-stixxxx/board-dt.c | 50 +
arch/arm/mach-stixxxx/headsmp.S | 44 +
arch/arm/mach-stixxxx/platsmp.c | 117 ++
arch/arm/mach-stixxxx/smp.h | 19 +
drivers/base/regmap/internal.h | 8 +
drivers/base/regmap/regmap.c | 104 ++
drivers/clocksource/Kconfig | 13 +
drivers/clocksource/Makefile | 1 +
drivers/clocksource/arm_global_timer.c | 368 ++++++
drivers/mfd/Kconfig | 10 +
drivers/mfd/Makefile | 1 +
drivers/mfd/stixxxx-syscfg.c | 168 +++
drivers/pinctrl/Kconfig | 11 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/pinctrl-stixxxx.c | 1212 ++++++++++++++++++++
drivers/pinctrl/pinctrl-stixxxx.h | 197 ++++
drivers/tty/serial/Kconfig | 16 +
drivers/tty/serial/Makefile | 1 +
drivers/tty/serial/st-asc.c | 911 +++++++++++++++
include/linux/mfd/stixxxx-syscfg.h | 15 +
include/linux/regmap.h | 42 +
include/uapi/linux/serial_core.h | 3 +
52 files changed, 4993 insertions(+), 17 deletions(-)
create mode 100644 Documentation/arm/stixxxx/overview.txt
create mode 100644 Documentation/arm/stixxxx/stih415-overview.txt
create mode 100644 Documentation/arm/stixxxx/stih416-overview.txt
create mode 100644 Documentation/devicetree/bindings/arm/global_timer.txt
create mode 100644 Documentation/devicetree/bindings/mfd/stixxxx-syscfg.txt
create mode 100644 Documentation/devicetree/bindings/pinctrl/pinctrl-stixxxx.txt
create mode 100644 Documentation/devicetree/bindings/tty/serial/st-asc.txt
create mode 100644 arch/arm/boot/dts/stih415-b2000.dts
create mode 100644 arch/arm/boot/dts/stih415-b2020.dts
create mode 100644 arch/arm/boot/dts/stih415-clock.dtsi
create mode 100644 arch/arm/boot/dts/stih415-pinctrl.dtsi
create mode 100644 arch/arm/boot/dts/stih415.dtsi
create mode 100644 arch/arm/boot/dts/stih416-b2000.dts
create mode 100644 arch/arm/boot/dts/stih416-b2020.dts
create mode 100644 arch/arm/boot/dts/stih416-clock.dtsi
create mode 100644 arch/arm/boot/dts/stih416-pinctrl.dtsi
create mode 100644 arch/arm/boot/dts/stih416.dtsi
create mode 100644 arch/arm/boot/dts/stih41x-b2000.dtsi
create mode 100644 arch/arm/boot/dts/stih41x-b2020.dtsi
create mode 100644 arch/arm/boot/dts/stih41x.dtsi
create mode 100644 arch/arm/boot/dts/stixxxx-pincfg.h
create mode 100644 arch/arm/include/debug/stixxxx.S
create mode 100644 arch/arm/mach-stixxxx/Kconfig
create mode 100644 arch/arm/mach-stixxxx/Makefile
create mode 100644 arch/arm/mach-stixxxx/board-dt.c
create mode 100644 arch/arm/mach-stixxxx/headsmp.S
create mode 100644 arch/arm/mach-stixxxx/platsmp.c
create mode 100644 arch/arm/mach-stixxxx/smp.h
create mode 100644 drivers/clocksource/arm_global_timer.c
create mode 100644 drivers/mfd/stixxxx-syscfg.c
create mode 100644 drivers/pinctrl/pinctrl-stixxxx.c
create mode 100644 drivers/pinctrl/pinctrl-stixxxx.h
create mode 100644 drivers/tty/serial/st-asc.c
create mode 100644 include/linux/mfd/stixxxx-syscfg.h

--
1.7.6.5


2013-06-10 09:23:44

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: [PATCH v2 01/11] serial:st-asc: Add ST ASC driver.

This patch adds support to ASC (asynchronous serial controller)
driver, which is basically a standard serial driver. This IP is common
across all the ST parts for settop box platforms.

ASC is embedded in ST COMMS IP block. It supports Rx & Tx functionality.
It support all industry standard baud rates.

Signed-off-by: Srinivas Kandagatla <[email protected]>
CC: Stephen Gallimore <[email protected]>
CC: Stuart Menefy <[email protected]>
CC: Arnd Bergmann <[email protected]>
CC: Greg Kroah-Hartman <[email protected]>
---
.../devicetree/bindings/tty/serial/st-asc.txt | 18 +
drivers/tty/serial/Kconfig | 16 +
drivers/tty/serial/Makefile | 1 +
drivers/tty/serial/st-asc.c | 911 ++++++++++++++++++++
include/uapi/linux/serial_core.h | 3 +
5 files changed, 949 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/tty/serial/st-asc.txt
create mode 100644 drivers/tty/serial/st-asc.c

diff --git a/Documentation/devicetree/bindings/tty/serial/st-asc.txt b/Documentation/devicetree/bindings/tty/serial/st-asc.txt
new file mode 100644
index 0000000..75d877f
--- /dev/null
+++ b/Documentation/devicetree/bindings/tty/serial/st-asc.txt
@@ -0,0 +1,18 @@
+*st-asc(Serial Port)
+
+Required properties:
+- compatible : Should be "st,asc".
+- reg, reg-names, interrupts, interrupt-names : Standard way to define device
+ resources with names. look in
+ Documentation/devicetree/bindings/resource-names.txt
+
+Optional properties:
+- st,hw-flow-ctrl bool flag to enable hardware flow control.
+- st,force-m1 bool flat to force asc to be in Mode-1 recommeded
+ for high bit rates (above 19.2K)
+Example:
+serial@fe440000{
+ compatible = "st,asc";
+ reg = <0xfe440000 0x2c>;
+ interrupts = <0 209 0>;
+};
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 7e7006f..0c6ddf6 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1484,6 +1484,22 @@ config SERIAL_RP2_NR_UARTS
If multiple cards are present, the default limit of 32 ports may
need to be increased.

+config SERIAL_ST_ASC
+ tristate "ST ASC serial port support"
+ select SERIAL_CORE
+ help
+ This driver is for the on-chip Asychronous Serial Controller on
+ STMicroelectronics STixxxx SoCs.
+ ASC is embedded in ST COMMS IP block. It supports Rx & Tx functionality.
+ It support all industry standard baud rates.
+
+ If unsure, say N.
+
+config SERIAL_ST_ASC_CONSOLE
+ bool "Support for console on ST ASC"
+ depends on SERIAL_ST_ASC=y
+ select SERIAL_CORE_CONSOLE
+
endmenu

endif # TTY
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index eedfec4..536ccc7 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_SERIAL_KGDB_NMI) += kgdb_nmi.o
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
+obj-$(CONFIG_SERIAL_ST_ASC) += st-asc.o
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
new file mode 100644
index 0000000..6592c04
--- /dev/null
+++ b/drivers/tty/serial/st-asc.c
@@ -0,0 +1,911 @@
+/*
+ * st-asc.c: ST Asynchronous serial controller (ASC) driver
+ *
+ * Copyright (C) 2003-2013 STMicroelectronics (R&D) Limited
+ *
+ * This program 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.
+ *
+ */
+
+#if defined(CONFIG_SERIAL_ST_ASC_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 "st-asc"
+#define ASC_SERIAL_NAME "ttyAS"
+#define ASC_FIFO_SIZE 16
+#define ASC_MAX_PORTS 8
+
+struct asc_port {
+ struct uart_port port;
+ struct clk *clk;
+ unsigned int hw_flow_control:1;
+ unsigned int check_parity:1;
+ unsigned int force_m1:1;
+};
+
+static struct asc_port asc_ports[ASC_MAX_PORTS];
+static struct uart_driver asc_uart_driver;
+
+/*---- UART Register definitions ------------------------------*/
+
+/* Register offsets */
+
+#define ASC_BAUDRATE 0x00
+#define ASC_TXBUF 0x04
+#define ASC_RXBUF 0x08
+#define ASC_CTL 0x0C
+#define ASC_INTEN 0x10
+#define ASC_STA 0x14
+#define ASC_GUARDTIME 0x18
+#define ASC_TIMEOUT 0x1C
+#define ASC_TXRESET 0x20
+#define ASC_RXRESET 0x24
+#define ASC_RETRIES 0x28
+
+/* ASC_RXBUF */
+#define ASC_RXBUF_PE 0x100
+#define ASC_RXBUF_FE 0x200
+
+/* ASC_CTL */
+
+#define ASC_CTL_MODE_MSK 0x0007
+#define ASC_CTL_MODE_8BIT 0x0001
+#define ASC_CTL_MODE_7BIT_PAR 0x0003
+#define ASC_CTL_MODE_9BIT 0x0004
+#define ASC_CTL_MODE_8BIT_WKUP 0x0005
+#define ASC_CTL_MODE_8BIT_PAR 0x0007
+#define ASC_CTL_STOP_MSK 0x0018
+#define ASC_CTL_STOP_HALFBIT 0x0000
+#define ASC_CTL_STOP_1BIT 0x0008
+#define ASC_CTL_STOP_1_HALFBIT 0x0010
+#define ASC_CTL_STOP_2BIT 0x0018
+#define ASC_CTL_PARITYODD 0x0020
+#define ASC_CTL_LOOPBACK 0x0040
+#define ASC_CTL_RUN 0x0080
+#define ASC_CTL_RXENABLE 0x0100
+#define ASC_CTL_SCENABLE 0x0200
+#define ASC_CTL_FIFOENABLE 0x0400
+#define ASC_CTL_CTSENABLE 0x0800
+#define ASC_CTL_BAUDMODE 0x1000
+
+/* ASC_GUARDTIME */
+
+#define ASC_GUARDTIME_MSK 0x00FF
+
+/* ASC_INTEN */
+
+#define ASC_INTEN_RBE 0x0001
+#define ASC_INTEN_TE 0x0002
+#define ASC_INTEN_THE 0x0004
+#define ASC_INTEN_PE 0x0008
+#define ASC_INTEN_FE 0x0010
+#define ASC_INTEN_OE 0x0020
+#define ASC_INTEN_TNE 0x0040
+#define ASC_INTEN_TOI 0x0080
+#define ASC_INTEN_RHF 0x0100
+
+/* ASC_RETRIES */
+
+#define ASC_RETRIES_MSK 0x00FF
+
+/* ASC_RXBUF */
+
+#define ASC_RXBUF_MSK 0x03FF
+
+/* ASC_STA */
+
+#define ASC_STA_RBF 0x0001
+#define ASC_STA_TE 0x0002
+#define ASC_STA_THE 0x0004
+#define ASC_STA_PE 0x0008
+#define ASC_STA_FE 0x0010
+#define ASC_STA_OE 0x0020
+#define ASC_STA_TNE 0x0040
+#define ASC_STA_TOI 0x0080
+#define ASC_STA_RHF 0x0100
+#define ASC_STA_TF 0x0200
+#define ASC_STA_NKD 0x0400
+
+/* ASC_TIMEOUT */
+
+#define ASC_TIMEOUT_MSK 0x00FF
+
+/* ASC_TXBUF */
+
+#define ASC_TXBUF_MSK 0x01FF
+
+/*---- Inline function definitions ---------------------------*/
+
+static inline struct asc_port *to_asc_port(struct uart_port *port)
+{
+ return container_of(port, struct asc_port, port);
+}
+
+static inline u32 asc_in(struct uart_port *port, u32 offset)
+{
+ return readl(port->membase + offset);
+}
+
+static inline void asc_out(struct uart_port *port, u32 offset, u32 value)
+{
+ writel(value, port->membase + offset);
+}
+
+/*
+ * Some simple utility functions to enable and disable interrupts.
+ * Note that these need to be called with interrupts disabled.
+ */
+static inline void asc_disable_tx_interrupts(struct uart_port *port)
+{
+ u32 intenable = asc_in(port, ASC_INTEN) & ~ASC_INTEN_THE;
+ asc_out(port, ASC_INTEN, intenable);
+ (void)asc_in(port, ASC_INTEN); /* Defeat bus write posting */
+}
+
+static inline void asc_enable_tx_interrupts(struct uart_port *port)
+{
+ u32 intenable = asc_in(port, ASC_INTEN) | ASC_INTEN_THE;
+ asc_out(port, ASC_INTEN, intenable);
+}
+
+static inline void asc_disable_rx_interrupts(struct uart_port *port)
+{
+ u32 intenable = asc_in(port, ASC_INTEN) & ~ASC_INTEN_RBE;
+ asc_out(port, ASC_INTEN, intenable);
+ (void)asc_in(port, ASC_INTEN); /* Defeat bus write posting */
+}
+
+static inline void asc_enable_rx_interrupts(struct uart_port *port)
+{
+ u32 intenable = asc_in(port, ASC_INTEN) | ASC_INTEN_RBE;
+ asc_out(port, ASC_INTEN, intenable);
+}
+
+static inline u32 asc_txfifo_is_empty(struct uart_port *port)
+{
+ return asc_in(port, ASC_STA) & ASC_STA_TE;
+}
+
+static inline int asc_txfifo_is_full(struct uart_port *port)
+{
+ return asc_in(port, ASC_STA) & ASC_STA_TF;
+}
+
+static inline const char *asc_port_name(struct uart_port *port)
+{
+ return to_platform_device(port->dev)->name;
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * This section contains code to support the use of the ASC as a
+ * generic serial port.
+ */
+
+static inline unsigned asc_hw_txroom(struct uart_port *port)
+{
+ u32 status = asc_in(port, ASC_STA);
+
+ if (status & ASC_STA_THE)
+ return port->fifosize / 2;
+ else if (!(status & ASC_STA_TF))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Start transmitting chars.
+ * This is called from both interrupt and task level.
+ * Either way interrupts are disabled.
+ */
+static void asc_transmit_chars(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+ int txroom;
+ unsigned char c;
+
+ txroom = asc_hw_txroom(port);
+
+ if ((txroom != 0) && port->x_char) {
+ c = port->x_char;
+ port->x_char = 0;
+ asc_out(port, ASC_TXBUF, c);
+ port->icount.tx++;
+ txroom = asc_hw_txroom(port);
+ }
+
+ if (uart_tx_stopped(port)) {
+ /*
+ * We should try and stop the hardware here, but I
+ * don't think the ASC has any way to do that.
+ */
+ asc_disable_tx_interrupts(port);
+ return;
+ }
+
+ if (uart_circ_empty(xmit)) {
+ asc_disable_tx_interrupts(port);
+ return;
+ }
+
+ if (txroom == 0)
+ return;
+
+ do {
+ c = xmit->buf[xmit->tail];
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ asc_out(port, ASC_TXBUF, c);
+ port->icount.tx++;
+ txroom--;
+ } while ((txroom > 0) && (!uart_circ_empty(xmit)));
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ if (uart_circ_empty(xmit))
+ asc_disable_tx_interrupts(port);
+}
+
+static void asc_receive_chars(struct uart_port *port)
+{
+ int count;
+ struct asc_port *ascport = to_asc_port(port);
+ struct tty_port *tport = &port->state->port;
+ int copied = 0;
+ unsigned long status;
+ unsigned long c = 0;
+ char flag;
+ int overrun;
+
+ if (port->irq_wake)
+ pm_wakeup_event(tport->tty->dev, 0);
+
+ while (1) {
+ status = asc_in(port, ASC_STA);
+ if (status & ASC_STA_RHF)
+ count = port->fifosize / 2;
+ else if (status & ASC_STA_RBF)
+ count = 1;
+ else
+ break;
+
+ /*
+ * Check for overrun before reading any data from the
+ * RX FIFO, as this clears the overflow error condition.
+ */
+ overrun = status & ASC_STA_OE;
+
+ for (; count != 0; count--) {
+ c = asc_in(port, ASC_RXBUF);
+ flag = TTY_NORMAL;
+ port->icount.rx++;
+
+ if (unlikely(c & ASC_RXBUF_FE)) {
+ if (c == ASC_RXBUF_FE) {
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ continue;
+ flag = TTY_BREAK;
+ } else {
+ port->icount.frame++;
+ flag = TTY_FRAME;
+ }
+ } else if (ascport->check_parity &&
+ unlikely(c & ASC_RXBUF_PE)) {
+ port->icount.parity++;
+ flag = TTY_PARITY;
+ }
+
+ if (uart_handle_sysrq_char(port, c))
+ continue;
+ tty_insert_flip_char(tport, c & 0xff, flag);
+ }
+ if (overrun) {
+ port->icount.overrun++;
+ tty_insert_flip_char(tport, 0, TTY_OVERRUN);
+ }
+
+ copied = 1;
+ }
+
+ if (copied) {
+ /* Tell the rest of the system the news. New characters! */
+ tty_flip_buffer_push(tport);
+ }
+}
+
+static irqreturn_t asc_interrupt(int irq, void *ptr)
+{
+ struct uart_port *port = ptr;
+ u32 status;
+
+ spin_lock(&port->lock);
+
+ status = asc_in(port, ASC_STA);
+
+ if (status & ASC_STA_RBF) {
+ /* Receive FIFO not empty */
+ asc_receive_chars(port);
+ }
+
+ if ((status & ASC_STA_THE) &&
+ (asc_in(port, ASC_INTEN) & ASC_INTEN_THE)) {
+ /* Transmitter FIFO at least half empty */
+ asc_transmit_chars(port);
+ }
+
+ spin_unlock(&port->lock);
+
+ return IRQ_HANDLED;
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * UART Functions
+ */
+
+static unsigned int asc_tx_empty(struct uart_port *port)
+{
+ return asc_txfifo_is_empty(port) ? TIOCSER_TEMT : 0;
+}
+
+static void asc_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ /*
+ * This routine is used for seting signals of: DTR, DCD, CTS/RTS
+ * We use ASC'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 asc_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 asc_start_tx(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+
+ if (!uart_circ_empty(xmit))
+ asc_enable_tx_interrupts(port);
+}
+
+/* Transmit stop */
+static void asc_stop_tx(struct uart_port *port)
+{
+ asc_disable_tx_interrupts(port);
+}
+
+/* Receive stop */
+static void asc_stop_rx(struct uart_port *port)
+{
+ asc_disable_rx_interrupts(port);
+}
+
+/* Force modem status interrupts on */
+static void asc_enable_ms(struct uart_port *port)
+{
+ /* Nothing here yet .. */
+}
+
+/* Handle breaks - ignored by us */
+static void asc_break_ctl(struct uart_port *port, int break_state)
+{
+ /* Nothing here yet .. */
+}
+
+/*
+ * Enable port for reception.
+ */
+static int asc_startup(struct uart_port *port)
+{
+ if (request_irq(port->irq, asc_interrupt, IRQF_NO_SUSPEND,
+ asc_port_name(port), port)) {
+ dev_err(port->dev, "cannot allocate irq.\n");
+ return -ENODEV;
+ }
+
+ asc_transmit_chars(port);
+ asc_enable_rx_interrupts(port);
+
+ return 0;
+}
+
+static void asc_shutdown(struct uart_port *port)
+{
+ asc_disable_tx_interrupts(port);
+ asc_disable_rx_interrupts(port);
+ free_irq(port->irq, port);
+}
+
+static void asc_pm(struct uart_port *port, unsigned int state,
+ unsigned int oldstate)
+{
+ struct asc_port *ascport = to_asc_port(port);
+ unsigned long flags = 0;
+ u32 ctl;
+
+ switch (state) {
+ case UART_PM_STATE_ON:
+ clk_prepare_enable(ascport->clk);
+ break;
+ case UART_PM_STATE_OFF:
+ /*
+ * Disable the ASC baud rate generator, which is as close as
+ * we can come to turning it off. Note this is not called with
+ * the port spinlock held.
+ */
+ spin_lock_irqsave(&port->lock, flags);
+ ctl = asc_in(port, ASC_CTL) & ~ASC_CTL_RUN;
+ asc_out(port, ASC_CTL, ctl);
+ spin_unlock_irqrestore(&port->lock, flags);
+ clk_disable_unprepare(ascport->clk);
+ break;
+ }
+}
+
+static void asc_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ struct asc_port *ascport = to_asc_port(port);
+ unsigned int baud;
+ u32 ctrl_val;
+ tcflag_t cflag;
+ unsigned long flags;
+
+ port->uartclk = clk_get_rate(ascport->clk);
+
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+ cflag = termios->c_cflag;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* read control register */
+ ctrl_val = asc_in(port, ASC_CTL);
+
+ /* stop serial port and reset value */
+ asc_out(port, ASC_CTL, (ctrl_val & ~ASC_CTL_RUN));
+ ctrl_val = ASC_CTL_RXENABLE | ASC_CTL_FIFOENABLE;
+
+ /* reset fifo rx & tx */
+ asc_out(port, ASC_TXRESET, 1);
+ asc_out(port, ASC_RXRESET, 1);
+
+ /* set character length */
+ if ((cflag & CSIZE) == CS7) {
+ ctrl_val |= ASC_CTL_MODE_7BIT_PAR;
+ } else {
+ ctrl_val |= (cflag & PARENB) ? ASC_CTL_MODE_8BIT_PAR :
+ ASC_CTL_MODE_8BIT;
+ }
+
+ ascport->check_parity = (cflag & PARENB) ? 1 : 0;
+
+ /* set stop bit */
+ ctrl_val |= (cflag & CSTOPB) ? ASC_CTL_STOP_2BIT : ASC_CTL_STOP_1BIT;
+
+ /* odd parity */
+ if (cflag & PARODD)
+ ctrl_val |= ASC_CTL_PARITYODD;
+
+ /* hardware flow control */
+ if ((cflag & CRTSCTS) && ascport->hw_flow_control)
+ ctrl_val |= ASC_CTL_CTSENABLE;
+
+ if ((baud < 19200) && !ascport->force_m1) {
+ asc_out(port, ASC_BAUDRATE, (port->uartclk / (16 * baud)));
+ } else {
+ /*
+ * MODE 1: recommended for high bit rates (above 19.2K)
+ *
+ * baudrate * 16 * 2^16
+ * ASCBaudRate = ------------------------
+ * inputclock
+ *
+ * However to keep the maths inside 32bits we divide top and
+ * bottom by 64. The +1 is to avoid a divide by zero if the
+ * input clock rate is something unexpected.
+ */
+ u32 counter = (baud * 16384) / ((port->uartclk / 64) + 1);
+ asc_out(port, ASC_BAUDRATE, counter);
+ ctrl_val |= ASC_CTL_BAUDMODE;
+ }
+
+ uart_update_timeout(port, cflag, baud);
+
+ /* Set the timeout */
+ asc_out(port, ASC_TIMEOUT, 20);
+
+ /* write final value and enable port */
+ asc_out(port, ASC_CTL, (ctrl_val | ASC_CTL_RUN));
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *asc_type(struct uart_port *port)
+{
+ return (port->type == PORT_ASC) ? DRIVER_NAME : NULL;
+}
+
+static void asc_release_port(struct uart_port *port)
+{
+}
+
+static int asc_request_port(struct uart_port *port)
+{
+ return 0;
+}
+
+/*
+ * Called when the port is opened, and UPF_BOOT_AUTOCONF flag is set
+ * Set type field if successful
+ */
+static void asc_config_port(struct uart_port *port, int flags)
+{
+ if ((flags & UART_CONFIG_TYPE))
+ port->type = PORT_ASC;
+}
+
+static int
+asc_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ /* No user changeable parameters */
+ return -EINVAL;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+/*
+ * Console polling routines for writing and reading from the uart while
+ * in an interrupt or debug context (i.e. kgdb).
+ */
+
+static int asc_get_poll_char(struct uart_port *port)
+{
+ if (!(asc_in(port, ASC_STA) & ASC_STA_RBF))
+ return NO_POLL_CHAR;
+
+ return asc_in(port, ASC_RXBUF);
+}
+
+static void asc_put_poll_char(struct uart_port *port, unsigned char c)
+{
+ while (asc_txfifo_is_full(port))
+ cpu_relax();
+ asc_out(port, ASC_TXBUF, c);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
+/*---------------------------------------------------------------------*/
+
+static struct uart_ops asc_uart_ops = {
+ .tx_empty = asc_tx_empty,
+ .set_mctrl = asc_set_mctrl,
+ .get_mctrl = asc_get_mctrl,
+ .start_tx = asc_start_tx,
+ .stop_tx = asc_stop_tx,
+ .stop_rx = asc_stop_rx,
+ .enable_ms = asc_enable_ms,
+ .break_ctl = asc_break_ctl,
+ .startup = asc_startup,
+ .shutdown = asc_shutdown,
+ .set_termios = asc_set_termios,
+ .type = asc_type,
+ .release_port = asc_release_port,
+ .request_port = asc_request_port,
+ .config_port = asc_config_port,
+ .verify_port = asc_verify_port,
+ .pm = asc_pm,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = asc_get_poll_char,
+ .poll_put_char = asc_put_poll_char,
+#endif /* CONFIG_CONSOLE_POLL */
+};
+
+static int asc_init_port(struct asc_port *ascport,
+ struct platform_device *pdev)
+{
+ struct uart_port *port = &ascport->port;
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get io resource\n");
+ return -ENODEV;
+ }
+
+ port->iotype = UPIO_MEM;
+ port->flags = UPF_BOOT_AUTOCONF;
+ port->ops = &asc_uart_ops;
+ port->fifosize = ASC_FIFO_SIZE;
+ port->dev = &pdev->dev;
+ port->mapbase = res->start;
+ port->irq = platform_get_irq(pdev, 0);
+
+ port->membase = devm_request_and_ioremap(&pdev->dev, res);
+ if (!port->membase) {
+ dev_err(&pdev->dev, "Unable to request io memory\n");
+ return -ENODEV;
+ }
+
+ spin_lock_init(&port->lock);
+
+ ascport->clk = devm_clk_get(&pdev->dev, NULL);
+
+ if (WARN_ON(IS_ERR(ascport->clk)))
+ return -EINVAL;
+ /* ensure that clk rate is correct by enabling the clk */
+ clk_prepare_enable(ascport->clk);
+ ascport->port.uartclk = clk_get_rate(ascport->clk);
+ WARN_ON(ascport->port.uartclk == 0);
+ clk_disable_unprepare(ascport->clk);
+
+ return 0;
+}
+
+static struct asc_port *asc_of_get_asc_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, ASC_SERIAL_NAME);
+ if (WARN_ON(id >= ASC_MAX_PORTS))
+ return NULL;
+
+ asc_ports[id].hw_flow_control = of_property_read_bool(np,
+ "st,hw-flow-control");
+ asc_ports[id].force_m1 = of_property_read_bool(np, "st,force_m1");
+ asc_ports[id].port.line = id;
+ return &asc_ports[id];
+}
+
+static struct of_device_id asc_match[] = {
+ { .compatible = "st,asc", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, asc_match);
+
+static int asc_serial_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct asc_port *ascport;
+
+ ascport = asc_of_get_asc_port(pdev);
+ if (!ascport)
+ return -ENODEV;
+
+ ret = asc_init_port(ascport, pdev);
+ if (ret)
+ return ret;
+
+ ret = uart_add_one_port(&asc_uart_driver, &ascport->port);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, &ascport->port);
+
+ return 0;
+}
+
+static int asc_serial_remove(struct platform_device *pdev)
+{
+ struct uart_port *port = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ return uart_remove_one_port(&asc_uart_driver, port);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int asc_serial_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct uart_port *port = platform_get_drvdata(pdev);
+
+ return uart_suspend_port(&asc_uart_driver, port);
+}
+
+static int asc_serial_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct uart_port *port = platform_get_drvdata(pdev);
+
+ if (pdev->dev.pins->default_state) {
+ if (pinctrl_select_state(pdev->dev.pins->p,
+ pdev->dev.pins->default_state) < 0)
+ return -EBUSY;
+ }
+
+ return uart_resume_port(&asc_uart_driver, port);
+}
+
+#endif /* CONFIG_PM_SLEEP */
+
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_SERIAL_ST_ASC_CONSOLE
+static void asc_console_putchar(struct uart_port *port, int ch)
+{
+ unsigned int timeout = 1000000;
+
+ /* Wait for upto 1 second in case flow control is stopping us. */
+ while (--timeout && asc_txfifo_is_full(port))
+ udelay(1);
+
+ asc_out(port, ASC_TXBUF, ch);
+}
+
+/*
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
+ */
+
+static void asc_console_write(struct console *co, const char *s, unsigned count)
+{
+ struct uart_port *port = &asc_ports[co->index].port;
+ unsigned long flags;
+ unsigned long timeout = 1000000;
+ int locked = 1;
+ u32 intenable;
+
+ local_irq_save(flags);
+ if (port->sysrq)
+ locked = 0; /* asc_interrupt has already claimed the lock */
+ else if (oops_in_progress)
+ locked = spin_trylock(&port->lock);
+ else
+ spin_lock(&port->lock);
+
+ /*
+ * Disable interrupts so we don't get the IRQ line bouncing
+ * up and down while interrupts are disabled.
+ */
+ intenable = asc_in(port, ASC_INTEN);
+ asc_out(port, ASC_INTEN, 0);
+ (void)asc_in(port, ASC_INTEN); /* Defeat bus write posting */
+
+ uart_console_write(port, s, count, asc_console_putchar);
+
+ while (--timeout && !asc_txfifo_is_empty(port))
+ udelay(1);
+
+ asc_out(port, ASC_INTEN, intenable);
+
+ if (locked)
+ spin_unlock(&port->lock);
+ local_irq_restore(flags);
+}
+
+static int asc_console_setup(struct console *co, char *options)
+{
+ struct asc_port *ascport;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (co->index >= ASC_MAX_PORTS)
+ return -ENODEV;
+
+ ascport = &asc_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.
+ */
+ BUG_ON(ascport->port.mapbase == 0 || ascport->port.membase == NULL);
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(&ascport->port, co, baud, parity, bits, flow);
+}
+
+static struct console asc_console = {
+ .name = ASC_SERIAL_NAME,
+ .device = uart_console_device,
+ .write = asc_console_write,
+ .setup = asc_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &asc_uart_driver,
+};
+
+#define ASC_SERIAL_CONSOLE (&asc_console)
+
+#else
+#define ASC_SERIAL_CONSOLE NULL
+#endif /* CONFIG_SERIAL_ST_ASC_CONSOLE */
+
+static struct uart_driver asc_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = DRIVER_NAME,
+ .dev_name = ASC_SERIAL_NAME,
+ .major = 0,
+ .minor = 0,
+ .nr = ASC_MAX_PORTS,
+ .cons = ASC_SERIAL_CONSOLE,
+};
+
+static const struct dev_pm_ops asc_serial_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(asc_serial_suspend, asc_serial_resume)
+};
+
+static struct platform_driver asc_serial_driver = {
+ .probe = asc_serial_probe,
+ .remove = asc_serial_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .pm = &asc_serial_pm_ops,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(asc_match),
+ },
+};
+
+static int __init asc_init(void)
+{
+ int ret;
+ static char banner[] __initdata =
+ KERN_INFO "STMicroelectronics ASC driver initialized\n";
+
+ printk(banner);
+
+ ret = uart_register_driver(&asc_uart_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&asc_serial_driver);
+ if (ret)
+ uart_unregister_driver(&asc_uart_driver);
+
+ return ret;
+}
+
+static void __exit asc_exit(void)
+{
+ platform_driver_unregister(&asc_serial_driver);
+ uart_unregister_driver(&asc_uart_driver);
+}
+
+module_init(asc_init);
+module_exit(asc_exit);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_AUTHOR("STMicroelectronics (R&D) Limited");
+MODULE_DESCRIPTION("STMicroelectronics ASC serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index 74c2bf7..ec80e01 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -226,4 +226,7 @@
/* Rocketport EXPRESS/INFINITY */
#define PORT_RP2 102

+/* ST ASC type numbers */
+#define PORT_ASC 103
+
#endif /* _UAPILINUX_SERIAL_CORE_H */
--
1.7.6.5

2013-06-10 09:24:28

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: [PATCH v2 02/11] clocksource:global_timer: Add ARM global timer support.

From: Stuart Menefy <[email protected]>

This is a simple driver for the global timer module found in the Cortex
A9-MP cores from revision r1p0 onwards. This should be able to perform
the functions of the system timer and the local timer in an SMP system.

The global timer has the following features:
The global timer is a 64-bit incrementing counter with an
auto-incrementing feature. It continues incrementing after sending
interrupts. The global timer is memory mapped in the private memory
region.
The global timer is accessible to all Cortex-A9 processors in the
cluster. Each Cortex-A9 processor has a private 64-bit comparator that
is used to assert a private interrupt when the global timer has reached
the comparator value. All the Cortex-A9 processors in a design use the
banked ID, ID27, for this interrupt. ID27 is sent to the Interrupt
Controller as a Private Peripheral Interrupt. The global timer is
clocked by PERIPHCLK.

Signed-off-by: Stuart Menefy <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
CC: Arnd Bergmann <[email protected]>
CC: Rob Herring <[email protected]>
CC: Linus Walleij <[email protected]>
CC: Will Deacon <[email protected]>
CC: Thomas Gleixner <[email protected]>
---
.../devicetree/bindings/arm/global_timer.txt | 21 ++
drivers/clocksource/Kconfig | 13 +
drivers/clocksource/Makefile | 1 +
drivers/clocksource/arm_global_timer.c | 368 ++++++++++++++++++++
4 files changed, 403 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/arm/global_timer.txt
create mode 100644 drivers/clocksource/arm_global_timer.c

diff --git a/Documentation/devicetree/bindings/arm/global_timer.txt b/Documentation/devicetree/bindings/arm/global_timer.txt
new file mode 100644
index 0000000..b64abac
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/global_timer.txt
@@ -0,0 +1,21 @@
+
+* ARM Global Timer
+ Cortex-A9 are often associated with a per-core Global timer.
+
+** Timer node required properties:
+
+- compatible : Should be "arm,cortex-a9-global-timer"
+ Driver supports versions r2p0 and above.
+
+- interrupts : One interrupt to each core
+
+- reg : Specify the base address and the size of the GT timer
+ register window.
+
+Example:
+
+ timer@2c000600 {
+ compatible = "arm,cortex-a9-global-timer";
+ reg = <0x2c000600 0x20>;
+ interrupts = <1 13 0xf01>;
+ };
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index f151c6c..b0c4c42 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -67,6 +67,19 @@ config ARM_ARCH_TIMER
bool
select CLKSRC_OF if OF

+config ARM_GLOBAL_TIMER
+ bool
+ select CLKSRC_OF if OF
+ help
+ This options enables support for the ARM global timer unit
+
+config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
+ bool
+ depends on ARM_GLOBAL_TIMER
+ default y
+ help
+ Use ARM global timer clock source as sched_clock
+
config CLKSRC_METAG_GENERIC
def_bool y if METAG
help
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 8d979c7..b2363cb 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -28,4 +28,5 @@ obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o
obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o

obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
+obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o
obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o
diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c
new file mode 100644
index 0000000..e4bc4fe
--- /dev/null
+++ b/drivers/clocksource/arm_global_timer.c
@@ -0,0 +1,368 @@
+/*
+ * drivers/clocksource/arm_global_timer.c
+ *
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Stuart Menefy <[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 <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+
+#include <asm/sched_clock.h>
+#include <asm/mach/irq.h>
+#include <asm/cputype.h>
+#include <asm/localtimer.h>
+
+#define GT_COUNTER0 0x00
+#define GT_COUNTER1 0x04
+
+#define GT_CONTROL 0x08
+#define GT_CONTROL_TIMER_ENABLE BIT(0) /* this bit is NOT banked */
+#define GT_CONTROL_COMP_ENABLE BIT(1) /* banked */
+#define GT_CONTROL_IRQ_ENABLE BIT(2) /* banked */
+#define GT_CONTROL_AUTO_INC BIT(3) /* banked */
+
+#define GT_INT_STATUS 0x0c
+#define GT_INT_STATUS_EVENT_FLAG BIT(0)
+
+#define GT_COMP0 0x10
+#define GT_COMP1 0x14
+#define GT_AUTO_INC 0x18
+
+/*
+ * We are expecting to be clocked by the ARM peripheral clock.
+ *
+ * Note: it is assumed we are using a prescaler value of zero, so this is
+ * the units for all operations.
+ */
+static void __iomem *gt_base;
+static unsigned long gt_clk_rate;
+static int gt_ppi;
+static struct clock_event_device __percpu **gt_evt;
+static DEFINE_PER_CPU(bool, percpu_init_called);
+static DEFINE_PER_CPU(struct clock_event_device, gt_clockevent);
+
+/*
+ * To get the value from the Global Timer Counter register proceed as follows:
+ * 1. Read the upper 32-bit timer counter register
+ * 2. Read the lower 32-bit timer counter register
+ * 3. Read the upper 32-bit timer counter register again. If the value is
+ * different to the 32-bit upper value read previously, go back to step 2.
+ * Otherwise the 64-bit timer counter value is correct.
+ */
+static u64 gt_counter_read(void)
+{
+ u64 counter;
+ u32 lower;
+ u32 upper, old_upper;
+
+ upper = __raw_readl(gt_base + GT_COUNTER1);
+ do {
+ old_upper = upper;
+ lower = __raw_readl(gt_base + GT_COUNTER0);
+ upper = __raw_readl(gt_base + GT_COUNTER1);
+ } while (upper != old_upper);
+
+ counter = upper;
+ counter <<= 32;
+ counter |= lower;
+ return counter;
+}
+
+/**
+ * To ensure that updates to comparator value register do not set the
+ * Interrupt Status Register proceed as follows:
+ * 1. Clear the Comp Enable bit in the Timer Control Register.
+ * 2. Write the lower 32-bit Comparator Value Register.
+ * 3. Write the upper 32-bit Comparator Value Register.
+ * 4. Set the Comp Enable bit and, if necessary, the IRQ enable bit.
+ */
+static void gt_compare_set(unsigned long delta, int periodic)
+{
+ u64 counter = gt_counter_read();
+ unsigned long ctrl = __raw_readl(gt_base + GT_CONTROL);
+
+ counter += delta;
+ ctrl &= ~(GT_CONTROL_COMP_ENABLE | GT_CONTROL_IRQ_ENABLE);
+
+ __raw_writel(ctrl, gt_base + GT_CONTROL);
+ __raw_writel(lower_32_bits(counter), gt_base + GT_COMP0);
+ __raw_writel(upper_32_bits(counter), gt_base + GT_COMP1);
+
+ if (periodic) {
+ __raw_writel(delta, gt_base + GT_AUTO_INC);
+ ctrl |= GT_CONTROL_AUTO_INC;
+ }
+
+ ctrl |= GT_CONTROL_COMP_ENABLE | GT_CONTROL_IRQ_ENABLE;
+ __raw_writel(ctrl, gt_base + GT_CONTROL);
+}
+
+static void gt_clockevent_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *clk)
+{
+ unsigned long ctrl;
+
+ ctrl = __raw_readl(gt_base + GT_CONTROL);
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ gt_compare_set(DIV_ROUND_CLOSEST(gt_clk_rate, HZ), 1);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ ctrl &= ~(GT_CONTROL_AUTO_INC);
+ __raw_writel(ctrl, gt_base + GT_CONTROL);
+ break;
+ /* Can not shut down it as enable bit is not banked */
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ ctrl &= ~(GT_CONTROL_COMP_ENABLE |
+ GT_CONTROL_IRQ_ENABLE | GT_CONTROL_AUTO_INC);
+ __raw_writel(ctrl, gt_base + GT_CONTROL);
+ break;
+ default:
+ break;
+ }
+}
+
+static int gt_clockevent_set_next_event(unsigned long evt,
+ struct clock_event_device *unused)
+{
+ gt_compare_set(evt, 0);
+ return 0;
+}
+
+static irqreturn_t gt_clockevent_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
+
+ if (__raw_readl(gt_base + GT_INT_STATUS) & GT_INT_STATUS_EVENT_FLAG) {
+ /**
+ * ERRATA 740657( Global Timer can send 2 interrupts for
+ * the same event in single-shot mode)
+ * Workaround:
+ * Either disable single-shot mode.
+ * Or
+ * Modify the Interrupt Handler to avoid the
+ * offending sequence. This is achieved by clearing
+ * the Global Timer flag _after_ having incremented
+ * the Comparator register value to a higher value.
+ */
+ if (!(__raw_readl(gt_base + GT_CONTROL) & GT_CONTROL_AUTO_INC))
+ gt_compare_set(ULONG_MAX, 0);
+
+ __raw_writel(GT_INT_STATUS_EVENT_FLAG, gt_base + GT_INT_STATUS);
+
+ evt->event_handler(evt);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int __cpuinit gt_clockevents_init(struct clock_event_device *clk)
+{
+ struct clock_event_device **this_cpu_clk;
+ int cpu = smp_processor_id();
+
+ clk->name = "ARM global timer clock event";
+ clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+ clk->set_mode = gt_clockevent_set_mode;
+ clk->set_next_event = gt_clockevent_set_next_event;
+ this_cpu_clk = __this_cpu_ptr(gt_evt);
+ *this_cpu_clk = clk;
+ clk->cpumask = cpumask_of(cpu);
+ clk->irq = gt_ppi;
+ clockevents_config_and_register(clk, gt_clk_rate,
+ 0, 0xffffffff);
+ per_cpu(percpu_init_called, cpu) = true;
+ enable_percpu_irq(clk->irq, IRQ_TYPE_NONE);
+ return 0;
+}
+
+static void gt_clockevents_stop(struct clock_event_device *clk)
+{
+ gt_clockevent_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
+ disable_percpu_irq(clk->irq);
+}
+
+static int __cpuinit gt_clockevents_setup(struct clock_event_device *clk)
+{
+ /* Use existing clock_event for boot cpu */
+ if (per_cpu(percpu_init_called, smp_processor_id()))
+ return 0;
+
+ /* already enabled in gt_clocksource_init. */
+ return gt_clockevents_init(clk);
+}
+
+static cycle_t gt_clocksource_read(struct clocksource *cs)
+{
+ return gt_counter_read();
+}
+
+static struct clocksource gt_clocksource = {
+ .name = "ARM global timer clock source",
+ .rating = 300,
+ .read = gt_clocksource_read,
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+#ifdef CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
+static u32 gt_sched_clock_read(void)
+{
+ if (!gt_base)
+ return 0;
+
+ return gt_counter_read();
+}
+#endif
+
+static void __init gt_clocksource_init(void)
+{
+ __raw_writel(0, gt_base + GT_CONTROL);
+ __raw_writel(0, gt_base + GT_COUNTER0);
+ __raw_writel(0, gt_base + GT_COUNTER1);
+ /* enables timer on all the cores */
+ __raw_writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
+
+#ifdef CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
+ setup_sched_clock(gt_sched_clock_read, 32, gt_clk_rate);
+#endif
+ clocksource_register_hz(&gt_clocksource, gt_clk_rate);
+}
+
+static struct clk *gt_get_clock(void)
+{
+ struct clk *clk;
+ int err;
+
+ clk = clk_get_sys("gt", NULL);
+ if (IS_ERR(clk)) {
+ pr_err("global-timer: clock not found: %ld\n", PTR_ERR(clk));
+ return clk;
+ }
+
+ err = clk_prepare_enable(clk);
+ if (err) {
+ pr_err("global-timer: clock prepare+enable failed: %d\n", err);
+ clk_put(clk);
+ return ERR_PTR(err);
+ }
+
+ return clk;
+}
+
+static struct local_timer_ops gt_lt_ops __cpuinitdata = {
+ .setup = gt_clockevents_setup,
+ .stop = gt_clockevents_stop,
+};
+
+int __init global_timer_init(void __iomem *base, unsigned int timer_irq)
+{
+ unsigned int cpu = smp_processor_id();
+ struct clock_event_device *evt = &per_cpu(gt_clockevent, cpu);
+ int err = 0;
+ struct clk *gt_clk;
+
+ if (gt_base) {
+ pr_warn("global-timer: invalid base address\n");
+ return -EINVAL;
+ }
+
+ gt_clk = gt_get_clock();
+ if (IS_ERR(gt_clk)) {
+ pr_warn("global-timer: clk not found\n");
+ return -EINVAL;
+ }
+
+ gt_evt = alloc_percpu(struct clock_event_device *);
+ if (!gt_evt) {
+ pr_warn("global-timer: can't allocate memory\n");
+ return -ENOMEM;
+ }
+
+ err = request_percpu_irq(timer_irq, gt_clockevent_interrupt,
+ "gt", gt_evt);
+ if (err) {
+ pr_warn("global-timer: can't register interrupt %d (%d)\n",
+ timer_irq, err);
+ goto out_free;
+ }
+
+ gt_base = base;
+ gt_clk_rate = clk_get_rate(gt_clk);
+ gt_ppi = timer_irq;
+ gt_clocksource_init();
+ gt_clockevents_init(evt);
+#ifdef CONFIG_LOCAL_TIMERS
+ err = local_timer_register(&gt_lt_ops);
+ if (err) {
+ pr_warn("global-timer: unable to register local timer.\n");
+ goto out_irq;
+ }
+#endif
+ return 0;
+
+out_irq:
+ free_percpu_irq(timer_irq, gt_evt);
+out_free:
+ free_percpu(gt_evt);
+ return err;
+}
+
+#ifdef CONFIG_OF
+static void __init global_timer_of_register(struct device_node *np)
+{
+ struct clk *clk;
+ int err = 0;
+ int gt_ppi;
+ static void __iomem *gt_base;
+
+ /*
+ * In r2p0 the comparators for each processor with the global timer
+ * fire when the timer value is greater than or equal to. In previous
+ * revisions the comparators fired when the timer value was equal to.
+ */
+ if ((read_cpuid_id() & 0xf0000f) < 0x200000)
+ goto out;
+
+ gt_ppi = irq_of_parse_and_map(np, 0);
+ if (!gt_ppi) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ gt_base = of_iomap(np, 0);
+ if (!gt_base) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ clk = of_clk_get(np, 0);
+ if (!IS_ERR(clk))
+ clk_register_clkdev(clk, NULL, "gt");
+
+ global_timer_init(gt_base, gt_ppi);
+
+out:
+ WARN(err, "Global timer register failed (%d)\n", err);
+}
+
+/* Only tested on r2p2 and r3p0 */
+CLOCKSOURCE_OF_DECLARE(arm_gt, "arm,cortex-a9-global-timer",
+ global_timer_of_register);
+#endif
--
1.7.6.5

2013-06-10 09:25:09

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: [PATCH v2 04/11] mfd:stixxxx-syscfg: Add ST System Configuration support.

System configuration(aka syscfg) registers are very basic configuration
registers arranged in groups across ST Settop Box parts.

The SOCs are assembled from existing IP blocks, which don't change very
often. However these blocks are assembled in different configurations to
meet the device requirements. So most IP blocks as well as having a bus
interface through which their own registers are accessible, will also
have a number of bristles(wires) which are signals that are going in and
out of the IP for configuration and status. To make these signals
accessible to software they are wired to "System Configuration
Registers".

Drivers target the IP blocks, which don't change much. Where as the
mapping of IP specific bristles(wires) to "System Configuration
Registers" do change per each SOC, and therefore we do not want this
information to be part of the driver.

Having a System Configuration infrastructure gives much flexibility and
abstraction to drivers to configure them. Typically in a SOC there will
be more than hundreds of these registers, which are again divided into
groups. The IP related config registers tend to much regular in latest
ST SOCs, so having a common place for configuring these registers makes
sense and avoid lot of code duplication.

This mfd driver provides higher level inialization routines for various
IPs like Ethernet, USB, PCIE, SATA and so on. Also it provides way to
get to syscfg registers via standard regmap api which is usefull for
drivers like pinctrl.

This patch adds support to ST System Configuration registers, which can
be configured by the drivers.

Signed-off-by: Srinivas Kandagatla <[email protected]>
CC: Stuart Menefy <[email protected]>
CC: Stephen Gallimore <[email protected]>
CC: Linus Walleij <[email protected]>
CC: Mark Brown <[email protected]>
---
.../devicetree/bindings/mfd/stixxxx-syscfg.txt | 18 ++
drivers/mfd/Kconfig | 10 ++
drivers/mfd/Makefile | 1 +
drivers/mfd/stixxxx-syscfg.c | 168 ++++++++++++++++++++
include/linux/mfd/stixxxx-syscfg.h | 15 ++
5 files changed, 212 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/mfd/stixxxx-syscfg.txt
create mode 100644 drivers/mfd/stixxxx-syscfg.c
create mode 100644 include/linux/mfd/stixxxx-syscfg.h

diff --git a/Documentation/devicetree/bindings/mfd/stixxxx-syscfg.txt b/Documentation/devicetree/bindings/mfd/stixxxx-syscfg.txt
new file mode 100644
index 0000000..428c751
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/stixxxx-syscfg.txt
@@ -0,0 +1,18 @@
+*STixxxx SYSCFG
+
+- compatible : should be "st,<SOC>-syscfg" like "st,stih415-syscfg"
+ or "st,stih416-syscfg".
+- reg, reg-names, interrupts, interrupt-names : Standard way to define device
+ resources with names. look in
+ Documentation/devicetree/bindings/resource-names.txt
+- syscfg-range <start size> : Should be syscfg number range for this bank.
+- syscfg-name : Should be name of the syscfg, will be used in debugfs.
+
+Example of a SBC_SYSCFG bank node:
+
+syscfg_sbc: syscfg@fe600000{
+ compatible = "st,stih415-syscfg";
+ reg = <0xfe600000 0xb4>;
+ syscfg-range = <0 44>;
+ syscfg-name = "SYSCFG_SBC";
+};
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index d54e985..af49b58 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -649,6 +649,16 @@ config MFD_STA2X11
select MFD_CORE
select REGMAP_MMIO

+config MFD_STIXXXX_SYSCFG
+ bool "ST System Configuration Registers(aka syscfg) via regmap"
+ select REGMAP_MMIO
+ help
+ Select this option to enable accessing STMicroelectronics
+ System Configuration Registers via standard regmap apis with
+ lookup helper functions.
+
+ If unsure, say N.
+
config MFD_SYSCON
bool "System Controller Register R/W Based on Regmap"
select REGMAP_MMIO
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 718e94a..c1f6570 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -150,6 +150,7 @@ obj-$(CONFIG_MFD_PALMAS) += palmas.o
obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o
+obj-$(CONFIG_MFD_STIXXXX_SYSCFG) += stixxxx-syscfg.o
obj-$(CONFIG_MFD_SYSCON) += syscon.o
obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o
obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o vexpress-sysreg.o
diff --git a/drivers/mfd/stixxxx-syscfg.c b/drivers/mfd/stixxxx-syscfg.c
new file mode 100644
index 0000000..10ea4e4
--- /dev/null
+++ b/drivers/mfd/stixxxx-syscfg.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics Limited
+ * Author: Srinivas Kandagatla <[email protected]>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Syscfg driver is used to configure various devices like Ethernet,
+ * USB, PCIE, SATA and so on.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/mfd/stixxxx-syscfg.h>
+
+#define DRIVER_NAME "stixxxx-syscfg"
+
+static struct platform_driver syscfg_driver;
+struct syscfg {
+ void __iomem *base;
+ struct regmap *regmap;
+ int start, end;
+ const char *name;
+ struct device_node *of_node;
+};
+
+static int syscfg_match_name(struct device *dev, void *data)
+{
+ struct syscfg *syscfg = dev_get_drvdata(dev);
+
+ if (syscfg)
+ if (!strcmp(syscfg->name, (const char *)data))
+ return 1;
+ return 0;
+}
+
+struct regmap *syscfg_regmap_lookup_by_name(const char *name)
+{
+ struct syscfg *syscfg;
+ struct device *dev;
+
+ dev = driver_find_device(&syscfg_driver.driver, NULL, (void *)name,
+ syscfg_match_name);
+ if (!dev)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ syscfg = dev_get_drvdata(dev);
+
+ return syscfg->regmap;
+}
+
+static int syscfg_match_node(struct device *dev, void *data)
+{
+ struct device_node *dn = data;
+
+ return (dev->of_node == dn) ? 1 : 0;
+}
+
+struct regmap *syscfg_node_to_regmap(struct device_node *np)
+{
+ struct syscfg *syscfg;
+ struct device *dev;
+
+ dev = driver_find_device(&syscfg_driver.driver, NULL, np,
+ syscfg_match_node);
+ if (!dev)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ syscfg = dev_get_drvdata(dev);
+
+ return syscfg->regmap;
+}
+EXPORT_SYMBOL_GPL(syscfg_node_to_regmap);
+
+struct regmap *syscfg_regmap_lookup_by_phandle(struct device_node *np,
+ const char *property)
+{
+ struct device_node *syscfg_np;
+ struct regmap *regmap;
+
+ syscfg_np = of_parse_phandle(np, property, 0);
+ if (!syscfg_np)
+ return ERR_PTR(-ENODEV);
+
+ regmap = syscfg_node_to_regmap(syscfg_np);
+ of_node_put(syscfg_np);
+
+ return regmap;
+}
+EXPORT_SYMBOL_GPL(syscfg_regmap_lookup_by_phandle);
+
+static struct regmap_config syscfg_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static int syscfg_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct syscfg *syscfg;
+ struct resource *res;
+ u32 range[2];
+
+ if (!np)
+ return -EINVAL;
+
+ syscfg = devm_kzalloc(&pdev->dev, sizeof(*syscfg), GFP_KERNEL);
+ if (!syscfg)
+ return -ENOMEM;
+
+ syscfg->of_node = np;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ syscfg->base = devm_request_and_ioremap(&pdev->dev, res);
+ if (!syscfg->base) {
+ dev_err(&pdev->dev, "Unable to ioremap registers|\n");
+ return -ENODATA;
+ }
+
+ of_property_read_u32_array(np, "syscfg-range", (u32 *)&range, 2);
+ syscfg->start = range[0];
+ syscfg->end = range[0] + range[1];
+ of_property_read_string(np, "syscfg-name", &syscfg->name);
+
+ syscfg_regmap_config.name = kasprintf(GFP_KERNEL, "%s", syscfg->name);
+ syscfg_regmap_config.max_register = res->end - res->start - 3;
+ syscfg->regmap = devm_regmap_init_mmio(&pdev->dev, syscfg->base,
+ &syscfg_regmap_config);
+ if (IS_ERR(syscfg->regmap)) {
+ dev_err(&pdev->dev, "regmap init failed\n");
+ return PTR_ERR(syscfg->regmap);
+ }
+
+ platform_set_drvdata(pdev, syscfg);
+ dev_info(&pdev->dev,
+ "%s[%d - %d] sucessfully intialized\n",
+ syscfg->name, syscfg->start, syscfg->end);
+ return 0;
+}
+
+static struct of_device_id syscfg_match[] = {
+ { .compatible = "st,stih415-syscfg", },
+ { .compatible = "st,stih416-syscfg", },
+ {},
+};
+
+static struct platform_driver syscfg_driver = {
+ .probe = syscfg_probe,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(syscfg_match),
+ },
+};
+
+static int __init syscfg_init(void)
+{
+ return platform_driver_register(&syscfg_driver);
+}
+postcore_initcall(syscfg_init);
diff --git a/include/linux/mfd/stixxxx-syscfg.h b/include/linux/mfd/stixxxx-syscfg.h
new file mode 100644
index 0000000..18ed6da7
--- /dev/null
+++ b/include/linux/mfd/stixxxx-syscfg.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics R&D Limited
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ */
+
+#ifndef __LINUX_MFD_STIXXXX_SYSCFG_H
+#define __LINUX_MFD_STIXXXX_SYSCFG_H
+
+struct regmap *syscfg_regmap_lookup_by_phandle(struct device_node *np,
+ const char *property);
+struct regmap *syscfg_regmap_lookup_by_name(const char *name);
+
+#endif /* __LINUX_MFD_STIXXXX_SYSCFG_H */
--
1.7.6.5

2013-06-10 09:25:17

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: [PATCH v2 03/11] regmap: Add regmap_field APIs

It is common to access regmap registers at bit level, using
regmap_update_bits or regmap_read functions, however the end user has to
take care of a mask or shifting. This becomes overhead when such use
cases are high. Having a common function to do this is much convenient
and less error prone.

The idea of regmap_field is simple, regmap_field gives a logical
structure to bits of the regmap register, and the driver can use this
logical entity without the knowledge of the bit postions and masks all
over the code. This way code looks much neat and it need not handle the
masks, shifts every time it access the those entities.

With this new regmap_field_read/write apis the end user can setup a
regmap field using regmap_field_init and use the return regmap_field to
read write the register field without worrying about the masks or
shifts.

Also this apis will be usefull for drivers which are based on regmaps,
like some clocks or pinctrls which can work on the regmap_fields
directly without having to worry about bit positions.

Signed-off-by: Srinivas Kandagatla <[email protected]>
CC: Mark Brown <[email protected]>
CC: Arnd Bergmann <[email protected]>
CC: Alexander Shiyan <[email protected]>
CC: Lars-Peter Clausen <[email protected]>
---
drivers/base/regmap/internal.h | 8 +++
drivers/base/regmap/regmap.c | 104 ++++++++++++++++++++++++++++++++++++++++
include/linux/regmap.h | 42 ++++++++++++++++
3 files changed, 154 insertions(+), 0 deletions(-)

diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index c130536..c5f6ebd 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -174,6 +174,14 @@ struct regmap_range_node {
unsigned int window_len;
};

+struct regmap_field {
+ struct regmap *regmap;
+ unsigned int mask;
+ /* lsb */
+ unsigned int shift;
+ unsigned int reg;
+};
+
#ifdef CONFIG_DEBUG_FS
extern void regmap_debugfs_initcall(void);
extern void regmap_debugfs_init(struct regmap *map, const char *name);
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index a941dcf..8d967cc 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -801,6 +801,67 @@ struct regmap *devm_regmap_init(struct device *dev,
}
EXPORT_SYMBOL_GPL(devm_regmap_init);

+static void regmap_field_init(struct regmap_field *rm_field,
+ struct regmap *regmap, struct reg_field reg_field)
+{
+ int field_bits = reg_field.msb - reg_field.lsb + 1;
+ rm_field->regmap = regmap;
+ rm_field->reg = reg_field.reg;
+ rm_field->shift = reg_field.lsb;
+ rm_field->mask = ((BIT(field_bits) - 1) << reg_field.lsb);
+}
+
+/**
+ * devm_regmap_field_alloc(): Allocate and initialise a register field
+ * in a register map.
+ *
+ * @dev: Device that will be interacted with
+ * @regmap: regmap bank in which this register field is located.
+ * @reg_field: Register field with in the bank.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap_field. The regmap_field will be automatically freed
+ * by the device management code.
+ */
+struct regmap_field *devm_regmap_field_alloc(struct device *dev,
+ struct regmap *regmap, struct reg_field reg_field)
+{
+ struct regmap_field *rm_field = devm_kzalloc(dev,
+ sizeof(*rm_field), GFP_KERNEL);
+ if (!rm_field)
+ return ERR_PTR(-ENOMEM);
+
+ regmap_field_init(rm_field, regmap, reg_field);
+
+ return rm_field;
+
+}
+EXPORT_SYMBOL_GPL(devm_regmap_field_alloc);
+/**
+ * regmap_field_alloc(): Allocate and initialise a register field
+ * in a register map.
+ *
+ * @regmap: regmap bank in which this register field is located.
+ * @reg_field: Register field with in the bank.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap_field. The regmap_field should be freed by the
+ * user once its finished working with it using regmap_field_free().
+ */
+struct regmap_field *regmap_field_alloc(struct regmap *regmap,
+ struct reg_field reg_field)
+{
+ struct regmap_field *rm_field = kzalloc(sizeof(*rm_field), GFP_KERNEL);
+
+ if (!rm_field)
+ return ERR_PTR(-ENOMEM);
+
+ regmap_field_init(rm_field, regmap, reg_field);
+
+ return rm_field;
+}
+EXPORT_SYMBOL_GPL(regmap_field_alloc);
+
/**
* regmap_reinit_cache(): Reinitialise the current register cache
*
@@ -1249,6 +1310,23 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
}
EXPORT_SYMBOL_GPL(regmap_raw_write);

+/**
+ * regmap_field_write(): Write a value to a single register field
+ *
+ * @field: Register field to write to
+ * @val: Value to be written
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+
+int regmap_field_write(struct regmap_field *field, unsigned int val)
+{
+ return regmap_update_bits(field->regmap, field->reg,
+ field->mask, val << field->shift);
+}
+EXPORT_SYMBOL_GPL(regmap_field_write);
+
/*
* regmap_bulk_write(): Write multiple registers to the device
*
@@ -1532,6 +1610,32 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
EXPORT_SYMBOL_GPL(regmap_raw_read);

/**
+ * regmap_field_read(): Read a value to a single register field
+ *
+ * @field: Register field to read from
+ * @val: Pointer to store read value
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+
+int regmap_field_read(struct regmap_field *field, unsigned int *val)
+{
+ int ret;
+ unsigned int reg_val;
+ ret = regmap_read(field->regmap, field->reg, &reg_val);
+ if (ret != 0)
+ return ret;
+
+ reg_val &= field->mask;
+ reg_val >>= field->shift;
+ *val = reg_val;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_field_read);
+
+/**
* regmap_bulk_read(): Read multiple registers from the device
*
* @map: Register map to write to
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 02d84e2..557a54e 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -15,6 +15,8 @@

#include <linux/list.h>
#include <linux/rbtree.h>
+#include <linux/device.h>
+#include <linux/slab.h>

struct module;
struct device;
@@ -23,6 +25,7 @@ struct irq_domain;
struct spi_device;
struct regmap;
struct regmap_range_cfg;
+struct regmap_field;

/* An enum of all the supported cache types */
enum regcache_type {
@@ -412,6 +415,45 @@ bool regmap_reg_in_ranges(unsigned int reg,
unsigned int nranges);

/**
+ * Description of an register field
+ *
+ * @reg: Offset of the register within the regmap bank
+ * @lsb: lsb of the register field.
+ * @reg: msb of the register field.
+ */
+struct reg_field {
+ unsigned int reg;
+ unsigned int lsb;
+ unsigned int msb;
+};
+
+#define REG_FIELD(_reg, _lsb, _msb) { \
+ .reg = _reg, \
+ .lsb = _lsb, \
+ .msb = _msb, \
+ }
+
+struct regmap_field *regmap_field_alloc(struct regmap *regmap,
+ struct reg_field reg_field);
+
+struct regmap_field *devm_regmap_field_alloc(struct device *dev,
+ struct regmap *regmap, struct reg_field reg_field);
+
+static inline void regmap_field_free(struct regmap_field *field)
+{
+ kfree(field);
+}
+
+static inline void devm_regmap_field_free(struct device *dev,
+ struct regmap_field *field)
+{
+ devm_kfree(dev, field);
+}
+
+int regmap_field_read(struct regmap_field *field, unsigned int *val);
+int regmap_field_write(struct regmap_field *field, unsigned int val);
+
+/**
* Description of an IRQ for the generic regmap irq_chip.
*
* @reg_offset: Offset of the status/mask register within the bank
--
1.7.6.5

2013-06-10 09:25:22

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: [PATCH v2 05/11] pinctrl:stixxxx: Add pinctrl and pinconf support.

This patch add pinctrl support to ST SoCs.

About hardware:
ST Set-Top-Box parts have two blocks called PIO and PIO-mux which handle
pin configurations.

Each multi-function pin is controlled, driven and routed through the PIO
multiplexing block. Each pin supports GPIO functionality (ALT0) and
multiple alternate functions(ALT1 - ALTx) that directly connect the pin
to different hardware blocks. When a pin is in GPIO mode, Output Enable
(OE), Open Drain(OD), and Pull Up (PU) are driven by the related PIO
block. Otherwise the PIO multiplexing block configures these parameters
and retiming the signal.

About driver:
This pinctrl driver manages both PIO and PIO-mux block using pinctrl,
pinconf, pinmux, gpio subsystems. All the pinctrl related config
information can only come from device trees.

Signed-off-by: Srinivas Kandagatla <[email protected]>
CC: Stephen Gallimore <[email protected]>
CC: Stuart Menefy <[email protected]>
CC: Arnd Bergmann <[email protected]>
CC: Linus Walleij <[email protected]>
---
.../bindings/pinctrl/pinctrl-stixxxx.txt | 116 ++
drivers/pinctrl/Kconfig | 11 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/pinctrl-stixxxx.c | 1212 ++++++++++++++++++++
drivers/pinctrl/pinctrl-stixxxx.h | 197 ++++
5 files changed, 1537 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/pinctrl/pinctrl-stixxxx.txt
create mode 100644 drivers/pinctrl/pinctrl-stixxxx.c
create mode 100644 drivers/pinctrl/pinctrl-stixxxx.h

diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-stixxxx.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-stixxxx.txt
new file mode 100644
index 0000000..ac69dca
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-stixxxx.txt
@@ -0,0 +1,116 @@
+*ST pin controller.
+
+Each multi-function pin is controlled, driven and routed through the
+PIO multiplexing block. Each pin supports GPIO functionality (ALT0)
+and multiple alternate functions(ALT1 - ALTx) that directly connect
+the pin to different hardware blocks.
+
+When a pin is in GPIO mode, Output Enable (OE), Open Drain(OD), and
+Pull Up (PU) are driven by the related PIO block.
+
+ST pinctrl driver controls PIO multiplexing block and also interacts with
+gpio driver to configure a pin.
+
+Required properties: (PIO multiplexing block)
+- compatible : should be "st,stixxxx-pinctrl"
+ each subnode should set "st,stixxxx-gpio"
+ as compatible for each gpio-controller bank.
+- gpio-controller : Indicates this device is a GPIO controller
+- #gpio-cells : Should be one. The first cell is the pin number.
+- st,retime-in-delay : Should be array of delays in nsecs.
+- st,retime-out-delay : Should be array of delays in nsecs.
+- st,retime-pin-mask : Should be mask to specify which pins can be retimed.
+- st,bank-name : Should be a name string for this bank.
+- st,syscfg : phandle of the syscfg node.
+- st,syscfg-offsets : Should be a 5 cell entry which represent offset of altfunc,
+ output-enable, pull-up , open drain and retime registers in the syscfg bank
+
+Example:
+ pin-controller {
+ compatible = "st,stixxxx-pinctrl", "simple-bus";
+ st,retime-in-delay = <0 500 1000 1500>;
+ st,retime-out-delay = <0 1000 2000 3000>;
+ st,syscfg = <&syscfg_front>;
+ st,syscfg-offsets = <0 8 10 12 16>;
+ ranges;
+ PIO0: pinctrl@fe610000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfe610000 0x100>;
+ st,bank-name = "PIO0";
+ };
+ ...
+ pin-functions nodes follow...
+ };
+
+
+Contents of function subnode node:
+----------------------
+Required properties for pin configuration node:
+- st,function : Should be alternate function number associated
+ with this set of pins. Use same numbers from datasheet.
+
+- st,pins : Child node with list of pins with configuration.
+
+Below is the format of how each pin conf should look like.
+
+<bank offset mode rt_type rt_delay rt_clk>
+
+Every PIO is represented with 4-7 parameters depending on retime configuration.
+Each parameter is explained as below.
+
+-bank : Should be bank phandle to which this PIO belongs.
+-offset : Offset in the PIO bank.
+-mode :pin configuration is selected from one of the below values.
+ IN
+ IN_PU
+ OUT
+ BIDIR
+ BIDIR_PU
+
+-rt_type Retiming Configuration for the pin.
+ Possible retime configuration are:
+
+ ------- -------------
+ value args
+ ------- -------------
+ NICLK <delay> <clk>
+ ICLK_IO <delay> <clk>
+ BYPASS <delay>
+ DE_IO <delay> <clk>
+ SE_ICLK_IO <delay> <clk>
+ SE_NICLK_IO <delay> <clk>
+
+- delay is retime delay in pico seconds.
+ Possible values are: refer to retime-in/out-delays
+
+- rt_clk :clk to be use for retime.
+ Possible values are:
+ CLK_A
+ CLK_B
+ CLK_C
+ CLK_D
+
+Example of mmcclk pin which is a bi-direction pull pu with retime config
+as non inverted clock retimed with CLK_B and delay of 0 pico seconds:
+
+pin-controller {
+ ...
+ mmc0 {
+ pinctrl_mmc: mmc {
+ st,function = <ALT4>;
+ st,pins {
+ mmcclk = <&PIO13 4 BIDIR_PU NICLK 0 CLK_B>;
+ ...
+ };
+ };
+ ...
+ };
+};
+
+sdhci0:sdhci@fe810000{
+ ...
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mmc>;
+};
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 8f66924..0c040a3 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -169,6 +169,17 @@ config PINCTRL_SUNXI
select PINMUX
select GENERIC_PINCONF

+config PINCTRL_STIXXXX
+ bool "ST Microelectronics pin controller driver for STixxxx SoCs"
+ select PINMUX
+ select PINCONF
+ help
+ Say yes here to support pinctrl interface on STixxxx SOCs.
+ This driver is used to control both PIO block and PIO-mux
+ block to configure a pin.
+
+ If unsure, say N.
+
config PINCTRL_TEGRA
bool
select PINMUX
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 9bdaeb8..0e035bb 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_PINCTRL_EXYNOS5440) += pinctrl-exynos5440.o
obj-$(CONFIG_PINCTRL_S3C64XX) += pinctrl-s3c64xx.o
obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o
obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o
+obj-$(CONFIG_PINCTRL_STIXXXX) += pinctrl-stixxxx.o

obj-$(CONFIG_PLAT_ORION) += mvebu/
obj-$(CONFIG_ARCH_SHMOBILE) += sh-pfc/
diff --git a/drivers/pinctrl/pinctrl-stixxxx.c b/drivers/pinctrl/pinctrl-stixxxx.c
new file mode 100644
index 0000000..da4e3d7
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-stixxxx.c
@@ -0,0 +1,1212 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Authors:
+ * Srinivas Kandagatla <[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 <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/regmap.h>
+#include <linux/mfd/stixxxx-syscfg.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/platform_device.h>
+#include "core.h"
+#include "pinctrl-stixxxx.h"
+
+struct stixxxx_pinconf {
+ int pin;
+ const char *name;
+ unsigned long config;
+};
+
+struct stixxxx_pmx_func {
+ const char *name;
+ const char **groups;
+ unsigned ngroups;
+};
+
+struct stixxxx_pctl_group {
+ const char *name;
+ unsigned int *pins;
+ unsigned npins;
+ int altfunc;
+ struct stixxxx_pinconf *pin_conf;
+};
+
+#define to_stixxxx_gpio_port(chip) \
+ container_of(chip, struct stixxxx_gpio_port, gpio_chip)
+
+struct stixxxx_gpio_port {
+ struct gpio_chip gpio_chip;
+ struct pinctrl_gpio_range range;
+ void __iomem *base;
+ struct device_node *of_node;
+ const char *bank_name;
+};
+
+static struct stixxxx_gpio_port *gpio_ports[STIXXXX_MAX_GPIO_BANKS];
+
+struct stixxxx_pinctrl {
+ struct device *dev;
+ struct pinctrl_dev *pctl;
+ int nbanks;
+ struct stixxxx_pmx_func *functions;
+ int nfunctions;
+ struct stixxxx_pctl_group *groups;
+ int ngroups;
+ struct stixxxx_pio_control *pio_controls;
+ struct pinctrl_gpio_range **gpio_ranges;
+ struct regmap *regmap;
+};
+
+/* Low level functions.. */
+static void stixxxx_pinconf_set_direction(struct stixxxx_pio_control *pc,
+ int pin_id, unsigned long config)
+{
+ struct regmap_field *output_enable;
+ struct regmap_field *pull_up;
+ struct regmap_field *open_drain;
+ unsigned int oe_value, pu_value, od_value;
+ unsigned long mask;
+ int pin = stixxxx_gpio_pin(pin_id);
+
+ output_enable = pc->oe;
+ pull_up = pc->pu;
+ open_drain = pc->od;
+
+ mask = BIT(pin);
+
+ regmap_field_read(output_enable, &oe_value);
+ regmap_field_read(pull_up, &pu_value);
+ regmap_field_read(open_drain, &od_value);
+
+ /* Clear old values */
+ oe_value &= ~mask;
+ pu_value &= ~mask;
+ od_value &= ~mask;
+
+ if (config & STIXXXX_PINCONF_OE)
+ oe_value |= mask;
+ if (config & STIXXXX_PINCONF_PU)
+ pu_value |= mask;
+ if (config & STIXXXX_PINCONF_OD)
+ od_value |= mask;
+
+ regmap_field_write(output_enable, oe_value);
+ regmap_field_write(pull_up, pu_value);
+ regmap_field_write(open_drain, od_value);
+}
+
+static void stixxxx_pctl_set_function(struct stixxxx_pio_control *pc,
+ int pin_id, int function)
+{
+ struct regmap_field *selector;
+ int offset;
+ unsigned int val;
+ int pin = stixxxx_gpio_pin(pin_id);
+
+ selector = pc->alt;
+ offset = pin * 4;
+ regmap_field_read(selector, &val);
+ val &= ~(0xf << offset);
+ val |= function << offset;
+ regmap_field_write(selector, val);
+}
+
+static unsigned long stixxxx_pinconf_delay_to_bit(unsigned int delay,
+ const struct stixxxx_retime_params *rt_params,
+ unsigned long config)
+{
+ unsigned int *delay_times;
+ int num_delay_times, i, closest_index = -1;
+ unsigned int closest_divergence = UINT_MAX;
+
+ if (STIXXXX_PINCONF_UNPACK_OE(config)) {
+ delay_times = rt_params->delay_times_out;
+ num_delay_times = rt_params->num_delay_times_out;
+ } else {
+ delay_times = rt_params->delay_times_in;
+ num_delay_times = rt_params->num_delay_times_in;
+ }
+
+ for (i = 0; i < num_delay_times; i++) {
+ unsigned int divergence = abs(delay - delay_times[i]);
+
+ if (divergence == 0)
+ return i;
+
+ if (divergence < closest_divergence) {
+ closest_divergence = divergence;
+ closest_index = i;
+ }
+ }
+
+ pr_warn("Attempt to set delay %d, closest available %d\n",
+ delay, delay_times[closest_index]);
+
+ return closest_index;
+}
+
+static unsigned long stixxxx_pinconf_bit_to_delay(unsigned int index,
+ const struct stixxxx_retime_params *rt_params,
+ unsigned long output)
+{
+ unsigned int *delay_times;
+ int num_delay_times;
+
+ if (output) {
+ delay_times = rt_params->delay_times_out;
+ num_delay_times = rt_params->num_delay_times_out;
+ } else {
+ delay_times = rt_params->delay_times_in;
+ num_delay_times = rt_params->num_delay_times_in;
+ }
+
+ if (index < num_delay_times) {
+ return delay_times[index];
+ } else {
+ pr_warn("Delay not found in/out delay list\n");
+ return 0;
+ }
+}
+
+static void stixxxx_pinconf_set_retime_packed(
+ struct stixxxx_pio_control *pc,
+ unsigned long config, int pin)
+{
+ const struct stixxxx_retime_params *rt_params = pc->rt_params;
+ const struct stixxxx_retime_offset *offset = rt_params->retime_offset;
+ struct regmap_field **regs;
+ unsigned int values[2];
+ unsigned long mask;
+ int i, j;
+ int clk = STIXXXX_PINCONF_UNPACK_RT_CLK(config);
+ int clknotdata = STIXXXX_PINCONF_UNPACK_RT_CLKNOTDATA(config);
+ int double_edge = STIXXXX_PINCONF_UNPACK_RT_DOUBLE_EDGE(config);
+ int invertclk = STIXXXX_PINCONF_UNPACK_RT_INVERTCLK(config);
+ int retime = STIXXXX_PINCONF_UNPACK_RT(config);
+ unsigned long delay = stixxxx_pinconf_delay_to_bit(
+ STIXXXX_PINCONF_UNPACK_RT_DELAY(config),
+ pc->rt_params, config);
+
+ unsigned long rt_cfg =
+ ((clk & 1) << offset->clk1notclk0_offset) |
+ ((clknotdata & 1) << offset->clknotdata_offset) |
+ ((delay & 1) << offset->delay_lsb_offset) |
+ (((delay >> 1) & 1) << offset->delay_msb_offset) |
+ ((double_edge & 1) << offset->double_edge_offset) |
+ ((invertclk & 1) << offset->invertclk_offset) |
+ ((retime & 1) << offset->retime_offset);
+
+ regs = pc->retiming;
+ regmap_field_read(regs[0], &values[0]);
+ regmap_field_read(regs[1], &values[1]);
+
+ for (i = 0; i < 2; i++) {
+ mask = BIT(pin);
+ for (j = 0; j < 4; j++) {
+ if (rt_cfg & 1)
+ values[i] |= mask;
+ else
+ values[i] &= ~mask;
+ mask <<= 8;
+ rt_cfg >>= 1;
+ }
+ }
+
+ regmap_field_write(regs[0], values[0]);
+ regmap_field_write(regs[1], values[1]);
+}
+
+static void stixxxx_pinconf_set_retime_dedicated(
+ struct stixxxx_pio_control *pc,
+ unsigned long config, int pin)
+{
+ struct regmap_field *reg;
+ int input = STIXXXX_PINCONF_UNPACK_OE(config) ? 0 : 1;
+ int clk = STIXXXX_PINCONF_UNPACK_RT_CLK(config);
+ int clknotdata = STIXXXX_PINCONF_UNPACK_RT_CLKNOTDATA(config);
+ int double_edge = STIXXXX_PINCONF_UNPACK_RT_DOUBLE_EDGE(config);
+ int invertclk = STIXXXX_PINCONF_UNPACK_RT_INVERTCLK(config);
+ int retime = STIXXXX_PINCONF_UNPACK_RT(config);
+ unsigned long delay = stixxxx_pinconf_delay_to_bit(
+ STIXXXX_PINCONF_UNPACK_RT_DELAY(config),
+ pc->rt_params, config);
+
+ unsigned long retime_config =
+ ((clk & 0x3) << 0) |
+ ((clknotdata & 0x1) << 2) |
+ ((delay & 0xf) << 3) |
+ ((input & 0x1) << 7) |
+ ((double_edge & 0x1) << 8) |
+ ((invertclk & 0x1) << 9) |
+ ((retime & 0x1) << 10);
+
+ reg = pc->retiming[pin];
+ regmap_field_write(reg, retime_config);
+}
+
+static void stixxxx_pinconf_get_direction(struct stixxxx_pio_control *pc,
+ int pin_id, unsigned long *config)
+{
+ unsigned int oe_value, pu_value, od_value;
+ int pin = stixxxx_gpio_pin(pin_id);
+
+ regmap_field_read(pc->oe, &oe_value);
+ regmap_field_read(pc->pu, &pu_value);
+ regmap_field_read(pc->od, &od_value);
+
+ oe_value = (oe_value >> pin) & 1;
+ pu_value = (pu_value >> pin) & 1;
+ od_value = (od_value >> pin) & 1;
+
+ STIXXXX_PINCONF_PACK_OE(*config, oe_value);
+ STIXXXX_PINCONF_PACK_PU(*config, pu_value);
+ STIXXXX_PINCONF_PACK_OD(*config, od_value);
+}
+
+static int stixxxx_pinconf_get_retime_packed(
+ struct stixxxx_pio_control *pc,
+ int pin, unsigned long *config)
+{
+ const struct stixxxx_retime_params *rt_params = pc->rt_params;
+ const struct stixxxx_retime_offset *offset = rt_params->retime_offset;
+ unsigned long delay_bits, delay, rt_reduced;
+ unsigned int rt_value[2];
+ int i, j;
+ int output = STIXXXX_PINCONF_UNPACK_OE(*config);
+
+ regmap_field_read(pc->retiming[0], &rt_value[0]);
+ regmap_field_read(pc->retiming[1], &rt_value[1]);
+
+ rt_reduced = 0;
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 4; j++) {
+ if (rt_value[i] & (1<<((8*j)+pin)))
+ rt_reduced |= 1 << ((i*4)+j);
+ }
+ }
+
+ STIXXXX_PINCONF_PACK_RT(*config,
+ (rt_reduced >> offset->retime_offset) & 1);
+ STIXXXX_PINCONF_PACK_RT_CLK(*config,
+ (rt_reduced >> offset->clk1notclk0_offset) & 1);
+ STIXXXX_PINCONF_PACK_RT_CLKNOTDATA(*config,
+ (rt_reduced >> offset->clknotdata_offset) & 1);
+ STIXXXX_PINCONF_PACK_RT_DOUBLE_EDGE(*config,
+ (rt_reduced >> offset->double_edge_offset) & 1);
+ STIXXXX_PINCONF_PACK_RT_INVERTCLK(*config,
+ (rt_reduced >> offset->invertclk_offset) & 1);
+
+ delay_bits = (((rt_reduced >> offset->delay_msb_offset) & 1)<<1) |
+ ((rt_reduced >> offset->delay_lsb_offset) & 1);
+ delay = stixxxx_pinconf_bit_to_delay(delay_bits, rt_params, output);
+ STIXXXX_PINCONF_PACK_RT_DELAY(*config, delay);
+ return 0;
+}
+
+static int stixxxx_pinconf_get_retime_dedicated(
+ struct stixxxx_pio_control *pc,
+ int pin, unsigned long *config)
+{
+ unsigned int value;
+ unsigned long delay_bits, delay;
+ const struct stixxxx_retime_params *rt_params = pc->rt_params;
+ int output = STIXXXX_PINCONF_UNPACK_OE(*config);
+
+ regmap_field_read(pc->retiming[pin], &value);
+ STIXXXX_PINCONF_PACK_RT_CLK(*config, ((value >> 0) & 0x3));
+ STIXXXX_PINCONF_PACK_RT_CLKNOTDATA(*config, ((value >> 2) & 0x1));
+ delay_bits = ((value >> 3) & 0xf);
+ delay = stixxxx_pinconf_bit_to_delay(delay_bits, rt_params, output);
+ STIXXXX_PINCONF_PACK_RT_DELAY(*config, delay);
+ STIXXXX_PINCONF_PACK_RT_DOUBLE_EDGE(*config, ((value >> 8) & 0x1));
+ STIXXXX_PINCONF_PACK_RT_INVERTCLK(*config, ((value >> 9) & 0x1));
+ STIXXXX_PINCONF_PACK_RT(*config, ((value >> 10) & 0x1));
+
+ return 0;
+}
+
+/* GPIO related functions */
+
+static inline void __stixxxx_gpio_set(struct stixxxx_gpio_port *port,
+ unsigned offset, int value)
+{
+ if (value)
+ writel(BIT(offset), port->base + REG_PIO_SET_POUT);
+ else
+ writel(BIT(offset), port->base + REG_PIO_CLR_POUT);
+}
+
+static void stixxxx_gpio_direction(unsigned int gpio, unsigned int direction)
+{
+ int port_num = stixxxx_gpio_port(gpio);
+ int offset = stixxxx_gpio_pin(gpio);
+ struct stixxxx_gpio_port *port = gpio_ports[port_num];
+ int i = 0;
+
+ for (i = 0; i <= 2; i++) {
+ if (direction & BIT(i))
+ writel(BIT(offset), port->base + REG_PIO_SET_PC(i));
+ else
+ writel(BIT(offset), port->base + REG_PIO_CLR_PC(i));
+ }
+}
+
+static int stixxxx_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ return pinctrl_request_gpio(chip->base + offset);
+}
+
+static void stixxxx_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ pinctrl_free_gpio(chip->base + offset);
+}
+
+static int stixxxx_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct stixxxx_gpio_port *port = to_stixxxx_gpio_port(chip);
+
+ return (readl(port->base + REG_PIO_PIN) >> offset) & 1;
+}
+
+static void stixxxx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct stixxxx_gpio_port *port = to_stixxxx_gpio_port(chip);
+ __stixxxx_gpio_set(port, offset, value);
+}
+
+static int stixxxx_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ pinctrl_gpio_direction_input(chip->base + offset);
+ return 0;
+}
+
+static int stixxxx_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct stixxxx_gpio_port *port = to_stixxxx_gpio_port(chip);
+
+ __stixxxx_gpio_set(port, offset, value);
+ pinctrl_gpio_direction_output(chip->base + offset);
+
+ return 0;
+}
+
+static int stixxxx_gpio_xlate(struct gpio_chip *gc,
+ const struct of_phandle_args *gpiospec, u32 *flags)
+{
+ if (WARN_ON(gc->of_gpio_n_cells < 1))
+ return -EINVAL;
+
+ if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
+ return -EINVAL;
+
+ if (gpiospec->args[0] > gc->ngpio)
+ return -EINVAL;
+
+ return gpiospec->args[0];
+}
+
+/* Pinctrl Groups */
+static int stixxxx_pctl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ return info->ngroups;
+}
+
+static const char *stixxxx_pctl_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ return info->groups[selector].name;
+}
+
+static int stixxxx_pctl_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned selector, const unsigned **pins, unsigned *npins)
+{
+ struct stixxxx_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 stixxxx_pctl_group *stixxxx_pctl_find_group_by_name(
+ const struct stixxxx_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 stixxxx_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np, struct pinctrl_map **map, unsigned *num_maps)
+{
+ struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ const struct stixxxx_pctl_group *grp;
+ struct pinctrl_map *new_map;
+ struct device_node *parent;
+ int map_num, i;
+
+ grp = stixxxx_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 stixxxx_pctl_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map, unsigned num_maps)
+{
+}
+
+static struct pinctrl_ops stixxxx_pctlops = {
+ .get_groups_count = stixxxx_pctl_get_groups_count,
+ .get_group_pins = stixxxx_pctl_get_group_pins,
+ .get_group_name = stixxxx_pctl_get_group_name,
+ .dt_node_to_map = stixxxx_pctl_dt_node_to_map,
+ .dt_free_map = stixxxx_pctl_dt_free_map,
+};
+
+/* Pinmux */
+static int stixxxx_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+ struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ return info->nfunctions;
+}
+
+const char *stixxxx_pmx_get_fname(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ return info->functions[selector].name;
+}
+
+static int stixxxx_pmx_get_groups(struct pinctrl_dev *pctldev,
+ unsigned selector, const char * const **grps, unsigned * const ngrps)
+{
+ struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ *grps = info->functions[selector].groups;
+ *ngrps = info->functions[selector].ngroups;
+
+ return 0;
+}
+
+static struct stixxxx_pio_control *stixxxx_get_pio_control(
+ struct stixxxx_pinctrl *info, int pin_id)
+{
+ int index = stixxxx_gpio_port(pin_id) - info->gpio_ranges[0]->id;
+ return &info->pio_controls[index];
+}
+
+static int stixxxx_pmx_enable(struct pinctrl_dev *pctldev, unsigned fselector,
+ unsigned group)
+{
+ struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ struct stixxxx_pinconf *conf = info->groups[group].pin_conf;
+ struct stixxxx_pio_control *pc;
+ int i;
+
+ for (i = 0; i < info->groups[group].npins; i++) {
+ pc = stixxxx_get_pio_control(info, conf[i].pin);
+ stixxxx_pctl_set_function(pc, conf[i].pin,
+ info->groups[group].altfunc);
+ }
+
+ return 0;
+}
+
+static void stixxxx_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
+ unsigned group)
+{
+}
+
+static int stixxxx_pmx_set_gpio_direction(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, unsigned gpio,
+ bool input)
+{
+ struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ int offset = range->id - info->gpio_ranges[0]->id;
+ struct stixxxx_pio_control *pc = &info->pio_controls[offset];
+ /*
+ * When a PIO port is used in its primary function mode (altfunc = 0)
+ * Output Enable (OE), Open Drain(OD), and Pull Up (PU)
+ * for the primary PIO functions are driven by the related PIO block
+ */
+ stixxxx_pctl_set_function(pc, gpio, 0);
+ stixxxx_gpio_direction(gpio, input ?
+ STIXXXX_GPIO_DIRECTION_IN : STIXXXX_GPIO_DIRECTION_OUT);
+
+ return 0;
+}
+
+static struct pinmux_ops stixxxx_pmxops = {
+ .get_functions_count = stixxxx_pmx_get_funcs_count,
+ .get_function_name = stixxxx_pmx_get_fname,
+ .get_function_groups = stixxxx_pmx_get_groups,
+ .enable = stixxxx_pmx_enable,
+ .disable = stixxxx_pmx_disable,
+ .gpio_set_direction = stixxxx_pmx_set_gpio_direction,
+};
+
+/* Pinconf */
+static void stixxxx_pinconf_get_retime(struct stixxxx_pio_control *pc,
+ int pin_id, unsigned long *config)
+{
+ int pin = stixxxx_gpio_pin(pin_id);
+ if (pc->rt_style == stixxxx_retime_style_packed)
+ stixxxx_pinconf_get_retime_packed(pc, pin, config);
+ else if (pc->rt_style == stixxxx_retime_style_dedicated)
+ if ((BIT(pin) & pc->rt_pin_mask))
+ stixxxx_pinconf_get_retime_dedicated(pc, pin, config);
+}
+
+static void stixxxx_pinconf_set_retime(struct stixxxx_pio_control *pc,
+ int pin_id, unsigned long config)
+{
+ int pin = stixxxx_gpio_pin(pin_id);
+
+ if (pc->rt_style == stixxxx_retime_style_packed)
+ stixxxx_pinconf_set_retime_packed(pc, config, pin);
+ else if (pc->rt_style == stixxxx_retime_style_dedicated)
+ if ((BIT(pin) & pc->rt_pin_mask))
+ stixxxx_pinconf_set_retime_dedicated(pc, config, pin);
+}
+
+static int stixxxx_pinconf_set(struct pinctrl_dev *pctldev,
+ unsigned pin_id, unsigned long config)
+{
+ struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ struct stixxxx_pio_control *pc = stixxxx_get_pio_control(info, pin_id);
+
+ stixxxx_pinconf_set_direction(pc, pin_id, config);
+ stixxxx_pinconf_set_retime(pc, pin_id, config);
+ return 0;
+}
+
+static int stixxxx_pinconf_get(struct pinctrl_dev *pctldev,
+ unsigned pin_id, unsigned long *config)
+{
+ struct stixxxx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ struct stixxxx_pio_control *pc = stixxxx_get_pio_control(info, pin_id);
+
+ *config = 0;
+ stixxxx_pinconf_get_direction(pc, pin_id, config);
+ stixxxx_pinconf_get_retime(pc, pin_id, config);
+
+ return 0;
+}
+
+static void stixxxx_pinconf_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned pin_id)
+{
+ unsigned long config;
+ stixxxx_pinconf_get(pctldev, pin_id, &config);
+
+ seq_printf(s, "[OE:%ld,PU:%ld,OD:%ld]\n"
+ "\t\t[retime:%ld,invclk:%ld,clknotdat:%ld,"
+ "de:%ld,rt-clk:%ld,rt-delay:%ld]",
+ STIXXXX_PINCONF_UNPACK_OE(config),
+ STIXXXX_PINCONF_UNPACK_PU(config),
+ STIXXXX_PINCONF_UNPACK_OD(config),
+ STIXXXX_PINCONF_UNPACK_RT(config),
+ STIXXXX_PINCONF_UNPACK_RT_INVERTCLK(config),
+ STIXXXX_PINCONF_UNPACK_RT_CLKNOTDATA(config),
+ STIXXXX_PINCONF_UNPACK_RT_DOUBLE_EDGE(config),
+ STIXXXX_PINCONF_UNPACK_RT_CLK(config),
+ STIXXXX_PINCONF_UNPACK_RT_DELAY(config));
+}
+
+static struct pinconf_ops stixxxx_confops = {
+ .pin_config_get = stixxxx_pinconf_get,
+ .pin_config_set = stixxxx_pinconf_set,
+ .pin_config_dbg_show = stixxxx_pinconf_dbg_show,
+};
+
+static int stixxxx_pinconf_dt_parse_rt_params(struct stixxxx_pinctrl *info,
+ struct device_node *np, struct stixxxx_retime_params *params)
+{
+ struct stixxxx_retime_offset *rt_offset;
+ int delay_count = 0;
+ int len;
+ if (of_find_property(np, "st,retime-in-delay", &len))
+ delay_count = len/sizeof(__be32);
+ else
+ dev_err(info->dev, "No delays found\n");
+
+ params->num_delay_times_out = delay_count;
+ params->num_delay_times_in = delay_count;
+ params->delay_times_in = devm_kzalloc(info->dev,
+ sizeof(u32) * delay_count, GFP_KERNEL);
+ params->delay_times_out = devm_kzalloc(info->dev,
+ sizeof(u32) * delay_count, GFP_KERNEL);
+
+ if (!params->delay_times_in || !params->delay_times_out)
+ return -ENOMEM;
+
+ of_property_read_u32_array(np, "st,retime-in-delay",
+ (u32 *)params->delay_times_in, delay_count);
+ of_property_read_u32_array(np, "st,retime-out-delay",
+ (u32 *)params->delay_times_out, delay_count);
+
+ if (of_device_is_compatible(np, "st,stih415-pinctrl")) {
+ rt_offset = devm_kzalloc(info->dev,
+ sizeof(*rt_offset), GFP_KERNEL);
+
+ if (!rt_offset)
+ return -ENOMEM;
+
+ rt_offset->clk1notclk0_offset = 0;
+ rt_offset->delay_lsb_offset = 2;
+ rt_offset->delay_msb_offset = 3;
+ rt_offset->invertclk_offset = 4;
+ rt_offset->retime_offset = 5;
+ rt_offset->clknotdata_offset = 6;
+ rt_offset->double_edge_offset = 7;
+ params->retime_offset = rt_offset;
+ }
+
+ return 0;
+}
+
+static const char *gpio_compat = "st,stixxxx-gpio";
+
+static void stixxxx_pctl_dt_child_count(struct stixxxx_pinctrl *info,
+ struct device_node *np)
+{
+ struct device_node *child;
+ for_each_child_of_node(np, child) {
+ if (of_device_is_compatible(child, gpio_compat)) {
+ info->nbanks++;
+ } else {
+ info->nfunctions++;
+ info->ngroups += of_get_child_count(child);
+ }
+ }
+}
+
+static int stixxxx_pctl_dt_get_retime_conf(struct stixxxx_pinctrl *info,
+ struct stixxxx_pio_control *pc, u32 *syscfg)
+{
+ unsigned int j;
+ int rt_syscfg = *syscfg;
+ struct device_node *np = info->dev->of_node;
+
+ if (of_device_is_compatible(np, "st,stih415-pinctrl")) {
+ pc->rt_style = stixxxx_retime_style_packed;
+ for (j = 0; j < 2; j++) {
+ struct reg_field rt_reg =
+ REG_FIELD(4 * rt_syscfg ++, 0, 31);
+ pc->retiming[j] = devm_regmap_field_alloc(info->dev,
+ info->regmap, rt_reg);
+ if (IS_ERR(pc->retiming[j]))
+ return -ENODATA;
+ }
+ } else if (of_device_is_compatible(np, "st,stih416-pinctrl")) {
+ pc->rt_style = stixxxx_retime_style_dedicated;
+ for (j = 0; j < 8; j++) {
+ if ((1<<j) & pc->rt_pin_mask) {
+ struct reg_field rt_reg =
+ REG_FIELD(4 * rt_syscfg ++, 0, 31);
+ pc->retiming[j] = devm_regmap_field_alloc(
+ info->dev, info->regmap, rt_reg);
+ if (IS_ERR(pc->retiming[j]))
+ return -ENODATA;
+ }
+ }
+ } else {
+ pc->rt_style = stixxxx_retime_style_none;
+ }
+
+ *syscfg = rt_syscfg;
+ return 0;
+}
+
+static int stixxxx_pctl_dt_init(struct stixxxx_pinctrl *info,
+ struct device_node *np)
+{
+ struct stixxxx_pio_control *pc;
+ struct stixxxx_retime_params *rt_params;
+ struct device *dev = info->dev;
+ struct regmap *regmap;
+ unsigned int i = 0;
+ struct device_node *child = NULL;
+ u32 alt_syscfg, oe_syscfg, pu_syscfg, od_syscfg, rt_syscfg;
+ u32 syscfg_offsets[5];
+ u32 msb, lsb;
+
+ pc = devm_kzalloc(dev, sizeof(*pc) * info->nbanks, GFP_KERNEL);
+ rt_params = devm_kzalloc(dev, sizeof(*rt_params), GFP_KERNEL);
+
+ if (!pc || !rt_params)
+ return -ENOMEM;
+
+ regmap = syscfg_regmap_lookup_by_phandle(np, "st,syscfg");
+ if (!regmap) {
+ dev_err(dev, "No syscfg phandle specified\n");
+ return -ENOMEM;
+ }
+ info->regmap = regmap;
+ info->pio_controls = pc;
+ if (stixxxx_pinconf_dt_parse_rt_params(info, np, rt_params))
+ return -ENOMEM;
+
+ if (of_property_read_u32_array(np, "st,syscfg-offsets",
+ syscfg_offsets, 5)) {
+ dev_err(dev, "Syscfg offsets not found\n");
+ return -EINVAL;
+ }
+ alt_syscfg = syscfg_offsets[0];
+ oe_syscfg = syscfg_offsets[1];
+ pu_syscfg = syscfg_offsets[2];
+ od_syscfg = syscfg_offsets[3];
+ rt_syscfg = syscfg_offsets[4];
+
+ lsb = 0;
+ msb = 7;
+ for_each_child_of_node(np, child) {
+ if (of_device_is_compatible(child, gpio_compat)) {
+ struct reg_field alt_reg =
+ REG_FIELD(4 * alt_syscfg++, 0, 31);
+ struct reg_field oe_reg =
+ REG_FIELD(4 * oe_syscfg, lsb, msb);
+ struct reg_field pu_reg =
+ REG_FIELD(4 * pu_syscfg, lsb, msb);
+ struct reg_field od_reg =
+ REG_FIELD(4 * od_syscfg, lsb, msb);
+ pc[i].rt_params = rt_params;
+
+ pc[i].alt = devm_regmap_field_alloc(dev,
+ regmap, alt_reg);
+ pc[i].oe = devm_regmap_field_alloc(dev,
+ regmap, oe_reg);
+ pc[i].pu = devm_regmap_field_alloc(dev,
+ regmap, pu_reg);
+ pc[i].od = devm_regmap_field_alloc(dev,
+ regmap, od_reg);
+
+ if (IS_ERR(pc[i].alt) || IS_ERR(pc[i].oe)
+ || IS_ERR(pc[i].pu) || IS_ERR(pc[i].od))
+ goto failed;
+
+ of_property_read_u32(child, "st,retime-pin-mask",
+ &pc[i].rt_pin_mask);
+
+ stixxxx_pctl_dt_get_retime_conf(info, &pc[i],
+ &rt_syscfg);
+ i++;
+ if (msb == 31) {
+ oe_syscfg++;
+ pu_syscfg++;
+ od_syscfg++;
+ lsb = 0;
+ msb = 7;
+ } else {
+ lsb += 8;
+ msb += 8;
+ }
+ }
+ }
+
+ return 0;
+failed:
+ dev_err(dev, "Unable to allocate syscfgs\n");
+ return -ENOMEM;
+}
+
+#define OF_GPIO_ARGS_MIN (3)
+/*
+ * Each pin is represented in of the below forms.
+ * <bank offset direction func rt_type rt_delay rt_clk>
+ */
+static int stixxxx_pctl_dt_parse_groups(struct device_node *np,
+ struct stixxxx_pctl_group *grp, struct stixxxx_pinctrl *info, int idx)
+{
+ /* bank pad direction val altfunction */
+ const __be32 *list;
+ struct property *pp;
+ struct stixxxx_pinconf *conf;
+ phandle phandle;
+ struct device_node *pins;
+ u32 pin;
+ 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);
+ of_property_read_u32(np, "st,function", &grp->altfunc);
+
+ if (!grp->pins || !grp->pin_conf)
+ return -ENOMEM;
+
+ /* <bank offset direction rt_type rt_delay rt_clk> */
+ 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 */
+ phandle = be32_to_cpup(list++);
+ pin = be32_to_cpup(list++);
+ conf->pin = of_get_named_gpio(pins, pp->name, 0);
+ conf->name = pp->name;
+ grp->pins[i] = conf->pin;
+
+ conf->config = 0;
+ /* direction */
+ conf->config |= be32_to_cpup(list++);
+ /* rt_type rt_delay rt_clk */
+ if (nr_props >= OF_GPIO_ARGS_MIN + 2) {
+ /* rt_type */
+ conf->config |= be32_to_cpup(list++);
+ /* rt_delay */
+ conf->config |= be32_to_cpup(list++);
+ /* rt_clk */
+ if (nr_props > OF_GPIO_ARGS_MIN + 2)
+ conf->config |= be32_to_cpup(list++);
+ }
+ i++;
+ }
+ of_node_put(pins);
+
+ return 0;
+}
+
+static int stixxxx_pctl_parse_functions(struct device_node *np,
+ struct stixxxx_pinctrl *info, u32 index, int *grp_index)
+{
+ struct device_node *child;
+ struct stixxxx_pmx_func *func;
+ struct stixxxx_pctl_group *grp;
+ int ret, i;
+
+ 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;
+
+ i = 0;
+ for_each_child_of_node(np, child) {
+ func->groups[i] = child->name;
+ grp = &info->groups[*grp_index];
+ *grp_index += 1;
+ ret = stixxxx_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 struct pinctrl_gpio_range *find_gpio_range(struct device_node *np)
+{
+ int i;
+ for (i = 0; i < STIXXXX_MAX_GPIO_BANKS; i++)
+ if (gpio_ports[i]->of_node == np)
+ return &gpio_ports[i]->range;
+
+ return NULL;
+}
+
+static int stixxxx_pctl_probe_dt(struct platform_device *pdev,
+ struct pinctrl_desc *pctl_desc, struct stixxxx_pinctrl *info)
+{
+ int ret = 0;
+ int i = 0, j = 0, k = 0, bank;
+ struct pinctrl_pin_desc *pdesc;
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *child;
+ int grp_index = 0;
+
+ stixxxx_pctl_dt_child_count(info, np);
+ if (info->nbanks < 1) {
+ dev_err(&pdev->dev, "you need atleast one gpio bank\n");
+ return -EINVAL;
+ }
+
+ ret = stixxxx_pctl_dt_init(info, np);
+ if (ret)
+ return ret;
+
+ 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->gpio_ranges = devm_kzalloc(&pdev->dev,
+ info->nbanks * sizeof(*info->gpio_ranges), GFP_KERNEL);
+
+ if (!info->functions || !info->groups)
+ return -ENOMEM;
+
+ pctl_desc->npins = info->nbanks * STIXXXX_GPIO_PINS_PER_PORT;
+ pdesc = devm_kzalloc(&pdev->dev,
+ sizeof(*pdesc) * pctl_desc->npins, GFP_KERNEL);
+ if (!pdesc)
+ return -ENOMEM;
+
+ pctl_desc->pins = pdesc;
+
+ bank = 0;
+ for_each_child_of_node(np, child) {
+ if (of_device_is_compatible(child, gpio_compat)) {
+ info->gpio_ranges[bank] = find_gpio_range(child);
+ k = info->gpio_ranges[bank]->pin_base;
+ for (j = 0; j < STIXXXX_GPIO_PINS_PER_PORT; j++, k++) {
+ const char *port_name = NULL;
+ pdesc->number = k;
+ of_property_read_string(child, "st,bank-name",
+ &port_name);
+ pdesc->name = kasprintf(GFP_KERNEL, "%s[%d]",
+ port_name ? : "PIO",
+ port_name ? j : k);
+ pdesc++;
+ }
+ bank++;
+ } else {
+ ret = stixxxx_pctl_parse_functions(child, info,
+ i++, &grp_index);
+ if (ret) {
+ dev_err(&pdev->dev, "No functions found.\n");
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int stixxxx_pctl_probe(struct platform_device *pdev)
+{
+ struct stixxxx_pinctrl *info;
+ struct pinctrl_desc *pctl_desc;
+ int ret, i;
+
+ if (!pdev->dev.of_node) {
+ dev_err(&pdev->dev, "device node 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 = stixxxx_pctl_probe_dt(pdev, pctl_desc, info);
+ if (ret)
+ return ret;
+
+ pctl_desc->owner = THIS_MODULE,
+ pctl_desc->pctlops = &stixxxx_pctlops,
+ pctl_desc->pmxops = &stixxxx_pmxops,
+ pctl_desc->confops = &stixxxx_confops,
+ pctl_desc->name = dev_name(&pdev->dev);
+
+ info->pctl = pinctrl_register(pctl_desc, &pdev->dev, info);
+ if (IS_ERR(info->pctl)) {
+ dev_err(&pdev->dev, "Failed pinctrl registration\n");
+ return PTR_ERR(info->pctl);
+ }
+
+ for (i = 0; i < info->nbanks; i++)
+ pinctrl_add_gpio_range(info->pctl, info->gpio_ranges[i]);
+
+ return 0;
+}
+
+static struct gpio_chip stixxxx_gpio_template = {
+ .request = stixxxx_gpio_request,
+ .free = stixxxx_gpio_free,
+ .get = stixxxx_gpio_get,
+ .set = stixxxx_gpio_set,
+ .direction_input = stixxxx_gpio_direction_input,
+ .direction_output = stixxxx_gpio_direction_output,
+ .ngpio = STIXXXX_GPIO_PINS_PER_PORT,
+ .of_gpio_n_cells = 1,
+ .of_xlate = stixxxx_gpio_xlate,
+};
+
+static int stixxxx_gpio_probe(struct platform_device *pdev)
+{
+ struct stixxxx_gpio_port *port;
+ struct pinctrl_gpio_range *range;
+ struct device_node *np = pdev->dev.of_node;
+ int port_num = of_alias_get_id(np, "gpio");
+ struct resource *res;
+ int err;
+
+ port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ port->base = devm_request_and_ioremap(&pdev->dev, res);
+ if (!port->base) {
+ dev_err(&pdev->dev, "Can't get IO memory mapping!\n");
+ return -ENODEV;
+ }
+
+ of_property_read_string(np, "st,bank-name", &port->bank_name);
+ port->of_node = np;
+
+ port->gpio_chip = stixxxx_gpio_template;
+ port->gpio_chip.base = port_num * STIXXXX_GPIO_PINS_PER_PORT;
+ port->gpio_chip.ngpio = STIXXXX_GPIO_PINS_PER_PORT;
+ port->gpio_chip.of_node = np;
+ port->gpio_chip.label = dev_name(&pdev->dev);
+
+ dev_set_drvdata(&pdev->dev, port);
+ range = &port->range;
+ range->name = port->gpio_chip.label;
+ range->id = port_num;
+ range->pin_base = range->base = range->id * STIXXXX_GPIO_PINS_PER_PORT;
+ range->npins = port->gpio_chip.ngpio;
+ range->gc = &port->gpio_chip;
+ gpio_ports[port_num] = port;
+ err = gpiochip_add(&port->gpio_chip);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to add gpiochip(%d)!\n", port_num);
+ return err;
+ }
+ dev_info(&pdev->dev, "gpioport[%s] Added as bank%d\n",
+ port->bank_name, port_num);
+ return 0;
+}
+
+static struct of_device_id stixxxx_gpio_of_match[] = {
+ { .compatible = "st,stixxxx-gpio", },
+ { /* sentinel */ }
+};
+
+static struct platform_driver stixxxx_gpio_driver = {
+ .driver = {
+ .name = "st-gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(stixxxx_gpio_of_match),
+ },
+ .probe = stixxxx_gpio_probe,
+};
+
+static struct of_device_id stixxxx_pctl_of_match[] = {
+ { .compatible = "st,stixxxx-pinctrl",},
+ { .compatible = "st,stih415-pinctrl",},
+ { .compatible = "st,stih416-pinctrl",},
+ { /* sentinel */ }
+};
+
+static struct platform_driver stixxxx_pctl_driver = {
+ .driver = {
+ .name = "st-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(stixxxx_pctl_of_match),
+ },
+ .probe = stixxxx_pctl_probe,
+};
+
+static int __init stixxxx_pctl_init(void)
+{
+ int ret = platform_driver_register(&stixxxx_gpio_driver);
+ if (ret)
+ return ret;
+ return platform_driver_register(&stixxxx_pctl_driver);
+}
+arch_initcall(stixxxx_pctl_init);
diff --git a/drivers/pinctrl/pinctrl-stixxxx.h b/drivers/pinctrl/pinctrl-stixxxx.h
new file mode 100644
index 0000000..e88ab09
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-stixxxx.h
@@ -0,0 +1,197 @@
+
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Authors:
+ * Srinivas Kandagatla <[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.
+ *
+ */
+
+#ifndef __LINUX_DRIVERS_PINCTRL_STIXXXX_H
+#define __LINUX_DRIVERS_PINCTRL_STIXXXX_H
+
+enum stixxxx_retime_style {
+ stixxxx_retime_style_none,
+ stixxxx_retime_style_packed,
+ stixxxx_retime_style_dedicated,
+};
+
+/* Byte positions in 2 syscon words, starts from 0 */
+struct stixxxx_retime_offset {
+ int retime_offset;
+ int clk1notclk0_offset;
+ int clknotdata_offset;
+ int double_edge_offset;
+ int invertclk_offset;
+ int delay_lsb_offset;
+ int delay_msb_offset;
+};
+
+struct stixxxx_retime_params {
+ const struct stixxxx_retime_offset *retime_offset;
+ unsigned int *delay_times_in;
+ int num_delay_times_in;
+ unsigned int *delay_times_out;
+ int num_delay_times_out;
+};
+
+struct stixxxx_pio_control {
+ enum stixxxx_retime_style rt_style;
+ u32 rt_pin_mask;
+ const struct stixxxx_retime_params *rt_params;
+ struct regmap_field *alt;
+ struct regmap_field *oe, *pu, *od;
+ struct regmap_field *retiming[8];
+};
+
+/* PIO Block registers */
+/* PIO output */
+#define REG_PIO_POUT 0x00
+/* Set bits of POUT */
+#define REG_PIO_SET_POUT 0x04
+/* Clear bits of POUT */
+#define REG_PIO_CLR_POUT 0x08
+/* PIO input */
+#define REG_PIO_PIN 0x10
+/* PIO configuration */
+#define REG_PIO_PC(n) (0x20 + (n) * 0x10)
+/* Set bits of PC[2:0] */
+#define REG_PIO_SET_PC(n) (0x24 + (n) * 0x10)
+/* Clear bits of PC[2:0] */
+#define REG_PIO_CLR_PC(n) (0x28 + (n) * 0x10)
+/* PIO input comparison */
+#define REG_PIO_PCOMP 0x50
+/* Set bits of PCOMP */
+#define REG_PIO_SET_PCOMP 0x54
+/* Clear bits of PCOMP */
+#define REG_PIO_CLR_PCOMP 0x58
+/* PIO input comparison mask */
+#define REG_PIO_PMASK 0x60
+/* Set bits of PMASK */
+#define REG_PIO_SET_PMASK 0x64
+/* Clear bits of PMASK */
+#define REG_PIO_CLR_PMASK 0x68
+
+#define STIXXXX_MAX_GPIO_BANKS 32
+
+#define STIXXXX_GPIO_DIRECTION_BIDIR 0x1
+#define STIXXXX_GPIO_DIRECTION_OUT 0x2
+#define STIXXXX_GPIO_DIRECTION_IN 0x4
+
+#define STIXXXX_GPIO_PINS_PER_PORT 8
+#define stixxxx_gpio_port(gpio) ((gpio) / STIXXXX_GPIO_PINS_PER_PORT)
+#define stixxxx_gpio_pin(gpio) ((gpio) % STIXXXX_GPIO_PINS_PER_PORT)
+
+/* pinconf */
+/*
+ * Pinconf is represented in an opaque unsigned long variable.
+ * Below is the bit allocation details for each possible configuration.
+ * All the bit fields can be encapsulated into four variables
+ * (direction, retime-type, retime-clk, retime-delay)
+ *
+ * +----------------+
+ *[31:28]| reserved-3 |
+ * +----------------+-------------
+ *[27] | oe | |
+ * +----------------+ v
+ *[26] | pu | [Direction ]
+ * +----------------+ ^
+ *[25] | od | |
+ * +----------------+-------------
+ *[24] | reserved-2 |
+ * +----------------+-------------
+ *[23] | retime | |
+ * +----------------+ |
+ *[22] | retime-invclk | |
+ * +----------------+ v
+ *[21] |retime-clknotdat| [Retime-type ]
+ * +----------------+ ^
+ *[20] | retime-de | |
+ * +----------------+-------------
+ *[19:18]| retime-clk |------>[Retime-Clk ]
+ * +----------------+
+ *[17:16]| reserved-1 |
+ * +----------------+
+ *[15..0]| retime-delay |------>[Retime Delay]
+ * +----------------+
+ */
+
+#define STIXXXX_PINCONF_UNPACK(conf, param)\
+ ((conf >> STIXXXX_PINCONF_ ##param ##_SHIFT) \
+ & STIXXXX_PINCONF_ ##param ##_MASK)
+
+#define STIXXXX_PINCONF_PACK(conf, val, param) (conf |=\
+ ((val & STIXXXX_PINCONF_ ##param ##_MASK) << \
+ STIXXXX_PINCONF_ ##param ##_SHIFT))
+
+/* Output enable */
+#define STIXXXX_PINCONF_OE_MASK 0x1
+#define STIXXXX_PINCONF_OE_SHIFT 27
+#define STIXXXX_PINCONF_OE BIT(27)
+#define STIXXXX_PINCONF_UNPACK_OE(conf) STIXXXX_PINCONF_UNPACK(conf, OE)
+#define STIXXXX_PINCONF_PACK_OE(conf, val) STIXXXX_PINCONF_PACK(conf, val, OE)
+
+/* Pull Up */
+#define STIXXXX_PINCONF_PU_MASK 0x1
+#define STIXXXX_PINCONF_PU_SHIFT 26
+#define STIXXXX_PINCONF_PU BIT(26)
+#define STIXXXX_PINCONF_UNPACK_PU(conf) STIXXXX_PINCONF_UNPACK(conf, PU)
+#define STIXXXX_PINCONF_PACK_PU(conf, val) STIXXXX_PINCONF_PACK(conf, val, PU)
+
+/* Open Drain */
+#define STIXXXX_PINCONF_OD_MASK 0x1
+#define STIXXXX_PINCONF_OD_SHIFT 25
+#define STIXXXX_PINCONF_OD BIT(25)
+#define STIXXXX_PINCONF_UNPACK_OD(conf) STIXXXX_PINCONF_UNPACK(conf, OD)
+#define STIXXXX_PINCONF_PACK_OD(conf, val) STIXXXX_PINCONF_PACK(conf, val, OD)
+
+#define STIXXXX_PINCONF_RT_MASK 0x1
+#define STIXXXX_PINCONF_RT_SHIFT 23
+#define STIXXXX_PINCONF_RT BIT(23)
+#define STIXXXX_PINCONF_UNPACK_RT(conf) STIXXXX_PINCONF_UNPACK(conf, RT)
+#define STIXXXX_PINCONF_PACK_RT(conf, val) STIXXXX_PINCONF_PACK(conf, val, RT)
+
+#define STIXXXX_PINCONF_RT_INVERTCLK_MASK 0x1
+#define STIXXXX_PINCONF_RT_INVERTCLK_SHIFT 22
+#define STIXXXX_PINCONF_RT_INVERTCLK BIT(22)
+#define STIXXXX_PINCONF_UNPACK_RT_INVERTCLK(conf) \
+ STIXXXX_PINCONF_UNPACK(conf, RT_INVERTCLK)
+#define STIXXXX_PINCONF_PACK_RT_INVERTCLK(conf, val) \
+ STIXXXX_PINCONF_PACK(conf, val, RT_INVERTCLK)
+
+#define STIXXXX_PINCONF_RT_CLKNOTDATA_MASK 0x1
+#define STIXXXX_PINCONF_RT_CLKNOTDATA_SHIFT 21
+#define STIXXXX_PINCONF_RT_CLKNOTDATA BIT(21)
+#define STIXXXX_PINCONF_UNPACK_RT_CLKNOTDATA(conf) \
+ STIXXXX_PINCONF_UNPACK(conf, RT_CLKNOTDATA)
+#define STIXXXX_PINCONF_PACK_RT_CLKNOTDATA(conf, val) \
+ STIXXXX_PINCONF_PACK(conf, val, RT_CLKNOTDATA)
+
+#define STIXXXX_PINCONF_RT_DOUBLE_EDGE_MASK 0x1
+#define STIXXXX_PINCONF_RT_DOUBLE_EDGE_SHIFT 20
+#define STIXXXX_PINCONF_RT_DOUBLE_EDGE BIT(20)
+#define STIXXXX_PINCONF_UNPACK_RT_DOUBLE_EDGE(conf) \
+ STIXXXX_PINCONF_UNPACK(conf, RT_DOUBLE_EDGE)
+#define STIXXXX_PINCONF_PACK_RT_DOUBLE_EDGE(conf, val) \
+ STIXXXX_PINCONF_PACK(conf, val, RT_DOUBLE_EDGE)
+
+#define STIXXXX_PINCONF_RT_CLK_MASK 0x3
+#define STIXXXX_PINCONF_RT_CLK_SHIFT 18
+#define STIXXXX_PINCONF_RT_CLK BIT(18)
+#define STIXXXX_PINCONF_UNPACK_RT_CLK(conf) \
+ STIXXXX_PINCONF_UNPACK(conf, RT_CLK)
+#define STIXXXX_PINCONF_PACK_RT_CLK(conf, val) \
+ STIXXXX_PINCONF_PACK(conf, val, RT_CLK)
+
+/* RETIME_DELAY in Pico Secs */
+#define STIXXXX_PINCONF_RT_DELAY_MASK 0xffff
+#define STIXXXX_PINCONF_RT_DELAY_SHIFT 0
+#define STIXXXX_PINCONF_UNPACK_RT_DELAY(conf) \
+ STIXXXX_PINCONF_UNPACK(conf, RT_DELAY)
+#define STIXXXX_PINCONF_PACK_RT_DELAY(conf, val) \
+ STIXXXX_PINCONF_PACK(conf, val, RT_DELAY)
+
+#endif /* __LINUX_DRIVERS_PINCTRL_STIXXXX_H */
--
1.7.6.5

2013-06-10 09:29:05

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: [PATCH v2 06/11] ARM:stixxxx: Add STiH415 SOC support

The STiH415 is the next generation of HD, AVC set-top box processors for
satellite, cable, terrestrial and IP-STB markets. It is an ARM Cortex-A9
1.0 GHz, dual-core CPU.

Signed-off-by: Srinivas Kandagatla <[email protected]>
CC: Stephen Gallimore <[email protected]>
CC: Stuart Menefy <[email protected]>
CC: Arnd Bergmann <[email protected]>
CC: Linus Walleij <[email protected]>
---
Documentation/arm/stixxxx/overview.txt | 33 +++
Documentation/arm/stixxxx/stih415-overview.txt | 12 +
MAINTAINERS | 11 +
arch/arm/Kconfig | 2 +
arch/arm/Makefile | 1 +
arch/arm/boot/dts/stih415-clock.dtsi | 38 +++
arch/arm/boot/dts/stih415-pinctrl.dtsi | 326 ++++++++++++++++++++++++
arch/arm/boot/dts/stih415.dtsi | 102 ++++++++
arch/arm/boot/dts/stih41x.dtsi | 38 +++
arch/arm/boot/dts/stixxxx-pincfg.h | 94 +++++++
arch/arm/mach-stixxxx/Kconfig | 45 ++++
arch/arm/mach-stixxxx/Makefile | 2 +
arch/arm/mach-stixxxx/board-dt.c | 47 ++++
arch/arm/mach-stixxxx/headsmp.S | 44 ++++
arch/arm/mach-stixxxx/platsmp.c | 117 +++++++++
arch/arm/mach-stixxxx/smp.h | 19 ++
16 files changed, 931 insertions(+), 0 deletions(-)
create mode 100644 Documentation/arm/stixxxx/overview.txt
create mode 100644 Documentation/arm/stixxxx/stih415-overview.txt
create mode 100644 arch/arm/boot/dts/stih415-clock.dtsi
create mode 100644 arch/arm/boot/dts/stih415-pinctrl.dtsi
create mode 100644 arch/arm/boot/dts/stih415.dtsi
create mode 100644 arch/arm/boot/dts/stih41x.dtsi
create mode 100644 arch/arm/boot/dts/stixxxx-pincfg.h
create mode 100644 arch/arm/mach-stixxxx/Kconfig
create mode 100644 arch/arm/mach-stixxxx/Makefile
create mode 100644 arch/arm/mach-stixxxx/board-dt.c
create mode 100644 arch/arm/mach-stixxxx/headsmp.S
create mode 100644 arch/arm/mach-stixxxx/platsmp.c
create mode 100644 arch/arm/mach-stixxxx/smp.h

diff --git a/Documentation/arm/stixxxx/overview.txt b/Documentation/arm/stixxxx/overview.txt
new file mode 100644
index 0000000..a2f6390
--- /dev/null
+++ b/Documentation/arm/stixxxx/overview.txt
@@ -0,0 +1,33 @@
+ STixxxx ARM Linux Overview
+ ==========================
+
+Introduction
+------------
+
+ The ST Microelectronics Multimedia and Application Processors range of
+ CortexA9 System-on-Chip are supported by the 'STixxxx' platform of
+ ARM Linux. Currently STiH415, STiH416 SOCs are supported with both
+ B2000 and B2020 Reference boards.
+
+
+ configuration
+ -------------
+
+ A generic configuration is provided for both STiH415/416, and can be used as the
+ default by
+ make stih41x_defconfig
+
+ Layout
+ ------
+ All the files for multiple machine families (STiH415, STiH416, and STiG125)
+ are located in the platform code contained in arch/arm/mach-stixxxx
+
+ 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
+ ---------------
+
+ Srinivas Kandagatla <[email protected]>, (c) 2013 ST Microelectronics
diff --git a/Documentation/arm/stixxxx/stih415-overview.txt b/Documentation/arm/stixxxx/stih415-overview.txt
new file mode 100644
index 0000000..1c264b7
--- /dev/null
+++ b/Documentation/arm/stixxxx/stih415-overview.txt
@@ -0,0 +1,12 @@
+ STiH415 Overview
+ ================
+
+Introduction
+------------
+
+ The STiH415 is the next generation of HD, AVC set-top box processors
+ for satellite, cable, terrestrial and IP-STB markets.
+
+ Features
+ - ARM Cortex-A9 1.0 GHz, dual-core CPU
+ - SATA2×2,USB 2.0×3, PCIe, Gbit Ethernet MAC×2
diff --git a/MAINTAINERS b/MAINTAINERS
index 250dc97..2aca7d2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1201,6 +1201,17 @@ M: Dinh Nguyen <[email protected]>
S: Maintained
F: drivers/clk/socfpga/

+ARM/STIXXXX ARCHITECTURE
+M: Srinivas Kandagatla <[email protected]>
+M: Stuart Menefy <[email protected]>
+L: [email protected] (moderated for non-subscribers)
+W: http://www.stlinux.com
+S: Maintained
+F: arch/arm/mach-stixxxx/
+F: drivers/pinctrl/pinctrl-stixxxx*
+F: drivers/mfd/stixxxx-syscfg*
+F: drivers/clocksource/global_timer.c
+
ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
M: Lennert Buytenhek <[email protected]>
L: [email protected] (moderated for non-subscribers)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 49d993c..790e321 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -989,6 +989,8 @@ source "arch/arm/mach-socfpga/Kconfig"

source "arch/arm/mach-spear/Kconfig"

+source "arch/arm/mach-stixxxx/Kconfig"
+
source "arch/arm/mach-s3c24xx/Kconfig"

if ARCH_S3C64XX
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 1ba358b..c876e0a 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -191,6 +191,7 @@ machine-$(CONFIG_ARCH_W90X900) += w90x900
machine-$(CONFIG_FOOTBRIDGE) += footbridge
machine-$(CONFIG_ARCH_SOCFPGA) += socfpga
machine-$(CONFIG_PLAT_SPEAR) += spear
+machine-$(CONFIG_ARCH_STIXXXX) += stixxxx
machine-$(CONFIG_ARCH_VIRT) += virt
machine-$(CONFIG_ARCH_ZYNQ) += zynq
machine-$(CONFIG_ARCH_SUNXI) += sunxi
diff --git a/arch/arm/boot/dts/stih415-clock.dtsi b/arch/arm/boot/dts/stih415-clock.dtsi
new file mode 100644
index 0000000..174c799
--- /dev/null
+++ b/arch/arm/boot/dts/stih415-clock.dtsi
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited
+ *
+ * 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.
+ */
+/ {
+ clocks {
+ /*
+ * Fixed 30MHz oscillator input to SoC
+ */
+ CLK_SYSIN: CLK_SYSIN {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <30000000>;
+ };
+
+ /*
+ * ARM Peripheral clock for timers
+ */
+ arm_periph_clk: arm_periph_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <500000000>;
+ };
+
+ /*
+ * Bootloader initialized system infrastructure clock for
+ * serial devices.
+ */
+ CLKS_ICN_REG_0: CLKS_ICN_REG_0 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <100000000>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/stih415-pinctrl.dtsi b/arch/arm/boot/dts/stih415-pinctrl.dtsi
new file mode 100644
index 0000000..c510f11
--- /dev/null
+++ b/arch/arm/boot/dts/stih415-pinctrl.dtsi
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Srinivas Kandagatla <[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
+ * publishhed by the Free Software Foundation.
+ */
+#include "stixxxx-pincfg.h"
+/ {
+
+ aliases {
+ gpio0 = &PIO0;
+ gpio1 = &PIO1;
+ gpio2 = &PIO2;
+ gpio3 = &PIO3;
+ gpio4 = &PIO4;
+ gpio5 = &PIO5;
+ gpio6 = &PIO6;
+ gpio7 = &PIO7;
+ gpio8 = &PIO8;
+ gpio9 = &PIO9;
+ gpio10 = &PIO10;
+ gpio11 = &PIO11;
+ gpio12 = &PIO12;
+ gpio13 = &PIO13;
+ gpio14 = &PIO14;
+ gpio15 = &PIO15;
+ gpio16 = &PIO16;
+ gpio17 = &PIO17;
+ gpio18 = &PIO18;
+ gpio19 = &PIO100;
+ gpio20 = &PIO101;
+ gpio21 = &PIO102;
+ gpio22 = &PIO103;
+ gpio23 = &PIO104;
+ gpio24 = &PIO105;
+ gpio25 = &PIO106;
+ gpio26 = &PIO107;
+ };
+
+
+ soc {
+ pin-controller-sbc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,stih415-pinctrl", "simple-bus";
+ st,retime-in-delay = <0 500 1000 1500>;
+ st,retime-out-delay = <0 1000 2000 3000>;
+ st,syscfg = <&syscfg_sbc>;
+ st,syscfg-offsets = <0 5 7 9 16>;
+ ranges;
+
+ PIO0: pinctrl@fe610000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfe610000 0x100>;
+ st,bank-name = "PIO0";
+ };
+
+ PIO1: pinctrl@fe611000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfe611000 0x100>;
+ st,bank-name = "PIO1";
+ };
+
+ PIO2: pinctrl@fe612000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfe612000 0x100>;
+ st,bank-name = "PIO2";
+ };
+
+ PIO3: pinctrl@fe613000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfe613000 0x100>;
+ st,bank-name = "PIO3";
+
+ };
+
+ PIO4: pinctrl@fe614000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfe614000 0x100>;
+ st,bank-name = "PIO4";
+ };
+
+ sbc_serial1 {
+ pinctrl_sbc_serial1:sbc_serial1 {
+ st,function = <ALT3>;
+ st,pins {
+ tx = <&PIO2 6 OUT>;
+ rx = <&PIO2 7 IN>;
+ };
+ };
+ };
+ };
+
+ pin-controller-front {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,stih415-pinctrl", "simple-bus";
+ st,retime-in-delay = <0 500 1000 1500>;
+ st,retime-out-delay = <0 1000 2000 3000>;
+ st,syscfg = <&syscfg_front>;
+ st,syscfg-offsets = <0 8 10 12 16>;
+ ranges;
+
+ PIO5: pinctrl@fee00000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfee00000 0x100>;
+ st,bank-name = "PIO5";
+ };
+ PIO6: pinctrl@fee01000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfee01000 0x100>;
+ st,bank-name = "PIO6";
+ };
+
+ PIO7: pinctrl@fee02000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfee02000 0x100>;
+ st,bank-name = "PIO7";
+ };
+ PIO8: pinctrl@fee03000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfee03000 0x100>;
+ st,bank-name = "PIO8";
+ };
+ PIO9: pinctrl@fee04000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfee04000 0x100>;
+ st,bank-name = "PIO9";
+ };
+ PIO10: pinctrl@fee05000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfee05000 0x100>;
+ st,bank-name = "PIO10";
+ };
+ PIO11: pinctrl@fee06000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfee06000 0x100>;
+ st,bank-name = "PIO11";
+ };
+ PIO12: pinctrl@fee07000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfee07000 0x100>;
+ st,bank-name = "PIO12";
+ };
+ };
+
+ pin-controller-rear {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,stih415-pinctrl", "simple-bus";
+ st,retime-in-delay = <0 500 1000 1500>;
+ st,retime-out-delay = <0 1000 2000 3000>;
+ st,syscfg = <&syscfg_rear>;
+ st,syscfg-offsets = <0 6 8 10 38>;
+ ranges;
+
+ PIO13: pinctrl@fe820000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfe820000 0x100>;
+ st,bank-name = "PIO13";
+ };
+ PIO14: pinctrl@fe821000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfe821000 0x100>;
+ st,bank-name = "PIO14";
+ };
+ PIO15: pinctrl@fe822000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfe822000 0x100>;
+ st,bank-name = "PIO15";
+ };
+ PIO16: pinctrl@fe823000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfe823000 0x100>;
+ st,bank-name = "PIO16";
+
+ };
+ PIO17: pinctrl@fe824000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfe824000 0x100>;
+ st,bank-name = "PIO17";
+
+ };
+ PIO18: pinctrl@fe825000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfe825000 0x100>;
+ st,bank-name = "PIO18";
+
+ };
+
+ serial2 {
+ pinctrl_serial2: serial2-0 {
+ st,function = <ALT2>;
+ st,pins {
+ tx = <&PIO17 4 OUT>;
+ rx = <&PIO17 5 IN>;
+ };
+ };
+ };
+
+ };
+
+ pin-controller-left {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,stih415-pinctrl", "simple-bus";
+ st,retime-in-delay = <0 500 1000 1500>;
+ st,retime-out-delay = <0 1000 2000 3000>;
+ st,syscfg = <&syscfg_left>;
+ st,syscfg-offsets = <0 3 4 5 6>;
+ ranges;
+
+ PIO100: pinctrl@fd6b0000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfd6b0000 0x100>;
+ st,bank-name = "PIO100";
+ };
+ PIO101: pinctrl@fd6b1000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfd6b1000 0x100>;
+ st,bank-name = "PIO101";
+
+ };
+ PIO102: pinctrl@fd6b2000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfd6b2000 0x100>;
+ st,bank-name = "PIO102";
+
+ };
+
+ };
+
+ pin-controller-right {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,stih415-pinctrl", "simple-bus";
+ st,retime-in-delay = <0 500 1000 1500>;
+ st,retime-out-delay = <0 1000 2000 3000>;
+ st,syscfg = <&syscfg_right>;
+ st,syscfg-offsets = <0 5 7 9 11>;
+ ranges;
+
+ PIO103: pinctrl@fd330000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfd330000 0x100>;
+ st,bank-name = "PIO103";
+ };
+ PIO104: pinctrl@fd331000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfd331000 0x100>;
+ st,bank-name = "PIO104";
+ };
+ PIO105: pinctrl@fd332000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfd332000 0x100>;
+ st,bank-name = "PIO105";
+ };
+ PIO106: pinctrl@fd333000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfd333000 0x100>;
+ st,bank-name = "PIO106";
+ };
+ PIO107: pinctrl@fd334000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ reg = <0xfd334000 0x100>;
+ st,bank-name = "PIO107";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/stih415.dtsi b/arch/arm/boot/dts/stih415.dtsi
new file mode 100644
index 0000000..6dcf5b4
--- /dev/null
+++ b/arch/arm/boot/dts/stih415.dtsi
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Srinivas Kandagatla <[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
+ * publishhed by the Free Software Foundation.
+ */
+#include "stih41x.dtsi"
+#include "stih415-clock.dtsi"
+#include "stih415-pinctrl.dtsi"
+/ {
+
+ L2: cache-controller {
+ compatible = "arm,pl310-cache";
+ reg = <0xfffe2000 0x1000>;
+ arm,data-latency = <3 2 2>;
+ arm,tag-latency = <1 1 1>;
+ cache-unified;
+ cache-level = <2>;
+ };
+
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&intc>;
+ ranges;
+ compatible = "simple-bus";
+
+ syscfg_sbc: syscfg@fe600000{
+ compatible = "st,stih415-syscfg";
+ reg = <0xfe600000 0xb4>;
+ syscfg-range = <0 44>;
+ syscfg-name = "SYSCFG_SBC";
+ };
+
+ syscfg_front: syscfg@fee10000{
+ compatible = "st,stih415-syscfg";
+ reg = <0xfee10000 0x194>;
+ syscfg-range = <100 100>;
+ syscfg-name = "SYSCFG_FRONT";
+ };
+
+ syscfg_rear: syscfg@fe830000{
+ compatible = "st,stih415-syscfg";
+ reg = <0xfe830000 0x190>;
+ syscfg-range = <300 99>;
+ syscfg-name = "SYSCFG_REAR";
+ };
+
+ /* MPE syscfgs */
+ syscfg_left: syscfg@fd690000{
+ compatible = "st,stih415-syscfg";
+ reg = <0xfd690000 0x78>;
+ syscfg-range = <400 29>;
+ syscfg-name = "SYSCFG_LEFT";
+ };
+
+ syscfg_right: syscfg@fd320000{
+ compatible = "st,stih415-syscfg";
+ reg = <0xfd320000 0x180>;
+ syscfg-range = <500 95>;
+ syscfg-name = "SYSCFG_RIGHT";
+ };
+
+ syscfg_system: syscfg@fdde0000 {
+ compatible = "st,stih415-syscfg";
+ reg = <0xfdde0000 0x15c>;
+ syscfg-range = <600 86>;
+ syscfg-name = "SYSCFG_SYSTEM";
+ };
+
+ syscfg_lpm: syscfg@fe4b5100{
+ compatible = "st,stih415-syscfg";
+ reg = <0xfe4b5100 0x08>;
+ syscfg-range = <0 10>;
+ syscfg-name = "LPM_CFG_REGS";
+ };
+
+ serial2: serial@fed32000 {
+ compatible = "st,asc";
+ status = "disabled";
+ reg = <0xfed32000 0x2c>;
+ interrupts = <0 197 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_serial2>;
+ clocks = <&CLKS_ICN_REG_0>;
+ };
+
+ /* SBC comms block ASCs in SASG1 */
+ sbc_serial1: serial@fe531000 {
+ compatible = "st,asc";
+ status = "disabled";
+ reg = <0xfe531000 0x2c>;
+ interrupts = <0 210 0>;
+ clocks = <&CLK_SYSIN>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sbc_serial1>;
+ };
+
+ };
+};
diff --git a/arch/arm/boot/dts/stih41x.dtsi b/arch/arm/boot/dts/stih41x.dtsi
new file mode 100644
index 0000000..7321403
--- /dev/null
+++ b/arch/arm/boot/dts/stih41x.dtsi
@@ -0,0 +1,38 @@
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cpu@0 {
+ compatible = "arm,cortex-a9";
+ reg = <0>;
+ };
+ cpu@1 {
+ compatible = "arm,cortex-a9";
+ reg = <1>;
+ };
+ };
+
+ intc: interrupt-controller@fffe1000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0xfffe1000 0x1000>,
+ <0xfffe0100 0x100>;
+ };
+
+ scu@fffe0000 {
+ compatible = "arm,cortex-a9-scu";
+ reg = <0xfffe0000 0x1000>;
+ };
+
+ timer@fffe0200 {
+ interrupt-parent = <&intc>;
+ compatible = "arm,cortex-a9-global-timer";
+ reg = <0xfffe0200 0x100>;
+ interrupts = <1 11 0x04>;
+ clocks = <&arm_periph_clk>;
+ };
+};
diff --git a/arch/arm/boot/dts/stixxxx-pincfg.h b/arch/arm/boot/dts/stixxxx-pincfg.h
new file mode 100644
index 0000000..0dfaba0
--- /dev/null
+++ b/arch/arm/boot/dts/stixxxx-pincfg.h
@@ -0,0 +1,94 @@
+#ifndef _STIXXXX_PINCFG_H_
+#define _STIXXXX_PINCFG_H_
+
+/* Alternate functions */
+#define ALT1 1
+#define ALT2 2
+#define ALT3 3
+#define ALT4 4
+#define ALT5 5
+#define ALT6 6
+#define ALT7 7
+
+/* Output enable */
+#define OE_MASK 0x1
+#define OE_SHIFT 27
+#define OE (1 << OE_SHIFT)
+
+/* Pull Up */
+#define PU_MASK 0x1
+#define PU_SHIFT 26
+#define PU (1 << PU_SHIFT)
+
+/* Open Drain */
+#define OD_MASK 0x1
+#define OD_SHIFT 25
+#define OD (1 << OD_SHIFT)
+
+#define RT_MASK 0x1
+#define RT_SHIFT 23
+#define RT (1 << RT_SHIFT)
+
+#define INVERTCLK_MASK 0x1
+#define INVERTCLK_SHIFT 22
+#define INVERTCLK (1 << INVERTCLK_SHIFT)
+
+#define CLKNOTDATA_MASK 0x1
+#define CLKNOTDATA_SHIFT 21
+#define CLKNOTDATA (1 << CLKNOTDATA_SHIFT)
+
+#define DOUBLE_EDGE_MASK 0x1
+#define DOUBLE_EDGE_SHIFT 20
+#define DOUBLE_EDGE (1 << DOUBLE_EDGE_SHIFT)
+
+#define CLK_MASK 0x3
+#define CLK_SHIFT 18
+#define CLK_A (0 << CLK_SHIFT)
+#define CLK_B (1 << CLK_SHIFT)
+#define CLK_C (2 << CLK_SHIFT)
+#define CLK_D (3 << CLK_SHIFT)
+
+/* User-frendly defines for Pin Direction */
+ /* oe = 0, pu = 0, od = 0 */
+#define IN (0)
+ /* oe = 0, pu = 1, od = 0 */
+#define IN_PU (PU)
+ /* oe = 1, pu = 0, od = 0 */
+#define OUT (OE)
+ /* oe = 1, pu = 0, od = 1 */
+#define BIDIR (OE | OD)
+ /* oe = 1, pu = 1, od = 1 */
+#define BIDIR_PU (OE | PU | OD)
+
+/* RETIME_TYPE */
+/*
+ * B Mode
+ * Bypass retime with optional delay parameter
+ */
+#define BYPASS (0)
+/*
+ * R0, R1, R0D, R1D modes
+ * single-edge data non inverted clock, retime data with clk
+ */
+#define SE_NICLK_IO (RT)
+/*
+ * RIV0, RIV1, RIV0D, RIV1D modes
+ * single-edge data inverted clock, retime data with clk
+ */
+#define SE_ICLK_IO (RT | INVERTCLK)
+/*
+ * R0E, R1E, R0ED, R1ED modes
+ * double-edge data, retime data with clk
+ */
+#define DE_IO (RT | DOUBLE_EDGE)
+/*
+ * CIV0, CIV1 modes with inverted clock
+ * Retiming the clk pins will park clock & reduce the noise within the core.
+ */
+#define ICLK (RT | CLKNOTDATA | INVERTCLK)
+/*
+ * CLK0, CLK1 modes with non-inverted clock
+ * Retiming the clk pins will park clock & reduce the noise within the core.
+ */
+#define NICLK (RT | CLKNOTDATA)
+#endif /* _STIXXXX_PINCFG_H_ */
diff --git a/arch/arm/mach-stixxxx/Kconfig b/arch/arm/mach-stixxxx/Kconfig
new file mode 100644
index 0000000..278d938
--- /dev/null
+++ b/arch/arm/mach-stixxxx/Kconfig
@@ -0,0 +1,45 @@
+menuconfig ARCH_STIXXXX
+ bool "STMicroelectronics Consumer Electronics SOCs with Device Trees" if ARCH_MULTI_V7
+ select GENERIC_CLOCKEVENTS
+ select CLKDEV_LOOKUP
+ select ARM_GIC
+ select ARM_GLOBAL_TIMER
+ select MFD_STIXXXX_SYSCFG
+ select PINCTRL
+ select PINCTRL_STIXXXX
+ select MIGHT_HAVE_CACHE_L2X0
+ select HAVE_SMP
+ select HAVE_ARM_SCU if SMP
+ select ARCH_REQUIRE_GPIOLIB
+ select ARM_ERRATA_720789
+ select ARM_ERRATA_754322
+ select PL310_ERRATA_753970
+ select PL310_ERRATA_769419
+ help
+ Include support for STiH41x SOCs like STiH415/416 using the device tree
+ for discovery
+ More information at Documentation/arm/STiH41x and
+ at Documentation/devicetree
+
+
+if ARCH_STIXXXX
+
+config SOC_STIH415
+ bool "STiH415 STMicroelectronics Consumer Electronics family"
+ default y
+ help
+ This enables support for STMicroelectronics Digital Consumer
+ Electronics family StiH415 parts, primarily targetted at set-top-box
+ and other digital audio/video applications using Flattned Device
+ Trees.
+
+config SOC_STIH416
+ bool "STiH416 STMicroelectronics Consumer Electronics family"
+ default y
+ help
+ This enables support for STMicroelectronics Digital Consumer
+ Electronics family StiH416 parts, primarily targetted at set-top-box
+ and other digital audio/video applications using Flattened Device
+ Trees.
+
+endif
diff --git a/arch/arm/mach-stixxxx/Makefile b/arch/arm/mach-stixxxx/Makefile
new file mode 100644
index 0000000..50bf128
--- /dev/null
+++ b/arch/arm/mach-stixxxx/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SMP) += platsmp.o headsmp.o
+obj-$(CONFIG_ARCH_STIXXXX) += board-dt.o
diff --git a/arch/arm/mach-stixxxx/board-dt.c b/arch/arm/mach-stixxxx/board-dt.c
new file mode 100644
index 0000000..52ce665
--- /dev/null
+++ b/arch/arm/mach-stixxxx/board-dt.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author(s): Srinivas Kandagatla <[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 <linux/clk-provider.h>
+#include <linux/clocksource.h>
+#include <linux/irq.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <asm/mach/arch.h>
+
+#include "smp.h"
+
+void __init stih41x_l2x0_init(void)
+{
+ u32 way_size = 0x4;
+ u32 aux_ctrl;
+
+ aux_ctrl = (0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) |
+ (0x1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) |
+ (0x1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) |
+ (way_size << L2X0_AUX_CTRL_WAY_SIZE_SHIFT);
+
+ l2x0_of_init(aux_ctrl, L2X0_AUX_CTRL_MASK);
+}
+
+static void __init stih41x_timer_init(void)
+{
+ of_clk_init(NULL);
+ clocksource_of_init();
+ stih41x_l2x0_init();
+}
+
+static const char *stih41x_dt_match[] __initdata = {
+ "st,stih415",
+ NULL
+};
+
+DT_MACHINE_START(STM, "STiH415 SoC with Flattened Device Tree")
+ .init_time = stih41x_timer_init,
+ .smp = smp_ops(stixxxx_smp_ops),
+ .dt_compat = stih41x_dt_match,
+MACHINE_END
diff --git a/arch/arm/mach-stixxxx/headsmp.S b/arch/arm/mach-stixxxx/headsmp.S
new file mode 100644
index 0000000..3dd5c04
--- /dev/null
+++ b/arch/arm/mach-stixxxx/headsmp.S
@@ -0,0 +1,44 @@
+/*
+ * arch/arm/plat-stixxxx/headsmp.S
+ *
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * http://www.st.com
+ *
+ * Cloned from linux/arch/arm/mach-vexpress/headsmp.S
+ *
+ * Copyright (c) 2003 ARM Limited
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+ __INIT
+
+/*
+ * ST specific entry point for secondary CPUs. This provides
+ * a "holding pen" into which all secondary cores are held until we're
+ * ready for them to initialise.
+ */
+ENTRY(stixxxx_secondary_startup)
+ mrc p15, 0, r0, c0, c0, 5
+ and r0, r0, #15
+ adr r4, 1f
+ ldmia r4, {r5, r6}
+ sub r4, r4, r5
+ add r6, r6, r4
+pen: ldr r7, [r6]
+ cmp r7, r0
+ bne pen
+
+ /*
+ * we've been released from the holding pen: secondary_stack
+ * should now contain the SVC stack for this core
+ */
+ b secondary_startup
+
+1: .long .
+ .long pen_release
diff --git a/arch/arm/mach-stixxxx/platsmp.c b/arch/arm/mach-stixxxx/platsmp.c
new file mode 100644
index 0000000..ffc40c0
--- /dev/null
+++ b/arch/arm/mach-stixxxx/platsmp.c
@@ -0,0 +1,117 @@
+/*
+ * arch/arm/plat-stixxxx/platsmp.c
+ *
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * http://www.st.com
+ *
+ * Cloned from linux/arch/arm/mach-vexpress/platsmp.c
+ *
+ * Copyright (C) 2002 ARM Ltd.
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/smp.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <asm/cacheflush.h>
+#include <asm/smp_plat.h>
+#include <asm/smp_scu.h>
+
+#include "smp.h"
+
+static void __cpuinit write_pen_release(int val)
+{
+ pen_release = val;
+ smp_wmb();
+ __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
+ outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
+}
+
+static DEFINE_SPINLOCK(boot_lock);
+
+void __cpuinit stixxxx_secondary_init(unsigned int cpu)
+{
+ trace_hardirqs_off();
+
+ /*
+ * let the primary processor know we're out of the
+ * pen, then head off into the C entry point
+ */
+ write_pen_release(-1);
+
+ /*
+ * Synchronise with the boot thread.
+ */
+ spin_lock(&boot_lock);
+ spin_unlock(&boot_lock);
+}
+
+int __cpuinit stixxxx_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ unsigned long timeout;
+
+ /*
+ * set synchronisation state between this boot processor
+ * and the secondary one
+ */
+ spin_lock(&boot_lock);
+
+ /*
+ * The secondary processor is waiting to be released from
+ * the holding pen - release it, then wait for it to flag
+ * that it has been released by resetting pen_release.
+ *
+ * Note that "pen_release" is the hardware CPU ID, whereas
+ * "cpu" is Linux's internal ID.
+ */
+ write_pen_release(cpu_logical_map(cpu));
+
+ /*
+ * Send the secondary CPU a soft interrupt, thereby causing
+ * it to jump to the secondary entrypoint.
+ */
+ arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+
+ timeout = jiffies + (1 * HZ);
+ while (time_before(jiffies, timeout)) {
+ smp_rmb();
+ if (pen_release == -1)
+ break;
+
+ udelay(10);
+ }
+
+ /*
+ * now the secondary core is starting up let it run its
+ * calibrations, then wait for it to finish
+ */
+ spin_unlock(&boot_lock);
+
+ return pen_release != -1 ? -ENOSYS : 0;
+}
+
+void __init stixxxx_smp_prepare_cpus(unsigned int max_cpus)
+{
+ void __iomem *scu_base = NULL;
+ struct device_node *np = of_find_compatible_node(
+ NULL, NULL, "arm,cortex-a9-scu");
+ if (np) {
+ scu_base = of_iomap(np, 0);
+ scu_enable(scu_base);
+ of_node_put(np);
+ }
+}
+
+struct smp_operations __initdata stixxxx_smp_ops = {
+ .smp_prepare_cpus = stixxxx_smp_prepare_cpus,
+ .smp_secondary_init = stixxxx_secondary_init,
+ .smp_boot_secondary = stixxxx_boot_secondary,
+};
diff --git a/arch/arm/mach-stixxxx/smp.h b/arch/arm/mach-stixxxx/smp.h
new file mode 100644
index 0000000..c3e3d40
--- /dev/null
+++ b/arch/arm/mach-stixxxx/smp.h
@@ -0,0 +1,19 @@
+/*
+ * arch/arm/plat-stixxxx/platsmp.c
+ *
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * http://www.st.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __PLAT_SMP_H
+#define __PLAT_SMP_H
+
+extern struct smp_operations stixxxx_smp_ops;
+extern void __iomem *stixxxx_scu_base_addr;
+extern void stixxxx_secondary_startup(void);
+
+#endif
--
1.7.6.5

2013-06-10 09:30:24

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: [PATCH v2 08/11] ARM:stixxxx: Add DEBUG_LL console support

This patch adds low level debug uart support to stixxxx based SOCs.

Signed-off-by: Srinivas Kandagatla <[email protected]>
CC: Arnd Bergmann <[email protected]>
---
arch/arm/Kconfig.debug | 38 +++++++++++++++++++++++
arch/arm/include/debug/stixxxx.S | 61 ++++++++++++++++++++++++++++++++++++++
arch/arm/mach-stixxxx/board-dt.c | 2 +
3 files changed, 101 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/include/debug/stixxxx.S

diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 1d41908..cc98ef3 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -483,6 +483,16 @@ choice
This option selects UART0 on VIA/Wondermedia System-on-a-chip
devices, including VT8500, WM8505, WM8650 and WM8850.

+ config DEBUG_STIXXXX_UART
+ depends on ARCH_STIXXXX
+ bool "Use StiH415/416 ASC for low-level debug"
+ help
+ Say Y here if you want kernel low-level debugging support
+ on StiH415/416 based platforms like B2000, B2020.
+ It support UART2 and SBC_UART1.
+
+ If unsure, say N.
+
config DEBUG_LL_UART_NONE
bool "No low-level debugging UART"
depends on !ARCH_MULTIPLATFORM
@@ -617,6 +627,33 @@ choice

endchoice

+choice
+ prompt "Low-level debug console UART"
+ depends on DEBUG_LL && DEBUG_STIXXXX_UART
+
+ config STIH41X_DEBUG_ASC2
+ bool "ASC2 UART"
+ help
+ Say Y here if you want kernel low-level debugging support
+ on STiH415/416 based platforms like b2000, which has
+ default UART wired up to ASC2.
+
+ If unsure, say N.
+
+ config STIH41X_DEBUG_SBC_ASC1
+ bool "SBC ASC1 UART"
+ help
+ Say Y here if you want kernel low-level debugging support
+ on STiH415/416 based platforms like b2020. which has
+ default UART wired up to SBC ASC1.
+
+ If unsure, say N.
+
+endchoice
+
+
+
+
config DEBUG_LL_INCLUDE
string
default "debug/bcm2835.S" if DEBUG_BCM2835
@@ -641,6 +678,7 @@ config DEBUG_LL_INCLUDE
DEBUG_MMP_UART3
default "debug/sirf.S" if DEBUG_SIRFPRIMA2_UART1 || DEBUG_SIRFMARCO_UART1
default "debug/socfpga.S" if DEBUG_SOCFPGA_UART
+ default "debug/stixxxx.S" if DEBUG_STIXXXX_UART
default "debug/sunxi.S" if DEBUG_SUNXI_UART0 || DEBUG_SUNXI_UART1
default "debug/tegra.S" if DEBUG_TEGRA_UART
default "debug/ux500.S" if DEBUG_UX500_UART
diff --git a/arch/arm/include/debug/stixxxx.S b/arch/arm/include/debug/stixxxx.S
new file mode 100644
index 0000000..7bc02a7
--- /dev/null
+++ b/arch/arm/include/debug/stixxxx.S
@@ -0,0 +1,61 @@
+/*
+ * arch/arm/include/debug/stixxxx.S
+ *
+ * Debugging macro include header
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ *
+ * 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 STIH41X_COMMS_BASE 0xfed00000
+#define STIH41X_ASC2_BASE (STIH41X_COMMS_BASE+0x32000)
+
+#define STIH41X_SBC_LPM_BASE 0xfe400000
+#define STIH41X_SBC_COMMS_BASE (STIH41X_SBC_LPM_BASE + 0x100000)
+#define STIH41X_SBC_ASC1_BASE (STIH41X_SBC_COMMS_BASE + 0x31000)
+
+
+#define VIRT_ADDRESS(x) (x - 0x1000000)
+
+#if IS_ENABLED(CONFIG_STIH41X_DEBUG_ASC2)
+#define DEBUG_LL_UART_BASE STIH41X_ASC2_BASE
+#endif
+
+#if IS_ENABLED(CONFIG_STIH41X_DEBUG_SBC_ASC1)
+#define DEBUG_LL_UART_BASE STIH41X_SBC_ASC1_BASE
+#endif
+
+#ifndef DEBUG_LL_UART_BASE
+#error "DEBUG UART is not Configured"
+#endif
+
+#define ASC_TX_BUF_OFF 0x04
+#define ASC_CTRL_OFF 0x0c
+#define ASC_STA_OFF 0x14
+
+#define ASC_STA_TX_FULL (1<<9)
+#define ASC_STA_TX_EMPTY (1<<1)
+
+
+ .macro addruart, rp, rv, tmp
+ ldr \rp, =DEBUG_LL_UART_BASE @ physical base
+ ldr \rv, =VIRT_ADDRESS(DEBUG_LL_UART_BASE) @ virt base
+ .endm
+
+ .macro senduart,rd,rx
+ strb \rd, [\rx, #ASC_TX_BUF_OFF]
+ .endm
+
+ .macro waituart,rd,rx
+1001: ldr \rd, [\rx, #ASC_STA_OFF]
+ tst \rd, #ASC_STA_TX_FULL
+ bne 1001b
+ .endm
+
+ .macro busyuart,rd,rx
+1001: ldr \rd, [\rx, #ASC_STA_OFF]
+ tst \rd, #ASC_STA_TX_EMPTY
+ beq 1001b
+ .endm
diff --git a/arch/arm/mach-stixxxx/board-dt.c b/arch/arm/mach-stixxxx/board-dt.c
index 2b2552e..2482d139 100644
--- a/arch/arm/mach-stixxxx/board-dt.c
+++ b/arch/arm/mach-stixxxx/board-dt.c
@@ -11,6 +11,7 @@
#include <linux/clocksource.h>
#include <linux/irq.h>
#include <asm/hardware/cache-l2x0.h>
+#include <asm/mach/map.h>
#include <asm/mach/arch.h>

#include "smp.h"
@@ -42,6 +43,7 @@ static const char *stih41x_dt_match[] __initdata = {
};

DT_MACHINE_START(STM, "STiH415/416 SoC with Flattened Device Tree")
+ .map_io = debug_ll_io_init,
.init_time = stih41x_timer_init,
.smp = smp_ops(stixxxx_smp_ops),
.dt_compat = stih41x_dt_match,
--
1.7.6.5

2013-06-10 09:30:37

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: [PATCH v2 09/11] ARM:stixxxx: Add stixxxx options to multi_v7_defconfig

This patch adds stih415 and stih416 support to multi_v7_defconfig.

Signed-off-by: Srinivas Kandagatla <[email protected]>
CC: Arnd Bergmann <[email protected]>
---
arch/arm/configs/multi_v7_defconfig | 32 +++++++++++++++-----------------
1 files changed, 15 insertions(+), 17 deletions(-)

diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index 2e67a27..8a5cd5c 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -1,23 +1,20 @@
-CONFIG_EXPERIMENTAL=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_ARCH_MVEBU=y
CONFIG_MACH_ARMADA_370=y
-CONFIG_ARCH_SIRF=y
CONFIG_MACH_ARMADA_XP=y
CONFIG_ARCH_HIGHBANK=y
CONFIG_ARCH_SOCFPGA=y
-CONFIG_ARCH_SUNXI=y
-CONFIG_ARCH_WM8850=y
-# CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA is not set
-CONFIG_ARCH_ZYNQ=y
-CONFIG_ARM_ERRATA_754322=y
CONFIG_PLAT_SPEAR=y
CONFIG_ARCH_SPEAR13XX=y
CONFIG_MACH_SPEAR1310=y
CONFIG_MACH_SPEAR1340=y
+CONFIG_ARCH_STIXXXX=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_ARCH_SIRF=y
+CONFIG_ARCH_WM8850=y
+CONFIG_ARCH_ZYNQ=y
CONFIG_SMP=y
-CONFIG_ARM_ARCH_TIMER=y
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_HIGHPTE=y
@@ -25,27 +22,30 @@ CONFIG_ARM_APPENDED_DTB=y
CONFIG_VFP=y
CONFIG_NEON=y
CONFIG_NET=y
+CONFIG_DEVTMPFS=y
CONFIG_BLK_DEV_SD=y
CONFIG_ATA=y
+CONFIG_SATA_AHCI_PLATFORM=y
CONFIG_SATA_HIGHBANK=y
CONFIG_SATA_MV=y
-CONFIG_SATA_AHCI_PLATFORM=y
CONFIG_NETDEVICES=y
CONFIG_NET_CALXEDA_XGMAC=y
CONFIG_SMSC911X=y
CONFIG_STMMAC_ETH=y
+CONFIG_KEYBOARD_SPEAR=y
CONFIG_SERIO_AMBAKMI=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_DW=y
-CONFIG_KEYBOARD_SPEAR=y
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
-CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SERIAL_SIRFSOC=y
CONFIG_SERIAL_SIRFSOC_CONSOLE=y
CONFIG_SERIAL_VT8500=y
CONFIG_SERIAL_VT8500_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_ST_ASC=y
+CONFIG_SERIAL_ST_ASC_CONSOLE=y
CONFIG_IPMI_HANDLER=y
CONFIG_IPMI_SI=y
CONFIG_I2C=y
@@ -54,7 +54,6 @@ CONFIG_I2C_SIRF=y
CONFIG_SPI=y
CONFIG_SPI_PL022=y
CONFIG_SPI_SIRF=y
-CONFIG_GPIO_PL061=y
CONFIG_FB=y
CONFIG_FB_ARMCLCD=y
CONFIG_FB_WM8505=y
@@ -67,7 +66,6 @@ CONFIG_MMC_ARMMMCI=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_SPEAR=y
-CONFIG_MMC_WMT=y
CONFIG_EDAC=y
CONFIG_EDAC_MM_EDAC=y
CONFIG_EDAC_HIGHBANK_MC=y
@@ -75,9 +73,9 @@ CONFIG_EDAC_HIGHBANK_L2=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_PL031=y
CONFIG_RTC_DRV_VT8500=y
-CONFIG_PWM=y
-CONFIG_PWM_VT8500=y
CONFIG_DMADEVICES=y
-CONFIG_PL330_DMA=y
-CONFIG_SIRF_DMA=y
CONFIG_DW_DMAC=y
+CONFIG_SIRF_DMA=y
+CONFIG_PL330_DMA=y
+CONFIG_PWM=y
+CONFIG_PWM_VT8500=y
--
1.7.6.5

2013-06-10 09:30:57

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: [PATCH v2 10/11] ARM:stih41x: Add B2000 board support

B2000 board is reference board for STIH415/416 SOCs, it has
2 x UART, 4x USB, 2 x Ethernet, 1 x SATA, 1 x PCIe, and 1GB RAM.

This patch add initial support to b2000 with STiH415/416 with UART2 as
console and a heard beat LED.

Signed-off-by: Srinivas Kandagatla <[email protected]>
CC: Stephen Gallimore <[email protected]>
CC: Arnd Bergmann <[email protected]>
---
arch/arm/boot/dts/Makefile | 2 +
arch/arm/boot/dts/stih415-b2000.dts | 15 ++++++++++++
arch/arm/boot/dts/stih416-b2000.dts | 16 +++++++++++++
arch/arm/boot/dts/stih41x-b2000.dtsi | 41 ++++++++++++++++++++++++++++++++++
4 files changed, 74 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/boot/dts/stih415-b2000.dts
create mode 100644 arch/arm/boot/dts/stih416-b2000.dts
create mode 100644 arch/arm/boot/dts/stih41x-b2000.dtsi

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index f0895c5..d4615fd 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -177,6 +177,8 @@ dtb-$(CONFIG_ARCH_SPEAR3XX)+= spear300-evb.dtb \
spear320-evb.dtb \
spear320-hmi.dtb
dtb-$(CONFIG_ARCH_SPEAR6XX)+= spear600-evb.dtb
+dtb-$(CONFIG_ARCH_STIXXXX)+= stih415-b2000.dtb \
+ stih416-b2000.dtb
dtb-$(CONFIG_ARCH_SUNXI) += \
sun4i-a10-cubieboard.dtb \
sun4i-a10-mini-xplus.dtb \
diff --git a/arch/arm/boot/dts/stih415-b2000.dts b/arch/arm/boot/dts/stih415-b2000.dts
new file mode 100644
index 0000000..d4af531
--- /dev/null
+++ b/arch/arm/boot/dts/stih415-b2000.dts
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Srinivas Kandagatla <[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
+ * publishhed by the Free Software Foundation.
+ */
+/dts-v1/;
+#include "stih415.dtsi"
+#include "stih41x-b2000.dtsi"
+/ {
+ model = "STiH415 B2000 Board";
+ compatible = "st,stih415", "st,stih415-b2000";
+};
diff --git a/arch/arm/boot/dts/stih416-b2000.dts b/arch/arm/boot/dts/stih416-b2000.dts
new file mode 100644
index 0000000..a5eb6ee
--- /dev/null
+++ b/arch/arm/boot/dts/stih416-b2000.dts
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Srinivas Kandagatla <[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
+ * publishhed by the Free Software Foundation.
+ */
+/dts-v1/;
+#include "stih416.dtsi"
+#include "stih41x-b2000.dtsi"
+
+/ {
+ compatible = "st,stih416", "st,stih416-b2000";
+ model = "STiH416 B2000";
+};
diff --git a/arch/arm/boot/dts/stih41x-b2000.dtsi b/arch/arm/boot/dts/stih41x-b2000.dtsi
new file mode 100644
index 0000000..8e694d2
--- /dev/null
+++ b/arch/arm/boot/dts/stih41x-b2000.dtsi
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Srinivas Kandagatla <[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
+ * publishhed by the Free Software Foundation.
+ */
+/ {
+
+ memory{
+ device_type = "memory";
+ reg = <0x60000000 0x40000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyAS0,115200";
+ linux,stdout-path = &serial2;
+ };
+
+ aliases {
+ ttyAS0 = &serial2;
+ };
+
+ soc {
+ serial2: serial@fed32000 {
+ status = "okay";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ fp_led {
+ #gpio-cells = <1>;
+ label = "Front Panel LED";
+ gpios = <&PIO105 7>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ };
+};
--
1.7.6.5

2013-06-10 09:31:07

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: [PATCH v2 11/11] ARM:stih41x: Add B2020 board support

B2020 ADI board is reference board for STIH415/416 SOCs, it has 2 x
UART, 4x USB, 1 x Ethernet, 1 x SATA, 1 x PCIe, and 2GB RAM with
standard set-top box IPs.

This patch adds initial support to B2020 with STiH415/416 with SBC_UART1
as console and a heard beat LED.

Signed-off-by: Srinivas Kandagatla <[email protected]>
CC: Stephen Gallimore <[email protected]>
CC: Stuart Menefy <[email protected]>
CC: Arnd Bergmann <[email protected]>
---
arch/arm/boot/dts/Makefile | 4 ++-
arch/arm/boot/dts/stih415-b2020.dts | 15 ++++++++++++
arch/arm/boot/dts/stih416-b2020.dts | 16 +++++++++++++
arch/arm/boot/dts/stih41x-b2020.dtsi | 42 ++++++++++++++++++++++++++++++++++
4 files changed, 76 insertions(+), 1 deletions(-)
create mode 100644 arch/arm/boot/dts/stih415-b2020.dts
create mode 100644 arch/arm/boot/dts/stih416-b2020.dts
create mode 100644 arch/arm/boot/dts/stih41x-b2020.dtsi

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index d4615fd..0d24c95 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -178,7 +178,9 @@ dtb-$(CONFIG_ARCH_SPEAR3XX)+= spear300-evb.dtb \
spear320-hmi.dtb
dtb-$(CONFIG_ARCH_SPEAR6XX)+= spear600-evb.dtb
dtb-$(CONFIG_ARCH_STIXXXX)+= stih415-b2000.dtb \
- stih416-b2000.dtb
+ stih416-b2000.dtb \
+ stih415-b2020.dtb \
+ stih416-b2020.dtb
dtb-$(CONFIG_ARCH_SUNXI) += \
sun4i-a10-cubieboard.dtb \
sun4i-a10-mini-xplus.dtb \
diff --git a/arch/arm/boot/dts/stih415-b2020.dts b/arch/arm/boot/dts/stih415-b2020.dts
new file mode 100644
index 0000000..442b019
--- /dev/null
+++ b/arch/arm/boot/dts/stih415-b2020.dts
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Srinivas Kandagatla <[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
+ * publishhed by the Free Software Foundation.
+ */
+/dts-v1/;
+#include "stih415.dtsi"
+#include "stih41x-b2020.dtsi"
+/ {
+ model = "STiH415 B2020 Board";
+ compatible = "st,stih415", "st,stih415-b2020";
+};
diff --git a/arch/arm/boot/dts/stih416-b2020.dts b/arch/arm/boot/dts/stih416-b2020.dts
new file mode 100644
index 0000000..276f28d
--- /dev/null
+++ b/arch/arm/boot/dts/stih416-b2020.dts
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Srinivas Kandagatla <[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
+ * publishhed by the Free Software Foundation.
+ */
+/dts-v1/;
+#include "stih416.dtsi"
+#include "stih41x-b2020.dtsi"
+/ {
+ model = "STiH416 B2020";
+ compatible = "st,stih416", "st,stih416-b2020";
+
+};
diff --git a/arch/arm/boot/dts/stih41x-b2020.dtsi b/arch/arm/boot/dts/stih41x-b2020.dtsi
new file mode 100644
index 0000000..133e181
--- /dev/null
+++ b/arch/arm/boot/dts/stih41x-b2020.dtsi
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Srinivas Kandagatla <[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
+ * publishhed by the Free Software Foundation.
+ */
+/ {
+ memory{
+ device_type = "memory";
+ reg = <0x40000000 0x80000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyAS0,115200";
+ linux,stdout-path = &sbc_serial1;
+ };
+
+ aliases {
+ ttyAS0 = &sbc_serial1;
+ };
+ soc {
+ sbc_serial1: serial@fe531000 {
+ status = "okay";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ red {
+ #gpio-cells = <1>;
+ label = "Front Panel LED";
+ gpios = <&PIO4 1>;
+ linux,default-trigger = "heartbeat";
+ };
+ green {
+ gpios = <&PIO4 7>;
+ default-state = "off";
+ };
+ };
+ };
+};
--
1.7.6.5

2013-06-10 09:36:17

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH v2 01/11] serial:st-asc: Add ST ASC driver.

On Mon, Jun 10, 2013 at 10:21:00AM +0100, Srinivas KANDAGATLA wrote:
> This patch adds support to ASC (asynchronous serial controller)
> driver, which is basically a standard serial driver. This IP is common
> across all the ST parts for settop box platforms.
>
> ASC is embedded in ST COMMS IP block. It supports Rx & Tx functionality.
> It support all industry standard baud rates.

Your driver is not POSIX compliant.

> + for (; count != 0; count--) {
> + c = asc_in(port, ASC_RXBUF);
> + flag = TTY_NORMAL;
> + port->icount.rx++;
> +
> + if (unlikely(c & ASC_RXBUF_FE)) {
> + if (c == ASC_RXBUF_FE) {
> + port->icount.brk++;
> + if (uart_handle_break(port))
> + continue;
> + flag = TTY_BREAK;
> + } else {
> + port->icount.frame++;
> + flag = TTY_FRAME;
> + }
> + } else if (ascport->check_parity &&
> + unlikely(c & ASC_RXBUF_PE)) {
> + port->icount.parity++;
> + flag = TTY_PARITY;
> + }
> +
> + if (uart_handle_sysrq_char(port, c))
> + continue;
> + tty_insert_flip_char(tport, c & 0xff, flag);
> + }
> + if (overrun) {
> + port->icount.overrun++;
> + tty_insert_flip_char(tport, 0, TTY_OVERRUN);
> + }

No support for ignoring error conditions. No support for ignoring all
input... and:

> +static void asc_set_termios(struct uart_port *port, struct ktermios *termios,
> + struct ktermios *old)
> +{
> + struct asc_port *ascport = to_asc_port(port);
> + unsigned int baud;
> + u32 ctrl_val;
> + tcflag_t cflag;
> + unsigned long flags;
> +
> + port->uartclk = clk_get_rate(ascport->clk);
> +
> + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
> + cflag = termios->c_cflag;
> +
> + spin_lock_irqsave(&port->lock, flags);
> +
> + /* read control register */
> + ctrl_val = asc_in(port, ASC_CTL);
> +
> + /* stop serial port and reset value */
> + asc_out(port, ASC_CTL, (ctrl_val & ~ASC_CTL_RUN));
> + ctrl_val = ASC_CTL_RXENABLE | ASC_CTL_FIFOENABLE;
> +
> + /* reset fifo rx & tx */
> + asc_out(port, ASC_TXRESET, 1);
> + asc_out(port, ASC_RXRESET, 1);
> +
> + /* set character length */
> + if ((cflag & CSIZE) == CS7) {
> + ctrl_val |= ASC_CTL_MODE_7BIT_PAR;
> + } else {
> + ctrl_val |= (cflag & PARENB) ? ASC_CTL_MODE_8BIT_PAR :
> + ASC_CTL_MODE_8BIT;
> + }
> +
> + ascport->check_parity = (cflag & PARENB) ? 1 : 0;
> +
> + /* set stop bit */
> + ctrl_val |= (cflag & CSTOPB) ? ASC_CTL_STOP_2BIT : ASC_CTL_STOP_1BIT;
> +
> + /* odd parity */
> + if (cflag & PARODD)
> + ctrl_val |= ASC_CTL_PARITYODD;
> +
> + /* hardware flow control */
> + if ((cflag & CRTSCTS) && ascport->hw_flow_control)
> + ctrl_val |= ASC_CTL_CTSENABLE;

This doesn't reflect those facts back into the termios structure to
indicate that they aren't supported.

Consider using uart_port's ignore and read status masks to implement
the break, framing, parity and overrun checking in your interrupt
handler using the same methodology as drivers like 8250, amba-pl011
etc. That will help you get these code sequences correct.

2013-06-10 09:56:24

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: [PATCH v2 07/11] ARM:stixxxx: Add STiH416 SOC support

The STiH416 is advanced HD AVC processor with 3D graphics acceleration
and 1.2-GHz ARM Cortex-A9 SMP CPU.

Signed-off-by: Srinivas Kandagatla <[email protected]>
CC: Stephen Gallimore <[email protected]>
CC: Stuart Menefy <[email protected]>
CC: Arnd Bergmann <[email protected]>
CC: Linus Walleij <[email protected]>
---
Documentation/arm/stixxxx/stih416-overview.txt | 12 +
arch/arm/boot/dts/stih416-clock.dtsi | 41 +++
arch/arm/boot/dts/stih416-pinctrl.dtsi | 377 ++++++++++++++++++++++++
arch/arm/boot/dts/stih416.dtsi | 111 +++++++
arch/arm/mach-stixxxx/board-dt.c | 3 +-
5 files changed, 543 insertions(+), 1 deletions(-)
create mode 100644 Documentation/arm/stixxxx/stih416-overview.txt
create mode 100644 arch/arm/boot/dts/stih416-clock.dtsi
create mode 100644 arch/arm/boot/dts/stih416-pinctrl.dtsi
create mode 100644 arch/arm/boot/dts/stih416.dtsi

diff --git a/Documentation/arm/stixxxx/stih416-overview.txt b/Documentation/arm/stixxxx/stih416-overview.txt
new file mode 100644
index 0000000..e060867
--- /dev/null
+++ b/Documentation/arm/stixxxx/stih416-overview.txt
@@ -0,0 +1,12 @@
+ STiH416 Overview
+ ================
+
+Introduction
+------------
+
+ The STiH416 is the next generation of HD, AVC set-top box processors
+ for satellite, cable, terrestrial and IP-STB markets.
+
+ Features
+ - ARM Cortex-A9 1.2 GHz dual core CPU
+ - SATA2×2,USB 2.0×3, PCIe, Gbit Ethernet MAC×2
diff --git a/arch/arm/boot/dts/stih416-clock.dtsi b/arch/arm/boot/dts/stih416-clock.dtsi
new file mode 100644
index 0000000..7026bf1
--- /dev/null
+++ b/arch/arm/boot/dts/stih416-clock.dtsi
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics R&D Limited
+ * <[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.
+ */
+/ {
+ clocks {
+ /*
+ * Fixed 30MHz oscillator inputs to SoC
+ */
+ CLK_SYSIN: CLK_SYSIN {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <30000000>;
+ clock-output-names = "CLK_SYSIN";
+ };
+
+ /*
+ * ARM Peripheral clock for timers
+ */
+ arm_periph_clk: arm_periph_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <600000000>;
+ };
+
+ /*
+ * Bootloader initialized system infrastructure clock for
+ * serial devices.
+ */
+ CLK_S_ICN_REG_0: clockgenA0@4 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <100000000>;
+ clock-output-names = "CLK_S_ICN_REG_0";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/stih416-pinctrl.dtsi b/arch/arm/boot/dts/stih416-pinctrl.dtsi
new file mode 100644
index 0000000..15843a9
--- /dev/null
+++ b/arch/arm/boot/dts/stih416-pinctrl.dtsi
@@ -0,0 +1,377 @@
+
+/*
+ * Copyright (C) 2013 STMicroelectronics Limited.
+ * Author: Srinivas Kandagatla <[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
+ * publishhed by the Free Software Foundation.
+ */
+#include "stixxxx-pincfg.h"
+/ {
+
+ aliases {
+ gpio0 = &PIO0;
+ gpio1 = &PIO1;
+ gpio2 = &PIO2;
+ gpio3 = &PIO3;
+ gpio4 = &PIO4;
+ gpio5 = &PIO40;
+ gpio6 = &PIO5;
+ gpio7 = &PIO6;
+ gpio8 = &PIO7;
+ gpio9 = &PIO8;
+ gpio10 = &PIO9;
+ gpio11 = &PIO10;
+ gpio12 = &PIO11;
+ gpio13 = &PIO12;
+ gpio14 = &PIO30;
+ gpio15 = &PIO31;
+ gpio16 = &PIO13;
+ gpio17 = &PIO14;
+ gpio18 = &PIO15;
+ gpio19 = &PIO16;
+ gpio20 = &PIO17;
+ gpio21 = &PIO18;
+ gpio22 = &PIO100;
+ gpio23 = &PIO101;
+ gpio24 = &PIO102;
+ gpio25 = &PIO103;
+ gpio26 = &PIO104;
+ gpio27 = &PIO105;
+ gpio28 = &PIO106;
+ gpio29 = &PIO107;
+ };
+
+ soc {
+ pin-controller-sbc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,stih416-pinctrl", "simple-bus";
+ st,retime-in-delay = <0 300 500 750 1000 1250 1500 1750 2000 2250 2500 2750 3000 3250>;
+ st,retime-out-delay = <0 300 500 750 1000 1250 1500 1750 2000 2250 2500 2750 3000 3250>;
+ st,syscfg = <&syscfg_sbc>;
+ st,syscfg-offsets = <0 40 50 60 100>;
+ ranges;
+ PIO0: pinctrl@fe610000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfe610000 0x100>;
+ st,bank-name = "PIO0";
+ st,retime-pin-mask = <0xff>;
+ };
+ PIO1: pinctrl@fe611000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfe611000 0x100>;
+ st,bank-name = "PIO1";
+ st,retime-pin-mask = <0xff>;
+ };
+ PIO2: pinctrl@fe612000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfe612000 0x100>;
+ st,bank-name = "PIO2";
+ st,retime-pin-mask = <0xff>;
+ };
+ PIO3: pinctrl@fe613000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfe613000 0x100>;
+ st,bank-name = "PIO3";
+ st,retime-pin-mask = <0xff>;
+ };
+
+ PIO4: pinctrl@fe614000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfe614000 0x100>;
+ st,bank-name = "PIO4";
+ st,retime-pin-mask = <0xff>;
+ };
+
+ PIO40: pinctrl@fe615000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfe615000 0x100>;
+ st,bank-name = "PIO40";
+ st,retime-pin-mask = <0x7f>;
+ };
+
+ sbc_serial1 {
+ pinctrl_sbc_serial1: sbc_serial1 {
+ st,function = <ALT3>;
+ st,pins {
+ tx = <&PIO2 6 OUT>;
+ rx = <&PIO2 7 IN>;
+ };
+ };
+ };
+ };
+
+ pin-controller-front {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,stih416-pinctrl", "simple-bus";
+ st,retime-in-delay = <0 300 500 750 1000 1250 1500 1750 2000 2250 2500 2750 3000 3250>;
+ st,retime-out-delay = <0 300 500 750 1000 1250 1500 1750 2000 2250 2500 2750 3000 3250>;
+ st,syscfg = <&syscfg_front>;
+ st,syscfg-offsets = <0 40 50 60 100>;
+ ranges;
+
+ PIO5: pinctrl@fee00000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfee00000 0x100>;
+ st,bank-name = "PIO5";
+ st,retime-pin-mask = <0xff>;
+ };
+ PIO6: pinctrl@fee01000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfee01000 0x100>;
+ st,bank-name = "PIO6";
+ st,retime-pin-mask = <0xff>;
+ };
+ PIO7: pinctrl@fee02000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfee02000 0x100>;
+ st,bank-name = "PIO7";
+ st,retime-pin-mask = <0xff>;
+ };
+ PIO8: pinctrl@fee03000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfee03000 0x100>;
+ st,bank-name = "PIO8";
+ st,retime-pin-mask = <0xff>;
+ };
+
+ PIO9: pinctrl@fee04000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfee04000 0x100>;
+ st,bank-name = "PIO9";
+ st,retime-pin-mask = <0xff>;
+ };
+ PIO10: pinctrl@fee05000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfee05000 0x100>;
+ st,bank-name = "PIO10";
+ st,retime-pin-mask = <0xff>;
+ };
+ PIO11: pinctrl@fee06000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfee06000 0x100>;
+ st,bank-name = "PIO11";
+ st,retime-pin-mask = <0xff>;
+ };
+ PIO12: pinctrl@fee07000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfee07000 0x100>;
+ st,bank-name = "PIO12";
+ st,retime-pin-mask = <0xff>;
+ };
+
+ PIO30: pinctrl@fee08000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfee08000 0x100>;
+ st,bank-name = "PIO30";
+ st,retime-pin-mask = <0xff>;
+ };
+
+ PIO31: pinctrl@fee09000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfee09000 0x100>;
+ st,bank-name = "PIO31";
+ st,retime-pin-mask = <0xff>;
+ };
+ };
+
+ pin-controller-rear {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,stih416-pinctrl", "simple-bus";
+ st,retime-in-delay = <0 300 500 750 1000 1250 1500 1750 2000 2250 2500 2750 3000 3250>;
+ st,retime-out-delay = <0 300 500 750 1000 1250 1500 1750 2000 2250 2500 2750 3000 3250>;
+ st,syscfg = <&syscfg_rear>;
+ st,syscfg-offsets = <0 40 50 60 100>;
+ ranges;
+
+ PIO13: pinctrl@fe820000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfe820000 0x100>;
+ st,bank-name = "PIO13";
+ st,retime-pin-mask = <0xff>;
+ };
+ PIO14: pinctrl@fe821000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfe821000 0x100>;
+ st,bank-name = "PIO14";
+ st,retime-pin-mask = <0xff>;
+ };
+ PIO15: pinctrl@fe822000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfe822000 0x100>;
+ st,bank-name = "PIO15";
+ st,retime-pin-mask = <0xff>;
+ };
+ PIO16: pinctrl@fe823000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfe823000 0x100>;
+ st,bank-name = "PIO16";
+ st,retime-pin-mask = <0xff>;
+ };
+
+ PIO17: pinctrl@fe824000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfe824000 0x100>;
+ st,bank-name = "PIO17";
+ st,retime-pin-mask = <0xff>;
+ };
+
+ PIO18: pinctrl@fe825000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfe825000 0x100>;
+ st,bank-name = "PIO18";
+ st,retime-pin-mask = <0xf>;
+ };
+
+ serial2 {
+ pinctrl_serial2: serial2-0 {
+ st,function = <ALT2>;
+ st,pins {
+ tx = <&PIO17 4 OUT>;
+ rx = <&PIO17 5 IN>;
+ output-enable = <&PIO11 3 OUT>;
+ };
+ };
+ };
+ };
+
+ pin-controller-fvdp-fe {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,stih416-pinctrl", "simple-bus";
+ st,retime-in-delay = <0 300 500 750 1000 1250 1500 1750 2000 2250 2500 2750 3000 3250>;
+ st,retime-out-delay = <0 300 500 750 1000 1250 1500 1750 2000 2250 2500 2750 3000 3250>;
+ st,syscfg = <&syscfg_fvdp_fe>;
+ st,syscfg-offsets = <0 40 50 60 100>;
+ ranges;
+
+ PIO100: pinctrl@fd6b0000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfd6b0000 0x100>;
+ st,bank-name = "PIO100";
+ st,retime-pin-mask = <0xff>;
+ };
+
+ PIO101: pinctrl@fd6b1000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfd6b1000 0x100>;
+ st,bank-name = "PIO101";
+ st,retime-pin-mask = <0xff>;
+ };
+
+ PIO102: pinctrl@fd6b2000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfd6b2000 0x100>;
+ st,bank-name = "PIO102";
+ st,retime-pin-mask = <0xff>;
+ };
+ };
+
+ pin-controller-fvdp-lite {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,stih416-pinctrl", "simple-bus";
+ st,retime-in-delay = <0 300 500 750 1000 1250 1500 1750 2000 2250 2500 2750 3000 3250>;
+ st,retime-out-delay = <0 300 500 750 1000 1250 1500 1750 2000 2250 2500 2750 3000 3250>;
+ st,syscfg = <&syscfg_fvdp_lite>;
+ st,syscfg-offsets = <0 40 50 60 100>;
+ ranges;
+
+ PIO103: pinctrl@fd330000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfd330000 0x100>;
+ st,bank-name = "PIO103";
+ st,retime-pin-mask = <0xff>;
+ };
+ PIO104: pinctrl@fd331000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfd331000 0x100>;
+ st,bank-name = "PIO104";
+ st,retime-pin-mask = <0xff>;
+ };
+ PIO105: pinctrl@fd332000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfd332000 0x100>;
+ st,bank-name = "PIO105";
+ st,retime-pin-mask = <0xff>;
+ };
+ PIO106: pinctrl@fd333000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfd333000 0x100>;
+ st,bank-name = "PIO106";
+ st,retime-pin-mask = <0xff>;
+ };
+
+ PIO107: pinctrl@fd334000 {
+ #gpio-cells = <1>;
+ compatible = "st,stixxxx-gpio";
+ gpio-controller;
+ reg = <0xfd334000 0x100>;
+ st,bank-name = "PIO107";
+ st,retime-pin-mask = <0xf>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/stih416.dtsi b/arch/arm/boot/dts/stih416.dtsi
new file mode 100644
index 0000000..7dbe450
--- /dev/null
+++ b/arch/arm/boot/dts/stih416.dtsi
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2012 STMicroelectronics Limited.
+ * Author: Srinivas Kandagatla <[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
+ * publishhed by the Free Software Foundation.
+ */
+#include "stih41x.dtsi"
+#include "stih416-clock.dtsi"
+#include "stih416-pinctrl.dtsi"
+/ {
+ L2: cache-controller {
+ compatible = "arm,pl310-cache";
+ reg = <0xfffe2000 0x1000>;
+ arm,data-latency = <3 3 3>;
+ arm,tag-latency = <2 2 2>;
+ cache-unified;
+ cache-level = <2>;
+ };
+
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&intc>;
+ ranges;
+ compatible = "simple-bus";
+
+ syscfg_sbc:syscfg@fe600000{
+ compatible = "st,stih416-syscfg";
+ reg = <0xfe600000 0x1000>;
+ syscfg-range = <0 999>;
+ syscfg-name = "SYSCFG_SBC";
+ };
+ syscfg_front:syscfg@fee10000{
+ compatible = "st,stih416-syscfg";
+ reg = <0xfee10000 0x1000>;
+ syscfg-range = <1000 999>;
+ syscfg-name = "SYSCFG_FRONT";
+ };
+ syscfg_rear:syscfg@fe830000{
+ compatible = "st,stih416-syscfg";
+ reg = <0xfe830000 0x1000>;
+ syscfg-range = <2000 999>;
+ syscfg-name = "SYSCFG_REAR";
+ };
+
+ /* MPE */
+ syscfg_fvdp_fe:syscfg@fddf0000{
+ compatible = "st,stih416-syscfg";
+ reg = <0xfddf0000 0x1000>;
+ syscfg-range = <5000 999>;
+ syscfg-name = "SYSCFG_FVDP_FE";
+ };
+ syscfg_fvdp_lite:syscfg@fd6a0000{
+ compatible = "st,stih416-syscfg";
+ reg = <0xfd6a0000 0x1000>;
+ syscfg-range = <6000 999>;
+ syscfg-name = "SYSCFG_FVDP_LITE";
+ };
+
+ syscfg_cpu:syscfg@fdde0000{
+ compatible = "st,stih416-syscfg";
+ reg = <0xfdde0000 0x1000>;
+ syscfg-range = <7000 999>;
+ syscfg-name = "SYSCFG_CPU";
+ };
+
+ syscfg_compo:syscfg@fd320000{
+ compatible = "st,stih416-syscfg";
+ reg = <0xfd320000 0x1000>;
+ syscfg-range = <8000 999>;
+ syscfg-name = "SYSCFG_COMPO";
+ };
+
+ syscfg_transport:syscfg@fd690000{
+ compatible = "st,stih416-syscfg";
+ reg = <0xfd690000 0x1000>;
+ syscfg-range = <9000 999>;
+ syscfg-name = "SYSCFG_TRANSPORT";
+ };
+
+ syscfg_lpm:syscfg@fe4b5100{
+ compatible = "st,stih416-syscfg";
+ reg = <0xfe4b5100 0x8>;
+ syscfg-range = <0 10>;
+ syscfg-name = "LPM_CFG_REGS";
+ };
+
+ serial2: serial@fed32000{
+ compatible = "st,asc";
+ status = "disabled";
+ reg = <0xfed32000 0x2c>;
+ interrupts = <0 197 0>;
+ clocks = <&CLK_S_ICN_REG_0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_serial2>;
+ };
+
+ /* SBC_UART1 */
+ sbc_serial1: serial@fe531000 {
+ compatible = "st,asc";
+ status = "disabled";
+ reg = <0xfe531000 0x2c>;
+ interrupts = <0 210 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sbc_serial1>;
+ clocks = <&CLK_SYSIN>;
+ };
+ };
+};
diff --git a/arch/arm/mach-stixxxx/board-dt.c b/arch/arm/mach-stixxxx/board-dt.c
index 52ce665..2b2552e 100644
--- a/arch/arm/mach-stixxxx/board-dt.c
+++ b/arch/arm/mach-stixxxx/board-dt.c
@@ -37,10 +37,11 @@ static void __init stih41x_timer_init(void)

static const char *stih41x_dt_match[] __initdata = {
"st,stih415",
+ "st,stih416",
NULL
};

-DT_MACHINE_START(STM, "STiH415 SoC with Flattened Device Tree")
+DT_MACHINE_START(STM, "STiH415/416 SoC with Flattened Device Tree")
.init_time = stih41x_timer_init,
.smp = smp_ops(stixxxx_smp_ops),
.dt_compat = stih41x_dt_match,
--
1.7.6.5

2013-06-10 10:40:36

by Mark Rutland

[permalink] [raw]
Subject: Re: [PATCH v2 09/11] ARM:stixxxx: Add stixxxx options to multi_v7_defconfig

On Mon, Jun 10, 2013 at 10:27:57AM +0100, Srinivas KANDAGATLA wrote:
> This patch adds stih415 and stih416 support to multi_v7_defconfig.

This seems to drop a few options also:

CONFIG_ARM_ARCH_TIMER
CONFIG_ARM_ERRATA_754322
CONFIG_EXPERIMENTAL
CONFIG_GPIO_PL061
CONFIG_MMC_WMT

I just applied this to v3.10-rc5, and ran `make ARCH=arm multi_v7_defconfig`.
It seems MMC_WMT and GPIO_PL061 get selected elsewhere, but ARM_ARCH_TIMER and
ARM_ERRATA_754322 are left unselected.

Thanks,
Mark.

>
> Signed-off-by: Srinivas Kandagatla <[email protected]>
> CC: Arnd Bergmann <[email protected]>
> ---
> arch/arm/configs/multi_v7_defconfig | 32 +++++++++++++++-----------------
> 1 files changed, 15 insertions(+), 17 deletions(-)
>
> diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
> index 2e67a27..8a5cd5c 100644
> --- a/arch/arm/configs/multi_v7_defconfig
> +++ b/arch/arm/configs/multi_v7_defconfig
> @@ -1,23 +1,20 @@
> -CONFIG_EXPERIMENTAL=y
> CONFIG_NO_HZ=y
> CONFIG_HIGH_RES_TIMERS=y
> CONFIG_ARCH_MVEBU=y
> CONFIG_MACH_ARMADA_370=y
> -CONFIG_ARCH_SIRF=y
> CONFIG_MACH_ARMADA_XP=y
> CONFIG_ARCH_HIGHBANK=y
> CONFIG_ARCH_SOCFPGA=y
> -CONFIG_ARCH_SUNXI=y
> -CONFIG_ARCH_WM8850=y
> -# CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA is not set
> -CONFIG_ARCH_ZYNQ=y
> -CONFIG_ARM_ERRATA_754322=y
> CONFIG_PLAT_SPEAR=y
> CONFIG_ARCH_SPEAR13XX=y
> CONFIG_MACH_SPEAR1310=y
> CONFIG_MACH_SPEAR1340=y
> +CONFIG_ARCH_STIXXXX=y
> +CONFIG_ARCH_SUNXI=y
> +CONFIG_ARCH_SIRF=y
> +CONFIG_ARCH_WM8850=y
> +CONFIG_ARCH_ZYNQ=y
> CONFIG_SMP=y
> -CONFIG_ARM_ARCH_TIMER=y
> CONFIG_AEABI=y
> CONFIG_HIGHMEM=y
> CONFIG_HIGHPTE=y
> @@ -25,27 +22,30 @@ CONFIG_ARM_APPENDED_DTB=y
> CONFIG_VFP=y
> CONFIG_NEON=y
> CONFIG_NET=y
> +CONFIG_DEVTMPFS=y
> CONFIG_BLK_DEV_SD=y
> CONFIG_ATA=y
> +CONFIG_SATA_AHCI_PLATFORM=y
> CONFIG_SATA_HIGHBANK=y
> CONFIG_SATA_MV=y
> -CONFIG_SATA_AHCI_PLATFORM=y
> CONFIG_NETDEVICES=y
> CONFIG_NET_CALXEDA_XGMAC=y
> CONFIG_SMSC911X=y
> CONFIG_STMMAC_ETH=y
> +CONFIG_KEYBOARD_SPEAR=y
> CONFIG_SERIO_AMBAKMI=y
> CONFIG_SERIAL_8250=y
> CONFIG_SERIAL_8250_CONSOLE=y
> CONFIG_SERIAL_8250_DW=y
> -CONFIG_KEYBOARD_SPEAR=y
> CONFIG_SERIAL_AMBA_PL011=y
> CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
> -CONFIG_SERIAL_OF_PLATFORM=y
> CONFIG_SERIAL_SIRFSOC=y
> CONFIG_SERIAL_SIRFSOC_CONSOLE=y
> CONFIG_SERIAL_VT8500=y
> CONFIG_SERIAL_VT8500_CONSOLE=y
> +CONFIG_SERIAL_OF_PLATFORM=y
> +CONFIG_SERIAL_ST_ASC=y
> +CONFIG_SERIAL_ST_ASC_CONSOLE=y
> CONFIG_IPMI_HANDLER=y
> CONFIG_IPMI_SI=y
> CONFIG_I2C=y
> @@ -54,7 +54,6 @@ CONFIG_I2C_SIRF=y
> CONFIG_SPI=y
> CONFIG_SPI_PL022=y
> CONFIG_SPI_SIRF=y
> -CONFIG_GPIO_PL061=y
> CONFIG_FB=y
> CONFIG_FB_ARMCLCD=y
> CONFIG_FB_WM8505=y
> @@ -67,7 +66,6 @@ CONFIG_MMC_ARMMMCI=y
> CONFIG_MMC_SDHCI=y
> CONFIG_MMC_SDHCI_PLTFM=y
> CONFIG_MMC_SDHCI_SPEAR=y
> -CONFIG_MMC_WMT=y
> CONFIG_EDAC=y
> CONFIG_EDAC_MM_EDAC=y
> CONFIG_EDAC_HIGHBANK_MC=y
> @@ -75,9 +73,9 @@ CONFIG_EDAC_HIGHBANK_L2=y
> CONFIG_RTC_CLASS=y
> CONFIG_RTC_DRV_PL031=y
> CONFIG_RTC_DRV_VT8500=y
> -CONFIG_PWM=y
> -CONFIG_PWM_VT8500=y
> CONFIG_DMADEVICES=y
> -CONFIG_PL330_DMA=y
> -CONFIG_SIRF_DMA=y
> CONFIG_DW_DMAC=y
> +CONFIG_SIRF_DMA=y
> +CONFIG_PL330_DMA=y
> +CONFIG_PWM=y
> +CONFIG_PWM_VT8500=y
> --
> 1.7.6.5
>
> _______________________________________________
> devicetree-discuss mailing list
> [email protected]
> https://lists.ozlabs.org/listinfo/devicetree-discuss
>

2013-06-10 11:01:19

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: Re: [PATCH v2 09/11] ARM:stixxxx: Add stixxxx options to multi_v7_defconfig

Thanks for testing...
On 10/06/13 11:40, Mark Rutland wrote:
> On Mon, Jun 10, 2013 at 10:27:57AM +0100, Srinivas KANDAGATLA wrote:
>> > This patch adds stih415 and stih416 support to multi_v7_defconfig.
> This seems to drop a few options also:
>
> CONFIG_ARM_ARCH_TIMER

Same as last comment 2:
> CONFIG_ARM_ERRATA_754322
ARM_ERRATA_754322 gets selected by the mach level Kconfig of stixxxx, so
it disappears, Should the mach level Kconfig select that?

> CONFIG_EXPERIMENTAL
> CONFIG_GPIO_PL061
> CONFIG_MMC_WMT

Comment 2: Without any modifications to multi_v7_defconfig if I run
savedefconfig CONFIG_ARM_ARCH_TIMER, CONFIG_EXPERIMENTAL,
CONFIG_GPIO_PL061 and CONFIG_MMC_WMT disappears.
Which suggests that these options seems to be selected by another
kconfigs or mach level. And since then the multi_v7_defconfig was not
run with savedefconfig.


Thanks,
srini
>
> I just applied this to v3.10-rc5, and ran `make ARCH=arm multi_v7_defconfig`.
> It seems MMC_WMT and GPIO_PL061 get selected elsewhere, but ARM_ARCH_TIMER and
> ARM_ERRATA_754322 are left unselected.
>
> Thanks,
> Mark.
>

2013-06-10 11:49:57

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: Re: [PATCH v2 06/11] ARM:stixxxx: Add STiH415 SOC support

On 10/06/13 12:15, Michal Simek wrote:

Thankyou for your comments,
> Hi,
>
> hmm - that's a nice bug that thunderbird is not able to send this email. :-(
> Let's comment it again via gmail.
> diff --git a/arch/arm/boot/dts/stih415.dtsi
> b/arch/arm/boot/dts/stih415.dtsi
> new file mode 100644
> index 0000000..6dcf5b4
> --- /dev/null
> +++ b/arch/arm/boot/dts/stih415.dtsi
...
> +
> + soc {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + interrupt-parent = <&intc>;
> + ranges;
> + compatible = "simple-bus";
>
>
>
> Rob and Grant: what's the purpose of SoC node.
> It seems to me odd that SoC is compatible with simple-bus.

All the drivers on this SOC are based on platform bus, so we use
simple-bus, here.

> diff --git a/arch/arm/boot/dts/stih41x.dtsi
> b/arch/arm/boot/dts/stih41x.dtsi
> new file mode 100644
> index 0000000..7321403
> --- /dev/null
> +++ b/arch/arm/boot/dts/stih41x.dtsi
> @@ -0,0 +1,38 @@
> +/ {
> + #address-cells = <1>;
> + #size-cells = <1>;
> +
> + cpus {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + cpu@0 {
> + compatible = "arm,cortex-a9";
> + reg = <0>;
> + };
> + cpu@1 {
> + compatible = "arm,cortex-a9";
> + reg = <1>;
> + };
> + };
> +
>
>
> I believe your SoC also has a bus here.

It does but there is no active driver to manage it.

> --- /dev/null
> +++ b/arch/arm/mach-stixxxx/board-dt.c
> @@ -0,0 +1,47 @@

> +
> +void __init stih41x_l2x0_init(void)
> +{
> + u32 way_size = 0x4;
> + u32 aux_ctrl;
> +
> + aux_ctrl = (0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) |
> + (0x1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) |
> + (0x1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) |
> + (way_size << L2X0_AUX_CTRL_WAY_SIZE_SHIFT);
>
>
>
> #include <linux/bitops.h>
> Linus Walleij would write use BIT() here

I will use BIT() macro.

> diff --git a/arch/arm/mach-stixxxx/headsmp.S
> b/arch/arm/mach-stixxxx/headsmp.S
> new file mode 100644
> index 0000000..3dd5c04
> --- /dev/null
> +++ b/arch/arm/mach-stixxxx/headsmp.S
> @@ -0,0 +1,44 @@
> +/*
> + * arch/arm/plat-stixxxx/headsmp.S
>

> + .long pen_release
>
>
> check that your SoC has no option to start/reset cpus separately.
> If yes, then you shouldn't use pen_release.
> We discussed this with Russel some days ago.
No, stih41x series can't reset the cores separately.
>
>
> diff --git a/arch/arm/mach-stixxxx/platsmp.c
> b/arch/arm/mach-stixxxx/platsmp.c
> new file mode 100644
> index 0000000..ffc40c0
> --- /dev/null
> +++ b/arch/arm/mach-stixxxx/platsmp.c
> @@ -0,0 +1,117 @@
> +/*
> + * arch/arm/plat-stixxxx/platsmp.c
>
>
> wrong.

Left over, will clean it up in next version.

> + * arch/arm/plat-stixxxx/platsmp.c
>
>
> incorrect.
Left over, will clean it up in next version.
>
> +extern struct smp_operations stixxxx_smp_ops;
> +extern void __iomem *stixxxx_scu_base_addr;
>
>
> Unused variable in this patch.
yes, I will remove stixxxx_scu_base_addr.

thanks,
srini

2013-06-10 11:56:35

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: Re: [PATCH v2 01/11] serial:st-asc: Add ST ASC driver.

Thankyou for your comment and suggestion,
I will fix the POSIX compliant issue.

On 10/06/13 10:35, Russell King - ARM Linux wrote:
> On Mon, Jun 10, 2013 at 10:21:00AM +0100, Srinivas KANDAGATLA wrote:
>> This patch adds support to ASC (asynchronous serial controller)
>> driver, which is basically a standard serial driver. This IP is common
>> across all the ST parts for settop box platforms.
>>
>> ASC is embedded in ST COMMS IP block. It supports Rx & Tx functionality.
>> It support all industry standard baud rates.
>
> Your driver is not POSIX compliant.
>
>> + for (; count != 0; count--) {
>> + c = asc_in(port, ASC_RXBUF);
>> + flag = TTY_NORMAL;
>> + port->icount.rx++;
>> +
>> + if (unlikely(c & ASC_RXBUF_FE)) {
>> + if (c == ASC_RXBUF_FE) {
>> + port->icount.brk++;
>> + if (uart_handle_break(port))
>> + continue;
>> + flag = TTY_BREAK;
>> + } else {
>> + port->icount.frame++;
>> + flag = TTY_FRAME;
>> + }
>> + } else if (ascport->check_parity &&
>> + unlikely(c & ASC_RXBUF_PE)) {
>> + port->icount.parity++;
>> + flag = TTY_PARITY;
>> + }
>> +
>> + if (uart_handle_sysrq_char(port, c))
>> + continue;
>> + tty_insert_flip_char(tport, c & 0xff, flag);
>> + }
>> + if (overrun) {
>> + port->icount.overrun++;
>> + tty_insert_flip_char(tport, 0, TTY_OVERRUN);
>> + }
>
> No support for ignoring error conditions. No support for ignoring all
> input... and:
>
>> +static void asc_set_termios(struct uart_port *port, struct ktermios *termios,
>> + struct ktermios *old)
>> +{
>> + struct asc_port *ascport = to_asc_port(port);
>> + unsigned int baud;
>> + u32 ctrl_val;
>> + tcflag_t cflag;
>> + unsigned long flags;
>> +
>> + port->uartclk = clk_get_rate(ascport->clk);
>> +
>> + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
>> + cflag = termios->c_cflag;
>> +
>> + spin_lock_irqsave(&port->lock, flags);
>> +
>> + /* read control register */
>> + ctrl_val = asc_in(port, ASC_CTL);
>> +
>> + /* stop serial port and reset value */
>> + asc_out(port, ASC_CTL, (ctrl_val & ~ASC_CTL_RUN));
>> + ctrl_val = ASC_CTL_RXENABLE | ASC_CTL_FIFOENABLE;
>> +
>> + /* reset fifo rx & tx */
>> + asc_out(port, ASC_TXRESET, 1);
>> + asc_out(port, ASC_RXRESET, 1);
>> +
>> + /* set character length */
>> + if ((cflag & CSIZE) == CS7) {
>> + ctrl_val |= ASC_CTL_MODE_7BIT_PAR;
>> + } else {
>> + ctrl_val |= (cflag & PARENB) ? ASC_CTL_MODE_8BIT_PAR :
>> + ASC_CTL_MODE_8BIT;
>> + }
>> +
>> + ascport->check_parity = (cflag & PARENB) ? 1 : 0;
>> +
>> + /* set stop bit */
>> + ctrl_val |= (cflag & CSTOPB) ? ASC_CTL_STOP_2BIT : ASC_CTL_STOP_1BIT;
>> +
>> + /* odd parity */
>> + if (cflag & PARODD)
>> + ctrl_val |= ASC_CTL_PARITYODD;
>> +
>> + /* hardware flow control */
>> + if ((cflag & CRTSCTS) && ascport->hw_flow_control)
>> + ctrl_val |= ASC_CTL_CTSENABLE;
>
> This doesn't reflect those facts back into the termios structure to
> indicate that they aren't supported.
>
> Consider using uart_port's ignore and read status masks to implement
> the break, framing, parity and overrun checking in your interrupt
> handler using the same methodology as drivers like 8250, amba-pl011
> etc. That will help you get these code sequences correct.
>
>

2013-06-10 13:15:18

by Mark Rutland

[permalink] [raw]
Subject: Re: [PATCH v2 09/11] ARM:stixxxx: Add stixxxx options to multi_v7_defconfig

On Mon, Jun 10, 2013 at 11:58:38AM +0100, Srinivas KANDAGATLA wrote:
> Thanks for testing...
> On 10/06/13 11:40, Mark Rutland wrote:
> > On Mon, Jun 10, 2013 at 10:27:57AM +0100, Srinivas KANDAGATLA wrote:
> >> > This patch adds stih415 and stih416 support to multi_v7_defconfig.
> > This seems to drop a few options also:
> >
> > CONFIG_ARM_ARCH_TIMER
>
> Same as last comment 2:
> > CONFIG_ARM_ERRATA_754322
> ARM_ERRATA_754322 gets selected by the mach level Kconfig of stixxxx, so
> it disappears, Should the mach level Kconfig select that?
>

I couldn't find the patch adding mach-stixxxx's Kconfig, though I seem to be
missing patch 6 of the series. As long as CONFIG_ARM_ERRATA_754322 appears in
the resulting .config, it should be fine.

> > CONFIG_EXPERIMENTAL
> > CONFIG_GPIO_PL061
> > CONFIG_MMC_WMT
>
> Comment 2: Without any modifications to multi_v7_defconfig if I run
> savedefconfig CONFIG_ARM_ARCH_TIMER, CONFIG_EXPERIMENTAL,
> CONFIG_GPIO_PL061 and CONFIG_MMC_WMT disappears.
> Which suggests that these options seems to be selected by another
> kconfigs or mach level. And since then the multi_v7_defconfig was not
> run with savedefconfig.

CONFIG_EXPERIMENTAL's gone as of 3d374d09f1: "final removal of
CONFIG_EXPERIMENTAL", so that's fine to go. CONFIG_GPIO_PL061 and
CONFIG_MMC_WMT get selected elsewhere, so that's fine.

It looks like the architected timer deselection is fallout of my own making,
the multi_v7_defconfig should now contain HAVE_ARM_ARCH_TIMER rather than
ARM_ARCH_TIMER.

Thanks,
Mark.

2013-06-10 13:52:09

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v2 07/11] ARM:stixxxx: Add STiH416 SOC support

On Monday 10 June 2013 10:27:05 Srinivas KANDAGATLA wrote:

> + soc {
> + pin-controller-sbc {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + compatible = "st,stih416-pinctrl", "simple-bus";

Why is this both its own device with a compatible string and a
"simple-bus" at the same time? Wouldn't it be simpler to just
scan the child device nodes from the "st,stih416-pinctrl"
driver instead of having a separate platform_driver for them?

> + st,retime-in-delay = <0 300 500 750 1000 1250 1500 1750 2000 2250 2500 2750 3000 3250>;
> + st,retime-out-delay = <0 300 500 750 1000 1250 1500 1750 2000 2250 2500 2750 3000 3250>;
> + st,syscfg = <&syscfg_sbc>;
> + st,syscfg-offsets = <0 40 50 60 100>;
> + ranges;
> + PIO0: pinctrl@fe610000 {
> + #gpio-cells = <1>;
> + compatible = "st,stixxxx-gpio";
> + gpio-controller;
> + reg = <0xfe610000 0x100>;
> + st,bank-name = "PIO0";
> + st,retime-pin-mask = <0xff>;
> + };
> + PIO1: pinctrl@fe611000 {
> + #gpio-cells = <1>;
> + compatible = "st,stixxxx-gpio";
> + gpio-controller;
> + reg = <0xfe611000 0x100>;
> + st,bank-name = "PIO1";
> + st,retime-pin-mask = <0xff>;
> + };

What is in the ranges between these registers? It seems you have
256 bytes for each pinctrl node, with 4kb spacing. I wonder if
it would make sense to declare the entire range to belong to a single
pinctrl device. At least since all of the registers are in a single
range, you could add a property like

ranges = <0 0xfe610000 0x10000>;

and use relative addresses in the sub-nodes.

Please don't use identifiers with 'xxx' in them. Instead use numbers
of actual chips, ideally using the first one that this is compatible
with.

> + syscfg_sbc:syscfg@fe600000{
> + compatible = "st,stih416-syscfg";
> + reg = <0xfe600000 0x1000>;
> + syscfg-range = <0 999>;
> + syscfg-name = "SYSCFG_SBC";
> + };
> + syscfg_front:syscfg@fee10000{
> + compatible = "st,stih416-syscfg";
> + reg = <0xfee10000 0x1000>;
> + syscfg-range = <1000 999>;
> + syscfg-name = "SYSCFG_FRONT";
> + };

Did you mean to declare ranges excluding 1000 and 2000 here?
Normally I would expect inclusive ranges like syscfg-range=<0 1000>;

What is the idea of the 'syscfg-name'? If the nodes are all different,
I would expect them to have distinct "compatible" values and not
need them.

Arnd

2013-06-10 13:55:14

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: Re: [PATCH v2 04/11] mfd:stixxxx-syscfg: Add ST System Configuration support.

On 10/06/13 14:16, Linus Walleij wrote:
> On Mon, Jun 10, 2013 at 11:22 AM, Srinivas KANDAGATLA
> <[email protected]> wrote:
>
>> This mfd driver provides higher level inialization routines for various
>> IPs like Ethernet, USB, PCIE, SATA and so on. Also it provides way to
>> get to syscfg registers via standard regmap api which is usefull for
>> drivers like pinctrl.
>>
>> This patch adds support to ST System Configuration registers, which can
>> be configured by the drivers.
>>
>> Signed-off-by: Srinivas Kandagatla <[email protected]>
>> CC: Stuart Menefy <[email protected]>
>> CC: Stephen Gallimore <[email protected]>
>> CC: Linus Walleij <[email protected]>
>> CC: Mark Brown <[email protected]>
>
> What is this driver doing that drivers/mfd/syscon.c is not already
> doing?
As of now, the driver is very much similar to syscon + some additional
functionality, but we are planning to use this file to add higher level
functions to configure different IPs like ethernet, usb, power, reset
and so on which are very much specific to ST System Configuration Registers.

Thanks,
srini
>
> I just get the feeling that you're reinventing the wheel here.
>
> Yours,
> Linus Walleij
> _______________________________________________
> devicetree-discuss mailing list
> [email protected]
> https://lists.ozlabs.org/listinfo/devicetree-discuss
>

2013-06-10 14:02:00

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v2 04/11] mfd:stixxxx-syscfg: Add ST System Configuration support.

On Monday 10 June 2013 14:52:38 Srinivas KANDAGATLA wrote:
> On 10/06/13 14:16, Linus Walleij wrote:
> > On Mon, Jun 10, 2013 at 11:22 AM, Srinivas KANDAGATLA
> > <[email protected]> wrote:
> >
> >> This mfd driver provides higher level inialization routines for various
> >> IPs like Ethernet, USB, PCIE, SATA and so on. Also it provides way to
> >> get to syscfg registers via standard regmap api which is usefull for
> >> drivers like pinctrl.
> >>
> >> This patch adds support to ST System Configuration registers, which can
> >> be configured by the drivers.
> >>
> >> Signed-off-by: Srinivas Kandagatla <[email protected]>
> >> CC: Stuart Menefy <[email protected]>
> >> CC: Stephen Gallimore <[email protected]>
> >> CC: Linus Walleij <[email protected]>
> >> CC: Mark Brown <[email protected]>
> >
> > What is this driver doing that drivers/mfd/syscon.c is not already
> > doing?
>
> As of now, the driver is very much similar to syscon + some additional
> functionality, but we are planning to use this file to add higher level
> functions to configure different IPs like ethernet, usb, power, reset
> and so on which are very much specific to ST System Configuration Registers.

I was expecting that you'd actually interface with the syscon code and
build on top, rather than copy it.

There are multiple ways of doing that, e.g. you could export a function
from syscon.c that you call to register the device node and then import
the regmap from syscon into your high-level driver again.

Arnd

2013-06-10 15:54:23

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: Re: [PATCH v2 04/11] mfd:stixxxx-syscfg: Add ST System Configuration support.

Thanks for the comments.
On 10/06/13 15:02, Arnd Bergmann wrote:
> On Monday 10 June 2013 14:52:38 Srinivas KANDAGATLA wrote:
>> On 10/06/13 14:16, Linus Walleij wrote:
>>> On Mon, Jun 10, 2013 at 11:22 AM, Srinivas KANDAGATLA
>>> <[email protected]> wrote:
>>>
>>>> This mfd driver provides higher level inialization routines for various
>>>> IPs like Ethernet, USB, PCIE, SATA and so on. Also it provides way to
>>>> get to syscfg registers via standard regmap api which is usefull for
>>>> drivers like pinctrl.
>>>>
>>>> This patch adds support to ST System Configuration registers, which can
>>>> be configured by the drivers.
>>>>
>>>> Signed-off-by: Srinivas Kandagatla <[email protected]>
>>>> CC: Stuart Menefy <[email protected]>
>>>> CC: Stephen Gallimore <[email protected]>
>>>> CC: Linus Walleij <[email protected]>
>>>> CC: Mark Brown <[email protected]>
>>>
>>> What is this driver doing that drivers/mfd/syscon.c is not already
>>> doing?
>>
>> As of now, the driver is very much similar to syscon + some additional
>> functionality, but we are planning to use this file to add higher level
>> functions to configure different IPs like ethernet, usb, power, reset
>> and so on which are very much specific to ST System Configuration Registers.
>
> I was expecting that you'd actually interface with the syscon code and
> build on top, rather than copy it.
>
I did not like the copying either, on the other hand I don't want to
pollute the syscon code.

As you said, I will make use of existing syscon and build "System
configuration interface" on top of it and see how it look like. It will
definitely get rid of lot of code duplication.

Thanks,
srini

> There are multiple ways of doing that, e.g. you could export a function
> from syscon.c that you call to register the device node and then import
> the regmap from syscon into your high-level driver again.

>
> Arnd
>
>

2013-06-10 16:21:04

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: Re: [PATCH v2 07/11] ARM:stixxxx: Add STiH416 SOC support

Thankyou for your comments.
On 10/06/13 14:52, Arnd Bergmann wrote:
> On Monday 10 June 2013 10:27:05 Srinivas KANDAGATLA wrote:
>
>> + soc {
>> + pin-controller-sbc {
>> + #address-cells = <1>;
>> + #size-cells = <1>;
>> + compatible = "st,stih416-pinctrl", "simple-bus";
>
> Why is this both its own device with a compatible string and a
> "simple-bus" at the same time? Wouldn't it be simpler to just
> scan the child device nodes from the "st,stih416-pinctrl"
> driver instead of having a separate platform_driver for them?
Am happy to get rid of gpio platform_driver, But looking at the existing
pinctrl drivers like at91, they do it exactly like this.

Also having a gpio platform driver ties the resources to driver in a
neat way.

>
>> + st,retime-in-delay = <0 300 500 750 1000 1250 1500 1750 2000 2250 2500 2750 3000 3250>;
>> + st,retime-out-delay = <0 300 500 750 1000 1250 1500 1750 2000 2250 2500 2750 3000 3250>;
>> + st,syscfg = <&syscfg_sbc>;
>> + st,syscfg-offsets = <0 40 50 60 100>;
>> + ranges;
>> + PIO0: pinctrl@fe610000 {
>> + #gpio-cells = <1>;
>> + compatible = "st,stixxxx-gpio";
>> + gpio-controller;
>> + reg = <0xfe610000 0x100>;
>> + st,bank-name = "PIO0";
>> + st,retime-pin-mask = <0xff>;
>> + };
>> + PIO1: pinctrl@fe611000 {
>> + #gpio-cells = <1>;
>> + compatible = "st,stixxxx-gpio";
>> + gpio-controller;
>> + reg = <0xfe611000 0x100>;
>> + st,bank-name = "PIO1";
>> + st,retime-pin-mask = <0xff>;
>> + };
>
> What is in the ranges between these registers? It seems you have
> 256 bytes for each pinctrl node, with 4kb spacing. I wonder if
> it would make sense to declare the entire range to belong to a single
> pinctrl device. At least since all of the registers are in a single
> range, you could add a property like
>
> ranges = <0 0xfe610000 0x10000>;
>
> and use relative addresses in the sub-nodes.
>
OK, I will change to use ranges.
> Please don't use identifiers with 'xxx' in them. Instead use numbers
> of actual chips, ideally using the first one that this is compatible
> with.

Ok, I will change st,stixxxx-gpio to st,stih415-gpio.

>
>> + syscfg_sbc:syscfg@fe600000{
>> + compatible = "st,stih416-syscfg";
>> + reg = <0xfe600000 0x1000>;
>> + syscfg-range = <0 999>;
>> + syscfg-name = "SYSCFG_SBC";
>> + };
>> + syscfg_front:syscfg@fee10000{
>> + compatible = "st,stih416-syscfg";
>> + reg = <0xfee10000 0x1000>;
>> + syscfg-range = <1000 999>;
>> + syscfg-name = "SYSCFG_FRONT";
>> + };
>
> Did you mean to declare ranges excluding 1000 and 2000 here?
> Normally I would expect inclusive ranges like syscfg-range=<0 1000>;
>
These numbers are from data sheet so I used it as it is.

> What is the idea of the 'syscfg-name'? If the nodes are all different,
The idea of having syscfg-name is to lookup any sysconf bank(regmap)
from code which do not have reference to phandle from device trees.

> I would expect them to have distinct "compatible" values and not
> need them.
Yes, If we have distinct compatible we would not need them, but there
will be 5-10 compatibility list for each SOC.
It looks like its going to be much neater Am going to try this change
and see how it looks like.
>
> Arnd
> _______________________________________________
> devicetree-discuss mailing list
> [email protected]
> https://lists.ozlabs.org/listinfo/devicetree-discuss
>

2013-06-10 23:20:43

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH v2 06/11] ARM:stixxxx: Add STiH415 SOC support

On Mon, Jun 10, 2013 at 12:46:59PM +0100, Srinivas KANDAGATLA wrote:
> > + aux_ctrl = (0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) |
> > + (0x1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) |
> > + (0x1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) |
> > + (way_size << L2X0_AUX_CTRL_WAY_SIZE_SHIFT);
> >
> >
> >
> > #include <linux/bitops.h>
> > Linus Walleij would write use BIT() here
>
> I will use BIT() macro.

Without checking those fields... BIT() is only appropriate if you're
really talking about single bits. If you have a field of more than a
single bit which you happen to be setting to '1' then it's not
appropriate to use BIT().

2013-06-11 06:54:42

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: Re: [PATCH v2 06/11] ARM:stixxxx: Add STiH415 SOC support

On 11/06/13 00:19, Russell King - ARM Linux wrote:
> On Mon, Jun 10, 2013 at 12:46:59PM +0100, Srinivas KANDAGATLA wrote:
>>> > > + aux_ctrl = (0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) |
>>> > > + (0x1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) |
>>> > > + (0x1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) |
>>> > > + (way_size << L2X0_AUX_CTRL_WAY_SIZE_SHIFT);
>>> > >
>>> > >
>>> > >
>>> > > #include <linux/bitops.h>
>>> > > Linus Walleij would write use BIT() here
>> >
>> > I will use BIT() macro.
> Without checking those fields... BIT() is only appropriate if you're
> really talking about single bits. If you have a field of more than a
> single bit which you happen to be setting to '1' then it's not
> appropriate to use BIT().
>
>
You are right, It does not make sense to use BIT() macro for field which
has more than 1 bit. I think using mix of both BIT() and the old style
will make code look bit confusing to reader, Also no other mach code in
the kernel use BIT while configuring L2 controller. So am going to drop
the idea of using BIT here and leave the code as it is.

Thanks,
srini

2013-06-11 07:44:13

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: Re: [PATCH v2 04/11] mfd:stixxxx-syscfg: Add ST System Configuration support.

On 10/06/13 15:02, Arnd Bergmann wrote:
> There are multiple ways of doing that, e.g. you could export a function
> from syscon.c that you call to register the device node and then import
> the regmap from syscon into your high-level driver again.
>

Hi Arnd/Linus,

Thankyou for your comments,
I did try using the full sysconf names in compatible and make use of
syscon driver, with this change the nodes look much neater.

The nodes changes to:

syscfg_sbc:syscfg@fe600000{
compatible = "st,stih416-sbc-syscfg", "syscon";
reg = <0xfe600000 0x1000>;
};

From:
syscfg_sbc:syscfg@fe600000{
compatible = "st,stih416-syscfg";
reg = <0xfe600000 0x1000>;
syscfg-range = <0 999>;
syscfg-name = "SYSCFG_SBC";
};


Also I got rid of the drivers/mfd/stixxxx-syscfg.c driver all together
for this basic support patch series, I will add this once there are new
high level functions.
Additional compatible string will allow code to get to regmap via syscon
apis.

I will get rid of this driver in next version for this series.

Thanks,
srini

> Arnd
>
>

2013-06-11 10:49:39

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH v2 03/11] regmap: Add regmap_field APIs

On Mon, Jun 10, 2013 at 10:21:58AM +0100, Srinivas KANDAGATLA wrote:
> It is common to access regmap registers at bit level, using
> regmap_update_bits or regmap_read functions, however the end user has to
> take care of a mask or shifting. This becomes overhead when such use
> cases are high. Having a common function to do this is much convenient
> and less error prone.

So this looks basically good. A couple of smallish nits below, if you
could respin I'll apply this on a branch so it can be pulled in as
dependency for the other things that use it.

> + regmap_field_init(rm_field, regmap, reg_field);
> +
> + return rm_field;
> +
> +}
> +EXPORT_SYMBOL_GPL(devm_regmap_field_alloc);
> +/**
> + * regmap_field_alloc(): Allocate and initialise a register field

Needs a blank line between the two functions.

> +#include <linux/device.h>
> +#include <linux/slab.h>

> +static inline void regmap_field_free(struct regmap_field *field)
> +{
> + kfree(field);
> +}

> +static inline void devm_regmap_field_free(struct device *dev,
> + struct regmap_field *field)
> +{
> + devm_kfree(dev, field);
> +}

Probably not worth inlining these, just put them in the code.


Attachments:
(No filename) (1.14 kB)
signature.asc (836.00 B)
Digital signature
Download all attachments

2013-06-11 11:40:56

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: Re: [PATCH v2 03/11] regmap: Add regmap_field APIs

On 11/06/13 11:48, Mark Brown wrote:
> On Mon, Jun 10, 2013 at 10:21:58AM +0100, Srinivas KANDAGATLA wrote:
>> It is common to access regmap registers at bit level, using
>> regmap_update_bits or regmap_read functions, however the end user has to
>> take care of a mask or shifting. This becomes overhead when such use
>> cases are high. Having a common function to do this is much convenient
>> and less error prone.
>
> So this looks basically good. A couple of smallish nits below, if you
> could respin I'll apply this on a branch so it can be pulled in as
> dependency for the other things that use it.
>
Thankyou for the comments,
I will fix it and send a v3 patch.

>> + regmap_field_init(rm_field, regmap, reg_field);
>> +
>> + return rm_field;
>> +
>> +}
>> +EXPORT_SYMBOL_GPL(devm_regmap_field_alloc);
>> +/**
>> + * regmap_field_alloc(): Allocate and initialise a register field
>
> Needs a blank line between the two functions.
>
>> +#include <linux/device.h>
>> +#include <linux/slab.h>
>
>> +static inline void regmap_field_free(struct regmap_field *field)
>> +{
>> + kfree(field);
>> +}
>
>> +static inline void devm_regmap_field_free(struct device *dev,
>> + struct regmap_field *field)
>> +{
>> + devm_kfree(dev, field);
>> +}
>
> Probably not worth inlining these, just put them in the code.
>
>
>
> _______________________________________________
> devicetree-discuss mailing list
> [email protected]
> https://lists.ozlabs.org/listinfo/devicetree-discuss
>

2013-06-12 10:48:59

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: Re: [PATCH v2 02/11] clocksource:global_timer: Add ARM global timer support.

On 11/06/13 21:13, Linus Walleij wrote:
> On Tue, Jun 11, 2013 at 4:05 PM, Srinivas KANDAGATLA
> <[email protected]> wrote:
>
>> Doing this is not adding any value to the driver, because
>> 1. Currently the driver only support DT boot paths, in my previous RFC
>> patches, Arnd suggested to get rid of the header as all platforms are DT
>> now.
>
> In that case why do you have the separate global_timer_init()
> at all? Just move that code into global_timer_of_register() and
> also remove the #ifdef around CONFIG_OF and make the driver
> depend on CONFIG_OF in Kconfig.
>
> After this you realize that all that business with
> clk_register_clkdev() / clk_get_sys() is just pure surplus
> baggade, you just use of_clk_get() and that's it.

It makes sense to move all the code into global_timer_of_register().
This will also get rid of un-used code. I will do this in the next spin.

Thanks,
srini

>
> Yours,
> Linus Walleij
> _______________________________________________
> devicetree-discuss mailing list
> [email protected]
> https://lists.ozlabs.org/listinfo/devicetree-discuss
>

2013-06-13 09:28:13

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: Re: [PATCH v2 09/11] ARM:stixxxx: Add stixxxx options to multi_v7_defconfig

On 10/06/13 14:15, Mark Rutland wrote:
> CONFIG_EXPERIMENTAL's gone as of 3d374d09f1: "final removal of
> CONFIG_EXPERIMENTAL", so that's fine to go. CONFIG_GPIO_PL061 and
> CONFIG_MMC_WMT get selected elsewhere, so that's fine.
>

Am planning to send a patch to clean this up, so that any new platform
addition to the multi_v7_defconfig will not under go this discussion again..

> It looks like the architected timer deselection is fallout of my own making,
> the multi_v7_defconfig should now contain HAVE_ARM_ARCH_TIMER rather than
> ARM_ARCH_TIMER.
Why should it even contain HAVE_ARM_ARCH_TIMER/ARM_ARCH_TIMER?
The only reason I see for de-selection is because none of the platforms
in the multi_v7 defconfig selects it.

Looks like there is no platform in mulit_v7 config which requires this
support. If there is one I think it should select it.

Am I correct?

Thanks,
srini

2013-06-13 11:57:58

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH v2 06/11] ARM:stixxxx: Add STiH415 SOC support

On Tue, Jun 11, 2013 at 07:50:31AM +0100, Srinivas KANDAGATLA wrote:
> You are right, It does not make sense to use BIT() macro for field which
> has more than 1 bit. I think using mix of both BIT() and the old style
> will make code look bit confusing to reader, Also no other mach code in
> the kernel use BIT while configuring L2 controller. So am going to drop
> the idea of using BIT here and leave the code as it is.

I'd suggest putting a comment in the code to that effect. With the way
"cleanups" get done, I wouldn't be surprised if this attracts a lot of
people wanting to do a trivial "1 << bit" -> "BIT(bit)" conversions.

One of the problems of open source is that you can say "no" to a patch
like that until you're blue in the face, but it will eventually make
its way in via some path.

Just one of the reasons I consider BIT() to be evil and an inappropriate
macro.

2013-06-13 12:45:44

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: Re: [PATCH v2 06/11] ARM:stixxxx: Add STiH415 SOC support

On 13/06/13 12:56, Russell King - ARM Linux wrote:
> On Tue, Jun 11, 2013 at 07:50:31AM +0100, Srinivas KANDAGATLA wrote:
>> You are right, It does not make sense to use BIT() macro for field which
>> has more than 1 bit. I think using mix of both BIT() and the old style
>> will make code look bit confusing to reader, Also no other mach code in
>> the kernel use BIT while configuring L2 controller. So am going to drop
>> the idea of using BIT here and leave the code as it is.
>
> I'd suggest putting a comment in the code to that effect. With the way
> "cleanups" get done, I wouldn't be surprised if this attracts a lot of
> people wanting to do a trivial "1 << bit" -> "BIT(bit)" conversions.
Hmm... I can add a comment for them.

>
> One of the problems of open source is that you can say "no" to a patch
> like that until you're blue in the face, but it will eventually make
> its way in via some path.
>
> Just one of the reasons I consider BIT() to be evil and an inappropriate
> macro.
>
>

2013-06-13 12:47:30

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH v2 06/11] ARM:stixxxx: Add STiH415 SOC support

On Tue, Jun 11, 2013 at 1:19 AM, Russell King - ARM Linux
<[email protected]> wrote:
> On Mon, Jun 10, 2013 at 12:46:59PM +0100, Srinivas KANDAGATLA wrote:
>> > + aux_ctrl = (0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) |
>> > + (0x1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) |
>> > + (0x1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) |
>> > + (way_size << L2X0_AUX_CTRL_WAY_SIZE_SHIFT);
>> >
>> >
>> >
>> > #include <linux/bitops.h>
>> > Linus Walleij would write use BIT() here
>>
>> I will use BIT() macro.
>
> Without checking those fields... BIT() is only appropriate if you're
> really talking about single bits. If you have a field of more than a
> single bit which you happen to be setting to '1' then it's not
> appropriate to use BIT().

This is true. Luckily I didn't push for it myself this time.

However, on a related key we have this hidden away in MFD
drivers/mfd/dbx500-prcmu-regs.h:

#define BITS(_start, _end) ((BIT(_end) - BIT(_start)) + BIT(_end))

It's used like so:

#define PRCM_PLL_FREQ_D_MASK BITS(0, 7)

So you can define an multi-bit mask with a macro like that.

If there is interest in a construct like this I can make a patch to
move this thing to <linux/bitops.h>.

Yours,
Linus Walleij

2013-06-14 07:16:47

by Srinivas KANDAGATLA

[permalink] [raw]
Subject: Re: [PATCH v2 07/11] ARM:stixxxx: Add STiH416 SOC support

On 10/06/13 14:52, Arnd Bergmann wrote:
> On Monday 10 June 2013 10:27:05 Srinivas KANDAGATLA wrote:
>
>> > + soc {
>> > + pin-controller-sbc {
>> > + #address-cells = <1>;
>> > + #size-cells = <1>;
>> > + compatible = "st,stih416-pinctrl", "simple-bus";
> Why is this both its own device with a compatible string and a
> "simple-bus" at the same time? Wouldn't it be simpler to just
> scan the child device nodes from the "st,stih416-pinctrl"
> driver instead of having a separate platform_driver for them?
>
I did try this suggestion, and it simplified driver too, I will do this
change in next version.

Thanks,
srini

2013-06-17 09:32:52

by Mark Rutland

[permalink] [raw]
Subject: Re: [PATCH v2 09/11] ARM:stixxxx: Add stixxxx options to multi_v7_defconfig

On Thu, Jun 13, 2013 at 10:24:45AM +0100, Srinivas KANDAGATLA wrote:
> On 10/06/13 14:15, Mark Rutland wrote:
> > CONFIG_EXPERIMENTAL's gone as of 3d374d09f1: "final removal of
> > CONFIG_EXPERIMENTAL", so that's fine to go. CONFIG_GPIO_PL061 and
> > CONFIG_MMC_WMT get selected elsewhere, so that's fine.
> >
>
> Am planning to send a patch to clean this up, so that any new platform
> addition to the multi_v7_defconfig will not under go this discussion again..
>
> > It looks like the architected timer deselection is fallout of my own making,
> > the multi_v7_defconfig should now contain HAVE_ARM_ARCH_TIMER rather than
> > ARM_ARCH_TIMER.
> Why should it even contain HAVE_ARM_ARCH_TIMER/ARM_ARCH_TIMER?
> The only reason I see for de-selection is because none of the platforms
> in the multi_v7 defconfig selects it.
>
> Looks like there is no platform in mulit_v7 config which requires this
> support. If there is one I think it should select it.
>
> Am I correct?

You're right, I agree that the selection should be moved down into the
platforms requiring it. I'll put together patches to fix up those platforms.

Thanks,
Mark.