* [PATCH V3 7/8] mv643xx.c: Add basic device tree support.
From: Jason Cooper @ 2013-01-28 19:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20130128101249.GB7754@e106331-lin.cambridge.arm.com>
On Mon, Jan 28, 2013 at 10:12:49AM +0000, Mark Rutland wrote:
> Hello,
>
> I've taken a quick look at this, and I have a couple of comments on the binding
> and the way it's parsed.
>
> On Fri, Jan 25, 2013 at 08:53:59PM +0000, Jason Cooper wrote:
> > From: Ian Molton <ian.molton@codethink.co.uk>
> >
> > This patch adds basic device tree support to the mv643xx ethernet driver.
> >
> > It should be enough for most current users of the device, and should allow
> > a painless migration.
> >
> > Signed-off-by: Ian Molton <ian.molton@codethink.co.uk>
> >
> > Signed-off-by: Jason Cooper <jason@lakedaemon.net>
> > ---
> > Documentation/devicetree/bindings/net/mv643xx.txt | 75 ++++++++++++++++++
> > drivers/net/ethernet/marvell/mv643xx_eth.c | 93 +++++++++++++++++++++--
> > 2 files changed, 161 insertions(+), 7 deletions(-)
> > create mode 100644 Documentation/devicetree/bindings/net/mv643xx.txt
> >
> > diff --git a/Documentation/devicetree/bindings/net/mv643xx.txt b/Documentation/devicetree/bindings/net/mv643xx.txt
> > new file mode 100644
> > index 0000000..2727f798
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/net/mv643xx.txt
> > @@ -0,0 +1,75 @@
> > +mv643xx related nodes.
> > +
> > +marvell,mdio-mv643xx:
> > +
> > +Required properties:
> > +
> > + - interrupts : <a> where a is the SMI interrupt number.
> > + - reg : the base address and size of the controllers register space.
> > +
> > +Optional properties:
> > + - shared_smi : on some chips, the second PHY is "shared", meaning it is
> > + really accessed via the first SMI controller. It is passed in this
> > + way due to the present structure of the driver, which requires the
> > + base address for the MAC to be passed in via the SMI controllers
> > + platform data.
>
> The phrase "the present structure of the driver" is not something that's
> generally good to hear in a binding document. Is shared_smi always going to be
> required for such configurations, or is there going to be any driver rework
> that makes it irrelevant?
Florian is working on bring mvmdio up to speed, I'll let him comment on
this.
> > + - tx_csum_limit : on some devices, this option is required for proper
> > + operation wrt. jumbo frames.
>
> This doesn't explain what this property is. Also "limit" doesn't describe
> what's limited (e.g. size, rate). How about something like
> max-tx-checksum-size?
sounds better, I'll update for the next version.
>
> > +
> > +
> > +Example:
> > +
> > +smi0: mdio at 72000 {
> > + compatible = "marvell,mdio-mv643xx";
> > + reg = <0x72000 0x4000>;
> > + interrupts = <46>;
> > + tx_csum_limit = <1600>;
> > + status = "disabled";
> > +};
> > +
> > +smi1: mdio at 76000 {
> > + compatible = "marvell,mdio-mv643xx";
> > + reg = <0x76000 0x4000>;
> > + interrupts = <47>;
> > + shared_smi = <&smi0>;
> > + tx_csum_limit = <1600>;
> > + status = "disabled";
> > +};
> > +
> > +
> > +
> > +marvell,mv643xx-eth:
> > +
> > +Required properties:
> > + - interrupts : the port interrupt number.
> > + - mdio : phandle of the smi device as drescribed above
> > +
> > +Optional properties:
> > + - port_number : the port number on this bus.
> > + - phy_addr : the PHY address.
> > + - reg : should match the mdio reg this device is attached to.
> > + this is a required hack for now due to the way the
> > + driver is constructed. This allows the device clock to be
> > + kept running so that the MAC is not lost after boot.
>
> More s/_/-/ candidates.
ok.
> Is there any reason to have "phy_addr" rather than "phy_address"? We already
> have #address-cells, which would seem to have set a precedent for naming.
Well, we also have "reg", which would seem to indicate the opposite. And,
following your logic, we should really say "physical_address" :-P . I
personally feel "phy_addr" is well understood, but I don't have a strong
opinion on it.
>
> [...]
>
> > @@ -2610,6 +2613,26 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
> > if (msp->base == NULL)
> > goto out_free;
> >
> > + if (pdev->dev.of_node) {
> > + struct device_node *np = NULL;
> > +
> > + /* when all users of this driver use FDT, we can remove this */
> > + pd = kzalloc(sizeof(*pd), GFP_KERNEL);
> > + if (!pd) {
> > + dev_dbg(&pdev->dev, "Could not allocate platform data\n");
> > + goto out_free;
> > + }
> > +
> > + of_property_read_u32(pdev->dev.of_node,
> > + "tx_csum_limit", &pd->tx_csum_limit);
>
> Is there any upper limit on what this property could be? It would be nice to
> have a sanity check.
>
> Also, of_property_read_u32 reads a u32, but pd->tx_csum_limit is an int. It
> would be good to use a u32 temporary.
Good catch, I'll update for both.
>
> [...]
>
> > @@ -2858,7 +2893,36 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
> > struct resource *res;
> > int err;
> >
> > - pd = pdev->dev.platform_data;
> > + if (pdev->dev.of_node) {
> > + struct device_node *np = NULL;
> > +
> > + /* when all users of this driver use FDT, we can remove this */
> > + pd = kzalloc(sizeof(*pd), GFP_KERNEL);
> > + if (!pd) {
> > + dev_dbg(&pdev->dev, "Could not allocate platform data\n");
> > + return -ENOMEM;
> > + }
> > +
> > + of_property_read_u32(pdev->dev.of_node,
> > + "port_number", &pd->port_number);
> > +
> > + if (!of_property_read_u32(pdev->dev.of_node,
> > + "phy_addr", &pd->phy_addr))
> > + pd->phy_addr = MV643XX_ETH_PHY_ADDR(pd->phy_addr);
>
> From a cursory glance at mv643xx_eth.c, it looks like phy_addr needs to be in
> the range 0 to 0x1f. It might be worth a sanity check here (even if it just
> prints a warning).
right, this had been commented elsewhere. phy_addr is XORd with 0x80,
so I'll correct my subsequent patch adding the DT entries and add the
warning here.
Thanks for the review,
Jason.
^ permalink raw reply
* [RFC] socfpga: make function static
From: Pavel Machek @ 2013-01-28 19:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359075633-13502-6-git-send-email-dinguyen@altera.com>
Hi!
While moving cpu1 start address into device tree, I noticed that
sysmgr_init can be static. Trivial patch is below.
Signed-off-by: Pavel Machek <pavel@denx.de>
commit 11030de41d7da7a14ca0c77abb726d6eec3a2fb7
diff --git a/arch/arm/mach-socfpga/core.h b/arch/arm/mach-socfpga/core.h
index 323c74a..3ebd469 100644
--- a/arch/arm/mach-socfpga/core.h
+++ b/arch/arm/mach-socfpga/core.h
@@ -26,7 +26,6 @@ extern void v7_secondary_startup(void);
extern void __iomem *socfpga_scu_base_addr;
extern void socfpga_init_clocks(void);
-extern void socfpga_sysmgr_init(void);
extern struct smp_operations socfpga_smp_ops;
extern char secondary_trampoline, secondary_trampoline_end;
diff --git a/arch/arm/mach-socfpga/socfpga.c b/arch/arm/mach-socfpga/socfpga.c
index bb17810..334c330 100644
--- a/arch/arm/mach-socfpga/socfpga.c
+++ b/arch/arm/mach-socfpga/socfpga.c
@@ -68,7 +68,7 @@ const static struct of_device_id irq_match[] = {
{}
};
-void __init socfpga_sysmgr_init(void)
+static void __init socfpga_sysmgr_init(void)
{
struct device_node *np;
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply related
* [PATCH v2 08/27] pci: implement an emulated PCI-to-PCI bridge
From: Jason Gunthorpe @ 2013-01-28 19:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359399397-29729-9-git-send-email-thomas.petazzoni@free-electrons.com>
On Mon, Jan 28, 2013 at 07:56:17PM +0100, Thomas Petazzoni wrote:
> +int pci_sw_pci_bridge_read(struct pci_sw_pci_bridge *bridge,
> + unsigned int where, int size, u32 *value)
> +{
> + switch (where & ~3) {
It is not essential, but desirable, to report an Express Root Port
capability for PCI-E bridges:
Capabilities: [40] Express (v2) Root Port (Slot+), MSI 00
DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s <64ns, L1 <1us
ExtTag- RBE+ FLReset-
DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
MaxPayload 128 bytes, MaxReadReq 128 bytes
DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
LnkCap: Port #1, Speed 5GT/s, Width x4, ASPM L0s L1, Latency L0 <1us, L1 <4us
ClockPM- Surprise- LLActRep+ BwNot-
LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- Retrain- CommClk-
ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
LnkSta: Speed 2.5GT/s, Width x0, TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
SltCap: AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug- Surprise-
Slot #0, PowerLimit 25.000W; Interlock- NoCompl+
SltCtl: Enable: AttnBtn- PwrFlt- MRL- PresDet- CmdCplt- HPIrq- LinkChg-
Control: AttnInd Unknown, PwrInd Unknown, Power- Interlock-
SltSta: Status: AttnBtn- PowerFlt- MRL- CmdCplt- PresDet- Interlock-
Changed: MRL- PresDet- LinkState-
RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal- PMEIntEna+ CRSVisible-
RootCap: CRSVisible-
RootSta: PME ReqID 0000, PMEStatus- PMEPending-
DevCap2: Completion Timeout: Range BC, TimeoutDis+ ARIFwd-
DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis- ARIFwd-
LnkCtl2: Target Link Speed: 2.5GT/s, EnterCompliance- SpeedDis-, Selectable De-emphasis: -6dB
Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
Compliance De-emphasis: -6dB
LnkSta2: Current De-emphasis Level: -3.5dB
In the Marvell case, this capability can be constructed by pulling
data from the the Express End Point capability of the PCI-E port:
Capabilities: [60] Express (v2) Endpoint, MSI 00
DevCap: MaxPayload 256 bytes, PhantFunc 0, Latency L0s <64ns, L1 unlimited
ExtTag- AttnBtn- AttnInd- PwrInd- RBE+ FLReset-
DevCtl: Report errors: Correctable- Non-Fatal+ Fatal+ Unsupported-
RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
MaxPayload 128 bytes, MaxReadReq 512 bytes
DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr- TransPend-
LnkCap: Port #8, Speed 2.5GT/s, Width x8, ASPM L0s, Latency L0 unlimited, L1 unlimited
ClockPM- Surprise- LLActRep- BwNot-
LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- Retrain- CommClk-
ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
LnkSta: Speed 2.5GT/s, Width x8, TrErr- Train- SlotClk- DLActive- BWMgmt- ABWMgmt-
DevCap2: Completion Timeout: Range ABCD, TimeoutDis+
DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-
LnkCtl2: Target Link Speed: 2.5GT/s, EnterCompliance- SpeedDis-, Selectable De-emphasis: -6dB
Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
Compliance De-emphasis: -6dB
LnkSta2: Current De-emphasis Level: -6dB
This lets user space see the width/speed/etc state of the PCI-E link
itself...
Jason
^ permalink raw reply
* [PATCH v5 07/14] dmaengine: add dma_request_slave_channel_compat()
From: Andy Shevchenko @ 2013-01-28 19:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358281974-8411-8-git-send-email-mporter@ti.com>
On Tue, Jan 15, 2013 at 10:32 PM, Matt Porter <mporter@ti.com> wrote:
> Adds a dma_request_slave_channel_compat() wrapper which accepts
> both the arguments from dma_request_channel() and
> dma_request_slave_channel(). Based on whether the driver is
> instantiated via DT, the appropriate channel request call will be
> made.
>
> This allows for a much cleaner migration of drivers to the
> dmaengine DT API as platforms continue to be mixed between those
> that boot using DT and those that do not.
Does it mean the introduced function is kinda temporary?
>
> Suggested-by: Tony Lindgren <tony@atomide.com>
> Signed-off-by: Matt Porter <mporter@ti.com>
> Acked-by: Tony Lindgren <tony@atomide.com>
> ---
> include/linux/dmaengine.h | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> index 9fd0c5b..64f9f69 100644
> --- a/include/linux/dmaengine.h
> +++ b/include/linux/dmaengine.h
> @@ -1047,6 +1047,16 @@ void dma_run_dependencies(struct dma_async_tx_descriptor *tx);
> struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type);
> struct dma_chan *net_dma_find_channel(void);
> #define dma_request_channel(mask, x, y) __dma_request_channel(&(mask), x, y)
> +static inline struct dma_chan
> +*dma_request_slave_channel_compat(dma_cap_mask_t mask, dma_filter_fn fn,
> + void *fn_param, struct device *dev,
> + char *name)
> +{
> + if (dev->of_node)
> + return dma_request_slave_channel(dev, name);
> + else
> + return dma_request_channel(mask, fn, fn_param);
> +}
>
> /* --- Helper iov-locking functions --- */
>
> --
> 1.7.9.5
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* [PATCHv1 for soc 5/5] arm: socfpga: Add SMP support for actual socfpga harware
From: Pavel Machek @ 2013-01-28 19:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359075633-13502-6-git-send-email-dinguyen@altera.com>
Hi!
I believe cpu1start_addr should go to the device tree, so that this
code is not neccessary. Proposed patch is below...
Thanks,
Pavel
> +static void __init init_socfpga_vt(void)
> +{
> + cpu1start_addr = 0xffd08010;
> +}
> +
> +static void __init init_socfpga(void)
> +{
> + cpu1start_addr = 0xffd080c4;
> +}
> +
...
> +
> + if (of_machine_is_compatible("altr,socfpga-vt"))
> + init_socfpga_vt();
> + else
> + init_socfpga();
commit b0d651bb4deeb0d8d08969a47b77d3317cbbc0a2
Author: Pavel <pavel@ucw.cz>
Date: Mon Jan 28 20:28:06 2013 +0100
Fix whitespace in socfpga.dtsi.
Move cpu1-start-addr variable to device tree, so that config code is
not neccessary in kernel.
Signed-off-by: Pavel Machek <pavel@denx.de>
diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi
index 688729f..35d4bdc 100644
--- a/arch/arm/boot/dts/socfpga.dtsi
+++ b/arch/arm/boot/dts/socfpga.dtsi
@@ -180,13 +180,13 @@
};
rstmgr at ffd05000 {
- compatible = "altr,rst-mgr";
- reg = <0xffd05000 0x1000>;
- };
+ compatible = "altr,rst-mgr";
+ reg = <0xffd05000 0x1000>;
+ };
sysmgr at ffd08000 {
- compatible = "altr,sys-mgr";
- reg = <0xffd08000 0x4000>;
- };
+ compatible = "altr,sys-mgr";
+ reg = <0xffd08000 0x4000>;
+ };
};
};
diff --git a/arch/arm/boot/dts/socfpga_cyclone5.dts b/arch/arm/boot/dts/socfpga_cyclone5.dts
index 1a6d088..e922475 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5.dts
+++ b/arch/arm/boot/dts/socfpga_cyclone5.dts
@@ -56,5 +56,9 @@
serial1 at ffc03000 {
clock-frequency = <100000000>;
};
+
+ sysmgr at ffd08000 {
+ cpu1-start-addr = <0xffd08010>;
+ };
};
};
diff --git a/arch/arm/boot/dts/socfpga_vt.dts b/arch/arm/boot/dts/socfpga_vt.dts
index df3551f..407ba14 100644
--- a/arch/arm/boot/dts/socfpga_vt.dts
+++ b/arch/arm/boot/dts/socfpga_vt.dts
@@ -56,5 +56,9 @@
serial1 at ffc03000 {
clock-frequency = <7372800>;
};
+
+ sysmgr at ffd08000 {
+ cpu1-start-addr = <0xffd08010>;
+ };
};
};
diff --git a/arch/arm/mach-socfpga/socfpga.c b/arch/arm/mach-socfpga/socfpga.c
index 2d1e8db..bb17810 100644
--- a/arch/arm/mach-socfpga/socfpga.c
+++ b/arch/arm/mach-socfpga/socfpga.c
@@ -56,16 +56,6 @@ static void __init socfpga_scu_map_io(void)
iotable_init(&scu_io_desc, 1);
}
-static void __init init_socfpga_vt(void)
-{
- cpu1start_addr = 0xffd08010;
-}
-
-static void __init init_socfpga(void)
-{
- cpu1start_addr = 0xffd080c4;
-}
-
static void __init socfpga_map_io(void)
{
socfpga_scu_map_io();
@@ -83,6 +73,11 @@ void __init socfpga_sysmgr_init(void)
struct device_node *np;
np = of_find_compatible_node(NULL, NULL, "altr,sys-mgr");
+
+ if (of_property_read_u32(np, "cpu1-start-addr", (u32 *) &cpu1start_addr)) {
+ early_printk("Need cpu1-start-addr in device tree.\n");
+ panic("Need cpu1-start-addr in device tree.\n");
+ }
sys_manager_base_addr = of_iomap(np, 0);
np = of_find_compatible_node(NULL, NULL, "altr,rst-mgr");
@@ -93,11 +88,6 @@ static void __init gic_init_irq(void)
{
of_irq_init(irq_match);
socfpga_sysmgr_init();
-
- if (of_machine_is_compatible("altr,socfpga-vt"))
- init_socfpga_vt();
- else
- init_socfpga();
}
static void socfpga_cyclone5_restart(char mode, const char *cmd)
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply related
* [PATCH v5 03/14] ARM: edma: add AM33XX support to the private EDMA API
From: Andy Shevchenko @ 2013-01-28 19:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358281974-8411-4-git-send-email-mporter@ti.com>
On Tue, Jan 15, 2013 at 10:32 PM, Matt Porter <mporter@ti.com> wrote:
> Adds support for parsing the TI EDMA DT data into the required
> EDMA private API platform data. Enables runtime PM support to
> initialize the EDMA hwmod. Adds AM33XX EMDA crossbar event mux
> support.
>
> Signed-off-by: Matt Porter <mporter@ti.com>
> ---
> arch/arm/common/edma.c | 314 ++++++++++++++++++++++++++++++++++--
> include/linux/platform_data/edma.h | 1 +
> 2 files changed, 306 insertions(+), 9 deletions(-)
>
> diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c
> index 2dce245..beeb1d2 100644
> --- a/arch/arm/common/edma.c
> +++ b/arch/arm/common/edma.c
> @@ -24,6 +24,13 @@
> #include <linux/platform_device.h>
> #include <linux/io.h>
> #include <linux/slab.h>
> +#include <linux/edma.h>
> +#include <linux/err.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/of_dma.h>
> +#include <linux/of_irq.h>
> +#include <linux/pm_runtime.h>
>
> #include <linux/platform_data/edma.h>
>
> @@ -723,6 +730,9 @@ EXPORT_SYMBOL(edma_free_channel);
> */
> int edma_alloc_slot(unsigned ctlr, int slot)
> {
> + if (!edma_cc[ctlr])
> + return -EINVAL;
> +
> if (slot >= 0)
> slot = EDMA_CHAN_SLOT(slot);
>
> @@ -1366,31 +1376,291 @@ void edma_clear_event(unsigned channel)
> EXPORT_SYMBOL(edma_clear_event);
>
> /*-----------------------------------------------------------------------*/
> +static int edma_of_read_u32_to_s8_array(const struct device_node *np,
> + const char *propname, s8 *out_values,
> + size_t sz)
I'm sorry I didn't get why you couldn't use of_property_read_u8_array() ?
The similar comment to u16 and so on.
> +{
> + struct property *prop = of_find_property(np, propname, NULL);
> + const __be32 *val;
> +
> + if (!prop)
> + return -EINVAL;
> + if (!prop->value)
> + return -ENODATA;
> + if ((sz * sizeof(u32)) > prop->length)
> + return -EOVERFLOW;
> +
> + val = prop->value;
> +
> + while (sz--)
> + *out_values++ = (s8)(be32_to_cpup(val++) & 0xff);
> +
> + /* Terminate it */
> + *out_values++ = -1;
> + *out_values++ = -1;
> +
> + return 0;
> +}
> +
> +static int edma_of_read_u32_to_s16_array(const struct device_node *np,
> + const char *propname, s16 *out_values,
> + size_t sz)
> +{
> + struct property *prop = of_find_property(np, propname, NULL);
> + const __be32 *val;
> +
> + if (!prop)
> + return -EINVAL;
> + if (!prop->value)
> + return -ENODATA;
> + if ((sz * sizeof(u32)) > prop->length)
> + return -EOVERFLOW;
> +
> + val = prop->value;
> +
> + while (sz--)
> + *out_values++ = (s16)(be32_to_cpup(val++) & 0xffff);
> +
> + /* Terminate it */
> + *out_values++ = -1;
> + *out_values++ = -1;
> +
> + return 0;
> +}
> +
> +static int edma_xbar_event_map(struct device *dev,
> + struct device_node *node,
> + struct edma_soc_info *pdata, int len)
> +{
> + int ret = 0;
> + int i;
> + struct resource res;
> + void *xbar;
> + const s16 (*xbar_chans)[2];
> + u32 shift, offset, mux;
> +
> + xbar_chans = devm_kzalloc(dev,
> + len/sizeof(s16) + 2*sizeof(s16),
> + GFP_KERNEL);
> + if (!xbar_chans)
> + return -ENOMEM;
> +
> + ret = of_address_to_resource(node, 1, &res);
> + if (IS_ERR_VALUE(ret))
> + return -EIO;
> +
> + xbar = devm_ioremap(dev, res.start, resource_size(&res));
> + if (!xbar)
> + return -ENOMEM;
> +
> + ret = edma_of_read_u32_to_s16_array(node,
> + "ti,edma-xbar-event-map",
> + (s16 *)xbar_chans,
> + len/sizeof(u32));
> + if (IS_ERR_VALUE(ret))
> + return -EIO;
> +
> + for (i = 0; xbar_chans[i][0] != -1; i++) {
> + shift = (xbar_chans[i][1] % 4) * 8;
> + offset = xbar_chans[i][1] >> 2;
> + offset <<= 2;
> + mux = readl((void *)((u32)xbar + offset));
> + mux &= ~(0xff << shift);
> + mux |= xbar_chans[i][0] << shift;
> + writel(mux, (void *)((u32)xbar + offset));
> + }
> +
> + pdata->xbar_chans = xbar_chans;
> +
> + return 0;
> +}
> +
> +static int edma_of_parse_dt(struct device *dev,
> + struct device_node *node,
> + struct edma_soc_info *pdata)
> +{
> + int ret = 0;
> + u32 value;
> + struct property *prop;
> + size_t sz;
> + struct edma_rsv_info *rsv_info;
> + const s16 (*rsv_chans)[2], (*rsv_slots)[2];
> + const s8 (*queue_tc_map)[2], (*queue_priority_map)[2];
> +
> + memset(pdata, 0, sizeof(struct edma_soc_info));
> +
> + ret = of_property_read_u32(node, "dma-channels", &value);
> + if (ret < 0)
> + return ret;
> + pdata->n_channel = value;
> +
> + ret = of_property_read_u32(node, "ti,edma-regions", &value);
> + if (ret < 0)
> + return ret;
> + pdata->n_region = value;
> +
> + ret = of_property_read_u32(node, "ti,edma-slots", &value);
> + if (ret < 0)
> + return ret;
> + pdata->n_slot = value;
> +
> + pdata->n_cc = 1;
> + pdata->n_tc = 3;
> +
> + rsv_info =
> + devm_kzalloc(dev, sizeof(struct edma_rsv_info), GFP_KERNEL);
> + if (!rsv_info)
> + return -ENOMEM;
> + pdata->rsv = rsv_info;
> +
> + /* Build the reserved channel/slots arrays */
> + prop = of_find_property(node, "ti,edma-reserved-channels", &sz);
> + if (prop) {
> + rsv_chans = devm_kzalloc(dev,
> + sz/sizeof(s16) + 2*sizeof(s16),
> + GFP_KERNEL);
> + if (!rsv_chans)
> + return -ENOMEM;
> + pdata->rsv->rsv_chans = rsv_chans;
> +
> + ret = edma_of_read_u32_to_s16_array(node,
> + "ti,edma-reserved-channels",
> + (s16 *)rsv_chans,
> + sz/sizeof(u32));
> + if (ret < 0)
> + return ret;
> + }
> +
> + prop = of_find_property(node, "ti,edma-reserved-slots", &sz);
> + if (prop) {
> + rsv_slots = devm_kzalloc(dev,
> + sz/sizeof(s16) + 2*sizeof(s16),
> + GFP_KERNEL);
> + if (!rsv_slots)
> + return -ENOMEM;
> + pdata->rsv->rsv_slots = rsv_slots;
> +
> + ret = edma_of_read_u32_to_s16_array(node,
> + "ti,edma-reserved-slots",
> + (s16 *)rsv_slots,
> + sz/sizeof(u32));
> + if (ret < 0)
> + return ret;
> + }
> +
> + prop = of_find_property(node, "ti,edma-queue-tc-map", &sz);
> + if (!prop)
> + return -EINVAL;
> +
> + queue_tc_map = devm_kzalloc(dev,
> + sz/sizeof(s8) + 2*sizeof(s8),
> + GFP_KERNEL);
> + if (!queue_tc_map)
> + return -ENOMEM;
> + pdata->queue_tc_mapping = queue_tc_map;
> +
> + ret = edma_of_read_u32_to_s8_array(node,
> + "ti,edma-queue-tc-map",
> + (s8 *)queue_tc_map,
> + sz/sizeof(u32));
> + if (ret < 0)
> + return ret;
> +
> + prop = of_find_property(node, "ti,edma-queue-priority-map", &sz);
> + if (!prop)
> + return -EINVAL;
> +
> + queue_priority_map = devm_kzalloc(dev,
> + sz/sizeof(s8) + 2*sizeof(s8),
> + GFP_KERNEL);
> + if (!queue_priority_map)
> + return -ENOMEM;
> + pdata->queue_priority_mapping = queue_priority_map;
> +
> + ret = edma_of_read_u32_to_s8_array(node,
> + "ti,edma-queue-tc-map",
> + (s8 *)queue_priority_map,
> + sz/sizeof(u32));
> + if (ret < 0)
> + return ret;
> +
> + ret = of_property_read_u32(node, "ti,edma-default-queue", &value);
> + if (ret < 0)
> + return ret;
> + pdata->default_queue = value;
> +
> + prop = of_find_property(node, "ti,edma-xbar-event-map", &sz);
> + if (prop)
> + ret = edma_xbar_event_map(dev, node, pdata, sz);
> +
> + return ret;
> +}
> +
> +static struct of_dma_filter_info edma_filter_info = {
> + .filter_fn = edma_filter_fn,
> +};
>
> static int edma_probe(struct platform_device *pdev)
> {
> struct edma_soc_info **info = pdev->dev.platform_data;
> + struct edma_soc_info *ninfo[EDMA_MAX_CC] = {NULL, NULL};
> + struct edma_soc_info tmpinfo;
> const s8 (*queue_priority_mapping)[2];
> const s8 (*queue_tc_mapping)[2];
> int i, j, off, ln, found = 0;
> int status = -1;
> const s16 (*rsv_chans)[2];
> const s16 (*rsv_slots)[2];
> + const s16 (*xbar_chans)[2];
> int irq[EDMA_MAX_CC] = {0, 0};
> int err_irq[EDMA_MAX_CC] = {0, 0};
> - struct resource *r[EDMA_MAX_CC] = {NULL};
> + struct resource *r[EDMA_MAX_CC] = {NULL, NULL};
> + struct resource res[EDMA_MAX_CC];
> resource_size_t len[EDMA_MAX_CC];
> char res_name[10];
> char irq_name[10];
> + struct device_node *node = pdev->dev.of_node;
> + struct device *dev = &pdev->dev;
> + int ret;
> +
> + if (node) {
> + info = ninfo;
> + edma_of_parse_dt(dev, node, &tmpinfo);
> + info[0] = &tmpinfo;
> +
> + dma_cap_set(DMA_SLAVE, edma_filter_info.dma_cap);
> + of_dma_controller_register(dev->of_node,
> + of_dma_simple_xlate,
> + &edma_filter_info);
> + }
>
> if (!info)
> return -ENODEV;
>
> + pm_runtime_enable(dev);
> + ret = pm_runtime_get_sync(dev);
> + if (IS_ERR_VALUE(ret)) {
> + dev_err(dev, "pm_runtime_get_sync() failed\n");
> + return ret;
> + }
> +
> for (j = 0; j < EDMA_MAX_CC; j++) {
> - sprintf(res_name, "edma_cc%d", j);
> - r[j] = platform_get_resource_byname(pdev, IORESOURCE_MEM,
> + if (!info[j]) {
> + if (!found)
> + return -ENODEV;
> + break;
> + }
> + if (node) {
> + ret = of_address_to_resource(node, j, &res[j]);
> + if (!IS_ERR_VALUE(ret))
> + r[j] = &res[j];
> + } else {
> + sprintf(res_name, "edma_cc%d", j);
> + r[j] = platform_get_resource_byname(pdev,
> + IORESOURCE_MEM,
> res_name);
> - if (!r[j] || !info[j]) {
> + }
> + if (!r[j]) {
> if (found)
> break;
> else
> @@ -1465,8 +1735,22 @@ static int edma_probe(struct platform_device *pdev)
> }
> }
>
> - sprintf(irq_name, "edma%d", j);
> - irq[j] = platform_get_irq_byname(pdev, irq_name);
> + /* Clear the xbar mapped channels in unused list */
> + xbar_chans = info[j]->xbar_chans;
> + if (xbar_chans) {
> + for (i = 0; xbar_chans[i][1] != -1; i++) {
> + off = xbar_chans[i][1];
> + clear_bits(off, 1,
> + edma_cc[j]->edma_unused);
> + }
> + }
> +
> + if (node)
> + irq[j] = irq_of_parse_and_map(node, 0);
> + else {
> + sprintf(irq_name, "edma%d", j);
> + irq[j] = platform_get_irq_byname(pdev, irq_name);
> + }
> edma_cc[j]->irq_res_start = irq[j];
> status = request_irq(irq[j], dma_irq_handler, 0, "edma",
> &pdev->dev);
> @@ -1476,8 +1760,12 @@ static int edma_probe(struct platform_device *pdev)
> goto fail;
> }
>
> - sprintf(irq_name, "edma%d_err", j);
> - err_irq[j] = platform_get_irq_byname(pdev, irq_name);
> + if (node)
> + err_irq[j] = irq_of_parse_and_map(node, 2);
> + else {
> + sprintf(irq_name, "edma%d_err", j);
> + err_irq[j] = platform_get_irq_byname(pdev, irq_name);
> + }
> edma_cc[j]->irq_res_end = err_irq[j];
> status = request_irq(err_irq[j], dma_ccerr_handler, 0,
> "edma_error", &pdev->dev);
> @@ -1538,9 +1826,17 @@ fail1:
> return status;
> }
>
> +static const struct of_device_id edma_of_ids[] = {
> + { .compatible = "ti,edma3", },
> + {}
> +};
>
> static struct platform_driver edma_driver = {
> - .driver.name = "edma",
> + .driver = {
> + .name = "edma",
> + .of_match_table = edma_of_ids,
> + },
> + .probe = edma_probe,
> };
>
> static int __init edma_init(void)
> diff --git a/include/linux/platform_data/edma.h b/include/linux/platform_data/edma.h
> index 2344ea2..ffc1fb2 100644
> --- a/include/linux/platform_data/edma.h
> +++ b/include/linux/platform_data/edma.h
> @@ -177,6 +177,7 @@ struct edma_soc_info {
>
> const s8 (*queue_tc_mapping)[2];
> const s8 (*queue_priority_mapping)[2];
> + const s16 (*xbar_chans)[2];
> };
>
> #endif
> --
> 1.7.9.5
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* [RFC V2 PATCH 0/8] ARM: kirkwood: cleanup DT conversion
From: Ezequiel Garcia @ 2013-01-28 19:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20130128200332.2770093e@skate>
On Mon, Jan 28, 2013 at 4:03 PM, Thomas Petazzoni
<thomas.petazzoni@free-electrons.com> wrote:
> Dear Ezequiel Garcia,
>
> On Mon, 28 Jan 2013 15:41:12 -0300, Ezequiel Garcia wrote:
>
>> Note that in Jason's proposal, it's possible to instantiate a bus'
>> child device, configure its address window and then call the
>> corresponding driver using a regular of_node.
>>
>> For instance,
>>
>> // MBUS Decoder window for NAND
>> nand at f4000000 {
>> #address-cells = <1>;
>> #size-cells = <1>;
>> compatible = "simple-bus", "marvell,orion-mbus";
>> mbus-target = <0x01 0x2f>;
>> ranges = <0 0xf4000000 0x10000>;
>>
>> nand at 0 {
>> // ...
>> compatible = "marvell,orion-nand";
>> reg = <0x0 0x400>;
>> };
>> };
>>
>> In this example, we can configure the window using both mbus-target
>> and ranges properties and then use the child node to instantiate an
>> "orion-nand" device.
>>
>> I understand your point regarding PCIe flexibility needs.
>> So I wonder, in your proposed scheme,
>> who should call this "address decoding window" driver
>> in order to still be able to instantiate child devices easily?
>
> I am not sure to exactly understand what you mean here. You would have
> a DT node for the NAND, and another one for the NOR. Each of them use a
> different compatible string (such as the "marvell,orion-nand" you've
> mentioned). Those correspond to platform_drivers, like all other
> devices described in the DT, nothing different. In their ->probe()
> function, those driver call some mvebu_setup_addr_decoding_window()
> function, which is part of an API provided by the address mapping
> driver.
>
Well, I guess we can call this mvebu_setup_addr_decoding_window()
from orion-nand driver, being orion specific.
I assume we will have to add something like the mbus-target property
to the orion-nand DT node, right?
(This describes the hardware, since it basically describes how the
flash is wired;
so I believe we must put that into the DT).
On the other side, I still don't understand how we will call something like this
for the NOR driver, which could probably be cfi-flash.
> The address at which we configure the various address decoding windows
> is an operating system specific decision, it is not a description of
> the hardware. Therefore, it shouldn't be encoded in the DT, because the
> DT describes the hardware, not the Linux-specific decisions on how the
> hardware should be used.
>
Good point. I haven't thought it that way.
--
Ezequiel
^ permalink raw reply
* [RFC V2 PATCH 0/8] ARM: kirkwood: cleanup DT conversion
From: Jason Gunthorpe @ 2013-01-28 19:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20130128200332.2770093e@skate>
On Mon, Jan 28, 2013 at 08:03:32PM +0100, Thomas Petazzoni wrote:
> devices described in the DT, nothing different. In their ->probe()
> function, those driver call some mvebu_setup_addr_decoding_window()
> function, which is part of an API provided by the address mapping
> driver.
I think that would be a layering mess to update these possibly shared
drivers to conditionally call some mvebu specific function in some
case, with some SOC specific set of parameters.. The MBUS driver
should take care of that, just like the PCI framework takes care of
address allocation.
> The address at which we configure the various address decoding windows
> is an operating system specific decision, it is not a description of
> the hardware. Therefore, it shouldn't be encoded in the DT, because the
> DT describes the hardware, not the Linux-specific decisions on how the
> hardware should be used.
DT models PCI BARs/Bridge windows as well, which are functionally
identical to the MBUS decode windows. There *is* a piece of address
decoder hardware, and the DT binding for that kind of hardware is a
bus with ranges. So it is completely appropriate to model that in DT.
The OF convention for bridge buses is to put the boot loader assigned
address in the DT (under the assumption that the boot loader sets
things up properly) so it is reasonable to include those addresses in
DT as well..
If, someday, the MBUS driver wants to dynamically allocate every MBUS
region, then that is fine, it can ignore/override the addresses from
the DT, just like the PCI stuff does for BARs/etc, but for today
without dynamic assignment it makes alot of sense to just use the DT
values directly.
Jason
^ permalink raw reply
* [PATCH 00/15] OMAP SHAM & AES Crypto Updates
From: Mark A. Greer @ 2013-01-28 19:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20130117222728.GA32446@animalcreek.com>
On Thu, Jan 17, 2013 at 03:27:28PM -0700, Mark A. Greer wrote:
> On Thu, Jan 17, 2013 at 07:13:36PM +0000, Paul Walmsley wrote:
> > Hi Mark,
>
> Hi Paul.
Hi again, Paul. Sorry for the delay, I've been under the weather.
> > I regret the delay,
> >
> > On Tue, 8 Jan 2013, Mark A. Greer wrote:
> >
> > > On Sun, Dec 23, 2012 at 08:40:43AM +0000, Paul Walmsley wrote:
> > What do you think about adding an am35xx_es11plus_hwmod_ocp_ifs[] array to
> > omap_hwmod_3xxx_data.c for these secure hwmods? That carries the implicit
> > and possibly wrong assumption that it's likely to be ES1.0 devices that
> > are missing the SHAM/AES, but it seems unlikely that TI would have
> > multiple silicon revs running around claiming to be ES1.1? Or maybe I'm
> > just being na?ve.
>
> Something like that makes sense to me. I'll re-read my email, etc. and
> see if I can find something to help us figure it out.
I couldn't find any information that helped with this so AFAIK there is no
good way to tell if a particular am35xx has the crypto hardware available
or not. At this point, I vote for moving 'omap3xxx_l4_core__sham' and
'omap3xxx_l4_core__aes' from omap3xxx_gp_hwmod_ocp_ifs[] and putting them
in omap34xx_hwmod_ocp_ifs[] and omap36xx_hwmod_ocp_ifs[]. That should be
safe in general and if someone with an am35xx wants to use those modules,
they can edit am35xx_hwmod_ocp_ifs[] locally.
What do you think?
^ permalink raw reply
* [PATCH v5 31/45] blackfin/smp: Use get/put_online_cpus_atomic() to prevent CPU offline
From: Tejun Heo @ 2013-01-28 19:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAA_GA1fSLNKSDTGSzHoA+j-mur85BvoSRkARq+DMfORuwrrX4Q@mail.gmail.com>
Hello, Bob.
On Mon, Jan 28, 2013 at 1:09 AM, Bob Liu <lliubbo@gmail.com> wrote:
> Thanks, will be applied to my blackfin arch tree.
I think we still have some work ahead of us to have this patchset
ready for inclusion and even then it probably would be best to route
these patches together, so probably not a very good idea to apply this
to blackfin right now.
Thanks.
--
tejun
^ permalink raw reply
* [RFC V2 PATCH 0/8] ARM: kirkwood: cleanup DT conversion
From: Thomas Petazzoni @ 2013-01-28 19:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CALF0-+U5DVGAMZGw1nsBMe5cJ1=U1b19D+kunWtSYn3sUYiRDg@mail.gmail.com>
Dear Ezequiel Garcia,
On Mon, 28 Jan 2013 15:41:12 -0300, Ezequiel Garcia wrote:
> Note that in Jason's proposal, it's possible to instantiate a bus'
> child device, configure its address window and then call the
> corresponding driver using a regular of_node.
>
> For instance,
>
> // MBUS Decoder window for NAND
> nand at f4000000 {
> #address-cells = <1>;
> #size-cells = <1>;
> compatible = "simple-bus", "marvell,orion-mbus";
> mbus-target = <0x01 0x2f>;
> ranges = <0 0xf4000000 0x10000>;
>
> nand at 0 {
> // ...
> compatible = "marvell,orion-nand";
> reg = <0x0 0x400>;
> };
> };
>
> In this example, we can configure the window using both mbus-target
> and ranges properties and then use the child node to instantiate an
> "orion-nand" device.
>
> I understand your point regarding PCIe flexibility needs.
> So I wonder, in your proposed scheme,
> who should call this "address decoding window" driver
> in order to still be able to instantiate child devices easily?
I am not sure to exactly understand what you mean here. You would have
a DT node for the NAND, and another one for the NOR. Each of them use a
different compatible string (such as the "marvell,orion-nand" you've
mentioned). Those correspond to platform_drivers, like all other
devices described in the DT, nothing different. In their ->probe()
function, those driver call some mvebu_setup_addr_decoding_window()
function, which is part of an API provided by the address mapping
driver.
The address at which we configure the various address decoding windows
is an operating system specific decision, it is not a description of
the hardware. Therefore, it shouldn't be encoded in the DT, because the
DT describes the hardware, not the Linux-specific decisions on how the
hardware should be used.
Of course, for things like the internal registers decoding windows, we
can't really make the DT unaware of that, because it is so fundamental
to even having the platform booting. But for all other windows, it is
an operating system decision, and not a hardware description.
Best regards,
Thomas
--
Thomas Petazzoni, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
^ permalink raw reply
* [PATCH] ARM: tegra114: cpuidle: add ARM_CPUIDLE_WFI_STATE support
From: Stephen Warren @ 2013-01-28 19:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358761746-13118-1-git-send-email-josephl@nvidia.com>
On 01/21/2013 02:49 AM, Joseph Lo wrote:
> Adding the generic ARM_CPUIDLE_WFI_STATE support for Tegra114.
I've applied this to Tegra's for-3.9/soc-t114 branch.
^ permalink raw reply
* [PATCH v2 27/27] arm: mvebu: update defconfig with PCI and USB support
From: Thomas Petazzoni @ 2013-01-28 18:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359399397-29729-1-git-send-email-thomas.petazzoni@free-electrons.com>
Now that we have the necessary drivers and Device Tree informations to
support PCIe on Armada 370 and Armada XP, enable the CONFIG_PCI
option.
Also, since the Armada 370 Mirabox has a built-in USB XHCI controller
connected on the PCIe bus, enable the corresponding options as well.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/configs/mvebu_defconfig | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/arch/arm/configs/mvebu_defconfig b/arch/arm/configs/mvebu_defconfig
index b5bc96c..68ef50b 100644
--- a/arch/arm/configs/mvebu_defconfig
+++ b/arch/arm/configs/mvebu_defconfig
@@ -13,6 +13,7 @@ CONFIG_MACH_ARMADA_370=y
CONFIG_MACH_ARMADA_XP=y
# CONFIG_CACHE_L2X0 is not set
# CONFIG_SWP_EMULATE is not set
+CONFIG_PCI=y
CONFIG_SMP=y
# CONFIG_LOCAL_TIMERS is not set
CONFIG_AEABI=y
@@ -36,7 +37,8 @@ CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_DW=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
-# CONFIG_USB_SUPPORT is not set
+CONFIG_USB=y
+CONFIG_USB_XHCI_HCD=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_S35390A=y
CONFIG_DMADEVICES=y
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 26/27] arm: mvebu: PCIe Device Tree informations for Armada 370 DB
From: Thomas Petazzoni @ 2013-01-28 18:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359399397-29729-1-git-send-email-thomas.petazzoni@free-electrons.com>
The Marvell evaluation board (DB) for the Armada 370 SoC has 2
physical full-size PCIe slots, so we enable the corresponding PCIe
interfaces in the Device Tree.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/boot/dts/armada-370-db.dts | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/arch/arm/boot/dts/armada-370-db.dts b/arch/arm/boot/dts/armada-370-db.dts
index 9b82fac..fba3e8e 100644
--- a/arch/arm/boot/dts/armada-370-db.dts
+++ b/arch/arm/boot/dts/armada-370-db.dts
@@ -59,5 +59,20 @@
phy = <&phy1>;
phy-mode = "rgmii-id";
};
+
+ pcie-controller {
+ status = "okay";
+ /*
+ * The two PCIe units are accessible through
+ * both standard PCIe slots and mini-PCIe
+ * slots on the board.
+ */
+ pcie at 0,0 {
+ status = "okay";
+ };
+ pcie at 1,0 {
+ status = "okay";
+ };
+ };
};
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 25/27] arm: mvebu: PCIe Device Tree informations for Armada 370 Mirabox
From: Thomas Petazzoni @ 2013-01-28 18:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359399397-29729-1-git-send-email-thomas.petazzoni@free-electrons.com>
The Globalscale Mirabox platform uses one PCIe interface for an
available mini-PCIe slot, and the other PCIe interface for an internal
USB 3.0 controller. We add the necessary Device Tree informations to
enable those two interfaces.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/boot/dts/armada-370-mirabox.dts | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/arch/arm/boot/dts/armada-370-mirabox.dts b/arch/arm/boot/dts/armada-370-mirabox.dts
index 3b40713..591068a 100644
--- a/arch/arm/boot/dts/armada-370-mirabox.dts
+++ b/arch/arm/boot/dts/armada-370-mirabox.dts
@@ -52,5 +52,19 @@
phy = <&phy1>;
phy-mode = "rgmii-id";
};
+
+ pcie-controller {
+ status = "okay";
+
+ /* Internal mini-PCIe connector */
+ pcie at 0,0 {
+ status = "okay";
+ };
+
+ /* Connected on the PCB to a USB 3.0 XHCI controller */
+ pcie at 1,0 {
+ status = "okay";
+ };
+ };
};
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 24/27] arm: mvebu: PCIe Device Tree informations for Armada XP DB
From: Thomas Petazzoni @ 2013-01-28 18:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359399397-29729-1-git-send-email-thomas.petazzoni@free-electrons.com>
The Marvell evaluation board (DB) for the Armada XP SoC has 6
physicals full-size PCIe slots, so we enable the corresponding PCIe
interfaces in the Device Tree.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/boot/dts/armada-xp-db.dts | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/arch/arm/boot/dts/armada-xp-db.dts b/arch/arm/boot/dts/armada-xp-db.dts
index 8e53b25..7dcc36c 100644
--- a/arch/arm/boot/dts/armada-xp-db.dts
+++ b/arch/arm/boot/dts/armada-xp-db.dts
@@ -90,5 +90,32 @@
phy = <&phy3>;
phy-mode = "sgmii";
};
+
+ pcie-controller {
+ status = "okay";
+
+ /*
+ * All 6 slots are physically present as
+ * standard PCIe slots on the board.
+ */
+ pcie at 0,0 {
+ status = "okay";
+ };
+ pcie at 0,1 {
+ status = "okay";
+ };
+ pcie at 0,2 {
+ status = "okay";
+ };
+ pcie at 0,3 {
+ status = "okay";
+ };
+ pcie at 2,0 {
+ status = "okay";
+ };
+ pcie at 3,0 {
+ status = "okay";
+ };
+ };
};
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 23/27] arm: mvebu: PCIe Device Tree informations for OpenBlocks AX3-4
From: Thomas Petazzoni @ 2013-01-28 18:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359399397-29729-1-git-send-email-thomas.petazzoni@free-electrons.com>
The PlatHome OpenBlocks AX3-4 has an internal mini-PCIe slot that can
be used to plug mini-PCIe devices. We therefore enable the PCIe
interface that corresponds to this slot.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
index b42652f..67fcaaa 100644
--- a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
+++ b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
@@ -121,5 +121,12 @@
nr-ports = <2>;
status = "okay";
};
+ pcie-controller {
+ status = "okay";
+ /* Internal mini-PCIe connector */
+ pcie at 0,0 {
+ status = "okay";
+ };
+ };
};
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 22/27] arm: mvebu: add PCIe Device Tree informations for Armada XP
From: Thomas Petazzoni @ 2013-01-28 18:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359399397-29729-1-git-send-email-thomas.petazzoni@free-electrons.com>
The Armada XP SoCs have multiple PCIe interfaces. The MV78230 has 2
PCIe units (one 4x or quad 1x, the other 1x only), the MV78260 has 3
PCIe units (two 4x or quad 1x and one 4x/1x), the MV78460 has 4 PCIe
units (two 4x or quad 1x and two 4x/1x). We therefore add the
necessary Device Tree informations to make those PCIe interfaces
usable.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/boot/dts/armada-xp-mv78230.dtsi | 92 ++++++++++++++++++
arch/arm/boot/dts/armada-xp-mv78260.dtsi | 105 +++++++++++++++++++++
arch/arm/boot/dts/armada-xp-mv78460.dtsi | 150 ++++++++++++++++++++++++++++++
3 files changed, 347 insertions(+)
diff --git a/arch/arm/boot/dts/armada-xp-mv78230.dtsi b/arch/arm/boot/dts/armada-xp-mv78230.dtsi
index e041f42..6abb0ff 100644
--- a/arch/arm/boot/dts/armada-xp-mv78230.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78230.dtsi
@@ -70,5 +70,97 @@
#interrupts-cells = <2>;
interrupts = <87>, <88>, <89>;
};
+
+ /*
+ * MV78230 has 2 PCIe units Gen2.0: One unit can be
+ * configured as x4 or quad x1 lanes. One unit is
+ * x4/x1.
+ */
+ pcie-controller {
+ compatible = "marvell,armada-370-xp-pcie";
+ status = "disabled";
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+
+ bus-range = <0x00 0xff>;
+
+ ranges = <0x00000800 0 0xd0040000 0xd0040000 0 0x00002000 /* port 0.0 registers */
+ 0x00004800 0 0xd0042000 0xd0042000 0 0x00002000 /* port 2.0 registers */
+ 0x00001000 0 0xd0044000 0xd0044000 0 0x00002000 /* port 0.1 registers */
+ 0x00001800 0 0xd0048000 0xd0048000 0 0x00002000 /* port 0.2 registers */
+ 0x00002000 0 0xd004C000 0xd004C000 0 0x00002000 /* port 0.3 registers */
+ 0x81000000 0 0 0xc0000000 0 0x00010000 /* downstream I/O */
+ 0x82000000 0 0 0xc1000000 0 0x08000000>; /* non-prefetchable memory */
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xf800 0 0 1>;
+ interrupt-map = <0x0800 0 0 1 &mpic 58 1
+ 0x1000 0 0 1 &mpic 59 1
+ 0x1800 0 0 1 &mpic 60 1
+ 0x2000 0 0 1 &mpic 61 1
+ 0x4800 0 0 1 &mpic 99 1>;
+
+ pcie at 0,0 {
+ device_type = "pciex";
+ reg = <0x0800 0 0xd0040000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <0>;
+ interrupts = <1>;
+ clocks = <&gateclk 5>;
+ status = "disabled";
+ };
+
+ pcie at 0,1 {
+ device_type = "pciex";
+ reg = <0x1000 0 0xd0044000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <1>;
+ interrupts = <1>;
+ clocks = <&gateclk 6>;
+ status = "disabled";
+ };
+
+ pcie at 0,2 {
+ device_type = "pciex";
+ reg = <0x1800 0 0xd0048000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <2>;
+ interrupts = <1>;
+ clocks = <&gateclk 7>;
+ status = "disabled";
+ };
+
+ pcie at 0,3 {
+ device_type = "pciex";
+ reg = <0x2000 0 0xd004C000 0 0xC000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <3>;
+ interrupts = <1>;
+ clocks = <&gateclk 8>;
+ status = "disabled";
+ };
+
+ pcie at 2,0 {
+ device_type = "pciex";
+ reg = <0x4800 0 0xd0042000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <2>;
+ marvell,pcie-lane = <0>;
+ interrupts = <1>;
+ clocks = <&gateclk 26>;
+ status = "disabled";
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/armada-xp-mv78260.dtsi b/arch/arm/boot/dts/armada-xp-mv78260.dtsi
index 9e23bd8..ab8c593 100644
--- a/arch/arm/boot/dts/armada-xp-mv78260.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78260.dtsi
@@ -90,5 +90,110 @@
clocks = <&gateclk 1>;
status = "disabled";
};
+
+ /*
+ * MV78260 has 3 PCIe units Gen2.0: Two units can be
+ * configured as x4 or quad x1 lanes. One unit is
+ * x4/x1.
+ */
+ pcie-controller {
+ compatible = "marvell,armada-370-xp-pcie";
+ status = "disabled";
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ bus-range = <0x00 0xff>;
+
+ ranges = <0x00000800 0 0xd0040000 0xd0040000 0 0x00002000 /* port 0.0 registers */
+ 0x00004800 0 0xd0042000 0xd0042000 0 0x00002000 /* port 2.0 registers */
+ 0x00001000 0 0xd0044000 0xd0044000 0 0x00002000 /* port 0.1 registers */
+ 0x00001800 0 0xd0048000 0xd0048000 0 0x00002000 /* port 0.2 registers */
+ 0x00002000 0 0xd004C000 0xd004C000 0 0x00002000 /* port 0.3 registers */
+ 0x00005000 0 0xd0082000 0xd0082000 0 0x00002000 /* port 3.0 registers */
+ 0x81000000 0 0 0xc0000000 0 0x00010000 /* downstream I/O */
+ 0x82000000 0 0 0xc1000000 0 0x08000000>; /* non-prefetchable memory */
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xf800 0 0 1>;
+ interrupt-map = <0x0800 0 0 1 &mpic 58 1
+ 0x1000 0 0 1 &mpic 59 1
+ 0x1800 0 0 1 &mpic 60 1
+ 0x2000 0 0 1 &mpic 61 1
+ 0x4800 0 0 1 &mpic 99 1
+ 0x5000 0 0 1 &mpic 103 1>;
+
+ pcie at 0,0 {
+ device_type = "pciex";
+ reg = <0x0800 0 0xd0040000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <0>;
+ interrupts = <1>;
+ clocks = <&gateclk 5>;
+ status = "disabled";
+ };
+
+ pcie at 0,1 {
+ device_type = "pciex";
+ reg = <0x1000 0 0xd0044000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <1>;
+ interrupts = <1>;
+ clocks = <&gateclk 6>;
+ status = "disabled";
+ };
+
+ pcie at 0,2 {
+ device_type = "pciex";
+ reg = <0x1800 0 0xd0048000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <2>;
+ interrupts = <1>;
+ clocks = <&gateclk 7>;
+ status = "disabled";
+ };
+
+ pcie at 0,3 {
+ device_type = "pciex";
+ reg = <0x2000 0 0xd004C000 0 0xC000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <3>;
+ interrupts = <1>;
+ clocks = <&gateclk 8>;
+ status = "disabled";
+ };
+
+ pcie at 2,0 {
+ device_type = "pciex";
+ reg = <0x4800 0 0xd0042000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <2>;
+ marvell,pcie-lane = <0>;
+ interrupts = <1>;
+ clocks = <&gateclk 26>;
+ status = "disabled";
+ };
+
+ pcie at 3,0 {
+ device_type = "pciex";
+ reg = <0x5000 0 0xd0082000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <3>;
+ marvell,pcie-lane = <0>;
+ interrupts = <1>;
+ clocks = <&gateclk 27>;
+ status = "disabled";
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/armada-xp-mv78460.dtsi b/arch/arm/boot/dts/armada-xp-mv78460.dtsi
index 9659661..00c69aa 100644
--- a/arch/arm/boot/dts/armada-xp-mv78460.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78460.dtsi
@@ -105,5 +105,155 @@
clocks = <&gateclk 1>;
status = "disabled";
};
+
+ /*
+ * MV78460 has 4 PCIe units Gen2.0: Two units can be
+ * configured as x4 or quad x1 lanes. Two units are
+ * x4/x1.
+ */
+ pcie-controller {
+ compatible = "marvell,armada-370-xp-pcie";
+ status = "disabled";
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ bus-range = <0x00 0xff>;
+
+ ranges = <0x00000800 0 0xd0040000 0xd0040000 0 0x00002000 /* port 0.0 registers */
+ 0x00004800 0 0xd0042000 0xd0042000 0 0x00002000 /* port 2.0 registers */
+ 0x00001000 0 0xd0044000 0xd0044000 0 0x00002000 /* port 0.1 registers */
+ 0x00001800 0 0xd0048000 0xd0048000 0 0x00002000 /* port 0.2 registers */
+ 0x00002000 0 0xd004C000 0xd004C000 0 0x00002000 /* port 0.3 registers */
+ 0x00002800 0 0xd0080000 0xd0080000 0 0x00002000 /* port 1.0 registers */
+ 0x00005000 0 0xd0082000 0xd0082000 0 0x00002000 /* port 3.0 registers */
+ 0x00003000 0 0xd0084000 0xd0084000 0 0x00002000 /* port 1.1 registers */
+ 0x00003800 0 0xd0088000 0xd0088000 0 0x00002000 /* port 1.2 registers */
+ 0x00004000 0 0xd008C000 0xd008C000 0 0x00002000 /* port 1.3 registers */
+ 0x81000000 0 0 0xc0000000 0 0x00100000 /* downstream I/O */
+ 0x82000000 0 0 0xc1000000 0 0x08000000>; /* non-prefetchable memory */
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xf800 0 0 1>;
+ interrupt-map = <0x0800 0 0 1 &mpic 58
+ 0x1000 0 0 1 &mpic 59
+ 0x1800 0 0 1 &mpic 60
+ 0x2000 0 0 1 &mpic 61
+ 0x2800 0 0 1 &mpic 62
+ 0x3000 0 0 1 &mpic 63
+ 0x3800 0 0 1 &mpic 64
+ 0x4000 0 0 1 &mpic 65
+ 0x4800 0 0 1 &mpic 99
+ 0x5000 0 0 1 &mpic 103>;
+
+ pcie at 0,0 {
+ device_type = "pciex";
+ reg = <0x0800 0 0xd0040000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 5>;
+ status = "disabled";
+ };
+
+ pcie at 0,1 {
+ device_type = "pciex";
+ reg = <0x1000 0 0xd0044000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <1>;
+ clocks = <&gateclk 6>;
+ status = "disabled";
+ };
+
+ pcie at 0,2 {
+ device_type = "pciex";
+ reg = <0x1800 0 0xd0048000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <2>;
+ clocks = <&gateclk 7>;
+ status = "disabled";
+ };
+
+ pcie at 0,3 {
+ device_type = "pciex";
+ reg = <0x2000 0 0xd004C000 0 0xC000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <3>;
+ clocks = <&gateclk 8>;
+ status = "disabled";
+ };
+
+ pcie at 1,0 {
+ device_type = "pciex";
+ reg = <0x2800 0 0xd0080000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 9>;
+ status = "disabled";
+ };
+
+ pcie at 1,1 {
+ device_type = "pciex";
+ reg = <0x3000 0 0xd0084000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <1>;
+ clocks = <&gateclk 10>;
+ status = "disabled";
+ };
+
+ pcie at 1,2 {
+ device_type = "pciex";
+ reg = <0x3800 0 0xd0088000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <2>;
+ clocks = <&gateclk 11>;
+ status = "disabled";
+ };
+
+ pcie at 1,3 {
+ device_type = "pciex";
+ reg = <0x4000 0 0xd008C000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <3>;
+ clocks = <&gateclk 12>;
+ status = "disabled";
+ };
+ pcie at 2,0 {
+ device_type = "pciex";
+ reg = <0x4800 0 0xd0042000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <2>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 26>;
+ status = "disabled";
+ };
+
+ pcie at 3,0 {
+ device_type = "pciex";
+ reg = <0x5000 0 0xd0082000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <3>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 27>;
+ status = "disabled";
+ };
+ };
};
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 21/27] arm: mvebu: add PCIe Device Tree informations for Armada 370
From: Thomas Petazzoni @ 2013-01-28 18:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359399397-29729-1-git-send-email-thomas.petazzoni@free-electrons.com>
The Armada 370 SoC has two 1x PCIe 2.0 interfaces, so we add the
necessary Device Tree informations to make these interfaces availabel.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/boot/dts/armada-370.dtsi | 42 +++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/arch/arm/boot/dts/armada-370.dtsi b/arch/arm/boot/dts/armada-370.dtsi
index 636cf7d..a66e371 100644
--- a/arch/arm/boot/dts/armada-370.dtsi
+++ b/arch/arm/boot/dts/armada-370.dtsi
@@ -132,5 +132,47 @@
dmacap,memset;
};
};
+
+ pcie-controller {
+ compatible = "marvell,armada-370-xp-pcie";
+ status = "disabled";
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ bus-range = <0x00 0xff>;
+
+ ranges = <0x00000800 0 0xd0040000 0xd0040000 0 0x00002000 /* port 0.0 registers */
+ 0x00001000 0 0xd0080000 0xd0080000 0 0x00002000 /* port 1.0 registers */
+ 0x81000000 0 0 0xc0000000 0 0x00010000 /* downstream I/O */
+ 0x82000000 0 0 0xc1000000 0 0x08000000>; /* non-prefetchable memory */
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xf800 0 0 1>;
+ interrupt-map = <0x0800 0 0 1 &mpic 58 /* port 0.0 */
+ 0x1000 0 0 1 &mpic 62>; /* port 1.0 */
+
+ pcie at 0,0 {
+ device_type = "pciex";
+ reg = <0x0800 0 0xd0040000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 5>;
+ status = "disabled";
+ };
+
+ pcie at 1,0 {
+ device_type = "pciex";
+ reg = <0x1000 0 0xd0080000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 9>;
+ status = "disabled";
+ };
+ };
};
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 20/27] arm: mvebu: PCIe support is now available on mvebu
From: Thomas Petazzoni @ 2013-01-28 18:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359399397-29729-1-git-send-email-thomas.petazzoni@free-electrons.com>
Now that the PCIe driver for mvebu has been integrated and all its
relevant dependencies, we can mark the ARCH_MVEBU platform has
MIGHT_HAVE_PCI, which allows to select the PCI bus support if needed.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/mach-mvebu/Kconfig | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
index 440b13e..f12e475 100644
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -13,6 +13,8 @@ config ARCH_MVEBU
select MVEBU_CLK_CORE
select MVEBU_CLK_CPU
select MVEBU_CLK_GATING
+ select MIGHT_HAVE_PCI
+ select PCI_QUIRKS if PCI
if ARCH_MVEBU
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 19/27] pci: PCIe driver for Marvell Armada 370/XP systems
From: Thomas Petazzoni @ 2013-01-28 18:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359399397-29729-1-git-send-email-thomas.petazzoni@free-electrons.com>
This driver implements the support for the PCIe interfaces on the
Marvell Armada 370/XP ARM SoCs. In the future, it might be extended to
cover earlier families of Marvell SoCs, such as Dove, Orion and
Kirkwood.
The driver implements the hw_pci operations needed by the core ARM PCI
code to setup PCI devices and get their corresponding IRQs, and the
pci_ops operations that are used by the PCI core to read/write the
configuration space of PCI devices.
Since the PCIe interfaces of Marvell SoCs are completely separate and
not linked together in a bus, this driver sets up an emulated PCI host
bridge, with one PCI-to-PCI bridge as child for each hardware PCIe
interface.
In addition, this driver enumerates the different PCIe slots, and for
those having a device plugged in, it sets up the necessary address
decoding windows, using the new armada_370_xp_alloc_pcie_window()
function from mach-mvebu/addr-map.c.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
.../devicetree/bindings/pci/armada-370-xp-pcie.txt | 175 +++++++
drivers/pci/host/Kconfig | 6 +
drivers/pci/host/Makefile | 4 +
drivers/pci/host/pci-mvebu.c | 500 ++++++++++++++++++++
4 files changed, 685 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/armada-370-xp-pcie.txt
create mode 100644 drivers/pci/host/Makefile
create mode 100644 drivers/pci/host/pci-mvebu.c
diff --git a/Documentation/devicetree/bindings/pci/armada-370-xp-pcie.txt b/Documentation/devicetree/bindings/pci/armada-370-xp-pcie.txt
new file mode 100644
index 0000000..9313e92
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/armada-370-xp-pcie.txt
@@ -0,0 +1,175 @@
+* Marvell Armada 370/XP PCIe interfaces
+
+Mandatory properties:
+- compatible: must be "marvell,armada-370-xp-pcie"
+- status: either "disabled" or "okay"
+- #address-cells, set to <3>
+- #size-cells, set to <2>
+- #interrupt-cells, set to <1>
+- bus-range: PCI bus numbers covered
+- ranges: standard PCI-style address ranges, describing the PCIe
+ registers for each PCIe interface, and then ranges for the PCI
+ memory and I/O regions.
+- interrupt-map-mask and interrupt-map are standard PCI Device Tree
+ properties to describe the interrupts associated to each PCI
+ interface.
+
+In addition, the Device Tree node must have sub-nodes describing each
+PCIe interface, having the following mandatory properties:
+- reg: the address and size of the PCIe registers (translated
+ addresses according to the ranges property of the parent)
+- clocks: the clock associated to this PCIe interface
+- marvell,pcie-port: the physical PCIe port number
+- status: either "disabled" or "okay"
+
+and the following optional properties:
+- marvell,pcie-lane: the physical PCIe lane number, for ports having
+ multiple lanes. If this property is not found, we assume that the
+ value is 0.
+
+Example:
+
+pcie-controller {
+ compatible = "marvell,armada-370-xp-pcie";
+ status = "disabled";
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ bus-range = <0x00 0xff>;
+
+ ranges = <0x00000800 0 0xd0040000 0xd0040000 0 0x00002000 /* port 0.0 registers */
+ 0x00004800 0 0xd0042000 0xd0042000 0 0x00002000 /* port 2.0 registers */
+ 0x00001000 0 0xd0044000 0xd0044000 0 0x00002000 /* port 0.1 registers */
+ 0x00001800 0 0xd0048000 0xd0048000 0 0x00002000 /* port 0.2 registers */
+ 0x00002000 0 0xd004C000 0xd004C000 0 0x00002000 /* port 0.3 registers */
+ 0x00002800 0 0xd0080000 0xd0080000 0 0x00002000 /* port 1.0 registers */
+ 0x00005000 0 0xd0082000 0xd0082000 0 0x00002000 /* port 3.0 registers */
+ 0x00003000 0 0xd0084000 0xd0084000 0 0x00002000 /* port 1.1 registers */
+ 0x00003800 0 0xd0088000 0xd0088000 0 0x00002000 /* port 1.2 registers */
+ 0x00004000 0 0xd008C000 0xd008C000 0 0x00002000 /* port 1.3 registers */
+ 0x81000000 0 0 0xc0000000 0 0x00100000 /* downstream I/O */
+ 0x82000000 0 0 0xc1000000 0 0x08000000>; /* non-prefetchable memory */
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xf800 0 0 1>;
+ interrupt-map = <0x0800 0 0 1 &mpic 58
+ 0x1000 0 0 1 &mpic 59
+ 0x1800 0 0 1 &mpic 60
+ 0x2000 0 0 1 &mpic 61
+ 0x2800 0 0 1 &mpic 62
+ 0x3000 0 0 1 &mpic 63
+ 0x3800 0 0 1 &mpic 64
+ 0x4000 0 0 1 &mpic 65
+ 0x4800 0 0 1 &mpic 99
+ 0x5000 0 0 1 &mpic 103>;
+
+ pcie at 0,0 {
+ device_type = "pciex";
+ reg = <0x0800 0 0xd0040000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 5>;
+ status = "disabled";
+ };
+
+ pcie at 0,1 {
+ device_type = "pciex";
+ reg = <0x1000 0 0xd0044000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <1>;
+ clocks = <&gateclk 6>;
+ status = "disabled";
+ };
+
+ pcie at 0,2 {
+ device_type = "pciex";
+ reg = <0x1800 0 0xd0048000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <2>;
+ clocks = <&gateclk 7>;
+ status = "disabled";
+ };
+
+ pcie at 0,3 {
+ device_type = "pciex";
+ reg = <0x2000 0 0xd004C000 0 0xC000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <0>;
+ marvell,pcie-lane = <3>;
+ clocks = <&gateclk 8>;
+ status = "disabled";
+ };
+
+ pcie at 1,0 {
+ device_type = "pciex";
+ reg = <0x2800 0 0xd0080000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 9>;
+ status = "disabled";
+ };
+
+ pcie at 1,1 {
+ device_type = "pciex";
+ reg = <0x3000 0 0xd0084000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <1>;
+ clocks = <&gateclk 10>;
+ status = "disabled";
+ };
+
+ pcie at 1,2 {
+ device_type = "pciex";
+ reg = <0x3800 0 0xd0088000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <2>;
+ clocks = <&gateclk 11>;
+ status = "disabled";
+ };
+
+ pcie at 1,3 {
+ device_type = "pciex";
+ reg = <0x4000 0 0xd008C000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <1>;
+ marvell,pcie-lane = <3>;
+ clocks = <&gateclk 12>;
+ status = "disabled";
+ };
+ pcie at 2,0 {
+ device_type = "pciex";
+ reg = <0x4800 0 0xd0042000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <2>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 26>;
+ status = "disabled";
+ };
+
+ pcie at 3,0 {
+ device_type = "pciex";
+ reg = <0x5000 0 0xd0082000 0 0x2000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ marvell,pcie-port = <3>;
+ marvell,pcie-lane = <0>;
+ clocks = <&gateclk 27>;
+ status = "disabled";
+ };
+};
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index cc3a1af..03e15e7 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -1,4 +1,10 @@
menu "PCI host controller drivers"
depends on PCI
+config PCI_MVEBU
+ bool "Marvell EBU PCIe controller"
+ depends on ARCH_MVEBU
+ select PCI_SW_HOST_BRIDGE
+ select PCI_SW_PCI_PCI_BRIDGE
+
endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
new file mode 100644
index 0000000..34d6057
--- /dev/null
+++ b/drivers/pci/host/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
+ccflags-$(CONFIG_PCI_MVEBU) += \
+ -I$(srctree)/arch/arm/plat-orion/include \
+ -I$(srctree)/arch/arm/mach-mvebu/include
diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c
new file mode 100644
index 0000000..4db09e1
--- /dev/null
+++ b/drivers/pci/host/pci-mvebu.c
@@ -0,0 +1,500 @@
+/*
+ * PCIe driver for Marvell Armada 370 and Armada XP SoCs
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <plat/pcie.h>
+#include <mach/addr-map.h>
+
+/*
+ * Those are the product IDs used for the emulated PCI Host bridge and
+ * emulated PCI-to-PCI bridges. They are temporary until we get
+ * official IDs assigned.
+ */
+#define MARVELL_EMULATED_HOST_BRIDGE_ID 4141
+#define MARVELL_EMULATED_PCI_PCI_BRIDGE_ID 4242
+
+struct mvebu_pcie_port;
+
+/* Structure representing all PCIe interfaces */
+struct mvebu_pcie {
+ struct pci_sw_host_bridge bridge;
+ struct platform_device *pdev;
+ struct mvebu_pcie_port *ports;
+ struct resource io;
+ struct resource mem;
+ struct resource busn;
+ int nports;
+};
+
+/* Structure representing one PCIe interface */
+struct mvebu_pcie_port {
+ void __iomem *base;
+ spinlock_t conf_lock;
+ int haslink;
+ u32 port;
+ u32 lane;
+ int devfn;
+ struct clk *clk;
+ struct pci_sw_pci_bridge bridge;
+ struct device_node *dn;
+};
+
+static inline struct mvebu_pcie *sys_to_pcie(struct pci_sys_data *sys)
+{
+ return sys->private_data;
+}
+
+/* PCI configuration space write function */
+static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
+ int where, int size, u32 val)
+{
+ struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata);
+
+ if (bus->number != 0) {
+ /*
+ * Accessing a real PCIe interface, where the Linux
+ * virtual bus number is equal to the hardware PCIe
+ * interface number + 1
+ */
+ struct mvebu_pcie_port *port;
+ unsigned long flags;
+ int porti, ret;
+
+ porti = bus->number - 1;
+ if (porti >= pcie->nports)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ port = &pcie->ports[porti];
+
+ if (!port->haslink)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (PCI_SLOT(devfn) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ spin_lock_irqsave(&port->conf_lock, flags);
+ ret = orion_pcie_wr_conf_bus(port->base, bus->number - 1,
+ PCI_DEVFN(1, PCI_FUNC(devfn)),
+ where, size, val);
+ spin_unlock_irqrestore(&port->conf_lock, flags);
+
+ return ret;
+ } else {
+ /*
+ * Accessing the emulated PCIe devices. In the first
+ * slot, the emulated host bridge, and in the next
+ * slots, the PCI-to-PCI bridges that correspond to
+ * each PCIe hardware interface
+ */
+ if (PCI_SLOT(devfn) == 0 && PCI_FUNC(devfn) == 0)
+ return pci_sw_host_bridge_write(&pcie->bridge, where,
+ size, val);
+ else if (PCI_SLOT(devfn) >= 1 &&
+ PCI_SLOT(devfn) <= pcie->nports) {
+ struct mvebu_pcie_port *port;
+ int porti = PCI_SLOT(devfn) - 1;
+ port = &pcie->ports[porti];
+ return pci_sw_pci_bridge_write(&port->bridge, where,
+ size, val);
+ } else {
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+/* PCI configuration space read function */
+static int mvebu_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
+ int size, u32 *val)
+{
+ struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata);
+
+ if (bus->number != 0) {
+ /*
+ * Accessing a real PCIe interface, where the Linux
+ * virtual bus number is equal to the hardware PCIe
+ * interface number + 1
+ */
+ struct mvebu_pcie_port *port;
+ unsigned long flags;
+ int porti, ret;
+
+ porti = bus->number - 1;
+ if (porti >= pcie->nports) {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ port = &pcie->ports[porti];
+
+ if (!port->haslink || PCI_SLOT(devfn) != 0) {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ spin_lock_irqsave(&port->conf_lock, flags);
+ ret = orion_pcie_rd_conf_bus(port->base, bus->number - 1,
+ PCI_DEVFN(1, PCI_FUNC(devfn)),
+ where, size, val);
+ spin_unlock_irqrestore(&port->conf_lock, flags);
+
+ return ret;
+ } else {
+ /*
+ * Accessing the emulated PCIe devices. In the first
+ * slot, the emulated host bridge, and in the next
+ * slots, the PCI-to-PCI bridges that correspond to
+ * each PCIe hardware interface
+ */
+ if (PCI_SLOT(devfn) == 0 && PCI_FUNC(devfn) == 0)
+ return pci_sw_host_bridge_read(&pcie->bridge, where,
+ size, val);
+ else if (PCI_SLOT(devfn) >= 1 &&
+ PCI_SLOT(devfn) <= pcie->nports) {
+ struct mvebu_pcie_port *port;
+ int porti = PCI_SLOT(devfn) - 1;
+ port = &pcie->ports[porti];
+ return pci_sw_pci_bridge_read(&port->bridge, where,
+ size, val);
+ } else {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ }
+}
+
+static struct pci_ops mvebu_pcie_ops = {
+ .read = mvebu_pcie_rd_conf,
+ .write = mvebu_pcie_wr_conf,
+};
+
+static int __init mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+ struct mvebu_pcie *pcie = sys_to_pcie(sys);
+ int i;
+
+ pci_add_resource_offset(&sys->resources, &pcie->io, sys->io_offset);
+ pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
+ pci_add_resource(&sys->resources, &pcie->busn);
+
+ pci_ioremap_io(nr * SZ_64K, pcie->io.start);
+
+ for (i = 0; i < pcie->nports; i++) {
+ struct mvebu_pcie_port *port = &pcie->ports[i];
+ orion_pcie_set_local_bus_nr(port->base, i);
+ orion_pcie_setup(port->base);
+ }
+
+ return 1;
+}
+
+static int __init mvebu_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ struct mvebu_pcie *pcie = sys_to_pcie(dev->bus->sysdata);
+ struct mvebu_pcie_port *port;
+ struct of_irq oirq;
+ u32 laddr[3];
+ int ret;
+ __be32 intspec;
+
+ /*
+ * Ignore requests related to the emulated host bridge or the
+ * emulated pci-to-pci bridges
+ */
+ if (!dev->bus->number)
+ return -1;
+
+ port = &pcie->ports[dev->bus->number - 1];
+
+ /*
+ * Build an laddr array that describes the PCI device in a DT
+ * way
+ */
+ laddr[0] = cpu_to_be32(port->devfn << 8);
+ laddr[1] = laddr[2] = 0;
+ intspec = cpu_to_be32(pin);
+
+ ret = of_irq_map_raw(port->dn, &intspec, 1, laddr, &oirq);
+ if (ret) {
+ dev_err(&pcie->pdev->dev,
+ "%s: of_irq_map_raw() failed, %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return irq_create_of_mapping(oirq.controller, oirq.specifier,
+ oirq.size);
+}
+
+/*
+ * For a given PCIe interface (represented by a mvebu_pcie_port
+ * structure), we read the PCI configuration space of the
+ * corresponding PCI-to-PCI bridge in order to find out which range of
+ * I/O addresses and memory addresses have been assigned to this PCIe
+ * interface. Using these informations, we set up the appropriate
+ * address decoding windows so that the physical address are actually
+ * resolved to the right PCIe interface.
+ */
+static int mvebu_pcie_window_config_port(struct mvebu_pcie *pcie,
+ struct mvebu_pcie_port *port)
+{
+ unsigned long iobase = 0;
+ int ret;
+
+ if (port->bridge.iolimit >= port->bridge.iobase) {
+ unsigned long iolimit = 0xFFF |
+ ((port->bridge.iolimit & 0xF0) << 8) |
+ (port->bridge.iolimitupper << 16);
+ iobase = ((port->bridge.iobase & 0xF0) << 8) |
+ (port->bridge.iobaseupper << 16);
+ ret = armada_370_xp_alloc_pcie_window(port->port, port->lane,
+ iobase, iolimit-iobase,
+ IORESOURCE_IO);
+ if (ret) {
+ dev_err(&pcie->pdev->dev,
+ "%s: could not alloc PCIe %d:%d window for I/O [0x%lx; 0x%lx]\n",
+ __func__, port->port, port->lane,
+ iobase, iolimit);
+ goto out_io;
+ }
+ }
+
+ if (port->bridge.memlimit >= port->bridge.membase) {
+ unsigned long membase =
+ ((port->bridge.membase & 0xFFF0) << 16);
+ unsigned long memlimit =
+ ((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF;
+ ret = armada_370_xp_alloc_pcie_window(port->port, port->lane,
+ membase, memlimit-membase,
+ IORESOURCE_MEM);
+ if (ret) {
+ dev_err(&pcie->pdev->dev,
+ "%s: could not alloc PCIe %d:%d window for MEM [0x%lx; 0x%lx]\n",
+ __func__, port->port, port->lane,
+ membase, memlimit);
+ goto out_mem;
+ }
+ }
+
+out_mem:
+ if (port->bridge.iolimit >= port->bridge.iobase)
+ armada_370_xp_free_pcie_window(iobase);
+out_io:
+ return ret;
+}
+
+/*
+ * Set up the address decoding windows for all PCIe interfaces.
+ */
+static int mvebu_pcie_window_config(struct mvebu_pcie *pcie)
+{
+ int i, ret;
+
+ for (i = 0; i < pcie->nports; i++) {
+ struct mvebu_pcie_port *port = &pcie->ports[i];
+ if (!port->haslink)
+ continue;
+
+ ret = mvebu_pcie_window_config_port(pcie, port);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev,
+ const struct resource *res,
+ resource_size_t start,
+ resource_size_t size,
+ resource_size_t align)
+{
+ if (!(res->flags & IORESOURCE_IO))
+ return start;
+
+ /*
+ * The I/O regions must be 64K aligned, because the
+ * granularity of PCIe I/O address decoding windows is 64 K
+ */
+ return round_up(start, SZ_64K);
+}
+
+static int mvebu_pcie_enable(struct mvebu_pcie *pcie)
+{
+ struct hw_pci hw;
+
+ memset(&hw, 0, sizeof(hw));
+
+ hw.nr_controllers = 1;
+ hw.private_data = (void **)&pcie;
+ hw.setup = mvebu_pcie_setup;
+ hw.map_irq = mvebu_pcie_map_irq;
+ hw.align_resource = mvebu_pcie_align_resource;
+ hw.ops = &mvebu_pcie_ops;
+
+ pci_common_init(&hw);
+
+ return mvebu_pcie_window_config(pcie);
+}
+
+static int __init mvebu_pcie_probe(struct platform_device *pdev)
+{
+ struct mvebu_pcie *pcie;
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *child;
+ const __be32 *range = NULL;
+ struct resource res;
+ int i, ret;
+
+ pcie = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pcie),
+ GFP_KERNEL);
+ if (!pcie)
+ return -ENOMEM;
+
+ pcie->pdev = pdev;
+
+ pci_sw_host_bridge_init(&pcie->bridge);
+ pcie->bridge.vendor = PCI_VENDOR_ID_MARVELL;
+ pcie->bridge.device = MARVELL_EMULATED_HOST_BRIDGE_ID;
+
+ /* Get the I/O and memory ranges from DT */
+ while ((range = of_pci_process_ranges(np, &res, range)) != NULL) {
+ if (resource_type(&res) == IORESOURCE_IO) {
+ memcpy(&pcie->io, &res, sizeof(res));
+ pcie->io.name = "I/O";
+ }
+ if (resource_type(&res) == IORESOURCE_MEM) {
+ memcpy(&pcie->mem, &res, sizeof(res));
+ pcie->mem.name = "MEM";
+ }
+ }
+
+ /* Get the bus range */
+ ret = of_pci_parse_bus_range(np, &pcie->busn);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to parse bus-range property: %d\n",
+ ret);
+ return ret;
+ }
+
+ for_each_child_of_node(pdev->dev.of_node, child) {
+ if (!of_device_is_available(child))
+ continue;
+ pcie->nports++;
+ }
+
+ pcie->ports = devm_kzalloc(&pdev->dev, pcie->nports *
+ sizeof(struct mvebu_pcie_port),
+ GFP_KERNEL);
+ if (!pcie->ports)
+ return -ENOMEM;
+
+ i = 0;
+ for_each_child_of_node(pdev->dev.of_node, child) {
+ struct mvebu_pcie_port *port = &pcie->ports[i];
+
+ if (!of_device_is_available(child))
+ continue;
+
+ if (of_property_read_u32(child, "marvell,pcie-port",
+ &port->port)) {
+ dev_warn(&pdev->dev,
+ "ignoring PCIe DT node, missing pcie-port property\n");
+ continue;
+ }
+
+ if (of_property_read_u32(child, "marvell,pcie-lane",
+ &port->lane))
+ port->lane = 0;
+
+ port->devfn = of_pci_get_devfn(child);
+ if (port->devfn < 0)
+ continue;
+
+ port->base = of_iomap(child, 0);
+ if (!port->base) {
+ dev_err(&pdev->dev, "PCIe%d.%d: cannot map registers\n",
+ port->port, port->lane);
+ continue;
+ }
+
+ if (orion_pcie_link_up(port->base)) {
+ port->haslink = 1;
+ dev_info(&pdev->dev, "PCIe%d.%d: link up\n",
+ port->port, port->lane);
+ } else {
+ port->haslink = 0;
+ dev_info(&pdev->dev, "PCIe%d.%d: link down\n",
+ port->port, port->lane);
+ }
+
+ port->clk = of_clk_get_by_name(child, NULL);
+ if (!port->clk) {
+ dev_err(&pdev->dev, "PCIe%d.%d: cannot get clock\n",
+ port->port, port->lane);
+ iounmap(port->base);
+ port->haslink = 0;
+ continue;
+ }
+
+ port->dn = child;
+
+ clk_prepare_enable(port->clk);
+ spin_lock_init(&port->conf_lock);
+
+ pci_sw_pci_bridge_init(&port->bridge);
+ port->bridge.vendor = PCI_VENDOR_ID_MARVELL;
+ port->bridge.device = MARVELL_EMULATED_PCI_PCI_BRIDGE_ID;
+ port->bridge.primary_bus = 0;
+ port->bridge.secondary_bus = PCI_SLOT(port->devfn);
+ port->bridge.subordinate_bus = PCI_SLOT(port->devfn);
+
+ i++;
+ }
+
+ mvebu_pcie_enable(pcie);
+
+ return 0;
+}
+
+static const struct of_device_id mvebu_pcie_of_match_table[] = {
+ { .compatible = "marvell,armada-370-xp-pcie", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mvebu_pcie_of_match_table);
+
+static struct platform_driver mvebu_pcie_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "mvebu-pcie",
+ .of_match_table =
+ of_match_ptr(mvebu_pcie_of_match_table),
+ },
+};
+
+static int mvebu_pcie_init(void)
+{
+ return platform_driver_probe(&mvebu_pcie_driver,
+ mvebu_pcie_probe);
+}
+
+subsys_initcall(mvebu_pcie_init);
+
+MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
+MODULE_DESCRIPTION("Marvell EBU PCIe driver");
+MODULE_LICENSE("GPL");
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 18/27] arm: plat-orion: add more flexible PCI configuration space read/write functions
From: Thomas Petazzoni @ 2013-01-28 18:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359399397-29729-1-git-send-email-thomas.petazzoni@free-electrons.com>
The existing orion_pcie_rd_conf() and orion_pcie_wr_conf() functions
provided by plat-orion/pcie.c are nice to read and write the PCI
configuration space of a device, but they unfortunately assume that
the bus number and slot number at which a device is visible at the
Linux software level is the same as the bus number and slot number at
the hardware level.
However, with the usage of the emulated PCI host bridge and emulated
PCI-to-PCI bridges, this is not the case: bus number 0 is the emulated
bus on which the emulated PCI-to-PCI bridges sit, so from the Linux
point of view, the real busses start at bus 1, but from a hardware
point of view, they start at bus 0.
So, we cannot use the existing orion_pcie_rd_conf() and
orion_pcie_wr_conf() implementations, which take their bus number
directly from a given pci_bus structure. Instead, we add lower-level
variants, orion_pcie_rd_conf_bus() and orion_pcie_wr_conf_bus() that
take a bus number as argument. The existing orion_pcie_rd_conf() and
orion_pcie_wr_conf() functions are implemented on top of the new
*_bus() variants.
Those *_bus() variants will be used by the Marvell Armada 370/XP PCIe
driver.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/plat-orion/include/plat/pcie.h | 4 ++++
arch/arm/plat-orion/pcie.c | 26 ++++++++++++++++++++------
2 files changed, 24 insertions(+), 6 deletions(-)
diff --git a/arch/arm/plat-orion/include/plat/pcie.h b/arch/arm/plat-orion/include/plat/pcie.h
index fe5b9e8..46974c1 100644
--- a/arch/arm/plat-orion/include/plat/pcie.h
+++ b/arch/arm/plat-orion/include/plat/pcie.h
@@ -21,12 +21,16 @@ int orion_pcie_get_local_bus_nr(void __iomem *base);
void orion_pcie_set_local_bus_nr(void __iomem *base, int nr);
void orion_pcie_reset(void __iomem *base);
void orion_pcie_setup(void __iomem *base);
+int orion_pcie_rd_conf_bus(void __iomem *base, u32 busn,
+ u32 devfn, int where, int size, u32 *val);
int orion_pcie_rd_conf(void __iomem *base, struct pci_bus *bus,
u32 devfn, int where, int size, u32 *val);
int orion_pcie_rd_conf_tlp(void __iomem *base, struct pci_bus *bus,
u32 devfn, int where, int size, u32 *val);
int orion_pcie_rd_conf_wa(void __iomem *wa_base, struct pci_bus *bus,
u32 devfn, int where, int size, u32 *val);
+int orion_pcie_wr_conf_bus(void __iomem *base, u32 busn,
+ u32 devfn, int where, int size, u32 val);
int orion_pcie_wr_conf(void __iomem *base, struct pci_bus *bus,
u32 devfn, int where, int size, u32 val);
diff --git a/arch/arm/plat-orion/pcie.c b/arch/arm/plat-orion/pcie.c
index f20a321..0e85bdd 100644
--- a/arch/arm/plat-orion/pcie.c
+++ b/arch/arm/plat-orion/pcie.c
@@ -203,10 +203,10 @@ void __init orion_pcie_setup(void __iomem *base)
writel(mask, base + PCIE_MASK_OFF);
}
-int orion_pcie_rd_conf(void __iomem *base, struct pci_bus *bus,
- u32 devfn, int where, int size, u32 *val)
+int orion_pcie_rd_conf_bus(void __iomem *base, u32 busn, u32 devfn,
+ int where, int size, u32 *val)
{
- writel(PCIE_CONF_BUS(bus->number) |
+ writel(PCIE_CONF_BUS(busn) |
PCIE_CONF_DEV(PCI_SLOT(devfn)) |
PCIE_CONF_FUNC(PCI_FUNC(devfn)) |
PCIE_CONF_REG(where) | PCIE_CONF_ADDR_EN,
@@ -222,6 +222,13 @@ int orion_pcie_rd_conf(void __iomem *base, struct pci_bus *bus,
return PCIBIOS_SUCCESSFUL;
}
+int orion_pcie_rd_conf(void __iomem *base, struct pci_bus *bus,
+ u32 devfn, int where, int size, u32 *val)
+{
+ return orion_pcie_rd_conf_bus(base, bus->number, devfn,
+ where, size, val);
+}
+
int orion_pcie_rd_conf_tlp(void __iomem *base, struct pci_bus *bus,
u32 devfn, int where, int size, u32 *val)
{
@@ -261,12 +268,12 @@ int orion_pcie_rd_conf_wa(void __iomem *wa_base, struct pci_bus *bus,
return PCIBIOS_SUCCESSFUL;
}
-int orion_pcie_wr_conf(void __iomem *base, struct pci_bus *bus,
- u32 devfn, int where, int size, u32 val)
+int orion_pcie_wr_conf_bus(void __iomem *base, u32 busn,
+ u32 devfn, int where, int size, u32 val)
{
int ret = PCIBIOS_SUCCESSFUL;
- writel(PCIE_CONF_BUS(bus->number) |
+ writel(PCIE_CONF_BUS(busn) |
PCIE_CONF_DEV(PCI_SLOT(devfn)) |
PCIE_CONF_FUNC(PCI_FUNC(devfn)) |
PCIE_CONF_REG(where) | PCIE_CONF_ADDR_EN,
@@ -284,3 +291,10 @@ int orion_pcie_wr_conf(void __iomem *base, struct pci_bus *bus,
return ret;
}
+
+int orion_pcie_wr_conf(void __iomem *base, struct pci_bus *bus,
+ u32 devfn, int where, int size, u32 val)
+{
+ return orion_pcie_wr_conf_bus(base, bus->number, devfn,
+ where, size, val);
+}
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 17/27] arm: plat-orion: make common PCIe code usable on mvebu
From: Thomas Petazzoni @ 2013-01-28 18:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359399397-29729-1-git-send-email-thomas.petazzoni@free-electrons.com>
mvebu is a new-style Orion platform, so it only selects PLAT_ORION,
but not PLAT_ORION_LEGACY. It will however need the common PCIe code
from plat-orion, so make this code available for PLAT_ORION platforms
as a whole, and not only PLAT_ORION_LEGACY platforms.
We also take this opportunity to build the PCIe code only when
CONFIG_PCI is enabled.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/plat-orion/Makefile | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/arm/plat-orion/Makefile b/arch/arm/plat-orion/Makefile
index a82cecb..1aca22b 100644
--- a/arch/arm/plat-orion/Makefile
+++ b/arch/arm/plat-orion/Makefile
@@ -4,7 +4,8 @@
ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include
obj-y += addr-map.o
+obj-$(CONFIG_PCI) += pcie.o
orion-gpio-$(CONFIG_GENERIC_GPIO) += gpio.o
-obj-$(CONFIG_PLAT_ORION_LEGACY) += irq.o pcie.o time.o common.o mpp.o
+obj-$(CONFIG_PLAT_ORION_LEGACY) += irq.o time.o common.o mpp.o
obj-$(CONFIG_PLAT_ORION_LEGACY) += $(orion-gpio-y)
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 16/27] arm: mvebu: add functions to alloc/free PCIe decoding windows
From: Thomas Petazzoni @ 2013-01-28 18:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359399397-29729-1-git-send-email-thomas.petazzoni@free-electrons.com>
This commit adds two functions armada_370_xp_alloc_pcie_window() and
armada_370_xp_free_pcie_window() that respectively allocate and free
an address decoding window pointing to either a memory or I/O region
of a PCIe device.
Those functions will be used by the PCIe driver to create and remove
those regions depending on the PCIe devices that are detected.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/mach-mvebu/addr-map.c | 87 +++++++++++++++++++++++++--
arch/arm/mach-mvebu/common.h | 1 +
arch/arm/mach-mvebu/include/mach/addr-map.h | 8 +++
3 files changed, 92 insertions(+), 4 deletions(-)
create mode 100644 arch/arm/mach-mvebu/include/mach/addr-map.h
diff --git a/arch/arm/mach-mvebu/addr-map.c b/arch/arm/mach-mvebu/addr-map.c
index ab9b3bd..7ec8fc6 100644
--- a/arch/arm/mach-mvebu/addr-map.c
+++ b/arch/arm/mach-mvebu/addr-map.c
@@ -24,14 +24,10 @@
#define ARMADA_XP_TARGET_DEV_BUS 1
#define ARMADA_XP_ATTR_DEV_BOOTROM 0x1D
#define ARMADA_XP_TARGET_ETH1 3
-#define ARMADA_XP_TARGET_PCIE_0_2 4
#define ARMADA_XP_TARGET_ETH0 7
-#define ARMADA_XP_TARGET_PCIE_1_3 8
#define ARMADA_370_TARGET_DEV_BUS 1
#define ARMADA_370_ATTR_DEV_BOOTROM 0x1D
-#define ARMADA_370_TARGET_PCIE_0 4
-#define ARMADA_370_TARGET_PCIE_1 8
#define ARMADA_WINDOW_8_PLUS_OFFSET 0x90
#define ARMADA_SDRAM_ADDR_DECODING_OFFSET 0x180
@@ -89,6 +85,89 @@ static struct __initdata orion_addr_map_cfg addr_map_cfg = {
.win_cfg_base = armada_cfg_base,
};
+#ifdef CONFIG_PCI
+/*
+ * This structure and the following arrays allow to map a PCIe (port,
+ * lane) tuple to the corresponding (target, attribute) tuple needed
+ * to configure an address decoding window for the given PCIe (port,
+ * lane).
+ */
+struct pcie_mapping {
+ int port;
+ int lane;
+ u8 target;
+ u8 attr;
+};
+
+struct pcie_mapping armada_xp_pcie_mappings[] = {
+ { .port = 0, .lane = 0, .target = 4, .attr = 0xE0 },
+ { .port = 0, .lane = 1, .target = 4, .attr = 0xD0 },
+ { .port = 0, .lane = 2, .target = 4, .attr = 0xB0 },
+ { .port = 0, .lane = 3, .target = 4, .attr = 0x70 },
+ { .port = 1, .lane = 0, .target = 8, .attr = 0xE0 },
+ { .port = 1, .lane = 1, .target = 8, .attr = 0xD0 },
+ { .port = 1, .lane = 2, .target = 8, .attr = 0xB0 },
+ { .port = 1, .lane = 3, .target = 8, .attr = 0x70 },
+ { .port = 2, .lane = 0, .target = 4, .attr = 0xF0 },
+ { .port = 3, .lane = 0, .target = 8, .attr = 0xF0 },
+ { .port = -1 },
+};
+
+struct pcie_mapping armada_370_pcie_mappings[] = {
+ { .port = 0, .lane = 0, .target = 4, .attr = 0xE0 },
+ { .port = 1, .lane = 0, .target = 8, .attr = 0xE0 },
+ { .port = -1 },
+};
+
+/*
+ * This function sets up a new address decoding window at the given
+ * base address, pointing to the given PCIe interface (through
+ * pcie_port and pcie_lane).
+ */
+int __init armada_370_xp_alloc_pcie_window(int pcie_port, int pcie_lane,
+ unsigned long base, u32 size,
+ int type)
+{
+ struct pcie_mapping *mapping, *mappings;
+ u8 target, attr;
+
+ if (of_machine_is_compatible("marvell,armadaxp"))
+ mappings = armada_xp_pcie_mappings;
+ else if (of_machine_is_compatible("marvell,armada370"))
+ mappings = armada_370_pcie_mappings;
+ else
+ return -ENODEV;
+
+ for (mapping = mappings; mapping->port != -1; mapping++)
+ if (mapping->port == pcie_port && mapping->lane == pcie_lane)
+ break;
+
+ if (mapping->port == -1)
+ return -ENODEV;
+
+ target = mapping->target;
+ attr = mapping->attr;
+
+ /*
+ * Bit 3 of the attributes indicates that it is a
+ * memory region, as opposed to an I/O region
+ */
+ if (type == IORESOURCE_MEM)
+ attr |= (1 << 3);
+
+ return orion_alloc_cpu_win(&addr_map_cfg, base, size, target, attr, -1);
+}
+
+/*
+ * Frees an address decoding window previously set up by
+ * armada_370_xp_setup_pcie_window().
+ */
+int __init armada_370_xp_free_pcie_window(unsigned long base)
+{
+ return orion_free_cpu_win(&addr_map_cfg, base);
+}
+#endif
+
static int __init armada_setup_cpu_mbus(void)
{
struct device_node *np;
diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h
index aa27bc2..77c078c 100644
--- a/arch/arm/mach-mvebu/common.h
+++ b/arch/arm/mach-mvebu/common.h
@@ -25,4 +25,5 @@ int armada_370_xp_coherency_init(void);
int armada_370_xp_pmsu_init(void);
void armada_xp_secondary_startup(void);
extern struct smp_operations armada_xp_smp_ops;
+
#endif
diff --git a/arch/arm/mach-mvebu/include/mach/addr-map.h b/arch/arm/mach-mvebu/include/mach/addr-map.h
new file mode 100644
index 0000000..0845b27
--- /dev/null
+++ b/arch/arm/mach-mvebu/include/mach/addr-map.h
@@ -0,0 +1,8 @@
+#ifndef MVEBU_ADDR_MAP_H
+#define MVEBU_ADDR_MAP_H
+
+int armada_370_xp_alloc_pcie_window(int pcie_port, int pcie_lane,
+ unsigned long base, u32 size, int type);
+int armada_370_xp_free_pcie_window(unsigned long base);
+
+#endif /* MVEBU_ADDR_MAP_H */
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 15/27] arm: plat-orion: introduce orion_{alloc, free}_cpu_win() functions
From: Thomas Petazzoni @ 2013-01-28 18:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1359399397-29729-1-git-send-email-thomas.petazzoni@free-electrons.com>
In the address decoding code, we implement two new functions:
orion_alloc_cpu_win() and orion_free_cpu_win(). The first function
finds an unused address decoding window, and configures it according
to the given arguments (in terms of base address, size, target,
attributes). The second function frees an address decoding window,
given a physical base address.
Those two new functions will be used by the PCIe code, which needs to
dynamically register address decoding windows depending on the PCIe
devices that are detected.
The orion_free_cpu_win() function is only here to handle error cases
in the PCIe devices initialization, in the normal case, address
decoding windows are never freed.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
arch/arm/plat-orion/addr-map.c | 50 +++++++++++++++++++++++++++
arch/arm/plat-orion/include/plat/addr-map.h | 7 ++++
2 files changed, 57 insertions(+)
diff --git a/arch/arm/plat-orion/addr-map.c b/arch/arm/plat-orion/addr-map.c
index dd98638..8f4ef82 100644
--- a/arch/arm/plat-orion/addr-map.c
+++ b/arch/arm/plat-orion/addr-map.c
@@ -109,6 +109,56 @@ static void __init orion_disable_cpu_win(const struct orion_addr_map_cfg *cfg,
}
/*
+ * Find an unused address decoding window, and enable it according to
+ * the arguments passed (base, size, target, attributes, remap).
+ */
+int __init orion_alloc_cpu_win(const struct orion_addr_map_cfg *cfg,
+ const u32 base, const u32 size,
+ const u8 target, const u8 attr, const int remap)
+{
+ int win;
+
+ for (win = 0; win < cfg->num_wins; win++) {
+ void __iomem *addr = cfg->win_cfg_base(cfg, win);
+ u32 ctrl = readl(addr + WIN_CTRL_OFF);
+ if (!(ctrl & WIN_CTRL_ENABLE))
+ break;
+ }
+
+ /* No more windows available */
+ if (win == cfg->num_wins)
+ return -ENOMEM;
+
+ orion_setup_cpu_win(cfg, win, base, size, target, attr, remap);
+ return 0;
+}
+
+/*
+ * Free an address decoding window, given its base address.
+ */
+int __init orion_free_cpu_win(const struct orion_addr_map_cfg *cfg,
+ const u32 base)
+{
+ int win;
+
+ for (win = 0; win < cfg->num_wins; win++) {
+ void __iomem *addr = cfg->win_cfg_base(cfg, win);
+ u32 winbase = readl(addr + WIN_BASE_OFF);
+ u32 ctrl = readl(addr + WIN_CTRL_OFF);
+
+ if (!(ctrl & WIN_CTRL_ENABLE))
+ continue;
+
+ if (winbase == (base & 0xffff0000)) {
+ orion_disable_cpu_win(cfg, win);
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+/*
* Configure a number of windows.
*/
static void __init orion_setup_cpu_wins(const struct orion_addr_map_cfg * cfg,
diff --git a/arch/arm/plat-orion/include/plat/addr-map.h b/arch/arm/plat-orion/include/plat/addr-map.h
index b76c065..f8bb539 100644
--- a/arch/arm/plat-orion/include/plat/addr-map.h
+++ b/arch/arm/plat-orion/include/plat/addr-map.h
@@ -49,6 +49,13 @@ void __init orion_setup_cpu_win(const struct orion_addr_map_cfg *cfg,
const u32 size, const u8 target,
const u8 attr, const int remap);
+int __init orion_alloc_cpu_win(const struct orion_addr_map_cfg *cfg,
+ const u32 base, const u32 size,
+ const u8 target, const u8 attr, const int remap);
+
+int __init orion_free_cpu_win(const struct orion_addr_map_cfg *cfg,
+ const u32 base);
+
void __init orion_setup_cpu_mbus_target(const struct orion_addr_map_cfg *cfg,
const void __iomem *ddr_window_cpu_base);
#endif
--
1.7.9.5
^ 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