* [RFC 2/2] dma-buf: Documentation for buffer sharing framework
From: Semwal, Sumit @ 2011-10-13 4:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4E9614FA.20108@xenotime.net>
Hi Randy,
On Thu, Oct 13, 2011 at 4:00 AM, Randy Dunlap <rdunlap@xenotime.net> wrote:
> On 10/11/2011 02:23 AM, Sumit Semwal wrote:
>> Add documentation for dma buffer sharing framework, explaining the
>> various operations, members and API of the dma buffer sharing
>> framework.
>>
>> Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
>> Signed-off-by: Sumit Semwal <sumit.semwal@ti.com>
>> ---
>> ?Documentation/dma-buf-sharing.txt | ?210 +++++++++++++++++++++++++++++++++++++
<snip>
>> + ? ?if the new buffer-user has stricter 'backing-storage constraints', and the
>> + ? ?exporter can handle these constraints, the exporter can just stall on the
>> + ? ?get_scatterlist till all outstanding access is completed (as signalled by
>
> ? ? ? ? ? ? ? ? ? ? ? until
>
Thanks for your review; I will update all these in the next version.
>> + ? ?put_scatterlist).
>> + ? ?Once all ongoing access is completed, the exporter could potentially move
>> + ? ?the buffer to the stricter backing-storage, and then allow further
>> + ? ?{get,put}_scatterlist operations from any buffer-user from the migrated
>> + ? ?backing-storage.
>> +
>> + ? If the exporter cannot fulfill the backing-storage constraints of the new
>> + ? buffer-user device as requested, dma_buf_attach() would return an error to
>> + ? denote non-compatibility of the new buffer-sharing request with the current
>> + ? buffer.
>> +
>> + ? If the exporter chooses not to allow an attach() operation once a
>> + ? get_scatterlist has been called, it simply returns an error.
>> +
>> +- mmap file operation
>> + ? An mmap() file operation is provided for the fd associated with the buffer.
>> + ? If the exporter defines an mmap operation, the mmap() fop calls this to allow
>> + ? mmap for devices that might need it; if not, it returns an error.
>> +
>> +References:
>> +[1] struct dma_buf_ops in include/linux/dma-buf.h
>> +[2] All interfaces mentioned above defined in include/linux/dma-buf.h
>
>
> --
> ~Randy
> *** Remember to use Documentation/SubmitChecklist when testing your code ***
>
Best regards,
~Sumit.
^ permalink raw reply
* [PATCH] UART: add CSR SiRFprimaII SoC on-chip uart drivers
From: Barry Song @ 2011-10-13 6:28 UTC (permalink / raw)
To: linux-arm-kernel
From: Rong Wang <Rong.Wang@csr.com>
SiRFprimaII is the latest generation application
processor from CSR?s multi-function SoC product
family.
The SoC support codes are in arch/arm/mach-prima2
from Linux mainline 3.0.
There are three dedicated UARTs in system. This
patch adds basic driver support for them.
It has used the newest pinmux subsystem from Linus
Walleij.
Cc: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Rong Wang <Rong.Wang@csr.com>
Signed-off-by: Bin Shi <Bin.Shi@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
---
drivers/tty/serial/Kconfig | 21 +
drivers/tty/serial/Makefile | 1 +
drivers/tty/serial/sirfsoc_uart.c | 740 +++++++++++++++++++++++++++++++++++++
drivers/tty/serial/sirfsoc_uart.h | 180 +++++++++
4 files changed, 942 insertions(+), 0 deletions(-)
create mode 100644 drivers/tty/serial/sirfsoc_uart.c
create mode 100644 drivers/tty/serial/sirfsoc_uart.h
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 4dcb37b..cadbbec 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -528,6 +528,27 @@ config SERIAL_S5PV210
help
Serial port support for Samsung's S5P Family of SoC's
+config SERIAL_SIRFSOC
+ tristate "SiRF SoC Platform Serial port support"
+ depends on ARM && ARCH_PRIMA2
+ select SERIAL_CORE
+ help
+ Support for the on-chip UART on the CSR SiRFprimaII series,
+ providing /dev/ttyS0, 1 and 2 (note, some machines may not
+ provide all of these ports, depending on how the serial port
+ pins are configured.
+
+config SERIAL_SIRFSOC_CONSOLE
+ bool "Support for console on SiRF SoC serial port"
+ depends on SERIAL_SIRFSOC=y
+ select SERIAL_CORE_CONSOLE
+ help
+ Even if you say Y here, the currently visible virtual console
+ (/dev/tty0) will still be used as the system console by default, but
+ you can alter that using a kernel command line option such as
+ "console=ttySx". (Try "man bootparam" or see the documentation of
+ your boot loader about how to pass options to the kernel at
+ boot time.)
config SERIAL_MAX3100
tristate "MAX3100 support"
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 83b4da6..5ca170d 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -94,3 +94,4 @@ obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o
obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o
obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o
obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
+obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o
diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
new file mode 100644
index 0000000..ec41ad0
--- /dev/null
+++ b/drivers/tty/serial/sirfsoc_uart.c
@@ -0,0 +1,740 @@
+/*
+ * Driver for CSR SiRFprimaII onboard UARTs.
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "sirfsoc_uart.h"
+
+static unsigned int
+sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count);
+static unsigned int
+sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count);
+static struct uart_driver sirfsoc_uart_drv;
+
+static struct sirfsoc_baudrate_to_regv baudrate_to_regv[] = {
+ {4000000, 2359296},
+ {3500000, 1310721},
+ {3000000, 1572865},
+ {2500000, 1245186},
+ {2000000, 1572866},
+ {1500000, 1245188},
+ {1152000, 1638404},
+ {1000000, 1572869},
+ {921600, 1114120},
+ {576000, 1245196},
+ {500000, 1245198},
+ {460800, 1572876},
+ {230400, 1310750},
+ {115200, 1310781},
+ {57600, 1310843},
+ {38400, 1114328},
+ {19200, 1114545},
+ {9600, 1114979},
+};
+
+static struct sirfsoc_uart_port sirfsoc_uart_ports[SIRFSOC_UART_NR] = {
+ [0] = {
+ .port = {
+ .iotype = UPIO_MEM,
+ .flags = UPF_BOOT_AUTOCONF,
+ .line = 0,
+ },
+ },
+ [1] = {
+ .port = {
+ .iotype = UPIO_MEM,
+ .flags = UPF_BOOT_AUTOCONF,
+ .line = 1,
+ },
+ },
+ [2] = {
+ .port = {
+ .iotype = UPIO_MEM,
+ .flags = UPF_BOOT_AUTOCONF,
+ .line = 2,
+ },
+ },
+};
+
+static inline struct sirfsoc_uart_port *to_sirfport(struct uart_port *port)
+{
+ return container_of(port, struct sirfsoc_uart_port, port);
+}
+
+static inline unsigned int sirfsoc_uart_tx_empty(struct uart_port *port)
+{
+ unsigned long reg;
+ reg = rd_regl(port, SIRFUART_TX_FIFO_STATUS);
+ if (reg & SIRFUART_FIFOEMPTY_MASK(port))
+ return TIOCSER_TEMT;
+ else
+ return 0;
+}
+
+static unsigned int sirfsoc_uart_get_mctrl(struct uart_port *port)
+{
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ if (!(sirfport->ms_enabled)) {
+ goto cts_asserted;
+ } else if (sirfport->hw_flow_ctrl) {
+ if (!(rd_regl(port, SIRFUART_AFC_CTRL) &
+ SIRFUART_CTS_IN_STATUS))
+ goto cts_asserted;
+ else
+ goto cts_deasserted;
+ }
+cts_deasserted:
+ return TIOCM_CAR | TIOCM_DSR;
+cts_asserted:
+ return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+static void sirfsoc_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ unsigned int assert = mctrl & TIOCM_RTS;
+ unsigned int val = assert ? SIRFUART_AFC_CTRL_RX_THD : 0x0;
+ unsigned int current_val;
+ if (sirfport->hw_flow_ctrl) {
+ current_val = rd_regl(port, SIRFUART_AFC_CTRL) & ~0xFF;
+ val |= current_val;
+ wr_regl(port, SIRFUART_AFC_CTRL, val);
+ }
+}
+
+static void sirfsoc_uart_stop_tx(struct uart_port *port)
+{
+ unsigned int regv;
+ regv = rd_regl(port, SIRFUART_INT_EN);
+ wr_regl(port, SIRFUART_INT_EN, regv & ~SIRFUART_TX_INT_EN);
+}
+
+void sirfsoc_uart_start_tx(struct uart_port *port)
+{
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ unsigned long regv;
+ sirfsoc_uart_pio_tx_chars(sirfport, 1);
+ wr_regl(port, SIRFUART_TX_FIFO_OP, SIRFUART_TX_FIFO_START);
+ regv = rd_regl(port, SIRFUART_INT_EN);
+ wr_regl(port, SIRFUART_INT_EN, regv | SIRFUART_TX_INT_EN);
+}
+
+static void sirfsoc_uart_stop_rx(struct uart_port *port)
+{
+ unsigned long regv;
+ wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
+ regv = rd_regl(port, SIRFUART_INT_EN);
+ wr_regl(port, SIRFUART_INT_EN, regv & ~SIRFUART_RX_IO_INT_EN);
+}
+
+static void sirfsoc_uart_disable_ms(struct uart_port *port)
+{
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ unsigned long reg;
+ sirfport->ms_enabled = 0;
+ if (!sirfport->hw_flow_ctrl)
+ return;
+ reg = rd_regl(port, SIRFUART_AFC_CTRL);
+ wr_regl(port, SIRFUART_AFC_CTRL, reg & ~0x3FF);
+ reg = rd_regl(port, SIRFUART_INT_EN);
+ wr_regl(port, SIRFUART_INT_EN, reg & ~SIRFUART_CTS_INT_EN);
+}
+
+static void sirfsoc_uart_enable_ms(struct uart_port *port)
+{
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ unsigned long reg;
+ unsigned long flg;
+ if (!sirfport->hw_flow_ctrl)
+ return;
+ flg = SIRFUART_AFC_RX_EN | SIRFUART_AFC_TX_EN;
+ reg = rd_regl(port, SIRFUART_AFC_CTRL);
+ wr_regl(port, SIRFUART_AFC_CTRL, reg | flg);
+ reg = rd_regl(port, SIRFUART_INT_EN);
+ wr_regl(port, SIRFUART_INT_EN, reg | SIRFUART_CTS_INT_EN);
+ uart_handle_cts_change(port,
+ !(rd_regl(port, SIRFUART_AFC_CTRL) & SIRFUART_CTS_IN_STATUS));
+ sirfport->ms_enabled = 1;
+}
+
+static void sirfsoc_uart_break_ctl(struct uart_port *port, int break_state)
+{
+ unsigned long ulcon = rd_regl(port, SIRFUART_LINE_CTRL);
+ if (break_state)
+ ulcon |= SIRFUART_SET_BREAK;
+ else
+ ulcon &= ~SIRFUART_SET_BREAK;
+ wr_regl(port, SIRFUART_LINE_CTRL, ulcon);
+}
+
+static unsigned int
+sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)
+{
+ unsigned int ch, rx_count = 0;
+ int temp;
+ struct tty_struct *tty = port->state->port.tty;
+ while (!(rd_regl(port, SIRFUART_RX_FIFO_STATUS) &
+ SIRFUART_FIFOEMPTY_MASK(port))) {
+ temp = tty_buffer_request_room(port->state->port.tty, 1);
+ if (unlikely(temp == 0)) {
+ port->icount.buf_overrun++;
+ break;
+ }
+ ch = rd_regl(port, SIRFUART_RX_FIFO_DATA) | SIRFUART_DUMMY_READ;
+ if (unlikely(uart_handle_sysrq_char(port, ch)))
+ continue;
+ uart_insert_char(port, 0, 0, ch, TTY_NORMAL);
+ rx_count++;
+ if (rx_count >= max_rx_count)
+ break;
+ }
+ port->icount.rx += rx_count;
+ tty_flip_buffer_push(tty);
+ return rx_count;
+}
+
+static unsigned int
+sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count)
+{
+ struct uart_port *port = &sirfport->port;
+ struct circ_buf *xmit = &port->state->xmit;
+ unsigned int num_tx = 0;
+ while (!uart_circ_empty(xmit) &&
+ !(rd_regl(port, SIRFUART_TX_FIFO_STATUS) &
+ SIRFUART_FIFOFULL_MASK(port)) &&
+ count--) {
+ wr_regl(port, SIRFUART_TX_FIFO_DATA, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ num_tx++;
+ }
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+ return num_tx;
+}
+
+static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
+{
+ unsigned long intr_status;
+ unsigned long cts_status;
+ unsigned long flag = TTY_NORMAL;
+ struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
+ struct uart_port *port = &sirfport->port;
+ struct uart_state *state = port->state;
+ struct circ_buf *xmit = &port->state->xmit;
+ intr_status = rd_regl(port, SIRFUART_INT_STATUS);
+ wr_regl(port, SIRFUART_INT_STATUS, intr_status);
+ intr_status &= rd_regl(port, SIRFUART_INT_EN);
+ if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT))) {
+ if (intr_status & SIRFUART_RXD_BREAK) {
+ if (uart_handle_break(port))
+ goto recv_char;
+ uart_insert_char(port, intr_status,
+ SIRFUART_RX_OFLOW, 0, TTY_BREAK);
+ return IRQ_HANDLED;
+ }
+ if (intr_status & SIRFUART_RX_OFLOW)
+ port->icount.overrun++;
+ if (intr_status & SIRFUART_FRM_ERR) {
+ port->icount.frame++;
+ flag = TTY_FRAME;
+ }
+ if (intr_status & SIRFUART_PARITY_ERR)
+ flag = TTY_PARITY;
+ wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_RESET);
+ wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
+ wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_START);
+ intr_status &= port->read_status_mask;
+ uart_insert_char(port, intr_status,
+ SIRFUART_RX_OFLOW_INT, 0, flag);
+ }
+recv_char:
+ if (intr_status & SIRFUART_CTS_INT_EN) {
+ cts_status = !(rd_regl(port, SIRFUART_AFC_CTRL) &
+ SIRFUART_CTS_IN_STATUS);
+ if (cts_status != 0) {
+ uart_handle_cts_change(port, 1);
+ } else {
+ uart_handle_cts_change(port, 0);
+ wake_up_interruptible(&state->port.delta_msr_wait);
+ }
+ }
+ if (intr_status & SIRFUART_RX_IO_INT_EN)
+ sirfsoc_uart_pio_rx_chars(port, SIRFSOC_UART_IO_RX_MAX_CNT);
+ if (intr_status & SIRFUART_TX_INT_EN) {
+ if (!(uart_tx_port_tty_invalid(port) ||
+ uart_tx_stopped(port))) {
+ sirfsoc_uart_pio_tx_chars(sirfport,
+ SIRFSOC_UART_IO_TX_REASONABLE_CNT);
+ if ((uart_circ_empty(xmit)) &&
+ (rd_regl(port, SIRFUART_TX_FIFO_STATUS) &
+ SIRFUART_FIFOEMPTY_MASK(port)))
+ sirfsoc_uart_stop_tx(port);
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+static void sirfsoc_uart_start_rx(struct uart_port *port)
+{
+ unsigned long regv;
+ regv = rd_regl(port, SIRFUART_INT_EN);
+ wr_regl(port, SIRFUART_INT_EN, regv | SIRFUART_RX_IO_INT_EN);
+ wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_RESET);
+ wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
+ wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_START);
+}
+
+static void sirfsoc_uart_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ unsigned long ioclk_rate;
+ unsigned long config_reg = 0;
+ unsigned long baud_rate;
+ unsigned long flags;
+ unsigned long ic;
+ unsigned int clk_div_reg = 0;
+ unsigned long temp_reg_val;
+ unsigned long rx_time_out;
+ int threshold_div;
+ int temp;
+
+ ioclk_rate = 150000000;
+ switch (termios->c_cflag & CSIZE) {
+ default:
+ case CS8:
+ config_reg |= SIRFUART_DATA_BIT_LEN_8;
+ break;
+ case CS7:
+ config_reg |= SIRFUART_DATA_BIT_LEN_7;
+ break;
+ case CS6:
+ config_reg |= SIRFUART_DATA_BIT_LEN_6;
+ break;
+ case CS5:
+ config_reg |= SIRFUART_DATA_BIT_LEN_5;
+ break;
+ }
+ if (termios->c_cflag & CSTOPB)
+ config_reg |= SIRFUART_STOP_BIT_LEN_2;
+ baud_rate = uart_get_baud_rate(port, termios, old, 0, 4000000);
+ spin_lock_irqsave(&port->lock, flags);
+ port->read_status_mask = SIRFUART_RX_OFLOW_INT;
+ port->ignore_status_mask = 0;
+ /* read flags */
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |=
+ SIRFUART_FRM_ERR_INT | SIRFUART_PARITY_ERR_INT;
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= SIRFUART_RXD_BREAK_INT;
+ /* ignore flags */
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |=
+ SIRFUART_FRM_ERR_INT | SIRFUART_PARITY_ERR_INT;
+ if ((termios->c_cflag & CREAD) == 0)
+ port->ignore_status_mask |= SIRFUART_DUMMY_READ;
+ /* enable parity if PARENB is set*/
+ if (termios->c_cflag & PARENB) {
+ if (termios->c_cflag & CMSPAR) {
+ if (termios->c_cflag & PARODD)
+ config_reg |= SIRFUART_STICK_BIT_MARK;
+ else
+ config_reg |= SIRFUART_STICK_BIT_SPACE;
+ } else if (termios->c_cflag & PARODD) {
+ config_reg |= SIRFUART_STICK_BIT_ODD;
+ } else {
+ config_reg |= SIRFUART_STICK_BIT_EVEN;
+ }
+ }
+ /* Hardware Flow Control Settings */
+ if (UART_ENABLE_MS(port, termios->c_cflag)) {
+ if (!sirfport->ms_enabled)
+ sirfsoc_uart_enable_ms(port);
+ } else {
+ if (sirfport->ms_enabled)
+ sirfsoc_uart_disable_ms(port);
+ }
+ for (ic = 0; ic < SIRFUART_BAUD_RATE_SUPPORT_NR; ic++)
+ if (baud_rate == baudrate_to_regv[ic].baud_rate)
+ clk_div_reg = baudrate_to_regv[ic].reg_val;
+ if (clk_div_reg == 0)
+ pr_err("SiRF UART: Cannot set Baud Rate (9600 ~ 4000000).\n");
+ wr_regl(port, SIRFUART_DIVISOR, clk_div_reg);
+ /* set receive timeout */
+ rx_time_out = SIRFSOC_UART_RX_TIMEOUT(baud_rate, 20000);
+ rx_time_out = (rx_time_out > 0xFFFF) ? 0xFFFF : rx_time_out;
+ config_reg |= SIRFUART_RECV_TIMEOUT(rx_time_out);
+ temp_reg_val = rd_regl(port, SIRFUART_TX_FIFO_OP);
+ wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
+ wr_regl(port, SIRFUART_TX_FIFO_OP,
+ temp_reg_val & ~SIRFUART_TX_FIFO_START);
+ wr_regl(port, SIRFUART_TX_DMA_IO_CTRL, SIRFUART_TX_MODE_IO);
+ wr_regl(port, SIRFUART_RX_DMA_IO_CTRL, SIRFUART_RX_MODE_IO);
+ wr_regl(port, SIRFUART_LINE_CTRL, config_reg);
+ /* Reset Rx/Tx FIFO Threshold level for proper baudrate */
+ if (baud_rate < 1000000)
+ threshold_div = 1;
+ else
+ threshold_div = 2;
+ temp = port->line == 1 ? 16 : 64;
+ wr_regl(port, SIRFUART_TX_FIFO_CTRL, temp / threshold_div);
+ wr_regl(port, SIRFUART_RX_FIFO_CTRL, temp / threshold_div);
+ temp_reg_val |= SIRFUART_TX_FIFO_START;
+ wr_regl(port, SIRFUART_TX_FIFO_OP, temp_reg_val);
+ uart_update_timeout(port, termios->c_cflag, baud_rate);
+ sirfsoc_uart_start_rx(port);
+ wr_regl(port, SIRFUART_TX_RX_EN, SIRFUART_TX_EN | SIRFUART_RX_EN);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void startup_uart_controller(struct uart_port *port)
+{
+ unsigned long temp_regv;
+ int temp;
+ temp_regv = rd_regl(port, SIRFUART_TX_DMA_IO_CTRL);
+ wr_regl(port, SIRFUART_TX_DMA_IO_CTRL, temp_regv | SIRFUART_TX_MODE_IO);
+ temp_regv = rd_regl(port, SIRFUART_RX_DMA_IO_CTRL);
+ wr_regl(port, SIRFUART_RX_DMA_IO_CTRL, temp_regv | SIRFUART_RX_MODE_IO);
+ wr_regl(port, SIRFUART_TX_DMA_IO_LEN, 0);
+ wr_regl(port, SIRFUART_RX_DMA_IO_LEN, 0);
+ wr_regl(port, SIRFUART_TX_RX_EN, SIRFUART_RX_EN | SIRFUART_TX_EN);
+ wr_regl(port, SIRFUART_TX_FIFO_OP, SIRFUART_TX_FIFO_RESET);
+ wr_regl(port, SIRFUART_TX_FIFO_OP, 0);
+ wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_RESET);
+ wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
+ temp = port->line == 1 ? 16 : 64;
+ wr_regl(port, SIRFUART_TX_FIFO_CTRL, temp);
+ wr_regl(port, SIRFUART_RX_FIFO_CTRL, temp);
+}
+
+static int sirfsoc_uart_startup(struct uart_port *port)
+{
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ unsigned int index = port->line;
+ int ret;
+ set_irq_flags(port->irq, IRQF_VALID | IRQF_NOAUTOEN);
+ ret = request_irq(port->irq,
+ sirfsoc_uart_isr,
+ 0,
+ SIRFUART_PORT_NAME,
+ sirfport);
+ if (ret != 0) {
+ dev_err(port->dev, "UART%d request IRQ line (%d) failed.\n",
+ index, port->irq);
+ goto irq_err;
+ }
+ startup_uart_controller(port);
+ enable_irq(port->irq);
+irq_err:
+ return ret;
+}
+
+static void sirfsoc_uart_shutdown(struct uart_port *port)
+{
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ wr_regl(port, SIRFUART_INT_EN, 0);
+ free_irq(port->irq, sirfport);
+ if (sirfport->ms_enabled) {
+ sirfsoc_uart_disable_ms(port);
+ sirfport->ms_enabled = 0;
+ }
+}
+
+static const char *sirfsoc_uart_type(struct uart_port *port)
+{
+ return port->type == SIRFSOC_PORT_TYPE ? SIRFUART_PORT_NAME : NULL;
+}
+
+static int sirfsoc_uart_request_port(struct uart_port *port)
+{
+ void *ret;
+ ret = request_mem_region(port->mapbase,
+ SIRFUART_MAP_SIZE, SIRFUART_PORT_NAME);
+ return ret ? 0 : -EBUSY;
+}
+
+static void sirfsoc_uart_release_port(struct uart_port *port)
+{
+ release_mem_region(port->mapbase, SIRFUART_MAP_SIZE);
+}
+
+static void sirfsoc_uart_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE) {
+ port->type = SIRFSOC_PORT_TYPE;
+ sirfsoc_uart_request_port(port);
+ }
+}
+
+static struct uart_ops sirfsoc_uart_ops = {
+ .tx_empty = sirfsoc_uart_tx_empty,
+ .get_mctrl = sirfsoc_uart_get_mctrl,
+ .set_mctrl = sirfsoc_uart_set_mctrl,
+ .stop_tx = sirfsoc_uart_stop_tx,
+ .start_tx = sirfsoc_uart_start_tx,
+ .stop_rx = sirfsoc_uart_stop_rx,
+ .enable_ms = sirfsoc_uart_enable_ms,
+ .break_ctl = sirfsoc_uart_break_ctl,
+ .startup = sirfsoc_uart_startup,
+ .shutdown = sirfsoc_uart_shutdown,
+ .set_termios = sirfsoc_uart_set_termios,
+ .type = sirfsoc_uart_type,
+ .release_port = sirfsoc_uart_release_port,
+ .request_port = sirfsoc_uart_request_port,
+ .config_port = sirfsoc_uart_config_port,
+};
+
+#ifdef CONFIG_SERIAL_SIRFSOC_CONSOLE
+static int __init sirfsoc_uart_console_setup(struct console *co, char *options)
+{
+ unsigned int baud = 115200;
+ unsigned int bits = 8;
+ unsigned int parity = 'n';
+ unsigned int flow = 'n';
+ struct uart_port *port = &sirfsoc_uart_ports[co->index].port;
+
+ if (co->index < 0 || co->index >= SIRFSOC_UART_NR)
+ return -EINVAL;
+
+ if (!port->mapbase) {
+ pr_err("Console on ttyS%i is not present.\n", co->index);
+ return -ENODEV;
+ }
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ port->cons = co;
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
+{
+ while (rd_regl(port,
+ SIRFUART_TX_FIFO_STATUS) & SIRFUART_FIFOFULL_MASK(port))
+ cpu_relax();
+ wr_regb(port, SIRFUART_TX_FIFO_DATA, ch);
+}
+
+static void sirfsoc_uart_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ struct uart_port *port = &sirfsoc_uart_ports[co->index].port;
+ uart_console_write(port, s, count, sirfsoc_uart_console_putchar);
+}
+
+static struct console sirfsoc_uart_console = {
+ .name = "ttyS",
+ .device = uart_console_device,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .write = sirfsoc_uart_console_write,
+ .setup = sirfsoc_uart_console_setup,
+ .data = &sirfsoc_uart_drv,
+};
+
+static int __init sirfsoc_uart_console_init(void)
+{
+ register_console(&sirfsoc_uart_console);
+ return 0;
+}
+console_initcall(sirfsoc_uart_console_init);
+#endif
+
+static struct uart_driver sirfsoc_uart_drv = {
+ .owner = THIS_MODULE,
+ .driver_name = SIRFUART_PORT_NAME,
+ .nr = SIRFSOC_UART_NR,
+ .dev_name = SIRFSOC_UART_NAME,
+ .major = SIRFSOC_UART_MAJOR,
+ .minor = SIRFSOC_UART_MINOR,
+#ifdef CONFIG_SERIAL_SIRFSOC_CONSOLE
+ .cons = &sirfsoc_uart_console,
+#else
+ .cons = NULL,
+#endif
+};
+
+int sirfsoc_uart_probe(struct platform_device *pdev)
+{
+ struct sirfsoc_uart_port *sirfport;
+ struct uart_port *port;
+ struct resource *res;
+ int ret;
+
+ if (of_property_read_u32(pdev->dev.of_node, "cell-index", &pdev->id)) {
+ dev_err(&pdev->dev,
+ "Unable to find cell-index in uart node.\n");
+ ret = -EFAULT;
+ goto err;
+ }
+
+ sirfport = &sirfsoc_uart_ports[pdev->id];
+ port = &sirfport->port;
+ port->dev = &pdev->dev;
+ port->private_data = sirfport;
+
+ if (of_find_property(pdev->dev.of_node, "hw_flow_ctrl", NULL))
+ sirfport->hw_flow_ctrl = 1;
+
+ if (of_property_read_u32(pdev->dev.of_node,
+ "fifosize",
+ &port->fifosize)) {
+ dev_err(&pdev->dev,
+ "Unable to find fifosize in uart node.\n");
+ ret = -EFAULT;
+ goto err;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "Insufficient resources.\n");
+ ret = -EFAULT;
+ goto err;
+ }
+ port->mapbase = res->start;
+ port->membase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!port->membase) {
+ dev_err(&pdev->dev, "Cannot remap resource.\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "Insufficient resources.\n");
+ ret = -EFAULT;
+ goto irq_err;
+ }
+ port->irq = res->start;
+
+ if (sirfport->hw_flow_ctrl) {
+ sirfport->pmx = pinmux_get(&pdev->dev, NULL);
+ ret = IS_ERR(sirfport->pmx);
+ if (ret)
+ goto pmx_err;
+
+ pinmux_enable(sirfport->pmx);
+ }
+
+ port->ops = &sirfsoc_uart_ops;
+ spin_lock_init(&port->lock);
+
+ platform_set_drvdata(pdev, sirfport);
+ ret = uart_add_one_port(&sirfsoc_uart_drv, port);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Cannot add UART port(%d).\n", pdev->id);
+ goto port_err;
+ }
+
+ return 0;
+
+port_err:
+ platform_set_drvdata(pdev, NULL);
+ if (sirfport->hw_flow_ctrl) {
+ pinmux_disable(sirfport->pmx);
+ pinmux_put(sirfport->pmx);
+ }
+pmx_err:
+irq_err:
+ devm_iounmap(&pdev->dev, port->membase);
+err:
+ return ret;
+}
+
+static int sirfsoc_uart_remove(struct platform_device *pdev)
+{
+ struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
+ struct uart_port *port = &sirfport->port;
+ platform_set_drvdata(pdev, NULL);
+ if (sirfport->hw_flow_ctrl) {
+ pinmux_disable(sirfport->pmx);
+ pinmux_put(sirfport->pmx);
+ }
+ devm_iounmap(&pdev->dev, port->membase);
+ uart_remove_one_port(&sirfsoc_uart_drv, port);
+ return 0;
+}
+
+static int
+sirfsoc_uart_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
+ struct uart_port *port = &sirfport->port;
+ uart_suspend_port(&sirfsoc_uart_drv, port);
+ return 0;
+}
+
+static int sirfsoc_uart_resume(struct platform_device *pdev)
+{
+ struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
+ struct uart_port *port = &sirfport->port;
+ uart_resume_port(&sirfsoc_uart_drv, port);
+ return 0;
+}
+
+static struct of_device_id sirfsoc_uart_ids[] __devinitdata = {
+ { .compatible = "sirf,prima2-uart", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sirfsoc_serial_of_match);
+
+static struct platform_driver sirfsoc_uart_driver = {
+ .probe = sirfsoc_uart_probe,
+ .remove = __devexit_p(sirfsoc_uart_remove),
+ .suspend = sirfsoc_uart_suspend,
+ .resume = sirfsoc_uart_resume,
+ .driver = {
+ .name = SIRFUART_PORT_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = sirfsoc_uart_ids,
+ },
+};
+
+static int __init sirfsoc_uart_init(void)
+{
+ int ret = 0;
+
+ ret = uart_register_driver(&sirfsoc_uart_drv);
+ if (ret)
+ goto out;
+
+ ret = platform_driver_register(&sirfsoc_uart_driver);
+ if (ret)
+ uart_unregister_driver(&sirfsoc_uart_drv);
+out:
+ return ret;
+}
+module_init(sirfsoc_uart_init);
+
+static void __exit sirfsoc_uart_exit(void)
+{
+ platform_driver_unregister(&sirfsoc_uart_driver);
+ uart_unregister_driver(&sirfsoc_uart_drv);
+}
+module_exit(sirfsoc_uart_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Bin Shi <Bin.Shi@csr.com>, Rong Wang<Rong.Wang@csr.com>");
+MODULE_DESCRIPTION("CSR SiRFprimaII Uart Driver");
diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h
new file mode 100644
index 0000000..567c396
--- /dev/null
+++ b/drivers/tty/serial/sirfsoc_uart.h
@@ -0,0 +1,180 @@
+/*
+ * Drivers for CSR SiRFprimaII onboard UARTs.
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+#include <linux/bitops.h>
+
+/* UART Register Offset Define */
+#define SIRFUART_LINE_CTRL 0x0040
+#define SIRFUART_TX_RX_EN 0x004c
+#define SIRFUART_DIVISOR 0x0050
+#define SIRFUART_INT_EN 0x0054
+#define SIRFUART_INT_STATUS 0x0058
+#define SIRFUART_TX_DMA_IO_CTRL 0x0100
+#define SIRFUART_TX_DMA_IO_LEN 0x0104
+#define SIRFUART_TX_FIFO_CTRL 0x0108
+#define SIRFUART_TX_FIFO_LEVEL_CHK 0x010C
+#define SIRFUART_TX_FIFO_OP 0x0110
+#define SIRFUART_TX_FIFO_STATUS 0x0114
+#define SIRFUART_TX_FIFO_DATA 0x0118
+#define SIRFUART_RX_DMA_IO_CTRL 0x0120
+#define SIRFUART_RX_DMA_IO_LEN 0x0124
+#define SIRFUART_RX_FIFO_CTRL 0x0128
+#define SIRFUART_RX_FIFO_LEVEL_CHK 0x012C
+#define SIRFUART_RX_FIFO_OP 0x0130
+#define SIRFUART_RX_FIFO_STATUS 0x0134
+#define SIRFUART_RX_FIFO_DATA 0x0138
+#define SIRFUART_AFC_CTRL 0x0140
+#define SIRFUART_SWH_DMA_IO 0x0148
+
+/* UART Line Control Register */
+#define SIRFUART_DATA_BIT_LEN_MASK 0x3
+#define SIRFUART_DATA_BIT_LEN_5 BIT(0)
+#define SIRFUART_DATA_BIT_LEN_6 1
+#define SIRFUART_DATA_BIT_LEN_7 2
+#define SIRFUART_DATA_BIT_LEN_8 3
+#define SIRFUART_STOP_BIT_LEN_1 0
+#define SIRFUART_STOP_BIT_LEN_2 BIT(2)
+#define SIRFUART_PARITY_EN BIT(3)
+#define SIRFUART_EVEN_BIT BIT(4)
+#define SIRFUART_STICK_BIT_MASK (7 << 3)
+#define SIRFUART_STICK_BIT_NONE (0 << 3)
+#define SIRFUART_STICK_BIT_EVEN BIT(3)
+#define SIRFUART_STICK_BIT_ODD (3 << 3)
+#define SIRFUART_STICK_BIT_MARK (5 << 3)
+#define SIRFUART_STICK_BIT_SPACE (7 << 3)
+#define SIRFUART_SET_BREAK BIT(6)
+#define SIRFUART_LOOP_BACK BIT(7)
+#define SIRFUART_PARITY_MASK (7 << 3)
+
+#define SIRFSOC_UART_RX_TIMEOUT(br, to) (((br) * (((to) + 999) / 1000)) / 1000)
+#define SIRFUART_RECV_TIMEOUT_MASK (0xFFFF << 16)
+#define SIRFUART_RECV_TIMEOUT(x) (((x) & 0xFFFF) << 16)
+
+/* UART Auto Flow Control */
+#define SIRFUART_AFC_RX_THD_MASK 0x000000FF
+#define SIRFUART_AFC_RX_EN BIT(8)
+#define SIRFUART_AFC_TX_EN BIT(9)
+#define SIRFUART_CTS_CTRL BIT(10)
+#define SIRFUART_RTS_CTRL BIT(11)
+#define SIRFUART_CTS_IN_STATUS BIT(12)
+#define SIRFUART_RTS_OUT_STATUS BIT(13)
+
+/* UART Interrupt Enable Register */
+#define SIRFUART_RX_DONE_INT BIT(0)
+#define SIRFUART_TX_DONE_INT BIT(1)
+#define SIRFUART_RX_OFLOW_INT BIT(2)
+#define SIRFUART_TX_ALLOUT_INT BIT(3)
+#define SIRFUART_RX_IO_DMA_INT BIT(4)
+#define SIRFUART_TX_IO_DMA_INT BIT(5)
+#define SIRFUART_RXFIFO_FULL_INT BIT(6)
+#define SIRFUART_TXFIFO_EMPTY_INT BIT(7)
+#define SIRFUART_RXFIFO_THD_INT BIT(8)
+#define SIRFUART_TXFIFO_THD_INT BIT(9)
+#define SIRFUART_FRM_ERR_INT BIT(10)
+#define SIRFUART_RXD_BREAK_INT BIT(11)
+#define SIRFUART_RX_TIMEOUT_INT BIT(12)
+#define SIRFUART_PARITY_ERR_INT BIT(13)
+#define SIRFUART_CTS_INT_EN BIT(14)
+#define SIRFUART_RTS_INT_EN BIT(15)
+
+/* UART Interrupt Status Register */
+#define SIRFUART_RX_DONE BIT(0)
+#define SIRFUART_TX_DONE BIT(1)
+#define SIRFUART_RX_OFLOW BIT(2)
+#define SIRFUART_TX_ALL_EMPTY BIT(3)
+#define SIRFUART_DMA_IO_RX_DONE BIT(4)
+#define SIRFUART_DMA_IO_TX_DONE BIT(5)
+#define SIRFUART_RXFIFO_FULL BIT(6)
+#define SIRFUART_TXFIFO_EMPTY BIT(7)
+#define SIRFUART_RXFIFO_THD_REACH BIT(8)
+#define SIRFUART_TXFIFO_THD_REACH BIT(9)
+#define SIRFUART_FRM_ERR BIT(10)
+#define SIRFUART_RXD_BREAK BIT(11)
+#define SIRFUART_RX_TIMEOUT BIT(12)
+#define SIRFUART_PARITY_ERR BIT(13)
+#define SIRFUART_CTS_CHANGE BIT(14)
+#define SIRFUART_RTS_CHANGE BIT(15)
+#define SIRFUART_PLUG_IN BIT(16)
+
+#define SIRFUART_ERR_INT_STAT \
+ (SIRFUART_RX_OFLOW | \
+ SIRFUART_FRM_ERR | \
+ SIRFUART_RXD_BREAK | \
+ SIRFUART_PARITY_ERR)
+#define SIRFUART_ERR_INT_EN \
+ (SIRFUART_RX_OFLOW_INT | \
+ SIRFUART_FRM_ERR_INT | \
+ SIRFUART_RXD_BREAK_INT | \
+ SIRFUART_PARITY_ERR_INT)
+#define SIRFUART_TX_INT_EN SIRFUART_TXFIFO_EMPTY_INT
+#define SIRFUART_RX_IO_INT_EN \
+ (SIRFUART_RX_TIMEOUT_INT | \
+ SIRFUART_RXFIFO_THD_INT | \
+ SIRFUART_RXFIFO_FULL_INT | \
+ SIRFUART_ERR_INT_EN)
+
+/* UART FIFO Register */
+#define SIRFUART_TX_FIFO_STOP 0x0
+#define SIRFUART_TX_FIFO_RESET 0x1
+#define SIRFUART_TX_FIFO_START 0x2
+#define SIRFUART_RX_FIFO_STOP 0x0
+#define SIRFUART_RX_FIFO_RESET 0x1
+#define SIRFUART_RX_FIFO_START 0x2
+#define SIRFUART_TX_MODE_DMA 0
+#define SIRFUART_TX_MODE_IO 1
+#define SIRFUART_RX_MODE_DMA 0
+#define SIRFUART_RX_MODE_IO 1
+
+#define SIRFUART_RX_EN 0x1
+#define SIRFUART_TX_EN 0x2
+
+/* Generic Definitions */
+#define SIRFSOC_UART_NAME "ttyS"
+#define SIRFSOC_UART_MAJOR TTY_MAJOR
+#define SIRFSOC_UART_MINOR 64
+#define SIRFUART_PORT_NAME "sirfsoc-uart"
+#define SIRFUART_BAUD_RATE_SUPPORT_NR 18
+#define SIRFUART_MAP_SIZE 0x200
+#define SIRFSOC_UART_NR 3
+#define SIRFSOC_PORT_TYPE 0xa5
+
+/* For Fast Baud Rate Calculation */
+struct sirfsoc_baudrate_to_regv {
+ unsigned int baud_rate;
+ unsigned int reg_val;
+};
+
+struct sirfsoc_uart_port {
+ unsigned char hw_flow_ctrl;
+ unsigned char ms_enabled;
+
+ struct uart_port port;
+ struct pinmux *pmx;
+};
+
+#define uart_tx_port_tty_invalid(port) \
+ (((port)->state == NULL) || ((port)->state->port.tty == NULL))
+#define SIRFUART_DUMMY_READ BIT(16)
+
+/* Hardware Flow Control */
+#define SIRFUART_AFC_CTRL_RX_THD 0x70
+
+/* Register Access Control */
+#define portaddr(port, reg) ((port)->membase + (reg))
+#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
+#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
+#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))
+#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
+
+/* UART Port Mask */
+#define SIRFUART_FIFOLEVEL_MASK(port) ((port->line == 1) ? (0x1f) : (0x7f))
+#define SIRFUART_FIFOFULL_MASK(port) ((port->line == 1) ? (0x20) : (0x80))
+#define SIRFUART_FIFOEMPTY_MASK(port) ((port->line == 1) ? (0x40) : (0x100))
+
+/* I/O Mode */
+#define SIRFSOC_UART_IO_RX_MAX_CNT 256
+#define SIRFSOC_UART_IO_TX_REASONABLE_CNT 6
--
1.7.1
Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom
More information can be found at www.csr.com. Follow CSR on Twitter at http://twitter.com/CSR_PLC and read our blog at www.csr.com/blog
^ permalink raw reply related
* [PATCHv2] ARM: zImage: Use $(CROSS_COMPILE)size to get .bss size
From: Thomas Weber @ 2011-10-13 6:50 UTC (permalink / raw)
To: linux-arm-kernel
Use $(CROSS_COMPILE)size to determine the bss size
from vmlinux.
The problem is introduced in:
commit 5ffb04f6690d71fab241b3562ebf52b893ac4ff1
ARM: zImage: make sure appended DTB doesn't get
overwritten by kernel .bss
This fixes following error message:
size: arch/arm/boot/compressed/../../../../vmlinux:
File format is ambiguous
size: Matching formats:
elf32-littlearm
elf32-littlearm-symbian
elf32-littlearm-vxworks
Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Thomas Weber <weber@corscience.de>
---
v2:
- Fixed commit hash and rebased to rmk/devel-stable branch.
- Added received Acked-by
arch/arm/boot/compressed/Makefile | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index e4f32a8..3103632 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -126,7 +126,7 @@ ccflags-y := -fpic -fno-builtin -I$(obj)
asflags-y := -Wa,-march=all
# Supply kernel BSS size to the decompressor via a linker symbol.
-KBSS_SZ = $(shell size $(obj)/../../../../vmlinux | awk 'END{print $$3}')
+KBSS_SZ = $(shell $(CROSS_COMPILE)size $(obj)/../../../../vmlinux | awk 'END{print $$3}')
LDFLAGS_vmlinux = --defsym _kernel_bss_size=$(KBSS_SZ)
# Supply ZRELADDR to the decompressor via a linker symbol.
ifneq ($(CONFIG_AUTO_ZRELADDR),y)
--
1.7.7
^ permalink raw reply related
* [PATCH v6 10/16] OMAP2+: UART: Modify omap_uart_can_sleep function
From: Jean Pihet @ 2011-10-13 6:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAAL8m4zAOw9=qFCYV6-FxqGxQKwNZf71McCUtXSxoFMdOqz5PA@mail.gmail.com>
Hi Govindraj,
On Thu, Oct 13, 2011 at 3:09 AM, Govindraj <govindraj.ti@gmail.com> wrote:
...
>>
>> Yes, but obviously comes at the expense of power savings. ?IOW, This is
>> a hard-coded power vs. performance trade off that we are trying to get
>> away from.
>>
>> So, the root of the problem is that the MPU wakeup latency is causing a
>> "sluggish" console. ?The solution? ?request an MPU wakeup latency
>> constraint.
>>
>
> Okay, Will explore this.
>
>> This is a classic use-case for such a constraint, and the serial driver
>> should have the option of requesting a constraint to prevent the sluggish
>> console. ?The constraint only needs to be held until the auto-suspend
>> delay expires, so should be relased in the ->runtime_suspend() method of
>> the driver.
>>
>> This constraint needs to be configurable, probably from the board file,
>> so that it is optional, and so users who don't care about sluggish
>> consoles (or non-console UART users who don't care about response time)
>> have the option of preferring power savings over UART responsiveness.
>>
>> As a reference, the i2c driver is currently doing something similar
>> in that it request an MPU constraint to prevent the MPU from going into
>> retention/off while waiting for an i2c interrupt to arrive.
>>
>
> Thanks, will check and try to use the mpu constraints
As a reference the pm-qos branch of
https://gitorious.org/jpihet/omap-pm has the latest code for the
per-device constraints framework.
Please refer to the documentation at Documentation/power/pm_qos_interface.txt.
The commit dbec9ed1 [1] shows how I2C is using the framework.
[1] https://gitorious.org/jpihet/omap-pm/commit/dbec9ed1a6d6341d2ad2352a9578d66d15d198f4
Regards,
Jean
>
> --
> Govindraj.R.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* [RFC][PATCH] plat-mxc: iomux-v3.h: implicitly enable pull-up/down when that's desired
From: Paul Fertser @ 2011-10-13 7:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111012082702.GM13898@pengutronix.de>
On Wed, Oct 12, 2011 at 10:27:02AM +0200, Sascha Hauer wrote:
> On Mon, Oct 10, 2011 at 11:19:23AM +0400, Paul Fertser wrote:
> > This leads to some rather hard to understand bugs such as
> > misdetecting an absent ethernet PHY (a real bug i had)
...
> > This might affect mx25, mx35, mx50, mx51 and mx53 SoCs.
...
> > I'm not sure if that's really suitable for -stable so please excuse me
> > if it's not.
>
> I think it's not suitable for stable unless there is a real bug, that
> is PUE or PKE are forgotten somewhere.
If there wasn't a real bug with MDIO, i wouldn't have found the
problem. I've also checked all other potentially affected SoCs and all
of them (except for the mx35, whose iomux file doesn't configure any
pads at all) had some suspicious entries.
> I don't like that the defines which are supposed to be defines for
> the individual bits are changed. This may lead to trouble and confusion
> once someone wants to read the values from the iomux registers and
> tests for bits. How about Adding new defines like this instead:
I perfectly understand the reasoning and fully agree it would be best
to do it that way right from the beginning. But given the current
situation when many affected iomux headers share the error that can
lead to subtle strange bugs, i thought it might be beneficial to fix
them all implicitly. And testing for those pull-up bits set without
testing for PUE/PKE doesn't seem to be of any use, and also before
sending a patch i did a git grep and found no examples of using those
constants in an unexpected way.
If you still prefer the cleaner way, i can also do that and correct
all the suspicious entries manually, just let me know.
--
Be free, use free (http://www.gnu.org/philosophy/free-sw.html) software!
mailto:fercerpav at gmail.com
^ permalink raw reply
* [PATCH V4 3/3] ARM: SAMSUNG: Add lookup of sdhci-s3c clocks using generic names
From: Rajeshwari Birje @ 2011-10-13 7:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4E95BDF8.2080406@samsung.com>
Hi Sylwester,
On Wed, Oct 12, 2011 at 9:49 PM, Sylwester Nawrocki
<s.nawrocki@samsung.com> wrote:
> On 10/12/2011 02:36 PM, Rajeshwari Birje wrote:
>> On Wed, Oct 12, 2011 at 3:54 PM, Sylwester Nawrocki
>> <s.nawrocki@samsung.com> wrote:
>>> Hi Rajeshwari,
>>>
>>> On 10/12/2011 11:43 AM, Rajeshwari Shinde wrote:
>>>> Add support for lookup of sdhci-s3c controller clocks using generic names
>>>> for s3c2416, s3c64xx, s5pc100, s5pv210 and exynos4 SoC's.
>>>>
>>>> Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
>>>> ---
>>>> ?arch/arm/mach-exynos4/clock.c ? ? ? ? | ? 88 ++++++++++-------
>>>> ?arch/arm/mach-s3c2416/clock.c ? ? ? ? | ? 68 +++++++------
>>>> ?arch/arm/mach-s3c64xx/clock.c ? ? ? ? | ?126 +++++++++++++++----------
>>>> ?arch/arm/mach-s5pc100/clock.c ? ? ? ? | ?130 ++++++++++++++++----------
>>>> ?arch/arm/mach-s5pv210/clock.c ? ? ? ? | ?167 ++++++++++++++++++++-------------
>>>> ?arch/arm/plat-s3c24xx/s3c2443-clock.c | ? 15 ++-
>>>> ?6 files changed, 359 insertions(+), 235 deletions(-)
>>>>
>>>> diff --git a/arch/arm/mach-exynos4/clock.c b/arch/arm/mach-exynos4/clock.c
>>>> index 9f50e33..c6383b9 100644
>>>> --- a/arch/arm/mach-exynos4/clock.c
>>>> +++ b/arch/arm/mach-exynos4/clock.c
>>>> @@ -1157,42 +1157,6 @@ static struct clksrc_clk clksrcs[] = {
>>>> ? ? ? ? ? ? ? .reg_div = { .reg = S5P_CLKDIV_MFC, .shift = 0, .size = 4 },
> ...
>>>> +static struct clksrc_clk clk_sclk_mmc0 = {
>>>> + ? ? .clk ? ? ? ? ? ?= {
>>>> + ? ? ? ? ? ? .name ? ? ? ? ? = "sclk_mmc",
>>>> + ? ? ? ? ? ? .devname ? ? ? ?= "s3c-sdhci.0",
>>>
>>> Would it make sense to drop this 'devname' field here and others
>>> until sclk_mmc3 ....
>>
>> *** The devname here distinguishes these clocks. So it should be okay
>> to have a devname for these clocks.
>
> I'm not sure what's Mr Kukjin's opinion on that, but I personally would really
> like to see all the devname fields disappear from samsung clk data structures.
> Possibly if all involved people would keep that in mind we could achieve this
> over time.
**** Devname field is still required for clocks like hsmmc for driver
to work fine. Hence it would be tough to remove the devname
completely.
>
>>
>>>
>>>> + ? ? ? ? ? ? .parent ? ? ? ? = &clk_dout_mmc0.clk,
>>>> + ? ? ? ? ? ? .enable ? ? ? ? = exynos4_clksrc_mask_fsys_ctrl,
>>>> + ? ? ? ? ? ? .ctrlbit ? ? ? ?= (1 << 0),
>>>> + ? ? },
>>>> + ? ? .reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 8, .size = 8 },
>>>> +};
>>>> +
>>>> +static struct clksrc_clk clk_sclk_mmc1 = {
>>>> + ? ? .clk ? ? ? ? ? ?= {
>>>> + ? ? ? ? ? ? .name ? ? ? ? ? = "sclk_mmc",
>>>> + ? ? ? ? ? ? .devname ? ? ? ?= "s3c-sdhci.1",
>>>
>>>> + ? ? ? ? ? ? .parent ? ? ? ? = &clk_dout_mmc1.clk,
>>>> + ? ? ? ? ? ? .enable ? ? ? ? = exynos4_clksrc_mask_fsys_ctrl,
>>>> + ? ? ? ? ? ? .ctrlbit ? ? ? ?= (1 << 4),
>>>> + ? ? },
>>>> + ? ? .reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 24, .size = 8 },
>>>> +};
>>>> +
>>>> +static struct clksrc_clk clk_sclk_mmc2 = {
>>>> + ? ? .clk ? ? ? ? ? ?= {
>>>> + ? ? ? ? ? ? .name ? ? ? ? ? = "sclk_mmc",
>>>> + ? ? ? ? ? ? .devname ? ? ? ?= "s3c-sdhci.2",
>>>
>>>> + ? ? ? ? ? ? .parent ? ? ? ? = &clk_dout_mmc2.clk,
>>>> + ? ? ? ? ? ? .enable ? ? ? ? = exynos4_clksrc_mask_fsys_ctrl,
>>>> + ? ? ? ? ? ? .ctrlbit ? ? ? ?= (1 << 8),
>>>> + ? ? },
>>>> + ? ? .reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 8, .size = 8 },
>>>> +};
>>>> +
>>>> +static struct clksrc_clk clk_sclk_mmc3 = {
>>>> + ? ? .clk ? ? ? ? ? ?= {
>>>> + ? ? ? ? ? ? .name ? ? ? ? ? = "sclk_mmc",
>>>> + ? ? ? ? ? ? .devname ? ? ? ?= "s3c-sdhci.3",
>>>
>>>> + ? ? ? ? ? ? .parent ? ? ? ? = &clk_dout_mmc3.clk,
>>>> + ? ? ? ? ? ? .enable ? ? ? ? = exynos4_clksrc_mask_fsys_ctrl,
>>>> + ? ? ? ? ? ? .ctrlbit ? ? ? ?= (1 << 12),
>>>> + ? ? },
>>>> + ? ? .reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 24, .size = 8 },
>>>> +};
>>>> +
>>>> ?/* Clock initialization code */
>>>> ?static struct clksrc_clk *sysclks[] = {
>>>> ? ? ? &clk_mout_apll,
>>>> @@ -1289,6 +1297,10 @@ static struct clksrc_clk *clksrc_cdev[] = {
>>>> ? ? ? &clk_sclk_uart1,
>>>> ? ? ? &clk_sclk_uart2,
>>>> ? ? ? &clk_sclk_uart3,
>>>> + ? ? &clk_sclk_mmc0,
>>>> + ? ? &clk_sclk_mmc1,
>>>> + ? ? &clk_sclk_mmc2,
>>>> + ? ? &clk_sclk_mmc3,
>>>
>>> ..then drop the above 4 lines...
>>
>> **** The registration for these clocks are important. The
>> s3c_register_clksrc() function sets the .ops of this clock and also
>> its parent. So the registration cannot be dropped.
>
> OK.
>
>>
>>>
>>>> ?};
>>>>
>>>> ?static struct clk_lookup exynos4_clk_lookup[] = {
>>>> @@ -1296,6 +1308,10 @@ static struct clk_lookup exynos4_clk_lookup[] = {
>>>> ? ? ? CLKDEV_INIT("exynos4210-uart.1", "clk_uart_baud0", &clk_sclk_uart1.clk),
>>>> ? ? ? CLKDEV_INIT("exynos4210-uart.2", "clk_uart_baud0", &clk_sclk_uart2.clk),
>>>> ? ? ? CLKDEV_INIT("exynos4210-uart.3", "clk_uart_baud0", &clk_sclk_uart3.clk),
>>>> + ? ? CLKDEV_INIT("exynos4-sdhci.0", "mmc_busclk.2", &clk_sclk_mmc0.clk),
>>>> + ? ? CLKDEV_INIT("exynos4-sdhci.1", "mmc_busclk.2", &clk_sclk_mmc1.clk),
>>>> + ? ? CLKDEV_INIT("exynos4-sdhci.2", "mmc_busclk.2", &clk_sclk_mmc2.clk),
>>>> + ? ? CLKDEV_INIT("exynos4-sdhci.3", "mmc_busclk.2", &clk_sclk_mmc3.clk),
>>>
>>> ..and add something like:
>>>
>>> ?+ ? ? ?CLKDEV_INIT("s3c-sdhci.0", "sclk_mmc", &clk_sclk_mmc0.clk),
>>> ?+ ? ? ?CLKDEV_INIT("s3c-sdhci.1", "sclk_mmc", &clk_sclk_mmc1.clk),
>>> ?+ ? ? ?CLKDEV_INIT("s3c-sdhci.2", "sclk_mmc", &clk_sclk_mmc2.clk),
>>> ?+ ? ? ?CLKDEV_INIT("s3c-sdhci.3", "sclk_mmc", &clk_sclk_mmc3.clk),
>>>
>>> ?
>>
>> **** The driver uses a common name for the possible bus clock sources,
>> that is ?mmc_busclk?. This keeps the clock lookup code in the driver
>> simple. Also, there could be SoC?s which do no use sclk_mmc as the bus
>> clock name as per the user manual
>
> OK, I was aware of that. I didn't mean removing the "mmc_busclk.2" entries,
> just adding another 4, which are created anyway by s3c_register_clksrc()
> function. But for now I think the patch is OK.
>
>>
>>
>>>
>>> Also I'm wondering why we're using different device names for clk_sclk_mmc0..3
>>> clocks, i.e. exynos4-sdhci.? and s3c-sdhci.? ?
>>>
>>> Does it all work on exynos ? I would expect the device name to be same
>>> across all the clock definitions, otherwise clk_get(dev, ..) will fail.
>>
>> **** There was a patch submitted to rename the device name of sdhci
>> for Exynos to exynos4-sdhci. I will remove this change from this patch
>> and let that patch handle this change.
>
> I wouldn't do that. IMHO it's better to keep this patch as is, to make the final
> diff size lower.
**** Will modify the exynos4-sdhci. to s3c-sdhci. and send the
updated patch for review.
> Perhaps it's even worth to consider doing the clock rename altogether in this patch.
> But it's of course up to you.
>
>
> Regards,
> --
> Sylwester Nawrocki
> Samsung Poland R&D Center
>
Regards,
Rajeshwari Shinde.
^ permalink raw reply
* [RFC][PATCH] plat-mxc: iomux-v3.h: implicitly enable pull-up/down when that's desired
From: Sascha Hauer @ 2011-10-13 7:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111013071224.GR9395@home.lan>
On Thu, Oct 13, 2011 at 11:12:24AM +0400, Paul Fertser wrote:
> On Wed, Oct 12, 2011 at 10:27:02AM +0200, Sascha Hauer wrote:
> > On Mon, Oct 10, 2011 at 11:19:23AM +0400, Paul Fertser wrote:
> > > This leads to some rather hard to understand bugs such as
> > > misdetecting an absent ethernet PHY (a real bug i had)
> ...
> > > This might affect mx25, mx35, mx50, mx51 and mx53 SoCs.
> ...
> > > I'm not sure if that's really suitable for -stable so please excuse me
> > > if it's not.
> >
> > I think it's not suitable for stable unless there is a real bug, that
> > is PUE or PKE are forgotten somewhere.
>
> If there wasn't a real bug with MDIO, i wouldn't have found the
> problem. I've also checked all other potentially affected SoCs and all
> of them (except for the mx35, whose iomux file doesn't configure any
> pads at all) had some suspicious entries.
>
> > I don't like that the defines which are supposed to be defines for
> > the individual bits are changed. This may lead to trouble and confusion
> > once someone wants to read the values from the iomux registers and
> > tests for bits. How about Adding new defines like this instead:
>
> I perfectly understand the reasoning and fully agree it would be best
> to do it that way right from the beginning. But given the current
> situation when many affected iomux headers share the error that can
> lead to subtle strange bugs, i thought it might be beneficial to fix
> them all implicitly. And testing for those pull-up bits set without
> testing for PUE/PKE doesn't seem to be of any use, and also before
> sending a patch i did a git grep and found no examples of using those
> constants in an unexpected way.
Ok, convinced. Let's go with your patch for now as it's the least
intrusive way to deal with it. Still I think we should change this
as I suggested later.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* [PATCH] [RFC PATCH] ARM: kprobes: Make breakpoint setting/clearing SMP safe
From: Tixy @ 2011-10-13 7:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAH+eYFDSG=npBEjEgObqg+vPk8QuJBnnnGyULk9s-C9Bq3iH8Q@mail.gmail.com>
On Wed, 2011-10-12 at 22:03 +0530, Rabin Vincent wrote:
> On Tue, Jul 12, 2011 at 18:10, Tixy <tixy@yxit.co.uk> wrote:
> > Both these issues are known and the kprobe implementation uses
> > stop_machine() to avoid them, however, this is not sufficient.
> > stop_machine() does not perform any kind on synchronisation between CPUs
> > so it it still possible for one CPU to call the breakpoint changing
> > function before another CPU has been interrupted to do likewise.
> >
> > To fix this problem, this patch creates a new function
> > sync_stop_machine() which ensures that all online CPUs execute the
> > specified function at the same time.
>
> AFAICS stop_machine() already does what you want. When you use
> stop_machine(), the actual call to your function is done (on each
> CPU's stopper thread) using the stop_machine_cpu_stop() function,
> which already has the synchronization between CPUs which you're
> trying to do here.
The only serialisation I can see is the wait_for_completion() in
__stop_cpus() which waits for the all CPUs to have executed the
requested function. I don't see anything which prevents one CPU from
starting (and finishing) the requested function before other CPU's are
ready for it. If this synchronisation existed it would have to be in
cpu_stopper_thread() as it pulls tasks off the work list.
In queue_stop_cpus_work() we have
for_each_cpu(cpu, cpumask)
cpu_stop_queue_work(&per_cpu(cpu_stopper, cpu),
&per_cpu(stop_cpus_work, cpu));
If the CPU executing this gets delayed by an ISR on each iteration of
the for_each_cpu loop then the work it queues for one CPU could have
completed before it gets around to queuing it for the next CPU.
--
Tixy
^ permalink raw reply
* [PATCH V4 3/3] ARM: SAMSUNG: Add lookup of sdhci-s3c clocks using generic names
From: Sylwester Nawrocki @ 2011-10-13 7:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAPs=JDeFyoCYnR-Xa_fdmBVHxfNGuVNfdHd-MZgYcPytprsmFg@mail.gmail.com>
On 10/13/2011 09:16 AM, Rajeshwari Birje wrote:
> On Wed, Oct 12, 2011 at 9:49 PM, Sylwester Nawrocki
> <s.nawrocki@samsung.com> wrote:
>> On 10/12/2011 02:36 PM, Rajeshwari Birje wrote:
>>> On Wed, Oct 12, 2011 at 3:54 PM, Sylwester Nawrocki
>>> <s.nawrocki@samsung.com> wrote:
>>>> Hi Rajeshwari,
>>>>
>>>> On 10/12/2011 11:43 AM, Rajeshwari Shinde wrote:
>>>>> Add support for lookup of sdhci-s3c controller clocks using generic names
>>>>> for s3c2416, s3c64xx, s5pc100, s5pv210 and exynos4 SoC's.
>>>>>
>>>>> Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
>>>>> ---
>>>>> arch/arm/mach-exynos4/clock.c | 88 ++++++++++-------
>>>>> arch/arm/mach-s3c2416/clock.c | 68 +++++++------
>>>>> arch/arm/mach-s3c64xx/clock.c | 126 +++++++++++++++----------
>>>>> arch/arm/mach-s5pc100/clock.c | 130 ++++++++++++++++----------
>>>>> arch/arm/mach-s5pv210/clock.c | 167 ++++++++++++++++++++-------------
>>>>> arch/arm/plat-s3c24xx/s3c2443-clock.c | 15 ++-
>>>>> 6 files changed, 359 insertions(+), 235 deletions(-)
>>>>>
>>>>> diff --git a/arch/arm/mach-exynos4/clock.c b/arch/arm/mach-exynos4/clock.c
>>>>> index 9f50e33..c6383b9 100644
>>>>> --- a/arch/arm/mach-exynos4/clock.c
>>>>> +++ b/arch/arm/mach-exynos4/clock.c
>>>>> @@ -1157,42 +1157,6 @@ static struct clksrc_clk clksrcs[] = {
>>>>> .reg_div = { .reg = S5P_CLKDIV_MFC, .shift = 0, .size = 4 },
>> ...
>>>>> +static struct clksrc_clk clk_sclk_mmc0 = {
>>>>> + .clk = {
>>>>> + .name = "sclk_mmc",
>>>>> + .devname = "s3c-sdhci.0",
>>>>
>>>> Would it make sense to drop this 'devname' field here and others
>>>> until sclk_mmc3 ....
>>>
>>> *** The devname here distinguishes these clocks. So it should be okay
>>> to have a devname for these clocks.
>>
>> I'm not sure what's Mr Kukjin's opinion on that, but I personally would really
>> like to see all the devname fields disappear from samsung clk data structures.
>> Possibly if all involved people would keep that in mind we could achieve this
>> over time.
>
>
> **** Devname field is still required for clocks like hsmmc for driver
> to work fine. Hence it would be tough to remove the devname
> completely.
Yes, it allowed to add clkdev support with minimal changes required.
But let's see what happens when the works on common struct clk for all
architectures are more or less completed and we convert Samsung platforms
to use it;)
Regards,
--
Sylwester Nawrocki
Samsung Poland R&D Center
^ permalink raw reply
* [PATCH] ARM: kprobes: only patch instructions on one CPU
From: Tixy @ 2011-10-13 7:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1318435944-21855-1-git-send-email-rabin@rab.in>
On Wed, 2011-10-12 at 21:42 +0530, Rabin Vincent wrote:
> The text patching needs to be done only once, instead of once on each
> CPU. The other CPUs will busy wait inside the stop machine code until
> the patching is done.
Where in the stop machine code do the other CPU's busy wait?
How I read the code is that __stop_cpus() calls queue_stop_cpus_work()
which queues the work on each of the specified CPU's work list and wakes
that CPU's stopper thread to process it. __stop_cpus() then calls
wait_for_completion() to wait for these CPUs to finish the work.
I don't see how the execution path of CPUs not specified in cpumask is
interrupted in any way.
--
Tixy
>
> Cc: Jon Medhurst <tixy@yxit.co.uk>
> Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
> Signed-off-by: Rabin Vincent <rabin@rab.in>
> ---
> arch/arm/kernel/kprobes.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c
> index 129c116..e9f95300 100644
> --- a/arch/arm/kernel/kprobes.c
> +++ b/arch/arm/kernel/kprobes.c
> @@ -127,7 +127,7 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)
> flush_insns(addr, sizeof(u16));
> } else if (addr & 2) {
> /* A 32-bit instruction spanning two words needs special care */
> - stop_machine(set_t32_breakpoint, (void *)addr, &cpu_online_map);
> + stop_machine(set_t32_breakpoint, (void *)addr, NULL);
> } else {
> /* Word aligned 32-bit instruction can be written atomically */
> u32 bkp = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION;
> @@ -190,7 +190,7 @@ int __kprobes __arch_disarm_kprobe(void *p)
>
> void __kprobes arch_disarm_kprobe(struct kprobe *p)
> {
> - stop_machine(__arch_disarm_kprobe, p, &cpu_online_map);
> + stop_machine(__arch_disarm_kprobe, p, NULL);
> }
>
> void __kprobes arch_remove_kprobe(struct kprobe *p)
^ permalink raw reply
* [PATCH v5 2/2] iommu/exynos: Add iommu driver for Exynos Platforms
From: KyongHo Cho @ 2011-10-13 8:13 UTC (permalink / raw)
To: linux-arm-kernel
This is the exactly same patch with the previous
"[PATCH v5 2/2] iommu/exynos: Add iommu driver for Exynos Platforms".
The only change from the previous one is to change Sylwester's
email address in the Cc list by his request.
Regards,
KyongHo.
commit e1ad653521025dec5888b9818ed1a96aa9a5ad3a
Author: KyongHo Cho <pullip.cho@samsung.com>
Date: Thu Oct 13 17:06:55 2011 +0900
This is the System MMU driver and IOMMU API implementation for
Exynos SOC platforms. Exynos platforms has more than 10 System
MMUs dedicated for each multimedia accellerators.
The System MMU driver is already in arc/arm/plat-s5p but it is
moved to drivers/iommu due to Ohad Ben-Cohen gathered IOMMU drivers
there
This patch also includes fault handling feature in IOMMU driver
suggested by Ohad.
Users of IOMMU API can register its own fault handler with
iommu_set_fault_handler() and the handler is called by IRQ handler
of System MMU.
If no user installs fault handler, IOMMU driver prints debugging
message and generates kernel oops.
This IOMMU driver calls bus_set_iommu() instead of register_iommu()
since Joerg suggested that installing iommu_ops in bus_type.
Cc: Joerg Roedel <joerg.roedel@amd.com>
Cc: Ohad Ben-Cohen <ohad@wizery.com>
Cc: Sylwester Nawrocki <s.nawrocki@samsung.com>
Cc: Russell King <linux@arm.linux.org.uk>
Signed-off-by: KyongHo Cho <pullip.cho@samsung.com>
---
arch/arm/plat-s5p/Kconfig | 8 -
arch/arm/plat-s5p/Makefile | 1 -
arch/arm/plat-s5p/sysmmu.c | 312 ---------
arch/arm/plat-samsung/include/plat/sysmmu.h | 95 ---
drivers/iommu/Kconfig | 14 +
drivers/iommu/Makefile | 1 +
drivers/iommu/exynos_iommu.c | 962
+++++++++++++++++++++++++++
7 files changed, 977 insertions(+), 416 deletions(-)
delete mode 100644 arch/arm/plat-s5p/sysmmu.c
delete mode 100644 arch/arm/plat-samsung/include/plat/sysmmu.h
create mode 100644 drivers/iommu/exynos_iommu.c
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
index 7b9dada..831e45b 100644
--- a/arch/arm/plat-s5p/Kconfig
+++ b/arch/arm/plat-s5p/Kconfig
@@ -46,14 +46,6 @@ config S5P_PM
Common code for power management support on S5P and newer SoCs
Note: Do not select this for S5P6440 and S5P6450.
-comment "System MMU"
-
-config S5P_SYSTEM_MMU
- bool "S5P SYSTEM MMU"
- depends on ARCH_EXYNOS4
- help
- Say Y here if you want to enable System MMU
-
config S5P_SLEEP
bool
help
diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile
index 06401dc..7a9c4fc 100644
--- a/arch/arm/plat-s5p/Makefile
+++ b/arch/arm/plat-s5p/Makefile
@@ -19,7 +19,6 @@ obj-y += clock.o
obj-y += irq.o
obj-$(CONFIG_S5P_EXT_INT) += irq-eint.o
obj-$(CONFIG_S5P_GPIO_INT) += irq-gpioint.o
-obj-$(CONFIG_S5P_SYSTEM_MMU) += sysmmu.o
obj-$(CONFIG_S5P_PM) += pm.o irq-pm.o
obj-$(CONFIG_S5P_SLEEP) += sleep.o
obj-$(CONFIG_S5P_HRT) += s5p-time.o
diff --git a/arch/arm/plat-s5p/sysmmu.c b/arch/arm/plat-s5p/sysmmu.c
deleted file mode 100644
index e1cbc72..0000000
--- a/arch/arm/plat-s5p/sysmmu.c
+++ /dev/null
@@ -1,312 +0,0 @@
-/* linux/arch/arm/plat-s5p/sysmmu.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.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.
- */
-
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-
-#include <asm/pgtable.h>
-
-#include <mach/map.h>
-#include <mach/regs-sysmmu.h>
-#include <plat/sysmmu.h>
-
-#define CTRL_ENABLE 0x5
-#define CTRL_BLOCK 0x7
-#define CTRL_DISABLE 0x0
-
-static struct device *dev;
-
-static unsigned short fault_reg_offset[SYSMMU_FAULTS_NUM] = {
- S5P_PAGE_FAULT_ADDR,
- S5P_AR_FAULT_ADDR,
- S5P_AW_FAULT_ADDR,
- S5P_DEFAULT_SLAVE_ADDR,
- S5P_AR_FAULT_ADDR,
- S5P_AR_FAULT_ADDR,
- S5P_AW_FAULT_ADDR,
- S5P_AW_FAULT_ADDR
-};
-
-static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
- "PAGE FAULT",
- "AR MULTI-HIT FAULT",
- "AW MULTI-HIT FAULT",
- "BUS ERROR",
- "AR SECURITY PROTECTION FAULT",
- "AR ACCESS PROTECTION FAULT",
- "AW SECURITY PROTECTION FAULT",
- "AW ACCESS PROTECTION FAULT"
-};
-
-static int (*fault_handlers[S5P_SYSMMU_TOTAL_IPNUM])(
- enum S5P_SYSMMU_INTERRUPT_TYPE itype,
- unsigned long pgtable_base,
- unsigned long fault_addr);
-
-/*
- * If adjacent 2 bits are true, the system MMU is enabled.
- * The system MMU is disabled, otherwise.
- */
-static unsigned long sysmmu_states;
-
-static inline void set_sysmmu_active(sysmmu_ips ips)
-{
- sysmmu_states |= 3 << (ips * 2);
-}
-
-static inline void set_sysmmu_inactive(sysmmu_ips ips)
-{
- sysmmu_states &= ~(3 << (ips * 2));
-}
-
-static inline int is_sysmmu_active(sysmmu_ips ips)
-{
- return sysmmu_states & (3 << (ips * 2));
-}
-
-static void __iomem *sysmmusfrs[S5P_SYSMMU_TOTAL_IPNUM];
-
-static inline void sysmmu_block(sysmmu_ips ips)
-{
- __raw_writel(CTRL_BLOCK, sysmmusfrs[ips] + S5P_MMU_CTRL);
- dev_dbg(dev, "%s is blocked.\n", sysmmu_ips_name[ips]);
-}
-
-static inline void sysmmu_unblock(sysmmu_ips ips)
-{
- __raw_writel(CTRL_ENABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
- dev_dbg(dev, "%s is unblocked.\n", sysmmu_ips_name[ips]);
-}
-
-static inline void __sysmmu_tlb_invalidate(sysmmu_ips ips)
-{
- __raw_writel(0x1, sysmmusfrs[ips] + S5P_MMU_FLUSH);
- dev_dbg(dev, "TLB of %s is invalidated.\n", sysmmu_ips_name[ips]);
-}
-
-static inline void __sysmmu_set_ptbase(sysmmu_ips ips, unsigned long pgd)
-{
- if (unlikely(pgd == 0)) {
- pgd = (unsigned long)ZERO_PAGE(0);
- __raw_writel(0x20, sysmmusfrs[ips] + S5P_MMU_CFG); /* 4KB
LV1 */
- } else {
- __raw_writel(0x0, sysmmusfrs[ips] + S5P_MMU_CFG); /* 16KB
LV1 */
- }
-
- __raw_writel(pgd, sysmmusfrs[ips] + S5P_PT_BASE_ADDR);
-
- dev_dbg(dev, "Page table base of %s is initialized with 0x%08lX.\n",
- sysmmu_ips_name[ips], pgd);
- __sysmmu_tlb_invalidate(ips);
-}
-
-void sysmmu_set_fault_handler(sysmmu_ips ips,
- int (*handler)(enum S5P_SYSMMU_INTERRUPT_TYPE itype,
- unsigned long pgtable_base,
- unsigned long fault_addr))
-{
- BUG_ON(!((ips >= SYSMMU_MDMA) && (ips < S5P_SYSMMU_TOTAL_IPNUM)));
- fault_handlers[ips] = handler;
-}
-
-static irqreturn_t s5p_sysmmu_irq(int irq, void *dev_id)
-{
- /* SYSMMU is in blocked when interrupt occurred. */
- unsigned long base = 0;
- sysmmu_ips ips = (sysmmu_ips)dev_id;
- enum S5P_SYSMMU_INTERRUPT_TYPE itype;
-
- itype = (enum S5P_SYSMMU_INTERRUPT_TYPE)
- __ffs(__raw_readl(sysmmusfrs[ips] + S5P_INT_STATUS));
-
- BUG_ON(!((itype >= 0) && (itype < 8)));
-
- dev_alert(dev, "%s occurred by %s.\n", sysmmu_fault_name[itype],
-
sysmmu_ips_name[ips]);
-
- if (fault_handlers[ips]) {
- unsigned long addr;
-
- base = __raw_readl(sysmmusfrs[ips] + S5P_PT_BASE_ADDR);
- addr = __raw_readl(sysmmusfrs[ips] +
fault_reg_offset[itype]);
-
- if (fault_handlers[ips](itype, base, addr)) {
- __raw_writel(1 << itype,
- sysmmusfrs[ips] + S5P_INT_CLEAR);
- dev_notice(dev, "%s from %s is resolved."
- " Retrying translation.\n",
- sysmmu_fault_name[itype],
sysmmu_ips_name[ips]);
- } else {
- base = 0;
- }
- }
-
- sysmmu_unblock(ips);
-
- if (!base)
- dev_notice(dev, "%s from %s is not handled.\n",
- sysmmu_fault_name[itype], sysmmu_ips_name[ips]);
-
- return IRQ_HANDLED;
-}
-
-void s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd)
-{
- if (is_sysmmu_active(ips)) {
- sysmmu_block(ips);
- __sysmmu_set_ptbase(ips, pgd);
- sysmmu_unblock(ips);
- } else {
- dev_dbg(dev, "%s is disabled. "
- "Skipping initializing page table base.\n",
- sysmmu_ips_name[ips]);
- }
-}
-
-void s5p_sysmmu_enable(sysmmu_ips ips, unsigned long pgd)
-{
- if (!is_sysmmu_active(ips)) {
- sysmmu_clk_enable(ips);
-
- __sysmmu_set_ptbase(ips, pgd);
-
- __raw_writel(CTRL_ENABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
-
- set_sysmmu_active(ips);
- dev_dbg(dev, "%s is enabled.\n", sysmmu_ips_name[ips]);
- } else {
- dev_dbg(dev, "%s is already enabled.\n",
sysmmu_ips_name[ips]);
- }
-}
-
-void s5p_sysmmu_disable(sysmmu_ips ips)
-{
- if (is_sysmmu_active(ips)) {
- __raw_writel(CTRL_DISABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
- set_sysmmu_inactive(ips);
- sysmmu_clk_disable(ips);
- dev_dbg(dev, "%s is disabled.\n", sysmmu_ips_name[ips]);
- } else {
- dev_dbg(dev, "%s is already disabled.\n",
sysmmu_ips_name[ips]);
- }
-}
-
-void s5p_sysmmu_tlb_invalidate(sysmmu_ips ips)
-{
- if (is_sysmmu_active(ips)) {
- sysmmu_block(ips);
- __sysmmu_tlb_invalidate(ips);
- sysmmu_unblock(ips);
- } else {
- dev_dbg(dev, "%s is disabled. "
- "Skipping invalidating TLB.\n",
sysmmu_ips_name[ips]);
- }
-}
-
-static int s5p_sysmmu_probe(struct platform_device *pdev)
-{
- int i, ret;
- struct resource *res, *mem;
-
- dev = &pdev->dev;
-
- for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) {
- int irq;
-
- sysmmu_clk_init(dev, i);
- sysmmu_clk_disable(i);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- if (!res) {
- dev_err(dev, "Failed to get the resource of %s.\n",
- sysmmu_ips_name[i]);
- ret = -ENODEV;
- goto err_res;
- }
-
- mem = request_mem_region(res->start, resource_size(res),
- pdev->name);
- if (!mem) {
- dev_err(dev, "Failed to request the memory region of
%s.\n",
- sysmmu_ips_name[i]);
- ret = -EBUSY;
- goto err_res;
- }
-
- sysmmusfrs[i] = ioremap(res->start, resource_size(res));
- if (!sysmmusfrs[i]) {
- dev_err(dev, "Failed to ioremap() for %s.\n",
- sysmmu_ips_name[i]);
- ret = -ENXIO;
- goto err_reg;
- }
-
- irq = platform_get_irq(pdev, i);
- if (irq <= 0) {
- dev_err(dev, "Failed to get the IRQ resource of
%s.\n",
- sysmmu_ips_name[i]);
- ret = -ENOENT;
- goto err_map;
- }
-
- if (request_irq(irq, s5p_sysmmu_irq, IRQF_DISABLED,
- pdev->name, (void *)i)) {
- dev_err(dev, "Failed to request IRQ for %s.\n",
- sysmmu_ips_name[i]);
- ret = -ENOENT;
- goto err_map;
- }
- }
-
- return 0;
-
-err_map:
- iounmap(sysmmusfrs[i]);
-err_reg:
- release_mem_region(mem->start, resource_size(mem));
-err_res:
- return ret;
-}
-
-static int s5p_sysmmu_remove(struct platform_device *pdev)
-{
- return 0;
-}
-int s5p_sysmmu_runtime_suspend(struct device *dev)
-{
- return 0;
-}
-
-int s5p_sysmmu_runtime_resume(struct device *dev)
-{
- return 0;
-}
-
-const struct dev_pm_ops s5p_sysmmu_pm_ops = {
- .runtime_suspend = s5p_sysmmu_runtime_suspend,
- .runtime_resume = s5p_sysmmu_runtime_resume,
-};
-
-static struct platform_driver s5p_sysmmu_driver = {
- .probe = s5p_sysmmu_probe,
- .remove = s5p_sysmmu_remove,
- .driver = {
- .owner = THIS_MODULE,
- .name = "s5p-sysmmu",
- .pm = &s5p_sysmmu_pm_ops,
- }
-};
-
-static int __init s5p_sysmmu_init(void)
-{
- return platform_driver_register(&s5p_sysmmu_driver);
-}
-arch_initcall(s5p_sysmmu_init);
diff --git a/arch/arm/plat-samsung/include/plat/sysmmu.h
b/arch/arm/plat-samsung/include/plat/sysmmu.h
deleted file mode 100644
index 5fe8ee0..0000000
--- a/arch/arm/plat-samsung/include/plat/sysmmu.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* linux/arch/arm/plat-samsung/include/plat/sysmmu.h
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * Samsung System MMU driver for S5P platform
- *
- * 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_SAMSUNG_SYSMMU_H
-#define __PLAT_SAMSUNG_SYSMMU_H __FILE__
-
-enum S5P_SYSMMU_INTERRUPT_TYPE {
- SYSMMU_PAGEFAULT,
- SYSMMU_AR_MULTIHIT,
- SYSMMU_AW_MULTIHIT,
- SYSMMU_BUSERROR,
- SYSMMU_AR_SECURITY,
- SYSMMU_AR_ACCESS,
- SYSMMU_AW_SECURITY,
- SYSMMU_AW_PROTECTION, /* 7 */
- SYSMMU_FAULTS_NUM
-};
-
-#ifdef CONFIG_S5P_SYSTEM_MMU
-
-#include <mach/sysmmu.h>
-
-/**
- * s5p_sysmmu_enable() - enable system mmu of ip
- * @ips: The ip connected system mmu.
- * #pgd: Base physical address of the 1st level page table
- *
- * This function enable system mmu to transfer address
- * from virtual address to physical address
- */
-void s5p_sysmmu_enable(sysmmu_ips ips, unsigned long pgd);
-
-/**
- * s5p_sysmmu_disable() - disable sysmmu mmu of ip
- * @ips: The ip connected system mmu.
- *
- * This function disable system mmu to transfer address
- * from virtual address to physical address
- */
-void s5p_sysmmu_disable(sysmmu_ips ips);
-
-/**
- * s5p_sysmmu_set_tablebase_pgd() - set page table base address to refer
page table
- * @ips: The ip connected system mmu.
- * @pgd: The page table base address.
- *
- * This function set page table base address
- * When system mmu transfer address from virtaul address to physical
address,
- * system mmu refer address information from page table
- */
-void s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd);
-
-/**
- * s5p_sysmmu_tlb_invalidate() - flush all TLB entry in system mmu
- * @ips: The ip connected system mmu.
- *
- * This function flush all TLB entry in system mmu
- */
-void s5p_sysmmu_tlb_invalidate(sysmmu_ips ips);
-
-/** s5p_sysmmu_set_fault_handler() - Fault handler for System MMUs
- * @itype: type of fault.
- * @pgtable_base: the physical address of page table base. This is 0 if
@ips is
- * SYSMMU_BUSERROR.
- * @fault_addr: the device (virtual) address that the System MMU tried to
- * translated. This is 0 if @ips is SYSMMU_BUSERROR.
- * Called when interrupt occurred by the System MMUs
- * The device drivers of peripheral devices that has a System MMU can
implement
- * a fault handler to resolve address translation fault by System MMU.
- * The meanings of return value and parameters are described below.
-
- * return value: non-zero if the fault is correctly resolved.
- * zero if the fault is not handled.
- */
-void s5p_sysmmu_set_fault_handler(sysmmu_ips ips,
- int (*handler)(enum S5P_SYSMMU_INTERRUPT_TYPE itype,
- unsigned long pgtable_base,
- unsigned long fault_addr));
-#else
-#define s5p_sysmmu_enable(ips, pgd) do { } while (0)
-#define s5p_sysmmu_disable(ips) do { } while (0)
-#define s5p_sysmmu_set_tablebase_pgd(ips, pgd) do { } while (0)
-#define s5p_sysmmu_tlb_invalidate(ips) do { } while (0)
-#define s5p_sysmmu_set_fault_handler(ips, handler) do { } while (0)
-#endif
-#endif /* __ASM_PLAT_SYSMMU_H */
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index b57b3fa..1c754cd 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -107,4 +107,18 @@ config INTR_REMAP
To use x2apic mode in the CPU's which support x2APIC enhancements
or
to support platforms with CPU's having > 8 bit APIC ID, say Y.
+# EXYNOS IOMMU support
+config EXYNOS_IOMMU
+ bool "Exynos IOMMU Support"
+ depends on ARCH_EXYNOS4
+ select IOMMU_API
+ select EXYNOS4_DEV_SYSMMU
+ help
+ Support for the IOMMUs (System MMUs) Samsung Exynos application
+ processor family. This enables H/W multimedia accellerators to
view
+ non-linear physical memory chunks as a linear memory in their
virtual
+ address spaces.
+
+ If unsure, say N here.
+
endif # IOMMU_SUPPORT
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 4d4d77d..1eb924f 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o
obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
obj-$(CONFIG_DMAR) += dmar.o iova.o intel-iommu.o
obj-$(CONFIG_INTR_REMAP) += dmar.o intr_remapping.o
+obj-$(CONFIG_EXYNOS_IOMMU) += exynos_iommu.o
diff --git a/drivers/iommu/exynos_iommu.c b/drivers/iommu/exynos_iommu.c
new file mode 100644
index 0000000..f6bda2f
--- /dev/null
+++ b/drivers/iommu/exynos_iommu.c
@@ -0,0 +1,962 @@
+/* linux/drivers/iommu/exynos_iommu.c
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.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.
+ */
+
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/iommu.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/atomic.h>
+#include <linux/spinlock.h>
+
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+
+#include <mach/map.h>
+#include <mach/regs-sysmmu.h>
+#include <mach/sysmmu.h>
+
+#define CTRL_ENABLE 0x5
+#define CTRL_BLOCK 0x7
+#define CTRL_DISABLE 0x0
+
+enum S5P_SYSMMU_INTERRUPT_TYPE {
+ SYSMMU_PAGEFAULT,
+ SYSMMU_AR_MULTIHIT,
+ SYSMMU_AW_MULTIHIT,
+ SYSMMU_BUSERROR,
+ SYSMMU_AR_SECURITY,
+ SYSMMU_AR_ACCESS,
+ SYSMMU_AW_SECURITY,
+ SYSMMU_AW_PROTECTION, /* 7 */
+ SYSMMU_FAULT_UNKNOWN,
+ SYSMMU_FAULTS_NUM
+};
+
+static unsigned short fault_reg_offset[SYSMMU_FAULTS_NUM] = {
+ S5P_PAGE_FAULT_ADDR,
+ S5P_AR_FAULT_ADDR,
+ S5P_AW_FAULT_ADDR,
+ S5P_DEFAULT_SLAVE_ADDR,
+ S5P_AR_FAULT_ADDR,
+ S5P_AR_FAULT_ADDR,
+ S5P_AW_FAULT_ADDR,
+ S5P_AW_FAULT_ADDR
+};
+
+static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM + 1] = {
+ "PAGE FAULT",
+ "AR MULTI-HIT FAULT",
+ "AW MULTI-HIT FAULT",
+ "BUS ERROR",
+ "AR SECURITY PROTECTION FAULT",
+ "AR ACCESS PROTECTION FAULT",
+ "AW SECURITY PROTECTION FAULT",
+ "AW ACCESS PROTECTION FAULT",
+ "UNKOWN FAULT"
+};
+
+struct exynos_iommu_domain {
+ struct device *dev;
+ unsigned long *pgtable;
+ spinlock_t lock;
+ spinlock_t pgtablelock;
+};
+
+typedef int (*s5p_sysmmu_fault_handler_t)(enum S5P_SYSMMU_INTERRUPT_TYPE
itype,
+ unsigned long pgtable_base,
+ unsigned long fault_addr);
+struct sysmmu_drvdata {
+ struct list_head node;
+ struct device *dev;
+ struct device *owner;
+ void __iomem *sfrbase;
+ struct clk *clk;
+ int activations;
+ rwlock_t lock;
+ struct iommu_domain *domain;
+ s5p_sysmmu_fault_handler_t fault_handler;
+};
+
+
+/* List of sysmmu_drvdata */
+static LIST_HEAD(sysmmu_list);
+
+static struct sysmmu_drvdata *get_sysmmu_data(struct device *owner,
+ struct sysmmu_drvdata
*start)
+{
+ if (start) {
+ list_for_each_entry_continue(start, &sysmmu_list, node)
+ if (start->owner == owner)
+ return start;
+ } else {
+ list_for_each_entry(start, &sysmmu_list, node)
+ if (start->owner == owner)
+ return start;
+ }
+
+ return NULL;
+}
+
+static struct sysmmu_drvdata *get_sysmmu_data_rollback(struct device
*owner,
+ struct sysmmu_drvdata
*start)
+{
+ if (start) {
+ list_for_each_entry_continue_reverse(start, &sysmmu_list,
node)
+ if (start->owner == owner)
+ return start;
+ }
+
+ return NULL;
+}
+
+static bool set_sysmmu_active(struct sysmmu_drvdata *data)
+{
+ /* return true if the System MMU was not active previously
+ and it needs to be initialized */
+ data->activations++;
+ return data->activations == 1;
+}
+
+static bool set_sysmmu_inactive(struct sysmmu_drvdata *data)
+{
+ /* return true if the System MMU is needed to be disabled */
+ data->activations--;
+
+ WARN_ON(data->activations < 0);
+
+ return data->activations == 0;
+}
+
+static bool is_sysmmu_active(struct sysmmu_drvdata *data)
+{
+ return data->activations != 0;
+}
+
+static void sysmmu_block(void __iomem *sfrbase)
+{
+ __raw_writel(CTRL_BLOCK, sfrbase + S5P_MMU_CTRL);
+}
+
+static void sysmmu_unblock(void __iomem *sfrbase)
+{
+ __raw_writel(CTRL_ENABLE, sfrbase + S5P_MMU_CTRL);
+}
+
+static void __sysmmu_tlb_invalidate(void __iomem *sfrbase)
+{
+ __raw_writel(0x1, sfrbase + S5P_MMU_FLUSH);
+}
+
+static void __sysmmu_set_ptbase(void __iomem *sfrbase,
+ unsigned long pgd)
+{
+ if (unlikely(pgd == 0)) {
+ pgd = (unsigned long)ZERO_PAGE(0);
+ __raw_writel(0x20, sfrbase + S5P_MMU_CFG); /* 4KB LV1 */
+ } else {
+ __raw_writel(0x0, sfrbase + S5P_MMU_CFG); /* 16KB LV1 */
+ }
+
+ __raw_writel(pgd, sfrbase + S5P_PT_BASE_ADDR);
+
+ __sysmmu_tlb_invalidate(sfrbase);
+}
+
+static void __set_fault_handler(struct sysmmu_drvdata *data,
+ s5p_sysmmu_fault_handler_t handler)
+{
+ unsigned long flags;
+
+ write_lock_irqsave(&data->lock, flags);
+ data->fault_handler = handler;
+ write_unlock_irqrestore(&data->lock, flags);
+}
+
+void s5p_sysmmu_set_fault_handler(struct device *owner,
+ s5p_sysmmu_fault_handler_t handler)
+{
+ struct sysmmu_drvdata *data = NULL;
+
+ while ((data = get_sysmmu_data(owner, data)))
+ __set_fault_handler(data, handler);
+}
+
+static int default_fault_handler(enum S5P_SYSMMU_INTERRUPT_TYPE itype,
+ unsigned long pgtable_base, unsigned long
fault_addr)
+{
+ if ((itype >= SYSMMU_FAULTS_NUM) || (itype < SYSMMU_PAGEFAULT))
+ itype = SYSMMU_FAULT_UNKNOWN;
+
+ pr_err("%s occured@0x%08lx(Page table base: 0x%08lx)\n",
+ sysmmu_fault_name[itype], fault_addr, pgtable_base);
+ pr_err("\t\tGenerating Kernel OOPS... because it is
unrecoverable.\n");
+
+ BUG();
+
+ return 0;
+}
+
+static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
+{
+ /* SYSMMU is in blocked when interrupt occurred. */
+ struct sysmmu_drvdata *data = dev_id;
+ enum S5P_SYSMMU_INTERRUPT_TYPE itype;
+ unsigned long addr;
+ int ret = -ENOSYS;
+
+ read_lock(&data->lock);
+
+ WARN_ON(!is_sysmmu_active(data));
+
+ itype = (enum S5P_SYSMMU_INTERRUPT_TYPE)
+ __ffs(__raw_readl(data->sfrbase + S5P_INT_STATUS));
+
+ if (WARN_ON((itype < 0) && (itype >= 8)))
+ itype = SYSMMU_FAULT_UNKNOWN;
+
+ addr = __raw_readl(data->sfrbase + fault_reg_offset[itype]);
+
+ if (data->domain)
+ ret = report_iommu_fault(data->domain, data->owner, addr,
+
itype);
+
+ if ((ret == -ENOSYS) && (data->fault_handler)) {
+ unsigned long base;
+ base = __raw_readl(data->sfrbase + S5P_PT_BASE_ADDR);
+
+ ret = data->fault_handler(itype, base, addr);
+ }
+
+ if (!ret)
+ __raw_writel(1 << itype, data->sfrbase + S5P_INT_CLEAR);
+ else
+ dev_dbg(data->dev, "%s is not handled.\n",
+ sysmmu_fault_name[itype]);
+
+ sysmmu_unblock(data->sfrbase);
+
+ read_unlock(&data->lock);
+
+ return IRQ_HANDLED;
+}
+
+void exynos_sysmmu_set_tablebase_pgd(struct device *owner, unsigned long
pgd)
+{
+ struct sysmmu_drvdata *data = NULL;
+
+ while ((data = get_sysmmu_data(owner, data))) {
+ unsigned long flags;
+
+ read_lock_irqsave(&data->lock, flags);
+
+ if (is_sysmmu_active(data)) {
+ sysmmu_block(data->sfrbase);
+ __sysmmu_set_ptbase(data->sfrbase, pgd);
+ sysmmu_unblock(data->sfrbase);
+ dev_dbg(data->dev,
+ "New page table base is 0x%08lx\n", pgd);
+ } else {
+ dev_dbg(data->dev,
+ "Disabled: Skipping setting page table base.\n");
+ }
+
+ read_unlock_irqrestore(&data->lock, flags);
+ }
+}
+
+static int __exynos_sysmmu_enable(struct device *owner, unsigned long
pgtable,
+ struct iommu_domain *domain)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct sysmmu_drvdata *data = NULL;
+
+ /* There are some devices that control more System MMUs than one
such
+ * as MFC.
+ */
+ while ((data = get_sysmmu_data(owner, data))) {
+ ret = pm_runtime_get_sync(data->dev);
+ if (ret) {
+ set_sysmmu_active(data); /* for rollback */
+ break;
+ }
+
+ write_lock_irqsave(&data->lock, flags);
+
+ if (set_sysmmu_active(data)) {
+ __sysmmu_set_ptbase(data->sfrbase, pgtable);
+
+ __raw_writel(CTRL_ENABLE, data->sfrbase +
S5P_MMU_CTRL);
+
+ data->domain = domain;
+
+ dev_dbg(data->dev, "Enabled.\n");
+ } else {
+ dev_dbg(data->dev, "Already enabled.\n");
+ }
+
+ write_unlock_irqrestore(&data->lock, flags);
+ }
+
+ if (ret) {
+ do {
+ write_lock_irqsave(&data->lock, flags);
+ set_sysmmu_inactive(data);
+ data->domain = NULL;
+ /* deinitialization is not required actually. */
+ write_unlock_irqrestore(&data->lock, flags);
+
+ pm_runtime_put_sync(data->dev);
+
+ dev_dbg(data->dev, "Failed to enable.\n");
+ } while ((data = get_sysmmu_data_rollback(owner, data)));
+ }
+
+ return ret;
+}
+
+static int exynos_iommu_enable(struct iommu_domain *domain)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+
+ if (!priv || !priv->dev)
+ return -EINVAL;
+
+ return __exynos_sysmmu_enable(priv->dev, __pa(priv->pgtable),
domain);
+}
+
+int exynos_sysmmu_enable(struct device *owner, unsigned long pgtable)
+{
+ return __exynos_sysmmu_enable(owner, pgtable, NULL);
+}
+
+void exynos_sysmmu_disable(struct device *owner)
+{
+ struct sysmmu_drvdata *data = NULL;
+
+ while ((data = get_sysmmu_data(owner, data))) {
+ unsigned long flags;
+
+ write_lock_irqsave(&data->lock, flags);
+
+ if (set_sysmmu_inactive(data)) {
+ __raw_writel(CTRL_DISABLE,
+ data->sfrbase +
S5P_MMU_CTRL);
+
+ dev_dbg(data->dev, "Disabled.\n");
+ } else {
+ dev_dbg(data->dev, "Inactivation request
ignorred\n");
+ }
+
+ __raw_writel(CTRL_DISABLE, data->sfrbase + S5P_MMU_CTRL);
+
+ data->domain = NULL;
+
+ write_unlock_irqrestore(&data->lock, flags);
+
+ pm_runtime_put_sync(data->dev);
+ }
+}
+
+static void exynos_iommu_disable(struct iommu_domain *domain)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+
+ if (priv && priv->dev)
+ exynos_sysmmu_disable(priv->dev);
+}
+
+void exynos_sysmmu_tlb_invalidate(struct device *owner)
+{
+ struct sysmmu_drvdata *data = NULL;
+
+ while ((data = get_sysmmu_data(owner, data))) {
+ unsigned long flags;
+
+ read_lock_irqsave(&data->lock, flags);
+
+ if (is_sysmmu_active(data)) {
+ sysmmu_block(data->sfrbase);
+ __sysmmu_tlb_invalidate(data->sfrbase);
+ sysmmu_unblock(data->sfrbase);
+ } else {
+ dev_dbg(data->dev,
+ "Disabled: Skipping invalidating TLB.\n");
+ }
+
+ read_unlock_irqrestore(&data->lock, flags);
+ }
+}
+
+static int exynos_sysmmu_probe(struct platform_device *pdev)
+{
+ struct resource *res, *ioarea;
+ int ret = 0;
+ int irq;
+ struct device *dev;
+ void *sfr;
+ struct sysmmu_drvdata *data;
+ struct clk *clk;
+
+ dev = &pdev->dev;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(dev, "Failed to probing System MMU: "
+ "Not enough memory");
+ return -ENOMEM;
+ }
+
+ data->owner = dev_get_platdata(dev);
+ if (!data->owner) {
+ /* This is not an error */
+ dev_dbg(dev, "Not initialized: Owner device is not set.");
+
+ ret = -ENODEV;
+ goto err_init;
+ }
+
+ ret = dev_set_drvdata(dev, data);
+ if (ret) {
+ dev_err(dev, "Failed to probing system MMU: "
+ "Unable to set driver
data.");
+ goto err_init;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev,
+ "Failed probing system MMU: failed to get
resource.");
+ ret = -ENOENT;
+ goto err_init;
+ }
+
+ ioarea = request_mem_region(res->start, resource_size(res),
+
dev_name(dev));
+ if (ioarea == NULL) {
+ dev_err(dev, "Failed probing system MMU: "
+ "failed to request memory region.");
+ ret = -ENOENT;
+ goto err_init;
+ }
+
+ sfr = ioremap(res->start, resource_size(res));
+ if (!sfr) {
+ dev_err(dev, "Failed probing system MMU: "
+ "failed to call
ioremap().");
+ ret = -ENOENT;
+ goto err_ioremap;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(dev, "Failed probing system MMU: "
+ "failed to get irq
resource.");
+ ret = irq;
+ goto err_irq;
+ }
+
+ ret = request_irq(irq, exynos_sysmmu_irq, 0, dev_name(dev), data);
+ if (ret) {
+ dev_err(dev, "Failed probing system MMU: "
+ "failed to request irq.");
+ goto err_irq;
+ }
+
+ clk = clk_get(dev, "sysmmu");
+ if (IS_ERR(clk)) {
+ dev_err(dev, "Failed to probing System MMU: "
+ "failed to get clock descriptor");
+ ret = PTR_ERR(clk);
+ goto err_clk;
+ }
+
+ data->dev = dev;
+ data->clk = clk;
+ data->sfrbase = sfr;
+ __set_fault_handler(data, &default_fault_handler);
+ rwlock_init(&data->lock);
+ INIT_LIST_HEAD(&data->node);
+
+ list_add(&data->node, &sysmmu_list);
+
+ if (dev->parent)
+ pm_runtime_enable(dev);
+
+ dev_dbg(dev, "Initialized.\n");
+ return 0;
+err_clk:
+ free_irq(irq, data);
+err_irq:
+ iounmap(sfr);
+err_ioremap:
+ release_resource(ioarea);
+ kfree(ioarea);
+err_init:
+ kfree(data);
+ return ret;
+}
+
+int exynos_sysmmu_runtime_suspend(struct device *dev)
+{
+ struct sysmmu_drvdata *data = dev_get_drvdata(dev);
+
+ clk_disable(data->clk);
+
+ return 0;
+}
+
+int exynos_sysmmu_runtime_resume(struct device *dev)
+{
+ struct sysmmu_drvdata *data = dev_get_drvdata(dev);
+
+ return clk_enable(data->clk);
+}
+
+const struct dev_pm_ops exynos_sysmmu_pm_ops = {
+ .runtime_suspend = exynos_sysmmu_runtime_suspend,
+ .runtime_resume = exynos_sysmmu_runtime_resume,
+};
+
+static struct platform_driver exynos_sysmmu_driver = {
+ .probe = exynos_sysmmu_probe,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "s5p-sysmmu",
+ .pm = &exynos_sysmmu_pm_ops,
+ }
+};
+
+static int __init exynos_sysmmu_init(void)
+{
+ return platform_driver_register(&exynos_sysmmu_driver);
+}
+arch_initcall(exynos_sysmmu_init);
+
+/* We does not consider super section mapping (16MB) */
+#define S5P_SPAGE_SHIFT 12
+#define S5P_LPAGE_SHIFT 16
+#define S5P_SECTION_SHIFT 20
+
+#define S5P_SPAGE_SIZE (1 << S5P_SPAGE_SHIFT)
+#define S5P_LPAGE_SIZE (1 << S5P_LPAGE_SHIFT)
+#define S5P_SECTION_SIZE (1 << S5P_SECTION_SHIFT)
+
+#define S5P_SPAGE_MASK (~(S5P_SPAGE_SIZE - 1))
+#define S5P_LPAGE_MASK (~(S5P_LPAGE_SIZE - 1))
+#define S5P_SECTION_MASK (~(S5P_SECTION_SIZE - 1))
+
+#define S5P_SPAGE_ORDER (S5P_SPAGE_SHIFT - PAGE_SHIFT)
+#define S5P_LPAGE_ORDER (S5P_LPAGE_SHIFT - S5P_SPAGE_SHIFT)
+#define S5P_SECTION_ORDER (S5P_SECTION_SHIFT - S5P_SPAGE_SHIFT)
+
+#define S5P_LV1TABLE_ENTRIES (1 << (BITS_PER_LONG - S5P_SECTION_SHIFT))
+#define S5P_LV1TABLE_ORDER 2 /* get_order(S5P_LV1TABLE_ENTRIES) */
+
+#define S5P_LV2TABLE_ENTRIES (1 << S5P_SECTION_ORDER)
+#define S5P_LV2TABLE_SIZE (S5P_LV2TABLE_ENTRIES * sizeof(long))
+#define S5P_LV2TABLE_MASK (~(S5P_LV2TABLE_SIZE - 1)) /* 0xFFFFFC00 */
+
+#define S5P_SECTION_LV1_ENTRY(entry) ((entry & 0x40003) == 2)
+#define S5P_SUPSECT_LV1_ENTRY(entry) ((entry & 0x40003) == 0x40002)
+#define S5P_PAGE_LV1_ENTRY(entry) ((entry & 3) == 1)
+#define S5P_FAULT_LV1_ENTRY(entry) (((entry & 3) == 0) || (entry & 3) == 3)
+
+#define S5P_LPAGE_LV2_ENTRY(entry) ((entry & 3) == 1)
+#define S5P_SPAGE_LV2_ENTRY(entry) ((entry & 2) == 2)
+#define S5P_FAULT_LV2_ENTRY(entry) ((entry & 3) == 0)
+
+#define MAKE_FAULT_ENTRY(entry) do { entry = 0; } while (0)
+#define MAKE_SECTION_ENTRY(entry, pa) do { entry = pa | 2; } while (0)
+#define MAKE_SUPSECT_ENTRY(entry, pa) do { entry = pa | 0x40002; } while
(0)
+#define MAKE_LV2TABLE_ENTRY(entry, pa) do { entry = pa | 1; } while (0)
+
+#define MAKE_LPAGE_ENTRY(entry, pa) do { entry = pa | 1; } while (0)
+#define MAKE_SPAGE_ENTRY(entry, pa) do { entry = pa | 3; } while (0)
+
+#define GET_LV2ENTRY(entry, iova) (\
+ (unsigned long *)phys_to_virt(entry & S5P_LV2TABLE_MASK) +\
+ ((iova & (~S5P_SECTION_MASK)) >> S5P_SPAGE_SHIFT))
+
+/* slab cache for level 2 page tables */
+static struct kmem_cache *l2table_cachep;
+
+static void pgtable_flush(void *vastart, void *vaend)
+{
+ dmac_flush_range(vastart, vaend);
+ outer_flush_range(virt_to_phys(vastart),
+ virt_to_phys(vaend));
+}
+
+static int exynos_iommu_domain_init(struct iommu_domain *domain)
+{
+ struct exynos_iommu_domain *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->pgtable = (unsigned long *)
+ __get_free_pages(S5P_LV1TABLE_ORDER, GFP_KERNEL);
+ if (!priv->pgtable) {
+ kfree(priv);
+ return -ENOMEM;
+ }
+
+ memset(priv->pgtable, 0, S5P_LV1TABLE_ENTRIES * sizeof(unsigned
long));
+ pgtable_flush(priv->pgtable, priv->pgtable + S5P_LV1TABLE_ENTRIES);
+
+ spin_lock_init(&priv->lock);
+ spin_lock_init(&priv->pgtablelock);
+
+ domain->priv = priv;
+
+ return 0;
+}
+
+static void exynos_iommu_domain_destroy(struct iommu_domain *domain)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+
+ free_pages((unsigned long)priv->pgtable, S5P_LV1TABLE_ORDER);
+
+ kfree(priv);
+
+ domain->priv = NULL;
+}
+
+static int exynos_iommu_attach_device(struct iommu_domain *domain,
+ struct device *dev)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+ int ret;
+
+ spin_lock(&priv->lock);
+
+ priv->dev = dev;
+
+ spin_unlock(&priv->lock);
+
+ ret = exynos_iommu_enable(domain);
+
+ return ret;
+}
+
+static void exynos_iommu_detach_device(struct iommu_domain *domain,
+ struct device *dev)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+
+ spin_lock(&priv->lock);
+
+ if (priv->dev == dev) {
+ priv->dev = NULL;
+
+ spin_unlock(&priv->lock);
+
+ exynos_iommu_disable(domain);
+ } else {
+ spin_unlock(&priv->lock);
+ }
+}
+
+static bool section_available(struct iommu_domain *domain,
+ unsigned long *lv1entry)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+
+ if (S5P_SECTION_LV1_ENTRY(*lv1entry)) {
+ dev_err(priv->dev, "1MB entry alread exists at 0x%08x\n",
+ (lv1entry - priv->pgtable) * SZ_1M);
+ return false;
+ }
+
+ if (S5P_PAGE_LV1_ENTRY(*lv1entry)) {
+ unsigned long *lv2end, *lv2base;
+
+ lv2base = phys_to_virt(*lv1entry & S5P_LV2TABLE_MASK);
+ lv2end = lv2base + S5P_LV2TABLE_ENTRIES;
+ while (lv2base != lv2end) {
+ if (!S5P_FAULT_LV2_ENTRY(*lv2base)) {
+ dev_err(priv->dev, "Failed to free L2 page "
+ "table for section
mapping.\n");
+ return false;
+ }
+ lv2base++;
+ }
+
+ kmem_cache_free(l2table_cachep,
+ phys_to_virt(*lv1entry &
S5P_LV2TABLE_MASK));
+
+ MAKE_FAULT_ENTRY(*lv1entry);
+ }
+
+ return true;
+}
+
+static bool write_lpage(unsigned long *head_entry, unsigned long phys_addr)
+{
+ unsigned long *entry, *end;
+
+ entry = head_entry;
+ end = entry + (1 << S5P_LPAGE_ORDER);
+
+ while (entry != end) {
+ if (!S5P_FAULT_LV2_ENTRY(*entry))
+ break;
+
+ MAKE_LPAGE_ENTRY(*entry, phys_addr);
+
+ entry++;
+ }
+
+ if (entry != end) {
+ end = entry;
+ while (entry != head_entry)
+ MAKE_FAULT_ENTRY(*(--entry));
+
+ return false;
+ }
+
+ return true;
+}
+
+static int exynos_iommu_map(struct iommu_domain *domain, unsigned long
iova,
+ phys_addr_t paddr, int gfp_order, int prot)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+ unsigned long *start_entry, *entry, *end_entry;
+ int num_entry;
+ int ret = 0;
+ unsigned long flags;
+
+ BUG_ON(priv->pgtable == NULL);
+
+ spin_lock_irqsave(&priv->pgtablelock, flags);
+
+ start_entry = entry = priv->pgtable + (iova >> S5P_SECTION_SHIFT);
+
+ if (gfp_order >= S5P_SECTION_ORDER) {
+ BUG_ON(!IS_ALIGNED(paddr | iova, S5P_SECTION_SIZE));
+ /* 1MiB mapping */
+
+ num_entry = 1 << (gfp_order - S5P_SECTION_ORDER);
+ end_entry = entry + num_entry;
+
+ while (entry != end_entry) {
+ if (!section_available(domain, entry))
+ break;
+
+ MAKE_SECTION_ENTRY(*entry, paddr);
+
+ paddr += S5P_SECTION_SIZE;
+ entry++;
+ }
+
+ if (entry != end_entry)
+ goto mapping_error;
+
+ pgtable_flush(start_entry, entry);
+ goto mapping_done;
+ }
+
+ if (S5P_FAULT_LV1_ENTRY(*entry)) {
+ unsigned long *l2table;
+
+ l2table = kmem_cache_zalloc(l2table_cachep, GFP_KERNEL);
+ if (!l2table) {
+ ret = -ENOMEM;
+ goto nomem_error;
+ }
+
+ pgtable_flush(entry, entry + S5P_LV2TABLE_ENTRIES);
+
+ MAKE_LV2TABLE_ENTRY(*entry, virt_to_phys(l2table));
+ pgtable_flush(entry, entry + 1);
+ }
+
+ /* 'entry' points level 2 entries, hereafter */
+ entry = GET_LV2ENTRY(*entry, iova);
+
+ start_entry = entry;
+ num_entry = 1 << gfp_order;
+ end_entry = entry + num_entry;
+
+ if (gfp_order >= S5P_LPAGE_ORDER) {
+ /* large page(64KiB) mapping */
+ BUG_ON(!IS_ALIGNED(paddr | iova, S5P_LPAGE_SIZE));
+
+ while (entry != end_entry) {
+ if (!write_lpage(entry, paddr)) {
+ pr_err("%s: "
+ "Failed to allocate large page
entry."
+ "\n", __func__);
+ break;
+ }
+
+ paddr += S5P_LPAGE_SIZE;
+ entry += (1 << S5P_LPAGE_ORDER);
+ }
+
+ if (entry != end_entry) {
+ entry -= 1 << S5P_LPAGE_ORDER;
+ goto mapping_error;
+ }
+ } else {
+ /* page (4KiB) mapping */
+ while (entry != end_entry && S5P_FAULT_LV2_ENTRY(*entry)) {
+
+ MAKE_SPAGE_ENTRY(*entry, paddr);
+
+ entry++;
+ paddr += S5P_SPAGE_SIZE;
+ }
+
+ if (entry != end_entry) {
+ pr_err("%s: Failed to allocate small page entry.\n",
+ __func__);
+ goto mapping_error;
+ }
+ }
+
+ pgtable_flush(start_entry, entry);
+mapping_error:
+ if (entry != end_entry) {
+ unsigned long *current_entry = entry;
+ while (entry != start_entry)
+ MAKE_FAULT_ENTRY(*(--entry));
+ pgtable_flush(start_entry, current_entry);
+ ret = -EADDRINUSE;
+ }
+
+nomem_error:
+mapping_done:
+ spin_unlock_irqrestore(&priv->pgtablelock, flags);
+
+ return 0;
+}
+
+static int exynos_iommu_unmap(struct iommu_domain *domain, unsigned long
iova,
+ int gfp_order)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+ unsigned long *entry;
+ int num_entry;
+ unsigned long flags;
+
+ BUG_ON(priv->pgtable == NULL);
+
+ spin_lock_irqsave(&priv->pgtablelock, flags);
+
+ entry = priv->pgtable + (iova >> S5P_SECTION_SHIFT);
+
+ if (gfp_order >= S5P_SECTION_ORDER) {
+ gfp_order -= S5P_SECTION_ORDER;
+ num_entry = 1 << (gfp_order - S5P_SECTION_ORDER);
+ while (num_entry--) {
+ if (S5P_SECTION_LV1_ENTRY(*entry)) {
+ MAKE_FAULT_ENTRY(*entry);
+ } else if (S5P_PAGE_LV1_ENTRY(*entry)) {
+ unsigned long *lv2beg, *lv2end;
+ lv2beg = phys_to_virt(
+ *entry & S5P_LV2TABLE_MASK);
+ lv2end = lv2beg + S5P_LV2TABLE_ENTRIES;
+ while (lv2beg != lv2end) {
+ MAKE_FAULT_ENTRY(*lv2beg);
+ lv2beg++;
+ }
+ }
+ entry++;
+ }
+ } else {
+ entry = GET_LV2ENTRY(*entry, iova);
+
+ BUG_ON(S5P_LPAGE_LV2_ENTRY(*entry) &&
+ (gfp_order <
S5P_LPAGE_ORDER));
+
+ num_entry = 1 << gfp_order;
+
+ while (num_entry--) {
+ MAKE_FAULT_ENTRY(*entry);
+ entry++;
+ }
+ }
+
+ spin_unlock_irqrestore(&priv->pgtablelock, flags);
+
+ if (priv->dev)
+ exynos_sysmmu_tlb_invalidate(priv->dev);
+
+ return gfp_order;
+}
+
+static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *domain,
+ unsigned long iova)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+ unsigned long *entry;
+ unsigned long offset;
+
+ entry = priv->pgtable + (iova >> S5P_SECTION_SHIFT);
+
+ if (S5P_FAULT_LV1_ENTRY(*entry))
+ return 0;
+
+ offset = iova & ~S5P_SECTION_MASK;
+
+ if (S5P_SECTION_LV1_ENTRY(*entry))
+ return (*entry & S5P_SECTION_MASK) + offset;
+
+ entry = GET_LV2ENTRY(*entry, iova);
+
+ if (S5P_SPAGE_LV2_ENTRY(*entry))
+ return (*entry & S5P_SPAGE_MASK) + (iova & ~S5P_SPAGE_MASK);
+
+ if (S5P_LPAGE_LV2_ENTRY(*entry))
+ return (*entry & S5P_LPAGE_MASK) + (iova & ~S5P_LPAGE_MASK);
+
+ return 0;
+}
+
+static int exynos_iommu_domain_has_cap(struct iommu_domain *domain,
+ unsigned long cap)
+{
+ return 0;
+}
+
+static struct iommu_ops exynos_iommu_ops = {
+ .domain_init = &exynos_iommu_domain_init,
+ .domain_destroy = &exynos_iommu_domain_destroy,
+ .attach_dev = &exynos_iommu_attach_device,
+ .detach_dev = &exynos_iommu_detach_device,
+ .map = &exynos_iommu_map,
+ .unmap = &exynos_iommu_unmap,
+ .iova_to_phys = &exynos_iommu_iova_to_phys,
+ .domain_has_cap = &exynos_iommu_domain_has_cap,
+};
+
+static int __init exynos_iommu_init(void)
+{
+ l2table_cachep = kmem_cache_create("SysMMU Lv2 Tables",
+ S5P_LV2TABLE_SIZE, S5P_LV2TABLE_SIZE, 0,
NULL);
+ if (!l2table_cachep)
+ return -ENOMEM;
+
+ bus_set_iommu(&platform_bus_type, &exynos_iommu_ops);
+
+ return 0;
+}
+arch_initcall(exynos_iommu_init);
--
1.7.1
^ permalink raw reply related
* [PATCH V4 0/3] ARM: SAMSUNG: Add support for sdhci clock lookup using generic names
From: Rajeshwari Shinde @ 2011-10-13 8:16 UTC (permalink / raw)
To: linux-arm-kernel
This patchset adds support for sdhci controller clock lookup using
generic names. With this patchset, there will be no need to pass clock
names in sdhci platform data.
This patchset depends on the patchset:
Add a common macro for creating struct clk_lookup entries.
mmc: sdhci-s3c: add default controller configuration.
V2 Changes:
- Added HCLK instance for HSMMC instance 1 as suggested by Heiko.
- Rebased on UART clkdev patches. So these patches should be applied
after UART clkdev patches are applied.
V3 Changes:
- Removed double registration of hsmmc1 hclk from s3c2416 as suggested by
Heiko
V4 Changes:
- Changed the devname for bus clocks in Exynos4 to s3c-sdhci. from
exynos4-sdhci. as suggested by Sylwester.
Rajeshwari Shinde (3):
SDHCI: S3C: Use generic clock names for sdhci bus clock options
ARM: SAMSUNG: Remove SDHCI bus clocks from platform data
ARM: SAMSUNG: Add lookup of sdhci-s3c clocks using generic names
arch/arm/mach-exynos4/Makefile | 1 -
arch/arm/mach-exynos4/clock.c | 88 +++++++++------
arch/arm/mach-exynos4/setup-sdhci.c | 22 ----
arch/arm/mach-s3c2416/Makefile | 1 -
arch/arm/mach-s3c2416/clock.c | 68 ++++++-----
arch/arm/mach-s3c2416/setup-sdhci.c | 24 ----
arch/arm/mach-s3c64xx/Makefile | 1 -
arch/arm/mach-s3c64xx/clock.c | 126 +++++++++++++--------
arch/arm/mach-s3c64xx/setup-sdhci.c | 24 ----
arch/arm/mach-s5pc100/Makefile | 1 -
arch/arm/mach-s5pc100/clock.c | 130 +++++++++++++---------
arch/arm/mach-s5pc100/setup-sdhci.c | 23 ----
arch/arm/mach-s5pv210/Makefile | 1 -
arch/arm/mach-s5pv210/clock.c | 167 +++++++++++++++++-----------
arch/arm/mach-s5pv210/setup-sdhci.c | 22 ----
arch/arm/plat-s3c24xx/s3c2443-clock.c | 15 ++-
arch/arm/plat-samsung/include/plat/sdhci.h | 31 -----
drivers/mmc/host/sdhci-s3c.c | 6 +-
18 files changed, 361 insertions(+), 390 deletions(-)
delete mode 100644 arch/arm/mach-exynos4/setup-sdhci.c
delete mode 100644 arch/arm/mach-s3c2416/setup-sdhci.c
delete mode 100644 arch/arm/mach-s3c64xx/setup-sdhci.c
delete mode 100644 arch/arm/mach-s5pc100/setup-sdhci.c
delete mode 100644 arch/arm/mach-s5pv210/setup-sdhci.c
--
1.7.4.4
^ permalink raw reply
* [PATCH V4 1/3] SDHCI: S3C: Use generic clock names for sdhci bus clock options
From: Rajeshwari Shinde @ 2011-10-13 8:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1318493819-18906-1-git-send-email-rajeshwari.s@samsung.com>
This patch modifies the driver to stop depending on the clock names
being passed from the platform and switch over to bus clock lookup
using generic clock names.
Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
---
drivers/mmc/host/sdhci-s3c.c | 6 ++----
1 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index 82709b6..a5fde87 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -435,14 +435,12 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
for (clks = 0, ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
struct clk *clk;
- char *name = pdata->clocks[ptr];
+ char name[14];
- if (name == NULL)
- continue;
+ sprintf(name, "mmc_busclk.%d", ptr);
clk = clk_get(dev, name);
if (IS_ERR(clk)) {
- dev_err(dev, "failed to get clock %s\n", name);
continue;
}
--
1.7.4.4
^ permalink raw reply related
* [PATCH V4 2/3] ARM: SAMSUNG: Remove SDHCI bus clocks from platform data
From: Rajeshwari Shinde @ 2011-10-13 8:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1318493819-18906-1-git-send-email-rajeshwari.s@samsung.com>
The bus clocks previously sent through platform data to SDHCI controller
are removed.
Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
---
arch/arm/mach-exynos4/Makefile | 1 -
arch/arm/mach-exynos4/setup-sdhci.c | 22 -------------------
arch/arm/mach-s3c2416/Makefile | 1 -
arch/arm/mach-s3c2416/setup-sdhci.c | 24 ---------------------
arch/arm/mach-s3c64xx/Makefile | 1 -
arch/arm/mach-s3c64xx/setup-sdhci.c | 24 ---------------------
arch/arm/mach-s5pc100/Makefile | 1 -
arch/arm/mach-s5pc100/setup-sdhci.c | 23 --------------------
arch/arm/mach-s5pv210/Makefile | 1 -
arch/arm/mach-s5pv210/setup-sdhci.c | 22 -------------------
arch/arm/plat-samsung/include/plat/sdhci.h | 31 ----------------------------
11 files changed, 0 insertions(+), 151 deletions(-)
delete mode 100644 arch/arm/mach-exynos4/setup-sdhci.c
delete mode 100644 arch/arm/mach-s3c2416/setup-sdhci.c
delete mode 100644 arch/arm/mach-s3c64xx/setup-sdhci.c
delete mode 100644 arch/arm/mach-s5pc100/setup-sdhci.c
delete mode 100644 arch/arm/mach-s5pv210/setup-sdhci.c
diff --git a/arch/arm/mach-exynos4/Makefile b/arch/arm/mach-exynos4/Makefile
index 2bb18f4..c47aae3 100644
--- a/arch/arm/mach-exynos4/Makefile
+++ b/arch/arm/mach-exynos4/Makefile
@@ -55,7 +55,6 @@ obj-$(CONFIG_EXYNOS4_SETUP_I2C5) += setup-i2c5.o
obj-$(CONFIG_EXYNOS4_SETUP_I2C6) += setup-i2c6.o
obj-$(CONFIG_EXYNOS4_SETUP_I2C7) += setup-i2c7.o
obj-$(CONFIG_EXYNOS4_SETUP_KEYPAD) += setup-keypad.o
-obj-$(CONFIG_EXYNOS4_SETUP_SDHCI) += setup-sdhci.o
obj-$(CONFIG_EXYNOS4_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
obj-$(CONFIG_EXYNOS4_SETUP_USB_PHY) += setup-usb-phy.o
diff --git a/arch/arm/mach-exynos4/setup-sdhci.c b/arch/arm/mach-exynos4/setup-sdhci.c
deleted file mode 100644
index 92937b4..0000000
--- a/arch/arm/mach-exynos4/setup-sdhci.c
+++ /dev/null
@@ -1,22 +0,0 @@
-/* linux/arch/arm/mach-exynos4/setup-sdhci.c
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * EXYNOS4 - Helper functions for settign up SDHCI device(s) (HSMMC)
- *
- * 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/types.h>
-
-/* clock sources for the mmc bus clock, order as for the ctrl2[5..4] */
-
-char *exynos4_hsmmc_clksrcs[4] = {
- [0] = NULL,
- [1] = NULL,
- [2] = "sclk_mmc", /* mmc_bus */
- [3] = NULL,
-};
diff --git a/arch/arm/mach-s3c2416/Makefile b/arch/arm/mach-s3c2416/Makefile
index 7b805b2..ca0cd22 100644
--- a/arch/arm/mach-s3c2416/Makefile
+++ b/arch/arm/mach-s3c2416/Makefile
@@ -15,7 +15,6 @@ obj-$(CONFIG_S3C2416_PM) += pm.o
#obj-$(CONFIG_S3C2416_DMA) += dma.o
# Device setup
-obj-$(CONFIG_S3C2416_SETUP_SDHCI) += setup-sdhci.o
obj-$(CONFIG_S3C2416_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
# Machine support
diff --git a/arch/arm/mach-s3c2416/setup-sdhci.c b/arch/arm/mach-s3c2416/setup-sdhci.c
deleted file mode 100644
index cee5395..0000000
--- a/arch/arm/mach-s3c2416/setup-sdhci.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/* linux/arch/arm/mach-s3c2416/setup-sdhci.c
- *
- * Copyright 2010 Promwad Innovation Company
- * Yauhen Kharuzhy <yauhen.kharuzhy@promwad.com>
- *
- * S3C2416 - Helper functions for settign up SDHCI device(s) (HSMMC)
- *
- * Based on mach-s3c64xx/setup-sdhci.c
- *
- * 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/types.h>
-
-/* clock sources for the mmc bus clock, order as for the ctrl2[5..4] */
-
-char *s3c2416_hsmmc_clksrcs[4] = {
- [0] = "hsmmc",
- [1] = "hsmmc",
- [2] = "hsmmc-if",
- /* [3] = "48m", - note not successfully used yet */
-};
diff --git a/arch/arm/mach-s3c64xx/Makefile b/arch/arm/mach-s3c64xx/Makefile
index 902ab9a..94de24b 100644
--- a/arch/arm/mach-s3c64xx/Makefile
+++ b/arch/arm/mach-s3c64xx/Makefile
@@ -32,7 +32,6 @@ obj-$(CONFIG_S3C64XX_SETUP_I2C0) += setup-i2c0.o
obj-$(CONFIG_S3C64XX_SETUP_I2C1) += setup-i2c1.o
obj-$(CONFIG_S3C64XX_SETUP_IDE) += setup-ide.o
obj-$(CONFIG_S3C64XX_SETUP_KEYPAD) += setup-keypad.o
-obj-$(CONFIG_S3C64XX_SETUP_SDHCI) += setup-sdhci.o
obj-$(CONFIG_S3C64XX_SETUP_FB_24BPP) += setup-fb-24bpp.o
obj-$(CONFIG_S3C64XX_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
diff --git a/arch/arm/mach-s3c64xx/setup-sdhci.c b/arch/arm/mach-s3c64xx/setup-sdhci.c
deleted file mode 100644
index c75a71b..0000000
--- a/arch/arm/mach-s3c64xx/setup-sdhci.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/* linux/arch/arm/mach-s3c64xx/setup-sdhci.c
- *
- * Copyright 2008 Simtec Electronics
- * Copyright 2008 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- * http://armlinux.simtec.co.uk/
- *
- * S3C6400/S3C6410 - Helper functions for settign up SDHCI device(s) (HSMMC)
- *
- * 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/types.h>
-
-/* clock sources for the mmc bus clock, order as for the ctrl2[5..4] */
-
-char *s3c64xx_hsmmc_clksrcs[4] = {
- [0] = "hsmmc",
- [1] = "hsmmc",
- [2] = "mmc_bus",
- /* [3] = "48m", - note not successfully used yet */
-};
diff --git a/arch/arm/mach-s5pc100/Makefile b/arch/arm/mach-s5pc100/Makefile
index a5e6e60..2320e54 100644
--- a/arch/arm/mach-s5pc100/Makefile
+++ b/arch/arm/mach-s5pc100/Makefile
@@ -21,7 +21,6 @@ obj-$(CONFIG_S5PC100_SETUP_FB_24BPP) += setup-fb-24bpp.o
obj-$(CONFIG_S5PC100_SETUP_I2C1) += setup-i2c1.o
obj-$(CONFIG_S5PC100_SETUP_IDE) += setup-ide.o
obj-$(CONFIG_S5PC100_SETUP_KEYPAD) += setup-keypad.o
-obj-$(CONFIG_S5PC100_SETUP_SDHCI) += setup-sdhci.o
obj-$(CONFIG_S5PC100_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
# device support
diff --git a/arch/arm/mach-s5pc100/setup-sdhci.c b/arch/arm/mach-s5pc100/setup-sdhci.c
deleted file mode 100644
index 6418c6e..0000000
--- a/arch/arm/mach-s5pc100/setup-sdhci.c
+++ /dev/null
@@ -1,23 +0,0 @@
-/* linux/arch/arm/mach-s5pc100/setup-sdhci.c
- *
- * Copyright 2008 Samsung Electronics
- *
- * S5PC100 - Helper functions for settign up SDHCI device(s) (HSMMC)
- *
- * Based on mach-s3c6410/setup-sdhci.c
- *
- * 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/types.h>
-
-/* clock sources for the mmc bus clock, order as for the ctrl2[5..4] */
-
-char *s5pc100_hsmmc_clksrcs[4] = {
- [0] = "hsmmc", /* HCLK */
- /* [1] = "hsmmc", - duplicate HCLK entry */
- [2] = "sclk_mmc", /* mmc_bus */
- /* [3] = "48m", - note not successfully used yet */
-};
diff --git a/arch/arm/mach-s5pv210/Makefile b/arch/arm/mach-s5pv210/Makefile
index 009fbe5..53c346a 100644
--- a/arch/arm/mach-s5pv210/Makefile
+++ b/arch/arm/mach-s5pv210/Makefile
@@ -35,5 +35,4 @@ obj-$(CONFIG_S5PV210_SETUP_I2C1) += setup-i2c1.o
obj-$(CONFIG_S5PV210_SETUP_I2C2) += setup-i2c2.o
obj-$(CONFIG_S5PV210_SETUP_IDE) += setup-ide.o
obj-$(CONFIG_S5PV210_SETUP_KEYPAD) += setup-keypad.o
-obj-$(CONFIG_S5PV210_SETUP_SDHCI) += setup-sdhci.o
obj-$(CONFIG_S5PV210_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
diff --git a/arch/arm/mach-s5pv210/setup-sdhci.c b/arch/arm/mach-s5pv210/setup-sdhci.c
deleted file mode 100644
index 6b8ccc4..0000000
--- a/arch/arm/mach-s5pv210/setup-sdhci.c
+++ /dev/null
@@ -1,22 +0,0 @@
-/* linux/arch/arm/mach-s5pv210/setup-sdhci.c
- *
- * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * S5PV210 - Helper functions for settign up SDHCI device(s) (HSMMC)
- *
- * 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/types.h>
-
-/* clock sources for the mmc bus clock, order as for the ctrl2[5..4] */
-
-char *s5pv210_hsmmc_clksrcs[4] = {
- [0] = "hsmmc", /* HCLK */
- /* [1] = "hsmmc", - duplicate HCLK entry */
- [2] = "sclk_mmc", /* mmc_bus */
- /* [3] = NULL, - reserved */
-};
diff --git a/arch/arm/plat-samsung/include/plat/sdhci.h b/arch/arm/plat-samsung/include/plat/sdhci.h
index e7b3c75..dcff7dd 100644
--- a/arch/arm/plat-samsung/include/plat/sdhci.h
+++ b/arch/arm/plat-samsung/include/plat/sdhci.h
@@ -66,8 +66,6 @@ struct s3c_sdhci_platdata {
enum cd_types cd_type;
enum clk_types clk_type;
- char **clocks; /* set of clock sources */
-
int ext_cd_gpio;
bool ext_cd_gpio_invert;
int (*ext_cd_init)(void (*notify_func)(struct platform_device *,
@@ -129,12 +127,9 @@ extern void exynos4_setup_sdhci3_cfg_gpio(struct platform_device *, int w);
/* S3C2416 SDHCI setup */
#ifdef CONFIG_S3C2416_SETUP_SDHCI
-extern char *s3c2416_hsmmc_clksrcs[4];
-
static inline void s3c2416_default_sdhci0(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC
- s3c_hsmmc0_def_platdata.clocks = s3c2416_hsmmc_clksrcs;
s3c_hsmmc0_def_platdata.cfg_gpio = s3c2416_setup_sdhci0_cfg_gpio;
#endif /* CONFIG_S3C_DEV_HSMMC */
}
@@ -142,7 +137,6 @@ static inline void s3c2416_default_sdhci0(void)
static inline void s3c2416_default_sdhci1(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC1
- s3c_hsmmc1_def_platdata.clocks = s3c2416_hsmmc_clksrcs;
s3c_hsmmc1_def_platdata.cfg_gpio = s3c2416_setup_sdhci1_cfg_gpio;
#endif /* CONFIG_S3C_DEV_HSMMC1 */
}
@@ -155,12 +149,9 @@ static inline void s3c2416_default_sdhci1(void) { }
/* S3C64XX SDHCI setup */
#ifdef CONFIG_S3C64XX_SETUP_SDHCI
-extern char *s3c64xx_hsmmc_clksrcs[4];
-
static inline void s3c6400_default_sdhci0(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC
- s3c_hsmmc0_def_platdata.clocks = s3c64xx_hsmmc_clksrcs;
s3c_hsmmc0_def_platdata.cfg_gpio = s3c64xx_setup_sdhci0_cfg_gpio;
#endif
}
@@ -168,7 +159,6 @@ static inline void s3c6400_default_sdhci0(void)
static inline void s3c6400_default_sdhci1(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC1
- s3c_hsmmc1_def_platdata.clocks = s3c64xx_hsmmc_clksrcs;
s3c_hsmmc1_def_platdata.cfg_gpio = s3c64xx_setup_sdhci1_cfg_gpio;
#endif
}
@@ -176,7 +166,6 @@ static inline void s3c6400_default_sdhci1(void)
static inline void s3c6400_default_sdhci2(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC2
- s3c_hsmmc2_def_platdata.clocks = s3c64xx_hsmmc_clksrcs;
s3c_hsmmc2_def_platdata.cfg_gpio = s3c64xx_setup_sdhci2_cfg_gpio;
#endif
}
@@ -184,7 +173,6 @@ static inline void s3c6400_default_sdhci2(void)
static inline void s3c6410_default_sdhci0(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC
- s3c_hsmmc0_def_platdata.clocks = s3c64xx_hsmmc_clksrcs;
s3c_hsmmc0_def_platdata.cfg_gpio = s3c64xx_setup_sdhci0_cfg_gpio;
#endif
}
@@ -192,7 +180,6 @@ static inline void s3c6410_default_sdhci0(void)
static inline void s3c6410_default_sdhci1(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC1
- s3c_hsmmc1_def_platdata.clocks = s3c64xx_hsmmc_clksrcs;
s3c_hsmmc1_def_platdata.cfg_gpio = s3c64xx_setup_sdhci1_cfg_gpio;
#endif
}
@@ -200,7 +187,6 @@ static inline void s3c6410_default_sdhci1(void)
static inline void s3c6410_default_sdhci2(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC2
- s3c_hsmmc2_def_platdata.clocks = s3c64xx_hsmmc_clksrcs;
s3c_hsmmc2_def_platdata.cfg_gpio = s3c64xx_setup_sdhci2_cfg_gpio;
#endif
}
@@ -218,12 +204,9 @@ static inline void s3c6400_default_sdhci2(void) { }
/* S5PC100 SDHCI setup */
#ifdef CONFIG_S5PC100_SETUP_SDHCI
-extern char *s5pc100_hsmmc_clksrcs[4];
-
static inline void s5pc100_default_sdhci0(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC
- s3c_hsmmc0_def_platdata.clocks = s5pc100_hsmmc_clksrcs;
s3c_hsmmc0_def_platdata.cfg_gpio = s5pc100_setup_sdhci0_cfg_gpio;
#endif
}
@@ -231,7 +214,6 @@ static inline void s5pc100_default_sdhci0(void)
static inline void s5pc100_default_sdhci1(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC1
- s3c_hsmmc1_def_platdata.clocks = s5pc100_hsmmc_clksrcs;
s3c_hsmmc1_def_platdata.cfg_gpio = s5pc100_setup_sdhci1_cfg_gpio;
#endif
}
@@ -239,7 +221,6 @@ static inline void s5pc100_default_sdhci1(void)
static inline void s5pc100_default_sdhci2(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC2
- s3c_hsmmc2_def_platdata.clocks = s5pc100_hsmmc_clksrcs;
s3c_hsmmc2_def_platdata.cfg_gpio = s5pc100_setup_sdhci2_cfg_gpio;
#endif
}
@@ -254,12 +235,9 @@ static inline void s5pc100_default_sdhci2(void) { }
/* S5PV210 SDHCI setup */
#ifdef CONFIG_S5PV210_SETUP_SDHCI
-extern char *s5pv210_hsmmc_clksrcs[4];
-
static inline void s5pv210_default_sdhci0(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC
- s3c_hsmmc0_def_platdata.clocks = s5pv210_hsmmc_clksrcs;
s3c_hsmmc0_def_platdata.cfg_gpio = s5pv210_setup_sdhci0_cfg_gpio;
#endif
}
@@ -267,7 +245,6 @@ static inline void s5pv210_default_sdhci0(void)
static inline void s5pv210_default_sdhci1(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC1
- s3c_hsmmc1_def_platdata.clocks = s5pv210_hsmmc_clksrcs;
s3c_hsmmc1_def_platdata.cfg_gpio = s5pv210_setup_sdhci1_cfg_gpio;
#endif
}
@@ -275,7 +252,6 @@ static inline void s5pv210_default_sdhci1(void)
static inline void s5pv210_default_sdhci2(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC2
- s3c_hsmmc2_def_platdata.clocks = s5pv210_hsmmc_clksrcs;
s3c_hsmmc2_def_platdata.cfg_gpio = s5pv210_setup_sdhci2_cfg_gpio;
#endif
}
@@ -283,7 +259,6 @@ static inline void s5pv210_default_sdhci2(void)
static inline void s5pv210_default_sdhci3(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC3
- s3c_hsmmc3_def_platdata.clocks = s5pv210_hsmmc_clksrcs;
s3c_hsmmc3_def_platdata.cfg_gpio = s5pv210_setup_sdhci3_cfg_gpio;
#endif
}
@@ -298,12 +273,9 @@ static inline void s5pv210_default_sdhci3(void) { }
/* EXYNOS4 SDHCI setup */
#ifdef CONFIG_EXYNOS4_SETUP_SDHCI
-extern char *exynos4_hsmmc_clksrcs[4];
-
static inline void exynos4_default_sdhci0(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC
- s3c_hsmmc0_def_platdata.clocks = exynos4_hsmmc_clksrcs;
s3c_hsmmc0_def_platdata.cfg_gpio = exynos4_setup_sdhci0_cfg_gpio;
#endif
}
@@ -311,7 +283,6 @@ static inline void exynos4_default_sdhci0(void)
static inline void exynos4_default_sdhci1(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC1
- s3c_hsmmc1_def_platdata.clocks = exynos4_hsmmc_clksrcs;
s3c_hsmmc1_def_platdata.cfg_gpio = exynos4_setup_sdhci1_cfg_gpio;
#endif
}
@@ -319,7 +290,6 @@ static inline void exynos4_default_sdhci1(void)
static inline void exynos4_default_sdhci2(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC2
- s3c_hsmmc2_def_platdata.clocks = exynos4_hsmmc_clksrcs;
s3c_hsmmc2_def_platdata.cfg_gpio = exynos4_setup_sdhci2_cfg_gpio;
#endif
}
@@ -327,7 +297,6 @@ static inline void exynos4_default_sdhci2(void)
static inline void exynos4_default_sdhci3(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC3
- s3c_hsmmc3_def_platdata.clocks = exynos4_hsmmc_clksrcs;
s3c_hsmmc3_def_platdata.cfg_gpio = exynos4_setup_sdhci3_cfg_gpio;
#endif
}
--
1.7.4.4
^ permalink raw reply related
* [PATCH V5 3/3] ARM: SAMSUNG: Add lookup of sdhci-s3c clocks using generic names
From: Rajeshwari Shinde @ 2011-10-13 8:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1318493819-18906-1-git-send-email-rajeshwari.s@samsung.com>
Add support for lookup of sdhci-s3c controller clocks using generic names
for s3c2416, s3c64xx, s5pc100, s5pv210 and exynos4 SoC's.
Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
---
arch/arm/mach-exynos4/clock.c | 88 ++++++++++-------
arch/arm/mach-s3c2416/clock.c | 68 +++++++------
arch/arm/mach-s3c64xx/clock.c | 126 +++++++++++++++----------
arch/arm/mach-s5pc100/clock.c | 130 ++++++++++++++++----------
arch/arm/mach-s5pv210/clock.c | 167 ++++++++++++++++++++-------------
arch/arm/plat-s3c24xx/s3c2443-clock.c | 15 ++-
6 files changed, 359 insertions(+), 235 deletions(-)
diff --git a/arch/arm/mach-exynos4/clock.c b/arch/arm/mach-exynos4/clock.c
index 9f50e33..8bc7534 100644
--- a/arch/arm/mach-exynos4/clock.c
+++ b/arch/arm/mach-exynos4/clock.c
@@ -1157,42 +1157,6 @@ static struct clksrc_clk clksrcs[] = {
.reg_div = { .reg = S5P_CLKDIV_MFC, .shift = 0, .size = 4 },
}, {
.clk = {
- .name = "sclk_mmc",
- .devname = "s3c-sdhci.0",
- .parent = &clk_dout_mmc0.clk,
- .enable = exynos4_clksrc_mask_fsys_ctrl,
- .ctrlbit = (1 << 0),
- },
- .reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 8, .size = 8 },
- }, {
- .clk = {
- .name = "sclk_mmc",
- .devname = "s3c-sdhci.1",
- .parent = &clk_dout_mmc1.clk,
- .enable = exynos4_clksrc_mask_fsys_ctrl,
- .ctrlbit = (1 << 4),
- },
- .reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 24, .size = 8 },
- }, {
- .clk = {
- .name = "sclk_mmc",
- .devname = "s3c-sdhci.2",
- .parent = &clk_dout_mmc2.clk,
- .enable = exynos4_clksrc_mask_fsys_ctrl,
- .ctrlbit = (1 << 8),
- },
- .reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 8, .size = 8 },
- }, {
- .clk = {
- .name = "sclk_mmc",
- .devname = "s3c-sdhci.3",
- .parent = &clk_dout_mmc3.clk,
- .enable = exynos4_clksrc_mask_fsys_ctrl,
- .ctrlbit = (1 << 12),
- },
- .reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 24, .size = 8 },
- }, {
- .clk = {
.name = "sclk_dwmmc",
.parent = &clk_dout_mmc4.clk,
.enable = exynos4_clksrc_mask_fsys_ctrl,
@@ -1250,6 +1214,50 @@ static struct clksrc_clk clk_sclk_uart3 = {
.reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 12, .size = 4 },
};
+static struct clksrc_clk clk_sclk_mmc0 = {
+ .clk = {
+ .name = "sclk_mmc",
+ .devname = "s3c-sdhci.0",
+ .parent = &clk_dout_mmc0.clk,
+ .enable = exynos4_clksrc_mask_fsys_ctrl,
+ .ctrlbit = (1 << 0),
+ },
+ .reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 8, .size = 8 },
+};
+
+static struct clksrc_clk clk_sclk_mmc1 = {
+ .clk = {
+ .name = "sclk_mmc",
+ .devname = "s3c-sdhci.1",
+ .parent = &clk_dout_mmc1.clk,
+ .enable = exynos4_clksrc_mask_fsys_ctrl,
+ .ctrlbit = (1 << 4),
+ },
+ .reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 24, .size = 8 },
+};
+
+static struct clksrc_clk clk_sclk_mmc2 = {
+ .clk = {
+ .name = "sclk_mmc",
+ .devname = "s3c-sdhci.2",
+ .parent = &clk_dout_mmc2.clk,
+ .enable = exynos4_clksrc_mask_fsys_ctrl,
+ .ctrlbit = (1 << 8),
+ },
+ .reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 8, .size = 8 },
+};
+
+static struct clksrc_clk clk_sclk_mmc3 = {
+ .clk = {
+ .name = "sclk_mmc",
+ .devname = "s3c-sdhci.3",
+ .parent = &clk_dout_mmc3.clk,
+ .enable = exynos4_clksrc_mask_fsys_ctrl,
+ .ctrlbit = (1 << 12),
+ },
+ .reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 24, .size = 8 },
+};
+
/* Clock initialization code */
static struct clksrc_clk *sysclks[] = {
&clk_mout_apll,
@@ -1289,6 +1297,10 @@ static struct clksrc_clk *clksrc_cdev[] = {
&clk_sclk_uart1,
&clk_sclk_uart2,
&clk_sclk_uart3,
+ &clk_sclk_mmc0,
+ &clk_sclk_mmc1,
+ &clk_sclk_mmc2,
+ &clk_sclk_mmc3,
};
static struct clk_lookup exynos4_clk_lookup[] = {
@@ -1296,6 +1308,10 @@ static struct clk_lookup exynos4_clk_lookup[] = {
CLKDEV_INIT("exynos4210-uart.1", "clk_uart_baud0", &clk_sclk_uart1.clk),
CLKDEV_INIT("exynos4210-uart.2", "clk_uart_baud0", &clk_sclk_uart2.clk),
CLKDEV_INIT("exynos4210-uart.3", "clk_uart_baud0", &clk_sclk_uart3.clk),
+ CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &clk_sclk_mmc0.clk),
+ CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &clk_sclk_mmc1.clk),
+ CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.2", &clk_sclk_mmc2.clk),
+ CLKDEV_INIT("s3c-sdhci.3", "mmc_busclk.2", &clk_sclk_mmc3.clk),
};
static int xtal_rate;
diff --git a/arch/arm/mach-s3c2416/clock.c b/arch/arm/mach-s3c2416/clock.c
index 72b7c62..6ece510 100644
--- a/arch/arm/mach-s3c2416/clock.c
+++ b/arch/arm/mach-s3c2416/clock.c
@@ -82,39 +82,38 @@ static struct clksrc_clk hsmmc_div[] = {
},
};
-static struct clksrc_clk hsmmc_mux[] = {
- [0] = {
- .clk = {
- .name = "hsmmc-if",
- .devname = "s3c-sdhci.0",
- .ctrlbit = (1 << 6),
- .enable = s3c2443_clkcon_enable_s,
- },
- .sources = &(struct clksrc_sources) {
- .nr_sources = 2,
- .sources = (struct clk *[]) {
- [0] = &hsmmc_div[0].clk,
- [1] = NULL, /* to fix */
- },
- },
- .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 16 },
+static struct clksrc_clk hsmmc_mux0 = {
+ .clk = {
+ .name = "hsmmc-if",
+ .devname = "s3c-sdhci.0",
+ .ctrlbit = (1 << 6),
+ .enable = s3c2443_clkcon_enable_s,
},
- [1] = {
- .clk = {
- .name = "hsmmc-if",
- .devname = "s3c-sdhci.1",
- .ctrlbit = (1 << 12),
- .enable = s3c2443_clkcon_enable_s,
+ .sources = &(struct clksrc_sources) {
+ .nr_sources = 2,
+ .sources = (struct clk * []) {
+ [0] = &hsmmc_div[0].clk,
+ [1] = NULL, /* to fix */
},
- .sources = &(struct clksrc_sources) {
- .nr_sources = 2,
- .sources = (struct clk *[]) {
- [0] = &hsmmc_div[1].clk,
- [1] = NULL, /* to fix */
- },
+ },
+ .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 16 },
+};
+
+static struct clksrc_clk hsmmc_mux1 = {
+ .clk = {
+ .name = "hsmmc-if",
+ .devname = "s3c-sdhci.1",
+ .ctrlbit = (1 << 12),
+ .enable = s3c2443_clkcon_enable_s,
+ },
+ .sources = &(struct clksrc_sources) {
+ .nr_sources = 2,
+ .sources = (struct clk * []) {
+ [0] = &hsmmc_div[1].clk,
+ [1] = NULL, /* to fix */
},
- .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 17 },
},
+ .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 17 },
};
static struct clk hsmmc0_clk = {
@@ -143,8 +142,14 @@ static struct clksrc_clk *clksrcs[] __initdata = {
&hsspi_mux,
&hsmmc_div[0],
&hsmmc_div[1],
- &hsmmc_mux[0],
- &hsmmc_mux[1],
+ &hsmmc_mux0,
+ &hsmmc_mux1,
+};
+
+static struct clk_lookup s3c2416_clk_lookup[] = {
+ CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.0", &hsmmc0_clk),
+ CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &hsmmc_mux0.clk),
+ CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &hsmmc_mux1.clk),
};
void __init s3c2416_init_clocks(int xtal)
@@ -164,6 +169,7 @@ void __init s3c2416_init_clocks(int xtal)
s3c_register_clksrc(clksrcs[ptr], 1);
s3c24xx_register_clock(&hsmmc0_clk);
+ clkdev_add_table(s3c2416_clk_lookup, ARRAY_SIZE(s3c2416_clk_lookup));
s3c_pwmclk_init();
diff --git a/arch/arm/mach-s3c64xx/clock.c b/arch/arm/mach-s3c64xx/clock.c
index 2addd98..415c540 100644
--- a/arch/arm/mach-s3c64xx/clock.c
+++ b/arch/arm/mach-s3c64xx/clock.c
@@ -243,24 +243,6 @@ static struct clk init_clocks[] = {
.enable = s3c64xx_hclk_ctrl,
.ctrlbit = S3C_CLKCON_HCLK_UHOST,
}, {
- .name = "hsmmc",
- .devname = "s3c-sdhci.0",
- .parent = &clk_h,
- .enable = s3c64xx_hclk_ctrl,
- .ctrlbit = S3C_CLKCON_HCLK_HSMMC0,
- }, {
- .name = "hsmmc",
- .devname = "s3c-sdhci.1",
- .parent = &clk_h,
- .enable = s3c64xx_hclk_ctrl,
- .ctrlbit = S3C_CLKCON_HCLK_HSMMC1,
- }, {
- .name = "hsmmc",
- .devname = "s3c-sdhci.2",
- .parent = &clk_h,
- .enable = s3c64xx_hclk_ctrl,
- .ctrlbit = S3C_CLKCON_HCLK_HSMMC2,
- }, {
.name = "otg",
.parent = &clk_h,
.enable = s3c64xx_hclk_ctrl,
@@ -310,6 +292,29 @@ static struct clk init_clocks[] = {
}
};
+static struct clk clk_hsmmc0 = {
+ .name = "hsmmc",
+ .devname = "s3c-sdhci.0",
+ .parent = &clk_h,
+ .enable = s3c64xx_hclk_ctrl,
+ .ctrlbit = S3C_CLKCON_HCLK_HSMMC0,
+};
+
+static struct clk clk_hsmmc1 = {
+ .name = "hsmmc",
+ .devname = "s3c-sdhci.1",
+ .parent = &clk_h,
+ .enable = s3c64xx_hclk_ctrl,
+ .ctrlbit = S3C_CLKCON_HCLK_HSMMC1,
+};
+
+static struct clk clk_hsmmc2 = {
+ .name = "hsmmc",
+ .devname = "s3c-sdhci.2",
+ .parent = &clk_h,
+ .enable = s3c64xx_hclk_ctrl,
+ .ctrlbit = S3C_CLKCON_HCLK_HSMMC2,
+};
static struct clk clk_fout_apll = {
.name = "fout_apll",
@@ -578,36 +583,6 @@ static struct clksrc_sources clkset_camif = {
static struct clksrc_clk clksrcs[] = {
{
.clk = {
- .name = "mmc_bus",
- .devname = "s3c-sdhci.0",
- .ctrlbit = S3C_CLKCON_SCLK_MMC0,
- .enable = s3c64xx_sclk_ctrl,
- },
- .reg_src = { .reg = S3C_CLK_SRC, .shift = 18, .size = 2 },
- .reg_div = { .reg = S3C_CLK_DIV1, .shift = 0, .size = 4 },
- .sources = &clkset_spi_mmc,
- }, {
- .clk = {
- .name = "mmc_bus",
- .devname = "s3c-sdhci.1",
- .ctrlbit = S3C_CLKCON_SCLK_MMC1,
- .enable = s3c64xx_sclk_ctrl,
- },
- .reg_src = { .reg = S3C_CLK_SRC, .shift = 20, .size = 2 },
- .reg_div = { .reg = S3C_CLK_DIV1, .shift = 4, .size = 4 },
- .sources = &clkset_spi_mmc,
- }, {
- .clk = {
- .name = "mmc_bus",
- .devname = "s3c-sdhci.2",
- .ctrlbit = S3C_CLKCON_SCLK_MMC2,
- .enable = s3c64xx_sclk_ctrl,
- },
- .reg_src = { .reg = S3C_CLK_SRC, .shift = 22, .size = 2 },
- .reg_div = { .reg = S3C_CLK_DIV1, .shift = 8, .size = 4 },
- .sources = &clkset_spi_mmc,
- }, {
- .clk = {
.name = "usb-bus-host",
.ctrlbit = S3C_CLKCON_SCLK_UHOST,
.enable = s3c64xx_sclk_ctrl,
@@ -697,6 +672,42 @@ static struct clksrc_clk clk_sclk_uclk = {
.sources = &clkset_uart,
};
+static struct clksrc_clk clk_sclk_mmc0 = {
+ .clk = {
+ .name = "mmc_bus",
+ .devname = "s3c-sdhci.0",
+ .ctrlbit = S3C_CLKCON_SCLK_MMC0,
+ .enable = s3c64xx_sclk_ctrl,
+ },
+ .reg_src = { .reg = S3C_CLK_SRC, .shift = 18, .size = 2 },
+ .reg_div = { .reg = S3C_CLK_DIV1, .shift = 0, .size = 4 },
+ .sources = &clkset_spi_mmc,
+};
+
+static struct clksrc_clk clk_sclk_mmc1 = {
+ .clk = {
+ .name = "mmc_bus",
+ .devname = "s3c-sdhci.1",
+ .ctrlbit = S3C_CLKCON_SCLK_MMC1,
+ .enable = s3c64xx_sclk_ctrl,
+ },
+ .reg_src = { .reg = S3C_CLK_SRC, .shift = 20, .size = 2 },
+ .reg_div = { .reg = S3C_CLK_DIV1, .shift = 4, .size = 4 },
+ .sources = &clkset_spi_mmc,
+};
+
+static struct clksrc_clk clk_sclk_mmc2 = {
+ .clk = {
+ .name = "mmc_bus",
+ .devname = "s3c-sdhci.2",
+ .ctrlbit = S3C_CLKCON_SCLK_MMC2,
+ .enable = s3c64xx_sclk_ctrl,
+ },
+ .reg_src = { .reg = S3C_CLK_SRC, .shift = 22, .size = 2 },
+ .reg_div = { .reg = S3C_CLK_DIV1, .shift = 8, .size = 4 },
+ .sources = &clkset_spi_mmc,
+};
+
/* Clock initialisation code */
static struct clksrc_clk *init_parents[] = {
@@ -707,11 +718,26 @@ static struct clksrc_clk *init_parents[] = {
static struct clksrc_clk *clksrc_cdev[] = {
&clk_sclk_uclk,
+ &clk_sclk_mmc0,
+ &clk_sclk_mmc1,
+ &clk_sclk_mmc2,
+};
+
+static struct clk *clk_cdev[] = {
+ &clk_hsmmc0,
+ &clk_hsmmc1,
+ &clk_hsmmc2,
};
static struct clk_lookup s3c64xx_clk_lookup[] = {
CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p),
CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_sclk_uclk.clk),
+ CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.0", &clk_hsmmc0),
+ CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.0", &clk_hsmmc1),
+ CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.0", &clk_hsmmc2),
+ CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &clk_sclk_mmc0.clk),
+ CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &clk_sclk_mmc1.clk),
+ CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.2", &clk_sclk_mmc2.clk),
};
#define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
@@ -834,6 +860,10 @@ void __init s3c64xx_register_clocks(unsigned long xtal,
s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
+ s3c24xx_register_clocks(clk_cdev, ARRAY_SIZE(clk_cdev));
+ for (cnt = 0; cnt < ARRAY_SIZE(clk_cdev); cnt++)
+ s3c_disable_clocks(clk_cdev[cnt], 1);
+
s3c24xx_register_clocks(clks1, ARRAY_SIZE(clks1));
s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
for (cnt = 0; cnt < ARRAY_SIZE(clksrc_cdev); cnt++)
diff --git a/arch/arm/mach-s5pc100/clock.c b/arch/arm/mach-s5pc100/clock.c
index 9d644ec..69829ba 100644
--- a/arch/arm/mach-s5pc100/clock.c
+++ b/arch/arm/mach-s5pc100/clock.c
@@ -426,24 +426,6 @@ static struct clk init_clocks_off[] = {
.enable = s5pc100_d0_2_ctrl,
.ctrlbit = (1 << 1),
}, {
- .name = "hsmmc",
- .devname = "s3c-sdhci.2",
- .parent = &clk_div_d1_bus.clk,
- .enable = s5pc100_d1_0_ctrl,
- .ctrlbit = (1 << 7),
- }, {
- .name = "hsmmc",
- .devname = "s3c-sdhci.1",
- .parent = &clk_div_d1_bus.clk,
- .enable = s5pc100_d1_0_ctrl,
- .ctrlbit = (1 << 6),
- }, {
- .name = "hsmmc",
- .devname = "s3c-sdhci.0",
- .parent = &clk_div_d1_bus.clk,
- .enable = s5pc100_d1_0_ctrl,
- .ctrlbit = (1 << 5),
- }, {
.name = "modemif",
.parent = &clk_div_d1_bus.clk,
.enable = s5pc100_d1_0_ctrl,
@@ -711,6 +693,30 @@ static struct clk init_clocks_off[] = {
},
};
+static struct clk clk_hsmmc2 = {
+ .name = "hsmmc",
+ .devname = "s3c-sdhci.2",
+ .parent = &clk_div_d1_bus.clk,
+ .enable = s5pc100_d1_0_ctrl,
+ .ctrlbit = (1 << 7),
+};
+
+static struct clk clk_hsmmc1 = {
+ .name = "hsmmc",
+ .devname = "s3c-sdhci.1",
+ .parent = &clk_div_d1_bus.clk,
+ .enable = s5pc100_d1_0_ctrl,
+ .ctrlbit = (1 << 6),
+};
+
+static struct clk clk_hsmmc0 = {
+ .name = "hsmmc",
+ .devname = "s3c-sdhci.0",
+ .parent = &clk_div_d1_bus.clk,
+ .enable = s5pc100_d1_0_ctrl,
+ .ctrlbit = (1 << 5),
+};
+
static struct clk clk_vclk54m = {
.name = "vclk_54m",
.rate = 54000000,
@@ -1014,39 +1020,6 @@ static struct clksrc_clk clksrcs[] = {
.reg_div = { .reg = S5P_CLK_DIV3, .shift = 24, .size = 4 },
}, {
.clk = {
- .name = "sclk_mmc",
- .devname = "s3c-sdhci.0",
- .ctrlbit = (1 << 12),
- .enable = s5pc100_sclk1_ctrl,
-
- },
- .sources = &clk_src_mmc0,
- .reg_src = { .reg = S5P_CLK_SRC2, .shift = 0, .size = 2 },
- .reg_div = { .reg = S5P_CLK_DIV3, .shift = 0, .size = 4 },
- }, {
- .clk = {
- .name = "sclk_mmc",
- .devname = "s3c-sdhci.1",
- .ctrlbit = (1 << 13),
- .enable = s5pc100_sclk1_ctrl,
-
- },
- .sources = &clk_src_mmc12,
- .reg_src = { .reg = S5P_CLK_SRC2, .shift = 4, .size = 2 },
- .reg_div = { .reg = S5P_CLK_DIV3, .shift = 4, .size = 4 },
- }, {
- .clk = {
- .name = "sclk_mmc",
- .devname = "s3c-sdhci.2",
- .ctrlbit = (1 << 14),
- .enable = s5pc100_sclk1_ctrl,
-
- },
- .sources = &clk_src_mmc12,
- .reg_src = { .reg = S5P_CLK_SRC2, .shift = 8, .size = 2 },
- .reg_div = { .reg = S5P_CLK_DIV3, .shift = 8, .size = 4 },
- }, {
- .clk = {
.name = "sclk_irda",
.ctrlbit = (1 << 10),
.enable = s5pc100_sclk0_ctrl,
@@ -1099,6 +1072,42 @@ static struct clksrc_clk clk_sclk_uart = {
.reg_div = { .reg = S5P_CLK_DIV2, .shift = 0, .size = 4 },
};
+static struct clksrc_clk clk_sclk_mmc0 = {
+ .clk = {
+ .name = "sclk_mmc",
+ .devname = "s3c-sdhci.0",
+ .ctrlbit = (1 << 12),
+ .enable = s5pc100_sclk1_ctrl,
+ },
+ .sources = &clk_src_mmc0,
+ .reg_src = { .reg = S5P_CLK_SRC2, .shift = 0, .size = 2 },
+ .reg_div = { .reg = S5P_CLK_DIV3, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk clk_sclk_mmc1 = {
+ .clk = {
+ .name = "sclk_mmc",
+ .devname = "s3c-sdhci.1",
+ .ctrlbit = (1 << 13),
+ .enable = s5pc100_sclk1_ctrl,
+ },
+ .sources = &clk_src_mmc12,
+ .reg_src = { .reg = S5P_CLK_SRC2, .shift = 4, .size = 2 },
+ .reg_div = { .reg = S5P_CLK_DIV3, .shift = 4, .size = 4 },
+};
+
+static struct clksrc_clk clk_sclk_mmc2 = {
+ .clk = {
+ .name = "sclk_mmc",
+ .devname = "s3c-sdhci.2",
+ .ctrlbit = (1 << 14),
+ .enable = s5pc100_sclk1_ctrl,
+ },
+ .sources = &clk_src_mmc12,
+ .reg_src = { .reg = S5P_CLK_SRC2, .shift = 8, .size = 2 },
+ .reg_div = { .reg = S5P_CLK_DIV3, .shift = 8, .size = 4 },
+};
+
/* Clock initialisation code */
static struct clksrc_clk *sysclks[] = {
&clk_mout_apll,
@@ -1128,8 +1137,17 @@ static struct clksrc_clk *sysclks[] = {
&clk_sclk_spdif,
};
+static struct clk *clk_cdev[] = {
+ &clk_hsmmc0,
+ &clk_hsmmc1,
+ &clk_hsmmc2,
+};
+
static struct clksrc_clk *clksrc_cdev[] = {
&clk_sclk_uart,
+ &clk_sclk_mmc0,
+ &clk_sclk_mmc1,
+ &clk_sclk_mmc2,
};
void __init_or_cpufreq s5pc100_setup_clocks(void)
@@ -1274,6 +1292,12 @@ static struct clk *clks[] __initdata = {
static struct clk_lookup s5pc100_clk_lookup[] = {
CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p),
CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_sclk_uart.clk),
+ CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.0", &clk_hsmmc0),
+ CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.0", &clk_hsmmc1),
+ CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.0", &clk_hsmmc2),
+ CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &clk_sclk_mmc0.clk),
+ CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &clk_sclk_mmc1.clk),
+ CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.2", &clk_sclk_mmc2.clk),
};
void __init s5pc100_register_clocks(void)
@@ -1294,6 +1318,10 @@ void __init s5pc100_register_clocks(void)
s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
clkdev_add_table(s5pc100_clk_lookup, ARRAY_SIZE(s5pc100_clk_lookup));
+ s3c24xx_register_clocks(clk_cdev, ARRAY_SIZE(clk_cdev));
+ for (ptr = 0; ptr < ARRAY_SIZE(clk_cdev); ptr++)
+ s3c_disable_clocks(clk_cdev[ptr], 1);
+
s3c24xx_register_clock(&dummy_apb_pclk);
s3c_pwmclk_init();
diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c
index 43a045d..dc4586b 100644
--- a/arch/arm/mach-s5pv210/clock.c
+++ b/arch/arm/mach-s5pv210/clock.c
@@ -399,30 +399,6 @@ static struct clk init_clocks_off[] = {
.enable = s5pv210_clk_ip1_ctrl,
.ctrlbit = (1<<25),
}, {
- .name = "hsmmc",
- .devname = "s3c-sdhci.0",
- .parent = &clk_hclk_psys.clk,
- .enable = s5pv210_clk_ip2_ctrl,
- .ctrlbit = (1<<16),
- }, {
- .name = "hsmmc",
- .devname = "s3c-sdhci.1",
- .parent = &clk_hclk_psys.clk,
- .enable = s5pv210_clk_ip2_ctrl,
- .ctrlbit = (1<<17),
- }, {
- .name = "hsmmc",
- .devname = "s3c-sdhci.2",
- .parent = &clk_hclk_psys.clk,
- .enable = s5pv210_clk_ip2_ctrl,
- .ctrlbit = (1<<18),
- }, {
- .name = "hsmmc",
- .devname = "s3c-sdhci.3",
- .parent = &clk_hclk_psys.clk,
- .enable = s5pv210_clk_ip2_ctrl,
- .ctrlbit = (1<<19),
- }, {
.name = "systimer",
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
@@ -559,6 +535,38 @@ static struct clk init_clocks[] = {
},
};
+static struct clk clk_hsmmc0 = {
+ .name = "hsmmc",
+ .devname = "s3c-sdhci.0",
+ .parent = &clk_hclk_psys.clk,
+ .enable = s5pv210_clk_ip2_ctrl,
+ .ctrlbit = (1<<16),
+};
+
+static struct clk clk_hsmmc1 = {
+ .name = "hsmmc",
+ .devname = "s3c-sdhci.1",
+ .parent = &clk_hclk_psys.clk,
+ .enable = s5pv210_clk_ip2_ctrl,
+ .ctrlbit = (1<<17),
+};
+
+static struct clk clk_hsmmc2 = {
+ .name = "hsmmc",
+ .devname = "s3c-sdhci.2",
+ .parent = &clk_hclk_psys.clk,
+ .enable = s5pv210_clk_ip2_ctrl,
+ .ctrlbit = (1<<18),
+};
+
+static struct clk clk_hsmmc3 = {
+ .name = "hsmmc",
+ .devname = "s3c-sdhci.3",
+ .parent = &clk_hclk_psys.clk,
+ .enable = s5pv210_clk_ip2_ctrl,
+ .ctrlbit = (1<<19),
+};
+
static struct clk *clkset_uart_list[] = {
[6] = &clk_mout_mpll.clk,
[7] = &clk_mout_epll.clk,
@@ -866,46 +874,6 @@ static struct clksrc_clk clksrcs[] = {
.reg_div = { .reg = S5P_CLK_DIV1, .shift = 20, .size = 4 },
}, {
.clk = {
- .name = "sclk_mmc",
- .devname = "s3c-sdhci.0",
- .enable = s5pv210_clk_mask0_ctrl,
- .ctrlbit = (1 << 8),
- },
- .sources = &clkset_group2,
- .reg_src = { .reg = S5P_CLK_SRC4, .shift = 0, .size = 4 },
- .reg_div = { .reg = S5P_CLK_DIV4, .shift = 0, .size = 4 },
- }, {
- .clk = {
- .name = "sclk_mmc",
- .devname = "s3c-sdhci.1",
- .enable = s5pv210_clk_mask0_ctrl,
- .ctrlbit = (1 << 9),
- },
- .sources = &clkset_group2,
- .reg_src = { .reg = S5P_CLK_SRC4, .shift = 4, .size = 4 },
- .reg_div = { .reg = S5P_CLK_DIV4, .shift = 4, .size = 4 },
- }, {
- .clk = {
- .name = "sclk_mmc",
- .devname = "s3c-sdhci.2",
- .enable = s5pv210_clk_mask0_ctrl,
- .ctrlbit = (1 << 10),
- },
- .sources = &clkset_group2,
- .reg_src = { .reg = S5P_CLK_SRC4, .shift = 8, .size = 4 },
- .reg_div = { .reg = S5P_CLK_DIV4, .shift = 8, .size = 4 },
- }, {
- .clk = {
- .name = "sclk_mmc",
- .devname = "s3c-sdhci.3",
- .enable = s5pv210_clk_mask0_ctrl,
- .ctrlbit = (1 << 11),
- },
- .sources = &clkset_group2,
- .reg_src = { .reg = S5P_CLK_SRC4, .shift = 12, .size = 4 },
- .reg_div = { .reg = S5P_CLK_DIV4, .shift = 12, .size = 4 },
- }, {
- .clk = {
.name = "sclk_mfc",
.devname = "s5p-mfc",
.enable = s5pv210_clk_ip0_ctrl,
@@ -1030,11 +998,70 @@ static struct clksrc_clk clk_sclk_uart3 = {
.reg_div = { .reg = S5P_CLK_DIV4, .shift = 28, .size = 4 },
};
+static struct clksrc_clk clk_sclk_mmc0 = {
+ .clk = {
+ .name = "sclk_mmc",
+ .devname = "s3c-sdhci.0",
+ .enable = s5pv210_clk_mask0_ctrl,
+ .ctrlbit = (1 << 8),
+ },
+ .sources = &clkset_group2,
+ .reg_src = { .reg = S5P_CLK_SRC4, .shift = 0, .size = 4 },
+ .reg_div = { .reg = S5P_CLK_DIV4, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk clk_sclk_mmc1 = {
+ .clk = {
+ .name = "sclk_mmc",
+ .devname = "s3c-sdhci.1",
+ .enable = s5pv210_clk_mask0_ctrl,
+ .ctrlbit = (1 << 9),
+ },
+ .sources = &clkset_group2,
+ .reg_src = { .reg = S5P_CLK_SRC4, .shift = 4, .size = 4 },
+ .reg_div = { .reg = S5P_CLK_DIV4, .shift = 4, .size = 4 },
+};
+
+static struct clksrc_clk clk_sclk_mmc2 = {
+ .clk = {
+ .name = "sclk_mmc",
+ .devname = "s3c-sdhci.2",
+ .enable = s5pv210_clk_mask0_ctrl,
+ .ctrlbit = (1 << 10),
+ },
+ .sources = &clkset_group2,
+ .reg_src = { .reg = S5P_CLK_SRC4, .shift = 8, .size = 4 },
+ .reg_div = { .reg = S5P_CLK_DIV4, .shift = 8, .size = 4 },
+};
+
+static struct clksrc_clk clk_sclk_mmc3 = {
+ .clk = {
+ .name = "sclk_mmc",
+ .devname = "s3c-sdhci.3",
+ .enable = s5pv210_clk_mask0_ctrl,
+ .ctrlbit = (1 << 11),
+ },
+ .sources = &clkset_group2,
+ .reg_src = { .reg = S5P_CLK_SRC4, .shift = 12, .size = 4 },
+ .reg_div = { .reg = S5P_CLK_DIV4, .shift = 12, .size = 4 },
+};
+
static struct clksrc_clk *clksrc_cdev[] = {
&clk_sclk_uart0,
&clk_sclk_uart1,
&clk_sclk_uart2,
&clk_sclk_uart3,
+ &clk_sclk_mmc0,
+ &clk_sclk_mmc1,
+ &clk_sclk_mmc2,
+ &clk_sclk_mmc3,
+};
+
+static struct clk *clk_cdev[] = {
+ &clk_hsmmc0,
+ &clk_hsmmc1,
+ &clk_hsmmc2,
+ &clk_hsmmc3,
};
/* Clock initialisation code */
@@ -1282,6 +1309,14 @@ static struct clk_lookup s5pv210_clk_lookup[] = {
CLKDEV_INIT("s5pv210-uart.1", "clk_uart_baud1", &clk_sclk_uart1.clk),
CLKDEV_INIT("s5pv210-uart.2", "clk_uart_baud1", &clk_sclk_uart2.clk),
CLKDEV_INIT("s5pv210-uart.3", "clk_uart_baud1", &clk_sclk_uart3.clk),
+ CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.0", &clk_hsmmc0),
+ CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.0", &clk_hsmmc1),
+ CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.0", &clk_hsmmc2),
+ CLKDEV_INIT("s3c-sdhci.3", "mmc_busclk.0", &clk_hsmmc3),
+ CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &clk_sclk_mmc0.clk),
+ CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &clk_sclk_mmc1.clk),
+ CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.2", &clk_sclk_mmc2.clk),
+ CLKDEV_INIT("s3c-sdhci.3", "mmc_busclk.2", &clk_sclk_mmc3.clk),
};
void __init s5pv210_register_clocks(void)
@@ -1306,6 +1341,10 @@ void __init s5pv210_register_clocks(void)
s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
clkdev_add_table(s5pv210_clk_lookup, ARRAY_SIZE(s5pv210_clk_lookup));
+ s3c24xx_register_clocks(clk_cdev, ARRAY_SIZE(clk_cdev));
+ for (ptr = 0; ptr < ARRAY_SIZE(clk_cdev); ptr++)
+ s3c_disable_clocks(clk_cdev[ptr], 1);
+
s3c24xx_register_clock(&dummy_apb_pclk);
s3c_pwmclk_init();
}
diff --git a/arch/arm/plat-s3c24xx/s3c2443-clock.c b/arch/arm/plat-s3c24xx/s3c2443-clock.c
index 4a24e15..2a2a255 100644
--- a/arch/arm/plat-s3c24xx/s3c2443-clock.c
+++ b/arch/arm/plat-s3c24xx/s3c2443-clock.c
@@ -309,11 +309,6 @@ static struct clk init_clocks[] = {
.enable = s3c2443_clkcon_enable_h,
.ctrlbit = S3C2443_HCLKCON_DMA5,
}, {
- .name = "hsmmc",
- .parent = &clk_h,
- .enable = s3c2443_clkcon_enable_h,
- .ctrlbit = S3C2443_HCLKCON_HSMMC,
- }, {
.name = "gpio",
.parent = &clk_p,
.enable = s3c2443_clkcon_enable_p,
@@ -395,6 +390,14 @@ static struct clk init_clocks[] = {
}
};
+static struct clk hsmmc1_clk = {
+ .name = "hsmmc",
+ .devname = "s3c-sdhci.1",
+ .parent = &clk_h,
+ .enable = s3c2443_clkcon_enable_h,
+ .ctrlbit = S3C2443_HCLKCON_HSMMC,
+};
+
static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
{
clkcon0 &= S3C2443_CLKDIV0_HCLKDIV_MASK;
@@ -460,6 +463,7 @@ static struct clk *clks[] __initdata = {
&clk_ext,
&clk_epll,
&clk_usb_bus,
+ &hsmmc1_clk,
};
static struct clksrc_clk *clksrcs[] __initdata = {
@@ -475,6 +479,7 @@ static struct clk_lookup s3c2443_clk_lookup[] = {
CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk),
CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p),
CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_esys_uart.clk),
+ CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.0", &hsmmc1_clk),
};
void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll,
--
1.7.4.4
^ permalink raw reply related
* [GIT PULL] DEBUG_LL platform updates for 3.2
From: Russell King - ARM Linux @ 2011-10-13 8:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.LFD.2.02.1110111950290.17040@xanadu.home>
On Tue, Oct 11, 2011 at 08:03:38PM -0400, Nicolas Pitre wrote:
> On Tue, 11 Oct 2011, Arnd Bergmann wrote:
>
> > I've stuck them into the arm-soc tree for now, so we get linux-next
> > coverage, but I won't send them to Linus this way because then we
> > would get the same commits twice in the history.
>
> Could you please do the same with the following:
>
> git://git.linaro.org/people/nico/linux.git mach_memory_h
>
> Russell pulled it at some point, and dropped it due to concerns about
> repeated conflict resolutions (or so I presume). I just did a test
> merge between your for-next branch and the above and that looked trivial
> enough.
_and_ the breakage of the ZBOOT_ROM stuff.
So I'm now interpreting your request to Arnd to pull it as an attempt to
bypass me. That's not what arm-soc is supposed to be about, and that's
certainly not what Linaro is supposed to be doing.
If that's how you want to behave, I'm disgusted, and be prepared for your
work to become a lot harder in the future.
^ permalink raw reply
* [GIT PULL] DEBUG_LL platform updates for 3.2
From: Russell King - ARM Linux @ 2011-10-13 8:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1837446.fiK2eIOO53@wuerfel>
On Wed, Oct 12, 2011 at 10:30:11AM +0200, Arnd Bergmann wrote:
> On Tuesday 11 October 2011 20:03:38 Nicolas Pitre wrote:
> > On Tue, 11 Oct 2011, Arnd Bergmann wrote:
> >
> > > I've stuck them into the arm-soc tree for now, so we get linux-next
> > > coverage, but I won't send them to Linus this way because then we
> > > would get the same commits twice in the history.
> >
> > Could you please do the same with the following:
> >
> > git://git.linaro.org/people/nico/linux.git mach_memory_h
> >
> > Russell pulled it at some point, and dropped it due to concerns about
> > repeated conflict resolutions (or so I presume). I just did a test
> > merge between your for-next branch and the above and that looked trivial
> > enough.
>
> Ok, done.
Bypassing maintainers stinks - especially when there are unaddressed
comments outstanding. Nicolas has "simplified" my objections in this
request for you to pull - and has completely ignored the problem that
it breaks ZBOOT_ROM by deleting the zreladdr definitions on EP93xx
with no way for that to be provided.
Moreover, it forces EP93xx to always use AUTO_ZRELADDR, but you can
still select ZBOOT_ROM, which is an invalid combination.
Not only that, I'm carrying a patch from Sascha which detects the
multiple-zreladdr problem and prevents building such kernels and this
conflicts with that patch.
So I'm not pulling Nicolas' mach_memory_h branch until he comes to his
senses. I had pointed this out but got a rather stroppy replies in
return.
^ permalink raw reply
* [PATCH] [RFC PATCH] ARM: kprobes: Make breakpoint setting/clearing SMP safe
From: Tixy @ 2011-10-13 8:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1318491642.2265.36.camel@computer2>
On Thu, 2011-10-13 at 08:40 +0100, Tixy wrote:
> On Wed, 2011-10-12 at 22:03 +0530, Rabin Vincent wrote:
> > On Tue, Jul 12, 2011 at 18:10, Tixy <tixy@yxit.co.uk> wrote:
> > > Both these issues are known and the kprobe implementation uses
> > > stop_machine() to avoid them, however, this is not sufficient.
> > > stop_machine() does not perform any kind on synchronisation between CPUs
> > > so it it still possible for one CPU to call the breakpoint changing
> > > function before another CPU has been interrupted to do likewise.
> > >
> > > To fix this problem, this patch creates a new function
> > > sync_stop_machine() which ensures that all online CPUs execute the
> > > specified function at the same time.
> >
> > AFAICS stop_machine() already does what you want. When you use
> > stop_machine(), the actual call to your function is done (on each
> > CPU's stopper thread) using the stop_machine_cpu_stop() function,
> > which already has the synchronization between CPUs which you're
> > trying to do here.
>
> The only serialisation I can see is the wait_for_completion() in
> __stop_cpus() which waits for the all CPUs to have executed the
> requested function. I don't see anything which prevents one CPU from
> starting (and finishing) the requested function before other CPU's are
> ready for it. If this synchronisation existed it would have to be in
> cpu_stopper_thread() as it pulls tasks off the work list.
>
> In queue_stop_cpus_work() we have
>
> for_each_cpu(cpu, cpumask)
> cpu_stop_queue_work(&per_cpu(cpu_stopper, cpu),
> &per_cpu(stop_cpus_work, cpu));
>
> If the CPU executing this gets delayed by an ISR on each iteration of
> the for_each_cpu loop then the work it queues for one CPU could have
> completed before it gets around to queuing it for the next CPU.
>
What I said above is wrong because I didn't see the whole picture.
queue_stop_cpus_work() isn't queueing the work we specify, it is used to
queue stop_machine_cpu_stop() on all running CPUs. This function then
synchronises all cores before executing our function with IRQs off.
Therefore, as Rabin said, the problem with kprobes I thought existed,
doesn't.
--
Tixy
^ permalink raw reply
* [PATCHv2] ARM: zImage: Use $(CROSS_COMPILE)size to get .bss size
From: Russell King - ARM Linux @ 2011-10-13 8:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1318488622-20023-1-git-send-email-weber@corscience.de>
On Thu, Oct 13, 2011 at 08:50:22AM +0200, Thomas Weber wrote:
> Use $(CROSS_COMPILE)size to determine the bss size
> from vmlinux.
>
> The problem is introduced in:
>
> commit 5ffb04f6690d71fab241b3562ebf52b893ac4ff1
> ARM: zImage: make sure appended DTB doesn't get
> overwritten by kernel .bss
>
> This fixes following error message:
>
> size: arch/arm/boot/compressed/../../../../vmlinux:
> File format is ambiguous
>
> size: Matching formats:
> elf32-littlearm
> elf32-littlearm-symbian
> elf32-littlearm-vxworks
>
> Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
> Acked-by: Tony Lindgren <tony@atomide.com>
> Signed-off-by: Thomas Weber <weber@corscience.de>
This is going to totally break my ability to build any kernels at the
moment - for some reason I don't have an arm-linux-size with all the
other bits of binutils, so I've been relying on the x86 version so far.
I'll add it to the list of things to look at...
^ permalink raw reply
* change_page_attr() implementation for ARM?
From: Russell King - ARM Linux @ 2011-10-13 8:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <401E54CE964CD94BAE1EB4A729C7087E3722519EE2@HQMAIL04.nvidia.com>
On Wed, Oct 12, 2011 at 07:27:58PM -0700, Krishna Reddy wrote:
> Catalin,
> >The kernel linear mapping is done using sections, so we would have to
> >change the attributes for a full section. Russell's approach I think
> >is better but people reported some stability issues.
>
> X86 way breaks the sections into pages and it only changes the attributes
> for the requested pages. the other pages of section would have same prot
> attributes as section.
And doing that is the problem - you have multiple page tables to manipulate,
which in a SMP world could be in-use on different CPUs. When you alter
such a page table, you will have a race between the CPU walking the
page tables and your update of that table.
Not only that but you will have to send a TLB flush to the other CPUs for
that address, and that requires an interruptible context. There are
contexts which memory is allocated for DMA where that's not possible
(because IRQs are disabled by the caller.)
> does Russell's approach refer to a different way?
> Is there any link on how Russell wants to do it?
I had a patch which pre-allocates memory for the DMA allocators, but I
had to drop it because it caused regressions on platforms which had
very limited DMA memory available - it caused such platforms to panic
at boot.
So, this is proving to be an extremely difficult problem to solve -
and I've been wishing for quite a long time that ARM Ltd would get
their act together and realize that the combination of restrictions
(DMA incoherence plus not permitting aliases) is Very Bad News.
So, I'm hoping that there's an increasing chorus of voices trying to
persuade a move towards data-cache DMA coherence as standard.
^ permalink raw reply
* change_page_attr() implementation for ARM?
From: Catalin Marinas @ 2011-10-13 8:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <401E54CE964CD94BAE1EB4A729C7087E3722519EE2@HQMAIL04.nvidia.com>
On Thu, Oct 13, 2011 at 03:27:58AM +0100, Krishna Reddy wrote:
> >> On Cortex-A9, we have observed stale data being read from
> >> write-combine (C=0 B=1) memory regions mapped into userspace which
> >> have a duplicate cacheable mapping in the kernel address space (due
> >> to the kernel linear mapping).
> >>
> >> The issue appears to be due to speculative prefetch on the
> >> cacheable kernel linear mapping which gets lines into the L2 cache.
> >> When reads are performed on the write-combine mapping for this
> >> address range, these reads get the stale data from L2 instead of
> >> memory.
>
> >If your system has a PL310, there is bit 22 in the auxiliary control
> >register which makes reads via the non-cacheable mapping not to hit
> >the L2 cache. I had this patch queued in Russell's system for a long
> >time:
> >http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=6529/1
> >Alternatively, you can pass this bit via your platform code.
>
> Is this is a quick fix for ARM processors with PL310. Can this be
> expected in future versions of ARM processors with different L2 cache?
That's specific to the PL310 cache controller, nothing to do with the
CPU. It's a configuration bit that may be useful in some scenarios.
--
Catalin
^ permalink raw reply
* [PATCH V4 3/3] ARM: SAMSUNG: Add lookup of sdhci-s3c clocks using generic names
From: Russell King - ARM Linux @ 2011-10-13 8:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4E969958.9020200@samsung.com>
On Thu, Oct 13, 2011 at 09:55:04AM +0200, Sylwester Nawrocki wrote:
> Yes, it allowed to add clkdev support with minimal changes required.
>
> But let's see what happens when the works on common struct clk for all
> architectures are more or less completed and we convert Samsung platforms
> to use it;)
The common struct clk shouldn't have much to do with the clkdev part of
it - clkdev just provides a method to associate a struct clk with the
drivers request. The common struct clk doesn't change that.
^ permalink raw reply
* change_page_attr() implementation for ARM?
From: Catalin Marinas @ 2011-10-13 8:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111013084947.GI21648@n2100.arm.linux.org.uk>
On 13 October 2011 09:49, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Wed, Oct 12, 2011 at 07:27:58PM -0700, Krishna Reddy wrote:
>> >The kernel linear mapping is done using sections, so we would have to
>> >change the attributes for a full section. Russell's approach I think
>> >is better but people reported some stability issues.
...
>> does Russell's approach refer to a different way?
>> Is there any link on how Russell wants to do it?
>
> I had a patch which pre-allocates memory for the DMA allocators, but I
> had to drop it because it caused regressions on platforms which had
> very limited DMA memory available - it caused such platforms to panic
> at boot.
>
> So, this is proving to be an extremely difficult problem to solve -
> and I've been wishing for quite a long time that ARM Ltd would get
> their act together and realize that the combination of restrictions
> (DMA incoherence plus not permitting aliases) is Very Bad News.
>
> So, I'm hoping that there's an increasing chorus of voices trying to
> persuade a move towards data-cache DMA coherence as standard.
I mentioned the mismatched aliases clarification on several occasions,
though in private emails as the ARM ARM revC is not public yet. IIRC I
even sent a short document to a few people including you. Is that
clarification not enough (I can send it again if you want)?
Basically with Normal Non-cacheable DMA buffers (but not Strongly
Ordered) we are ok as long as the caches are cleaned on the other
Normal Cacheable mapping. Of course, you get different behaviour with
PL310 if you don't set bit 22 but that's a documented bit and not some
undocumented errata workaround (maybe this bit should have been 1 by
default).
--
Catalin
^ permalink raw reply
* [PATCH 1/2] [ARM] mach-types: Re-add apf9328
From: Uwe Kleine-König @ 2011-10-13 9:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111008220722.GG25689@n2100.arm.linux.org.uk>
On Sat, Oct 08, 2011 at 11:07:22PM +0100, Russell King - ARM Linux wrote:
> On Sat, Oct 08, 2011 at 09:26:21PM +0200, Wolfram Sang wrote:
> > On Sat, Oct 08, 2011 at 05:19:48PM +0200, Gwenhael Goavec-Merou wrote:
> > >
> > > Signed-off-by: Gwenhael Goavec-Merou <gwenhael.goavec-merou@armadeus.com>
> >
> > I think this file is maintained by Russell, yet I want to ack that the entry
> > below is missing for building mx1_defconfig. Found that, too.
>
> The thing is - read the comments at the top of the file. There's hints
> there as to what will happen if you patch the file. The hint is
> 'automatically generated'. So when I next update the file, any patches
> done to the file will be wiped out.
Currently the id is still missing in your for-next branch and it is
marked as "mainlined" on http://www.arm.linux.org.uk/developer/machines/
(906).
That means that the next update should include the id, right? Maybe it's
worth to add it already earlier with the patch Gwenhael proposed as
without it mx1_defconfig is broken. After f32609c5a035 it even breaks
imx_v4_v5_defconfig.
BTW is there a way to see the mach-types file as it would land in
linux.git if it were updated now?
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply
* [PATCH] ARM: kprobes: only patch instructions on one CPU
From: Tixy @ 2011-10-13 9:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1318492515.2265.51.camel@computer2>
On Thu, 2011-10-13 at 08:55 +0100, Tixy wrote:
> On Wed, 2011-10-12 at 21:42 +0530, Rabin Vincent wrote:
> > The text patching needs to be done only once, instead of once on
> each
> > CPU. The other CPUs will busy wait inside the stop machine code
> until
> > the patching is done.
>
> Where in the stop machine code do the other CPU's busy wait?
>
> How I read the code is that __stop_cpus() calls queue_stop_cpus_work()
> which queues the work on each of the specified CPU's work list and
> wakes
> that CPU's stopper thread to process it. __stop_cpus() then calls
> wait_for_completion() to wait for these CPUs to finish the work.
>
> I don't see how the execution path of CPUs not specified in cpumask is
> interrupted in any way.
>
As I said in my reply to the other mail, I had missed the fact that it
is stop_machine_cpu_stop() which is used to call our function, and this
synchronises all cores. Therefore, this patch is correct, assuming that
a flush_icache_range executed on one core also flushes I-caches on other
cores. (I'm a bit doubtfull of this as I beleive that at least
ARM11MPCore requires this to be managed in software and I can't find any
code that handles this.)
--
Tixy
>
> >
> > Cc: Jon Medhurst <tixy@yxit.co.uk>
> > Cc: Nicolas Pitre <nicolas.pitre@linaro.org>
> > Signed-off-by: Rabin Vincent <rabin@rab.in>
> > ---
> > arch/arm/kernel/kprobes.c | 4 ++--
> > 1 files changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c
> > index 129c116..e9f95300 100644
> > --- a/arch/arm/kernel/kprobes.c
> > +++ b/arch/arm/kernel/kprobes.c
> > @@ -127,7 +127,7 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)
> > flush_insns(addr, sizeof(u16));
> > } else if (addr & 2) {
> > /* A 32-bit instruction spanning two words needs
> special care */
> > - stop_machine(set_t32_breakpoint, (void *)addr,
> &cpu_online_map);
> > + stop_machine(set_t32_breakpoint, (void *)addr, NULL);
> > } else {
> > /* Word aligned 32-bit instruction can be written
> atomically */
> > u32 bkp = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION;
> > @@ -190,7 +190,7 @@ int __kprobes __arch_disarm_kprobe(void *p)
> >
> > void __kprobes arch_disarm_kprobe(struct kprobe *p)
> > {
> > - stop_machine(__arch_disarm_kprobe, p, &cpu_online_map);
> > + stop_machine(__arch_disarm_kprobe, p, NULL);
> > }
> >
> > void __kprobes arch_remove_kprobe(struct kprobe *p)
>
>
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox