* [PATCHv13 00/40] ARM: TI SoC clock DT conversion
From: Mike Turquette @ 2014-01-15 3:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140115031632.4167.2698@quantum>
Quoting Mike Turquette (2014-01-14 19:16:32)
> Quoting Felipe Balbi (2014-01-14 18:04:21)
> > Hi,
> >
> > On Tue, Jan 14, 2014 at 02:36:13PM -0600, Felipe Balbi wrote:
> > > > Felipe, care to run your randconfig magic for this?
> > >
> > > This branch builds just fine so far, I still have omap5 multiplaform and
> > > uniplatform builds, but since that was working before i'm assuming it
> > > won't break.
> >
> > No build failures in any of my 18 seeds (5 randconfigs of each), I'd
> > attach logs, but it's a 2.8MiB tarball, if anyone cares enough, I can
> > send it.
> >
> > FWIW:
> >
> > Acked-by: Felipe Balbi <balbi@ti.com>
>
> Felipe,
>
> That's great to hear. Thanks for testing.
>
> Tero & Tony,
>
> These 40 patches apply very cleanly on top of clk-next with 2
> exceptions:
>
> 1) I did not apply "[PATCH 30/42] ARM: dts: AM35xx: use DT clock data"
> because I do not have arch/arm/boot/dts/am3517.dtsi in clk-next (based
> on 3.13-rc1).
>
> 2) Minor merge conflict in arch/arm/boot/dts/omap3.dtsi which I think I
> resolved correctly but would like verification.
>
> I'd prefer to simply merge these patches into clk-next, which is the
> most straightforward route. Any ideas on how to handle the missing
> AM35xx dtsi data? It can always go as a separate fix after this stuff
> gets merged which, ironically, is how that file was created in the first
> place.
I've pushed my branch. Tero can you take a look and let me know if you
see any problems?
git://git.linaro.org/people/mike.turquette/linux.git clk-next-omap
Thanks!
Mike
>
> Regards,
> Mike
>
> >
> > cheers
> >
> > --
> > balbi
^ permalink raw reply
* [PATCH 1/2] clk: hisilicon: add hi3620_mmc_clks
From: Mike Turquette @ 2014-01-15 3:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <52D5E709.7040105@linaro.org>
Quoting zhangfei (2014-01-14 17:40:25)
> Dear Mike
>
> On 01/15/2014 04:17 AM, Mike Turquette wrote:
> > Quoting Zhangfei Gao (2014-01-13 01:14:28)
> >> Suggest by Arnd: abstract mmc tuning as clock behavior,
> >> also because different soc have different tuning method and registers.
> >> hi3620_mmc_clks is added to handle mmc clock specifically on hi3620.
> >>
> >> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
> >> Acked-by: Arnd Bergmann <arnd@arndb.de>
> >> Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
> >
> > Patch looks good to me with one exception. I do not have
> > Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt in the
> > clk-next branch. Is there a stable branch I can pull in as a dependency?
>
> Mach-hisi just have been uploaeded.
> Have tried next-20140114, the patch can be applied successfully.
> While v3.13-rc8 still can not.
>
> Is this fine?
Can you give me a link to the branch that introduces
Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt?
I guess the patch introducing it is going through arm-soc. Is this going
in for 3.14? If so then perhaps the clk tree and the arm-soc tree can
share a stable branch that introduces it.
Regards,
Mike
>
> Thanks
^ permalink raw reply
* [GIT PULL] clk: socfpga: Clean-ups for 3.14
From: Mike Turquette @ 2014-01-15 4:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1389029246-27434-1-git-send-email-dinguyen@altera.com>
Quoting dinguyen at altera.com (2014-01-06 09:27:26)
> Hi Mike,
>
> Please pull in these patches that cleans up the SOCFPGA clock driver. This is
> V2 of the pull request that includes 4 patches from Steffen Trumtrar.
>
> Thanks,
>
> Dinh
>
> The following changes since commit 6ce4eac1f600b34f2f7f58f9cd8f0503d79e42ae:
>
> Linux 3.13-rc1 (2013-11-22 11:30:55 -0800)
>
> are available in the git repository at:
>
> git://git.rocketboards.org/linux-socfpga-next.git tags/socfpga-clk-for-3.14_v2
>
> for you to fetch changes up to d5387681665e58bafc1a9c745182f03aab0579c3:
>
> clk: socfpga: split clk code (2014-01-06 11:22:22 -0600)
>
> ----------------------------------------------------------------
> v2: SOCFPGA clk cleanups for 3.14
>
> ----------------------------------------------------------------
> Dinh Nguyen (3):
> clk: socfpga: Map the clk manager base address in the clock driver
> clk: socfpga: Look for the GPIO_DB_CLK by its offset
Hi Dinh,
Patch "clk: socfpga: Look for the GPIO_DB_CLK by its offset" still
causes a compilation error. I know it gets fixed by "clk: socfpga: fix
compile error" later on but this still breaks git bisect.
Can you please fold the fixes into the patches that introduce the bugs?
No need to keep them separate since they are all part of the same pull
request.
Regards,
Mike
> clk: socfpga: Remove socfpga_init_clocks
>
> Steffen Trumtrar (4):
> clk: socfpga: remove unused field
> clk: socfpga: fix define typo
> clk: socfpga: fix compile error
> clk: socfpga: split clk code
>
> arch/arm/mach-socfpga/socfpga.c | 5 -
> drivers/clk/socfpga/Makefile | 3 +
> drivers/clk/socfpga/clk-gate.c | 223 ++++++++++++++++++++++++++
> drivers/clk/socfpga/clk-periph.c | 94 +++++++++++
> drivers/clk/socfpga/clk-pll.c | 111 +++++++++++++
> drivers/clk/socfpga/clk.c | 328 ++------------------------------------
> drivers/clk/socfpga/clk.h | 57 +++++++
> 7 files changed, 500 insertions(+), 321 deletions(-)
> create mode 100644 drivers/clk/socfpga/clk-gate.c
> create mode 100644 drivers/clk/socfpga/clk-periph.c
> create mode 100644 drivers/clk/socfpga/clk-pll.c
> create mode 100644 drivers/clk/socfpga/clk.h
>
^ permalink raw reply
* AArch64 kernel image decompression
From: Olof Johansson @ 2014-01-15 4:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140114185302.0B0813821F2@gemini.denx.de>
Hi,
On Tue, Jan 14, 2014 at 10:53 AM, Wolfgang Denk <wd@denx.de> wrote:
> Dear Olof,
>
> In message <CAOesGMj0HPWD=Mavt1ut+Oze4KQZHjhHmcKTcdKELaF=Or8XsA@mail.gmail.com> you wrote:
>>
>> > The FIT image approach as suggested by Marek also allows for secure
>> > boot methods (like cryptographically signed images); this is used in
>> > production for several systems, including the Google Chromebook.
>>
>> This can very easily be misunderstood so I would like to clarify:
>> Chromebooks do not use the fitImage version of signatures and
>> verification, it is done independently from a separate library that
>> wraps either a zImage (x86) or a fitImage (ARM).
>
> This is not what I'm talking about. What I mean is the support for
> Verified Boot (see [1]) and FIT Signature Verification (see [2]) which
> is done with plain FIT images, without additional wrapping.
>
> [1] http://git.denx.de/?p=u-boot.git;a=blob;f=doc/uImage.FIT/verified-boot.txt
> [2] http://git.denx.de/?p=u-boot.git;a=blob;f=doc/uImage.FIT/signature.txt
The incorrect part of your statement was the claim that it was used
for secure boot on ARM Chromebooks. It is not -- the u-boot
implementation is completely different from what is used there.
-Olof
^ permalink raw reply
* [PATCH 1/3] mmc: dw_mmc: use slot-gpio to handle cd pin
From: zhangfei @ 2014-01-15 5:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <52D5DFB5.7@linaro.org>
Dear Kevin
On 01/15/2014 09:09 AM, zhangfei wrote:
>
>
> On 01/15/2014 01:23 AM, Olof Johansson wrote:
>> On Tue, Jan 14, 2014 at 7:58 AM, Kevin Hilman <khilman@linaro.org> wrote:
>>> On Thu, Jan 9, 2014 at 6:35 AM, Zhangfei Gao
>>> <zhangfei.gao@linaro.org> wrote:
>>>> Suggested by Jaehoon: Use slot-gpio to handle cd-gpio
>>>> Add function dw_mci_of_get_cd_gpio to check "cd-gpios" from dts.
>>>> mmc_gpio_request_cd and mmc_gpio_get_cd are used to handle cd pin
>>>>
>>>> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
>>>> Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
>>>
>>> The Samsung Arndale board started failing boot from MMC root tests
>>> starting with next-20140113 and I bisected it down to this patch.
>>> Reverting this patch on top of next-20140114 gets Arndale booting
>>> again from MMC. Is there some supporting DT data that's missing for
>>> Arndale?
>>
>> Rather, it looks like this patch changes behaviour and no longer uses
>> dw_mci_get_cd() to find out if there's a card attached -- it switches
>> to rely only on GPIO (see the last chunk in the patch). That seems
>> broken?
>>
> Oops,
> Change using dw_mci_get_cd set flag DW_MMC_CARD_PRESENT.
> And dw_mci_get_cd is called from mmc_rescan, a litter later than
> dw_mci_probe.
> Is that too late?
Should have found the issue, CDETECT is ignored since IS_ERR_VALUE does
not workable to !mmc_gpio_get_cd(mmc), which used for adding debounce.
Sorry for that.
However, with this change the debounce seems not stable as before.
In the test of plug-in-out, sometimes sd detect will return timeout
although present indicates as 1, while next time it can be detected again.
Still want to check more.
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index a776f24f4311..f1683ba194ee 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1033,7 +1033,7 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
int present;
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci_board *brd = slot->host->pdata;
- int gpio_cd = !mmc_gpio_get_cd(mmc);
+ int gpio_cd = mmc_gpio_get_cd(mmc);
/* Use platform get_cd function, else try onboard card detect */
if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
@@ -1041,7 +1041,7 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
else if (brd->get_cd)
present = !brd->get_cd(slot->id);
else if (!IS_ERR_VALUE(gpio_cd))
- present = !!gpio_cd;
+ present = !gpio_cd;
else
present = (mci_readl(slot->host, CDETECT) & (1 <<
slot->id))
== 0 ? 1 : 0;
^ permalink raw reply related
* [PATCH v3 1/2] ARM: dts: vf610: lpuart: Add eDMA support
From: Yuan Yao @ 2014-01-15 5:21 UTC (permalink / raw)
To: linux-arm-kernel
Add lpuart dts node properties for eDMA support, them depend on the eDMA driver.
See VF610_EDMA_MUXID0_UART*_*X macro on eDMA driver
Signed-off-by: Yuan Yao <yao.yuan@freescale.com>
---
arch/arm/boot/dts/vf610.dtsi | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/vf610.dtsi b/arch/arm/boot/dts/vf610.dtsi
index 365e0fa..ed6b053 100644
--- a/arch/arm/boot/dts/vf610.dtsi
+++ b/arch/arm/boot/dts/vf610.dtsi
@@ -118,6 +118,9 @@
interrupts = <0 61 0x00>;
clocks = <&clks VF610_CLK_UART0>;
clock-names = "ipg";
+ dma-names = "lpuart-tx","lpuart-rx";
+ dmas = <&edma0 0 VF610_EDMA_MUXID0_UART0_TX>,
+ <&edma0 0 VF610_EDMA_MUXID0_UART0_RX>;
status = "disabled";
};
@@ -127,6 +130,9 @@
interrupts = <0 62 0x04>;
clocks = <&clks VF610_CLK_UART1>;
clock-names = "ipg";
+ dma-names = "lpuart-tx","lpuart-rx";
+ dmas = <&edma0 0 VF610_EDMA_MUXID0_UART1_TX>,
+ <&edma0 0 VF610_EDMA_MUXID0_UART1_RX>;
status = "disabled";
};
@@ -136,6 +142,9 @@
interrupts = <0 63 0x04>;
clocks = <&clks VF610_CLK_UART2>;
clock-names = "ipg";
+ dma-names = "lpuart-tx","lpuart-rx";
+ dmas = <&edma0 0 VF610_EDMA_MUXID0_UART2_TX>,
+ <&edma0 0 VF610_EDMA_MUXID0_UART2_RX>;
status = "disabled";
};
@@ -145,6 +154,9 @@
interrupts = <0 64 0x04>;
clocks = <&clks VF610_CLK_UART3>;
clock-names = "ipg";
+ dma-names = "lpuart-tx","lpuart-rx";
+ dmas = <&edma0 0 VF610_EDMA_MUXID0_UART3_TX>,
+ <&edma0 0 VF610_EDMA_MUXID0_UART3_RX>;
status = "disabled";
};
--
1.8.4
^ permalink raw reply related
* [PATCH v3 2/2] serial: fsl_lpuart: add DMA support
From: Yuan Yao @ 2014-01-15 5:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1389763265-27300-2-git-send-email-yao.yuan@freescale.com>
Add dma support for lpuart. This function depend on DMA driver.
You can turn on it by SERIAL_FSL_LPUART_DMA=y. And It works if dts node has dma properties.
Signed-off-by: Yuan Yao <yao.yuan@freescale.com>
---
.../devicetree/bindings/serial/fsl-lpuart.txt | 21 +-
drivers/tty/serial/Kconfig | 7 +
drivers/tty/serial/fsl_lpuart.c | 457 ++++++++++++++++++++-
3 files changed, 473 insertions(+), 12 deletions(-)
diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
index 6fd1dd1..7509080 100644
--- a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
+++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
@@ -4,11 +4,24 @@ Required properties:
- compatible : Should be "fsl,<soc>-lpuart"
- reg : Address and length of the register set for the device
- interrupts : Should contain uart interrupt
+- clocks : from common clock binding: handle to uart clock
+- clock-names : from common clock binding: Shall be "ipg"
+
+Optional properties:
+- dma-names: Should contain "lpuart-tx" for transmit and "lpuart-rx" for receive channels
+- dmas: Should contain dma specifiers for transmit and receive channels
+
+Note: Optional properties for DMA support, If need this properties is must.
Example:
uart0: serial at 40027000 {
- compatible = "fsl,vf610-lpuart";
- reg = <0x40027000 0x1000>;
- interrupts = <0 61 0x00>;
- };
+ compatible = "fsl,vf610-lpuart";
+ reg = <0x40027000 0x1000>;
+ interrupts = <0 61 0x00>;
+ clocks = <&clks VF610_CLK_UART0>;
+ clock-names = "ipg";
+ dma-names = "lpuart-tx","lpuart-rx";
+ dmas = <&edma0 0 VF610_EDMA_MUXID0_UART0_TX>,
+ <&edma0 0 VF610_EDMA_MUXID0_UART0_RX>;
+ };
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index a3817ab..ab3910b 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1509,6 +1509,13 @@ config SERIAL_FSL_LPUART_CONSOLE
If you have enabled the lpuart serial port on the Freescale SoCs,
you can make it the console by answering Y to this option.
+config SERIAL_FSL_LPUART_DMA
+ bool "Freescale lpuart serial port dma support"
+ depends on FSL_EDMA=y && SERIAL_FSL_LPUART=y
+ help
+ DMA support for the on-chip lpuart on some Freescale SOCs,
+ you can turn on the dma support for lpuart by answering Y to this option.
+
config SERIAL_ST_ASC
tristate "ST ASC serial port support"
select SERIAL_CORE
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 67b8946..5fdcb18 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -13,14 +13,19 @@
#define SUPPORT_SYSRQ
#endif
-#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/dmapool.h>
#include <linux/io.h>
#include <linux/irq.h>
-#include <linux/clk.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/console.h>
+#include <linux/of_dma.h>
#include <linux/serial_core.h>
+#include <linux/slab.h>
#include <linux/tty_flip.h>
/* All registers are 8-bit width */
@@ -112,6 +117,12 @@
#define UARTSFIFO_TXOF 0x02
#define UARTSFIFO_RXUF 0x01
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+#define DMA_MAXBURST 16
+#define DMA_MAXBURST_MASK (DMA_MAXBURST - 1)
+#define FSL_UART_RX_DMA_BUFFER_SIZE 64
+#endif
+
#define DRIVER_NAME "fsl-lpuart"
#define DEV_NAME "ttyLP"
#define UART_NR 6
@@ -121,6 +132,26 @@ struct lpuart_port {
struct clk *clk;
unsigned int txfifo_size;
unsigned int rxfifo_size;
+
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+ bool lpuart_dma_use;
+ struct dma_chan *dma_tx_chan;
+ struct dma_chan *dma_rx_chan;
+ struct dma_async_tx_descriptor *dma_tx_desc;
+ struct dma_async_tx_descriptor *dma_rx_desc;
+ dma_addr_t dma_tx_buf_bus;
+ dma_addr_t dma_rx_buf_bus;
+ dma_cookie_t dma_tx_cookie;
+ dma_cookie_t dma_rx_cookie;
+ unsigned char *dma_tx_buf_virt;
+ unsigned char *dma_rx_buf_virt;
+ unsigned int dma_tx_bytes;
+ unsigned int dma_rx_bytes;
+ int dma_tx_in_progress;
+ int dma_rx_in_progress;
+ unsigned int dma_rx_timeout;
+ struct timer_list lpuart_timer;
+#endif
};
static struct of_device_id lpuart_dt_ids[] = {
@@ -131,6 +162,12 @@ static struct of_device_id lpuart_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+/* Forward declare this for the dma callbacks*/
+static void lpuart_dma_tx_complete(void *arg);
+static void lpuart_dma_rx_complete(void *arg);
+#endif
+
static void lpuart_stop_tx(struct uart_port *port)
{
unsigned char temp;
@@ -152,6 +189,212 @@ static void lpuart_enable_ms(struct uart_port *port)
{
}
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+static void lpuart_copy_rx_to_tty(struct lpuart_port *sport,
+ struct tty_port *tty, int count)
+{
+ int copied;
+
+ sport->port.icount.rx += count;
+
+ if (!tty) {
+ dev_err(sport->port.dev, "No tty port\n");
+ return;
+ }
+
+ dma_sync_single_for_cpu(sport->port.dev, sport->dma_rx_buf_bus,
+ FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+ copied = tty_insert_flip_string(tty,
+ ((unsigned char *)(sport->dma_rx_buf_virt)), count);
+
+ if (copied != count) {
+ WARN_ON(1);
+ dev_err(sport->port.dev, "RxData copy to tty layer failed\n");
+ }
+
+ dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus,
+ FSL_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE);
+}
+
+static void lpuart_pio_tx(struct lpuart_port *sport)
+{
+ struct circ_buf *xmit = &sport->port.state->xmit;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ while (!uart_circ_empty(xmit) &&
+ readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size) {
+ writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ sport->port.icount.tx++;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&sport->port);
+
+ if (uart_circ_empty(xmit))
+ writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS,
+ sport->port.membase + UARTCR5);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static int lpuart_dma_tx(struct lpuart_port *sport, unsigned long count)
+{
+ struct circ_buf *xmit = &sport->port.state->xmit;
+ dma_addr_t tx_bus_addr;
+
+ dma_sync_single_for_device(sport->port.dev, sport->dma_tx_buf_bus,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
+ sport->dma_tx_bytes = count & ~(DMA_MAXBURST_MASK);
+ tx_bus_addr = sport->dma_tx_buf_bus + xmit->tail;
+ sport->dma_tx_desc = dmaengine_prep_slave_single(sport->dma_tx_chan,
+ tx_bus_addr, sport->dma_tx_bytes,
+ DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
+
+ if (!sport->dma_tx_desc) {
+ dev_err(sport->port.dev, "Not able to get desc for tx\n");
+ return -EIO;
+ }
+
+ sport->dma_tx_desc->callback = lpuart_dma_tx_complete;
+ sport->dma_tx_desc->callback_param = sport;
+ sport->dma_tx_in_progress = 1;
+ sport->dma_tx_cookie = dmaengine_submit(sport->dma_tx_desc);
+ dma_async_issue_pending(sport->dma_tx_chan);
+
+ return 0;
+}
+
+static void lpuart_prepare_tx(struct lpuart_port *sport)
+{
+ struct circ_buf *xmit = &sport->port.state->xmit;
+ unsigned long count = CIRC_CNT_TO_END(xmit->head,
+ xmit->tail, UART_XMIT_SIZE);
+
+ if (!count)
+ return;
+
+ if (count < DMA_MAXBURST)
+ writeb(readb(sport->port.membase + UARTCR5) & ~UARTCR5_TDMAS,
+ sport->port.membase + UARTCR5);
+ else {
+ writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS,
+ sport->port.membase + UARTCR5);
+ lpuart_dma_tx(sport, count);
+ }
+}
+
+static void lpuart_dma_tx_complete(void *arg)
+{
+ struct lpuart_port *sport = arg;
+ struct circ_buf *xmit = &sport->port.state->xmit;
+ unsigned long flags;
+
+ async_tx_ack(sport->dma_tx_desc);
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ xmit->tail = (xmit->tail + sport->dma_tx_bytes) & (UART_XMIT_SIZE - 1);
+ sport->dma_tx_in_progress = 0;
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&sport->port);
+
+ lpuart_prepare_tx(sport);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static int lpuart_dma_rx(struct lpuart_port *sport)
+{
+ dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus,
+ FSL_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE);
+ sport->dma_rx_desc = dmaengine_prep_slave_single(sport->dma_rx_chan,
+ sport->dma_rx_buf_bus, FSL_UART_RX_DMA_BUFFER_SIZE,
+ DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
+
+ if (!sport->dma_rx_desc) {
+ dev_err(sport->port.dev, "Not able to get desc for rx\n");
+ return -EIO;
+ }
+
+ sport->dma_rx_desc->callback = lpuart_dma_rx_complete;
+ sport->dma_rx_desc->callback_param = sport;
+ sport->dma_rx_in_progress = 1;
+ sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc);
+ dma_async_issue_pending(sport->dma_rx_chan);
+
+ return 0;
+}
+
+static void lpuart_dma_rx_complete(void *arg)
+{
+ struct lpuart_port *sport = arg;
+ struct tty_port *port = &sport->port.state->port;
+ unsigned long flags;
+
+ async_tx_ack(sport->dma_rx_desc);
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ sport->dma_rx_in_progress = 0;
+ lpuart_copy_rx_to_tty(sport, port, FSL_UART_RX_DMA_BUFFER_SIZE);
+ tty_flip_buffer_push(port);
+ lpuart_dma_rx(sport);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static void lpuart_timer_func(unsigned long data)
+{
+ struct lpuart_port *sport = (struct lpuart_port *)data;
+ struct tty_port *port = &sport->port.state->port;
+ struct dma_tx_state state;
+ unsigned long flags;
+ unsigned char temp;
+ int count;
+
+ del_timer(&sport->lpuart_timer);
+ dmaengine_pause(sport->dma_rx_chan);
+ dmaengine_tx_status(sport->dma_rx_chan, sport->dma_rx_cookie, &state);
+ dmaengine_terminate_all(sport->dma_rx_chan);
+ count = FSL_UART_RX_DMA_BUFFER_SIZE - state.residue;
+ async_tx_ack(sport->dma_rx_desc);
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ sport->dma_rx_in_progress = 0;
+ lpuart_copy_rx_to_tty(sport, port, count);
+ tty_flip_buffer_push(port);
+ temp = readb(sport->port.membase + UARTCR5);
+ writeb(temp & ~UARTCR5_RDMAS, sport->port.membase + UARTCR5);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static inline void lpuart_prepare_rx(struct lpuart_port *sport)
+{
+ unsigned long flags;
+ unsigned char temp;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ init_timer(&sport->lpuart_timer);
+ sport->lpuart_timer.function = lpuart_timer_func;
+ sport->lpuart_timer.data = (unsigned long)sport;
+ sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
+ add_timer(&sport->lpuart_timer);
+
+ lpuart_dma_rx(sport);
+ temp = readb(sport->port.membase + UARTCR5);
+ writeb(temp | UARTCR5_RDMAS, sport->port.membase + UARTCR5);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+#endif
+
static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
{
struct circ_buf *xmit = &sport->port.state->xmit;
@@ -172,14 +415,26 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
static void lpuart_start_tx(struct uart_port *port)
{
- struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
+ struct lpuart_port *sport = container_of(port,
+ struct lpuart_port, port);
+ struct circ_buf *xmit = &sport->port.state->xmit;
unsigned char temp;
temp = readb(port->membase + UARTCR2);
writeb(temp | UARTCR2_TIE, port->membase + UARTCR2);
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+ if (sport->lpuart_dma_use) {
+ if (!uart_circ_empty(xmit) && !sport->dma_tx_in_progress)
+ lpuart_prepare_tx(sport);
+ } else {
+ if (readb(port->membase + UARTSR1) & UARTSR1_TDRE)
+ lpuart_transmit_buffer(sport);
+ }
+#else
if (readb(port->membase + UARTSR1) & UARTSR1_TDRE)
lpuart_transmit_buffer(sport);
+#endif
}
static irqreturn_t lpuart_txint(int irq, void *dev_id)
@@ -279,12 +534,27 @@ static irqreturn_t lpuart_int(int irq, void *dev_id)
sts = readb(sport->port.membase + UARTSR1);
- if (sts & UARTSR1_RDRF)
+ if (sts & UARTSR1_RDRF) {
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+ if (sport->lpuart_dma_use)
+ lpuart_prepare_rx(sport);
+ else
+ lpuart_rxint(irq, dev_id);
+#else
lpuart_rxint(irq, dev_id);
-
+#endif
+ }
if (sts & UARTSR1_TDRE &&
- !(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS))
+ !(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS)) {
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+ if (sport->lpuart_dma_use)
+ lpuart_pio_tx(sport);
+ else
+ lpuart_txint(irq, dev_id);
+#else
lpuart_txint(irq, dev_id);
+#endif
+ }
return IRQ_HANDLED;
}
@@ -366,19 +636,179 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH,
sport->port.membase + UARTCFIFO);
- writeb(2, sport->port.membase + UARTTWFIFO);
+ writeb(0, sport->port.membase + UARTTWFIFO);
writeb(1, sport->port.membase + UARTRWFIFO);
/* Restore cr2 */
writeb(cr2_saved, sport->port.membase + UARTCR2);
}
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+static int lpuart_dma_tx_request(struct uart_port *port)
+{
+ struct lpuart_port *sport = container_of(port,
+ struct lpuart_port, port);
+ struct dma_chan *tx_chan;
+ struct dma_slave_config dma_tx_sconfig;
+ dma_addr_t dma_bus;
+ unsigned char *dma_buf;
+ int ret;
+
+ tx_chan = dma_request_slave_channel(sport->port.dev, "lpuart-tx");
+
+ if (!tx_chan) {
+ dev_err(sport->port.dev, "Dma tx channel request failed!\n");
+ return -ENODEV;
+ }
+
+ dma_bus = dma_map_single(tx_chan->device->dev,
+ sport->port.state->xmit.buf,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
+
+ if (dma_mapping_error(tx_chan->device->dev, dma_bus)) {
+ dev_err(sport->port.dev, "dma_map_single tx failed\n");
+ dma_release_channel(tx_chan);
+ return -ENOMEM;
+ }
+
+ dma_buf = sport->port.state->xmit.buf;
+ dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR;
+ dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_tx_sconfig.dst_maxburst = DMA_MAXBURST;
+ dma_tx_sconfig.direction = DMA_MEM_TO_DEV;
+ ret = dmaengine_slave_config(tx_chan, &dma_tx_sconfig);
+
+ if (ret < 0) {
+ dev_err(sport->port.dev,
+ "Dma slave config failed, err = %d\n", ret);
+ dma_release_channel(tx_chan);
+ return ret;
+ }
+
+ sport->dma_tx_chan = tx_chan;
+ sport->dma_tx_buf_virt = dma_buf;
+ sport->dma_tx_buf_bus = dma_bus;
+ sport->dma_tx_in_progress = 0;
+
+ return 0;
+}
+
+static int lpuart_dma_rx_request(struct uart_port *port)
+{
+ struct lpuart_port *sport = container_of(port,
+ struct lpuart_port, port);
+ struct dma_chan *rx_chan;
+ struct dma_slave_config dma_rx_sconfig;
+ dma_addr_t dma_bus;
+ unsigned char *dma_buf;
+ int ret;
+
+ rx_chan = dma_request_slave_channel(sport->port.dev, "lpuart-rx");
+
+ if (!rx_chan) {
+ dev_err(sport->port.dev, "Dma rx channel request failed!\n");
+ return -ENODEV;
+ }
+
+ dma_buf = devm_kzalloc(sport->port.dev,
+ FSL_UART_RX_DMA_BUFFER_SIZE, GFP_KERNEL);
+
+ if (!dma_buf) {
+ dev_err(sport->port.dev, "Dma rx alloc failed\n");
+ dma_release_channel(rx_chan);
+ return -ENOMEM;
+ }
+
+ dma_bus = dma_map_single(rx_chan->device->dev, dma_buf,
+ FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+
+ if (dma_mapping_error(rx_chan->device->dev, dma_bus)) {
+ dev_err(sport->port.dev, "dma_map_single rx failed\n");
+ dma_release_channel(rx_chan);
+ return -ENOMEM;
+ }
+
+ dma_rx_sconfig.src_addr = sport->port.mapbase + UARTDR;
+ dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_rx_sconfig.src_maxburst = 1;
+ dma_rx_sconfig.direction = DMA_DEV_TO_MEM;
+ ret = dmaengine_slave_config(rx_chan, &dma_rx_sconfig);
+
+ if (ret < 0) {
+ dev_err(sport->port.dev,
+ "Dma slave config failed, err = %d\n", ret);
+ dma_release_channel(rx_chan);
+ return ret;
+ }
+
+ sport->dma_rx_chan = rx_chan;
+ sport->dma_rx_buf_virt = dma_buf;
+ sport->dma_rx_buf_bus = dma_bus;
+ sport->dma_rx_in_progress = 0;
+
+ sport->dma_rx_timeout = (sport->port.timeout - HZ / 50) *
+ FSL_UART_RX_DMA_BUFFER_SIZE * 3 /
+ sport->rxfifo_size / 2;
+
+ if (sport->dma_rx_timeout < msecs_to_jiffies(20))
+ sport->dma_rx_timeout = msecs_to_jiffies(20);
+
+ return 0;
+}
+
+static void lpuart_dma_tx_free(struct uart_port *port)
+{
+ struct lpuart_port *sport = container_of(port,
+ struct lpuart_port, port);
+ struct dma_chan *dma_chan;
+
+ dma_unmap_single(sport->port.dev, sport->dma_tx_buf_bus,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
+ dma_chan = sport->dma_tx_chan;
+ sport->dma_tx_chan = NULL;
+ sport->dma_tx_buf_bus = 0;
+ sport->dma_tx_buf_virt = NULL;
+ dma_release_channel(dma_chan);
+}
+
+static void lpuart_dma_rx_free(struct uart_port *port)
+{
+ struct lpuart_port *sport = container_of(port,
+ struct lpuart_port, port);
+ struct dma_chan *dma_chan;
+
+ dma_unmap_single(sport->port.dev, sport->dma_rx_buf_bus,
+ FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+
+ dma_chan = sport->dma_rx_chan;
+ sport->dma_rx_chan = NULL;
+ sport->dma_rx_buf_bus = 0;
+ sport->dma_rx_buf_virt = NULL;
+ dma_release_channel(dma_chan);
+}
+#endif
+
static int lpuart_startup(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
int ret;
unsigned long flags;
unsigned char temp;
+
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+ struct platform_device *pdev = to_platform_device(port->dev);
+ struct device_node *np = pdev->dev.of_node;
+
+ if (of_get_property(np, "dmas", NULL)) {
+ sport->lpuart_dma_use = true;
+ lpuart_dma_tx_request(port);
+ lpuart_dma_rx_request(port);
+ temp = readb(port->membase + UARTCR5);
+ writeb(temp | UARTCR5_TDMAS, port->membase + UARTCR5);
+ } else
+ sport->lpuart_dma_use = false;
+#endif
+
ret = devm_request_irq(port->dev, port->irq, lpuart_int, 0,
DRIVER_NAME, sport);
if (ret)
@@ -413,6 +843,13 @@ static void lpuart_shutdown(struct uart_port *port)
spin_unlock_irqrestore(&port->lock, flags);
devm_free_irq(port->dev, port->irq, sport);
+
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+ if (sport->lpuart_dma_use) {
+ lpuart_dma_tx_free(port);
+ lpuart_dma_rx_free(port);
+ }
+#endif
}
static void
@@ -854,6 +1291,10 @@ static int __init lpuart_serial_init(void)
pr_info("serial: Freescale lpuart driver\n");
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+ pr_info("serial: Freescale lpuart dma support\n");
+#endif
+
ret = uart_register_driver(&lpuart_reg);
if (ret)
return ret;
--
1.8.4
^ permalink raw reply related
* [PATCH V5 1/3] ARM: imx: add suspend in ocram support for i.mx6q
From: Anson.Huang at freescale.com @ 2014-01-15 5:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140115034321.GD1896@S2101-09.ap.freescale.net>
Hi, Shawn
these comments should be applicable, will optimize this asm code in V6, thanks.
Sent from Anson's iPhone
> ? 2014?1?15??11:42?"Shawn Guo" <shawn.guo@linaro.org> ???
>
>> On Tue, Jan 14, 2014 at 02:35:13PM +0800, Anson Huang wrote:
>> When system enter suspend, we can set the DDR IO to
>> high-Z state to save DDR IOs' power consumption, this
>> operation can save many power(from ~26mA at 1.5V to ~15mA at 1.5V,
>> measured on i.MX6Q SabreSD board, R25) of DDR IOs. To
>> achieve that, we need to copy the suspend code to ocram
>> and run the low level hardware related code(set DDR IOs
>> to high-Z state) in ocram.
>>
>> If there is no ocram space available, then system will
>> still do suspend in external DDR, hence no DDR IOs will
>> be set to high-Z.
>>
>> The OCRAM usage layout is as below,
>>
>> ocram suspend region(4K currently):
>> ======================== high address ======================
>> .
>> .
>> .
>> ^
>> ^
>> ^
>> imx6_suspend code
>> reserved space(to make imx6_suspend aligned with 8)
>
> We can remove this line now, right? Same for the comment in code.
>
>> PM_INFO structure(imx6_cpu_pm_info)
>> ======================== low address =======================
>>
>> Signed-off-by: Anson Huang <b20788@freescale.com>
>
> <snip>
>
>> +ENTRY(imx6_suspend)
>> + ldr r1, [r0, #PM_INFO_PBASE_OFFSET]
>> + ldr r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
>> + ldr r3, [r0, #PM_INFO_CPU_TYPE_OFFSET]
>> + ldr r4, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET]
>> +
>> + /*
>> + * counting the resume address in iram
>> + * to set it in SRC register.
>> + */
>> + ldr r6, =imx6_suspend
>> + ldr r7, =resume
>> + sub r7, r7, r6
>> + add r8, r1, r4
>> + add r9, r8, r7
>> +
>> + /*
>> + * make sure TLB contain the addr we want,
>> + * as we will access them after MMDC IO floated.
>> + */
>> +
>> + ldr r11, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET]
>> + ldr r6, [r11, #0x0]
>> + ldr r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
>> + ldr r6, [r11, #0x0]
>> +
>> + /* use r11 to store the IO address */
>> + ldr r11, [r0, #PM_INFO_MX6Q_SRC_V_OFFSET]
>> + /* store physical resume addr and pm_info address. */
>> + str r9, [r11, #MX6Q_SRC_GPR1]
>> + str r1, [r11, #MX6Q_SRC_GPR2]
>> +
>> + /* need to sync L2 cache before DSM. */
>> + sync_l2_cache
>> +
>> + ldr r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
>> + /*
>> + * put DDR explicitly into self-refresh and
>> + * disable automatic power savings.
>> + */
>> + ldr r7, [r11, #MX6Q_MMDC_MAPSR]
>> + orr r7, r7, #0x1
>> + str r7, [r11, #MX6Q_MMDC_MAPSR]
>> +
>> + /* make the DDR explicitly enter self-refresh. */
>> + ldr r7, [r11, #MX6Q_MMDC_MAPSR]
>> + orr r7, r7, #(1 << 21)
>> + str r7, [r11, #MX6Q_MMDC_MAPSR]
>> +
>> +poll_dvfs_set_1:
>> + ldr r7, [r11, #MX6Q_MMDC_MAPSR]
>> + ands r7, r7, #(1 << 25)
>> + beq poll_dvfs_set_1
>> +
>> + ldr r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
>> + ldr r6, =0x0
>> + ldr r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
>> + ldr r8, =PM_INFO_MMDC_IO_VAL_OFFSET
>
> If we add the following instruction here
>
> add r8, r0, r8
>
>> +set_mmdc_io_lpm:
>> + ldr r9, [r0, r8]
>
> , it can be replaced by the following one
>
> ldr r9, [r8], #0x8
>
>> + str r6, [r11, r9]
>> + add r8, r8, #0x8
>
> , and then we can save this one in the loop, right?
>
>> + sub r7, r7, #0x1
>> + cmp r7, #0x0
>
> The sequence of 'sub ...; cmp ..., #0' and 'and ...; cmp ..., #0' can
> generally be replaced by 'subs ...' and 'ands' respectively to save one
> instruction, right?
>
> The above two comments apply to a few other places in the code.
>
>> + bne set_mmdc_io_lpm
>> +
>> + /*
>> + * mask all GPC interrupts before
>> + * enabling the RBC counters to
>> + * avoid the counter starting too
>> + * early if an interupt is already
>> + * pending.
>> + */
>> + ldr r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
>> + ldr r6, [r11, #MX6Q_GPC_IMR1]
>> + ldr r7, [r11, #MX6Q_GPC_IMR2]
>> + ldr r8, [r11, #MX6Q_GPC_IMR3]
>> + ldr r9, [r11, #MX6Q_GPC_IMR4]
>> +
>> + ldr r10, =0xffffffff
>> + str r10, [r11, #MX6Q_GPC_IMR1]
>> + str r10, [r11, #MX6Q_GPC_IMR2]
>> + str r10, [r11, #MX6Q_GPC_IMR3]
>> + str r10, [r11, #MX6Q_GPC_IMR4]
>> +
>> + /*
>> + * enable the RBC bypass counter here
>> + * to hold off the interrupts. RBC counter
>> + * = 32 (1ms), Minimum RBC delay should be
>> + * 400us for the analog LDOs to power down.
>> + */
>> + ldr r11, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET]
>> + ldr r10, [r11, #MX6Q_CCM_CCR]
>> + bic r10, r10, #(0x3f << 21)
>> + orr r10, r10, #(0x20 << 21)
>> + str r10, [r11, #MX6Q_CCM_CCR]
>> +
>> + /* enable the counter. */
>> + ldr r10, [r11, #MX6Q_CCM_CCR]
>> + orr r10, r10, #(0x1 << 27)
>> + str r10, [r11, #MX6Q_CCM_CCR]
>> +
>> + /* unmask all the GPC interrupts. */
>> + ldr r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
>> + str r6, [r11, #MX6Q_GPC_IMR1]
>> + str r7, [r11, #MX6Q_GPC_IMR2]
>> + str r8, [r11, #MX6Q_GPC_IMR3]
>> + str r9, [r11, #MX6Q_GPC_IMR4]
>> +
>> + /*
>> + * now delay for a short while (3usec)
>> + * ARM is at 1GHz at this point
>> + * so a short loop should be enough.
>> + * this delay is required to ensure that
>> + * the RBC counter can start counting in
>> + * case an interrupt is already pending
>> + * or in case an interrupt arrives just
>> + * as ARM is about to assert DSM_request.
>> + */
>> + ldr r6, =2000
>> +rbc_loop:
>> + sub r6, r6, #0x1
>> + cmp r6, #0x0
>> + bne rbc_loop
>> +
>> + /* Zzz, enter stop mode */
>> + wfi
>> + nop
>> + nop
>> + nop
>> + nop
>> +
>> + /*
>> + * run to here means there is pending
>> + * wakeup source, system should auto
>> + * resume, we need to restore MMDC IO first
>> + */
>
> The MMDC restoring code looks identical between the case of wakeup
> source pending and the normal resume case, except that the former runs
> at virtual address and the later runs at the physical. Can we make
> a macro for it to save some code duplication?
>
> Shawn
>
>> + ldr r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
>> + ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
>> + ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET
>> +restore_mmdc_io:
>> + ldr r8, [r0, r7]
>> + add r7, r7, #0x4
>> + ldr r9, [r0, r7]
>> + add r7, r7, #0x4
>> + str r9, [r11, r8]
>> + sub r6, r6, #0x1
>> + cmp r6, #0x0
>> + bne restore_mmdc_io
>> +
>> + ldr r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
>> + /* let DDR out of self-refresh. */
>> + ldr r7, [r11, #MX6Q_MMDC_MAPSR]
>> + bic r7, r7, #(1 << 21)
>> + str r7, [r11, #MX6Q_MMDC_MAPSR]
>> +
>> +poll_dvfs_clear_2:
>> + ldr r7, [r11, #MX6Q_MMDC_MAPSR]
>> + ands r7, r7, #(1 << 25)
>> + bne poll_dvfs_clear_2
>> + /* enable DDR auto power saving */
>> + ldr r7, [r11, #MX6Q_MMDC_MAPSR]
>> + bic r7, r7, #0x1
>> + str r7, [r11, #MX6Q_MMDC_MAPSR]
>> + /* return to suspend finish */
>> + mov pc, lr
>> +
>> +resume:
>> + /* invalidate L1 I-cache first */
>> + mov r6, #0x0
>> + mcr p15, 0, r6, c7, c5, 0
>> + mcr p15, 0, r6, c7, c5, 0
>> + mcr p15, 0, r6, c7, c5, 6
>> + /* enable the Icache and branch prediction */
>> + mov r6, #0x1800
>> + mcr p15, 0, r6, c1, c0, 0
>> + isb
>> +
>> + /* get physical resume address from pm_info. */
>> + ldr lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
>> + /* clear core0's entry and parameter */
>> + ldr r11, [r0, #PM_INFO_MX6Q_SRC_P_OFFSET]
>> + mov r7, #0
>> + str r7, [r11, #MX6Q_SRC_GPR1]
>> + str r7, [r11, #MX6Q_SRC_GPR2]
>> +
>> + ldr r11, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET]
>> + ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
>> + ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET
>> +dsm_restore_mmdc_io:
>> + ldr r8, [r0, r7]
>> + add r7, r7, #0x4
>> + ldr r9, [r0, r7]
>> + add r7, r7, #0x4
>> + str r9, [r11, r8]
>> + sub r6, r6, #0x1
>> + cmp r6, #0x0
>> + bne dsm_restore_mmdc_io
>> +
>> + ldr r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET]
>> + /* let DDR out of self-refresh */
>> + ldr r7, [r11, #MX6Q_MMDC_MAPSR]
>> + bic r7, r7, #(1 << 21)
>> + str r7, [r11, #MX6Q_MMDC_MAPSR]
>> +
>> +poll_dvfs_clear_1:
>> + ldr r7, [r11, #MX6Q_MMDC_MAPSR]
>> + ands r7, r7, #(1 << 25)
>> + bne poll_dvfs_clear_1
>> + /* enable DDR auto power saving */
>> + ldr r7, [r11, #MX6Q_MMDC_MAPSR]
>> + bic r7, r7, #0x1
>> + str r7, [r11, #MX6Q_MMDC_MAPSR]
>> + mov pc, lr
>> +ENDPROC(imx6_suspend)
>> --
>> 1.7.9.5
>
^ permalink raw reply
* [PATCH v3 0/2] serial: fsl_lpuart: add DMA support
From: Yuan Yao @ 2014-01-15 5:24 UTC (permalink / raw)
To: linux-arm-kernel
Changed in v3:
- Use the streaming DMA API for receive.
- Add the macro(SERIAL_FSL_LPUART_DMA) and dts node propertie for whether using the dma.
- Adjust some coding style.
Changed in v2:
- Add eDMA support for lpuart receive.
- Use dma_mapping_error test dma_map_single.
- Change some names of variable.
- Fix some bugs.
Added in v1:
- Add device tree bindings for lupart eDMA support.
- Add eDMA support for lpuart send.
^ permalink raw reply
* [PATCH v3 1/2] ARM: dts: vf610: lpuart: Add eDMA support
From: Yuan Yao @ 2014-01-15 5:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1389763488-27361-1-git-send-email-yao.yuan@freescale.com>
Add lpuart dts node properties for eDMA support, them depend on the eDMA driver.
See VF610_EDMA_MUXID0_UART*_*X macro on eDMA driver
Signed-off-by: Yuan Yao <yao.yuan@freescale.com>
---
arch/arm/boot/dts/vf610.dtsi | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/vf610.dtsi b/arch/arm/boot/dts/vf610.dtsi
index 365e0fa..ed6b053 100644
--- a/arch/arm/boot/dts/vf610.dtsi
+++ b/arch/arm/boot/dts/vf610.dtsi
@@ -118,6 +118,9 @@
interrupts = <0 61 0x00>;
clocks = <&clks VF610_CLK_UART0>;
clock-names = "ipg";
+ dma-names = "lpuart-tx","lpuart-rx";
+ dmas = <&edma0 0 VF610_EDMA_MUXID0_UART0_TX>,
+ <&edma0 0 VF610_EDMA_MUXID0_UART0_RX>;
status = "disabled";
};
@@ -127,6 +130,9 @@
interrupts = <0 62 0x04>;
clocks = <&clks VF610_CLK_UART1>;
clock-names = "ipg";
+ dma-names = "lpuart-tx","lpuart-rx";
+ dmas = <&edma0 0 VF610_EDMA_MUXID0_UART1_TX>,
+ <&edma0 0 VF610_EDMA_MUXID0_UART1_RX>;
status = "disabled";
};
@@ -136,6 +142,9 @@
interrupts = <0 63 0x04>;
clocks = <&clks VF610_CLK_UART2>;
clock-names = "ipg";
+ dma-names = "lpuart-tx","lpuart-rx";
+ dmas = <&edma0 0 VF610_EDMA_MUXID0_UART2_TX>,
+ <&edma0 0 VF610_EDMA_MUXID0_UART2_RX>;
status = "disabled";
};
@@ -145,6 +154,9 @@
interrupts = <0 64 0x04>;
clocks = <&clks VF610_CLK_UART3>;
clock-names = "ipg";
+ dma-names = "lpuart-tx","lpuart-rx";
+ dmas = <&edma0 0 VF610_EDMA_MUXID0_UART3_TX>,
+ <&edma0 0 VF610_EDMA_MUXID0_UART3_RX>;
status = "disabled";
};
--
1.8.4
^ permalink raw reply related
* [PATCH v3 2/2] serial: fsl_lpuart: add DMA support
From: Yuan Yao @ 2014-01-15 5:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1389763488-27361-1-git-send-email-yao.yuan@freescale.com>
Add dma support for lpuart. This function depend on DMA driver.
You can turn on it by SERIAL_FSL_LPUART_DMA=y. And It works if dts node has dma properties.
Signed-off-by: Yuan Yao <yao.yuan@freescale.com>
---
.../devicetree/bindings/serial/fsl-lpuart.txt | 21 +-
drivers/tty/serial/Kconfig | 7 +
drivers/tty/serial/fsl_lpuart.c | 457 ++++++++++++++++++++-
3 files changed, 473 insertions(+), 12 deletions(-)
diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
index 6fd1dd1..7509080 100644
--- a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
+++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
@@ -4,11 +4,24 @@ Required properties:
- compatible : Should be "fsl,<soc>-lpuart"
- reg : Address and length of the register set for the device
- interrupts : Should contain uart interrupt
+- clocks : from common clock binding: handle to uart clock
+- clock-names : from common clock binding: Shall be "ipg"
+
+Optional properties:
+- dma-names: Should contain "lpuart-tx" for transmit and "lpuart-rx" for receive channels
+- dmas: Should contain dma specifiers for transmit and receive channels
+
+Note: Optional properties for DMA support, If need this properties is must.
Example:
uart0: serial at 40027000 {
- compatible = "fsl,vf610-lpuart";
- reg = <0x40027000 0x1000>;
- interrupts = <0 61 0x00>;
- };
+ compatible = "fsl,vf610-lpuart";
+ reg = <0x40027000 0x1000>;
+ interrupts = <0 61 0x00>;
+ clocks = <&clks VF610_CLK_UART0>;
+ clock-names = "ipg";
+ dma-names = "lpuart-tx","lpuart-rx";
+ dmas = <&edma0 0 VF610_EDMA_MUXID0_UART0_TX>,
+ <&edma0 0 VF610_EDMA_MUXID0_UART0_RX>;
+ };
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index a3817ab..ab3910b 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1509,6 +1509,13 @@ config SERIAL_FSL_LPUART_CONSOLE
If you have enabled the lpuart serial port on the Freescale SoCs,
you can make it the console by answering Y to this option.
+config SERIAL_FSL_LPUART_DMA
+ bool "Freescale lpuart serial port dma support"
+ depends on FSL_EDMA=y && SERIAL_FSL_LPUART=y
+ help
+ DMA support for the on-chip lpuart on some Freescale SOCs,
+ you can turn on the dma support for lpuart by answering Y to this option.
+
config SERIAL_ST_ASC
tristate "ST ASC serial port support"
select SERIAL_CORE
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 67b8946..5fdcb18 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -13,14 +13,19 @@
#define SUPPORT_SYSRQ
#endif
-#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/dmapool.h>
#include <linux/io.h>
#include <linux/irq.h>
-#include <linux/clk.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/console.h>
+#include <linux/of_dma.h>
#include <linux/serial_core.h>
+#include <linux/slab.h>
#include <linux/tty_flip.h>
/* All registers are 8-bit width */
@@ -112,6 +117,12 @@
#define UARTSFIFO_TXOF 0x02
#define UARTSFIFO_RXUF 0x01
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+#define DMA_MAXBURST 16
+#define DMA_MAXBURST_MASK (DMA_MAXBURST - 1)
+#define FSL_UART_RX_DMA_BUFFER_SIZE 64
+#endif
+
#define DRIVER_NAME "fsl-lpuart"
#define DEV_NAME "ttyLP"
#define UART_NR 6
@@ -121,6 +132,26 @@ struct lpuart_port {
struct clk *clk;
unsigned int txfifo_size;
unsigned int rxfifo_size;
+
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+ bool lpuart_dma_use;
+ struct dma_chan *dma_tx_chan;
+ struct dma_chan *dma_rx_chan;
+ struct dma_async_tx_descriptor *dma_tx_desc;
+ struct dma_async_tx_descriptor *dma_rx_desc;
+ dma_addr_t dma_tx_buf_bus;
+ dma_addr_t dma_rx_buf_bus;
+ dma_cookie_t dma_tx_cookie;
+ dma_cookie_t dma_rx_cookie;
+ unsigned char *dma_tx_buf_virt;
+ unsigned char *dma_rx_buf_virt;
+ unsigned int dma_tx_bytes;
+ unsigned int dma_rx_bytes;
+ int dma_tx_in_progress;
+ int dma_rx_in_progress;
+ unsigned int dma_rx_timeout;
+ struct timer_list lpuart_timer;
+#endif
};
static struct of_device_id lpuart_dt_ids[] = {
@@ -131,6 +162,12 @@ static struct of_device_id lpuart_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+/* Forward declare this for the dma callbacks*/
+static void lpuart_dma_tx_complete(void *arg);
+static void lpuart_dma_rx_complete(void *arg);
+#endif
+
static void lpuart_stop_tx(struct uart_port *port)
{
unsigned char temp;
@@ -152,6 +189,212 @@ static void lpuart_enable_ms(struct uart_port *port)
{
}
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+static void lpuart_copy_rx_to_tty(struct lpuart_port *sport,
+ struct tty_port *tty, int count)
+{
+ int copied;
+
+ sport->port.icount.rx += count;
+
+ if (!tty) {
+ dev_err(sport->port.dev, "No tty port\n");
+ return;
+ }
+
+ dma_sync_single_for_cpu(sport->port.dev, sport->dma_rx_buf_bus,
+ FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+ copied = tty_insert_flip_string(tty,
+ ((unsigned char *)(sport->dma_rx_buf_virt)), count);
+
+ if (copied != count) {
+ WARN_ON(1);
+ dev_err(sport->port.dev, "RxData copy to tty layer failed\n");
+ }
+
+ dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus,
+ FSL_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE);
+}
+
+static void lpuart_pio_tx(struct lpuart_port *sport)
+{
+ struct circ_buf *xmit = &sport->port.state->xmit;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ while (!uart_circ_empty(xmit) &&
+ readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size) {
+ writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ sport->port.icount.tx++;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&sport->port);
+
+ if (uart_circ_empty(xmit))
+ writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS,
+ sport->port.membase + UARTCR5);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static int lpuart_dma_tx(struct lpuart_port *sport, unsigned long count)
+{
+ struct circ_buf *xmit = &sport->port.state->xmit;
+ dma_addr_t tx_bus_addr;
+
+ dma_sync_single_for_device(sport->port.dev, sport->dma_tx_buf_bus,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
+ sport->dma_tx_bytes = count & ~(DMA_MAXBURST_MASK);
+ tx_bus_addr = sport->dma_tx_buf_bus + xmit->tail;
+ sport->dma_tx_desc = dmaengine_prep_slave_single(sport->dma_tx_chan,
+ tx_bus_addr, sport->dma_tx_bytes,
+ DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
+
+ if (!sport->dma_tx_desc) {
+ dev_err(sport->port.dev, "Not able to get desc for tx\n");
+ return -EIO;
+ }
+
+ sport->dma_tx_desc->callback = lpuart_dma_tx_complete;
+ sport->dma_tx_desc->callback_param = sport;
+ sport->dma_tx_in_progress = 1;
+ sport->dma_tx_cookie = dmaengine_submit(sport->dma_tx_desc);
+ dma_async_issue_pending(sport->dma_tx_chan);
+
+ return 0;
+}
+
+static void lpuart_prepare_tx(struct lpuart_port *sport)
+{
+ struct circ_buf *xmit = &sport->port.state->xmit;
+ unsigned long count = CIRC_CNT_TO_END(xmit->head,
+ xmit->tail, UART_XMIT_SIZE);
+
+ if (!count)
+ return;
+
+ if (count < DMA_MAXBURST)
+ writeb(readb(sport->port.membase + UARTCR5) & ~UARTCR5_TDMAS,
+ sport->port.membase + UARTCR5);
+ else {
+ writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS,
+ sport->port.membase + UARTCR5);
+ lpuart_dma_tx(sport, count);
+ }
+}
+
+static void lpuart_dma_tx_complete(void *arg)
+{
+ struct lpuart_port *sport = arg;
+ struct circ_buf *xmit = &sport->port.state->xmit;
+ unsigned long flags;
+
+ async_tx_ack(sport->dma_tx_desc);
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ xmit->tail = (xmit->tail + sport->dma_tx_bytes) & (UART_XMIT_SIZE - 1);
+ sport->dma_tx_in_progress = 0;
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&sport->port);
+
+ lpuart_prepare_tx(sport);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static int lpuart_dma_rx(struct lpuart_port *sport)
+{
+ dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus,
+ FSL_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE);
+ sport->dma_rx_desc = dmaengine_prep_slave_single(sport->dma_rx_chan,
+ sport->dma_rx_buf_bus, FSL_UART_RX_DMA_BUFFER_SIZE,
+ DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
+
+ if (!sport->dma_rx_desc) {
+ dev_err(sport->port.dev, "Not able to get desc for rx\n");
+ return -EIO;
+ }
+
+ sport->dma_rx_desc->callback = lpuart_dma_rx_complete;
+ sport->dma_rx_desc->callback_param = sport;
+ sport->dma_rx_in_progress = 1;
+ sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc);
+ dma_async_issue_pending(sport->dma_rx_chan);
+
+ return 0;
+}
+
+static void lpuart_dma_rx_complete(void *arg)
+{
+ struct lpuart_port *sport = arg;
+ struct tty_port *port = &sport->port.state->port;
+ unsigned long flags;
+
+ async_tx_ack(sport->dma_rx_desc);
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ sport->dma_rx_in_progress = 0;
+ lpuart_copy_rx_to_tty(sport, port, FSL_UART_RX_DMA_BUFFER_SIZE);
+ tty_flip_buffer_push(port);
+ lpuart_dma_rx(sport);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static void lpuart_timer_func(unsigned long data)
+{
+ struct lpuart_port *sport = (struct lpuart_port *)data;
+ struct tty_port *port = &sport->port.state->port;
+ struct dma_tx_state state;
+ unsigned long flags;
+ unsigned char temp;
+ int count;
+
+ del_timer(&sport->lpuart_timer);
+ dmaengine_pause(sport->dma_rx_chan);
+ dmaengine_tx_status(sport->dma_rx_chan, sport->dma_rx_cookie, &state);
+ dmaengine_terminate_all(sport->dma_rx_chan);
+ count = FSL_UART_RX_DMA_BUFFER_SIZE - state.residue;
+ async_tx_ack(sport->dma_rx_desc);
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ sport->dma_rx_in_progress = 0;
+ lpuart_copy_rx_to_tty(sport, port, count);
+ tty_flip_buffer_push(port);
+ temp = readb(sport->port.membase + UARTCR5);
+ writeb(temp & ~UARTCR5_RDMAS, sport->port.membase + UARTCR5);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static inline void lpuart_prepare_rx(struct lpuart_port *sport)
+{
+ unsigned long flags;
+ unsigned char temp;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ init_timer(&sport->lpuart_timer);
+ sport->lpuart_timer.function = lpuart_timer_func;
+ sport->lpuart_timer.data = (unsigned long)sport;
+ sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
+ add_timer(&sport->lpuart_timer);
+
+ lpuart_dma_rx(sport);
+ temp = readb(sport->port.membase + UARTCR5);
+ writeb(temp | UARTCR5_RDMAS, sport->port.membase + UARTCR5);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+#endif
+
static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
{
struct circ_buf *xmit = &sport->port.state->xmit;
@@ -172,14 +415,26 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
static void lpuart_start_tx(struct uart_port *port)
{
- struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
+ struct lpuart_port *sport = container_of(port,
+ struct lpuart_port, port);
+ struct circ_buf *xmit = &sport->port.state->xmit;
unsigned char temp;
temp = readb(port->membase + UARTCR2);
writeb(temp | UARTCR2_TIE, port->membase + UARTCR2);
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+ if (sport->lpuart_dma_use) {
+ if (!uart_circ_empty(xmit) && !sport->dma_tx_in_progress)
+ lpuart_prepare_tx(sport);
+ } else {
+ if (readb(port->membase + UARTSR1) & UARTSR1_TDRE)
+ lpuart_transmit_buffer(sport);
+ }
+#else
if (readb(port->membase + UARTSR1) & UARTSR1_TDRE)
lpuart_transmit_buffer(sport);
+#endif
}
static irqreturn_t lpuart_txint(int irq, void *dev_id)
@@ -279,12 +534,27 @@ static irqreturn_t lpuart_int(int irq, void *dev_id)
sts = readb(sport->port.membase + UARTSR1);
- if (sts & UARTSR1_RDRF)
+ if (sts & UARTSR1_RDRF) {
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+ if (sport->lpuart_dma_use)
+ lpuart_prepare_rx(sport);
+ else
+ lpuart_rxint(irq, dev_id);
+#else
lpuart_rxint(irq, dev_id);
-
+#endif
+ }
if (sts & UARTSR1_TDRE &&
- !(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS))
+ !(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS)) {
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+ if (sport->lpuart_dma_use)
+ lpuart_pio_tx(sport);
+ else
+ lpuart_txint(irq, dev_id);
+#else
lpuart_txint(irq, dev_id);
+#endif
+ }
return IRQ_HANDLED;
}
@@ -366,19 +636,179 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH,
sport->port.membase + UARTCFIFO);
- writeb(2, sport->port.membase + UARTTWFIFO);
+ writeb(0, sport->port.membase + UARTTWFIFO);
writeb(1, sport->port.membase + UARTRWFIFO);
/* Restore cr2 */
writeb(cr2_saved, sport->port.membase + UARTCR2);
}
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+static int lpuart_dma_tx_request(struct uart_port *port)
+{
+ struct lpuart_port *sport = container_of(port,
+ struct lpuart_port, port);
+ struct dma_chan *tx_chan;
+ struct dma_slave_config dma_tx_sconfig;
+ dma_addr_t dma_bus;
+ unsigned char *dma_buf;
+ int ret;
+
+ tx_chan = dma_request_slave_channel(sport->port.dev, "lpuart-tx");
+
+ if (!tx_chan) {
+ dev_err(sport->port.dev, "Dma tx channel request failed!\n");
+ return -ENODEV;
+ }
+
+ dma_bus = dma_map_single(tx_chan->device->dev,
+ sport->port.state->xmit.buf,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
+
+ if (dma_mapping_error(tx_chan->device->dev, dma_bus)) {
+ dev_err(sport->port.dev, "dma_map_single tx failed\n");
+ dma_release_channel(tx_chan);
+ return -ENOMEM;
+ }
+
+ dma_buf = sport->port.state->xmit.buf;
+ dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR;
+ dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_tx_sconfig.dst_maxburst = DMA_MAXBURST;
+ dma_tx_sconfig.direction = DMA_MEM_TO_DEV;
+ ret = dmaengine_slave_config(tx_chan, &dma_tx_sconfig);
+
+ if (ret < 0) {
+ dev_err(sport->port.dev,
+ "Dma slave config failed, err = %d\n", ret);
+ dma_release_channel(tx_chan);
+ return ret;
+ }
+
+ sport->dma_tx_chan = tx_chan;
+ sport->dma_tx_buf_virt = dma_buf;
+ sport->dma_tx_buf_bus = dma_bus;
+ sport->dma_tx_in_progress = 0;
+
+ return 0;
+}
+
+static int lpuart_dma_rx_request(struct uart_port *port)
+{
+ struct lpuart_port *sport = container_of(port,
+ struct lpuart_port, port);
+ struct dma_chan *rx_chan;
+ struct dma_slave_config dma_rx_sconfig;
+ dma_addr_t dma_bus;
+ unsigned char *dma_buf;
+ int ret;
+
+ rx_chan = dma_request_slave_channel(sport->port.dev, "lpuart-rx");
+
+ if (!rx_chan) {
+ dev_err(sport->port.dev, "Dma rx channel request failed!\n");
+ return -ENODEV;
+ }
+
+ dma_buf = devm_kzalloc(sport->port.dev,
+ FSL_UART_RX_DMA_BUFFER_SIZE, GFP_KERNEL);
+
+ if (!dma_buf) {
+ dev_err(sport->port.dev, "Dma rx alloc failed\n");
+ dma_release_channel(rx_chan);
+ return -ENOMEM;
+ }
+
+ dma_bus = dma_map_single(rx_chan->device->dev, dma_buf,
+ FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+
+ if (dma_mapping_error(rx_chan->device->dev, dma_bus)) {
+ dev_err(sport->port.dev, "dma_map_single rx failed\n");
+ dma_release_channel(rx_chan);
+ return -ENOMEM;
+ }
+
+ dma_rx_sconfig.src_addr = sport->port.mapbase + UARTDR;
+ dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_rx_sconfig.src_maxburst = 1;
+ dma_rx_sconfig.direction = DMA_DEV_TO_MEM;
+ ret = dmaengine_slave_config(rx_chan, &dma_rx_sconfig);
+
+ if (ret < 0) {
+ dev_err(sport->port.dev,
+ "Dma slave config failed, err = %d\n", ret);
+ dma_release_channel(rx_chan);
+ return ret;
+ }
+
+ sport->dma_rx_chan = rx_chan;
+ sport->dma_rx_buf_virt = dma_buf;
+ sport->dma_rx_buf_bus = dma_bus;
+ sport->dma_rx_in_progress = 0;
+
+ sport->dma_rx_timeout = (sport->port.timeout - HZ / 50) *
+ FSL_UART_RX_DMA_BUFFER_SIZE * 3 /
+ sport->rxfifo_size / 2;
+
+ if (sport->dma_rx_timeout < msecs_to_jiffies(20))
+ sport->dma_rx_timeout = msecs_to_jiffies(20);
+
+ return 0;
+}
+
+static void lpuart_dma_tx_free(struct uart_port *port)
+{
+ struct lpuart_port *sport = container_of(port,
+ struct lpuart_port, port);
+ struct dma_chan *dma_chan;
+
+ dma_unmap_single(sport->port.dev, sport->dma_tx_buf_bus,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
+ dma_chan = sport->dma_tx_chan;
+ sport->dma_tx_chan = NULL;
+ sport->dma_tx_buf_bus = 0;
+ sport->dma_tx_buf_virt = NULL;
+ dma_release_channel(dma_chan);
+}
+
+static void lpuart_dma_rx_free(struct uart_port *port)
+{
+ struct lpuart_port *sport = container_of(port,
+ struct lpuart_port, port);
+ struct dma_chan *dma_chan;
+
+ dma_unmap_single(sport->port.dev, sport->dma_rx_buf_bus,
+ FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+
+ dma_chan = sport->dma_rx_chan;
+ sport->dma_rx_chan = NULL;
+ sport->dma_rx_buf_bus = 0;
+ sport->dma_rx_buf_virt = NULL;
+ dma_release_channel(dma_chan);
+}
+#endif
+
static int lpuart_startup(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
int ret;
unsigned long flags;
unsigned char temp;
+
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+ struct platform_device *pdev = to_platform_device(port->dev);
+ struct device_node *np = pdev->dev.of_node;
+
+ if (of_get_property(np, "dmas", NULL)) {
+ sport->lpuart_dma_use = true;
+ lpuart_dma_tx_request(port);
+ lpuart_dma_rx_request(port);
+ temp = readb(port->membase + UARTCR5);
+ writeb(temp | UARTCR5_TDMAS, port->membase + UARTCR5);
+ } else
+ sport->lpuart_dma_use = false;
+#endif
+
ret = devm_request_irq(port->dev, port->irq, lpuart_int, 0,
DRIVER_NAME, sport);
if (ret)
@@ -413,6 +843,13 @@ static void lpuart_shutdown(struct uart_port *port)
spin_unlock_irqrestore(&port->lock, flags);
devm_free_irq(port->dev, port->irq, sport);
+
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+ if (sport->lpuart_dma_use) {
+ lpuart_dma_tx_free(port);
+ lpuart_dma_rx_free(port);
+ }
+#endif
}
static void
@@ -854,6 +1291,10 @@ static int __init lpuart_serial_init(void)
pr_info("serial: Freescale lpuart driver\n");
+#ifdef CONFIG_SERIAL_FSL_LPUART_DMA
+ pr_info("serial: Freescale lpuart dma support\n");
+#endif
+
ret = uart_register_driver(&lpuart_reg);
if (ret)
return ret;
--
1.8.4
^ permalink raw reply related
* [PATCH v2] clk: sirf: re-arch to make the codes support both prima2 and atlas6
From: Mike Turquette @ 2014-01-15 5:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1388986699-6470-1-git-send-email-21cnbao@gmail.com>
Quoting Barry Song (2014-01-05 21:38:19)
> diff --git a/drivers/clk/sirf/clk-atlas6.c b/drivers/clk/sirf/clk-atlas6.c
> new file mode 100644
> index 0000000..21e776a
> --- /dev/null
> +++ b/drivers/clk/sirf/clk-atlas6.c
> @@ -0,0 +1,153 @@
> +/*
> + * Clock tree for CSR SiRFatlasVI
> + *
> + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
> + *
> + * Licensed under GPLv2 or later.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/bitops.h>
> +#include <linux/io.h>
> +#include <linux/clk.h>
> +#include <linux/clk-private.h>
Please do not use clk-private.h. It is slated for removal (some day...).
Do you actually need it?
Regards,
Mike
^ permalink raw reply
* [PATCH 1/2] clk: tegra: Staticize tegra_clk_periph_no_gate_ops
From: Sachin Kamat @ 2014-01-15 5:43 UTC (permalink / raw)
To: linux-arm-kernel
tegra_clk_periph_no_gate_ops is a local symbol.
Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
---
drivers/clk/tegra/clk-periph.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c
index 356e9b804421..9e899c18af86 100644
--- a/drivers/clk/tegra/clk-periph.c
+++ b/drivers/clk/tegra/clk-periph.c
@@ -130,7 +130,7 @@ static const struct clk_ops tegra_clk_periph_nodiv_ops = {
.disable = clk_periph_disable,
};
-const struct clk_ops tegra_clk_periph_no_gate_ops = {
+static const struct clk_ops tegra_clk_periph_no_gate_ops = {
.get_parent = clk_periph_get_parent,
.set_parent = clk_periph_set_parent,
.recalc_rate = clk_periph_recalc_rate,
--
1.7.9.5
^ permalink raw reply related
* [PATCH 2/2] clk: ux500: Staticize ux500_twocell_get
From: Sachin Kamat @ 2014-01-15 5:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1389764606-14102-1-git-send-email-sachin.kamat@linaro.org>
ux500_twocell_get is a local symbol.
Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
Cc: Lee Jones <lee.jones@linaro.org>
---
drivers/clk/ux500/u8500_of_clk.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/ux500/u8500_of_clk.c b/drivers/clk/ux500/u8500_of_clk.c
index cdeff299de26..7b55ef89baa5 100644
--- a/drivers/clk/ux500/u8500_of_clk.c
+++ b/drivers/clk/ux500/u8500_of_clk.c
@@ -29,7 +29,8 @@ static struct clk *prcc_kclk[(PRCC_NUM_PERIPH_CLUSTERS + 1) * PRCC_PERIPHS_PER_C
#define PRCC_KCLK_STORE(clk, base, bit) \
prcc_kclk[(base * PRCC_PERIPHS_PER_CLUSTER) + bit] = clk
-struct clk *ux500_twocell_get(struct of_phandle_args *clkspec, void *data)
+static struct clk *ux500_twocell_get(struct of_phandle_args *clkspec,
+ void *data)
{
struct clk **clk_data = data;
unsigned int base, bit;
--
1.7.9.5
^ permalink raw reply related
* [RFC 0/2] Early patches to get rid of meminfo
From: Laura Abbott @ 2014-01-15 5:55 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
With the move away from bootmem and the convergence on memblock, it seems
like meminfo should be deprecated as well to avoid duplication. This is
a first pass attempt to just use memblock and not have meminfo integrated.
There is still a major issue in terms of actually specifying mem at location
on the command line but I wanted to send this out for some early feedback
before putting any more effort into this. I've done basic boot testing on
a simple DT target.
Thanks,
Laura
Laura Abbott (2):
mm/memblock: add memblock_get_current_limit
arm: Get rid of meminfo
arch/arm/include/asm/mach/arch.h | 4 +-
arch/arm/include/asm/memblock.h | 3 +-
arch/arm/include/asm/setup.h | 23 ------
arch/arm/kernel/atags_parse.c | 5 +-
arch/arm/kernel/setup.c | 33 +++------
arch/arm/mach-clps711x/board-clep7312.c | 7 +-
arch/arm/mach-clps711x/board-edb7211.c | 10 +--
arch/arm/mach-clps711x/board-p720t.c | 2 +-
arch/arm/mach-footbridge/cats-hw.c | 2 +-
arch/arm/mach-footbridge/netwinder-hw.c | 2 +-
arch/arm/mach-msm/board-halibut.c | 6 --
arch/arm/mach-msm/board-mahimahi.c | 13 +--
arch/arm/mach-msm/board-msm7x30.c | 3 +-
arch/arm/mach-msm/board-sapphire.c | 13 +--
arch/arm/mach-msm/board-trout.c | 8 +-
arch/arm/mach-orion5x/common.c | 3 +-
arch/arm/mach-orion5x/common.h | 3 +-
arch/arm/mach-pxa/cm-x300.c | 3 +-
arch/arm/mach-pxa/corgi.c | 10 +--
arch/arm/mach-pxa/eseries.c | 9 +-
arch/arm/mach-pxa/poodle.c | 8 +-
arch/arm/mach-pxa/spitz.c | 9 +--
arch/arm/mach-pxa/tosa.c | 8 +-
arch/arm/mach-realview/core.c | 11 +--
arch/arm/mach-realview/core.h | 3 +-
arch/arm/mach-realview/realview_pb1176.c | 8 +-
arch/arm/mach-realview/realview_pbx.c | 17 ++---
arch/arm/mach-s3c24xx/mach-smdk2413.c | 8 +-
arch/arm/mach-s3c24xx/mach-vstms.c | 8 +-
arch/arm/mach-sa1100/assabet.c | 2 +-
arch/arm/mm/init.c | 61 ++++++----------
arch/arm/mm/mmu.c | 122 ++++++++++--------------------
include/linux/memblock.h | 2 +
mm/memblock.c | 5 +
34 files changed, 150 insertions(+), 284 deletions(-)
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply
* [PATCH V3] ARM: dts: imx6sl: add keypad support for i.mx6sl-evk board.
From: Shawn Guo @ 2014-01-15 5:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1389691828-27000-1-git-send-email-b20788@freescale.com>
On Tue, Jan 14, 2014 at 05:30:28PM +0800, Anson Huang wrote:
> i.MX6SL EVK board has a 3*3 keypad matrix to support 8 keypads,
> enable them, the keymap is as below:
>
> SW6: MATRIX_KEY(0x0, 0x0, KEY_UP) /* ROW0, COL0 */
> SW7: MATRIX_KEY(0x0, 0x1, KEY_DOWN) /* ROW0, COL1 */
> SW8: MATRIX_KEY(0x0, 0x2, KEY_ENTER) /* ROW0, COL2 */
> SW9: MATRIX_KEY(0x1, 0x0, KEY_HOME) /* ROW1, COL0 */
> SW10: MATRIX_KEY(0x1, 0x1, KEY_RIGHT) /* ROW1, COL1 */
> SW11: MATRIX_KEY(0x1, 0x2, KEY_LEFT) /* ROW1, COL2 */
> SW12: MATRIX_KEY(0x2, 0x0, KEY_VOLUMEDOWN) /* ROW2, COL0 */
> SW13: MATRIX_KEY(0x2, 0x1, KEY_VOLUMEUP) /* ROW2, COL1 */
>
> Signed-off-by: Anson Huang <b20788@freescale.com>
Applied, thanks.
^ permalink raw reply
* [PATCH] ARM: dts: imx28-apf28dev: add user button
From: Shawn Guo @ 2014-01-15 5:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1389709287-25742-1-git-send-email-sebastien.szymanski@armadeus.com>
On Tue, Jan 14, 2014 at 03:21:27PM +0100, S?bastien Szymanski wrote:
> Signed-off-by: S?bastien Szymanski <sebastien.szymanski@armadeus.com>
> ---
> arch/arm/boot/dts/imx28-apf28dev.dts | 11 +++++++++++
> 1 file changed, 11 insertions(+)
Applied, thanks.
Shawn
>
> diff --git a/arch/arm/boot/dts/imx28-apf28dev.dts b/arch/arm/boot/dts/imx28-apf28dev.dts
> index 334dea5..221cac4 100644
> --- a/arch/arm/boot/dts/imx28-apf28dev.dts
> +++ b/arch/arm/boot/dts/imx28-apf28dev.dts
> @@ -48,6 +48,7 @@
> MX28_PAD_LCD_D20__GPIO_1_20
> MX28_PAD_LCD_D21__GPIO_1_21
> MX28_PAD_LCD_D22__GPIO_1_22
> + MX28_PAD_GPMI_CE1N__GPIO_0_17
> >;
> fsl,drive-strength = <MXS_DRIVE_4mA>;
> fsl,voltage = <MXS_VOLTAGE_HIGH>;
> @@ -193,4 +194,14 @@
> brightness-levels = <0 4 8 16 32 64 128 255>;
> default-brightness-level = <6>;
> };
> +
> + gpio-keys {
> + compatible = "gpio-keys";
> +
> + user-button {
> + label = "User button";
> + gpios = <&gpio0 17 0>;
> + linux,code = <0x100>;
> + };
> + };
> };
> --
> 1.8.3.2
>
^ permalink raw reply
* [PATCH 1/2] clk: hisilicon: add hi3620_mmc_clks
From: Haojian Zhuang @ 2014-01-15 5:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140115035339.4167.51194@quantum>
On 01/15/2014 11:53 AM, Mike Turquette wrote:
> Quoting zhangfei (2014-01-14 17:40:25)
>> Dear Mike
>>
>> On 01/15/2014 04:17 AM, Mike Turquette wrote:
>>> Quoting Zhangfei Gao (2014-01-13 01:14:28)
>>>> Suggest by Arnd: abstract mmc tuning as clock behavior,
>>>> also because different soc have different tuning method and registers.
>>>> hi3620_mmc_clks is added to handle mmc clock specifically on hi3620.
>>>>
>>>> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
>>>> Acked-by: Arnd Bergmann <arnd@arndb.de>
>>>> Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
>>> Patch looks good to me with one exception. I do not have
>>> Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt in the
>>> clk-next branch. Is there a stable branch I can pull in as a dependency?
>> Mach-hisi just have been uploaeded.
>> Have tried next-20140114, the patch can be applied successfully.
>> While v3.13-rc8 still can not.
>>
>> Is this fine?
> Can you give me a link to the branch that introduces
> Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt?
>
> I guess the patch introducing it is going through arm-soc. Is this going
> in for 3.14? If so then perhaps the clk tree and the arm-soc tree can
> share a stable branch that introduces it.
>
> Regards,
> Mike
>
Some patches are merged into arm-soc, and others are in clk tree.
If sharing a stable branch between arm-soc and clk tree, it only means
that we need to revert all commits that are in arm-soc and clk tree.
I think it's too complex.
How about split the patch? The patch on document should enter in arm-soc.
Regards
Haojian
^ permalink raw reply
* [PATCH v2] clk: sirf: re-arch to make the codes support both prima2 and atlas6
From: Barry Song @ 2014-01-15 6:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140115053706.4167.23616@quantum>
2014/1/15 Mike Turquette <mturquette@linaro.org>:
> Quoting Barry Song (2014-01-05 21:38:19)
>> diff --git a/drivers/clk/sirf/clk-atlas6.c b/drivers/clk/sirf/clk-atlas6.c
>> new file mode 100644
>> index 0000000..21e776a
>> --- /dev/null
>> +++ b/drivers/clk/sirf/clk-atlas6.c
>> @@ -0,0 +1,153 @@
>> +/*
>> + * Clock tree for CSR SiRFatlasVI
>> + *
>> + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
>> + *
>> + * Licensed under GPLv2 or later.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/bitops.h>
>> +#include <linux/io.h>
>> +#include <linux/clk.h>
>> +#include <linux/clk-private.h>
>
> Please do not use clk-private.h. It is slated for removal (some day...).
> Do you actually need it?
removed in v3.
>
> Regards,
> Mike
-barry
^ permalink raw reply
* [PATCH v3] clk: sirf: re-arch to make the codes support both prima2 and atlas6
From: Barry Song @ 2014-01-15 6:11 UTC (permalink / raw)
To: linux-arm-kernel
From: Barry Song <Baohua.Song@csr.com>
sirfprima2 and sirfatlas6 are two different SoCs in CSR SiRF series. for
prima2 and atlas6, there are many shared clocks but there are still
some different register layout and hardware clocks, then result in
different clock table.
here we re-arch the driver to
1. clk-common.c provides common clocks for prima2 and atlas6,
2. clk-prima2.h describles registers of prima2 and clk-prima2.c provides
prima2 specific clocks and clock table.
3. clk-atlas6.h describles registers of atlas6 and clk-atlas6.c provides
atlas6 specific clocks and clock table.
4. clk.h and clk.c expose external interfaces and provide uniform entry
for both prima2 and atlas6.
so both prima2 and atlas6 will get support by drivers/clk/sirf.
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com>
---
-v3: remove clk-private.h according to Mike's comment
drivers/clk/Makefile | 2 +-
drivers/clk/sirf/Makefile | 5 +
drivers/clk/sirf/atlas6.h | 31 +++
drivers/clk/sirf/clk-atlas6.c | 152 +++++++++++++
drivers/clk/{clk-prima2.c => sirf/clk-common.c} | 264 ++++++++---------------
drivers/clk/sirf/clk-prima2.c | 151 +++++++++++++
drivers/clk/sirf/prima2.h | 25 +++
7 files changed, 458 insertions(+), 172 deletions(-)
create mode 100644 drivers/clk/sirf/Makefile
create mode 100644 drivers/clk/sirf/atlas6.h
create mode 100644 drivers/clk/sirf/clk-atlas6.c
rename drivers/clk/{clk-prima2.c => sirf/clk-common.c} (82%)
create mode 100644 drivers/clk/sirf/clk-prima2.c
create mode 100644 drivers/clk/sirf/prima2.h
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 7a10bc9..aa2bd0f 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -20,7 +20,6 @@ obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
obj-$(CONFIG_PLAT_SPEAR) += spear/
obj-$(CONFIG_ARCH_U300) += clk-u300.o
obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/
-obj-$(CONFIG_ARCH_SIRF) += clk-prima2.o
obj-$(CONFIG_PLAT_ORION) += mvebu/
ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/
@@ -30,6 +29,7 @@ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_ARCH_U8500) += ux500/
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
+obj-$(CONFIG_ARCH_SIRF) += sirf/
obj-$(CONFIG_ARCH_ZYNQ) += zynq/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_PLAT_SAMSUNG) += samsung/
diff --git a/drivers/clk/sirf/Makefile b/drivers/clk/sirf/Makefile
new file mode 100644
index 0000000..36b8e20
--- /dev/null
+++ b/drivers/clk/sirf/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for sirf specific clk
+#
+
+obj-$(CONFIG_ARCH_SIRF) += clk-prima2.o clk-atlas6.o
diff --git a/drivers/clk/sirf/atlas6.h b/drivers/clk/sirf/atlas6.h
new file mode 100644
index 0000000..376217f
--- /dev/null
+++ b/drivers/clk/sirf/atlas6.h
@@ -0,0 +1,31 @@
+#define SIRFSOC_CLKC_CLK_EN0 0x0000
+#define SIRFSOC_CLKC_CLK_EN1 0x0004
+#define SIRFSOC_CLKC_REF_CFG 0x0020
+#define SIRFSOC_CLKC_CPU_CFG 0x0024
+#define SIRFSOC_CLKC_MEM_CFG 0x0028
+#define SIRFSOC_CLKC_MEMDIV_CFG 0x002C
+#define SIRFSOC_CLKC_SYS_CFG 0x0030
+#define SIRFSOC_CLKC_IO_CFG 0x0034
+#define SIRFSOC_CLKC_DSP_CFG 0x0038
+#define SIRFSOC_CLKC_GFX_CFG 0x003c
+#define SIRFSOC_CLKC_MM_CFG 0x0040
+#define SIRFSOC_CLKC_GFX2D_CFG 0x0040
+#define SIRFSOC_CLKC_LCD_CFG 0x0044
+#define SIRFSOC_CLKC_MMC01_CFG 0x0048
+#define SIRFSOC_CLKC_MMC23_CFG 0x004C
+#define SIRFSOC_CLKC_MMC45_CFG 0x0050
+#define SIRFSOC_CLKC_NAND_CFG 0x0054
+#define SIRFSOC_CLKC_NANDDIV_CFG 0x0058
+#define SIRFSOC_CLKC_PLL1_CFG0 0x0080
+#define SIRFSOC_CLKC_PLL2_CFG0 0x0084
+#define SIRFSOC_CLKC_PLL3_CFG0 0x0088
+#define SIRFSOC_CLKC_PLL1_CFG1 0x008c
+#define SIRFSOC_CLKC_PLL2_CFG1 0x0090
+#define SIRFSOC_CLKC_PLL3_CFG1 0x0094
+#define SIRFSOC_CLKC_PLL1_CFG2 0x0098
+#define SIRFSOC_CLKC_PLL2_CFG2 0x009c
+#define SIRFSOC_CLKC_PLL3_CFG2 0x00A0
+#define SIRFSOC_USBPHY_PLL_CTRL 0x0008
+#define SIRFSOC_USBPHY_PLL_POWERDOWN BIT(1)
+#define SIRFSOC_USBPHY_PLL_BYPASS BIT(2)
+#define SIRFSOC_USBPHY_PLL_LOCK BIT(3)
diff --git a/drivers/clk/sirf/clk-atlas6.c b/drivers/clk/sirf/clk-atlas6.c
new file mode 100644
index 0000000..f9f4a15
--- /dev/null
+++ b/drivers/clk/sirf/clk-atlas6.c
@@ -0,0 +1,152 @@
+/*
+ * Clock tree for CSR SiRFatlasVI
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
+
+#include "atlas6.h"
+#include "clk-common.c"
+
+static struct clk_dmn clk_mmc01 = {
+ .regofs = SIRFSOC_CLKC_MMC01_CFG,
+ .enable_bit = 59,
+ .hw = {
+ .init = &clk_mmc01_init,
+ },
+};
+
+static struct clk_dmn clk_mmc23 = {
+ .regofs = SIRFSOC_CLKC_MMC23_CFG,
+ .enable_bit = 60,
+ .hw = {
+ .init = &clk_mmc23_init,
+ },
+};
+
+static struct clk_dmn clk_mmc45 = {
+ .regofs = SIRFSOC_CLKC_MMC45_CFG,
+ .enable_bit = 61,
+ .hw = {
+ .init = &clk_mmc45_init,
+ },
+};
+
+static struct clk_init_data clk_nand_init = {
+ .name = "nand",
+ .ops = &dmn_ops,
+ .parent_names = dmn_clk_parents,
+ .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_nand = {
+ .regofs = SIRFSOC_CLKC_NAND_CFG,
+ .enable_bit = 34,
+ .hw = {
+ .init = &clk_nand_init,
+ },
+};
+
+enum atlas6_clk_index {
+ /* 0 1 2 3 4 5 6 7 8 9 */
+ rtc, osc, pll1, pll2, pll3, mem, sys, security, dsp, gps,
+ mf, io, cpu, uart0, uart1, uart2, tsc, i2c0, i2c1, spi0,
+ spi1, pwmc, efuse, pulse, dmac0, dmac1, nand, audio, usp0, usp1,
+ usp2, vip, gfx, gfx2d, lcd, vpp, mmc01, mmc23, mmc45, usbpll,
+ usb0, usb1, cphif, maxclk,
+};
+
+static __initdata struct clk_hw *atlas6_clk_hw_array[maxclk] = {
+ NULL, /* dummy */
+ NULL,
+ &clk_pll1.hw,
+ &clk_pll2.hw,
+ &clk_pll3.hw,
+ &clk_mem.hw,
+ &clk_sys.hw,
+ &clk_security.hw,
+ &clk_dsp.hw,
+ &clk_gps.hw,
+ &clk_mf.hw,
+ &clk_io.hw,
+ &clk_cpu.hw,
+ &clk_uart0.hw,
+ &clk_uart1.hw,
+ &clk_uart2.hw,
+ &clk_tsc.hw,
+ &clk_i2c0.hw,
+ &clk_i2c1.hw,
+ &clk_spi0.hw,
+ &clk_spi1.hw,
+ &clk_pwmc.hw,
+ &clk_efuse.hw,
+ &clk_pulse.hw,
+ &clk_dmac0.hw,
+ &clk_dmac1.hw,
+ &clk_nand.hw,
+ &clk_audio.hw,
+ &clk_usp0.hw,
+ &clk_usp1.hw,
+ &clk_usp2.hw,
+ &clk_vip.hw,
+ &clk_gfx.hw,
+ &clk_gfx2d.hw,
+ &clk_lcd.hw,
+ &clk_vpp.hw,
+ &clk_mmc01.hw,
+ &clk_mmc23.hw,
+ &clk_mmc45.hw,
+ &usb_pll_clk_hw,
+ &clk_usb0.hw,
+ &clk_usb1.hw,
+ &clk_cphif.hw,
+};
+
+static struct clk *atlas6_clks[maxclk];
+
+static void __init atlas6_clk_init(struct device_node *np)
+{
+ struct device_node *rscnp;
+ int i;
+
+ rscnp = of_find_compatible_node(NULL, NULL, "sirf,prima2-rsc");
+ sirfsoc_rsc_vbase = of_iomap(rscnp, 0);
+ if (!sirfsoc_rsc_vbase)
+ panic("unable to map rsc registers\n");
+ of_node_put(rscnp);
+
+ sirfsoc_clk_vbase = of_iomap(np, 0);
+ if (!sirfsoc_clk_vbase)
+ panic("unable to map clkc registers\n");
+
+ /* These are always available (RTC and 26MHz OSC)*/
+ atlas6_clks[rtc] = clk_register_fixed_rate(NULL, "rtc", NULL,
+ CLK_IS_ROOT, 32768);
+ atlas6_clks[osc] = clk_register_fixed_rate(NULL, "osc", NULL,
+ CLK_IS_ROOT, 26000000);
+
+ for (i = pll1; i < maxclk; i++) {
+ atlas6_clks[i] = clk_register(NULL, atlas6_clk_hw_array[i]);
+ BUG_ON(!atlas6_clks[i]);
+ }
+ clk_register_clkdev(atlas6_clks[cpu], NULL, "cpu");
+ clk_register_clkdev(atlas6_clks[io], NULL, "io");
+ clk_register_clkdev(atlas6_clks[mem], NULL, "mem");
+ clk_register_clkdev(atlas6_clks[mem], NULL, "osc");
+
+ clk_data.clks = atlas6_clks;
+ clk_data.clk_num = maxclk;
+
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+}
+CLK_OF_DECLARE(atlas6_clk, "sirf,atlas6-clkc", atlas6_clk_init);
diff --git a/drivers/clk/clk-prima2.c b/drivers/clk/sirf/clk-common.c
similarity index 82%
rename from drivers/clk/clk-prima2.c
rename to drivers/clk/sirf/clk-common.c
index 6c15e33..7dde6a8 100644
--- a/drivers/clk/clk-prima2.c
+++ b/drivers/clk/sirf/clk-common.c
@@ -1,51 +1,18 @@
/*
- * Clock tree for CSR SiRFprimaII
+ * common clks module for all SiRF SoCs
*
* Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
*
* Licensed under GPLv2 or later.
*/
-#include <linux/module.h>
-#include <linux/bitops.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/clkdev.h>
-#include <linux/clk-provider.h>
-#include <linux/of_address.h>
-#include <linux/syscore_ops.h>
-
-#define SIRFSOC_CLKC_CLK_EN0 0x0000
-#define SIRFSOC_CLKC_CLK_EN1 0x0004
-#define SIRFSOC_CLKC_REF_CFG 0x0014
-#define SIRFSOC_CLKC_CPU_CFG 0x0018
-#define SIRFSOC_CLKC_MEM_CFG 0x001c
-#define SIRFSOC_CLKC_SYS_CFG 0x0020
-#define SIRFSOC_CLKC_IO_CFG 0x0024
-#define SIRFSOC_CLKC_DSP_CFG 0x0028
-#define SIRFSOC_CLKC_GFX_CFG 0x002c
-#define SIRFSOC_CLKC_MM_CFG 0x0030
-#define SIRFSOC_CLKC_LCD_CFG 0x0034
-#define SIRFSOC_CLKC_MMC_CFG 0x0038
-#define SIRFSOC_CLKC_PLL1_CFG0 0x0040
-#define SIRFSOC_CLKC_PLL2_CFG0 0x0044
-#define SIRFSOC_CLKC_PLL3_CFG0 0x0048
-#define SIRFSOC_CLKC_PLL1_CFG1 0x004c
-#define SIRFSOC_CLKC_PLL2_CFG1 0x0050
-#define SIRFSOC_CLKC_PLL3_CFG1 0x0054
-#define SIRFSOC_CLKC_PLL1_CFG2 0x0058
-#define SIRFSOC_CLKC_PLL2_CFG2 0x005c
-#define SIRFSOC_CLKC_PLL3_CFG2 0x0060
-#define SIRFSOC_USBPHY_PLL_CTRL 0x0008
-#define SIRFSOC_USBPHY_PLL_POWERDOWN BIT(1)
-#define SIRFSOC_USBPHY_PLL_BYPASS BIT(2)
-#define SIRFSOC_USBPHY_PLL_LOCK BIT(3)
-
-static void *sirfsoc_clk_vbase, *sirfsoc_rsc_vbase;
-
#define KHZ 1000
#define MHZ (KHZ * KHZ)
+static void *sirfsoc_clk_vbase;
+static void *sirfsoc_rsc_vbase;
+static struct clk_onecell_data clk_data;
+
/*
* SiRFprimaII clock controller
* - 2 oscillators: osc-26MHz, rtc-32.768KHz
@@ -127,6 +94,7 @@ static long pll_clk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
unsigned long fin, nf, nr, od;
+ u64 dividend;
/*
* fout = fin * nf / (nr * od);
@@ -147,7 +115,10 @@ static long pll_clk_round_rate(struct clk_hw *hw, unsigned long rate,
nr = BIT(6);
od = 1;
- return fin * nf / (nr * od);
+ dividend = (u64)fin * nf;
+ do_div(dividend, nr * od);
+
+ return (long)dividend;
}
static int pll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -186,6 +157,30 @@ static int pll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
return 0;
}
+static long cpu_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ /*
+ * SiRF SoC has not cpu clock control,
+ * So bypass to it's parent pll.
+ */
+ struct clk *parent_clk = clk_get_parent(hw->clk);
+ struct clk *pll_parent_clk = clk_get_parent(parent_clk);
+ unsigned long pll_parent_rate = clk_get_rate(pll_parent_clk);
+ return pll_clk_round_rate(__clk_get_hw(parent_clk), rate, &pll_parent_rate);
+}
+
+static unsigned long cpu_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ /*
+ * SiRF SoC has not cpu clock control,
+ * So return the parent pll rate.
+ */
+ struct clk *parent_clk = clk_get_parent(hw->clk);
+ return __clk_get_rate(parent_clk);
+}
+
static struct clk_ops std_pll_ops = {
.recalc_rate = pll_clk_recalc_rate,
.round_rate = pll_clk_round_rate,
@@ -403,6 +398,42 @@ static int dmn_clk_set_rate(struct clk_hw *hw, unsigned long rate,
return 0;
}
+static int cpu_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ int ret1, ret2;
+ struct clk *cur_parent;
+
+ if (rate == clk_get_rate(clk_pll1.hw.clk)) {
+ ret1 = clk_set_parent(hw->clk, clk_pll1.hw.clk);
+ return ret1;
+ }
+
+ if (rate == clk_get_rate(clk_pll2.hw.clk)) {
+ ret1 = clk_set_parent(hw->clk, clk_pll2.hw.clk);
+ return ret1;
+ }
+
+ if (rate == clk_get_rate(clk_pll3.hw.clk)) {
+ ret1 = clk_set_parent(hw->clk, clk_pll3.hw.clk);
+ return ret1;
+ }
+
+ cur_parent = clk_get_parent(hw->clk);
+
+ /* switch to tmp pll before setting parent clock's rate */
+ if (cur_parent == clk_pll1.hw.clk) {
+ ret1 = clk_set_parent(hw->clk, clk_pll2.hw.clk);
+ BUG_ON(ret1);
+ }
+
+ ret2 = clk_set_rate(clk_pll1.hw.clk, rate);
+
+ ret1 = clk_set_parent(hw->clk, clk_pll1.hw.clk);
+
+ return ret2 ? ret2 : ret1;
+}
+
static struct clk_ops msi_ops = {
.set_rate = dmn_clk_set_rate,
.round_rate = dmn_clk_round_rate,
@@ -457,6 +488,9 @@ static struct clk_dmn clk_io = {
static struct clk_ops cpu_ops = {
.set_parent = dmn_clk_set_parent,
.get_parent = dmn_clk_get_parent,
+ .set_rate = cpu_clk_set_rate,
+ .round_rate = cpu_clk_round_rate,
+ .recalc_rate = cpu_clk_recalc_rate,
};
static struct clk_init_data clk_cpu_init = {
@@ -532,6 +566,11 @@ static struct clk_dmn clk_mm = {
},
};
+/*
+ * for atlas6, gfx2d holds the bit of prima2's clk_mm
+ */
+#define clk_gfx2d clk_mm
+
static struct clk_init_data clk_lcd_init = {
.name = "lcd",
.ops = &dmn_ops,
@@ -569,14 +608,6 @@ static struct clk_init_data clk_mmc01_init = {
.num_parents = ARRAY_SIZE(dmn_clk_parents),
};
-static struct clk_dmn clk_mmc01 = {
- .regofs = SIRFSOC_CLKC_MMC_CFG,
- .enable_bit = 59,
- .hw = {
- .init = &clk_mmc01_init,
- },
-};
-
static struct clk_init_data clk_mmc23_init = {
.name = "mmc23",
.ops = &dmn_ops,
@@ -584,14 +615,6 @@ static struct clk_init_data clk_mmc23_init = {
.num_parents = ARRAY_SIZE(dmn_clk_parents),
};
-static struct clk_dmn clk_mmc23 = {
- .regofs = SIRFSOC_CLKC_MMC_CFG,
- .enable_bit = 60,
- .hw = {
- .init = &clk_mmc23_init,
- },
-};
-
static struct clk_init_data clk_mmc45_init = {
.name = "mmc45",
.ops = &dmn_ops,
@@ -599,14 +622,6 @@ static struct clk_init_data clk_mmc45_init = {
.num_parents = ARRAY_SIZE(dmn_clk_parents),
};
-static struct clk_dmn clk_mmc45 = {
- .regofs = SIRFSOC_CLKC_MMC_CFG,
- .enable_bit = 61,
- .hw = {
- .init = &clk_mmc45_init,
- },
-};
-
/*
* peripheral controllers in io domain
*/
@@ -667,6 +682,20 @@ static struct clk_ops ios_ops = {
.disable = std_clk_disable,
};
+static struct clk_init_data clk_cphif_init = {
+ .name = "cphif",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_cphif = {
+ .enable_bit = 20,
+ .hw = {
+ .init = &clk_cphif_init,
+ },
+};
+
static struct clk_init_data clk_dmac0_init = {
.name = "dmac0",
.ops = &ios_ops,
@@ -695,20 +724,6 @@ static struct clk_std clk_dmac1 = {
},
};
-static struct clk_init_data clk_nand_init = {
- .name = "nand",
- .ops = &ios_ops,
- .parent_names = std_clk_io_parents,
- .num_parents = ARRAY_SIZE(std_clk_io_parents),
-};
-
-static struct clk_std clk_nand = {
- .enable_bit = 34,
- .hw = {
- .init = &clk_nand_init,
- },
-};
-
static struct clk_init_data clk_audio_init = {
.name = "audio",
.ops = &ios_ops,
@@ -970,7 +985,7 @@ static const char *std_clk_sys_parents[] = {
};
static struct clk_init_data clk_security_init = {
- .name = "mf",
+ .name = "security",
.ops = &ios_ops,
.parent_names = std_clk_sys_parents,
.num_parents = ARRAY_SIZE(std_clk_sys_parents),
@@ -1014,96 +1029,3 @@ static struct clk_std clk_usb1 = {
.init = &clk_usb1_init,
},
};
-
-enum prima2_clk_index {
- /* 0 1 2 3 4 5 6 7 8 9 */
- rtc, osc, pll1, pll2, pll3, mem, sys, security, dsp, gps,
- mf, io, cpu, uart0, uart1, uart2, tsc, i2c0, i2c1, spi0,
- spi1, pwmc, efuse, pulse, dmac0, dmac1, nand, audio, usp0, usp1,
- usp2, vip, gfx, mm, lcd, vpp, mmc01, mmc23, mmc45, usbpll,
- usb0, usb1, maxclk,
-};
-
-static struct clk_hw *prima2_clk_hw_array[maxclk] __initdata = {
- NULL, /* dummy */
- NULL,
- &clk_pll1.hw,
- &clk_pll2.hw,
- &clk_pll3.hw,
- &clk_mem.hw,
- &clk_sys.hw,
- &clk_security.hw,
- &clk_dsp.hw,
- &clk_gps.hw,
- &clk_mf.hw,
- &clk_io.hw,
- &clk_cpu.hw,
- &clk_uart0.hw,
- &clk_uart1.hw,
- &clk_uart2.hw,
- &clk_tsc.hw,
- &clk_i2c0.hw,
- &clk_i2c1.hw,
- &clk_spi0.hw,
- &clk_spi1.hw,
- &clk_pwmc.hw,
- &clk_efuse.hw,
- &clk_pulse.hw,
- &clk_dmac0.hw,
- &clk_dmac1.hw,
- &clk_nand.hw,
- &clk_audio.hw,
- &clk_usp0.hw,
- &clk_usp1.hw,
- &clk_usp2.hw,
- &clk_vip.hw,
- &clk_gfx.hw,
- &clk_mm.hw,
- &clk_lcd.hw,
- &clk_vpp.hw,
- &clk_mmc01.hw,
- &clk_mmc23.hw,
- &clk_mmc45.hw,
- &usb_pll_clk_hw,
- &clk_usb0.hw,
- &clk_usb1.hw,
-};
-
-static struct clk *prima2_clks[maxclk];
-static struct clk_onecell_data clk_data;
-
-static void __init sirfsoc_clk_init(struct device_node *np)
-{
- struct device_node *rscnp;
- int i;
-
- rscnp = of_find_compatible_node(NULL, NULL, "sirf,prima2-rsc");
- sirfsoc_rsc_vbase = of_iomap(rscnp, 0);
- if (!sirfsoc_rsc_vbase)
- panic("unable to map rsc registers\n");
- of_node_put(rscnp);
-
- sirfsoc_clk_vbase = of_iomap(np, 0);
- if (!sirfsoc_clk_vbase)
- panic("unable to map clkc registers\n");
-
- /* These are always available (RTC and 26MHz OSC)*/
- prima2_clks[rtc] = clk_register_fixed_rate(NULL, "rtc", NULL,
- CLK_IS_ROOT, 32768);
- prima2_clks[osc]= clk_register_fixed_rate(NULL, "osc", NULL,
- CLK_IS_ROOT, 26000000);
-
- for (i = pll1; i < maxclk; i++) {
- prima2_clks[i] = clk_register(NULL, prima2_clk_hw_array[i]);
- BUG_ON(IS_ERR(prima2_clks[i]));
- }
- clk_register_clkdev(prima2_clks[cpu], NULL, "cpu");
- clk_register_clkdev(prima2_clks[io], NULL, "io");
- clk_register_clkdev(prima2_clks[mem], NULL, "mem");
-
- clk_data.clks = prima2_clks;
- clk_data.clk_num = maxclk;
-
- of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
-}
-CLK_OF_DECLARE(sirfsoc_clk, "sirf,prima2-clkc", sirfsoc_clk_init);
diff --git a/drivers/clk/sirf/clk-prima2.c b/drivers/clk/sirf/clk-prima2.c
new file mode 100644
index 0000000..7adc5c7
--- /dev/null
+++ b/drivers/clk/sirf/clk-prima2.c
@@ -0,0 +1,151 @@
+/*
+ * Clock tree for CSR SiRFprimaII
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
+
+#include "prima2.h"
+#include "clk-common.c"
+
+static struct clk_dmn clk_mmc01 = {
+ .regofs = SIRFSOC_CLKC_MMC_CFG,
+ .enable_bit = 59,
+ .hw = {
+ .init = &clk_mmc01_init,
+ },
+};
+
+static struct clk_dmn clk_mmc23 = {
+ .regofs = SIRFSOC_CLKC_MMC_CFG,
+ .enable_bit = 60,
+ .hw = {
+ .init = &clk_mmc23_init,
+ },
+};
+
+static struct clk_dmn clk_mmc45 = {
+ .regofs = SIRFSOC_CLKC_MMC_CFG,
+ .enable_bit = 61,
+ .hw = {
+ .init = &clk_mmc45_init,
+ },
+};
+
+static struct clk_init_data clk_nand_init = {
+ .name = "nand",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_nand = {
+ .enable_bit = 34,
+ .hw = {
+ .init = &clk_nand_init,
+ },
+};
+
+enum prima2_clk_index {
+ /* 0 1 2 3 4 5 6 7 8 9 */
+ rtc, osc, pll1, pll2, pll3, mem, sys, security, dsp, gps,
+ mf, io, cpu, uart0, uart1, uart2, tsc, i2c0, i2c1, spi0,
+ spi1, pwmc, efuse, pulse, dmac0, dmac1, nand, audio, usp0, usp1,
+ usp2, vip, gfx, mm, lcd, vpp, mmc01, mmc23, mmc45, usbpll,
+ usb0, usb1, cphif, maxclk,
+};
+
+static __initdata struct clk_hw *prima2_clk_hw_array[maxclk] = {
+ NULL, /* dummy */
+ NULL,
+ &clk_pll1.hw,
+ &clk_pll2.hw,
+ &clk_pll3.hw,
+ &clk_mem.hw,
+ &clk_sys.hw,
+ &clk_security.hw,
+ &clk_dsp.hw,
+ &clk_gps.hw,
+ &clk_mf.hw,
+ &clk_io.hw,
+ &clk_cpu.hw,
+ &clk_uart0.hw,
+ &clk_uart1.hw,
+ &clk_uart2.hw,
+ &clk_tsc.hw,
+ &clk_i2c0.hw,
+ &clk_i2c1.hw,
+ &clk_spi0.hw,
+ &clk_spi1.hw,
+ &clk_pwmc.hw,
+ &clk_efuse.hw,
+ &clk_pulse.hw,
+ &clk_dmac0.hw,
+ &clk_dmac1.hw,
+ &clk_nand.hw,
+ &clk_audio.hw,
+ &clk_usp0.hw,
+ &clk_usp1.hw,
+ &clk_usp2.hw,
+ &clk_vip.hw,
+ &clk_gfx.hw,
+ &clk_mm.hw,
+ &clk_lcd.hw,
+ &clk_vpp.hw,
+ &clk_mmc01.hw,
+ &clk_mmc23.hw,
+ &clk_mmc45.hw,
+ &usb_pll_clk_hw,
+ &clk_usb0.hw,
+ &clk_usb1.hw,
+ &clk_cphif.hw,
+};
+
+static struct clk *prima2_clks[maxclk];
+
+static void __init prima2_clk_init(struct device_node *np)
+{
+ struct device_node *rscnp;
+ int i;
+
+ rscnp = of_find_compatible_node(NULL, NULL, "sirf,prima2-rsc");
+ sirfsoc_rsc_vbase = of_iomap(rscnp, 0);
+ if (!sirfsoc_rsc_vbase)
+ panic("unable to map rsc registers\n");
+ of_node_put(rscnp);
+
+ sirfsoc_clk_vbase = of_iomap(np, 0);
+ if (!sirfsoc_clk_vbase)
+ panic("unable to map clkc registers\n");
+
+ /* These are always available (RTC and 26MHz OSC)*/
+ prima2_clks[rtc] = clk_register_fixed_rate(NULL, "rtc", NULL,
+ CLK_IS_ROOT, 32768);
+ prima2_clks[osc] = clk_register_fixed_rate(NULL, "osc", NULL,
+ CLK_IS_ROOT, 26000000);
+
+ for (i = pll1; i < maxclk; i++) {
+ prima2_clks[i] = clk_register(NULL, prima2_clk_hw_array[i]);
+ BUG_ON(!prima2_clks[i]);
+ }
+ clk_register_clkdev(prima2_clks[cpu], NULL, "cpu");
+ clk_register_clkdev(prima2_clks[io], NULL, "io");
+ clk_register_clkdev(prima2_clks[mem], NULL, "mem");
+ clk_register_clkdev(prima2_clks[mem], NULL, "osc");
+
+ clk_data.clks = prima2_clks;
+ clk_data.clk_num = maxclk;
+
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+}
+CLK_OF_DECLARE(prima2_clk, "sirf,prima2-clkc", prima2_clk_init);
diff --git a/drivers/clk/sirf/prima2.h b/drivers/clk/sirf/prima2.h
new file mode 100644
index 0000000..01bc385
--- /dev/null
+++ b/drivers/clk/sirf/prima2.h
@@ -0,0 +1,25 @@
+#define SIRFSOC_CLKC_CLK_EN0 0x0000
+#define SIRFSOC_CLKC_CLK_EN1 0x0004
+#define SIRFSOC_CLKC_REF_CFG 0x0014
+#define SIRFSOC_CLKC_CPU_CFG 0x0018
+#define SIRFSOC_CLKC_MEM_CFG 0x001c
+#define SIRFSOC_CLKC_SYS_CFG 0x0020
+#define SIRFSOC_CLKC_IO_CFG 0x0024
+#define SIRFSOC_CLKC_DSP_CFG 0x0028
+#define SIRFSOC_CLKC_GFX_CFG 0x002c
+#define SIRFSOC_CLKC_MM_CFG 0x0030
+#define SIRFSOC_CLKC_LCD_CFG 0x0034
+#define SIRFSOC_CLKC_MMC_CFG 0x0038
+#define SIRFSOC_CLKC_PLL1_CFG0 0x0040
+#define SIRFSOC_CLKC_PLL2_CFG0 0x0044
+#define SIRFSOC_CLKC_PLL3_CFG0 0x0048
+#define SIRFSOC_CLKC_PLL1_CFG1 0x004c
+#define SIRFSOC_CLKC_PLL2_CFG1 0x0050
+#define SIRFSOC_CLKC_PLL3_CFG1 0x0054
+#define SIRFSOC_CLKC_PLL1_CFG2 0x0058
+#define SIRFSOC_CLKC_PLL2_CFG2 0x005c
+#define SIRFSOC_CLKC_PLL3_CFG2 0x0060
+#define SIRFSOC_USBPHY_PLL_CTRL 0x0008
+#define SIRFSOC_USBPHY_PLL_POWERDOWN BIT(1)
+#define SIRFSOC_USBPHY_PLL_BYPASS BIT(2)
+#define SIRFSOC_USBPHY_PLL_LOCK BIT(3)
--
1.7.5.4
^ permalink raw reply related
* [PATCH] ARM: dts: imx6qdl-sabreauto: Add LVDS support
From: Shawn Guo @ 2014-01-15 6:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1389739887-21272-1-git-send-email-festevam@gmail.com>
On Tue, Jan 14, 2014 at 08:51:27PM -0200, Fabio Estevam wrote:
> From: Fabio Estevam <fabio.estevam@freescale.com>
>
> Add LVDS support for mx6 sabreauto boards.
I would stall imx-drm device addition for a while, as the ongoing
componentised imx-drm transition will require some incompatible changes.
Shawn
>
> Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
> ---
> arch/arm/boot/dts/imx6qdl-sabreauto.dtsi | 43 ++++++++++++++++++++++++++++++++
> 1 file changed, 43 insertions(+)
>
> diff --git a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
> index 088b0d2..47c5a3f 100644
> --- a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
> +++ b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
> @@ -22,6 +22,14 @@
> spdif-controller = <&spdif>;
> spdif-in;
> };
> +
> + backlight {
> + compatible = "pwm-backlight";
> + pwms = <&pwm3 0 5000000>;
> + brightness-levels = <0 4 8 16 32 64 128 255>;
> + default-brightness-level = <7>;
> + status = "okay";
> + };
> };
>
> &ecspi1 {
> @@ -86,6 +94,10 @@
> fsl,pins = <MX6QDL_GPMI_NAND_PINGRP1>;
> };
>
> + pinctrl_pwm3: pwm1grp {
> + fsl,pins = <MX6QDL_PWM3_PINGRP1>;
> + };
> +
> pinctrl_spdif: spdifgrp {
> fsl,pins = <
> MX6QDL_PAD_KEY_COL3__SPDIF_IN 0x1b0b0
> @@ -118,6 +130,37 @@
> };
> };
>
> +&ldb {
> + status = "okay";
> +
> + lvds-channel at 0 {
> + fsl,data-mapping = "spwg";
> + fsl,data-width = <18>;
> + status = "okay";
> +
> + display-timings {
> + native-mode = <&timing0>;
> + timing0: hsd100pxn1 {
> + clock-frequency = <65000000>;
> + hactive = <1024>;
> + vactive = <768>;
> + hback-porch = <220>;
> + hfront-porch = <40>;
> + vback-porch = <21>;
> + vfront-porch = <7>;
> + hsync-len = <60>;
> + vsync-len = <10>;
> + };
> + };
> + };
> +};
> +
> +&pwm3 {
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_pwm3>;
> + status = "okay";
> +};
> +
> &spdif {
> pinctrl-names = "default";
> pinctrl-0 = <&pinctrl_spdif>;
> --
> 1.8.1.2
>
^ permalink raw reply
* [PATCH v5 0/4] Add ethernet support for r7s72100
From: Simon Horman @ 2014-01-15 6:12 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
this series adds ethernet support to sh-pfc for the r7s72100 SoC.
This series is based on a merge of:
* The topic/r7s72100-v3.13-rc8-20140115 tag in my renesas tree
* net-next
- Head revision: 08c93cd99b2f31ba9
("Merge branch 'for-davem' of git://gitorious.org/linux-can/linux-can-next")
The first two patches, targeted at net-next, also applies cleanly there.
Changes since v4
* Addressed feedback from Sergei Shtylyov as detailed in the changelog
of "sh_eth: Add support for r7s72100"
* Rebase
Changes since v3
* Use bool as return type of sh_eth_is_gether()
and sh_eth_is_rz_fast_ether()
* Correct coding style in sh_eth_get_stats()
Changes since v2
* Trivial rebase
* Dropped "RFC" from subject
Changes since v1 are noted in the changelog of each patch.
Simon Horman (4):
sh_eth: Use bool as return type of sh_eth_is_gether()
sh_eth: Add support for r7s72100
ARM: shmobile: r7s72100: Add clock for r7s72100-ether
ARM: shmobile: genmai: Enable r7s72100-ether
arch/arm/mach-shmobile/board-genmai.c | 21 +++++
arch/arm/mach-shmobile/clock-r7s72100.c | 4 +
drivers/net/ethernet/renesas/sh_eth.c | 132 +++++++++++++++++++++++++++++---
drivers/net/ethernet/renesas/sh_eth.h | 3 +-
4 files changed, 149 insertions(+), 11 deletions(-)
--
1.8.4
^ permalink raw reply
* [PATCH v5 net-next 1/4] sh_eth: Use bool as return type of sh_eth_is_gether()
From: Simon Horman @ 2014-01-15 6:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1389766341-14001-1-git-send-email-horms+renesas@verge.net.au>
Return a boolean and use true and false.
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
---
v5
* No change
v4
* First post
---
drivers/net/ethernet/renesas/sh_eth.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index ba1f6c9..4f5cfad 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -310,12 +310,12 @@ static const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = {
[TSU_ADRL31] = 0x01fc,
};
-static int sh_eth_is_gether(struct sh_eth_private *mdp)
+static bool sh_eth_is_gether(struct sh_eth_private *mdp)
{
if (mdp->reg_offset == sh_eth_offset_gigabit)
- return 1;
+ return true;
else
- return 0;
+ return false;
}
static void sh_eth_select_mii(struct net_device *ndev)
--
1.8.4
^ permalink raw reply related
* [PATCH v5 net-next 2/4] sh_eth: Add support for r7s72100
From: Simon Horman @ 2014-01-15 6:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1389766341-14001-1-git-send-email-horms+renesas@verge.net.au>
This is a fast ethernet controller.
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
---
v5
* As suggested by Sergei Shtylyov
- Do not use sh_eth_chip_reset_r8a7740 as it accesses non-existent
RMII registers. Instead use sh_eth_chip_reset.
- Do not use sh_eth_set_rate_gether as it accesses non-existent registers.
- Do not use reserved LCHNG bit of ECSR
- Do not use reserved LCHNGIP bit of ECSIPR
- Document that R8A779x also needs a 16 bit shift of the RFS bits
- Do not document that the R7S72100 has GECMR, it does not
v4
* As requested by David Miller
- Use a boolean for the return value of sh_eth_is_rz_fast_ether()
- Correct coding style in sh_eth_get_stats()
v3
* No change
v2
* As suggested by Magnus Damm and Sergei Shtylyov
- r7s72100 ethernet is not gigabit so do not refer to it as such
* As suggested by Magnus Damm
- As RZ specific register layout rather than using the gigabit layout
which includes registers that do not exist on this chip.
---
drivers/net/ethernet/renesas/sh_eth.c | 126 ++++++++++++++++++++++++++++++++--
drivers/net/ethernet/renesas/sh_eth.h | 3 +-
2 files changed, 121 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index 4f5cfad..a7a0555 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -190,6 +190,64 @@ static const u16 sh_eth_offset_fast_rcar[SH_ETH_MAX_REGISTER_OFFSET] = {
[TRIMD] = 0x027c,
};
+static const u16 sh_eth_offset_fast_rz[SH_ETH_MAX_REGISTER_OFFSET] = {
+ [EDSR] = 0x0000,
+ [EDMR] = 0x0400,
+ [EDTRR] = 0x0408,
+ [EDRRR] = 0x0410,
+ [EESR] = 0x0428,
+ [EESIPR] = 0x0430,
+ [TDLAR] = 0x0010,
+ [TDFAR] = 0x0014,
+ [TDFXR] = 0x0018,
+ [TDFFR] = 0x001c,
+ [RDLAR] = 0x0030,
+ [RDFAR] = 0x0034,
+ [RDFXR] = 0x0038,
+ [RDFFR] = 0x003c,
+ [TRSCER] = 0x0438,
+ [RMFCR] = 0x0440,
+ [TFTR] = 0x0448,
+ [FDR] = 0x0450,
+ [RMCR] = 0x0458,
+ [RPADIR] = 0x0460,
+ [FCFTR] = 0x0468,
+ [CSMR] = 0x04E4,
+
+ [ECMR] = 0x0500,
+ [RFLR] = 0x0508,
+ [ECSR] = 0x0510,
+ [ECSIPR] = 0x0518,
+ [PIR] = 0x0520,
+ [APR] = 0x0554,
+ [MPR] = 0x0558,
+ [PFTCR] = 0x055c,
+ [PFRCR] = 0x0560,
+ [TPAUSER] = 0x0564,
+ [MAHR] = 0x05c0,
+ [MALR] = 0x05c8,
+ [CEFCR] = 0x0740,
+ [FRECR] = 0x0748,
+ [TSFRCR] = 0x0750,
+ [TLFRCR] = 0x0758,
+ [RFCR] = 0x0760,
+ [MAFCR] = 0x0778,
+
+ [ARSTR] = 0x0000,
+ [TSU_CTRST] = 0x0004,
+ [TSU_VTAG0] = 0x0058,
+ [TSU_ADSBSY] = 0x0060,
+ [TSU_TEN] = 0x0064,
+ [TXNLCR0] = 0x0080,
+ [TXALCR0] = 0x0084,
+ [RXNLCR0] = 0x0088,
+ [RXALCR0] = 0x008C,
+ [TSU_ADRH0] = 0x0100,
+ [TSU_ADRL0] = 0x0104,
+ [TSU_ADRH31] = 0x01f8,
+ [TSU_ADRL31] = 0x01fc,
+};
+
static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = {
[ECMR] = 0x0100,
[RFLR] = 0x0108,
@@ -318,6 +376,14 @@ static bool sh_eth_is_gether(struct sh_eth_private *mdp)
return false;
}
+static bool sh_eth_is_rz_fast_ether(struct sh_eth_private *mdp)
+{
+ if (mdp->reg_offset == sh_eth_offset_fast_rz)
+ return true;
+ else
+ return false;
+}
+
static void sh_eth_select_mii(struct net_device *ndev)
{
u32 value = 0x0;
@@ -701,6 +767,38 @@ static struct sh_eth_cpu_data r8a7740_data = {
.shift_rd0 = 1,
};
+/* R7S72100 */
+static struct sh_eth_cpu_data r7s72100_data = {
+ .chip_reset = sh_eth_chip_reset,
+ .set_duplex = sh_eth_set_duplex,
+
+ .register_type = SH_ETH_REG_FAST_RZ,
+
+ .ecsr_value = ECSR_ICD,
+ .ecsipr_value = ECSIPR_ICDIP,
+ .eesipr_value = 0xff7f009f,
+
+ .tx_check = EESR_TC1 | EESR_FTC,
+ .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
+ EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE |
+ EESR_TDE | EESR_ECI,
+ .fdr_value = 0x0000070f,
+ .rmcr_value = RMCR_RNC,
+
+ .no_psr = 1,
+ .apr = 1,
+ .mpr = 1,
+ .tpauser = 1,
+ .hw_swap = 1,
+ .rpadir = 1,
+ .rpadir_value = 2 << 16,
+ .no_trimd = 1,
+ .no_ade = 1,
+ .hw_crc = 1,
+ .tsu = 1,
+ .shift_rd0 = 1,
+};
+
static struct sh_eth_cpu_data sh7619_data = {
.register_type = SH_ETH_REG_FAST_SH3_SH2,
@@ -767,7 +865,7 @@ static int sh_eth_reset(struct net_device *ndev)
struct sh_eth_private *mdp = netdev_priv(ndev);
int ret = 0;
- if (sh_eth_is_gether(mdp)) {
+ if (sh_eth_is_gether(mdp) || sh_eth_is_rz_fast_ether(mdp)) {
sh_eth_write(ndev, EDSR_ENALL, EDSR);
sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER,
EDMR);
@@ -878,7 +976,7 @@ static void read_mac_address(struct net_device *ndev, unsigned char *mac)
static unsigned long sh_eth_get_edtrr_trns(struct sh_eth_private *mdp)
{
- if (sh_eth_is_gether(mdp))
+ if (sh_eth_is_gether(mdp) || sh_eth_is_rz_fast_ether(mdp))
return EDTRR_TRNS_GETHER;
else
return EDTRR_TRNS_ETHER;
@@ -1041,7 +1139,8 @@ static void sh_eth_ring_format(struct net_device *ndev)
/* Rx descriptor address set */
if (i == 0) {
sh_eth_write(ndev, mdp->rx_desc_dma, RDLAR);
- if (sh_eth_is_gether(mdp))
+ if (sh_eth_is_gether(mdp) ||
+ sh_eth_is_rz_fast_ether(mdp))
sh_eth_write(ndev, mdp->rx_desc_dma, RDFAR);
}
}
@@ -1062,7 +1161,8 @@ static void sh_eth_ring_format(struct net_device *ndev)
if (i == 0) {
/* Tx descriptor address set */
sh_eth_write(ndev, mdp->tx_desc_dma, TDLAR);
- if (sh_eth_is_gether(mdp))
+ if (sh_eth_is_gether(mdp) ||
+ sh_eth_is_rz_fast_ether(mdp))
sh_eth_write(ndev, mdp->tx_desc_dma, TDFAR);
}
}
@@ -1309,9 +1409,9 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
/* In case of almost all GETHER/ETHERs, the Receive Frame State
* (RFS) bits in the Receive Descriptor 0 are from bit 9 to
- * bit 0. However, in case of the R8A7740's GETHER, the RFS
- * bits are from bit 25 to bit 16. So, the driver needs right
- * shifting by 16.
+ * bit 0. However, in case of the R8A7740, R8A779x and
+ * R7S72100 the RFS bits are from bit 25 to bit 16. So, the
+ * driver needs right shifting by 16.
*/
if (mdp->cd->shift_rd0)
desc_status >>= 16;
@@ -2061,6 +2161,9 @@ static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
+ if (sh_eth_is_rz_fast_ether(mdp))
+ return &ndev->stats;
+
pm_runtime_get_sync(&mdp->pdev->dev);
ndev->stats.tx_dropped += sh_eth_read(ndev, TROCR);
@@ -2442,6 +2545,11 @@ static int sh_eth_vlan_rx_kill_vid(struct net_device *ndev,
/* SuperH's TSU register init function */
static void sh_eth_tsu_init(struct sh_eth_private *mdp)
{
+ if (sh_eth_is_rz_fast_ether(mdp)) {
+ sh_eth_tsu_write(mdp, 0, TSU_TEN); /* Disable all CAM entry */
+ return;
+ }
+
sh_eth_tsu_write(mdp, 0, TSU_FWEN0); /* Disable forward(0->1) */
sh_eth_tsu_write(mdp, 0, TSU_FWEN1); /* Disable forward(1->0) */
sh_eth_tsu_write(mdp, 0, TSU_FCM); /* forward fifo 3k-3k */
@@ -2561,6 +2669,9 @@ static const u16 *sh_eth_get_register_offset(int register_type)
case SH_ETH_REG_GIGABIT:
reg_offset = sh_eth_offset_gigabit;
break;
+ case SH_ETH_REG_FAST_RZ:
+ reg_offset = sh_eth_offset_fast_rz;
+ break;
case SH_ETH_REG_FAST_RCAR:
reg_offset = sh_eth_offset_fast_rcar;
break;
@@ -2799,6 +2910,7 @@ static struct platform_device_id sh_eth_id_table[] = {
{ "sh7757-ether", (kernel_ulong_t)&sh7757_data },
{ "sh7757-gether", (kernel_ulong_t)&sh7757_data_giga },
{ "sh7763-gether", (kernel_ulong_t)&sh7763_data },
+ { "r7s72100-ether", (kernel_ulong_t)&r7s72100_data },
{ "r8a7740-gether", (kernel_ulong_t)&r8a7740_data },
{ "r8a777x-ether", (kernel_ulong_t)&r8a777x_data },
{ "r8a7790-ether", (kernel_ulong_t)&r8a779x_data },
diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h
index 0fe35b7..6075915 100644
--- a/drivers/net/ethernet/renesas/sh_eth.h
+++ b/drivers/net/ethernet/renesas/sh_eth.h
@@ -155,6 +155,7 @@ enum {
enum {
SH_ETH_REG_GIGABIT,
+ SH_ETH_REG_FAST_RZ,
SH_ETH_REG_FAST_RCAR,
SH_ETH_REG_FAST_SH4,
SH_ETH_REG_FAST_SH3_SH2
@@ -169,7 +170,7 @@ enum {
/* Register's bits
*/
-/* EDSR : sh7734, sh7757, sh7763, and r8a7740 only */
+/* EDSR : sh7734, sh7757, sh7763, r8a7740, and r7s72100 only */
enum EDSR_BIT {
EDSR_ENT = 0x01, EDSR_ENR = 0x02,
};
--
1.8.4
^ permalink raw reply related
* [PATCH v5 3/4] ARM: shmobile: r7s72100: Add clock for r7s72100-ether
From: Simon Horman @ 2014-01-15 6:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1389766341-14001-1-git-send-email-horms+renesas@verge.net.au>
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
Acked-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
---
Dave,
I plan to take this change through my tree.
v5
* Rebase
v3 - v4
* No change
v2
* As suggested by Sergei Shtylyov
- Add MSTP74 to beginning of enum on a line by itself
* As suggested by Magnus Damm
- r7s72100 ethernet is not gigabit so do not refer to it as such
---
arch/arm/mach-shmobile/clock-r7s72100.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/mach-shmobile/clock-r7s72100.c b/arch/arm/mach-shmobile/clock-r7s72100.c
index dd8ce87..0242ca5 100644
--- a/arch/arm/mach-shmobile/clock-r7s72100.c
+++ b/arch/arm/mach-shmobile/clock-r7s72100.c
@@ -27,6 +27,7 @@
#define FRQCR2 0xfcfe0014
#define STBCR3 0xfcfe0420
#define STBCR4 0xfcfe0424
+#define STBCR7 0xfcfe0430
#define STBCR9 0xfcfe0438
#define PLL_RATE 30
@@ -146,6 +147,7 @@ struct clk div4_clks[DIV4_NR] = {
};
enum { MSTP97, MSTP96, MSTP95, MSTP94,
+ MSTP74,
MSTP47, MSTP46, MSTP45, MSTP44, MSTP43, MSTP42, MSTP41, MSTP40,
MSTP33, MSTP_NR };
@@ -154,6 +156,7 @@ static struct clk mstp_clks[MSTP_NR] = {
[MSTP96] = SH_CLK_MSTP8(&peripheral0_clk, STBCR9, 6, 0), /* RIIC1 */
[MSTP95] = SH_CLK_MSTP8(&peripheral0_clk, STBCR9, 5, 0), /* RIIC2 */
[MSTP94] = SH_CLK_MSTP8(&peripheral0_clk, STBCR9, 4, 0), /* RIIC3 */
+ [MSTP74] = SH_CLK_MSTP8(&peripheral1_clk, STBCR7, 4, 0), /* Ether */
[MSTP47] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 7, 0), /* SCIF0 */
[MSTP46] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 6, 0), /* SCIF1 */
[MSTP45] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 5, 0), /* SCIF2 */
@@ -180,6 +183,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("fcfee400.i2c", &mstp_clks[MSTP96]),
CLKDEV_DEV_ID("fcfee800.i2c", &mstp_clks[MSTP95]),
CLKDEV_DEV_ID("fcfeec00.i2c", &mstp_clks[MSTP94]),
+ CLKDEV_DEV_ID("r7s72100-ether", &mstp_clks[MSTP74]),
CLKDEV_CON_ID("mtu2_fck", &mstp_clks[MSTP33]),
/* ICK */
--
1.8.4
^ permalink raw reply related
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