* RE: MSR_SPE - being turned off...
From: Morrison, Tom @ 2009-05-06 12:42 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev, Michael Neuling
In-Reply-To: <343F1A10-459E-4024-B0DD-ADB1D6DCDB9D@kernel.crashing.org>
I'm sorry I forgot to put that, this issue was found with our=20
currently running kernel 2.6.23.final (what comes with the=20
Freescale LTIB BSP package dated 05/23/2009).=20
I am sorry if I don't understand your statement that the SMP might
be broken on this kernel, because I tried to analyze the kernel that=20
came with the latest BSP LTIB [ackage from Freescale (dated 12/18/2009=20
(where we got the 4.2.171 compiler from)), and the associated 'switch=20
context' code is exactly the same. Unfortunately, I have not started=20
the process of porting my current platform's BSP to this new kernel -=20
otherwise, I would have done the test on that platform (this also=20
requires a new version of u-boot in order to test correctly))..
I may have mis-interpreted something and/or I am sure I don't=20
understand everything about the SMP resource management (and=20
associated SPE management), so thank you for any insight you=20
may have on this front...
Tom
>> -----Original Message-----
>> From: Kumar Gala [mailto:galak@kernel.crashing.org]
>> Sent: Wednesday, May 06, 2009 8:32 AM
>> To: Morrison, Tom
>> Cc: Michael Neuling; linuxppc-dev@ozlabs.org
>> Subject: Re: MSR_SPE - being turned off...
>>=20
>>=20
>> On May 6, 2009, at 3:31 AM, Morrison, Tom wrote:
>>=20
>> > Kumar,
>> >
>> > What about the case of a context switch (i.e.: when things are
setup
>> > in registers for the SPE, but then a context switch happens before
>> > the SPE is executed)?
>>=20
>> context switches will be fine. What we normally do is keep track of
>> which user app used SPE last and when some other app needs it we
clear
>> MSR_SPE for the old app, save its registers. Than we load up the
>> registers for the new app and set MSR_SPE. When the old app context
>> switches in it will get an SPE unavail exception at the point it
>> executes its next SPE insn and we will repeat the process.
>>=20
>> > As to load_up_spe & give_up_spe, it was pointed out to me tonight
by
>> > a co-worker
>> > to look at how things are saved in those routines, I definitely
will
>> > look at this again,
c>> > and see how it is done...
>> >
>> > This is happening for us on an 8572 SMP. We are trying to get it to
>> > happen
>> > on 8548 (and single core 8572), but we haven't been able to push
>> > this part
>> > of the application as hard as it is being pushed on 8572...but we
>> > will keep trying....
>>=20
>> Again, what kernel version for 8572? Its possible old SMP kernels
are
>> broken on 8572.
>>=20
>> - k
>>=20
>> > ________________________________
>> >
<snip previous emails>
^ permalink raw reply
* Re: MSR_SPE - being turned off...
From: Kumar Gala @ 2009-05-06 12:44 UTC (permalink / raw)
To: Morrison, Tom; +Cc: linuxppc-dev, Michael Neuling
In-Reply-To: <BD261180E6D35F4D9D32F3E44FD3D90110C94615@EMPBEDEX.empirix.com>
Can you describe the # of processes you are running in your test. Is
it possible for you to try the tests w/2.6.29 from kernel.org?
- k
On May 6, 2009, at 7:42 AM, Morrison, Tom wrote:
> I'm sorry I forgot to put that, this issue was found with our
> currently running kernel 2.6.23.final (what comes with the
> Freescale LTIB BSP package dated 05/23/2009).
>
> I am sorry if I don't understand your statement that the SMP might
> be broken on this kernel, because I tried to analyze the kernel that
> came with the latest BSP LTIB [ackage from Freescale (dated 12/18/2009
> (where we got the 4.2.171 compiler from)), and the associated 'switch
> context' code is exactly the same. Unfortunately, I have not started
> the process of porting my current platform's BSP to this new kernel -
> otherwise, I would have done the test on that platform (this also
> requires a new version of u-boot in order to test correctly))..
>
> I may have mis-interpreted something and/or I am sure I don't
> understand everything about the SMP resource management (and
> associated SPE management), so thank you for any insight you
> may have on this front...
>
> Tom
>
>>> -----Original Message-----
>>> From: Kumar Gala [mailto:galak@kernel.crashing.org]
>>> Sent: Wednesday, May 06, 2009 8:32 AM
>>> To: Morrison, Tom
>>> Cc: Michael Neuling; linuxppc-dev@ozlabs.org
>>> Subject: Re: MSR_SPE - being turned off...
>>>
>>>
>>> On May 6, 2009, at 3:31 AM, Morrison, Tom wrote:
>>>
>>>> Kumar,
>>>>
>>>> What about the case of a context switch (i.e.: when things are
> setup
>>>> in registers for the SPE, but then a context switch happens before
>>>> the SPE is executed)?
>>>
>>> context switches will be fine. What we normally do is keep track of
>>> which user app used SPE last and when some other app needs it we
> clear
>>> MSR_SPE for the old app, save its registers. Than we load up the
>>> registers for the new app and set MSR_SPE. When the old app context
>>> switches in it will get an SPE unavail exception at the point it
>>> executes its next SPE insn and we will repeat the process.
>>>
>>>> As to load_up_spe & give_up_spe, it was pointed out to me tonight
> by
>>>> a co-worker
>>>> to look at how things are saved in those routines, I definitely
> will
>>>> look at this again,
> c>> > and see how it is done...
>>>>
>>>> This is happening for us on an 8572 SMP. We are trying to get it to
>>>> happen
>>>> on 8548 (and single core 8572), but we haven't been able to push
>>>> this part
>>>> of the application as hard as it is being pushed on 8572...but we
>>>> will keep trying....
>>>
>>> Again, what kernel version for 8572? Its possible old SMP kernels
> are
>>> broken on 8572.
>>>
>>> - k
>>>
>>>> ________________________________
>>>>
> <snip previous emails>
^ permalink raw reply
* Re: [PATCH] powerpc/pci: clean up direct access to sysdata by iseries platform
From: Stephen Rothwell @ 2009-05-06 13:13 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev
In-Reply-To: <1241525095-18041-1-git-send-email-galak@kernel.crashing.org>
[-- Attachment #1: Type: text/plain, Size: 597 bytes --]
Hi Kumar,
On Tue, 5 May 2009 07:04:55 -0500 Kumar Gala <galak@kernel.crashing.org> wrote:
>
> We shouldn't directly access sysdata to get the device node. We should
> be calling pci_device_to_OF_node().
>
> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
It looks ok, but all I can say for now is that it doesn not make things
worse. During 2.6.28, the iSeries PCI code was broken. I am working on
a fix and after that I will be able to properly test this patch.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply
* 440SPE ADMA driver
From: Tirumala Reddy Marri @ 2009-05-06 15:32 UTC (permalink / raw)
To: Ilya Yanok, Josh Boyer; +Cc: linux-raid, linuxppc-dev, wd, dzu
In-Reply-To: <491C68F3.3030102@emcraft.com>
[-- Attachment #1: Type: text/plain, Size: 2294 bytes --]
Hi Ilya,
Are you going to push further in submitting the ADMA driver for 440SPE
? If you are not I am planning to pursue this effort. I also have
couple later version of Soc's needed to submit.
Thank and Regards,
Marri
From: linux-raid-owner@vger.kernel.org
[mailto:linux-raid-owner@vger.kernel.org] On Behalf Of Ilya Yanok
Sent: Thursday, November 13, 2008 9:51 AM
To: Josh Boyer
Cc:; dzu@denx.de; wd@denx.de
Subject: Re: [PATCH 11/11] ppc440spe-adma: ADMA driver for PPC440SP(e)
systems
This message has been archived. View the original item
<http://sdcmailvault.ad.amcc.com/EnterpriseVault/ViewMessage.asp?VaultId
=1E9560FDB597EB744B7F046F24F9462D91110000sdcmailvault.ad.amcc.com&Savese
tId=705000000000000~200811131750430000~2~2007F01CF3764FBC926BAD4B10FE5BC
>
Josh Boyer wrote:
> On Thu, Nov 13, 2008 at 06:16:04PM +0300, Ilya Yanok wrote:
>
>> Adds the platform device definitions and the architecture specific
support
>> routines for the ppc440spe adma driver.
>>
>> Any board equipped with PPC440SP(e) controller may utilize this
driver.
>>
>> Signed-off-by: Yuri Tikhonov <yur@emcraft.com>
>> Signed-off-by: Ilya Yanok <yanok@emcraft.com>
>>
>
> Before I really dig into reviewing this driver, I'm going to ask you
as simple
> question. This looks like a 1/2 completed port of an arch/ppc driver
that uses
> the device tree (incorrectly) to get the interrupt resources and
that's about it.
> Otherwise, it's just a straight up platform device driver. Is that
correct?
>
Yep, that's correct.
> If that is the case, I think the driver needs more work before it can
be merged.
> It should get the DCR and MMIO resources from the device tree as well.
It should
> be binding on compatible properties and not based on device tree
paths. And it
> should probably be an of_platform device driver.
>
Surely, you're right. I agree with you in that this driver isn't ready
for merging. But it works so we'd like to publish it so interested
people could use it and test it.
Regards, Ilya.
--
To unsubscribe from this list: send the line "unsubscribe linux-raid" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
[-- Attachment #2: Type: text/html, Size: 5830 bytes --]
^ permalink raw reply
* Re: [PATCH 1/2] Added support for Designware SATA controller driver
From: Feng Kan @ 2009-05-06 17:44 UTC (permalink / raw)
To: Scott Wood; +Cc: Mark Miesfeld, linuxppc-dev, linux-ide
In-Reply-To: <49FB68F2.10301@freescale.com>
Hi Scott:
I agree with your statement, however this driver is wrapped with this
AHB DMA controller.
It would be very hard for it to work on non 460EX platforms. I can
expand the depend in
the future if it is available on more cores.
Thanks
Feng Kan
Scott Wood wrote:
> Feng Kan wrote:
>> This adds support for the Designware SATA controller.
>>
>> Signed-off-by: Feng Kan <fkan@amcc.com>
>> Signed-off-by: Mark Miesfeld <miesfeld@gmail.com>
>> ---
>> drivers/ata/Kconfig | 10 +
>> drivers/ata/Makefile | 1 +
>> drivers/ata/sata_dwc.c | 2053
>> ++++++++++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 2064 insertions(+), 0 deletions(-)
>> create mode 100644 drivers/ata/sata_dwc.c
>>
>> diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
>> index 0bcf264..c3d0b24 100644
>> --- a/drivers/ata/Kconfig
>> +++ b/drivers/ata/Kconfig
>> @@ -72,6 +72,16 @@ config SATA_FSL
>>
>> If unsure, say N.
>>
>> +config SATA_DWC
>> + tristate "DesignWare Cores SATA support"
>> + depends on 460EX
>
> That "depends" looks too specific -- we don't want to grow a list if
> this controller gets added to other chips.
>
> Only depend on what this driver actually needs in order to function.
>
> -Scott
^ permalink raw reply
* [PATCH 1/3 v3] Added support for Designware SATA controller driver
From: Feng Kan @ 2009-05-06 17:49 UTC (permalink / raw)
To: linuxppc-dev, linux-ide; +Cc: Mark Miesfeld, Feng Kan
Signed-off-by: Feng Kan <fkan@amcc.com>
Signed-off-by: Mark Miesfeld <miesfeld@gmail.com>
---
drivers/ata/Kconfig | 10 +
drivers/ata/Makefile | 1 +
drivers/ata/sata_dwc.c | 2053 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 2064 insertions(+), 0 deletions(-)
create mode 100644 drivers/ata/sata_dwc.c
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 0bcf264..c3d0b24 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -72,6 +72,16 @@ config SATA_FSL
If unsure, say N.
+config SATA_DWC
+ tristate "DesignWare Cores SATA support"
+ depends on 460EX
+ help
+ This option enables support for the Synopsys DesignWare Cores SATA
+ controller.
+ It can be found on the AMCC 460EX.
+
+ If unsure, say N.
+
config ATA_SFF
bool "ATA SFF support"
default y
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 7f1ecf9..3d41fc7 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_SATA_MV) += sata_mv.o
obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
obj-$(CONFIG_SATA_FSL) += sata_fsl.o
+obj-$(CONFIG_SATA_DWC) += sata_dwc.o
obj-$(CONFIG_PATA_ALI) += pata_ali.o
obj-$(CONFIG_PATA_AMD) += pata_amd.o
diff --git a/drivers/ata/sata_dwc.c b/drivers/ata/sata_dwc.c
new file mode 100644
index 0000000..672f91f
--- /dev/null
+++ b/drivers/ata/sata_dwc.c
@@ -0,0 +1,2053 @@
+/*
+ * drivers/ata/sata_dwc.c
+ *
+ * Synopsys DesignWare Cores (DWC) SATA host driver
+ *
+ * Author: Mark Miesfeld <mmiesfeld@amcc.com>
+ *
+ * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese <sr@denx.de>
+ * Copyright 2008 DENX Software Engineering
+ *
+ * Based on versions provided by AMCC and Synopsys which are:
+ * Copyright 2006 Applied Micro Circuits Corporation
+ * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#ifdef CONFIG_SATA_DWC_DEBUG
+#define DEBUG
+#endif
+
+#ifdef CONFIG_SATA_DWC_VDEBUG
+#define VERBOSE_DEBUG
+#define DEBUG_NCQ
+#endif
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/libata.h>
+
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+
+#define DRV_NAME "sata-dwc"
+#define DRV_VERSION "1.0"
+
+/* SATA DMA driver Globals */
+#define DMA_NUM_CHANS 1
+#define DMA_NUM_CHAN_REGS 8
+
+/* SATA DMA Register definitions */
+#define AHB_DMA_BRST_DFLT 64 /* 16 data items burst length */
+
+struct dmareg {
+ u32 low; /* Low bits 0-31 */
+ u32 high; /* High bits 32-63 */
+};
+
+/* DMA Per Channel registers */
+
+struct dma_chan_regs {
+ struct dmareg sar; /* Source Address */
+ struct dmareg dar; /* Destination address */
+ struct dmareg llp; /* Linked List Pointer */
+ struct dmareg ctl; /* Control */
+ struct dmareg sstat; /* Source Status not implemented in core */
+ struct dmareg dstat; /* Destination Status not implemented in core */
+ struct dmareg sstatar; /* Source Status Address not impl in core */
+ struct dmareg dstatar; /* Destination Status Address not implemented */
+ struct dmareg cfg; /* Config */
+ struct dmareg sgr; /* Source Gather */
+ struct dmareg dsr; /* Destination Scatter */
+};
+
+/* Generic Interrupt Registers */
+struct dma_interrupt_regs {
+ struct dmareg tfr; /* Transfer Interrupt */
+ struct dmareg block; /* Block Interrupt */
+ struct dmareg srctran; /* Source Transfer Interrupt */
+ struct dmareg dsttran; /* Dest Transfer Interrupt */
+ struct dmareg error; /* Error */
+};
+
+struct ahb_dma_regs {
+ struct dma_chan_regs chan_regs[DMA_NUM_CHAN_REGS];
+ struct dma_interrupt_regs interrupt_raw; /* Raw Interrupt */
+ struct dma_interrupt_regs interrupt_status; /* Interrupt Status */
+ struct dma_interrupt_regs interrupt_mask; /* Interrupt Mask */
+ struct dma_interrupt_regs interrupt_clear; /* Interrupt Clear */
+ struct dmareg statusInt; /* Interrupt combined */
+ struct dmareg rq_srcreg; /* Src Trans Req */
+ struct dmareg rq_dstreg; /* Dst Trans Req */
+ struct dmareg rq_sgl_srcreg; /* Sngl Src Trans Req */
+ struct dmareg rq_sgl_dstreg; /* Sngl Dst Trans Req */
+ struct dmareg rq_lst_srcreg; /* Last Src Trans Req */
+ struct dmareg rq_lst_dstreg; /* Last Dst Trans Req */
+ struct dmareg dma_cfg; /* DMA Config */
+ struct dmareg dma_chan_en; /* DMA Channel Enable */
+ struct dmareg dma_id; /* DMA ID */
+ struct dmareg dma_test; /* DMA Test */
+ struct dmareg res1; /* reserved */
+ struct dmareg res2; /* reserved */
+
+ /* DMA Comp Params
+ * Param 6 = dma_param[0], Param 5 = dma_param[1],
+ * Param 4 = dma_param[2] ...
+ */
+ struct dmareg dma_params[6];
+};
+
+/* Data structure for linked list item */
+struct lli {
+ u32 sar; /* Source Address */
+ u32 dar; /* Destination address */
+ u32 llp; /* Linked List Pointer */
+ struct dmareg ctl; /* Control */
+ struct dmareg dstat; /* Destination Status */
+};
+
+#define SATA_DWC_DMAC_LLI_SZ (sizeof(struct lli))
+#define SATA_DWC_DMAC_LLI_NUM 256
+#define SATA_DWC_DMAC_TWIDTH_BYTES 4
+#define SATA_DWC_DMAC_LLI_TBL_SZ \
+ (SATA_DWC_DMAC_LLI_SZ * SATA_DWC_DMAC_LLI_NUM)
+#define SATA_DWC_DMAC_CTRL_TSIZE_MAX \
+ (0x00000800 * SATA_DWC_DMAC_TWIDTH_BYTES)
+
+/* DMA Register Operation Bits */
+#define DMA_EN 0x00000001 /* Enable AHB DMA */
+#define DMA_CHANNEL(ch) (0x00000001 << (ch)) /* Select channel */
+#define DMA_ENABLE_CHAN(ch) ((0x00000001 << (ch)) | \
+ ((0x000000001 << (ch)) << 8))
+#define DMA_DISABLE_CHAN(ch) (0x00000000 | ((0x000000001 << (ch)) << 8))
+
+/* Channel Control Register */
+#define DMA_CTL_BLK_TS(size) ((size) & 0x000000FFF) /* Blk Transfer size */
+#define DMA_CTL_LLP_SRCEN 0x10000000 /* Blk chain enable Src */
+#define DMA_CTL_LLP_DSTEN 0x08000000 /* Blk chain enable Dst */
+/*
+ * This define is used to set block chaining disabled in the control low
+ * register. It is already in little endian format so it can be &'d dirctly.
+ * It is essentially: cpu_to_le32(~(DMA_CTL_LLP_SRCEN | DMA_CTL_LLP_DSTEN))
+ */
+#define DMA_CTL_LLP_DISABLE_LE32 0xffffffe7
+#define DMA_CTL_SMS(num) ((num & 0x3) << 25) /*Src Master Select*/
+#define DMA_CTL_DMS(num) ((num & 0x3) << 23) /*Dst Master Select*/
+#define DMA_CTL_TTFC(type) ((type & 0x7) << 20) /*Type&Flow cntr*/
+#define DMA_CTL_TTFC_P2M_DMAC 0x00000002 /*Per mem,DMAC cntr*/
+#define DMA_CTL_TTFC_M2P_PER 0x00000003 /*Mem per,peri cntr*/
+#define DMA_CTL_SRC_MSIZE(size) ((size & 0x7) << 14) /*Src Burst Len*/
+#define DMA_CTL_DST_MSIZE(size) ((size & 0x7) << 11) /*Dst Burst Len*/
+#define DMA_CTL_SINC_INC 0x00000000 /*Src addr incr*/
+#define DMA_CTL_SINC_DEC 0x00000200
+#define DMA_CTL_SINC_NOCHANGE 0x00000400
+#define DMA_CTL_DINC_INC 0x00000000 /*Dst addr incr*/
+#define DMA_CTL_DINC_DEC 0x00000080
+#define DMA_CTL_DINC_NOCHANGE 0x00000100
+#define DMA_CTL_SRC_TRWID(size) ((size & 0x7) << 4) /*Src Trnsfr Width*/
+#define DMA_CTL_DST_TRWID(size) ((size & 0x7) << 1) /*Dst Trnsfr Width*/
+#define DMA_CTL_INT_EN 0x00000001 /*Interrupt Enable*/
+
+/* Channel Configuration Register high bits */
+#define DMA_CFG_FCMOD_REQ 0x00000001 /*Flow cntrl req*/
+#define DMA_CFG_PROTCTL (0x00000003 << 2) /*Protection cntrl*/
+
+/* Channel Configuration Register low bits */
+#define DMA_CFG_RELD_DST 0x80000000 /*Reload Dst/Src Addr*/
+#define DMA_CFG_RELD_SRC 0x40000000
+#define DMA_CFG_HS_SELSRC 0x00000800 /*SW hndshk Src/Dst*/
+#define DMA_CFG_HS_SELDST 0x00000400
+#define DMA_CFG_FIFOEMPTY (0x00000001 << 9) /*FIFO Empty bit*/
+
+/* Assign hardware handshaking interface (x) to dst / sre peripheral */
+#define DMA_CFG_HW_HS_DEST(int_num) ((int_num & 0xF) << 11)
+#define DMA_CFG_HW_HS_SRC(int_num) ((int_num & 0xF) << 7)
+
+/* Channel Linked List Pointer Register */
+#define DMA_LLP_LMS(addr, master) (((addr) & 0xfffffffc) | (master))
+#define DMA_LLP_AHBMASTER1 0 /* List Master Select */
+#define DMA_LLP_AHBMASTER2 1
+
+#define SATA_DWC_MAX_PORTS 1
+
+#define SATA_DWC_SCR_OFFSET 0x24
+#define SATA_DWC_REG_OFFSET 0x64
+
+/* DWC SATA Registers */
+struct sata_dwc_regs {
+ u32 fptagr; /* 1st party DMA tag */
+ u32 fpbor; /* 1st party DMA buffer offset */
+ u32 fptcr; /* 1st party DMA Xfr count */
+ u32 dmacr; /* DMA Control */
+ u32 dbtsr; /* DMA Burst Transac size */
+ u32 intpr; /* Interrupt Pending */
+ u32 intmr; /* Interrupt Mask */
+ u32 errmr; /* Error Mask */
+ u32 llcr; /* Link Layer Control */
+ u32 phycr; /* PHY Control */
+ u32 physr; /* PHY Status */
+ u32 rxbistpd; /* Recvd BIST pattern def register */
+ u32 rxbistpd1; /* Recvd BIST data dword1 */
+ u32 rxbistpd2; /* Recvd BIST pattern data dword2 */
+ u32 txbistpd; /* Trans BIST pattern def register */
+ u32 txbistpd1; /* Trans BIST data dword1 */
+ u32 txbistpd2; /* Trans BIST data dword2 */
+ u32 bistcr; /* BIST Control Register */
+ u32 bistfctr; /* BIST FIS Count Register */
+ u32 bistsr; /* BIST Status Register */
+ u32 bistdecr; /* BIST Dword Error count register */
+ u32 res[15]; /* Reserved locations */
+ u32 testr; /* Test Register */
+ u32 versionr; /* Version Register */
+ u32 idr; /* ID Register */
+ u32 unimpl[192]; /* Unimplemented */
+ u32 dmadr[256]; /* FIFO Locations in DMA Mode */
+};
+
+#define SCR_SCONTROL_DET_ENABLE 0x00000001
+#define SCR_SSTATUS_DET_PRESENT 0x00000001
+#define SCR_SERROR_DIAG_X 0x04000000
+
+/* DWC SATA Register Operations */
+#define SATA_DWC_TXFIFO_DEPTH 0x01FF
+#define SATA_DWC_RXFIFO_DEPTH 0x01FF
+
+#define SATA_DWC_DMACR_TMOD_TXCHEN 0x00000004
+#define SATA_DWC_DMACR_TXCHEN (0x00000001 | \
+ SATA_DWC_DMACR_TMOD_TXCHEN)
+#define SATA_DWC_DMACR_RXCHEN (0x00000002 | \
+ SATA_DWC_DMACR_TMOD_TXCHEN)
+#define SATA_DWC_DMACR_TX_CLEAR(v) (((v) & ~SATA_DWC_DMACR_TXCHEN) | \
+ SATA_DWC_DMACR_TMOD_TXCHEN)
+#define SATA_DWC_DMACR_RX_CLEAR(v) (((v) & ~SATA_DWC_DMACR_RXCHEN) | \
+ SATA_DWC_DMACR_TMOD_TXCHEN)
+#define SATA_DWC_DMACR_TXRXCH_CLEAR SATA_DWC_DMACR_TMOD_TXCHEN
+
+#define SATA_DWC_DBTSR_MWR(size) ((size/4) & \
+ SATA_DWC_TXFIFO_DEPTH)
+#define SATA_DWC_DBTSR_MRD(size) (((size/4) & \
+ SATA_DWC_RXFIFO_DEPTH) << 16)
+#define SATA_DWC_INTPR_DMAT 0x00000001
+#define SATA_DWC_INTPR_NEWFP 0x00000002
+#define SATA_DWC_INTPR_PMABRT 0x00000004
+#define SATA_DWC_INTPR_ERR 0x00000008
+#define SATA_DWC_INTPR_NEWBIST 0x00000010
+#define SATA_DWC_INTPR_IPF 0x10000000
+#define SATA_DWC_INTMR_DMATM 0x00000001
+#define SATA_DWC_INTMR_NEWFPM 0x00000002
+#define SATA_DWC_INTMR_PMABRTM 0x00000004
+#define SATA_DWC_INTMR_ERRM 0x00000008
+#define SATA_DWC_INTMR_NEWBISTM 0x00000010
+#define SATA_DWC_LLCR_SCRAMEN 0x00000001
+#define SATA_DWC_LLCR_DESCRAMEN 0x00000002
+#define SATA_DWC_LLCR_RPDEN 0x00000004
+
+/* This is all error bits, zero's are reserved fields. */
+#define SATA_DWC_SERROR_ERR_BITS 0x0FFF0F03
+
+#define SATA_DWC_SCR0_SPD_GET(v) ((v >> 4) & 0x0000000F)
+
+struct sata_dwc_device {
+ struct device *dev; /* generic device struct */
+ struct ata_probe_ent *pe; /* ptr to probe-ent */
+ struct ata_host *host;
+ u8 *reg_base;
+ struct sata_dwc_regs *sata_dwc_regs; /* DW Synopsys SATA specific */
+ int irq_dma;
+};
+
+#define SATA_DWC_QCMD_MAX 32
+
+struct sata_dwc_device_port {
+ struct sata_dwc_device *hsdev;
+ int cmd_issued[SATA_DWC_QCMD_MAX];
+ struct lli *llit[SATA_DWC_QCMD_MAX];
+ dma_addr_t llit_dma[SATA_DWC_QCMD_MAX];
+ u32 dma_chan[SATA_DWC_QCMD_MAX];
+ int dma_pending[SATA_DWC_QCMD_MAX];
+};
+
+/*
+ * Commonly used DWC SATA driver Macros
+ */
+#define HSDEV_FROM_HOST(host) ((struct sata_dwc_device *) \
+ (host)->private_data)
+#define HSDEV_FROM_AP(ap) ((struct sata_dwc_device *) \
+ (ap)->host->private_data)
+#define HSDEVP_FROM_AP(ap) ((struct sata_dwc_device_port *) \
+ (ap)->private_data)
+#define HSDEV_FROM_QC(qc) ((struct sata_dwc_device *) \
+ (qc)->ap->host->private_data)
+#define HSDEV_FROM_HSDEVP(p) ((struct sata_dwc_device *) \
+ (hsdevp)->hsdev)
+
+enum {
+ SATA_DWC_CMD_ISSUED_NOT = 0,
+ SATA_DWC_CMD_ISSUED_PEND = 1,
+ SATA_DWC_CMD_ISSUED_EXEC = 2,
+ SATA_DWC_CMD_ISSUED_NODATA = 3,
+
+ SATA_DWC_DMA_PEND_NONE = 0,
+ SATA_DWC_DMA_PEND_TX = 1,
+ SATA_DWC_DMA_PEND_RX = 2,
+};
+
+/*
+ * Globals
+ */
+static u32 sata_dwc_sactive_issued; /* issued queued ops */
+static u32 sata_dwc_sactive_queued; /* queued ops */
+static struct ahb_dma_regs *sata_dma_regs;
+static u32 dma_interrupt_count;
+static void *scr_addr_sstatus;
+static struct device *dwc_dev;
+
+/*
+ * Prototypes
+ */
+static void sata_dwc_bmdma_start_by_tag(struct ata_queued_cmd *qc, u8 tag);
+static int sata_dwc_qc_complete(struct ata_port *ap, struct ata_queued_cmd *qc,
+ u32 check_status);
+static void sata_dwc_dma_xfer_complete(struct ata_port *ap, u32 check_status);
+static void sata_dwc_port_stop(struct ata_port *ap);
+static void sata_dwc_clear_dmacr(struct sata_dwc_device_port *hsdevp, u8 tag);
+
+static int dma_dwc_init(struct sata_dwc_device *hsdev, struct resource *res,
+ int irq);
+static void dma_dwc_exit(struct sata_dwc_device *hsdev);
+static int dma_dwc_xfer_setup(struct scatterlist *sg, int num_elems,
+ struct lli *lli, dma_addr_t dma_lli,
+ void __iomem *addr, int dir);
+static void dma_dwc_xfer_start(int dma_ch);
+static void dma_dwc_terminate_dma(int dma_ch);
+
+static const char *dir_2_txt(enum dma_data_direction dir)
+{
+ switch (dir) {
+ case DMA_BIDIRECTIONAL:
+ return "bi";
+ case DMA_FROM_DEVICE:
+ return "from";
+ case DMA_TO_DEVICE:
+ return "to";
+ case DMA_NONE:
+ return "none";
+ default:
+ return "err";
+ }
+}
+
+static const char *prot_2_txt(enum ata_tf_protocols protocol)
+{
+ switch (protocol) {
+ case ATA_PROT_UNKNOWN:
+ return "unknown";
+ case ATA_PROT_NODATA:
+ return "nodata";
+ case ATA_PROT_PIO:
+ return "pio";
+ case ATA_PROT_DMA:
+ return "dma";
+ case ATA_PROT_NCQ:
+ return "ncq";
+ case ATAPI_PROT_PIO:
+ return "atapi pio";
+ case ATAPI_PROT_NODATA:
+ return "atapi nodata";
+ case ATAPI_PROT_DMA:
+ return "atapi dma";
+ default:
+ return "err";
+ }
+}
+
+inline const char *ata_cmd_2_txt(const struct ata_taskfile *tf)
+{
+ switch (tf->command) {
+ case ATA_CMD_CHK_POWER:
+ return "ATA_CMD_CHK_POWER";
+ case ATA_CMD_EDD:
+ return "ATA_CMD_EDD";
+ case ATA_CMD_FLUSH:
+ return "ATA_CMD_FLUSH";
+ case ATA_CMD_FLUSH_EXT:
+ return "ATA_CMD_FLUSH_EXT";
+ case ATA_CMD_ID_ATA:
+ return "ATA_CMD_ID_ATA";
+ case ATA_CMD_ID_ATAPI:
+ return "ATA_CMD_ID_ATAPI";
+ case ATA_CMD_FPDMA_READ:
+ return "ATA_CMD_FPDMA_READ";
+ case ATA_CMD_FPDMA_WRITE:
+ return "ATA_CMD_FPDMA_WRITE";
+ case ATA_CMD_READ:
+ return "ATA_CMD_READ";
+ case ATA_CMD_READ_EXT:
+ return "ATA_CMD_READ_EXT";
+ case ATA_CMD_WRITE:
+ return "ATA_CMD_WRITE";
+ case ATA_CMD_WRITE_EXT:
+ return "ATA_CMD_WRITE_EXT";
+ case ATA_CMD_PIO_READ:
+ return "ATA_CMD_PIO_READ";
+ case ATA_CMD_PIO_READ_EXT:
+ return "ATA_CMD_PIO_READ_EXT";
+ case ATA_CMD_PIO_WRITE:
+ return "ATA_CMD_PIO_WRITE";
+ case ATA_CMD_PIO_WRITE_EXT:
+ return "ATA_CMD_PIO_WRITE_EXT";
+ case ATA_CMD_SET_FEATURES:
+ return "ATA_CMD_SET_FEATURES";
+ case ATA_CMD_PACKET:
+ return "ATA_CMD_PACKET";
+ default:
+ return "ATA_CMD_???";
+ }
+}
+
+static void sata_dwc_tf_dump(struct ata_taskfile *tf)
+{
+ dev_vdbg(dwc_dev, "taskfile cmd: 0x%02x protocol: %s flags: 0x%lx"
+ "device: %x\n", tf->command, prot_2_txt(tf->protocol),
+ tf->flags, tf->device);
+ dev_vdbg(dwc_dev, "feature: 0x%02x nsect: 0x%x lbal: 0x%x lbam:"
+ "0x%x lbah: 0x%x\n", tf->feature, tf->nsect, tf->lbal,
+ tf->lbam, tf->lbah);
+ dev_vdbg(dwc_dev, "hob_feature: 0x%02x hob_nsect: 0x%x hob_lbal: 0x%x "
+ "hob_lbam: 0x%x hob_lbah: 0x%x\n", tf->hob_feature,
+ tf->hob_nsect, tf->hob_lbal, tf->hob_lbam,
+ tf->hob_lbah);
+}
+
+/*
+ * Function: get_burst_length_encode
+ * arguments: datalength: length in bytes of data
+ * returns value to be programmed in register corrresponding to data length
+ * This value is effectively the log(base 2) of the length
+ */
+static inline int get_burst_length_encode(int datalength)
+{
+ int items = datalength >> 2; /* div by 4 to get lword count */
+
+ if (items >= 64)
+ return 5;
+
+ if (items >= 32)
+ return 4;
+
+ if (items >= 16)
+ return 3;
+
+ if (items >= 8)
+ return 2;
+
+ if (items >= 4)
+ return 1;
+
+ return 0;
+}
+
+static inline void clear_chan_interrupts(int c)
+{
+ out_le32(&(sata_dma_regs->interrupt_clear.tfr.low), DMA_CHANNEL(c));
+ out_le32(&(sata_dma_regs->interrupt_clear.block.low), DMA_CHANNEL(c));
+ out_le32(&(sata_dma_regs->interrupt_clear.srctran.low), DMA_CHANNEL(c));
+ out_le32(&(sata_dma_regs->interrupt_clear.dsttran.low), DMA_CHANNEL(c));
+ out_le32(&(sata_dma_regs->interrupt_clear.error.low), DMA_CHANNEL(c));
+}
+
+/*
+ * Function: dma_request_channel
+ * arguments: None
+ * returns channel number if available else -1
+ * This function assigns the next available DMA channel from the list to the
+ * requester
+ */
+static int dma_request_channel(void)
+{
+ int i;
+ struct ahb_dma_regs *pdma;
+
+ pdma = sata_dma_regs;
+ for (i = 0; i < DMA_NUM_CHANS; i++) {
+ if (!(in_le32(&(pdma->dma_chan_en.low)) & DMA_CHANNEL(i)))
+ return i;
+ }
+
+ dev_err(dwc_dev, "%s NO channel chan_en: 0x%08x\n", __func__,
+ in_le32(&(pdma->dma_chan_en.low)));
+
+ return -1;
+}
+
+/*
+ * Function: dma_dwc_interrupt
+ * arguments: irq, dev_id, pt_regs
+ * returns channel number if available else -1
+ * Interrupt Handler for DW AHB SATA DMA
+ */
+static irqreturn_t dma_dwc_interrupt(int irq, void *hsdev_instance)
+{
+ int chan;
+ u32 tfr_reg, err_reg;
+ unsigned long flags;
+ struct sata_dwc_device *hsdev =
+ (struct sata_dwc_device *)hsdev_instance;
+ struct ata_host *host = (struct ata_host *)hsdev->host;
+ struct ata_port *ap;
+ struct sata_dwc_device_port *hsdevp;
+ u8 tag = 0;
+ unsigned int port = 0;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ ap = host->ports[port];
+ hsdevp = HSDEVP_FROM_AP(ap);
+ tag = ap->link.active_tag;
+
+ tfr_reg = in_le32(&(sata_dma_regs->interrupt_status.tfr.low));
+ err_reg = in_le32(&(sata_dma_regs->interrupt_status.error.low));
+
+ dev_dbg(ap->dev, "eot=0x%08x err=0x%08x pending=%d active port=%d\n",
+ tfr_reg, err_reg, hsdevp->dma_pending[tag], port);
+
+ for (chan = 0; chan < DMA_NUM_CHANS; chan++) {
+ /* Check for end-of-transfer interrupt. */
+ if (tfr_reg & DMA_CHANNEL(chan)) {
+ /*
+ *Each DMA command produces 2 interrupts. Only
+ * complete the command after both interrupts have been
+ * seen. (See sata_dwc_isr())
+ */
+ dma_interrupt_count++;
+
+ sata_dwc_clear_dmacr(hsdevp, tag);
+
+ if (hsdevp->dma_pending[tag] == 0) {
+ dev_err(ap->dev, "DMA not pending eot=0x%08x "
+ "err=0x%08x tag=0x%02x pending=%d\n",
+ tfr_reg, err_reg, tag,
+ hsdevp->dma_pending[tag]);
+ }
+
+ if ((dma_interrupt_count % 2) == 0)
+ sata_dwc_dma_xfer_complete(ap, 1);
+
+ /* Clear the interrupt */
+ out_le32(&(sata_dma_regs->interrupt_clear.tfr.low),
+ DMA_CHANNEL(chan));
+ }
+
+ /* Check for error interrupt. */
+ if (err_reg & DMA_CHANNEL(chan)) {
+ /* TODO Need error handler ! */
+ dev_err(ap->dev, "error interrupt err_reg=0x%08x\n",
+ err_reg);
+
+ /* Clear the interrupt. */
+ out_le32(&(sata_dma_regs->interrupt_clear.error.low),
+ DMA_CHANNEL(chan));
+ }
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Function: dma_request_interrupts
+ * arguments: hsdev
+ * returns status
+ * This function registers ISR for a particular DMA channel interrupt
+ */
+static int dma_request_interrupts(struct sata_dwc_device *hsdev, int irq)
+{
+ int retval = 0;
+ int chan;
+
+ for (chan = 0; chan < DMA_NUM_CHANS; chan++) {
+ /* Unmask error interrupt */
+ out_le32(&sata_dma_regs->interrupt_mask.error.low,
+ DMA_ENABLE_CHAN(chan));
+
+ /* Unmask end-of-transfer interrupt */
+ out_le32(&sata_dma_regs->interrupt_mask.tfr.low,
+ DMA_ENABLE_CHAN(chan));
+ }
+
+ retval = request_irq(irq, dma_dwc_interrupt, 0, "SATA DMA", hsdev);
+ if (retval) {
+ dev_err(dwc_dev, "%s: could not get IRQ %d\n", __func__, irq);
+ return -ENODEV;
+ }
+
+ /* Mark this interrupt as requested */
+ hsdev->irq_dma = irq;
+
+ return 0;
+}
+
+/*
+ * Function: map_sg_to_lli
+ * arguments: sg: scatter/gather list(sg)
+ * num_elems: no of elements in sg list
+ * dma_lli: LLI table
+ * dest: destination address
+ * read: whether the transfer is read or write
+ * returns array of AHB DMA Linked List Items
+ * This function creates a list of LLIs for DMA Xfr and returns the number
+ * of elements in the DMA linked list.
+ *
+ * Note that the Synopsis driver has a comment proposing that better performance
+ * is possible by only enabling interrupts on the last item in the linked list.
+ * However, it seems that could be a problem if an error happened on one of the
+ * first items. The transfer would halt, but no error interrupt would occur.
+ *
+ * Currently this function sets interrupts enabled for each linked list item:
+ * DMA_CTL_INT_EN.
+ */
+static int map_sg_to_lli(struct scatterlist *sg, int num_elems, struct lli *lli,
+ dma_addr_t dma_lli, void __iomem *dmadr_addr, int dir)
+{
+ int i, idx = 0;
+ int fis_len = 0;
+ dma_addr_t next_llp;
+ int bl;
+ unsigned int dma_ts = 0;
+
+ dev_dbg(dwc_dev, "%s: sg=%p nelem=%d lli=%p dma_lli=0x%08x "
+ "dmadr=0x%08x\n", __func__, sg, num_elems, lli, (u32)dma_lli,
+ (u32)dmadr_addr);
+
+ bl = get_burst_length_encode(AHB_DMA_BRST_DFLT);
+
+ for (i = 0; i < num_elems; i++, sg++) {
+ u32 addr, offset;
+ u32 sg_len, len;
+
+ addr = (u32) sg_dma_address(sg);
+ sg_len = sg_dma_len(sg);
+
+ dev_dbg(dwc_dev, "%s: elem=%d sg_addr=0x%x sg_len=%d\n",
+ __func__, i, addr, sg_len);
+
+ while (sg_len) {
+
+ if (idx >= SATA_DWC_DMAC_LLI_NUM) {
+ /* The LLI table is not large enough. */
+ dev_err(dwc_dev, "LLI table overrun (idx=%d)\n",
+ idx);
+ break;
+ }
+ len = (sg_len > SATA_DWC_DMAC_CTRL_TSIZE_MAX) ?
+ SATA_DWC_DMAC_CTRL_TSIZE_MAX : sg_len;
+
+ offset = addr & 0xffff;
+ if ((offset + sg_len) > 0x10000)
+ len = 0x10000 - offset;
+
+ /*
+ * Make sure a LLI block is not created that will span a
+ * 8K max FIS boundary. If the block spans such a FIS
+ * boundary, there is a chance that a DMA burst will
+ * cross that boundary -- this results in an error in
+ * the host controller.
+ */
+ if (fis_len + len > 8192) {
+ dev_dbg(dwc_dev, "SPLITTING: fis_len=%d(0x%x) "
+ "len=%d(0x%x)\n", fis_len, fis_len,
+ len, len);
+ len = 8192 - fis_len;
+ fis_len = 0;
+ } else {
+ fis_len += len;
+ }
+ if (fis_len == 8192)
+ fis_len = 0;
+
+ /*
+ * Set DMA addresses and lower half of control register
+ * based on direction.
+ */
+ if (dir == DMA_FROM_DEVICE) {
+ lli[idx].dar = cpu_to_le32(addr);
+ lli[idx].sar = cpu_to_le32((u32)dmadr_addr);
+
+ lli[idx].ctl.low = cpu_to_le32(
+ DMA_CTL_TTFC(DMA_CTL_TTFC_P2M_DMAC) |
+ DMA_CTL_SMS(0) |
+ DMA_CTL_DMS(1) |
+ DMA_CTL_SRC_MSIZE(bl) |
+ DMA_CTL_DST_MSIZE(bl) |
+ DMA_CTL_SINC_NOCHANGE |
+ DMA_CTL_SRC_TRWID(2) |
+ DMA_CTL_DST_TRWID(2) |
+ DMA_CTL_INT_EN |
+ DMA_CTL_LLP_SRCEN |
+ DMA_CTL_LLP_DSTEN);
+ } else { /* DMA_TO_DEVICE */
+ lli[idx].sar = cpu_to_le32(addr);
+ lli[idx].dar = cpu_to_le32((u32)dmadr_addr);
+
+ lli[idx].ctl.low = cpu_to_le32(
+ DMA_CTL_TTFC(DMA_CTL_TTFC_M2P_PER) |
+ DMA_CTL_SMS(1) |
+ DMA_CTL_DMS(0) |
+ DMA_CTL_SRC_MSIZE(bl) |
+ DMA_CTL_DST_MSIZE(bl) |
+ DMA_CTL_DINC_NOCHANGE |
+ DMA_CTL_SRC_TRWID(2) |
+ DMA_CTL_DST_TRWID(2) |
+ DMA_CTL_INT_EN |
+ DMA_CTL_LLP_SRCEN |
+ DMA_CTL_LLP_DSTEN);
+ }
+
+ dev_dbg(dwc_dev, "%s setting ctl.high len: 0x%08x val: "
+ "0x%08x\n", __func__, len,
+ DMA_CTL_BLK_TS(len / 4));
+
+ /* Program the LLI CTL high register */
+ dma_ts = DMA_CTL_BLK_TS(len / 4);
+ lli[idx].ctl.high = cpu_to_le32(dma_ts);
+
+ /*
+ *Program the next pointer. The next pointer must be
+ * the physical address, not the virtual address.
+ */
+ next_llp = (dma_lli + ((idx + 1) * sizeof(struct lli)));
+
+ /* The last 2 bits encode the list master select. */
+ next_llp = DMA_LLP_LMS(next_llp, DMA_LLP_AHBMASTER2);
+
+ lli[idx].llp = cpu_to_le32(next_llp);
+
+ idx++;
+ sg_len -= len;
+ addr += len;
+ }
+ }
+
+ /*
+ * The last next ptr has to be zero and the last control low register
+ * has to have LLP_SRC_EN and LLP_DST_EN (linked list pointer source
+ * and destination enable) set back to 0 (disabled.) This is what tells
+ * the core that this is the last item in the linked list.
+ */
+ if (idx) {
+ lli[idx-1].llp = 0x00000000;
+ lli[idx-1].ctl.low &= DMA_CTL_LLP_DISABLE_LE32;
+
+ /* Flush cache to memory */
+ dma_cache_sync(NULL, lli, (sizeof(struct lli) * idx),
+ DMA_BIDIRECTIONAL);
+ }
+
+ return idx;
+}
+
+/*
+ * Function: dma_dwc_xfer_start
+ * arguments: Channel number
+ * Return : None
+ * Enables the DMA channel
+ */
+static void dma_dwc_xfer_start(int dma_ch)
+{
+ /* Enable the DMA channel */
+ out_le32(&(sata_dma_regs->dma_chan_en.low),
+ in_le32(&(sata_dma_regs->dma_chan_en.low)) |
+ DMA_ENABLE_CHAN(dma_ch));
+}
+
+static int dma_dwc_channel_enabled(int ch)
+{
+ if (in_le32(&(sata_dma_regs->dma_chan_en.low)) & DMA_CHANNEL(ch))
+ return 1;
+
+ return 0;
+}
+
+static void dma_dwc_terminate_dma(int dma_ch)
+{
+ int enabled = dma_dwc_channel_enabled(dma_ch);
+
+ dev_info(dwc_dev, "%s terminate DMA on channel=%d enabled=%d\n",
+ __func__, dma_ch, enabled);
+
+ if (enabled) {
+ out_le32(&(sata_dma_regs->dma_chan_en.low),
+ DMA_DISABLE_CHAN(dma_ch));
+
+ do {
+ enabled = dma_dwc_channel_enabled(dma_ch);
+ } while (enabled);
+ }
+}
+
+static int dma_dwc_xfer_setup(struct scatterlist *sg, int num_elems,
+ struct lli *lli, dma_addr_t dma_lli,
+ void __iomem *addr, int dir)
+{
+ int dma_ch;
+ int num_lli;
+
+ /* Acquire DMA channel */
+ dma_ch = dma_request_channel();
+ if (dma_ch == -1) {
+ dev_err(dwc_dev, "%s: dma channel unavailable\n", __func__);
+ return -EAGAIN;
+ }
+
+ /* Convert SG list to linked list of items (LLIs) for AHB DMA */
+ num_lli = map_sg_to_lli(sg, num_elems, lli, dma_lli, addr, dir);
+
+ dev_dbg(dwc_dev, "%s sg: 0x%p, count: %d lli: %p dma_lli: 0x%0xlx addr:"
+ " %p lli count: %d\n", __func__, sg, num_elems, lli,
+ (u32)dma_lli, addr, num_lli);
+
+ /* Clear channel interrupts */
+ clear_chan_interrupts(dma_ch);
+
+ /* Program the CFG register. */
+ out_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.high),
+ DMA_CFG_PROTCTL | DMA_CFG_FCMOD_REQ);
+ out_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.low), 0);
+
+ /* Program the address of the linked list */
+ out_le32(&(sata_dma_regs->chan_regs[dma_ch].llp.low),
+ DMA_LLP_LMS(dma_lli, DMA_LLP_AHBMASTER2));
+
+ /* Program the CTL register with src enable / dst enable */
+ out_le32(&(sata_dma_regs->chan_regs[dma_ch].ctl.low),
+ DMA_CTL_LLP_SRCEN | DMA_CTL_LLP_DSTEN);
+
+ return 0;
+}
+
+/*
+ * Function: dma_dwc_exit
+ * arguments: None
+ * returns status
+ * This function exits the SATA DMA driver
+ */
+static void dma_dwc_exit(struct sata_dwc_device *hsdev)
+{
+ dev_dbg(dwc_dev, "%s:\n", __func__);
+ if (sata_dma_regs)
+ iounmap(sata_dma_regs);
+
+ if (hsdev->irq_dma)
+ free_irq(hsdev->irq_dma, hsdev);
+}
+
+/*
+ * Function: dma_dwc_init
+ * arguments: hsdev
+ * returns status
+ * This function initializes the SATA DMA driver
+ */
+static int dma_dwc_init(struct sata_dwc_device *hsdev, struct resource *res,
+ int irq)
+{
+ int err;
+
+ sata_dma_regs = ioremap(res->start, res->end - res->start + 1);
+ if (!sata_dma_regs) {
+ dev_err(dwc_dev, "%s: ioremap failed\n", __func__);
+ err = -ENODEV;
+ goto error_out;
+ }
+
+ err = dma_request_interrupts(hsdev, irq);
+ if (err) {
+ dev_err(dwc_dev, "%s: dma_request_interrupts returns %d\n",
+ __func__, err);
+ goto error_out;
+ }
+
+ /* Enabe DMA */
+ out_le32(&(sata_dma_regs->dma_cfg.low), DMA_EN);
+
+ dev_notice(dwc_dev, "DMA initialized\n");
+ dev_dbg(dwc_dev, "SATA DMA registers=0x%p\n", sata_dma_regs);
+
+ return 0;
+
+error_out:
+ dma_dwc_exit(hsdev);
+
+ return err;
+}
+
+static int sata_dwc_scr_read(struct ata_link *link, unsigned int scr, u32 *val)
+{
+ if (scr > SCR_NOTIFICATION) {
+ dev_err(link->ap->dev, "%s: Incorrect SCR offset 0x%02x\n",
+ __func__, scr);
+ return -EINVAL;
+ }
+
+ *val = in_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4));
+ dev_dbg(link->ap->dev, "%s: id=%d reg=%d val=val=0x%08x\n",
+ __func__, link->ap->print_id, scr, *val);
+
+ return 0;
+}
+
+static int sata_dwc_scr_write(struct ata_link *link, unsigned int scr, u32 val)
+{
+ dev_dbg(link->ap->dev, "%s: id=%d reg=%d val=val=0x%08x\n",
+ __func__, link->ap->print_id, scr, val);
+ if (scr > SCR_NOTIFICATION) {
+ dev_err(link->ap->dev, "%s: Incorrect SCR offset 0x%02x\n",
+ __func__, scr);
+ return -EINVAL;
+ }
+ out_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4), val);
+
+ return 0;
+}
+
+static inline u32 core_scr_read(unsigned int scr)
+{
+ return in_le32((void __iomem *)scr_addr_sstatus + (scr * 4));
+}
+
+static inline void core_scr_write(unsigned int scr, u32 val)
+{
+ out_le32((void __iomem *)scr_addr_sstatus + (scr * 4), val);
+}
+
+static inline void clear_serror(void)
+{
+ out_le32((void __iomem *)scr_addr_sstatus + 4,
+ in_le32((void __iomem *)scr_addr_sstatus + 4));
+}
+
+static inline void clear_intpr(struct sata_dwc_device *hsdev)
+{
+ out_le32(&hsdev->sata_dwc_regs->intpr,
+ in_le32(&hsdev->sata_dwc_regs->intpr));
+}
+
+static inline void clear_interrupt_bit(struct sata_dwc_device *hsdev, u32 bit)
+{
+ out_le32(&hsdev->sata_dwc_regs->intpr,
+ in_le32(&hsdev->sata_dwc_regs->intpr));
+}
+
+static inline void disable_err_irq(struct sata_dwc_device *hsdev)
+{
+ out_le32(&hsdev->sata_dwc_regs->intmr,
+ in_le32(&hsdev->sata_dwc_regs->intmr) & ~SATA_DWC_INTMR_ERRM);
+ out_le32(&hsdev->sata_dwc_regs->errmr, ~SATA_DWC_SERROR_ERR_BITS);
+}
+
+static inline void enable_err_irq(struct sata_dwc_device *hsdev)
+{
+ out_le32(&hsdev->sata_dwc_regs->intmr,
+ in_le32(&hsdev->sata_dwc_regs->intmr) | SATA_DWC_INTMR_ERRM);
+ out_le32(&hsdev->sata_dwc_regs->errmr, SATA_DWC_SERROR_ERR_BITS);
+}
+
+static inline u32 qcmd_tag_to_mask(u8 tag)
+{
+ return 0x00000001 << (tag & 0x1f);
+}
+
+/* See ahci.c */
+static void sata_dwc_error_intr(struct ata_port *ap,
+ struct sata_dwc_device *hsdev, uint intpr)
+{
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ unsigned int err_mask = 0, action = 0;
+ struct ata_queued_cmd *qc;
+ u32 serror;
+ u8 status, tag;
+ u32 err_reg;
+
+ ata_ehi_clear_desc(ehi);
+
+ serror = core_scr_read(SCR_ERROR);
+ status = ap->ops->sff_check_status(ap);
+
+ err_reg = in_le32(&(sata_dma_regs->interrupt_status.error.low));
+ tag = ap->link.active_tag;
+
+ dev_err(ap->dev, "%s SCR_ERROR=0x%08x intpr=0x%08x status=0x%08x "
+ "dma_intp=%d pending=%d issued=%d dma_err_status=0x%08x\n",
+ __func__, serror, intpr, status, dma_interrupt_count,
+ hsdevp->dma_pending[tag], hsdevp->cmd_issued[tag], err_reg);
+
+ /* Clear error register and interrupt bit */
+ clear_serror();
+ clear_interrupt_bit(hsdev, SATA_DWC_INTPR_ERR);
+
+ /* This is the only error happening now. */
+ /* TODO check for exact error */
+ err_mask |= AC_ERR_HOST_BUS;
+ action |= ATA_EH_RESET;
+
+ /* Pass this on to EH */
+ ehi->serror |= serror;
+ ehi->action |= action;
+
+ qc = ata_qc_from_tag(ap, tag);
+ if (qc)
+ qc->err_mask |= err_mask;
+ else
+ ehi->err_mask |= err_mask;
+
+ ata_port_abort(ap);
+
+ /*
+ if (irq_stat & PORT_IRQ_FREEZE)
+ ata_port_freeze(ap);
+ else
+ ata_port_abort(ap);
+ */
+}
+
+/*
+ * Function : sata_dwc_isr
+ * arguments : irq, void *dev_instance, struct pt_regs *regs
+ * Return value : irqreturn_t - status of IRQ
+ * This Interrupt handler called via port ops registered function.
+ * .irq_handler = sata_dwc_isr
+ */
+static irqreturn_t sata_dwc_isr(int irq, void *dev_instance)
+{
+ struct ata_host *host = (struct ata_host *)dev_instance;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_HOST(host);
+ struct ata_port *ap;
+ struct ata_queued_cmd *qc;
+ unsigned long flags;
+ u8 status, tag;
+ int handled, num_processed, port = 0;
+ uint intpr, sactive, sactive2, tag_mask;
+ struct sata_dwc_device_port *hsdevp;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ /* Read the interrupt register */
+ intpr = in_le32(&hsdev->sata_dwc_regs->intpr);
+
+ ap = host->ports[port];
+ hsdevp = HSDEVP_FROM_AP(ap);
+
+ dev_dbg(ap->dev, "%s intpr=0x%08x active_tag=%d\n", __func__, intpr,
+ ap->link.active_tag);
+
+ /* Check for error interrupt */
+ if (intpr & SATA_DWC_INTPR_ERR) {
+ sata_dwc_error_intr(ap, hsdev, intpr);
+ handled = 1;
+ goto done_irqrestore;
+ }
+
+ /* Check for DMA SETUP FIS (FP DMA) interrupt */
+ if (intpr & SATA_DWC_INTPR_NEWFP) {
+ clear_interrupt_bit(hsdev, SATA_DWC_INTPR_NEWFP);
+
+ tag = (u8)(in_le32(&hsdev->sata_dwc_regs->fptagr));
+ dev_dbg(ap->dev, "%s: NEWFP tag=%d\n", __func__, tag);
+ if (hsdevp->cmd_issued[tag] != SATA_DWC_CMD_ISSUED_PEND)
+ dev_warn(ap->dev, "CMD tag=%d not pending?\n", tag);
+
+ sata_dwc_sactive_issued |= qcmd_tag_to_mask(tag);
+
+ qc = ata_qc_from_tag(ap, tag);
+ /*
+ * Start FP DMA for NCQ command. At this point the tag is the
+ * active tag. It is the tag that matches the command about to
+ * be completed.
+ */
+ qc->ap->link.active_tag = tag;
+ sata_dwc_bmdma_start_by_tag(qc, tag);
+
+ handled = 1;
+ goto done_irqrestore;
+ }
+
+ sactive = core_scr_read(SCR_ACTIVE);
+ tag_mask = (sata_dwc_sactive_issued | sactive) ^ sactive;
+
+ /* If no sactive issued and tag_mask is zero then this is not NCQ */
+ if (sata_dwc_sactive_issued == 0 && tag_mask == 0) {
+ tag = 0;
+ qc = ata_qc_from_tag(ap, tag);
+
+ /* DEV interrupt w/ no active qc? */
+ if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
+ dev_err(ap->dev, "%s intr with no active qc qc=%p\n",
+ __func__, qc);
+ ata_sff_check_status(ap);
+ handled = 1;
+ goto done_irqrestore;
+ }
+
+ status = ap->ops->sff_check_status(ap);
+
+ qc->ap->link.active_tag = tag;
+ hsdevp->cmd_issued[tag] = SATA_DWC_CMD_ISSUED_NOT;
+
+ if (status & ATA_ERR) {
+ dev_dbg(ap->dev, "interrupt ATA_ERR (0x%x)\n", status);
+ sata_dwc_qc_complete(ap, qc, 1);
+ handled = 1;
+ goto done_irqrestore;
+ }
+
+ dev_dbg(ap->dev, "%s non-NCQ cmd interrupt, protocol: %s\n",
+ __func__, prot_2_txt(qc->tf.protocol));
+drv_still_busy:
+ if (ata_is_dma(qc->tf.protocol)) {
+ int dma_flag = hsdevp->dma_pending[tag];
+ /*
+ * Each DMA transaction produces 2 interrupts. The DMAC
+ * transfer complete interrupt and the SATA controller
+ * operation done interrupt. The command should be
+ * completed only after both interrupts are seen.
+ */
+ dma_interrupt_count++;
+ if (dma_flag == SATA_DWC_DMA_PEND_NONE) {
+ dev_err(ap->dev, "%s: DMA not pending "
+ "intpr=0x%08x status=0x%08x pend=%d\n",
+ __func__, intpr, status, dma_flag);
+ }
+
+ if ((dma_interrupt_count % 2) == 0)
+ sata_dwc_dma_xfer_complete(ap, 1);
+ } else {
+ if (unlikely(sata_dwc_qc_complete(ap, qc, 1)))
+ goto drv_still_busy;
+ }
+
+ handled = 1;
+ goto done_irqrestore;
+ }
+
+ /*
+ * This is a NCQ command. At this point we need to figure out for which
+ * tags we have gotten a completion interrupt. One interrupt may serve
+ * as completion for more than one operation when commands are queued
+ * (NCQ). We need to process each completed command.
+ */
+
+process_cmd: /* process completed commands */
+ sactive = core_scr_read(SCR_ACTIVE);
+ tag_mask = (sata_dwc_sactive_issued | sactive) ^ sactive;
+
+ if (sactive != 0 || sata_dwc_sactive_issued > 1 || tag_mask > 1) {
+ dev_dbg(ap->dev, "%s NCQ: sactive=0x%08x sactive_issued=0x%08x"
+ " tag_mask=0x%08x\n", __func__, sactive,
+ sata_dwc_sactive_issued, tag_mask);
+ }
+
+ if ((tag_mask | sata_dwc_sactive_issued) != sata_dwc_sactive_issued) {
+ dev_warn(ap->dev, "Bad tag mask? sactive=0x%08x "
+ "sata_dwc_sactive_issued=0x%08x tag_mask=0x%08x\n",
+ sactive, sata_dwc_sactive_issued, tag_mask);
+ }
+
+ /* read just to clear ... not bad if currently still busy */
+ status = ap->ops->sff_check_status(ap);
+ dev_dbg(ap->dev, "%s ATA status register=0x%x\n", __func__, status);
+
+ tag = 0;
+ num_processed = 0;
+ while (tag_mask) {
+ num_processed++;
+ while (!(tag_mask & 0x00000001)) {
+ tag++;
+ tag_mask <<= 1;
+ }
+ tag_mask &= (~0x00000001);
+ qc = ata_qc_from_tag(ap, tag);
+
+ /* To be picked up by completion functions */
+ qc->ap->link.active_tag = tag;
+ hsdevp->cmd_issued[tag] = SATA_DWC_CMD_ISSUED_NOT;
+
+ /* Let libata/scsi layers handle error */
+ if (status & ATA_ERR) {
+ dev_dbg(ap->dev, "%s ATA_ERR (0x%x)\n",
+ __func__, status);
+
+ sata_dwc_qc_complete(ap, qc, 1);
+ handled = 1;
+ goto done_irqrestore;
+ }
+
+ /* Process completed command */
+ dev_dbg(ap->dev, "%s NCQ command, protocol: %s\n", __func__,
+ prot_2_txt(qc->tf.protocol));
+ if (ata_is_dma(qc->tf.protocol)) {
+ dma_interrupt_count++;
+ if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PEND_NONE)
+ dev_warn(ap->dev,
+ "%s: DMA not pending?\n", __func__);
+ if ((dma_interrupt_count % 2) == 0)
+ sata_dwc_dma_xfer_complete(ap, 1);
+ } else {
+ if (unlikely(sata_dwc_qc_complete(ap, qc, 1)))
+ goto still_busy;
+ }
+ continue;
+
+still_busy:
+ ap->stats.idle_irq++;
+ dev_warn(ap->dev, "STILL BUSY IRQ ata%d: irq trap\n",
+ ap->print_id);
+ } /* while tag_mask */
+
+ /*
+ * Check to see if any commands completed while we were processing our
+ * initial set of completed commands (reading of status clears
+ * interrupts, so we might miss a completed command interrupt if one
+ * came in while we were processing:
+ * we read status as part of processing a completed command).
+ */
+ sactive2 = core_scr_read(SCR_ACTIVE);
+ if (sactive2 != sactive) {
+ dev_dbg(ap->dev, "More finished - sactive=0x%x sactive2=0x%x\n",
+ sactive, sactive2);
+ goto process_cmd;
+ }
+ handled = 1;
+
+done_irqrestore:
+ spin_unlock_irqrestore(&host->lock, flags);
+ return IRQ_RETVAL(handled);
+}
+
+static void sata_dwc_clear_dmacr(struct sata_dwc_device_port *hsdevp, u8 tag)
+{
+ struct sata_dwc_device *hsdev = HSDEV_FROM_HSDEVP(hsdevp);
+
+ if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PEND_RX) {
+ out_le32(&(hsdev->sata_dwc_regs->dmacr),
+ SATA_DWC_DMACR_RX_CLEAR(
+ in_le32(&(hsdev->sata_dwc_regs->dmacr))));
+ } else if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PEND_TX) {
+ out_le32(&(hsdev->sata_dwc_regs->dmacr),
+ SATA_DWC_DMACR_TX_CLEAR(
+ in_le32(&(hsdev->sata_dwc_regs->dmacr))));
+ } else {
+ /*
+ * This should not happen, it indicates the driver is out of
+ * sync. If it does happen, clear dmacr anyway.
+ */
+ dev_err(dwc_dev, "%s DMA protocol RX and TX DMA not pending "
+ "tag=0x%02x pending=%d dmacr: 0x%08x\n",
+ __func__, tag, hsdevp->dma_pending[tag],
+ in_le32(&(hsdev->sata_dwc_regs->dmacr)));
+ out_le32(&(hsdev->sata_dwc_regs->dmacr),
+ SATA_DWC_DMACR_TXRXCH_CLEAR);
+ }
+}
+
+static void sata_dwc_dma_xfer_complete(struct ata_port *ap, u32 check_status)
+{
+ struct ata_queued_cmd *qc;
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ u8 tag = 0;
+
+ tag = ap->link.active_tag;
+ qc = ata_qc_from_tag(ap, tag);
+
+#ifdef DEBUG_NCQ
+ if (tag > 0) {
+ dev_info(ap->dev, "%s tag=%u cmd=0x%02x dma dir=%s proto=%s "
+ "dmacr=0x%08x\n", __func__, qc->tag, qc->tf.command,
+ dir_2_txt(qc->dma_dir), prot_2_txt(qc->tf.protocol),
+ in_le32(&(hsdev->sata_dwc_regs->dmacr)));
+ }
+#endif
+
+ if (ata_is_dma(qc->tf.protocol)) {
+ if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PEND_NONE) {
+ dev_err(ap->dev, "%s DMA protocol RX and TX DMA not "
+ "pending dmacr: 0x%08x\n", __func__,
+ in_le32(&(hsdev->sata_dwc_regs->dmacr)));
+ }
+
+ hsdevp->dma_pending[tag] = SATA_DWC_DMA_PEND_NONE;
+ sata_dwc_qc_complete(ap, qc, check_status);
+ ap->link.active_tag = ATA_TAG_POISON;
+ } else {
+ sata_dwc_qc_complete(ap, qc, check_status);
+ }
+}
+
+static int sata_dwc_qc_complete(struct ata_port *ap, struct ata_queued_cmd *qc,
+ u32 check_status)
+{
+ u8 status = 0;
+ int i = 0;
+ u32 mask = 0x0;
+ u8 tag = qc->tag;
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ u32 serror;
+
+ dev_dbg(ap->dev, "%s checkstatus? %x\n", __func__, check_status);
+
+ if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PEND_TX)
+ dev_err(ap->dev, "TX DMA PENDING\n");
+ else if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PEND_RX)
+ dev_err(ap->dev, "RX DMA PENDING\n");
+
+ if (check_status) {
+ i = 0;
+ do {
+ /* check main status, clearing INTRQ */
+ status = ap->ops->sff_check_status(ap);
+ if (status & ATA_BUSY) {
+ dev_dbg(ap->dev, "STATUS BUSY (0x%02x) [%d]\n",
+ status, i);
+ }
+ if (++i > 10)
+ break;
+ } while (status & ATA_BUSY);
+
+ status = ap->ops->sff_check_status(ap);
+ if (unlikely(status & ATA_BUSY))
+ dev_err(ap->dev, "QC complete cmd=0x%02x STATUS BUSY "
+ "(0x%02x) [%d]\n", qc->tf.command, status, i);
+ serror = core_scr_read(SCR_ERROR);
+ if (serror & SATA_DWC_SERROR_ERR_BITS)
+ dev_err(ap->dev, "****** SERROR=0x%08x ******\n",
+ serror);
+ }
+ dev_dbg(ap->dev, "QC complete cmd=0x%02x status=0x%02x ata%u: "
+ "protocol=%d\n", qc->tf.command, status, ap->print_id,
+ qc->tf.protocol);
+
+ /* clear active bit */
+ mask = (~(qcmd_tag_to_mask(tag)));
+ sata_dwc_sactive_queued = sata_dwc_sactive_queued & mask;
+ sata_dwc_sactive_issued = sata_dwc_sactive_issued & mask;
+
+ /* Complete taskfile transaction (does not read SCR registers) */
+ ata_qc_complete(qc);
+
+ return 0;
+}
+
+static void sata_dwc_enable_interrupts(struct sata_dwc_device *hsdev)
+{
+ /* Enable selective interrupts by setting the interrupt mask register */
+ out_le32(&hsdev->sata_dwc_regs->intmr,
+ SATA_DWC_INTMR_ERRM |
+ SATA_DWC_INTMR_NEWFPM |
+ SATA_DWC_INTMR_PMABRTM |
+ SATA_DWC_INTMR_DMATM);
+
+ /*
+ * Unmask the error bits that should trigger an error interrupt by
+ * setting the error mask register.
+ */
+ out_le32(&hsdev->sata_dwc_regs->errmr, SATA_DWC_SERROR_ERR_BITS);
+
+ dev_dbg(dwc_dev, "%s: INTMR = 0x%08x, ERRMR = 0x%08x\n", __func__,
+ in_le32(&hsdev->sata_dwc_regs->intmr),
+ in_le32(&hsdev->sata_dwc_regs->errmr));
+}
+
+static void sata_dwc_setup_port(struct ata_ioports *port, unsigned long base)
+{
+ port->cmd_addr = (void *)base + 0x00;
+ port->data_addr = (void *)base + 0x00;
+
+ port->error_addr = (void *)base + 0x04;
+ port->feature_addr = (void *)base + 0x04;
+
+ port->nsect_addr = (void *)base + 0x08;
+
+ port->lbal_addr = (void *)base + 0x0c;
+ port->lbam_addr = (void *)base + 0x10;
+ port->lbah_addr = (void *)base + 0x14;
+
+ port->device_addr = (void *)base + 0x18;
+ port->command_addr = (void *)base + 0x1c;
+ port->status_addr = (void *)base + 0x1c;
+
+ port->altstatus_addr = (void *)base + 0x20;
+ port->ctl_addr = (void *)base + 0x20;
+}
+
+/*
+ * Function : sata_dwc_port_start
+ * arguments : struct ata_ioports *port
+ * Return value : returns 0 if success, error code otherwise
+ * This function allocates the scatter gather LLI table for AHB DMA
+ */
+static int sata_dwc_port_start(struct ata_port *ap)
+{
+ int err = 0;
+ struct sata_dwc_device *hsdev;
+ struct sata_dwc_device_port *hsdevp = NULL;
+ struct device *pdev;
+ u32 sstatus;
+ int i;
+
+ hsdev = HSDEV_FROM_AP(ap);
+
+ dev_dbg(ap->dev, "%s: port_no=%d\n", __func__, ap->port_no);
+
+ hsdev->host = ap->host;
+ pdev = ap->host->dev;
+ if (!pdev) {
+ dev_err(ap->dev, "%s: no ap->host->dev\n", __func__);
+ err = -ENODEV;
+ goto cleanup_exit;
+ }
+
+ /* Allocate Port Struct */
+ hsdevp = kmalloc(sizeof(*hsdevp), GFP_KERNEL);
+ if (!hsdevp) {
+ dev_err(ap->dev, "%s: kmalloc failed for hsdevp\n", __func__);
+ err = -ENOMEM;
+ goto cleanup_exit;
+ }
+ memset(hsdevp, 0, sizeof(*hsdevp));
+ hsdevp->hsdev = hsdev;
+
+ for (i = 0; i < SATA_DWC_QCMD_MAX; i++)
+ hsdevp->cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT;
+
+ ap->prd = 0; /* set these so libata doesn't use them */
+ ap->prd_dma = 0;
+
+ /*
+ * DMA - Assign scatter gather LLI table. We can't use the libata
+ * version since it's PRD is IDE PCI specific.
+ */
+ for (i = 0; i < SATA_DWC_QCMD_MAX; i++) {
+ hsdevp->llit[i] = dma_alloc_coherent(pdev,
+ SATA_DWC_DMAC_LLI_TBL_SZ,
+ &(hsdevp->llit_dma[i]),
+ GFP_ATOMIC);
+ if (!hsdevp->llit[i]) {
+ dev_err(ap->dev, "%s: dma_alloc_coherent failed size "
+ "0x%x\n", __func__, SATA_DWC_DMAC_LLI_TBL_SZ);
+ err = -ENOMEM;
+ goto cleanup_exit;
+ }
+ }
+
+ if (ap->port_no == 0) {
+ dev_dbg(ap->dev, "%s: clearing TXCHEN, RXCHEN in DMAC\n",
+ __func__);
+
+ out_le32(&hsdev->sata_dwc_regs->dmacr,
+ SATA_DWC_DMACR_TXRXCH_CLEAR);
+
+ dev_dbg(ap->dev, "%s: setting burst size in DBTSR\n", __func__);
+ out_le32(&hsdev->sata_dwc_regs->dbtsr,
+ (SATA_DWC_DBTSR_MWR(AHB_DMA_BRST_DFLT) |
+ SATA_DWC_DBTSR_MRD(AHB_DMA_BRST_DFLT)));
+ }
+
+ /* Clear any error bits before libata starts issuing commands */
+ clear_serror();
+
+ ap->private_data = hsdevp;
+
+ /* Are we in Gen I or II */
+ sstatus = core_scr_read(SCR_STATUS);
+ switch (SATA_DWC_SCR0_SPD_GET(sstatus)) {
+ case 0x0:
+ dev_info(ap->dev, "**** No neg speed (nothing attached?) \n");
+ break;
+ case 0x1:
+ dev_info(ap->dev, "**** GEN I speed rate negotiated \n");
+ break;
+ case 0x2:
+ dev_info(ap->dev, "**** GEN II speed rate negotiated \n");
+ break;
+ }
+
+cleanup_exit:
+ if (err) {
+ kfree(hsdevp);
+ sata_dwc_port_stop(ap);
+ dev_dbg(ap->dev, "%s: fail\n", __func__);
+ } else {
+ dev_dbg(ap->dev, "%s: done\n", __func__);
+ }
+
+ return err;
+}
+
+static void sata_dwc_port_stop(struct ata_port *ap)
+{
+ int i;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+
+ dev_dbg(ap->dev, "%s: ap->id = %d\n", __func__, ap->print_id);
+
+ if (hsdevp && hsdev) {
+ /* deallocate LLI table */
+ for (i = 0; i < SATA_DWC_QCMD_MAX; i++) {
+ dma_free_coherent(ap->host->dev,
+ SATA_DWC_DMAC_LLI_TBL_SZ,
+ hsdevp->llit[i], hsdevp->llit_dma[i]);
+ }
+
+ kfree(hsdevp);
+ }
+ ap->private_data = NULL;
+}
+
+/*
+ * Function : sata_dwc_exec_command_by_tag
+ * arguments : ata_port *ap, ata_taskfile *tf, u8 tag, u32 cmd_issued
+ * Return value : None
+ * This function keeps track of individual command tag ids and calls
+ * ata_exec_command in libata
+ */
+static void sata_dwc_exec_command_by_tag(struct ata_port *ap,
+ struct ata_taskfile *tf,
+ u8 tag, u32 cmd_issued)
+{
+ unsigned long flags;
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+
+ dev_dbg(ap->dev, "%s cmd(0x%02x): %s tag=%d\n", __func__, tf->command,
+ ata_cmd_2_txt(tf), tag);
+
+ spin_lock_irqsave(&ap->host->lock, flags);
+ hsdevp->cmd_issued[tag] = cmd_issued;
+ spin_unlock_irqrestore(&ap->host->lock, flags);
+
+ /*
+ * Clear SError before executing a new command.
+ *
+ * TODO if we read a PM's registers now, we will throw away the task
+ * file values loaded into the shadow registers for this command.
+ *
+ * sata_dwc_scr_write and read can not be used here. Clearing the PM
+ * managed SError register for the disk needs to be done before the
+ * task file is loaded.
+ */
+ clear_serror();
+ ata_sff_exec_command(ap, tf);
+}
+
+static void sata_dwc_bmdma_setup_by_tag(struct ata_queued_cmd *qc, u8 tag)
+{
+ sata_dwc_exec_command_by_tag(qc->ap, &qc->tf, tag,
+ SATA_DWC_CMD_ISSUED_PEND);
+}
+
+static void sata_dwc_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ u8 tag = qc->tag;
+
+ if (ata_is_ncq(qc->tf.protocol)) {
+ dev_dbg(qc->ap->dev, "%s: ap->link.sactive=0x%08x tag=%d\n",
+ __func__, qc->ap->link.sactive, tag);
+ } else {
+ tag = 0;
+ }
+
+ sata_dwc_bmdma_setup_by_tag(qc, tag);
+}
+
+static void sata_dwc_bmdma_start_by_tag(struct ata_queued_cmd *qc, u8 tag)
+{
+ int start_dma;
+ u32 reg, dma_chan;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_QC(qc);
+ struct ata_port *ap = qc->ap;
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ int dir = qc->dma_dir;
+ dma_chan = hsdevp->dma_chan[tag];
+
+ /* Used for ata_bmdma_start(qc) -- we are not BMDMA compatible */
+
+ if (hsdevp->cmd_issued[tag] != SATA_DWC_CMD_ISSUED_NOT) {
+ start_dma = 1;
+ if (dir == DMA_TO_DEVICE)
+ hsdevp->dma_pending[tag] = SATA_DWC_DMA_PEND_TX;
+ else
+ hsdevp->dma_pending[tag] = SATA_DWC_DMA_PEND_RX;
+ } else {
+ dev_err(ap->dev, "%s: Command not pending cmd_issued=%d "
+ "(tag=%d) - DMA NOT started\n", __func__,
+ hsdevp->cmd_issued[tag], tag);
+ start_dma = 0;
+ }
+
+ dev_dbg(ap->dev, "%s qc=%p tag: %x cmd: 0x%02x dma_dir: %s "
+ "start_dma? %x\n", __func__, qc, tag, qc->tf.command,
+ dir_2_txt(qc->dma_dir), start_dma);
+ sata_dwc_tf_dump(&(qc->tf));
+
+ if (start_dma) {
+ reg = core_scr_read(SCR_ERROR);
+ if (reg & SATA_DWC_SERROR_ERR_BITS) {
+ dev_err(ap->dev, "%s: ****** SError=0x%08x ******\n",
+ __func__, reg);
+ }
+
+ if (dir == DMA_TO_DEVICE)
+ out_le32(&hsdev->sata_dwc_regs->dmacr,
+ SATA_DWC_DMACR_TXCHEN);
+ else
+ out_le32(&hsdev->sata_dwc_regs->dmacr,
+ SATA_DWC_DMACR_RXCHEN);
+
+ /* Enable AHB DMA transfer on the specified channel */
+ dma_dwc_xfer_start(dma_chan);
+ }
+}
+
+static void sata_dwc_bmdma_start(struct ata_queued_cmd *qc)
+{
+ u8 tag = qc->tag;
+
+ if (ata_is_ncq(qc->tf.protocol)) {
+ dev_dbg(qc->ap->dev, "%s: ap->link.sactive=0x%08x tag=%d\n",
+ __func__, qc->ap->link.sactive, tag);
+ } else {
+ tag = 0;
+ }
+
+ dev_dbg(qc->ap->dev, "%s\n", __func__);
+ sata_dwc_bmdma_start_by_tag(qc, tag);
+}
+
+/*
+ * Function : sata_dwc_qc_prep_by_tag
+ * arguments : ata_queued_cmd *qc, u8 tag
+ * Return value : None
+ * qc_prep for a particular queued command based on tag
+ */
+static void sata_dwc_qc_prep_by_tag(struct ata_queued_cmd *qc, u8 tag)
+{
+ struct scatterlist *sg = qc->sg;
+ struct ata_port *ap = qc->ap;
+ u32 dma_chan;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ int dir;
+ int err;
+
+ dir = qc->dma_dir;
+
+ if ((dir == DMA_NONE) || (qc->tf.protocol == ATA_PROT_PIO))
+ return;
+
+ dev_dbg(ap->dev, "%s: port=%d dma dir=%s n_elem=%d\n",
+ __func__, ap->port_no, dir_2_txt(dir), qc->n_elem);
+
+ dma_chan = dma_dwc_xfer_setup(sg, qc->n_elem, hsdevp->llit[tag],
+ hsdevp->llit_dma[tag],
+ (void *__iomem)(&hsdev->sata_dwc_regs->dmadr),
+ dir);
+ if (dma_chan < 0) {
+ dev_err(ap->dev, "%s: dma_dwc_xfer_setup returns err %d\n",
+ __func__, err);
+ return;
+ }
+
+ hsdevp->dma_chan[tag] = dma_chan;
+}
+
+static unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+#ifdef DEBUG_NCQ
+ if (qc->tag > 0 || ap->link.sactive > 1) {
+ dev_info(ap->dev, "%s ap id=%d cmd(0x%02x)=%s qc tag=%d prot=%s"
+ " ap active_tag=0x%08x ap sactive=0x%08x\n",
+ __func__, ap->print_id, qc->tf.command,
+ ata_cmd_2_txt(&qc->tf), qc->tag,
+ prot_2_txt(qc->tf.protocol), ap->link.active_tag,
+ ap->link.sactive);
+ }
+#endif
+
+ if (ata_is_ncq(qc->tf.protocol)) {
+ ap->ops->sff_tf_load(ap, &qc->tf);
+ sata_dwc_exec_command_by_tag(ap, &qc->tf, qc->tag,
+ SATA_DWC_CMD_ISSUED_PEND);
+ } else {
+ ata_sff_qc_issue(qc);
+ }
+
+ return 0;
+}
+
+/*
+ * Function : sata_dwc_eng_timeout
+ * arguments : ata_port *ap
+ * Return value : None
+ * error handler for DMA time out
+ * ata_eng_timeout(ap) -- this does bmdma stuff which can not be done by this
+ * driver. SEE ALSO ata_qc_timeout(ap)
+ */
+static void sata_dwc_eng_timeout(struct ata_port *ap)
+{
+ struct ata_queued_cmd *qc;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ u8 tag;
+ uint mask = 0x0;
+ unsigned long flags;
+ u32 serror, intpr, dma_ch;
+
+ tag = ap->link.active_tag;
+ dma_ch = hsdevp->dma_chan[tag];
+ qc = ata_qc_from_tag(ap, tag);
+
+ dev_err(ap->dev, "%s: id=%d active_tag=%d qc=%p dma_chan=%d\n",
+ __func__, ap->print_id, tag, qc, dma_ch);
+
+ if (!qc) {
+ dev_err(ap->dev,
+ "%s: timeout without queued command\n", __func__);
+ return;
+ }
+
+ intpr = in_le32(&hsdev->sata_dwc_regs->intpr);
+ serror = core_scr_read(SCR_ERROR);
+
+ dev_err(ap->dev, "intpr=0x%08x serror=0x%08x\n", intpr, serror);
+
+ /* If there are no error bits set, can we just pass this on to eh? */
+ if (!(serror & SATA_DWC_SERROR_ERR_BITS) &&
+ !(intpr & SATA_DWC_INTPR_ERR)) {
+
+ spin_lock_irqsave(&ap->host->lock, flags);
+ if (dma_dwc_channel_enabled(dma_ch))
+ dma_dwc_terminate_dma(dma_ch);
+
+ hsdevp->dma_pending[tag] = SATA_DWC_DMA_PEND_NONE;
+
+ /* clear active bit */
+ mask = (~(qcmd_tag_to_mask(tag)));
+ sata_dwc_sactive_queued = sata_dwc_sactive_queued & mask;
+ sata_dwc_sactive_issued = sata_dwc_sactive_issued & mask;
+
+ spin_unlock_irqrestore(&ap->host->lock, flags);
+ } else {
+ /* This is wrong, what really needs to be done is a reset. */
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ if (ata_is_dma(qc->tf.protocol)) {
+ /* disable DMAC */
+ dma_dwc_terminate_dma(dma_ch);
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+ }
+
+ WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
+ if (qc->flags & ATA_QCFLAG_ACTIVE) {
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ /*
+ * test-only: The original code (AMCC: 2.6.19) called
+ * ata_eng_timeout(ap) here. This function is not available
+ * anymore. So what to do now?
+ */
+ }
+}
+
+/*
+ * Function : sata_dwc_qc_prep
+ * arguments : ata_queued_cmd *qc
+ * Return value : None
+ * qc_prep for a particular queued command
+ */
+static void sata_dwc_qc_prep(struct ata_queued_cmd *qc)
+{
+ u32 sactive;
+ u8 tag = qc->tag;
+
+#ifdef DEBUG_NCQ
+ if (qc->tag > 0) {
+ dev_info(qc->ap->dev, "%s: qc->tag=%d ap->active_tag=0x%08x\n",
+ __func__, tag, qc->ap->link.active_tag);
+ }
+#endif
+
+ if (qc->tf.protocol == ATA_PROT_NCQ) {
+ sactive = core_scr_read(SCR_ACTIVE);
+ sactive |= (0x00000001 << tag);
+ core_scr_write(SCR_ACTIVE, sactive);
+ dev_dbg(qc->ap->dev, "%s: tag=%d ap->link.sactive = 0x%08x "
+ "sactive=0x%08x\n", __func__, tag, qc->ap->link.sactive,
+ sactive);
+ } else {
+ tag = 0;
+ }
+
+ sata_dwc_qc_prep_by_tag(qc, tag);
+}
+
+/*
+ * test-only: Needed when no drive is connected upon driver startup.
+ * Otherwise, by using the default prereset routine, the driver crashes
+ * upon loading.
+ * Not sure if this could be handled differently.
+ */
+static int sata_dwc_prereset(struct ata_link *link, unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &ap->link.eh_context;
+ int rc = 0;
+
+ if (ata_link_online(link)) {
+ rc = ata_sff_wait_ready(link, deadline);
+ } else {
+ /* tell EH to bail */
+ ehc->i.action &= ~ATA_EH_RESET;
+ }
+
+ return rc;
+}
+
+/*
+ * scsi mid-layer and libata interface structures
+ */
+static struct scsi_host_template sata_dwc_sht = {
+ ATA_NCQ_SHT(DRV_NAME),
+ /*
+ * test-only: Currently this driver doesn't handle NCQ
+ * correctly. We enable NCQ but set the queue depth to a
+ * max of 1. This will get fixed in in a future release.
+ */
+ .can_queue = ATA_DEF_QUEUE, /* ATA_MAX_QUEUE */
+ .dma_boundary = ATA_DMA_BOUNDARY,
+};
+
+static struct ata_port_operations sata_dwc_ops = {
+ .inherits = &ata_sff_port_ops,
+
+ .qc_prep = sata_dwc_qc_prep,
+ .qc_issue = sata_dwc_qc_issue,
+
+ .scr_read = sata_dwc_scr_read,
+ .scr_write = sata_dwc_scr_write,
+
+ .port_start = sata_dwc_port_start,
+ .port_stop = sata_dwc_port_stop,
+
+ .bmdma_setup = sata_dwc_bmdma_setup,
+ .bmdma_start = sata_dwc_bmdma_start,
+
+ .prereset = sata_dwc_prereset,
+
+ /* test-only: really needed? */
+ .eng_timeout = sata_dwc_eng_timeout,
+};
+
+static const struct ata_port_info sata_dwc_port_info[] = {
+ {
+ /*
+ * test-only: Currently this driver doesn't handle NCQ
+ * correctly. So we disable NCQ here for now. To enable
+ * it ATA_FLAG_NCQ needs to be added to the flags below.
+ */
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO,
+ .pio_mask = 0x1f, /* pio 0-4 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &sata_dwc_ops,
+ },
+};
+
+static int sata_dwc_probe(struct platform_device *pdev)
+{
+ struct sata_dwc_device *hsdev;
+ u32 idr, versionr;
+ char *ver = (char *)&versionr;
+ u8 *base = NULL;
+ int err = 0;
+ struct resource *res;
+ int irq;
+ struct ata_host *host;
+ struct ata_port_info pi = sata_dwc_port_info[0];
+ const struct ata_port_info *ppi[] = { &pi, NULL };
+
+
+ /* Allocate DWC SATA device */
+ hsdev = kmalloc(sizeof(*hsdev), GFP_KERNEL);
+ if (hsdev == NULL) {
+ dev_err(&pdev->dev, "kmalloc failed for hsdev\n");
+ err = -ENOMEM;
+ goto error_out;
+ }
+ memset(hsdev, 0, sizeof(*hsdev));
+
+ /* Get physical SATA register base address */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no reg addr\n");
+ err = -ENODEV;
+ goto error_out;
+ }
+
+ /* Ioremap SATA registers */
+ base = ioremap(res->start, res->end - res->start + 1);
+ if (!base) {
+ dev_err(&pdev->dev, "ioremap failed for 0x%llx\n", res->start);
+ err = -ENODEV;
+ goto error_out;
+ }
+ hsdev->reg_base = base;
+ dev_dbg(&pdev->dev, "ioremap done (0x%llx -> 0x%08x)\n",
+ res->start, (u32)base);
+
+ /* Synopsys DWC SATA specific Registers */
+ hsdev->sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET);
+
+ /* Allocate and fill host */
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, SATA_DWC_MAX_PORTS);
+ if (!host) {
+ dev_err(&pdev->dev, "ata_host_alloc_pinfo failed\n");
+ err = -ENOMEM;
+ goto error_out;
+ }
+
+ host->private_data = hsdev;
+
+ /* Setup port */
+ host->ports[0]->ioaddr.cmd_addr = base;
+ host->ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET;
+ scr_addr_sstatus = base + SATA_DWC_SCR_OFFSET;
+ sata_dwc_setup_port(&host->ports[0]->ioaddr, (unsigned long)base);
+
+ /* Read the ID and Version Registers */
+ idr = in_le32(&hsdev->sata_dwc_regs->idr);
+ versionr = in_le32(&hsdev->sata_dwc_regs->versionr);
+ dev_notice(&pdev->dev, "id %d, controller version %c.%c%c\n",
+ idr, ver[0], ver[1], ver[2]);
+
+ /* Get SATA DMA interrupt number */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "no SATA DMA irq\n");
+ err = -ENODEV;
+ goto error_out;
+ }
+ irq = res->start;
+
+ /* Get physical SATA DMA register base address */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "no reg addr\n");
+ err = -ENODEV;
+ goto error_out;
+ }
+
+ /* Save dev for later use in dev_xxx() routines */
+ dwc_dev = &pdev->dev;
+
+ /* Initialize AHB DMAC */
+ dma_dwc_init(hsdev, res, irq);
+
+ /* Enable SATA Interrupts */
+ sata_dwc_enable_interrupts(hsdev);
+
+ /* Get SATA interrupt number */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no SATA irq\n");
+ err = -ENODEV;
+ goto error_out;
+ }
+ irq = res->start;
+
+ /*
+ * Now, register with libATA core, this will also initiate the
+ * device discovery process, invoking our port_start() handler &
+ * error_handler() to execute a dummy Softreset EH session
+ */
+ ata_host_activate(host, irq, sata_dwc_isr, 0, &sata_dwc_sht);
+
+ dev_set_drvdata(&pdev->dev, host);
+
+ /* Everything is fine */
+ return 0;
+
+error_out:
+ /* Free SATA DMA resources */
+ dma_dwc_exit(hsdev);
+
+ if (base)
+ iounmap(base);
+
+ kfree(hsdev);
+
+ return err;
+}
+
+static int sata_dwc_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct sata_dwc_device *hsdev = host->private_data;
+
+ ata_host_detach(host);
+
+ dev_set_drvdata(dev, NULL);
+
+ /* Free SATA DMA resources */
+ dma_dwc_exit(hsdev);
+
+ iounmap(hsdev->reg_base);
+ kfree(hsdev);
+ kfree(host);
+
+ dev_dbg(&pdev->dev, "done\n");
+
+ return 0;
+}
+
+static struct platform_driver sata_dwc_driver = {
+ .probe = sata_dwc_probe,
+ .remove = sata_dwc_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init sata_dwc_init(void)
+{
+ int err;
+
+ err = platform_driver_register(&sata_dwc_driver);
+
+ return err;
+}
+
+static void __exit sata_dwc_exit(void)
+{
+ platform_driver_unregister(&sata_dwc_driver);
+}
+
+module_init(sata_dwc_init);
+module_exit(sata_dwc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mark Miesfeld <mmiesfeld@amcc.com>");
+MODULE_DESCRIPTION("DesignWare Cores SATA controller driver");
+MODULE_VERSION(DRV_VERSION);
--
1.5.5
^ permalink raw reply related
* [PATCH 3/3 v3] Add 4xx SATA dts node documentation
From: Feng Kan @ 2009-05-06 17:49 UTC (permalink / raw)
To: linuxppc-dev, linux-ide; +Cc: Feng Kan
Signed-off-by: Feng Kan <fkan@amcc.com>
---
Documentation/powerpc/dts-bindings/4xx/sata.txt | 24 +++++++++++++++++++++++
1 files changed, 24 insertions(+), 0 deletions(-)
create mode 100644 Documentation/powerpc/dts-bindings/4xx/sata.txt
diff --git a/Documentation/powerpc/dts-bindings/4xx/sata.txt b/Documentation/powerpc/dts-bindings/4xx/sata.txt
new file mode 100644
index 0000000..3ce00d0
--- /dev/null
+++ b/Documentation/powerpc/dts-bindings/4xx/sata.txt
@@ -0,0 +1,24 @@
+AMCC SoC SATA Support
+
+This following is only for the 460ex support for Designware SATA core
+
+Required properties:
+- compatible : "amcc,sata-460ex".
+- reg : the first set defines SATA controller register, the second set
+ is for the AHB DMA controller for SATA.
+- interrupt-parent: UIC3
+- interrupts: one for SATA and one for the DMA
+
+Notes:
+The SATA is only available when the first PCIe port is disabled.
+
+Example:
+
+SATA0: sata@bffd1000 {
+ compatible = "amcc,sata-460ex";
+ reg = <4 0xbffd1000 0x800 4 0xbffd0800 0x400>;
+ interrupt-parent = <&UIC3>;
+ interrupts = <0 4 /* SATA */
+ 5 4>; /* AHBDMA */
+};
+
--
1.5.5
^ permalink raw reply related
* [PATCH 2/3 v3] Added AMCC 460EX Canyonlands SATA support.
From: Feng Kan @ 2009-05-06 17:49 UTC (permalink / raw)
To: linuxppc-dev, linux-ide; +Cc: Feng Kan
Signed-off-by: Feng Kan <fkan@amcc.com>
---
arch/powerpc/boot/dts/canyonlands.dts | 8 ++
arch/powerpc/platforms/44x/Makefile | 4 +
arch/powerpc/platforms/44x/amcc-sata.c | 125 ++++++++++++++++++++++++++++++++
3 files changed, 137 insertions(+), 0 deletions(-)
create mode 100644 arch/powerpc/platforms/44x/amcc-sata.c
diff --git a/arch/powerpc/boot/dts/canyonlands.dts b/arch/powerpc/boot/dts/canyonlands.dts
index 5fd1ad0..b536223 100644
--- a/arch/powerpc/boot/dts/canyonlands.dts
+++ b/arch/powerpc/boot/dts/canyonlands.dts
@@ -163,6 +163,14 @@
interrupts = <0x1e 4>;
};
+ SATA0: sata@bffd1000 {
+ compatible = "amcc,sata-460ex";
+ reg = <4 0xbffd1000 0x800 4 0xbffd0800 0x400>;
+ interrupt-parent = <&UIC3>;
+ interrupts = <0 4 /* SATA */
+ 5 4>; /* AHBDMA */
+ };
+
POB0: opb {
compatible = "ibm,opb-460ex", "ibm,opb";
#address-cells = <1>;
diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile
index 01f51da..fa0a999 100644
--- a/arch/powerpc/platforms/44x/Makefile
+++ b/arch/powerpc/platforms/44x/Makefile
@@ -4,3 +4,7 @@ obj-$(CONFIG_EBONY) += ebony.o
obj-$(CONFIG_SAM440EP) += sam440ep.o
obj-$(CONFIG_WARP) += warp.o
obj-$(CONFIG_XILINX_VIRTEX_5_FXT) += virtex.o
+ifeq ($(CONFIG_SATA_DWC),y)
+obj-$(CONFIG_CANYONLANDS) += amcc-sata.o
+endif
+
diff --git a/arch/powerpc/platforms/44x/amcc-sata.c b/arch/powerpc/platforms/44x/amcc-sata.c
new file mode 100644
index 0000000..fdda917
--- /dev/null
+++ b/arch/powerpc/platforms/44x/amcc-sata.c
@@ -0,0 +1,125 @@
+/*
+ * AMCC Canyonlands SATA wrapper
+ *
+ * Copyright 2008 DENX Software Engineering, Stefan Roese <sr@denx.de>
+ *
+ * Extract the resources (MEM & IRQ) from the dts file and put them
+ * into the platform-device struct for usage in the platform-device
+ * SATA driver.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+
+/*
+ * Resource template will be filled dynamically with the values
+ * extracted from the dts file
+ */
+static struct resource sata_resources[] = {
+ [0] = {
+ /* 460EX SATA registers */
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ /* 460EX AHBDMA registers */
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ /* 460EX SATA IRQ */
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ /* 460EX AHBDMA IRQ */
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 dma_mask = 0xffffffffULL;
+
+static struct platform_device sata_device = {
+ .name = "sata-dwc",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(sata_resources),
+ .resource = sata_resources,
+ .dev = {
+ .dma_mask = &dma_mask,
+ .coherent_dma_mask = 0xffffffffULL,
+ }
+};
+
+static struct platform_device *ppc460ex_devs[] __initdata = {
+ &sata_device,
+};
+
+static int __devinit ppc460ex_sata_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = ofdev->node;
+ struct resource res;
+ const char *val;
+
+ /*
+ * Check if device is enabled
+ */
+ val = of_get_property(np, "status", NULL);
+ if (val && !strcmp(val, "disabled")) {
+ printk(KERN_INFO "SATA port disabled via device-tree\n");
+ return 0;
+ }
+
+ /*
+ * Extract register address reange from device tree and put it into
+ * the platform device structure
+ */
+ if (of_address_to_resource(np, 0, &res)) {
+ printk(KERN_ERR "%s: Can't get SATA register address\n",
+ __func__);
+ return -ENOMEM;
+ }
+ sata_resources[0].start = res.start;
+ sata_resources[0].end = res.end;
+
+ if (of_address_to_resource(np, 1, &res)) {
+ printk(KERN_ERR "%s: Can't get AHBDMA register address\n",
+ __func__);
+ return -ENOMEM;
+ }
+ sata_resources[1].start = res.start;
+ sata_resources[1].end = res.end;
+
+ /*
+ * Extract IRQ number(s) from device tree and put them into
+ * the platform device structure
+ */
+ sata_resources[2].start = sata_resources[2].end =
+ irq_of_parse_and_map(np, 0);
+ sata_resources[3].start = sata_resources[3].end =
+ irq_of_parse_and_map(np, 1);
+
+ return platform_add_devices(ppc460ex_devs, ARRAY_SIZE(ppc460ex_devs));
+}
+
+static int __devexit ppc460ex_sata_remove(struct of_device *ofdev)
+{
+ /* Nothing to do here */
+ return 0;
+}
+
+static const struct of_device_id ppc460ex_sata_match[] = {
+ { .compatible = "amcc,sata-460ex", },
+ {}
+};
+
+static struct of_platform_driver ppc460ex_sata_driver = {
+ .name = "sata-460ex",
+ .match_table = ppc460ex_sata_match,
+ .probe = ppc460ex_sata_probe,
+ .remove = ppc460ex_sata_remove,
+};
+
+static int __init ppc460ex_sata_init(void)
+{
+ return of_register_platform_driver(&ppc460ex_sata_driver);
+}
+device_initcall(ppc460ex_sata_init);
--
1.5.5
^ permalink raw reply related
* Re: [PATCH 2/2] x86-64: seccomp: fix 32/64 syscall hole
From: Markus Gutschke @ 2009-05-06 18:42 UTC (permalink / raw)
To: Linus Torvalds
Cc: linux-mips, x86, linux-kernel, linuxppc-dev, sparclinux,
Andrew Morton, stable, Roland McGrath
In-Reply-To: <alpine.LFD.2.00.0902280916470.3111@localhost.localdomain>
[-- Attachment #1: Type: text/plain, Size: 469 bytes --]
On Sat, Feb 28, 2009 at 10:23, Linus Torvalds <torvalds@linux-foundation.org
> wrote:
> And I guess the seccomp interaction means that this is potentially a
> 2.6.29 thing. Not that I know whether anybody actually _uses_ seccomp. It
> does seem to be enabled in at least Fedora kernels, but it might not be
> used anywhere.
>
In the Linux version of Google Chrome, we are currently working on code that
will use seccomp for parts of our sandboxing solution.
Markus
[-- Attachment #2: Type: text/html, Size: 752 bytes --]
^ permalink raw reply
* Re: [PATCH 2/2] x86-64: seccomp: fix 32/64 syscall hole
From: Markus Gutschke (顧孟勤) @ 2009-05-06 18:46 UTC (permalink / raw)
To: Linus Torvalds
Cc: linux-mips, x86, linux-kernel, linuxppc-dev, sparclinux,
Andrew Morton, stable, Roland McGrath
In-Reply-To: <alpine.LFD.2.00.0902280916470.3111@localhost.localdomain>
On Sat, Feb 28, 2009 at 10:23, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
> And I guess the seccomp interaction means that this is potentially a
> 2.6.29 thing. Not that I know whether anybody actually _uses_ seccomp. It
> does seem to be enabled in at least Fedora kernels, but it might not be
> used anywhere.
In the Linux version of Google Chrome, we are currently working on
code that will use seccomp for parts of our sandboxing solution.
Markus
^ permalink raw reply
* RE: MSR_SPE - being turned off...
From: Morrison, Tom @ 2009-05-06 19:33 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev, Michael Neuling
In-Reply-To: <62217899-08C0-473A-8784-DEEC64A145DD@kernel.crashing.org>
After sitting with the developer of the application for a while, we may
have=20
two separate issues...
a) Alignment (aka: alignment exceptions) - Looking at how it handles it=20
And attempts to=20
b) For aligned data - we still contend that if you have enough tasks
working
>> -----Original Message-----
>> From: Kumar Gala [mailto:galak@kernel.crashing.org]
>> Sent: Wednesday, May 06, 2009 8:44 AM
>> To: Morrison, Tom
>> Cc: Michael Neuling; linuxppc-dev@ozlabs.org
>> Subject: Re: MSR_SPE - being turned off...
>>=20
>> Can you describe the # of processes you are running in your test. Is
>> it possible for you to try the tests w/2.6.29 from kernel.org?
>>=20
>> - k
>>=20
>> On May 6, 2009, at 7:42 AM, Morrison, Tom wrote:
>>=20
>> > I'm sorry I forgot to put that, this issue was found with our
>> > currently running kernel 2.6.23.final (what comes with the
>> > Freescale LTIB BSP package dated 05/23/2009).
>> >
>> > I am sorry if I don't understand your statement that the SMP might
>> > be broken on this kernel, because I tried to analyze the kernel
that
>> > came with the latest BSP LTIB [ackage from Freescale (dated
12/18/2009
>> > (where we got the 4.2.171 compiler from)), and the associated
'switch
>> > context' code is exactly the same. Unfortunately, I have not
started
>> > the process of porting my current platform's BSP to this new kernel
-
>> > otherwise, I would have done the test on that platform (this also
>> > requires a new version of u-boot in order to test correctly))..
>> >
>> > I may have mis-interpreted something and/or I am sure I don't
>> > understand everything about the SMP resource management (and
>> > associated SPE management), so thank you for any insight you
>> > may have on this front...
>> >
>> > Tom
>> >
>> >>> -----Original Message-----
<snip other emails>
^ permalink raw reply
* RE: MSR_SPE - being turned off...
From: Morrison, Tom @ 2009-05-06 20:15 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev, Michael Neuling
In-Reply-To: <62217899-08C0-473A-8784-DEEC64A145DD@kernel.crashing.org>
Sorry, let me try again...
>> -----Original Message-----
After sitting with the developer of the application for a while,=20
a) Alignment (aka: alignment exceptions) - Looking at how it=20
handles the instruction - it interprets these SPE as common
instructions & then resets the 'upper' 32bits.
I was just made aware that on 9/14/2007 - Kumar submitted a
patch that handles these instructions correctly (we don't
have that version - I am in the process of trying to port it=20
to my current version of the kernel (to see if part of
problem).
In general, this is a VERY disturbing thing. We 'turn on=20
SPE' in the compiler (-mspe=3Dyes)(a). We are NOT explicitly=20
using SPE instructions in our application(b), BUT(c), the
4.2.171
compiler (having origins from Code Sourcery (via Freescale))
upon
optimizations put SPE instructions in without any regard for=20
alignment (which instead of making the code faster - might
actually
make the code slower)? It's a little disturbing to me.
Stay tuned for more details about my port - and seeing if some
of my problems go away..
b) We still contend if you have multiple tasks using a (VERY) high=20
Density of SPE instructions - and the system is taxed heavily
(with lots of context switches) - there is the possibility that
a task will get unlucky and the registers setup will NOT there=20
after the context switches back (if some other task does something
else with the entire 64bits).
Tom
>>=20
>> >> -----Original Message-----
>> >> From: Kumar Gala [mailto:galak@kernel.crashing.org]
>> >> Sent: Wednesday, May 06, 2009 8:44 AM
>> >> To: Morrison, Tom
>> >> Cc: Michael Neuling; linuxppc-dev@ozlabs.org
>> >> Subject: Re: MSR_SPE - being turned off...
>> >>
>> >> Can you describe the # of processes you are running in your test.
Is
>> >> it possible for you to try the tests w/2.6.29 from kernel.org?
>> >>
>> >> - k
>> >>
>> >> On May 6, 2009, at 7:42 AM, Morrison, Tom wrote:
>> >>
>> >> > I'm sorry I forgot to put that, this issue was found with our
>> >> > currently running kernel 2.6.23.final (what comes with the
>> >> > Freescale LTIB BSP package dated 05/23/2009).
>> >> >
>> >> > I am sorry if I don't understand your statement that the SMP
might
>> >> > be broken on this kernel, because I tried to analyze the kernel
that
>> >> > came with the latest BSP LTIB [ackage from Freescale (dated
>> 12/18/2009
>> >> > (where we got the 4.2.171 compiler from)), and the associated
>> 'switch
>> >> > context' code is exactly the same. Unfortunately, I have not
started
>> >> > the process of porting my current platform's BSP to this new
kernel
>> -
>> >> > otherwise, I would have done the test on that platform (this
also
>> >> > requires a new version of u-boot in order to test correctly))..
>> >> >
>> >> > I may have mis-interpreted something and/or I am sure I don't
>> >> > understand everything about the SMP resource management (and
>> >> > associated SPE management), so thank you for any insight you
>> >> > may have on this front...
>> >> >
>> >> > Tom
>> >> >
>> >> >>> -----Original Message-----
>> <snip other emails>
^ permalink raw reply
* [PATCH 01/12] fs_enet: Use defines to set driver tunables.
From: Wolfgang Denk @ 2009-05-06 20:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: netdev, Piotr Ziecik, Wolfgang Denk
In-Reply-To: <1241640919-4650-1-git-send-email-wd@denx.de>
From: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Cc: <netdev@vger.kernel.org>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: John Rigby <jcrigby@gmail.com>
---
drivers/net/fs_enet/fs_enet-main.c | 19 ++++++++++++++-----
1 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index a9cbc31..f996a1a 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -46,6 +46,15 @@
#include "fs_enet.h"
+/* Driver tunables */
+
+#define ENET_RX_RING_SIZE 32
+#define ENET_TX_RING_SIZE 32
+#define ENET_RX_COPYBREAK 240
+
+#define ENET_USE_NAPI 1
+#define ENET_NAPI_WEIGHT 17
+
/*************************************************/
MODULE_AUTHOR("Pantelis Antoniou <panto@intracom.gr>");
@@ -1057,11 +1066,11 @@ static int __devinit fs_enet_probe(struct of_device *ofdev,
fpi->cp_command = *data;
}
- fpi->rx_ring = 32;
- fpi->tx_ring = 32;
- fpi->rx_copybreak = 240;
- fpi->use_napi = 1;
- fpi->napi_weight = 17;
+ fpi->rx_ring = ENET_RX_RING_SIZE;
+ fpi->tx_ring = ENET_TX_RING_SIZE;
+ fpi->rx_copybreak = ENET_RX_COPYBREAK;
+ fpi->use_napi = ENET_USE_NAPI;
+ fpi->napi_weight = ENET_NAPI_WEIGHT;
ret = find_phy(ofdev->node, fpi);
if (ret)
--
1.6.0.6
^ permalink raw reply related
* [PATCH 02/12] fs_enet: Add MPC5121 FEC support.
From: Wolfgang Denk @ 2009-05-06 20:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Piotr Ziecik, John Rigby, netdev, Wolfgang Denk
In-Reply-To: <1241640919-4650-1-git-send-email-wd@denx.de>
From: John Rigby <jrigby@freescale.com>
Add support for MPC512x to fs_enet driver
drivers/net/fs_enet/*
Enable fs_enet driver to work 5121 FEC
Enable it with CONFIG_FS_ENET_MPC5121_FEC
Signed-off-by: John Rigby <jrigby@freescale.com>
Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Cc: <netdev@vger.kernel.org>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: John Rigby <jcrigby@gmail.com>
---
arch/powerpc/include/asm/mpc5121_fec.h | 111 ++++++++++++++++++++++++++++++++
drivers/net/fs_enet/Kconfig | 10 ++-
drivers/net/fs_enet/fs_enet-main.c | 7 ++
drivers/net/fs_enet/fs_enet.h | 6 ++
drivers/net/fs_enet/mac-fec.c | 30 ++++++++-
drivers/net/fs_enet/mii-fec.c | 7 ++
6 files changed, 166 insertions(+), 5 deletions(-)
create mode 100644 arch/powerpc/include/asm/mpc5121_fec.h
diff --git a/arch/powerpc/include/asm/mpc5121_fec.h b/arch/powerpc/include/asm/mpc5121_fec.h
new file mode 100644
index 0000000..6bddf0b
--- /dev/null
+++ b/arch/powerpc/include/asm/mpc5121_fec.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: John Rigby, <jrigby@freescale.com>
+ *
+ * Modified version of drivers/net/fec.h:
+ *
+ * fec.h -- Fast Ethernet Controller for Motorola ColdFire SoC
+ * processors.
+ *
+ * (C) Copyright 2000-2005, Greg Ungerer (gerg@snapgear.com)
+ * (C) Copyright 2000-2001, Lineo (www.lineo.com)
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef MPC5121_FEC_H
+#define MPC5121_FEC_H
+
+typedef struct fec {
+ u32 fec_reserved0;
+ u32 fec_ievent; /* Interrupt event reg */
+ u32 fec_imask; /* Interrupt mask reg */
+ u32 fec_reserved1;
+ u32 fec_r_des_active; /* Receive descriptor reg */
+ u32 fec_x_des_active; /* Transmit descriptor reg */
+ u32 fec_reserved2[3];
+ u32 fec_ecntrl; /* Ethernet control reg */
+ u32 fec_reserved3[6];
+ u32 fec_mii_data; /* MII manage frame reg */
+ u32 fec_mii_speed; /* MII speed control reg */
+ u32 fec_reserved4[7];
+ u32 fec_mib_ctrlstat; /* MIB control/status reg */
+ u32 fec_reserved5[7];
+ u32 fec_r_cntrl; /* Receive control reg */
+ u32 fec_reserved6[15];
+ u32 fec_x_cntrl; /* Transmit Control reg */
+ u32 fec_reserved7[7];
+ u32 fec_addr_low; /* Low 32bits MAC address */
+ u32 fec_addr_high; /* High 16bits MAC address */
+ u32 fec_opd; /* Opcode + Pause duration */
+ u32 fec_reserved8[10];
+ u32 fec_hash_table_high; /* High 32bits hash table */
+ u32 fec_hash_table_low; /* Low 32bits hash table */
+ u32 fec_grp_hash_table_high; /* High 32bits hash table */
+ u32 fec_grp_hash_table_low; /* Low 32bits hash table */
+ u32 fec_reserved9[7];
+ u32 fec_x_wmrk; /* FIFO transmit water mark */
+ u32 fec_reserved10;
+ u32 fec_r_bound; /* FIFO receive bound reg */
+ u32 fec_r_fstart; /* FIFO receive start reg */
+ u32 fec_reserved11[11];
+ u32 fec_r_des_start; /* Receive descriptor ring */
+ u32 fec_x_des_start; /* Transmit descriptor ring */
+ u32 fec_r_buff_size; /* Maximum receive buff size */
+ u32 fec_reserved12[26];
+ u32 fec_dma_control; /* DMA Endian and other ctrl */
+} fec_t;
+
+/*
+ * Define the buffer descriptor structure.
+ */
+typedef struct bufdesc {
+ ushort cbd_sc; /* Control and status info */
+ ushort cbd_datlen; /* Data length */
+ uint cbd_bufaddr; /* Buffer address */
+} cbd_t;
+
+/*
+ * The following definitions courtesy of commproc.h, which where
+ * Copyright (c) 1997 Dan Malek (dmalek@jlc.net).
+ */
+#define BD_SC_WRAP ((ushort)0x2000)
+
+/*
+ * Buffer descriptor control/status used by Ethernet receive.
+ */
+#define BD_ENET_RX_EMPTY ((ushort)0x8000)
+#define BD_ENET_RX_WRAP ((ushort)0x2000)
+#define BD_ENET_RX_INTR ((ushort)0x1000)
+#define BD_ENET_RX_LAST ((ushort)0x0800)
+#define BD_ENET_RX_FIRST ((ushort)0x0400)
+#define BD_ENET_RX_MISS ((ushort)0x0100)
+#define BD_ENET_RX_LG ((ushort)0x0020)
+#define BD_ENET_RX_NO ((ushort)0x0010)
+#define BD_ENET_RX_SH ((ushort)0x0008)
+#define BD_ENET_RX_CR ((ushort)0x0004)
+#define BD_ENET_RX_OV ((ushort)0x0002)
+#define BD_ENET_RX_CL ((ushort)0x0001)
+#define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */
+
+/*
+ * Buffer descriptor control/status used by Ethernet transmit.
+ */
+#define BD_ENET_TX_READY ((ushort)0x8000)
+#define BD_ENET_TX_PAD ((ushort)0x4000)
+#define BD_ENET_TX_WRAP ((ushort)0x2000)
+#define BD_ENET_TX_INTR ((ushort)0x1000)
+#define BD_ENET_TX_LAST ((ushort)0x0800)
+#define BD_ENET_TX_TC ((ushort)0x0400)
+#define BD_ENET_TX_DEF ((ushort)0x0200)
+#define BD_ENET_TX_HB ((ushort)0x0100)
+#define BD_ENET_TX_LC ((ushort)0x0080)
+#define BD_ENET_TX_RL ((ushort)0x0040)
+#define BD_ENET_TX_UN ((ushort)0x0002)
+#define BD_ENET_TX_CSL ((ushort)0x0001)
+#define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */
+
+#endif /* MPC5121_FEC_H */
diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/fs_enet/Kconfig
index 562ea68..fc073b5 100644
--- a/drivers/net/fs_enet/Kconfig
+++ b/drivers/net/fs_enet/Kconfig
@@ -1,9 +1,13 @@
config FS_ENET
tristate "Freescale Ethernet Driver"
- depends on CPM1 || CPM2
+ depends on CPM1 || CPM2 || PPC_MPC512x
select MII
select PHYLIB
+config FS_ENET_MPC5121_FEC
+ def_bool y if (FS_ENET && PPC_MPC512x)
+ select FS_ENET_HAS_FEC
+
config FS_ENET_HAS_SCC
bool "Chip has an SCC usable for ethernet"
depends on FS_ENET && (CPM1 || CPM2)
@@ -16,13 +20,13 @@ config FS_ENET_HAS_FCC
config FS_ENET_HAS_FEC
bool "Chip has an FEC usable for ethernet"
- depends on FS_ENET && CPM1
+ depends on FS_ENET && (CPM1 || FS_ENET_MPC5121_FEC)
select FS_ENET_MDIO_FEC
default y
config FS_ENET_MDIO_FEC
tristate "MDIO driver for FEC"
- depends on FS_ENET && CPM1
+ depends on FS_ENET && (CPM1 || FS_ENET_MPC5121_FEC)
config FS_ENET_MDIO_FCC
tristate "MDIO driver for FCC"
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index f996a1a..4170d33 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -1183,11 +1183,18 @@ static struct of_device_id fs_enet_match[] = {
},
#endif
#ifdef CONFIG_FS_ENET_HAS_FEC
+#ifdef CONFIG_FS_ENET_MPC5121_FEC
+ {
+ .compatible = "fsl,mpc5121-fec",
+ .data = (void *)&fs_fec_ops,
+ },
+#else
{
.compatible = "fsl,pq1-fec-enet",
.data = (void *)&fs_fec_ops,
},
#endif
+#endif
{}
};
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
index 85a4bab..5d8258e 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -13,7 +13,13 @@
#ifdef CONFIG_CPM1
#include <asm/cpm1.h>
+#endif
+
+#ifdef CONFIG_FS_ENET_MPC5121_FEC
+#include <asm/mpc5121_fec.h>
+#endif
+#if defined(CONFIG_CPM1) || defined(CONFIG_FS_ENET_MPC5121_FEC)
struct fec_info {
fec_t __iomem *fecp;
u32 mii_speed;
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index 14e5753..b069088 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -44,6 +44,10 @@
#include <asm/cpm1.h>
#endif
+#ifdef CONFIG_FS_ENET_MPC5121_FEC
+#include <asm/mpc5121_fec.h>
+#endif
+
#include "fs_enet.h"
#include "fec.h"
@@ -285,7 +289,11 @@ static void restart(struct net_device *dev)
* Set maximum receive buffer size.
*/
FW(fecp, r_buff_size, PKT_MAXBLR_SIZE);
+#ifdef CONFIG_FS_ENET_MPC5121_FEC
+ FW(fecp, r_cntrl, PKT_MAXBUF_SIZE << 16);
+#else
FW(fecp, r_hash, PKT_MAXBUF_SIZE);
+#endif
/* get physical address */
rx_bd_base_phys = fep->ring_mem_addr;
@@ -300,9 +308,14 @@ static void restart(struct net_device *dev)
fs_init_bds(dev);
/*
- * Enable big endian and don't care about SDMA FC.
+ * Enable big endian.
*/
+#ifndef CONFIG_FS_ENET_MPC5121_FEC
+ /* Don't care about SDMA FC. */
FW(fecp, fun_code, 0x78000000);
+#else
+ FS(fecp, dma_control, 0xC0000000);
+#endif
/*
* Set MII speed.
@@ -313,7 +326,9 @@ static void restart(struct net_device *dev)
* Clear any outstanding interrupt.
*/
FW(fecp, ievent, 0xffc0);
+#ifndef CONFIG_FS_ENET_MPC5121_FEC
FW(fecp, ivec, (virq_to_hw(fep->interrupt) / 2) << 29);
+#endif
/*
* adjust to speed (only for DUET & RMII)
@@ -344,8 +359,19 @@ static void restart(struct net_device *dev)
}
#endif
+ /*
+ * Enable MII
+ */
+#ifdef CONFIG_FS_ENET_MPC5121_FEC
+ /*
+ * Only set requested bit - do not touch maximum packet size
+ * configured earlier.
+ */
+ FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE);
+#else
+ FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE);
+#endif
- FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
/*
* adjust to duplex mode
*/
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index 28077cc..9d8bd97 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -32,6 +32,7 @@
#include <linux/bitops.h>
#include <linux/platform_device.h>
#include <linux/of_platform.h>
+#include <linux/time.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
@@ -211,9 +212,15 @@ static int fs_enet_mdio_remove(struct of_device *ofdev)
}
static struct of_device_id fs_enet_mdio_fec_match[] = {
+#ifdef CONFIG_FS_ENET_MPC5121_FEC
+ {
+ .compatible = "fsl,mpc5121-fec-mdio",
+ },
+#else
{
.compatible = "fsl,pq1-fec-mdio",
},
+#endif
{},
};
--
1.6.0.6
^ permalink raw reply related
* [PATCH 07/12] mpc5121ads: Clean up and fix NAND description in mpc5121ads DTS.
From: Wolfgang Denk @ 2009-05-06 20:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Piotr Ziecik, Wolfgang Denk
In-Reply-To: <1241640919-4650-1-git-send-email-wd@denx.de>
From: Piotr Ziecik <kosmo@semihalf.com>
- Removed unused properties.
- Corrected NAND flash chip size.
Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: John Rigby <jcrigby@gmail.com>
---
arch/powerpc/boot/dts/mpc5121ads.dts | 13 ++++---------
1 files changed, 4 insertions(+), 9 deletions(-)
diff --git a/arch/powerpc/boot/dts/mpc5121ads.dts b/arch/powerpc/boot/dts/mpc5121ads.dts
index 1b83a9d..93fe12a 100644
--- a/arch/powerpc/boot/dts/mpc5121ads.dts
+++ b/arch/powerpc/boot/dts/mpc5121ads.dts
@@ -62,17 +62,12 @@
interrupt-parent = < &ipic >;
#address-cells = <1>;
#size-cells = <1>;
- bank-width = <1>;
// ADS has two Hynix 512MB Nand flash chips in a single
- // stacked package .
+ // stacked package.
chips = <2>;
- nand0@0 {
- label = "nand0";
- reg = <0x00000000 0x02000000>; // first 32 MB of chip 0
- };
- nand1@20000000 {
- label = "nand1";
- reg = <0x20000000 0x02000000>; // first 32 MB of chip 1
+ nand@0 {
+ label = "nand";
+ reg = <0x00000000 0x40000000>; // 512MB + 512MB
};
};
--
1.6.0.6
^ permalink raw reply related
* [PATCH 03/12] fs_enet: Add FEC TX Alignment workaround for MPC5121.
From: Wolfgang Denk @ 2009-05-06 20:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Piotr Ziecik, John Rigby, netdev, Wolfgang Denk
In-Reply-To: <1241640919-4650-1-git-send-email-wd@denx.de>
From: John Rigby <jrigby@freescale.com>
The FEC on 5121 has problems with misaligned tx buffers.
The RM says any alignment is ok but empirical results
show that packet buffers ending in 0x1E will sometimes
hang the FEC. Other bad alignment does not hang but will
cause silent TX failures resulting in about a 1% packet
loss as tested by ping -f from a remote host.
This patch is a work around that copies every tx packet
to an aligned skb before sending.
Signed-off-by: John Rigby <jrigby@freescale.com>
Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Cc: <netdev@vger.kernel.org>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: John Rigby <jcrigby@gmail.com>
---
drivers/net/fs_enet/Kconfig | 3 ++
drivers/net/fs_enet/fs_enet-main.c | 41 ++++++++++++++++++++++++++++++++++++
drivers/net/fs_enet/mac-fec.c | 2 +-
3 files changed, 45 insertions(+), 1 deletions(-)
diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/fs_enet/Kconfig
index fc073b5..79afd07 100644
--- a/drivers/net/fs_enet/Kconfig
+++ b/drivers/net/fs_enet/Kconfig
@@ -8,6 +8,9 @@ config FS_ENET_MPC5121_FEC
def_bool y if (FS_ENET && PPC_MPC512x)
select FS_ENET_HAS_FEC
+config FS_ENET_FEC_TX_ALIGN_WORKAROUND
+ def_bool y if FS_ENET_MPC5121_FEC
+
config FS_ENET_HAS_SCC
bool "Chip has an SCC usable for ethernet"
depends on FS_ENET && (CPM1 || CPM2)
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 4170d33..c83ffc3 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -594,6 +594,37 @@ void fs_cleanup_bds(struct net_device *dev)
/**********************************************************************************/
+#ifdef CONFIG_FS_ENET_FEC_TX_ALIGN_WORKAROUND
+static struct sk_buff *tx_skb_align_workaround(struct net_device *dev,
+ struct sk_buff *skb)
+{
+ struct sk_buff *new_skb;
+
+ /* Alloc new skb */
+ new_skb = dev_alloc_skb(ENET_RX_FRSIZE + 32);
+ if (!new_skb) {
+ printk(KERN_WARNING DRV_MODULE_NAME
+ ": %s Memory squeeze, dropping tx packet.\n",
+ dev->name);
+ return NULL;
+ }
+
+ /* Make sure new skb is properly aligned */
+ skb_align(new_skb, 32);
+
+ /* Copy data to new skb ... */
+ skb_copy_from_linear_data(skb, new_skb->data, skb->len);
+ skb_put(new_skb, skb->len);
+
+ /* ... and free an old one */
+ dev_kfree_skb_any(skb);
+
+ return new_skb;
+}
+#else
+#define tx_skb_align_workaround(dev, skb) (skb)
+#endif
+
static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
@@ -602,6 +633,16 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
u16 sc;
unsigned long flags;
+ skb = tx_skb_align_workaround(dev, skb);
+ if (!skb) {
+ /*
+ * We have lost packet due to memory allocation error in
+ * tx_skb_align_workaround(). Hopefully original skb is still
+ * valid, so try transmit it later.
+ */
+ return NETDEV_TX_BUSY;
+ }
+
spin_lock_irqsave(&fep->tx_lock, flags);
/*
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index b069088..3e86498 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -311,7 +311,7 @@ static void restart(struct net_device *dev)
* Enable big endian.
*/
#ifndef CONFIG_FS_ENET_MPC5121_FEC
- /* Don't care about SDMA FC. */
+ /* Don't care about SDMA Function Code. */
FW(fecp, fun_code, 0x78000000);
#else
FS(fecp, dma_control, 0xC0000000);
--
1.6.0.6
^ permalink raw reply related
* [PATCH 00/16] Add support for MPC512x
From: Wolfgang Denk @ 2009-05-06 20:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Wolfgang Denk
The following patch series brings support for the Freescale MPC512x
processsors up to date:
[PATCH 01/12] fs_enet: Use defines to set driver tunables.
Cc: <netdev@vger.kernel.org>
[PATCH 02/12] fs_enet: Add MPC5121 FEC support.
Cc: <netdev@vger.kernel.org>
[PATCH 03/12] fs_enet: Add FEC TX Alignment workaround for MPC5121.
Cc: <netdev@vger.kernel.org>
[PATCH 04/12] mpc5121: Added reset module registers representation.
[PATCH 05/12] mpc5121ads: Added Reset Module node to DTS.
[PATCH 06/12] mpc5121: Added NAND Flash Controller driver.
Cc: <linux-mtd@lists.infradead.org>
[PATCH 07/12] mpc5121ads: Clean up and fix NAND description in mpc5121ads DTS.
[PATCH 08/12] mpc5121: Added I2C support.
Cc: <linux-i2c@vger.kernel.org>
[PATCH 09/12] mpc5121ads: Added I2C RTC node to mpc5121ads DTS.
[PATCH 10/12] mpc5121: Add MPC5121 Real time clock driver.
Cc: <rtc-linux@googlegroups.com>
[PATCH 11/12] mpc5121: Added MPC512x DMA driver.
[PATCH 12/12] mpc5121: Added default config for MPC5121.
The patches are based on v2.6.30-rc4 and cover the following
items:
- platform, DTS
- DMA
- FEC Ethernet
- UART (without h/w flow control)
- I2C
- NAND
- RTC
The code has been tested on the Freescale/STX "MPC5121ADS" board
(board rev. 4) with a MPC5121e Rev. 2. No attempt was made to provide
backward compatibility to older silicon revisions or older revisions
of the board.
The work for this project has been approved as OSADL project by a
majority of OSADL members and funded by OSADL membership fees in 2009;
for details please see www.osadl.org.
Signed-off-by: Wolfgang Denk <wd@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: John Rigby <jcrigby@gmail.com>
---
Summary statistics:
arch/powerpc/boot/dts/aria.dts | 410 ++++++
arch/powerpc/boot/dts/mpc5121ads.dts | 25 +-
arch/powerpc/configs/512x/aria_defconfig | 1789 ++++++++++++++++++++++++
arch/powerpc/configs/512x/mpc5121ads_defconfig | 1190 ++++++++++++++++
arch/powerpc/configs/mpc5121_defconfig | 1158 +++++++++++++++
arch/powerpc/include/asm/mpc5121_fec.h | 111 ++
arch/powerpc/include/asm/mpc5121_nfc.h | 100 ++
arch/powerpc/include/asm/mpc512x.h | 13 +
arch/powerpc/platforms/512x/Kconfig | 9 +
arch/powerpc/platforms/512x/Makefile | 1 +
arch/powerpc/platforms/512x/aria.c | 73 +
arch/powerpc/platforms/512x/mpc5121_ads.c | 2 +
arch/powerpc/platforms/512x/mpc5121_generic.c | 1 +
arch/powerpc/platforms/512x/mpc512x.h | 1 +
arch/powerpc/platforms/512x/mpc512x_shared.c | 26 +
drivers/dma/Kconfig | 7 +
drivers/dma/Makefile | 1 +
drivers/dma/mpc512x_dma.c | 642 +++++++++
drivers/dma/mpc512x_dma.h | 192 +++
drivers/i2c/busses/Kconfig | 9 +-
drivers/mtd/nand/Kconfig | 7 +
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/mpc5121_nfc.c | 855 +++++++++++
drivers/net/fs_enet/Kconfig | 13 +-
drivers/net/fs_enet/fs_enet-main.c | 67 +-
drivers/net/fs_enet/fs_enet.h | 6 +
drivers/net/fs_enet/mac-fec.c | 30 +-
drivers/net/fs_enet/mii-fec.c | 13 +-
drivers/rtc/Kconfig | 10 +
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-mpc5121.c | 408 ++++++
31 files changed, 7146 insertions(+), 25 deletions(-)
^ permalink raw reply
* [PATCH 06/12] mpc5121: Added NAND Flash Controller driver.
From: Wolfgang Denk @ 2009-05-06 20:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: linux-mtd, Piotr Ziecik, Wolfgang Denk
In-Reply-To: <1241640919-4650-1-git-send-email-wd@denx.de>
From: Piotr Ziecik <kosmo@semihalf.com>
This patch adds NAND Flash Controller driver for MPC5121
revision 2. All device features, except hardware ECC and
power management, are supported.
Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Cc: <linux-mtd@lists.infradead.org>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: John Rigby <jcrigby@gmail.com>
---
arch/powerpc/include/asm/mpc5121_nfc.h | 100 +++
arch/powerpc/platforms/512x/mpc512x_shared.c | 1 +
drivers/mtd/nand/Kconfig | 7 +
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/mpc5121_nfc.c | 855 ++++++++++++++++++++++++++
5 files changed, 964 insertions(+), 0 deletions(-)
create mode 100644 arch/powerpc/include/asm/mpc5121_nfc.h
create mode 100644 drivers/mtd/nand/mpc5121_nfc.c
diff --git a/arch/powerpc/include/asm/mpc5121_nfc.h b/arch/powerpc/include/asm/mpc5121_nfc.h
new file mode 100644
index 0000000..b96a5b9
--- /dev/null
+++ b/arch/powerpc/include/asm/mpc5121_nfc.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2004-2008 Freescale Semiconductor, Inc.
+ * Copyright 2009 Semihalf.
+ *
+ * Approved as OSADL project by a majority of OSADL members and funded
+ * by OSADL membership fees in 2009; for details see www.osadl.org.
+ *
+ * Based on original driver from Freescale Semiconductor
+ * written by John Rigby <jrigby@freescale.com> on basis
+ * of drivers/mtd/nand/mxc_nand.c. Reworked and extended by
+ * Piotr Ziecik <kosmo@semihalf.com>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifndef MPC5121_NFC_H
+#define MPC5121_NFC_H
+
+/* Addresses for NFC MAIN RAM BUFFER areas */
+#define NFC_MAIN_AREA(n) ((n) * 0x200)
+
+/* Addresses for NFC SPARE BUFFER areas */
+#define NFC_SPARE_BUFFERS 8
+#define NFC_SPARE_LEN 0x40
+#define NFC_SPARE_AREA(n) (0x1000 + ((n) * NFC_SPARE_LEN))
+
+/* MPC5121 NFC registers */
+#define NFC_BUF_ADDR 0x1E04
+#define NFC_FLASH_ADDR 0x1E06
+#define NFC_FLASH_CMD 0x1E08
+#define NFC_CONFIG 0x1E0A
+#define NFC_ECC_STATUS1 0x1E0C
+#define NFC_ECC_STATUS2 0x1E0E
+#define NFC_SPAS 0x1E10
+#define NFC_WRPROT 0x1E12
+#define NFC_NF_WRPRST 0x1E18
+#define NFC_CONFIG1 0x1E1A
+#define NFC_CONFIG2 0x1E1C
+#define NFC_UNLOCKSTART_BLK0 0x1E20
+#define NFC_UNLOCKEND_BLK0 0x1E22
+#define NFC_UNLOCKSTART_BLK1 0x1E24
+#define NFC_UNLOCKEND_BLK1 0x1E26
+#define NFC_UNLOCKSTART_BLK2 0x1E28
+#define NFC_UNLOCKEND_BLK2 0x1E2A
+#define NFC_UNLOCKSTART_BLK3 0x1E2C
+#define NFC_UNLOCKEND_BLK3 0x1E2E
+
+/* Bit Definitions: NFC_BUF_ADDR */
+#define NFC_RBA_MASK (7 << 0)
+#define NFC_ACTIVE_CS_SHIFT 5
+#define NFC_ACTIVE_CS_MASK (3 << NFC_ACTIVE_CS_SHIFT)
+
+/* Bit Definitions: NFC_CONFIG */
+#define NFC_BLS_UNLOCKED (1 << 1)
+
+/* Bit Definitions: NFC_CONFIG1 */
+#define NFC_ECC_4BIT (1 << 0)
+#define NFC_FULL_PAGE_DMA (1 << 1)
+#define NFC_SPARE_ONLY (1 << 2)
+#define NFC_ECC_ENABLE (1 << 3)
+#define NFC_INT_MASK (1 << 4)
+#define NFC_BIG_ENDIAN (1 << 5)
+#define NFC_RESET (1 << 6)
+#define NFC_CE (1 << 7)
+#define NFC_ONE_CYCLE (1 << 8)
+#define NFC_PPB_32 (0 << 9)
+#define NFC_PPB_64 (1 << 9)
+#define NFC_PPB_128 (2 << 9)
+#define NFC_PPB_256 (3 << 9)
+#define NFC_PPB_MASK (3 << 9)
+#define NFC_FULL_PAGE_INT (1 << 11)
+
+/* Bit Definitions: NFC_CONFIG2 */
+#define NFC_COMMAND (1 << 0)
+#define NFC_ADDRESS (1 << 1)
+#define NFC_INPUT (1 << 2)
+#define NFC_OUTPUT (1 << 3)
+#define NFC_ID (1 << 4)
+#define NFC_STATUS (1 << 5)
+#define NFC_CMD_FAIL (1 << 15)
+#define NFC_INT (1 << 15)
+
+/* Bit Definitions: NFC_WRPROT */
+#define NFC_WPC_LOCK_TIGHT (1 << 0)
+#define NFC_WPC_LOCK (1 << 1)
+#define NFC_WPC_UNLOCK (1 << 2)
+
+#endif /* MPC5121_NFC_H */
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index d8cd579..7135d89 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -71,6 +71,7 @@ void __init mpc512x_init_IRQ(void)
static struct of_device_id __initdata of_bus_ids[] = {
{ .compatible = "fsl,mpc5121-immr", },
{ .compatible = "fsl,mpc5121-localbus", },
+ { .compatible = "fsl,mpc5121-nfc", },
{},
};
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 890936d..fb0d1c4 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -413,6 +413,13 @@ config MTD_NAND_FSL_UPM
Enables support for NAND Flash chips wired onto Freescale PowerPC
processor localbus with User-Programmable Machine support.
+config MTD_NAND_MPC5121_NFC
+ tristate "MPC5121 built-in NAND Flash Controller support"
+ depends on PPC_MPC512x
+ help
+ This enables the driver for the NAND flash controller on the
+ MPC5121 SoC.
+
config MTD_NAND_MXC
tristate "MXC NAND support"
depends on ARCH_MX2 || ARCH_MX3
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index d33860a..563e812 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -39,5 +39,6 @@ obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o
obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o
obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o
obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
+obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o
nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c
new file mode 100644
index 0000000..a8da4db
--- /dev/null
+++ b/drivers/mtd/nand/mpc5121_nfc.c
@@ -0,0 +1,855 @@
+/*
+ * Copyright 2004-2008 Freescale Semiconductor, Inc.
+ * Copyright 2009 Semihalf.
+ *
+ * Based on original driver from Freescale Semiconductor
+ * written by John Rigby <jrigby@freescale.com> on basis
+ * of drivers/mtd/nand/mxc_nand.c. Reworked and extended
+ * Piotr Ziecik <kosmo@semihalf.com>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+#include <asm/mpc512x.h>
+#include <asm/mpc5121_nfc.h>
+
+#define DRV_NAME "mpc5121_nfc"
+#define DRV_VERSION "0.5"
+
+/* Timeouts */
+#define NFC_RESET_TIMEOUT 1000 /* 1 ms */
+#define NFC_TIMEOUT (HZ / 10) /* 1/10 s */
+
+struct mpc5121_nfc_prv {
+ struct mtd_info mtd;
+ struct nand_chip chip;
+ int irq;
+ void __iomem *regs;
+ struct clk *clk;
+ wait_queue_head_t irq_waitq;
+ uint column;
+ int spareonly;
+ void __iomem *csreg;
+};
+
+static void mpc5121_nfc_done(struct mtd_info *mtd);
+
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *mpc5121_nfc_pprobes[] = { "cmdlinepart", NULL };
+#endif
+
+/* Read NFC register */
+static inline u16 nfc_read(struct mtd_info *mtd, uint reg)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct mpc5121_nfc_prv *prv = chip->priv;
+
+ return in_be16(prv->regs + reg);
+}
+
+/* Write NFC register */
+static inline void nfc_write(struct mtd_info *mtd, uint reg, u16 val)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct mpc5121_nfc_prv *prv = chip->priv;
+
+ out_be16(prv->regs + reg, val);
+}
+
+/* Set bits in NFC register */
+static inline void nfc_set(struct mtd_info *mtd, uint reg, u16 bits)
+{
+ nfc_write(mtd, reg, nfc_read(mtd, reg) | bits);
+}
+
+/* Clear bits in NFC register */
+static inline void nfc_clear(struct mtd_info *mtd, uint reg, u16 bits)
+{
+ nfc_write(mtd, reg, nfc_read(mtd, reg) & ~bits);
+}
+
+/* Invoke address cycle */
+static inline void mpc5121_nfc_send_addr(struct mtd_info *mtd, u16 addr)
+{
+ nfc_write(mtd, NFC_FLASH_ADDR, addr);
+ nfc_write(mtd, NFC_CONFIG2, NFC_ADDRESS);
+ mpc5121_nfc_done(mtd);
+}
+
+/* Invoke command cycle */
+static inline void mpc5121_nfc_send_cmd(struct mtd_info *mtd, u16 cmd)
+{
+ nfc_write(mtd, NFC_FLASH_CMD, cmd);
+ nfc_write(mtd, NFC_CONFIG2, NFC_COMMAND);
+ mpc5121_nfc_done(mtd);
+}
+
+/* Send data from NFC buffers to NAND flash */
+static inline void mpc5121_nfc_send_prog_page(struct mtd_info *mtd)
+{
+ nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
+ nfc_write(mtd, NFC_CONFIG2, NFC_INPUT);
+ mpc5121_nfc_done(mtd);
+}
+
+/* Receive data from NAND flash */
+static inline void mpc5121_nfc_send_read_page(struct mtd_info *mtd)
+{
+ nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
+ nfc_write(mtd, NFC_CONFIG2, NFC_OUTPUT);
+ mpc5121_nfc_done(mtd);
+}
+
+/* Receive ID from NAND flash */
+static inline void mpc5121_nfc_send_read_id(struct mtd_info *mtd)
+{
+ nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
+ nfc_write(mtd, NFC_CONFIG2, NFC_ID);
+ mpc5121_nfc_done(mtd);
+}
+
+/* Receive status from NAND flash */
+static inline void mpc5121_nfc_send_read_status(struct mtd_info *mtd)
+{
+ nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
+ nfc_write(mtd, NFC_CONFIG2, NFC_STATUS);
+ mpc5121_nfc_done(mtd);
+}
+
+/* NFC interrupt handler */
+static irqreturn_t mpc5121_nfc_irq(int irq, void *data)
+{
+ struct mtd_info *mtd = data;
+ struct nand_chip *chip = mtd->priv;
+ struct mpc5121_nfc_prv *prv = chip->priv;
+
+ nfc_set(mtd, NFC_CONFIG1, NFC_INT_MASK);
+ wake_up(&prv->irq_waitq);
+
+ return IRQ_HANDLED;
+}
+
+/* Wait for operation complete */
+static void mpc5121_nfc_done(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct mpc5121_nfc_prv *prv = chip->priv;
+ int rv;
+
+ if ((nfc_read(mtd, NFC_CONFIG2) & NFC_INT) == 0) {
+ nfc_clear(mtd, NFC_CONFIG1, NFC_INT_MASK);
+ rv = wait_event_timeout(prv->irq_waitq,
+ (nfc_read(mtd, NFC_CONFIG2) & NFC_INT), NFC_TIMEOUT);
+
+ if (!rv)
+ printk(KERN_WARNING DRV_NAME
+ ": Timeout while waiting for interrupt.\n");
+ }
+
+ nfc_clear(mtd, NFC_CONFIG2, NFC_INT);
+}
+
+/* Do address cycle(s) */
+static void mpc5121_nfc_addr_cycle(struct mtd_info *mtd, int column, int page)
+{
+ struct nand_chip *chip = mtd->priv;
+ u32 pagemask = chip->pagemask;
+
+ if (column != -1) {
+ mpc5121_nfc_send_addr(mtd, column);
+ if (mtd->writesize > 512)
+ mpc5121_nfc_send_addr(mtd, column >> 8);
+ }
+
+ if (page != -1) {
+ do {
+ mpc5121_nfc_send_addr(mtd, page & 0xFF);
+ page >>= 8;
+ pagemask >>= 8;
+ } while (pagemask);
+ }
+}
+
+/* Control chip select signals */
+static void mpc5121_nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+ if (chip < 0) {
+ nfc_clear(mtd, NFC_CONFIG1, NFC_CE);
+ return;
+ }
+
+ nfc_clear(mtd, NFC_BUF_ADDR, NFC_ACTIVE_CS_MASK);
+ nfc_set(mtd, NFC_BUF_ADDR, (chip << NFC_ACTIVE_CS_SHIFT) &
+ NFC_ACTIVE_CS_MASK);
+ nfc_set(mtd, NFC_CONFIG1, NFC_CE);
+}
+
+/* Init external chip select logic on ADS5121 board */
+static int ads5121_chipselect_init(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct mpc5121_nfc_prv *prv = chip->priv;
+ struct device_node *dn;
+
+ dn = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld");
+ if (dn) {
+ prv->csreg = of_iomap(dn, 0);
+ of_node_put(dn);
+ if (!prv->csreg)
+ return -ENOMEM;
+
+ /* CPLD Register 9 controls NAND /CE Lines */
+ prv->csreg += 9;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+/* Control chips select signal on ADS5121 board */
+static void ads5121_select_chip(struct mtd_info *mtd, int chip)
+{
+ struct nand_chip *nand = mtd->priv;
+ struct mpc5121_nfc_prv *prv = nand->priv;
+ u8 v;
+
+ v = in_8(prv->csreg);
+ v |= 0x0F;
+
+ if (chip >= 0) {
+ mpc5121_nfc_select_chip(mtd, 0);
+ v &= ~(1 << chip);
+ } else
+ mpc5121_nfc_select_chip(mtd, -1);
+
+ out_8(prv->csreg, v);
+}
+
+/* Read NAND Ready/Busy signal */
+static int mpc5121_nfc_dev_ready(struct mtd_info *mtd)
+{
+ /*
+ * NFC handles ready/busy signal internally. Therefore, this function
+ * always returns status as ready.
+ */
+ return 1;
+}
+
+/* Write command to NAND flash */
+static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
+ int column, int page)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct mpc5121_nfc_prv *prv = chip->priv;
+
+ prv->column = (column >= 0) ? column : 0;
+ prv->spareonly = 0;
+
+ switch (command) {
+ case NAND_CMD_PAGEPROG:
+ mpc5121_nfc_send_prog_page(mtd);
+ break;
+ /*
+ * NFC does not support sub-page reads and writes,
+ * so emulate them using full page transfers.
+ */
+ case NAND_CMD_READ0:
+ column = 0;
+ break;
+
+ case NAND_CMD_READ1:
+ prv->column += 256;
+ command = NAND_CMD_READ0;
+ column = 0;
+ break;
+
+ case NAND_CMD_READOOB:
+ prv->spareonly = 1;
+ command = NAND_CMD_READ0;
+ column = 0;
+ break;
+
+ case NAND_CMD_SEQIN:
+ mpc5121_nfc_command(mtd, NAND_CMD_READ0, column, page);
+ column = 0;
+ break;
+
+ case NAND_CMD_ERASE1:
+ case NAND_CMD_ERASE2:
+ case NAND_CMD_READID:
+ case NAND_CMD_STATUS:
+ break;
+
+ default:
+ return;
+ }
+
+ mpc5121_nfc_send_cmd(mtd, command);
+ mpc5121_nfc_addr_cycle(mtd, column, page);
+
+ switch (command) {
+ case NAND_CMD_READ0:
+ if (mtd->writesize > 512)
+ mpc5121_nfc_send_cmd(mtd, NAND_CMD_READSTART);
+ mpc5121_nfc_send_read_page(mtd);
+ break;
+
+ case NAND_CMD_READID:
+ mpc5121_nfc_send_read_id(mtd);
+ break;
+
+ case NAND_CMD_STATUS:
+ mpc5121_nfc_send_read_status(mtd);
+ if (chip->options & NAND_BUSWIDTH_16)
+ prv->column = 1;
+ else
+ prv->column = 0;
+ break;
+ }
+}
+
+/* Copy data from/to NFC spare buffers. */
+static void mpc5121_nfc_copy_spare(struct mtd_info *mtd, uint offset,
+ u8 *buffer, uint size, int wr)
+{
+ struct nand_chip *nand = mtd->priv;
+ struct mpc5121_nfc_prv *prv = nand->priv;
+ uint o, s, sbsize, blksize;
+
+ /*
+ * NAND spare area is available through NFC spare buffers.
+ * The NFC divides spare area into (page_size / 512) chunks.
+ * Each chunk is placed into separate spare memory area, using
+ * first (spare_size / num_of_chunks) bytes of the buffer.
+ *
+ * For NAND device in which the spare area is not divided fully
+ * by the number of chunks, number of used bytes in each spare
+ * buffer is rounded down to the nearest even number of bytes,
+ * and all remaining bytes are added to the last used spare area.
+ *
+ * For more information read section 26.6.10 of MPC5121e
+ * Microcontroller Reference Manual, Rev. 3.
+ */
+
+ /* Calculate number of valid bytes in each spare buffer */
+ sbsize = (mtd->oobsize / (mtd->writesize / 512)) & ~1;
+
+ while (size) {
+ /* Calculate spare buffer number */
+ s = offset / sbsize;
+ if (s > NFC_SPARE_BUFFERS - 1)
+ s = NFC_SPARE_BUFFERS - 1;
+
+ /*
+ * Calculate offset to requested data block in selected spare
+ * buffer and its size.
+ */
+ o = offset - (s * sbsize);
+ blksize = min(sbsize - o, size);
+
+ if (wr)
+ memcpy_toio(prv->regs + NFC_SPARE_AREA(s) + o,
+ buffer, blksize);
+ else
+ memcpy_fromio(buffer,
+ prv->regs + NFC_SPARE_AREA(s) + o, blksize);
+
+ buffer += blksize;
+ offset += blksize;
+ size -= blksize;
+ };
+}
+
+/* Copy data from/to NFC main and spare buffers */
+static void mpc5121_nfc_buf_copy(struct mtd_info *mtd, u_char *buf, int len,
+ int wr)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct mpc5121_nfc_prv *prv = chip->priv;
+ uint c = prv->column;
+ uint l;
+
+ /* Handle spare area access */
+ if (prv->spareonly || c >= mtd->writesize) {
+ /* Calculate offset from beginning of spare area */
+ if (c >= mtd->writesize)
+ c -= mtd->writesize;
+
+ prv->column += len;
+ mpc5121_nfc_copy_spare(mtd, c, buf, len, wr);
+ return;
+ }
+
+ /*
+ * Handle main area access - limit copy length to prevent
+ * crossing main/spare boundary.
+ */
+ l = min((uint)len, mtd->writesize - c);
+ prv->column += l;
+
+ if (wr)
+ memcpy_toio(prv->regs + NFC_MAIN_AREA(0) + c, buf, l);
+ else
+ memcpy_fromio(buf, prv->regs + NFC_MAIN_AREA(0) + c, l);
+
+ /* Handle crossing main/spare boundary */
+ if (l != len) {
+ buf += l;
+ len -= l;
+ mpc5121_nfc_buf_copy(mtd, buf, len, wr);
+ }
+}
+
+/* Read data from NFC buffers */
+static void mpc5121_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+ mpc5121_nfc_buf_copy(mtd, buf, len, 0);
+}
+
+/* Write data to NFC buffers */
+static void mpc5121_nfc_write_buf(struct mtd_info *mtd,
+ const u_char *buf, int len)
+{
+ mpc5121_nfc_buf_copy(mtd, (u_char *)buf, len, 1);
+}
+
+/* Compare buffer with NAND flash */
+static int mpc5121_nfc_verify_buf(struct mtd_info *mtd,
+ const u_char *buf, int len)
+{
+ u_char tmp[256];
+ uint bsize;
+
+ while (len) {
+ bsize = min(len, 256);
+ mpc5121_nfc_read_buf(mtd, tmp, bsize);
+
+ if (memcmp(buf, tmp, bsize))
+ return 1;
+
+ buf += bsize;
+ len -= bsize;
+ }
+
+ return 0;
+}
+
+/* Read byte from NFC buffers */
+static u8 mpc5121_nfc_read_byte(struct mtd_info *mtd)
+{
+ u8 tmp;
+
+ mpc5121_nfc_read_buf(mtd, &tmp, sizeof(tmp));
+
+ return tmp;
+}
+
+/* Read word from NFC buffers */
+static u16 mpc5121_nfc_read_word(struct mtd_info *mtd)
+{
+ u16 tmp;
+
+ mpc5121_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
+
+ return tmp;
+}
+
+/*
+ * Read NFC configuration from Reset Config Word
+ *
+ * NFC is configured during reset in basis of information stored
+ * in Reset Config Word. There is no other way to set NAND block
+ * size, spare size and bus width.
+ */
+static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct mpc512x_reset_module *rm;
+ struct device_node *rmnode;
+ uint rcw_pagesize = 0;
+ uint rcw_sparesize = 0;
+ uint rcw_width;
+ uint rcwh;
+ uint romloc, ps;
+
+ rmnode = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset");
+ if (!rmnode) {
+ printk(KERN_ERR DRV_NAME ": Missing 'fsl,mpc5121-reset' "
+ "node in device tree!\n");
+ return -ENODEV;
+ }
+
+ rm = of_iomap(rmnode, 0);
+ if (!rm) {
+ printk(KERN_ERR DRV_NAME
+ ": Error mapping reset module node!\n");
+ return -EBUSY;
+ }
+
+ rcwh = in_be32(&rm->rcwhr);
+
+ /* Bit 6: NFC bus width */
+ rcw_width = ((rcwh >> 6) & 0x1) ? 2 : 1;
+
+ /* Bit 7: NFC Page/Spare size */
+ ps = (rcwh >> 7) & 0x1;
+
+ /* Bits [22:21]: ROM Location */
+ romloc = (rcwh >> 21) & 0x3;
+
+ /* Decode RCW bits */
+ switch ((ps << 2) | romloc) {
+ case 0x00:
+ case 0x01:
+ rcw_pagesize = 512;
+ rcw_sparesize = 16;
+ break;
+ case 0x02:
+ case 0x03:
+ rcw_pagesize = 4096;
+ rcw_sparesize = 128;
+ break;
+ case 0x04:
+ case 0x05:
+ rcw_pagesize = 2048;
+ rcw_sparesize = 64;
+ break;
+ case 0x06:
+ case 0x07:
+ rcw_pagesize = 4096;
+ rcw_sparesize = 218;
+ break;
+ }
+
+ mtd->writesize = rcw_pagesize;
+ mtd->oobsize = rcw_sparesize;
+ if (rcw_width == 2)
+ chip->options |= NAND_BUSWIDTH_16;
+
+ printk(KERN_NOTICE DRV_NAME ": Configured for "
+ "%u-bit NAND, page size %u "
+ "with %u spare.\n",
+ rcw_width * 8, rcw_pagesize,
+ rcw_sparesize);
+ iounmap(rm);
+ of_node_put(rmnode);
+ return 0;
+}
+
+/* Free driver resources */
+static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct mpc5121_nfc_prv *prv = chip->priv;
+
+ if (prv->clk) {
+ clk_disable(prv->clk);
+ clk_put(prv->clk);
+ }
+
+ if (prv->csreg)
+ iounmap(prv->csreg);
+}
+
+static int __init mpc5121_nfc_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ struct device_node *rootnode, *dn = op->node;
+ struct device *dev = &op->dev;
+ struct mpc5121_nfc_prv *prv;
+ struct resource res;
+ struct mtd_info *mtd;
+#ifdef CONFIG_MTD_PARTITIONS
+ struct mtd_partition *parts;
+#endif
+ struct nand_chip *chip;
+ unsigned long regs_paddr, regs_size;
+ const uint *chips_no;
+ int resettime = 0;
+ int retval = 0;
+ int rev, len;
+
+ /*
+ * Check SoC revision. This driver supports only NFC
+ * in MPC5121 revision 2.
+ */
+ rev = (mfspr(SPRN_SVR) >> 4) & 0xF;
+ if (rev != 2) {
+ printk(KERN_ERR DRV_NAME
+ ": SoC revision %u is not supported!\n", rev);
+ return -ENXIO;
+ }
+
+ prv = devm_kzalloc(dev, sizeof(*prv), GFP_KERNEL);
+ if (!prv) {
+ printk(KERN_ERR DRV_NAME ": Memory exhausted!\n");
+ return -ENOMEM;
+ }
+
+ mtd = &prv->mtd;
+ chip = &prv->chip;
+
+ mtd->priv = chip;
+ chip->priv = prv;
+
+ /* Read NFC configuration from Reset Config Word */
+ retval = mpc5121_nfc_read_hw_config(mtd);
+ if (retval) {
+ printk(KERN_ERR DRV_NAME ": Unable to read NFC config!\n");
+ return retval;
+ }
+
+ prv->irq = irq_of_parse_and_map(dn, 0);
+ if (prv->irq == NO_IRQ) {
+ printk(KERN_ERR DRV_NAME ": Error mapping IRQ!\n");
+ return -EINVAL;
+ }
+
+ retval = of_address_to_resource(dn, 0, &res);
+ if (retval) {
+ printk(KERN_ERR DRV_NAME ": Error parsing memory region!\n");
+ return retval;
+ }
+
+ chips_no = of_get_property(dn, "chips", &len);
+ if (!chips_no || len != sizeof(*chips_no)) {
+ printk(KERN_ERR DRV_NAME ": Invalid/missing 'chips' "
+ "property!\n");
+ return -EINVAL;
+ }
+
+ regs_paddr = res.start;
+ regs_size = res.end - res.start + 1;
+
+ if (!devm_request_mem_region(dev, regs_paddr, regs_size, DRV_NAME)) {
+ printk(KERN_ERR DRV_NAME ": Error requesting memory region!\n");
+ return -EBUSY;
+ }
+
+ prv->regs = devm_ioremap(dev, regs_paddr, regs_size);
+ if (!prv->regs) {
+ printk(KERN_ERR DRV_NAME ": Error mapping memory region!\n");
+ return -ENOMEM;
+ }
+
+ mtd->name = "MPC5121 NAND";
+ chip->dev_ready = mpc5121_nfc_dev_ready;
+ chip->cmdfunc = mpc5121_nfc_command;
+ chip->read_byte = mpc5121_nfc_read_byte;
+ chip->read_word = mpc5121_nfc_read_word;
+ chip->read_buf = mpc5121_nfc_read_buf;
+ chip->write_buf = mpc5121_nfc_write_buf;
+ chip->verify_buf = mpc5121_nfc_verify_buf;
+ chip->select_chip = mpc5121_nfc_select_chip;
+ chip->options = NAND_NO_AUTOINCR | NAND_USE_FLASH_BBT;
+ chip->ecc.mode = NAND_ECC_SOFT;
+
+ /* Support external chip-select logic on ADS5121 board */
+ rootnode = of_find_node_by_path("/");
+ if (of_device_is_compatible(rootnode, "fsl,mpc5121ads")) {
+ retval = ads5121_chipselect_init(mtd);
+ if (retval) {
+ printk(KERN_ERR DRV_NAME ": Chipselect init error!\n");
+ of_node_put(rootnode);
+ return retval;
+ }
+
+ chip->select_chip = ads5121_select_chip;
+ }
+ of_node_put(rootnode);
+
+ /* Enable NFC clock */
+ prv->clk = clk_get(dev, "nfc_clk");
+ if (!prv->clk) {
+ printk(KERN_ERR DRV_NAME ": Unable to acquire NFC clock!\n");
+ retval = -ENODEV;
+ goto error;
+ }
+
+ clk_enable(prv->clk);
+
+ /* Reset NAND Flash controller */
+ nfc_set(mtd, NFC_CONFIG1, NFC_RESET);
+ while (nfc_read(mtd, NFC_CONFIG1) & NFC_RESET) {
+ if (resettime++ >= NFC_RESET_TIMEOUT) {
+ printk(KERN_ERR DRV_NAME
+ ": Timeout while resetting NFC!\n");
+ retval = -EINVAL;
+ goto error;
+ }
+
+ udelay(1);
+ }
+
+ /* Enable write to NFC memory */
+ nfc_write(mtd, NFC_CONFIG, NFC_BLS_UNLOCKED);
+
+ /* Enable write to all NAND pages */
+ nfc_write(mtd, NFC_UNLOCKSTART_BLK0, 0x0000);
+ nfc_write(mtd, NFC_UNLOCKEND_BLK0, 0xFFFF);
+ nfc_write(mtd, NFC_WRPROT, NFC_WPC_UNLOCK);
+
+ /*
+ * Setup NFC:
+ * - Big Endian transfers,
+ * - Interrupt after full page read/write.
+ */
+ nfc_write(mtd, NFC_CONFIG1, NFC_BIG_ENDIAN | NFC_INT_MASK |
+ NFC_FULL_PAGE_INT);
+
+ /* Set spare area size */
+ nfc_write(mtd, NFC_SPAS, mtd->oobsize >> 1);
+
+ init_waitqueue_head(&prv->irq_waitq);
+ retval = devm_request_irq(dev, prv->irq, &mpc5121_nfc_irq, 0, DRV_NAME,
+ mtd);
+ if (retval) {
+ printk(KERN_ERR DRV_NAME ": Error requesting IRQ!\n");
+ goto error;
+ }
+
+ /* Detect NAND chips */
+ if (nand_scan(mtd, *chips_no)) {
+ printk(KERN_ERR DRV_NAME ": NAND Flash not found !\n");
+ devm_free_irq(dev, prv->irq, mtd);
+ retval = -ENXIO;
+ goto error;
+ }
+
+ /* Set erase block size */
+ switch (mtd->erasesize / mtd->writesize) {
+ case 32:
+ nfc_set(mtd, NFC_CONFIG1, NFC_PPB_32);
+ break;
+
+ case 64:
+ nfc_set(mtd, NFC_CONFIG1, NFC_PPB_64);
+ break;
+
+ case 128:
+ nfc_set(mtd, NFC_CONFIG1, NFC_PPB_128);
+ break;
+
+ case 256:
+ nfc_set(mtd, NFC_CONFIG1, NFC_PPB_256);
+ break;
+
+ default:
+ printk(KERN_ERR DRV_NAME ": Unsupported NAND flash!\n");
+ devm_free_irq(dev, prv->irq, mtd);
+ retval = -ENXIO;
+ goto error;
+ }
+
+ dev_set_drvdata(dev, mtd);
+
+ /* Register device in MTD */
+#ifdef CONFIG_MTD_PARTITIONS
+ retval = parse_mtd_partitions(mtd, mpc5121_nfc_pprobes, &parts, 0);
+#ifdef CONFIG_MTD_OF_PARTS
+ if (retval == 0)
+ retval = of_mtd_parse_partitions(dev, dn, &parts);
+#endif
+ if (retval < 0) {
+ printk(KERN_ERR DRV_NAME ": Error parsing MTD partitions!\n");
+ devm_free_irq(dev, prv->irq, mtd);
+ retval = -EINVAL;
+ goto error;
+ }
+
+ if (retval > 0)
+ retval = add_mtd_partitions(mtd, parts, retval);
+ else
+#endif
+ retval = add_mtd_device(mtd);
+
+ if (retval) {
+ printk(KERN_ERR DRV_NAME ": Error adding MTD device!\n");
+ devm_free_irq(dev, prv->irq, mtd);
+ goto error;
+ }
+
+ return 0;
+error:
+ mpc5121_nfc_free(dev, mtd);
+ return retval;
+}
+
+static int __exit mpc5121_nfc_remove(struct of_device *op)
+{
+ struct device *dev = &op->dev;
+ struct mtd_info *mtd = dev_get_drvdata(dev);
+ struct nand_chip *chip = mtd->priv;
+ struct mpc5121_nfc_prv *prv = chip->priv;
+
+ nand_release(mtd);
+ devm_free_irq(dev, prv->irq, mtd);
+ mpc5121_nfc_free(dev, mtd);
+
+ return 0;
+}
+
+static struct of_device_id mpc5121_nfc_match[] = {
+ { .compatible = "fsl,mpc5121-nfc", },
+ {},
+};
+
+static struct of_platform_driver mpc5121_nfc_driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ .match_table = mpc5121_nfc_match,
+ .probe = mpc5121_nfc_probe,
+ .remove = __exit_p(mpc5121_nfc_remove),
+ .suspend = NULL,
+ .resume = NULL,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init mpc5121_nfc_init(void)
+{
+ if (of_register_platform_driver(&mpc5121_nfc_driver) != 0) {
+ printk(KERN_ERR DRV_NAME ": Driver register failed!\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void __exit mpc5121_nfc_cleanup(void)
+{
+ of_unregister_platform_driver(&mpc5121_nfc_driver);
+}
+
+module_init(mpc5121_nfc_init);
+module_exit(mpc5121_nfc_cleanup);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MPC5121 NAND MTD driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
--
1.6.0.6
^ permalink raw reply related
* [PATCH 12/12] mpc5121: Added default config for MPC5121.
From: Wolfgang Denk @ 2009-05-06 20:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Piotr Ziecik, Wolfgang Denk
In-Reply-To: <1241640919-4650-1-git-send-email-wd@denx.de>
From: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: John Rigby <jcrigby@gmail.com>
---
arch/powerpc/configs/mpc5121_defconfig | 1158 ++++++++++++++++++++++++++++++++
1 files changed, 1158 insertions(+), 0 deletions(-)
create mode 100644 arch/powerpc/configs/mpc5121_defconfig
diff --git a/arch/powerpc/configs/mpc5121_defconfig b/arch/powerpc/configs/mpc5121_defconfig
new file mode 100644
index 0000000..87b5f15
--- /dev/null
+++ b/arch/powerpc/configs/mpc5121_defconfig
@@ -0,0 +1,1158 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.29-rc5
+# Fri Feb 27 14:08:31 2009
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+CONFIG_6xx=y
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_PPC_FPU=y
+# CONFIG_ALTIVEC is not set
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_PPC_MM_SLICES is not set
+# CONFIG_SMP is not set
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_OF=y
+# CONFIG_PPC_UDBG_16550 is not set
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFAULT_UIMAGE=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=16
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_CLK=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+# CONFIG_FREEZER is not set
+CONFIG_PPC_MSI_BITMAP=y
+
+#
+# Platform support
+#
+CONFIG_PPC_MULTIPLATFORM=y
+CONFIG_CLASSIC32=y
+# CONFIG_PPC_CHRP is not set
+CONFIG_PPC_MPC512x=y
+CONFIG_PPC_MPC5121=y
+CONFIG_MPC5121_ADS=y
+# CONFIG_MPC5121_GENERIC is not set
+# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_PMAC is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PQ2ADS is not set
+# CONFIG_PPC_83xx is not set
+# CONFIG_PPC_86xx is not set
+# CONFIG_EMBEDDED6xx is not set
+CONFIG_IPIC=y
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_TAU is not set
+# CONFIG_QUICC_ENGINE is not set
+# CONFIG_FSL_ULI1575 is not set
+# CONFIG_SIMPLE_GPIO is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_IOMMU_HELPER is not set
+CONFIG_PPC_NEED_DMA_SYNC_OPS=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_MIGRATION is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_UNEVICTABLE_LRU is not set
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_64K_PAGES is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_EXTRA_TARGETS=""
+# CONFIG_PM is not set
+# CONFIG_SECCOMP is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_FSL_PCI=y
+CONFIG_PPC_PCI_CHOICE=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIEAER=y
+# CONFIG_PCIEASPM is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+CONFIG_PCI_MSI=y
+# CONFIG_PCI_LEGACY is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HAS_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_PAGE_OFFSET=0xc0000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_TASK_SIZE=0xc0000000
+CONFIG_CONSISTENT_START=0xff100000
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_COMPAT_NET_DEV_OPS=y
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_FW_LOADER=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_OF_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_NAND_FSL_ELBC is not set
+CONFIG_MTD_NAND_MPC5121_NFC=y
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+# CONFIG_MTD_QINFO_PROBE is not set
+
+#
+# UBI - Unsorted block images
+#
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+# CONFIG_MTD_UBI_GLUEBI is not set
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+CONFIG_OF_DEVICE=y
+CONFIG_OF_I2C=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=1
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_XIP=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+CONFIG_EEPROM_AT24=y
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# Enable only one of the two stacks, unless you know what you are doing
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=y
+CONFIG_DAVICOM_PHY=y
+CONFIG_QSEMI_PHY=y
+CONFIG_LXT_PHY=y
+CONFIG_CICADA_PHY=y
+CONFIG_VITESSE_PHY=y
+CONFIG_SMSC_PHY=y
+CONFIG_BROADCOM_PHY=y
+CONFIG_ICPLUS_PHY=y
+CONFIG_REALTEK_PHY=y
+CONFIG_NATIONAL_PHY=y
+CONFIG_STE10XP=y
+CONFIG_LSI_ET1011C_PHY=y
+CONFIG_FIXED_PHY=y
+CONFIG_MDIO_BITBANG=y
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+# CONFIG_ATL2 is not set
+CONFIG_FS_ENET=y
+CONFIG_FS_ENET_MPC5121_FEC=y
+CONFIG_FS_ENET_FEC_TX_ALIGN_WORKAROUND=y
+CONFIG_FS_ENET_HAS_FEC=y
+CONFIG_FS_ENET_MDIO_FEC=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_MPC52xx=y
+CONFIG_SERIAL_MPC52xx_CONSOLE=y
+CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD=115200
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HVC_UDBG is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Graphics adapter I2C/DDC channel drivers
+#
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_SPI is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_REGULATOR is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc1"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+CONFIG_RTC_DRV_M41T80=y
+# CONFIG_RTC_DRV_M41T80_WDT is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_PPC is not set
+CONFIG_RTC_DRV_MPC5121=y
+CONFIG_DMADEVICES=y
+
+#
+# DMA Devices
+#
+# CONFIG_FSL_DMA is not set
+CONFIG_MPC512X_DMA=y
+CONFIG_DMA_ENGINE=y
+
+#
+# DMA Clients
+#
+# CONFIG_NET_DMA is not set
+CONFIG_DMATEST=m
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT2_FS_XIP=y
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_FS_XIP=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_REGISTER_V4 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+
+#
+# Tracers
+#
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_PRINT_STACK_DEPTH=64
+# CONFIG_IRQSTACKS is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+CONFIG_PPC_CLOCK=y
+# CONFIG_VIRTUALIZATION is not set
--
1.6.0.6
^ permalink raw reply related
* [PATCH 04/12] mpc5121: Added reset module registers representation.
From: Wolfgang Denk @ 2009-05-06 20:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Piotr Ziecik, Wolfgang Denk
In-Reply-To: <1241640919-4650-1-git-send-email-wd@denx.de>
From: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: John Rigby <jcrigby@gmail.com>
---
arch/powerpc/include/asm/mpc512x.h | 13 +++++++++++++
1 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/include/asm/mpc512x.h b/arch/powerpc/include/asm/mpc512x.h
index c48a165..ea50d8d 100644
--- a/arch/powerpc/include/asm/mpc512x.h
+++ b/arch/powerpc/include/asm/mpc512x.h
@@ -16,6 +16,19 @@
#ifndef __ASM_POWERPC_MPC512x_H__
#define __ASM_POWERPC_MPC512x_H__
+/* MPC512x Reset module registers */
+struct mpc512x_reset_module {
+ u32 rcwlr; /* Reset Configuration Word Low Register */
+ u32 rcwhr; /* Reset Configuration Word High Register */
+ u32 reserved1;
+ u32 reserved2;
+ u32 rsr; /* Reset Status Register */
+ u32 rmr; /* Reset Mode Register */
+ u32 rpr; /* Reset Protection Register */
+ u32 rcr; /* Reset Control Register */
+ u32 rcer; /* Reset Control Enable Register */
+} __attribute__ ((__packed__));
+
extern unsigned long mpc512x_find_ips_freq(struct device_node *node);
#endif /* __ASM_POWERPC_MPC512x_H__ */
--
1.6.0.6
^ permalink raw reply related
* [PATCH 08/12] mpc5121: Added I2C support.
From: Wolfgang Denk @ 2009-05-06 20:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: linux-i2c, Piotr Ziecik, Wolfgang Denk
In-Reply-To: <1241640919-4650-1-git-send-email-wd@denx.de>
From: Piotr Ziecik <kosmo@semihalf.com>
- Enabled I2C interrupts on MPC5121.
- Updated Kconfig for i2c-mpc driver.
Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Cc: <linux-i2c@vger.kernel.org>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: John Rigby <jcrigby@gmail.com>
---
arch/powerpc/platforms/512x/mpc5121_ads.c | 2 ++
arch/powerpc/platforms/512x/mpc512x.h | 1 +
arch/powerpc/platforms/512x/mpc512x_shared.c | 24 ++++++++++++++++++++++++
drivers/i2c/busses/Kconfig | 9 +++++----
4 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c
index 441abc4..a8976b4 100644
--- a/arch/powerpc/platforms/512x/mpc5121_ads.c
+++ b/arch/powerpc/platforms/512x/mpc5121_ads.c
@@ -42,6 +42,8 @@ static void __init mpc5121_ads_setup_arch(void)
for_each_compatible_node(np, "pci", "fsl,mpc5121-pci")
mpc83xx_add_bridge(np);
#endif
+
+ mpc512x_init_i2c();
}
static void __init mpc5121_ads_init_IRQ(void)
diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h
index 9c03693..f4db8a7 100644
--- a/arch/powerpc/platforms/512x/mpc512x.h
+++ b/arch/powerpc/platforms/512x/mpc512x.h
@@ -13,5 +13,6 @@
#define __MPC512X_H__
extern unsigned long mpc512x_find_ips_freq(struct device_node *node);
extern void __init mpc512x_init_IRQ(void);
+extern void __init mpc512x_init_i2c(void);
void __init mpc512x_declare_of_platform_devices(void);
#endif /* __MPC512X_H__ */
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index 7135d89..b776e45 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -65,6 +65,30 @@ void __init mpc512x_init_IRQ(void)
ipic_set_default_priority();
}
+void __init mpc512x_init_i2c(void)
+{
+ struct device_node *np;
+ void __iomem *i2cctl;
+
+ /* Enable I2C interrupts */
+ np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-i2c-ctrl");
+ if (np) {
+ i2cctl = of_iomap(np, 0);
+ if (i2cctl) {
+ /*
+ * Set interrupt enable bits:
+ * - I2C-0: bit 24,
+ * - I2C-1: bit 26,
+ * - I2C-2: bit 28.
+ */
+ out_be32(i2cctl, 0x15000000);
+ iounmap(i2cctl);
+ }
+
+ of_node_put(np);
+ }
+}
+
/*
* Nodes to do bus probe on, soc and localbus
*/
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index a48c8ae..57ed637 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -391,13 +391,14 @@ config I2C_IXP2000
instead.
config I2C_MPC
- tristate "MPC107/824x/85xx/52xx/86xx"
+ tristate "MPC107/824x/85xx/512x/52xx/86xx"
depends on PPC32
help
If you say yes to this option, support will be included for the
- built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and
- MPC85xx/MPC8641 family processors. The driver may also work on 52xx
- family processors, though interrupts are known not to work.
+ built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245,
+ MPC85xx/MPC8641 and MPC512x family processors. The driver may
+ also work on 52xx family processors, though interrupts are known
+ not to work.
This driver can also be built as a module. If so, the module
will be called i2c-mpc.
--
1.6.0.6
^ permalink raw reply related
* [PATCH 05/12] mpc5121ads: Added Reset Module node to DTS.
From: Wolfgang Denk @ 2009-05-06 20:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Piotr Ziecik, Wolfgang Denk
In-Reply-To: <1241640919-4650-1-git-send-email-wd@denx.de>
From: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: John Rigby <jcrigby@gmail.com>
---
arch/powerpc/boot/dts/mpc5121ads.dts | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/boot/dts/mpc5121ads.dts b/arch/powerpc/boot/dts/mpc5121ads.dts
index c2b8dbf..1b83a9d 100644
--- a/arch/powerpc/boot/dts/mpc5121ads.dts
+++ b/arch/powerpc/boot/dts/mpc5121ads.dts
@@ -166,6 +166,11 @@
interrupt-parent = < &ipic >;
};
+ reset@e00 { // Reset module
+ compatible = "fsl,mpc5121-reset";
+ reg = <0xe00 0x100>;
+ };
+
clock@f00 { // Clock control
compatible = "fsl,mpc5121-clock";
reg = <0xf00 0x100>;
--
1.6.0.6
^ permalink raw reply related
* [PATCH 10/12] mpc5121: Add MPC5121 Real time clock driver.
From: Wolfgang Denk @ 2009-05-06 20:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Piotr Ziecik, rtc-linux, John Rigby, Wolfgang Denk
In-Reply-To: <1241640919-4650-1-git-send-email-wd@denx.de>
From: John Rigby <jrigby@freescale.com>
Based on Domen Puncer's rtc driver for 5200 posted to
the ppclinux mailing list:
http://patchwork.ozlabs.org/linuxppc-embedded/patch?id=11675
but never commited anywhere.
Changes to Domen's original:
Changed filenames/routine names from mpc5200* to mpc5121*
Changed match to only care about compatible and use "fsl,"
convention for compatible.
Make alarms more sane by dealing with lack of second alarm resolution.
Deal with the fact that most of the 5121 rtc registers are not persistent
across a reset even with a battery attached:
Use actual_time register for time keeping
and target_time register as an offset to linux time
The target_time register would normally be used for hibernation
but hibernation does not work on current silicon
Signed-off-by: John Rigby <jrigby@freescale.com>
Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Cc: <rtc-linux@googlegroups.com>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: John Rigby <jcrigby@gmail.com>
---
drivers/rtc/Kconfig | 10 +
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-mpc5121.c | 408 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 419 insertions(+), 0 deletions(-)
create mode 100644 drivers/rtc/rtc-mpc5121.c
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 4e9851f..900d5b8 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -750,4 +750,14 @@ config RTC_DRV_PS3
This driver can also be built as a module. If so, the module
will be called rtc-ps3.
+config RTC_DRV_MPC5121
+ tristate "Freescale MPC5121 built-in RTC"
+ depends on RTC_CLASS
+ help
+ If you say yes here you will get support for the
+ built-in RTC MPC5121.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-mpc5121.
+
endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 6c0639a..8c6d6a7 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o
+obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o
obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c
new file mode 100644
index 0000000..63460cb
--- /dev/null
+++ b/drivers/rtc/rtc-mpc5121.c
@@ -0,0 +1,408 @@
+/*
+ * Real-time clock driver for MPC5121
+ *
+ * Copyright 2007, Domen Puncer <domen.puncer@telargo.com>
+ * Copyright 2008, Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * History:
+ *
+ * Based on mpc5200_rtc.c written by Domen Puncer <domen.puncer@telargo.com>
+ * posted to linuxppc-embedded mailing list:
+ * http://patchwork.ozlabs.org/linuxppc-embedded/patch?id=11675
+ * but never committed to any public tree.
+ *
+ * Author: John Rigby <jrigby@freescale.com>
+ * Converted to 5121 rtc driver.
+ *
+ * Make alarms more sane by dealing with lack of second alarm resolution.
+ *
+ * Use actual_time time register for time keeping since it is persistent
+ * and the normal rtc registers are not. Use target_time register as an
+ * offset to linux time.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+
+struct mpc5121_rtc_regs {
+ u8 set_time; /* RTC + 0x00 */
+ u8 hour_set; /* RTC + 0x01 */
+ u8 minute_set; /* RTC + 0x02 */
+ u8 second_set; /* RTC + 0x03 */
+
+ u8 set_date; /* RTC + 0x04 */
+ u8 month_set; /* RTC + 0x05 */
+ u8 weekday_set; /* RTC + 0x06 */
+ u8 date_set; /* RTC + 0x07 */
+
+ u8 write_sw; /* RTC + 0x08 */
+ u8 sw_set; /* RTC + 0x09 */
+ u16 year_set; /* RTC + 0x0a */
+
+ u8 alm_enable; /* RTC + 0x0c */
+ u8 alm_hour_set; /* RTC + 0x0d */
+ u8 alm_min_set; /* RTC + 0x0e */
+ u8 int_enable; /* RTC + 0x0f */
+
+ u8 reserved1;
+ u8 hour; /* RTC + 0x11 */
+ u8 minute; /* RTC + 0x12 */
+ u8 second; /* RTC + 0x13 */
+
+ u8 month; /* RTC + 0x14 */
+ u8 wday_mday; /* RTC + 0x15 */
+ u16 year; /* RTC + 0x16 */
+
+ u8 int_alm; /* RTC + 0x18 */
+ u8 int_sw; /* RTC + 0x19 */
+ u8 alm_status; /* RTC + 0x1a */
+ u8 sw_minute; /* RTC + 0x1b */
+
+ u8 bus_error_1; /* RTC + 0x1c */
+ u8 int_day; /* RTC + 0x1d */
+ u8 int_min; /* RTC + 0x1e */
+ u8 int_sec; /* RTC + 0x1f */
+
+ /*
+ * target_time:
+ * intended to be used for hibernation but hibernation
+ * does not work on silicon rev 1.5 so use it for non-volatile
+ * storage of offset between the actual_time register and linux
+ * time
+ */
+ u32 target_time; /* RTC + 0x20 */
+ /*
+ * actual_time:
+ * readonly time since VBAT_RTC was last connected
+ */
+ u32 actual_time; /* RTC + 0x24 */
+ u32 keep_alive; /* RTC + 0x28 */
+};
+
+struct mpc5121_rtc_data {
+ unsigned irq;
+ unsigned irq_periodic;
+ struct mpc5121_rtc_regs __iomem *regs;
+ struct rtc_device *rtc;
+ struct rtc_wkalrm wkalarm;
+};
+
+/*
+ * Update second/minute/hour registers.
+ *
+ * This is just so alarm will work.
+ */
+static void mpc5121_rtc_update_smh(struct mpc5121_rtc_regs __iomem *regs,
+ struct rtc_time *tm)
+{
+ out_8(®s->second_set, tm->tm_sec);
+ out_8(®s->minute_set, tm->tm_min);
+ out_8(®s->hour_set, tm->tm_hour);
+
+ /* set time sequence */
+ out_8(®s->set_time, 0x1);
+ out_8(®s->set_time, 0x3);
+ out_8(®s->set_time, 0x1);
+ out_8(®s->set_time, 0x0);
+}
+
+static int mpc5121_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+ unsigned long now;
+
+ /*
+ * linux time is actual_time plus the offset saved in target_time
+ */
+ now = in_be32(®s->actual_time) + in_be32(®s->target_time);
+
+ rtc_time_to_tm(now, tm);
+
+ /*
+ * update second minute hour registers
+ * so alarms will work
+ */
+ mpc5121_rtc_update_smh(regs, tm);
+
+ return 0;
+}
+
+static int mpc5121_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+ int ret;
+ unsigned long now;
+
+
+ /*
+ * The actual_time register is read only so we write the offset
+ * between it and linux time to the target_time register.
+ */
+ ret = rtc_tm_to_time(tm, &now);
+ if (ret == 0)
+ out_be32(®s->target_time, now - in_be32(®s->actual_time));
+
+ /*
+ * update second minute hour registers
+ * so alarms will work
+ */
+ mpc5121_rtc_update_smh(regs, tm);
+
+ return 0;
+}
+
+static int mpc5121_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+ *alarm = rtc->wkalarm;
+
+ alarm->pending = in_8(®s->alm_status);
+
+ return 0;
+}
+
+static int mpc5121_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+ /*
+ * the alarm has no seconds so deal with it
+ */
+ if (alarm->time.tm_sec) {
+ alarm->time.tm_sec = 0;
+ alarm->time.tm_min++;
+ if (alarm->time.tm_min >= 60) {
+ alarm->time.tm_min = 0;
+ alarm->time.tm_hour++;
+ if (alarm->time.tm_hour >= 24)
+ alarm->time.tm_hour = 0;
+ }
+ }
+
+ alarm->time.tm_mday = -1;
+ alarm->time.tm_mon = -1;
+ alarm->time.tm_year = -1;
+
+ out_8(®s->alm_min_set, alarm->time.tm_min);
+ out_8(®s->alm_hour_set, alarm->time.tm_hour);
+
+ out_8(®s->alm_enable, alarm->enabled);
+
+ rtc->wkalarm = *alarm;
+ return 0;
+}
+
+static irqreturn_t mpc5121_rtc_handler(int irq, void *dev)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+ if (in_8(®s->int_alm)) {
+ /* acknowledge and clear status */
+ out_8(®s->int_alm, 1);
+ out_8(®s->alm_status, 1);
+
+ rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static irqreturn_t mpc5121_rtc_handler_upd(int irq, void *dev)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+ if (in_8(®s->int_sec) && (in_8(®s->int_enable) & 0x1)) {
+ /* acknowledge */
+ out_8(®s->int_sec, 1);
+
+ rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_UF);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int mpc5121_rtc_ioctl(struct device *dev, unsigned int cmd,
+ unsigned long arg)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+ switch (cmd) {
+ /* alarm interrupt */
+ case RTC_AIE_ON:
+ out_8(®s->alm_enable, 1);
+ rtc->wkalarm.enabled = 1;
+ break;
+ case RTC_AIE_OFF:
+ out_8(®s->alm_enable, 0);
+ rtc->wkalarm.enabled = 0;
+ break;
+
+ /* update interrupt */
+ case RTC_UIE_ON:
+ out_8(®s->int_enable,
+ (in_8(®s->int_enable) & ~0x8) | 0x1);
+ break;
+ case RTC_UIE_OFF:
+ out_8(®s->int_enable, in_8(®s->int_enable) & ~0x1);
+ break;
+
+ /* no periodic interrupts */
+ case RTC_IRQP_READ:
+ case RTC_IRQP_SET:
+ return -ENOTTY;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static const struct rtc_class_ops mpc5121_rtc_ops = {
+ .read_time = mpc5121_rtc_read_time,
+ .set_time = mpc5121_rtc_set_time,
+ .read_alarm = mpc5121_rtc_read_alarm,
+ .set_alarm = mpc5121_rtc_set_alarm,
+ .ioctl = mpc5121_rtc_ioctl,
+};
+
+static int __devinit mpc5121_rtc_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ struct mpc5121_rtc_data *rtc;
+ int err = 0;
+ u32 ka;
+
+ rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+ if (!rtc) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ rtc->regs = of_iomap(op->node, 0);
+
+ if (!rtc->regs) {
+ printk(KERN_ERR "%s: couldn't map io space\n", __func__);
+ err = -ENOSYS;
+ goto out_free;
+ }
+
+ device_init_wakeup(&op->dev, 1);
+
+ rtc->rtc = rtc_device_register("mpc5121-rtc", &op->dev,
+ &mpc5121_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc->rtc)) {
+ err = PTR_ERR(rtc->rtc);
+ goto out_unmap;
+ }
+
+ dev_set_drvdata(&op->dev, rtc);
+
+ rtc->irq = irq_of_parse_and_map(op->node, 1);
+ err = request_irq(rtc->irq, mpc5121_rtc_handler, IRQF_DISABLED,
+ "mpc5121-rtc", &op->dev);
+ if (err) {
+ printk(KERN_ERR "%s: could not request irq: %i\n",
+ __func__, rtc->irq);
+ goto out_dispose;
+ }
+
+ rtc->irq_periodic = irq_of_parse_and_map(op->node, 0);
+ err = request_irq(rtc->irq_periodic, mpc5121_rtc_handler_upd,
+ IRQF_DISABLED, "mpc5121-rtc_upd", &op->dev);
+ if (err) {
+ printk(KERN_ERR "%s: could not request irq: %i\n",
+ __func__, rtc->irq_periodic);
+ goto out_dispose2;
+ }
+
+ ka = in_be32(&rtc->regs->keep_alive);
+ if (ka & 0x02) {
+ printk(KERN_WARNING
+ "mpc5121-rtc: Battery or oscillator failure!\n");
+ out_be32(&rtc->regs->keep_alive, ka);
+ }
+
+ goto out;
+
+out_dispose2:
+ irq_dispose_mapping(rtc->irq_periodic);
+ free_irq(rtc->irq, &op->dev);
+out_dispose:
+ irq_dispose_mapping(rtc->irq);
+out_unmap:
+ iounmap(rtc->regs);
+out_free:
+ kfree(rtc);
+out:
+ return err;
+}
+
+static int __devexit mpc5121_rtc_remove(struct of_device *op)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(&op->dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+ /* disable interrupt, so there are no nasty surprises */
+ out_8(®s->alm_enable, 0);
+ out_8(®s->int_enable, in_8(®s->int_enable) & ~0x1);
+
+ rtc_device_unregister(rtc->rtc);
+ iounmap(rtc->regs);
+ free_irq(rtc->irq, &op->dev);
+ free_irq(rtc->irq_periodic, &op->dev);
+ irq_dispose_mapping(rtc->irq);
+ irq_dispose_mapping(rtc->irq_periodic);
+ dev_set_drvdata(&op->dev, NULL);
+ kfree(rtc);
+
+ return 0;
+}
+
+static struct of_device_id mpc5121_rtc_match[] = {
+ { .compatible = "fsl,mpc5121-rtc", },
+ {},
+};
+
+static struct of_platform_driver mpc5121_rtc_driver = {
+ .owner = THIS_MODULE,
+ .name = "mpc5121-rtc",
+ .match_table = mpc5121_rtc_match,
+ .probe = mpc5121_rtc_probe,
+ .remove = mpc5121_rtc_remove,
+};
+
+static int __init mpc5121_rtc_init(void)
+{
+ return of_register_platform_driver(&mpc5121_rtc_driver);
+}
+
+static void __exit mpc5121_rtc_exit(void)
+{
+ of_unregister_platform_driver(&mpc5121_rtc_driver);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Rigby <jrigby@freescale.com>");
+
+module_init(mpc5121_rtc_init);
+module_exit(mpc5121_rtc_exit);
--
1.6.0.6
^ permalink raw reply related
* [PATCH 11/12] mpc5121: Added MPC512x DMA driver.
From: Wolfgang Denk @ 2009-05-06 20:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Piotr Ziecik, Wolfgang Denk
In-Reply-To: <1241640919-4650-1-git-send-email-wd@denx.de>
From: Piotr Ziecik <kosmo@semihalf.com>
This patch adds initial version of MPC512x DMA driver.
Only memory to memory transfers are currenly supported.
Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: John Rigby <jcrigby@gmail.com>
---
arch/powerpc/boot/dts/mpc5121ads.dts | 2 +-
arch/powerpc/platforms/512x/mpc512x_shared.c | 1 +
drivers/dma/Kconfig | 7 +
drivers/dma/Makefile | 1 +
drivers/dma/mpc512x_dma.c | 642 ++++++++++++++++++++++++++
drivers/dma/mpc512x_dma.h | 192 ++++++++
6 files changed, 844 insertions(+), 1 deletions(-)
create mode 100644 drivers/dma/mpc512x_dma.c
create mode 100644 drivers/dma/mpc512x_dma.h
diff --git a/arch/powerpc/boot/dts/mpc5121ads.dts b/arch/powerpc/boot/dts/mpc5121ads.dts
index c2d9de9..e7f0e09 100644
--- a/arch/powerpc/boot/dts/mpc5121ads.dts
+++ b/arch/powerpc/boot/dts/mpc5121ads.dts
@@ -373,7 +373,7 @@
};
dma@14000 {
- compatible = "fsl,mpc5121-dma2";
+ compatible = "fsl,mpc512x-dma";
reg = <0x14000 0x1800>;
interrupts = <65 0x8>;
interrupt-parent = < &ipic >;
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index b776e45..135fd6b 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -95,6 +95,7 @@ void __init mpc512x_init_i2c(void)
static struct of_device_id __initdata of_bus_ids[] = {
{ .compatible = "fsl,mpc5121-immr", },
{ .compatible = "fsl,mpc5121-localbus", },
+ { .compatible = "fsl,mpc5121-dma", },
{ .compatible = "fsl,mpc5121-nfc", },
{},
};
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 3b3c01b..e734a7a 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -55,6 +55,13 @@ config FSL_DMA
The Elo is the DMA controller on some 82xx and 83xx parts, and the
Elo Plus is the DMA controller on 85xx and 86xx parts.
+config MPC512X_DMA
+ tristate "Freescale MPC512x built-in DMA engine support"
+ depends on PPC_MPC512x
+ select DMA_ENGINE
+ ---help---
+ Enable support for the Freescale MPC512x built-in DMA engine.
+
config MV_XOR
bool "Marvell XOR engine support"
depends on PLAT_ORION
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 2e5dc96..f02806c 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_INTEL_IOATDMA) += ioatdma.o
ioatdma-objs := ioat.o ioat_dma.o ioat_dca.o
obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o
obj-$(CONFIG_FSL_DMA) += fsldma.o
+obj-$(CONFIG_MPC512X_DMA) += mpc512x_dma.o
obj-$(CONFIG_MV_XOR) += mv_xor.o
obj-$(CONFIG_DW_DMAC) += dw_dmac.o
obj-$(CONFIG_MX3_IPU) += ipu/
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
new file mode 100644
index 0000000..1aac897
--- /dev/null
+++ b/drivers/dma/mpc512x_dma.c
@@ -0,0 +1,642 @@
+/*
+ * Copyright (C) Semihalf 2009
+ *
+ * Written by: Piotr Ziecik <kosmo@semihalf.com>
+ *
+ * Approved as OSADL project by a majority of OSADL members and funded
+ * by OSADL membership fees in 2009; for details see www.osadl.org.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ */
+
+/*
+ * This is initial version of MPC5121 DMA driver. Only memory to memory
+ * transfers are supported (tested using dmatest module).
+ */
+
+#include <linux/module.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+#include <linux/random.h>
+
+#include "mpc512x_dma.h"
+
+#define DRV_NAME "mpc512x_dma"
+
+/* Convert struct dma_chan to struct mpc_dma_chan */
+static inline struct mpc_dma_chan *dma_chan_to_mpc_dma_chan(struct dma_chan *c)
+{
+ return container_of(c, struct mpc_dma_chan, chan);
+}
+
+/* Convert struct dma_chan to struct mpc_dma */
+static inline struct mpc_dma *dma_chan_to_mpc_dma(struct dma_chan *c)
+{
+ struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(c);
+ return container_of(mchan, struct mpc_dma, channels[c->chan_id]);
+}
+
+/*
+ * Execute all queued DMA descriptors.
+ *
+ * Following requirements must be met while calling mpc_dma_execute():
+ * a) mchan->lock is acquired,
+ * b) mchan->active list is empty,
+ * c) mchan->queued list contains at least one entry.
+ */
+static void mpc_dma_execute(struct mpc_dma_chan *mchan)
+{
+ struct mpc_dma *mdma = dma_chan_to_mpc_dma(&mchan->chan);
+ struct mpc_dma_desc *first = NULL;
+ struct mpc_dma_desc *prev = NULL;
+ struct mpc_dma_desc *mdesc;
+ int cid = mchan->chan.chan_id;
+
+ /* Move all queued descriptors to active list */
+ list_splice_tail_init(&mchan->queued, &mchan->active);
+
+ /* Chain descriptors into one transaction */
+ list_for_each_entry(mdesc, &mchan->active, node) {
+ if (!first)
+ first = mdesc;
+
+ if (!prev) {
+ prev = mdesc;
+ continue;
+ }
+
+ prev->tcd->dlast_sga = mdesc->tcd_paddr;
+ prev->tcd->e_sg = 1;
+ mdesc->tcd->start = 1;
+
+ prev = mdesc;
+ }
+
+ prev->tcd->start = 0;
+ prev->tcd->int_maj = 1;
+
+ /* Send first descriptor in chain into hardware */
+ memcpy_toio(&mdma->tcd[cid], first->tcd, sizeof(struct mpc_dma_tcd));
+ out_8(&mdma->regs->dmassrt, cid);
+}
+
+/* Handle interrupt on one half of DMA controller (32 channels) */
+static void mpc_dma_irq_process(struct mpc_dma *mdma, u32 is, u32 es, int off)
+{
+ struct mpc_dma_chan *mchan;
+ struct mpc_dma_desc *mdesc;
+ u32 status = is | es;
+ int ch;
+
+ while ((ch = fls(status) - 1) >= 0) {
+ status &= ~(1 << ch);
+ mchan = &mdma->channels[ch + off];
+
+ spin_lock(&mchan->lock);
+
+ /* Check error status */
+ if (es & (1 << ch))
+ list_for_each_entry(mdesc, &mchan->active, node)
+ mdesc->error = -EIO;
+
+ /* Execute queued descriptors */
+ list_splice_tail_init(&mchan->active, &mchan->completed);
+ if (!list_empty(&mchan->queued))
+ mpc_dma_execute(mchan);
+
+ spin_unlock(&mchan->lock);
+ }
+}
+
+/* Interrupt handler */
+static irqreturn_t mpc_dma_irq(int irq, void *data)
+{
+ struct mpc_dma *mdma = data;
+ uint es;
+
+ /* Save error status register */
+ es = in_be32(&mdma->regs->dmaes);
+ spin_lock(&mdma->error_status_lock);
+ if ((es & MPC_DMA_DMAES_VLD) && mdma->error_status == 0)
+ mdma->error_status = es;
+ spin_unlock(&mdma->error_status_lock);
+
+ /* Handle interrupt on each channel */
+ mpc_dma_irq_process(mdma, in_be32(&mdma->regs->dmainth),
+ in_be32(&mdma->regs->dmaerrh), 32);
+ mpc_dma_irq_process(mdma, in_be32(&mdma->regs->dmaintl),
+ in_be32(&mdma->regs->dmaerrl), 0);
+
+ /* Ack interrupt on all channels */
+ out_be32(&mdma->regs->dmainth, 0xFFFFFFFF);
+ out_be32(&mdma->regs->dmaintl, 0xFFFFFFFF);
+ out_be32(&mdma->regs->dmaerrh, 0xFFFFFFFF);
+ out_be32(&mdma->regs->dmaerrl, 0xFFFFFFFF);
+
+ /* Schedule tasklet */
+ tasklet_schedule(&mdma->tasklet);
+
+ return IRQ_HANDLED;
+}
+
+/* DMA Tasklet */
+static void mpc_dma_tasklet(unsigned long data)
+{
+ struct mpc_dma *mdma = (void *)data;
+ dma_cookie_t last_cookie = 0;
+ struct mpc_dma_chan *mchan;
+ struct mpc_dma_desc *mdesc;
+ struct dma_async_tx_descriptor *desc;
+ unsigned long flags;
+ LIST_HEAD(list);
+ uint es;
+ int i;
+
+ spin_lock_irqsave(&mdma->error_status_lock, flags);
+ es = mdma->error_status;
+ mdma->error_status = 0;
+ spin_unlock_irqrestore(&mdma->error_status_lock, flags);
+
+ /* Print nice error report */
+ if (es) {
+ dev_err(mdma->dma.dev,
+ "Hardware reported following error(s) on channel %u:\n",
+ MPC_DMA_DMAES_ERRCHN(es));
+
+ if (es & MPC_DMA_DMAES_GPE)
+ dev_err(mdma->dma.dev, "- Group Priority Error\n");
+ if (es & MPC_DMA_DMAES_CPE)
+ dev_err(mdma->dma.dev, "- Channel Priority Error\n");
+ if (es & MPC_DMA_DMAES_SAE)
+ dev_err(mdma->dma.dev, "- Source Address Error\n");
+ if (es & MPC_DMA_DMAES_SOE)
+ dev_err(mdma->dma.dev, "- Source Offset"
+ " Configuration Error\n");
+ if (es & MPC_DMA_DMAES_DAE)
+ dev_err(mdma->dma.dev, "- Destination Address"
+ " Error\n");
+ if (es & MPC_DMA_DMAES_DOE)
+ dev_err(mdma->dma.dev, "- Destination Offset"
+ " Configuration Error\n");
+ if (es & MPC_DMA_DMAES_NCE)
+ dev_err(mdma->dma.dev, "- NBytes/Citter"
+ " Configuration Error\n");
+ if (es & MPC_DMA_DMAES_SGE)
+ dev_err(mdma->dma.dev, "- Scatter/Gather"
+ " Configuration Error\n");
+ if (es & MPC_DMA_DMAES_SBE)
+ dev_err(mdma->dma.dev, "- Source Bus Error\n");
+ if (es & MPC_DMA_DMAES_DBE)
+ dev_err(mdma->dma.dev, "- Destination Bus Error\n");
+ }
+
+ for (i = 0; i < mdma->dma.chancnt; i++) {
+ mchan = &mdma->channels[i];
+
+ /* Get all completed descriptors */
+ spin_lock_irqsave(&mchan->lock, flags);
+ if (!list_empty(&mchan->completed))
+ list_splice_tail_init(&mchan->completed, &list);
+ spin_unlock_irqrestore(&mchan->lock, flags);
+
+ if (list_empty(&list))
+ continue;
+
+ /* Execute callbacks and run dependencies */
+ list_for_each_entry(mdesc, &list, node) {
+ desc = &mdesc->desc;
+
+ if (desc->callback)
+ desc->callback(desc->callback_param);
+
+ last_cookie = desc->cookie;
+ dma_run_dependencies(desc);
+ }
+
+ /* Free descriptors */
+ spin_lock_irqsave(&mchan->lock, flags);
+ list_splice_tail_init(&list, &mchan->free);
+ mchan->completed_cookie = last_cookie;
+ spin_unlock_irqrestore(&mchan->lock, flags);
+ }
+}
+
+/* Submit descriptor to hardware */
+static dma_cookie_t mpc_dma_tx_submit(struct dma_async_tx_descriptor *txd)
+{
+ struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(txd->chan);
+ struct mpc_dma_desc *mdesc;
+ unsigned long flags;
+ dma_cookie_t cookie;
+
+ mdesc = container_of(txd, struct mpc_dma_desc, desc);
+
+ spin_lock_irqsave(&mchan->lock, flags);
+
+ /* Move descriptor to queue */
+ list_move_tail(&mdesc->node, &mchan->queued);
+
+ /* If channel is idle, execute all queued descriptors */
+ if (list_empty(&mchan->active))
+ mpc_dma_execute(mchan);
+
+ /* Update cookie */
+ cookie = mchan->chan.cookie + 1;
+ if (cookie <= 0)
+ cookie = 1;
+
+ mchan->chan.cookie = cookie;
+ mdesc->desc.cookie = cookie;
+
+ spin_unlock_irqrestore(&mchan->lock, flags);
+
+ return cookie;
+}
+
+/* Alloc channel resources */
+static int mpc_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct mpc_dma *mdma = dma_chan_to_mpc_dma(chan);
+ struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
+ struct mpc_dma_desc *mdesc;
+ struct mpc_dma_tcd *tcd;
+ dma_addr_t tcd_paddr;
+ unsigned long flags;
+ LIST_HEAD(descs);
+ int i;
+
+ /* Alloc DMA memory for Transfer Control Descriptors */
+ tcd = dma_alloc_coherent(mdma->dma.dev,
+ MPC_DMA_DESCRIPTORS * sizeof(struct mpc_dma_tcd),
+ &tcd_paddr, GFP_KERNEL);
+ if (!tcd)
+ return -ENOMEM;
+
+ /* Alloc descriptors for this channel */
+ for (i = 0; i < MPC_DMA_DESCRIPTORS; i++) {
+ mdesc = kzalloc(sizeof(struct mpc_dma_desc), GFP_KERNEL);
+ if (!mdesc) {
+ dev_notice(mdma->dma.dev, "Memory allocation error. "
+ "Allocated only %u descriptors\n", i);
+ break;
+ }
+
+ dma_async_tx_descriptor_init(&mdesc->desc, chan);
+ mdesc->desc.flags = DMA_CTRL_ACK;
+ mdesc->desc.tx_submit = mpc_dma_tx_submit;
+
+ mdesc->tcd = &tcd[i];
+ mdesc->tcd_paddr = tcd_paddr + (i * sizeof(struct mpc_dma_tcd));
+
+ list_add_tail(&mdesc->node, &descs);
+ }
+
+ /* Return error only if no descriptors were allocated */
+ if (i == 0) {
+ dma_free_coherent(mdma->dma.dev,
+ MPC_DMA_DESCRIPTORS * sizeof(struct mpc_dma_tcd),
+ tcd, tcd_paddr);
+ return -ENOMEM;
+ }
+
+ spin_lock_irqsave(&mchan->lock, flags);
+ mchan->tcd = tcd;
+ mchan->tcd_paddr = tcd_paddr;
+ list_splice_tail_init(&descs, &mchan->free);
+ spin_unlock_irqrestore(&mchan->lock, flags);
+
+ /* Enable Error Interrupt */
+ out_8(&mdma->regs->dmaseei, chan->chan_id);
+
+ return 0;
+}
+
+/* Free channel resources */
+static void mpc_dma_free_chan_resources(struct dma_chan *chan)
+{
+ struct mpc_dma *mdma = dma_chan_to_mpc_dma(chan);
+ struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
+ struct mpc_dma_desc *mdesc, *tmp;
+ struct mpc_dma_tcd *tcd;
+ dma_addr_t tcd_paddr;
+ unsigned long flags;
+ LIST_HEAD(descs);
+
+ spin_lock_irqsave(&mchan->lock, flags);
+
+ /* Channel must be idle */
+ BUG_ON(!list_empty(&mchan->prepared));
+ BUG_ON(!list_empty(&mchan->queued));
+ BUG_ON(!list_empty(&mchan->active));
+ BUG_ON(!list_empty(&mchan->completed));
+
+ /* Move data */
+ list_splice_tail_init(&mchan->free, &descs);
+ tcd = mchan->tcd;
+ tcd_paddr = mchan->tcd_paddr;
+
+ spin_unlock_irqrestore(&mchan->lock, flags);
+
+ /* Free DMA memory used by descriptors */
+ dma_free_coherent(mdma->dma.dev,
+ MPC_DMA_DESCRIPTORS * sizeof(struct mpc_dma_tcd),
+ tcd, tcd_paddr);
+
+ /* Free descriptors */
+ list_for_each_entry_safe(mdesc, tmp, &descs, node)
+ kfree(mdesc);
+
+ /* Disable Error Interrupt */
+ out_8(&mdma->regs->dmaceei, chan->chan_id);
+}
+
+/* Send all pending descriptor to hardware */
+static void mpc_dma_issue_pending(struct dma_chan *chan)
+{
+ /*
+ * We are posting descriptors to the hardware as soon as
+ * they are ready, so this function does nothing.
+ */
+}
+
+/* Check request completion status */
+static enum dma_status
+mpc_dma_is_tx_complete(struct dma_chan *chan, dma_cookie_t cookie,
+ dma_cookie_t *done, dma_cookie_t *used)
+{
+ struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
+ unsigned long flags;
+ dma_cookie_t last_used;
+ dma_cookie_t last_complete;
+
+ spin_lock_irqsave(&mchan->lock, flags);
+ last_used = mchan->chan.cookie;
+ last_complete = mchan->completed_cookie;
+ spin_unlock_irqrestore(&mchan->lock, flags);
+
+ if (done)
+ *done = last_complete;
+
+ if (used)
+ *used = last_used;
+
+ return dma_async_is_complete(cookie, last_complete, last_used);
+}
+
+/* Prepare descriptor for memory to memory copy */
+static struct dma_async_tx_descriptor *
+mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
+ size_t len, unsigned long flags)
+{
+ struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
+ struct mpc_dma_desc *mdesc = NULL;
+ struct mpc_dma_tcd *tcd;
+ unsigned long iflags;
+
+ /* Get free descriptor */
+ spin_lock_irqsave(&mchan->lock, iflags);
+ if (!list_empty(&mchan->free)) {
+ mdesc = list_first_entry(&mchan->free, struct mpc_dma_desc,
+ node);
+ list_del(&mdesc->node);
+ }
+ spin_unlock_irqrestore(&mchan->lock, iflags);
+
+ if (!mdesc)
+ return NULL;
+
+ mdesc->error = 0;
+ tcd = mdesc->tcd;
+
+ /* Prepare Transfer Control Descriptor for this transaction */
+ memset(tcd, 0, sizeof(struct mpc_dma_tcd));
+
+ if (IS_ALIGNED(src | dst | len, 32)) {
+ tcd->ssize = MPC_DMA_TSIZE_32;
+ tcd->dsize = MPC_DMA_TSIZE_32;
+ tcd->soff = 32;
+ tcd->doff = 32;
+ } else if (IS_ALIGNED(src | dst | len, 16)) {
+ tcd->ssize = MPC_DMA_TSIZE_16;
+ tcd->dsize = MPC_DMA_TSIZE_16;
+ tcd->soff = 16;
+ tcd->doff = 16;
+ } else if (IS_ALIGNED(src | dst | len, 4)) {
+ tcd->ssize = MPC_DMA_TSIZE_4;
+ tcd->dsize = MPC_DMA_TSIZE_4;
+ tcd->soff = 4;
+ tcd->doff = 4;
+ } else if (IS_ALIGNED(src | dst | len, 2)) {
+ tcd->ssize = MPC_DMA_TSIZE_2;
+ tcd->dsize = MPC_DMA_TSIZE_2;
+ tcd->soff = 2;
+ tcd->doff = 2;
+ } else {
+ tcd->ssize = MPC_DMA_TSIZE_1;
+ tcd->dsize = MPC_DMA_TSIZE_1;
+ tcd->soff = 1;
+ tcd->doff = 1;
+ }
+
+ tcd->saddr = src;
+ tcd->daddr = dst;
+ tcd->nbytes = len;
+ tcd->biter = 1;
+ tcd->citer = 1;
+
+ /* Place descriptor in prepared list */
+ spin_lock_irqsave(&mchan->lock, iflags);
+ list_add_tail(&mdesc->node, &mchan->prepared);
+ spin_unlock_irqrestore(&mchan->lock, iflags);
+
+ return &mdesc->desc;
+}
+
+static int __init mpc_dma_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ struct device_node *dn = op->node;
+ struct device *dev = &op->dev;
+ struct dma_device *dma;
+ struct mpc_dma *mdma;
+ struct mpc_dma_chan *mchan;
+ struct resource res;
+ ulong regs_start, regs_size;
+ int retval, i;
+
+ mdma = devm_kzalloc(dev, sizeof(struct mpc_dma), GFP_KERNEL);
+ if (!mdma) {
+ dev_err(dev, "Memory exhausted!\n");
+ return -ENOMEM;
+ }
+
+ mdma->irq = irq_of_parse_and_map(dn, 0);
+ if (mdma->irq == NO_IRQ) {
+ dev_err(dev, "Error mapping IRQ!\n");
+ return -EINVAL;
+ }
+
+ retval = of_address_to_resource(dn, 0, &res);
+ if (retval) {
+ dev_err(dev, "Error parsing memory region!\n");
+ return retval;
+ }
+
+ regs_start = res.start;
+ regs_size = res.end - res.start + 1;
+
+ if (!devm_request_mem_region(dev, regs_start, regs_size, DRV_NAME)) {
+ dev_err(dev, "Error requesting memory region!\n");
+ return -EBUSY;
+ }
+
+ mdma->regs = devm_ioremap(dev, regs_start, regs_size);
+ if (!mdma->regs) {
+ dev_err(dev, "Error mapping memory region!\n");
+ return -ENOMEM;
+ }
+
+ mdma->tcd = (struct mpc_dma_tcd *)((u8 *)(mdma->regs)
+ + MPC_DMA_TCD_OFFSET);
+
+ retval = devm_request_irq(dev, mdma->irq, &mpc_dma_irq, 0, DRV_NAME,
+ mdma);
+ if (retval) {
+ dev_err(dev, "Error requesting IRQ!\n");
+ return -EINVAL;
+ }
+
+ spin_lock_init(&mdma->error_status_lock);
+
+ dma = &mdma->dma;
+ dma->dev = dev;
+ dma->chancnt = MPC_DMA_CHANNELS;
+ dma->device_alloc_chan_resources = mpc_dma_alloc_chan_resources;
+ dma->device_free_chan_resources = mpc_dma_free_chan_resources;
+ dma->device_issue_pending = mpc_dma_issue_pending;
+ dma->device_is_tx_complete = mpc_dma_is_tx_complete;
+ dma->device_prep_dma_memcpy = mpc_dma_prep_memcpy;
+
+ INIT_LIST_HEAD(&dma->channels);
+ dma_cap_set(DMA_MEMCPY, dma->cap_mask);
+
+ for (i = 0; i < dma->chancnt; i++) {
+ mchan = &mdma->channels[i];
+
+ mchan->chan.device = dma;
+ mchan->chan.chan_id = i;
+ mchan->chan.cookie = 1;
+ mchan->completed_cookie = mchan->chan.cookie;
+
+ INIT_LIST_HEAD(&mchan->free);
+ INIT_LIST_HEAD(&mchan->prepared);
+ INIT_LIST_HEAD(&mchan->queued);
+ INIT_LIST_HEAD(&mchan->active);
+ INIT_LIST_HEAD(&mchan->completed);
+
+ spin_lock_init(&mchan->lock);
+ list_add_tail(&mchan->chan.device_node, &dma->channels);
+ }
+
+ tasklet_init(&mdma->tasklet, mpc_dma_tasklet, (unsigned long)mdma);
+
+ /*
+ * Configure DMA Engine:
+ * - Dynamic clock,
+ * - Round-robin group arbitration,
+ * - Round-robin channel arbitration.
+ */
+ out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_EDCG |
+ MPC_DMA_DMACR_ERGA | MPC_DMA_DMACR_ERCA);
+
+ /* Disable hardware DMA requests */
+ out_be32(&mdma->regs->dmaerqh, 0);
+ out_be32(&mdma->regs->dmaerql, 0);
+
+ /* Disable error interrupts */
+ out_be32(&mdma->regs->dmaeeih, 0);
+ out_be32(&mdma->regs->dmaeeil, 0);
+
+ /* Clear interrupts status */
+ out_be32(&mdma->regs->dmainth, 0xFFFFFFFF);
+ out_be32(&mdma->regs->dmaintl, 0xFFFFFFFF);
+ out_be32(&mdma->regs->dmaerrh, 0xFFFFFFFF);
+ out_be32(&mdma->regs->dmaerrl, 0xFFFFFFFF);
+
+ /* Route interrupts to IPIC */
+ out_be32(&mdma->regs->dmaihsa, 0);
+ out_be32(&mdma->regs->dmailsa, 0);
+
+ /* Register DMA engine */
+ dev_set_drvdata(dev, mdma);
+ retval = dma_async_device_register(dma);
+ if (retval)
+ devm_free_irq(dev, mdma->irq, mdma);
+
+ return retval;
+}
+
+static void __exit mpc_dma_remove(struct of_device *op)
+{
+ struct device *dev = &op->dev;
+ struct mpc_dma *mdma = dev_get_drvdata(dev);
+
+ devm_free_irq(dev, mdma->irq, mdma);
+}
+
+static struct of_device_id mpc_dma_match[] = {
+ { .compatible = "fsl,mpc512x-dma", },
+ {},
+};
+
+static struct of_platform_driver mpc_dma_driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .match_table = mpc_dma_match,
+ .probe = mpc_dma_probe,
+ .remove = __exit_p(mpc_dma_remove),
+ .suspend = NULL,
+ .resume = NULL,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init mpc_dma_init(void)
+{
+ return of_register_platform_driver(&mpc_dma_driver);
+}
+
+static void __exit mpc_dma_exit(void)
+{
+ of_unregister_platform_driver(&mpc_dma_driver);
+}
+
+module_init(mpc_dma_init);
+module_exit(mpc_dma_exit);
+
+/* MODULE API */
+MODULE_VERSION("0.5");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Piotr Ziecik <kosmo@semihalf.com>");
diff --git a/drivers/dma/mpc512x_dma.h b/drivers/dma/mpc512x_dma.h
new file mode 100644
index 0000000..867415b
--- /dev/null
+++ b/drivers/dma/mpc512x_dma.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) Freescale Semicondutor, Inc. 2007, 2008.
+ * Copyright (C) Semihalf, 2009.
+ *
+ * Written by Piotr Ziecik <kosmo@semihalf.com>. Hardware description
+ * (defines, structures and comments) was taken from MPC5121 DMA driver
+ * written by Hongjun Chen <hong-jun.chen@freescale.com>.
+ *
+ * Approved as OSADL project by a majority of OSADL members and funded
+ * by OSADL membership fees in 2009; for details see www.osadl.org.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ */
+#ifndef _MPC512X_DMA_H_
+#define _MPC512X_DMA_H_
+
+#include <linux/dmaengine.h>
+
+/* Number of DMA Transfer descriptors allocated per channel */
+#define MPC_DMA_DESCRIPTORS 64
+
+/* Macro definitions */
+#define MPC_DMA_CHANNELS 64
+#define MPC_DMA_TCD_OFFSET 0x1000
+
+/* Arbitration mode of group and channel */
+#define MPC_DMA_DMACR_EDCG (1 << 31)
+#define MPC_DMA_DMACR_ERGA (1 << 3)
+#define MPC_DMA_DMACR_ERCA (1 << 2)
+
+/* Error codes */
+#define MPC_DMA_DMAES_VLD (1 << 31)
+#define MPC_DMA_DMAES_GPE (1 << 15)
+#define MPC_DMA_DMAES_CPE (1 << 14)
+#define MPC_DMA_DMAES_ERRCHN(err) \
+ (((err) >> 8) & 0x3f)
+#define MPC_DMA_DMAES_SAE (1 << 7)
+#define MPC_DMA_DMAES_SOE (1 << 6)
+#define MPC_DMA_DMAES_DAE (1 << 5)
+#define MPC_DMA_DMAES_DOE (1 << 4)
+#define MPC_DMA_DMAES_NCE (1 << 3)
+#define MPC_DMA_DMAES_SGE (1 << 2)
+#define MPC_DMA_DMAES_SBE (1 << 1)
+#define MPC_DMA_DMAES_DBE (1 << 0)
+
+#define MPC_DMA_TSIZE_1 0x00
+#define MPC_DMA_TSIZE_2 0x01
+#define MPC_DMA_TSIZE_4 0x02
+#define MPC_DMA_TSIZE_16 0x04
+#define MPC_DMA_TSIZE_32 0x05
+
+/* MPC5121 DMA engine registers */
+struct __attribute__ ((__packed__)) mpc_dma_regs {
+ /* 0x00 */
+ u32 dmacr; /* DMA control register */
+ u32 dmaes; /* DMA error status */
+ /* 0x08 */
+ u32 dmaerqh; /* DMA enable request high(channels 63~32) */
+ u32 dmaerql; /* DMA enable request low(channels 31~0) */
+ u32 dmaeeih; /* DMA enable error interrupt high(ch63~32) */
+ u32 dmaeeil; /* DMA enable error interrupt low(ch31~0) */
+ /* 0x18 */
+ u8 dmaserq; /* DMA set enable request */
+ u8 dmacerq; /* DMA clear enable request */
+ u8 dmaseei; /* DMA set enable error interrupt */
+ u8 dmaceei; /* DMA clear enable error interrupt */
+ /* 0x1c */
+ u8 dmacint; /* DMA clear interrupt request */
+ u8 dmacerr; /* DMA clear error */
+ u8 dmassrt; /* DMA set start bit */
+ u8 dmacdne; /* DMA clear DONE status bit */
+ /* 0x20 */
+ u32 dmainth; /* DMA interrupt request high(ch63~32) */
+ u32 dmaintl; /* DMA interrupt request low(ch31~0) */
+ u32 dmaerrh; /* DMA error high(ch63~32) */
+ u32 dmaerrl; /* DMA error low(ch31~0) */
+ /* 0x30 */
+ u32 dmahrsh; /* DMA hw request status high(ch63~32) */
+ u32 dmahrsl; /* DMA hardware request status low(ch31~0) */
+ u32 dmaihsa; /* DMA interrupt high select AXE(ch63~32) */
+ u32 dmailsa; /* DMA interrupt low select AXE(ch31~0) */
+ /* 0x40 ~ 0xff */
+ u32 reserve0[48]; /* Reserved */
+ /* 0x100 */
+ u8 dchpri[MPC_DMA_CHANNELS];
+ /* DMA channels(0~63) priority */
+};
+
+struct __attribute__ ((__packed__)) mpc_dma_tcd {
+ /* 0x00 */
+ u32 saddr; /* Source address */
+
+ u32 smod:5; /* Source address modulo */
+ u32 ssize:3; /* Source data transfer size */
+ u32 dmod:5; /* Destination address modulo */
+ u32 dsize:3; /* Destination data transfer size */
+ u32 soff:16; /* Signed source address offset */
+
+ /* 0x08 */
+ u32 nbytes; /* Inner "minor" byte count */
+ u32 slast; /* Last source address adjustment */
+ u32 daddr; /* Destination address */
+
+ /* 0x14 */
+ u32 citer_elink:1; /* Enable channel-to-channel linking on
+ * minor loop complete
+ */
+ u32 citer_linkch:6; /* Link channel for minor loop complete */
+ u32 citer:9; /* Current "major" iteration count */
+ u32 doff:16; /* Signed destination address offset */
+
+ /* 0x18 */
+ u32 dlast_sga; /* Last Destination address adjustment/scatter
+ * gather address
+ */
+
+ /* 0x1c */
+ u32 biter_elink:1; /* Enable channel-to-channel linking on major
+ * loop complete
+ */
+ u32 biter_linkch:6;
+ u32 biter:9; /* Beginning "major" iteration count */
+ u32 bwc:2; /* Bandwidth control */
+ u32 major_linkch:6; /* Link channel number */
+ u32 done:1; /* Channel done */
+ u32 active:1; /* Channel active */
+ u32 major_elink:1; /* Enable channel-to-channel linking on major
+ * loop complete
+ */
+ u32 e_sg:1; /* Enable scatter/gather processing */
+ u32 d_req:1; /* Disable request */
+ u32 int_half:1; /* Enable an interrupt when major counter is
+ * half complete
+ */
+ u32 int_maj:1; /* Enable an interrupt when major iteration
+ * count completes
+ */
+ u32 start:1; /* Channel start */
+};
+
+struct mpc_dma_desc {
+ struct dma_async_tx_descriptor desc;
+ struct mpc_dma_tcd *tcd;
+ dma_addr_t tcd_paddr;
+ int error;
+ struct list_head node;
+};
+
+struct mpc_dma_chan {
+ struct dma_chan chan;
+ struct list_head free;
+ struct list_head prepared;
+ struct list_head queued;
+ struct list_head active;
+ struct list_head completed;
+ struct mpc_dma_tcd *tcd;
+ dma_addr_t tcd_paddr;
+ dma_cookie_t completed_cookie;
+
+ /* Lock for this structure */
+ spinlock_t lock;
+};
+
+struct mpc_dma {
+ struct dma_device dma;
+ struct tasklet_struct tasklet;
+ struct mpc_dma_chan channels[MPC_DMA_CHANNELS];
+ struct mpc_dma_regs __iomem *regs;
+ struct mpc_dma_tcd __iomem *tcd;
+ int irq;
+ uint error_status;
+
+ /* Lock for error_status field in this structure */
+ spinlock_t error_status_lock;
+};
+
+#endif /* _MPC512X_DMA_H_ */
--
1.6.0.6
^ permalink raw reply related
* [PATCH 02/04] ARIA: add device tree source file
From: Wolfgang Denk @ 2009-05-06 20:20 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Andrea Scian, Wolfgang Denk
In-Reply-To: <1241641262-5202-1-git-send-email-wd@denx.de>
ARIA is a MPC5121 based COM Express module by Dave/DENX.
Signed-off-by: Andrea Scian <andrea.scian@dave.eu>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: John Rigby <jcrigby@gmail.com>
---
arch/powerpc/boot/dts/aria.dts | 410 ++++++++++++++++++++++++++++++++++++++++
1 files changed, 410 insertions(+), 0 deletions(-)
create mode 100644 arch/powerpc/boot/dts/aria.dts
diff --git a/arch/powerpc/boot/dts/aria.dts b/arch/powerpc/boot/dts/aria.dts
new file mode 100644
index 0000000..6c6b5e4
--- /dev/null
+++ b/arch/powerpc/boot/dts/aria.dts
@@ -0,0 +1,407 @@
+/*
+ * Aria Device Tree Source
+ *
+ * Copyright 2009 Dave Srl www.dave.eu
+ * Copyright 2009 Wolfgang Denk <wd@denx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+/dts-v1/;
+
+/ {
+ model = "aria";
+ compatible = "davedenx,aria";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ aliases {
+ ethernet0 = &enet;
+
+ serial0 = &serial0;
+ serial1 = &serial1;
+
+ pci = &pci;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,5121@0 {
+ device_type = "cpu";
+ reg = <0>;
+ d-cache-line-size = <0x20>; // 32 bytes
+ i-cache-line-size = <0x20>; // 32 bytes
+ d-cache-size = <0x8000>; // L1, 32K
+ i-cache-size = <0x8000>; // L1, 32K
+ timebase-frequency = <49500000>;// 49.5 MHz (csb/4)
+ //bus-frequency = <198000000>; // 198 MHz csb bus
+ //clock-frequency = <396000000>; // 396 MHz ppc core
+ bus-frequency = <158000000>;
+ clock-frequency = <316000000>;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x10000000>; // 256MB at 0
+ };
+
+ mbx@20000000 {
+ device_type = "mbx";
+ compatible = "fsl,mpc5121-mbx";
+ reg = <0x20000000 0x4000>;
+ interrupts = <66 0x8>;
+ interrupt-parent = < &ipic >;
+ };
+
+ sram@30000000 {
+ compatible = "fsl,mpc5121-sram";
+ reg = <0x30000000 0x20000>; // 128K at 0x30000000
+ };
+
+ nfc@40000000 {
+ //compatible = "fsl,mpc5121rev2-nfc";
+ compatible = "fsl,mpc5121-nfc";
+ reg = <0x40000000 0x100000>; // 1M at 0x40000000
+ interrupts = <6 8>;
+ interrupt-parent = < &ipic >;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ write-size = <2048>;
+ spare-size = <64>;
+ chips = <1>;
+ nand@0 {
+ label = "nand";
+ reg = <0x00000000 0x08000000>; // 128 MB
+ };
+ };
+
+ localbus@80000020 {
+ compatible = "fsl,mpc5121-localbus";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ reg = <0x80000020 0x40>;
+
+ ranges = <0x0 0x0 0xF8000000 0x08000000>;
+
+ flash@0,0 {
+ compatible = "cfi-flash";
+ reg = <0 0x0 0x8000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ bank-width = <2>;
+ device-width = <2>;
+ partition@0 {
+ label = "user";
+ reg = <0x00000000 0x07000000>; // 112 MiB for user data
+ };
+ partition@07000000 {
+ label = "rootfs";
+ reg = <0x07000000 0x00c00000>; // 12 MiB for root file system
+ };
+ partition@07c00000 {
+ label = "kernel";
+ reg = <0x07c00000 0x00300000>; // 3 MiB for kernel
+ };
+ partition@07f00000 {
+ label = "u-boot";
+ reg = <0x07f00000 0x000c0000>; // 768 KiB for u-boot w/ env
+ read-only;
+ };
+ partition@07fc0000 {
+ label = "device-tree";
+ reg = <0x07fc0000 0x00040000>; // 256 KiB for device tree
+ };
+ };
+ };
+
+ soc@80000000 {
+ compatible = "fsl,mpc5121-immr";
+ device_type = "soc";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ ranges = <0x0 0x80000000 0x400000>;
+ reg = <0x80000000 0x400000>;
+ bus-frequency = <66000000>; // 66 MHz ips bus
+
+
+ // IPIC
+ // interrupts cell = <intr #, sense>
+ // sense values match linux IORESOURCE_IRQ_* defines:
+ // sense == 8: Level, low assertion
+ // sense == 2: Edge, high-to-low change
+ //
+ ipic: interrupt-controller@c00 {
+ compatible = "fsl,mpc5121-ipic", "fsl,ipic";
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ reg = <0xc00 0x100>;
+ };
+
+ rtc@a00 { // Real time clock
+ compatible = "fsl,mpc5121-rtc";
+ reg = <0xa00 0x100>;
+ interrupts = <79 0x8 80 0x8>;
+ interrupt-parent = < &ipic >;
+ };
+
+ reset@e00 { // Reset module
+ compatible = "fsl,mpc5121-reset";
+ reg = <0xe00 0x100>;
+ };
+
+ clock@f00 { // Clock control
+ compatible = "fsl,mpc5121rev2-clock", "fsl,mpc5121-clock";
+ reg = <0xf00 0x100>;
+ };
+
+ pmc@1000{ //Power Management Controller
+ compatible = "fsl,mpc5121-pmc";
+ reg = <0x1000 0x100>;
+ interrupts = <83 0x2>;
+ interrupt-parent = < &ipic >;
+ };
+
+ gpio@1100 {
+ compatible = "fsl,mpc5121-gpio";
+ reg = <0x1100 0x100>;
+ interrupts = <78 0x8>;
+ interrupt-parent = < &ipic >;
+ };
+
+ mscan@1300 {
+ compatible = "fsl,mpc5121-mscan";
+ cell-index = <0>;
+ interrupts = <12 0x8>;
+ interrupt-parent = < &ipic >;
+ reg = <0x1300 0x80>;
+ };
+
+ mscan@1380 {
+ compatible = "fsl,mpc5121-mscan";
+ cell-index = <1>;
+ interrupts = <13 0x8>;
+ interrupt-parent = < &ipic >;
+ reg = <0x1380 0x80>;
+ };
+
+ // this is here for reference only
+// sdhc@1500 {
+// compatible = "fsl,mpc5121-sdhc";
+// interrupts = <8 0x8>;
+// interrupt-parent = < &ipic >;
+// reg = <0x1500 0x100>;
+// };
+
+ i2c@1700 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,mpc5121-i2c", "fsl-i2c";
+ cell-index = <0>;
+ reg = <0x1700 0x20>;
+ interrupts = <9 0x8>;
+ interrupt-parent = < &ipic >;
+ fsl5200-clocking;
+
+ rtc@68 {
+ compatible = "stm,m41t80";
+ reg = <0x68>;
+ };
+ };
+
+ i2c@1720 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,mpc5121-i2c", "fsl-i2c";
+ cell-index = <1>;
+ reg = <0x1720 0x20>;
+ interrupts = <10 0x8>;
+ interrupt-parent = < &ipic >;
+ fsl5200-clocking;
+ };
+
+ i2c@1740 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,mpc5121-i2c", "fsl-i2c";
+ cell-index = <2>;
+ reg = <0x1740 0x20>;
+ interrupts = <11 0x8>;
+ interrupt-parent = < &ipic >;
+ fsl5200-clocking;
+ };
+
+ i2ccontrol@1760 {
+ compatible = "fsl,mpc5121-i2c-ctrl";
+ reg = <0x1760 0x8>;
+ };
+
+ axe@2000 {
+ compatible = "fsl,mpc5121-axe";
+ reg = <0x2000 0x100>;
+ interrupts = <42 0x8>;
+ interrupt-parent = < &ipic >;
+ };
+
+ diu@2100 {
+ device_type = "display";
+ compatible = "fsl-diu";
+ reg = <0x2100 0x100>;
+ interrupts = <64 0x8>;
+ interrupt-parent = < &ipic >;
+ };
+
+ mdio@2800 {
+ device_type = "mdio";
+ compatible = "fsl,mpc5121-fec-mdio";
+ reg = <0x2800 0x800>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ phy: ethernet-phy@0 {
+ reg = <23>;
+ device_type = "ethernet-phy";
+ };
+ };
+
+ enet: ethernet@2800 {
+ device_type = "network";
+ compatible = "fsl,mpc5121-fec";
+ reg = <0x2800 0x800>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <4 0x8>;
+ interrupt-parent = < &ipic >;
+ phy-handle = < &phy >;
+ fsl,align-tx-packets = <4>;
+ };
+
+ // 5121e has two dr usb modules
+ // We use only USB0
+
+ // USB1 using external ULPI PHY
+ //usb@3000 {
+ // device_type = "usb";
+ // compatible = "fsl-usb2-dr";
+ // reg = <0x3000 0x1000>;
+ // #address-cells = <1>;
+ // #size-cells = <0>;
+ // interrupt-parent = < &ipic >;
+ // interrupts = <43 0x8>;
+ // dr_mode = "otg";
+ // phy_type = "ulpi";
+ //};
+
+ // USB0 using internal UTMI PHY
+ usb@4000 {
+ device_type = "usb";
+ compatible = "fsl-usb2-dr";
+ reg = <0x4000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupt-parent = < &ipic >;
+ interrupts = <44 0x8>;
+ dr_mode = "host";
+ phy_type = "utmi_wide";
+ //port0;
+ };
+
+ // IO control
+ ioctl@a000 {
+ compatible = "fsl,mpc5121-ioctl";
+ reg = <0xA000 0x1000>;
+ };
+
+ pata@10200 {
+ compatible = "fsl,mpc5121-pata";
+ reg = <0x10200 0x100>;
+ interrupts = <5 0x8>;
+ interrupt-parent = < &ipic >;
+ };
+
+ // 512x PSCs are not 52xx PSCs compatible
+ // PSC3 serial port A aka ttyPSC0
+ serial0: serial@11300 {
+ device_type = "serial";
+ compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
+ // Logical port assignment needed until driver
+ // learns to use aliases
+ port-number = <0>;
+ cell-index = <3>;
+ reg = <0x11300 0x100>;
+ interrupts = <40 0x8 71 0x8>;
+ interrupt-parent = < &ipic >;
+ rx-fifo-size = <16>;
+ tx-fifo-size = <16>;
+ nodcd;
+ };
+
+ // PSC4 serial port B aka ttyPSC1
+ serial1: serial@11400 {
+ device_type = "serial";
+ compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
+ // Logical port assignment needed until driver
+ // learns to use aliases
+ port-number = <1>;
+ cell-index = <4>;
+ reg = <0x11400 0x100>;
+ interrupts = <40 0x8 32 0x8>;
+ interrupt-parent = < &ipic >;
+ rx-fifo-size = <16>;
+ tx-fifo-size = <16>;
+ nodcd;
+ };
+
+ // PSC5 in ac97 mode
+ ac97@11500 {
+ device_type = "sound";
+ compatible = "fsl,mpc5121-psc-ac97", "fsl,mpc5121-psc";
+ cell-index = <5>;
+ reg = <0x11500 0x100>;
+ interrupts = <40 0x8>;
+ interrupt-parent = < &ipic >;
+ fsl,mode = "ac97-slave";
+ rx-fifo-size = <384>;
+ tx-fifo-size = <384>;
+ };
+
+ pscfifo@11f00 {
+ compatible = "fsl,mpc5121-psc-fifo";
+ reg = <0x11f00 0x100>;
+ interrupts = <40 0x8>;
+ interrupt-parent = < &ipic >;
+ };
+
+ dma@14000 {
+ compatible = "mpc512x-dma";
+ reg = <0x14000 0x1800>;
+ interrupts = <65 0x8>;
+ interrupt-parent = < &ipic >;
+ };
+
+ };
+
+ pci: pci@80008500 {
+ interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+ interrupt-map = <
+ >;
+ interrupt-parent = < &ipic >;
+ interrupts = <1 0x8>;
+ bus-range = <0 0>;
+ ranges = <0x42000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000
+ 0x02000000 0x0 0xb0000000 0xb0000000 0x0 0x10000000
+ 0x01000000 0x0 0x00000000 0x84000000 0x0 0x01000000>;
+ clock-frequency = <66666666>;
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <0x80008500 0x100>;
+ compatible = "fsl,mpc5121-pci";
+ device_type = "pci";
+ };
+};
--
1.6.0.6
^ 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