diff options
author | luka <luka@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2014-02-11 02:07:38 +0000 |
---|---|---|
committer | luka <luka@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2014-02-11 02:07:38 +0000 |
commit | 1d4ea10d6ee10906ee9a605c6ea5119103ceac6f (patch) | |
tree | c62a7fd987aaeef721141f541c4477b8427e22ea /target/linux | |
parent | b4144ee2b03809cc82cef63e277a69b306de1321 (diff) |
mvebu: backport mainline patches from kernel 3.11
This is a backport of the patches accepted to the Linux mainline related to
mvebu SoC (Armada XP and Armada 370) between Linux v3.10, and Linux v3.11.
This work mainly covers:
* Enabling USB storage, and PCI to mvebu_defconfig.
* Add support for NOR flash.
* Some PCI device tree related updates, and bus parsing.
* Adding Armada XP & 370 PCI driver, and update some clock gating
specifics.
* Introduce Marvell EBU Device Bus driver.
* Enaling USB in the armada*.dts.
* Enabling, and updating the mvebu-mbus.
* Some SATA and Ethernet related fixes.
Signed-off-by: Seif Mazareeb <seif.mazareeb@gmail.com>
CC: Luka Perkov <luka@openwrt.org>
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@39564 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux')
47 files changed, 5206 insertions, 0 deletions
diff --git a/target/linux/mvebu/patches-3.10/0001-ARM-mvebu-Add-support-for-USB-storage-class-in-mvebu.patch b/target/linux/mvebu/patches-3.10/0001-ARM-mvebu-Add-support-for-USB-storage-class-in-mvebu.patch new file mode 100644 index 0000000000..7ffc403601 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0001-ARM-mvebu-Add-support-for-USB-storage-class-in-mvebu.patch @@ -0,0 +1,28 @@ +From 6c52eba54044791592aefd139bdc2a7b6127e981 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Date: Wed, 17 Apr 2013 16:51:34 -0300 +Subject: [PATCH 001/203] ARM: mvebu: Add support for USB storage class in + mvebu_defconfig + +Some boards can have built-in USB storage class controllers so +it's better to have this option included by default. + +Currently this option is needed to support built-in USB MMC controller +found in Globalscale Mirabox board. + +Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + arch/arm/configs/mvebu_defconfig | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/configs/mvebu_defconfig ++++ b/arch/arm/configs/mvebu_defconfig +@@ -60,6 +60,7 @@ CONFIG_USB_SUPPORT=y + CONFIG_USB=y + CONFIG_USB_EHCI_HCD=y + CONFIG_USB_EHCI_ROOT_HUB_TT=y ++CONFIG_USB_STORAGE=y + CONFIG_MMC=y + CONFIG_MMC_MVSDIO=y + CONFIG_NEW_LEDS=y diff --git a/target/linux/mvebu/patches-3.10/0002-ARM-mvebu-Use-standard-MMC-binding-for-all-users-of-.patch b/target/linux/mvebu/patches-3.10/0002-ARM-mvebu-Use-standard-MMC-binding-for-all-users-of-.patch new file mode 100644 index 0000000000..536009c7b2 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0002-ARM-mvebu-Use-standard-MMC-binding-for-all-users-of-.patch @@ -0,0 +1,133 @@ +From cf6eb4599d60cb9fa81465aa018c71d11e19ea6a Mon Sep 17 00:00:00 2001 +From: Simon Baatz <gmbnomis@gmail.com> +Date: Mon, 13 May 2013 23:18:58 +0200 +Subject: [PATCH 002/203] ARM: mvebu: Use standard MMC binding for all users of + mvsdio + +In order to prepare the switch to the standard MMC device tree parser +for mvsdio, adapt all current uses of mvsdio in the dts files to the +standard format. + +Signed-off-by: Simon Baatz <gmbnomis@gmail.com> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + arch/arm/boot/dts/armada-370-db.dts | 1 + + arch/arm/boot/dts/armada-370-mirabox.dts | 1 + + arch/arm/boot/dts/armada-370-rd.dts | 1 + + arch/arm/boot/dts/armada-370-xp.dtsi | 4 ++++ + arch/arm/boot/dts/armada-xp-db.dts | 1 + + arch/arm/boot/dts/kirkwood-dreamplug.dts | 1 + + arch/arm/boot/dts/kirkwood-guruplug-server-plus.dts | 2 ++ + arch/arm/boot/dts/kirkwood-mplcec4.dts | 2 +- + arch/arm/boot/dts/kirkwood-topkick.dts | 1 + + arch/arm/boot/dts/kirkwood.dtsi | 4 ++++ + 10 files changed, 17 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/armada-370-db.dts ++++ b/arch/arm/boot/dts/armada-370-db.dts +@@ -74,6 +74,7 @@ + */ + status = "disabled"; + /* No CD or WP GPIOs */ ++ broken-cd; + }; + + usb@50000 { +--- a/arch/arm/boot/dts/armada-370-mirabox.dts ++++ b/arch/arm/boot/dts/armada-370-mirabox.dts +@@ -99,6 +99,7 @@ + * No CD or WP GPIOs: SDIO interface used for + * Wifi/Bluetooth chip + */ ++ broken-cd; + }; + + usb@50000 { +--- a/arch/arm/boot/dts/armada-370-rd.dts ++++ b/arch/arm/boot/dts/armada-370-rd.dts +@@ -64,6 +64,7 @@ + pinctrl-names = "default"; + status = "okay"; + /* No CD or WP GPIOs */ ++ broken-cd; + }; + + usb@50000 { +--- a/arch/arm/boot/dts/armada-370-xp.dtsi ++++ b/arch/arm/boot/dts/armada-370-xp.dtsi +@@ -143,6 +143,10 @@ + reg = <0xd4000 0x200>; + interrupts = <54>; + clocks = <&gateclk 17>; ++ bus-width = <4>; ++ cap-sdio-irq; ++ cap-sd-highspeed; ++ cap-mmc-highspeed; + status = "disabled"; + }; + +--- a/arch/arm/boot/dts/armada-xp-db.dts ++++ b/arch/arm/boot/dts/armada-xp-db.dts +@@ -97,6 +97,7 @@ + pinctrl-names = "default"; + status = "okay"; + /* No CD or WP GPIOs */ ++ broken-cd; + }; + + usb@50000 { +--- a/arch/arm/boot/dts/kirkwood-dreamplug.dts ++++ b/arch/arm/boot/dts/kirkwood-dreamplug.dts +@@ -79,6 +79,7 @@ + pinctrl-names = "default"; + status = "okay"; + /* No CD or WP GPIOs */ ++ broken-cd; + }; + }; + +--- a/arch/arm/boot/dts/kirkwood-guruplug-server-plus.dts ++++ b/arch/arm/boot/dts/kirkwood-guruplug-server-plus.dts +@@ -72,6 +72,8 @@ + + mvsdio@90000 { + status = "okay"; ++ /* No CD or WP GPIOs */ ++ broken-cd; + }; + }; + +--- a/arch/arm/boot/dts/kirkwood-mplcec4.dts ++++ b/arch/arm/boot/dts/kirkwood-mplcec4.dts +@@ -136,7 +136,7 @@ + pinctrl-0 = <&pmx_sdio &pmx_sdio_cd>; + pinctrl-names = "default"; + status = "okay"; +- cd-gpios = <&gpio1 15 0>; ++ cd-gpios = <&gpio1 15 1>; + /* No WP GPIO */ + }; + }; +--- a/arch/arm/boot/dts/kirkwood-topkick.dts ++++ b/arch/arm/boot/dts/kirkwood-topkick.dts +@@ -154,6 +154,7 @@ + pinctrl-names = "default"; + status = "okay"; + /* No CD or WP GPIOs */ ++ broken-cd; + }; + }; + +--- a/arch/arm/boot/dts/kirkwood.dtsi ++++ b/arch/arm/boot/dts/kirkwood.dtsi +@@ -200,6 +200,10 @@ + reg = <0x90000 0x200>; + interrupts = <28>; + clocks = <&gate_clk 4>; ++ bus-width = <4>; ++ cap-sdio-irq; ++ cap-sd-highspeed; ++ cap-mmc-highspeed; + status = "disabled"; + }; + }; diff --git a/target/linux/mvebu/patches-3.10/0003-ARM-mvebu-Add-support-for-NOR-flash-device-on-Armada.patch b/target/linux/mvebu/patches-3.10/0003-ARM-mvebu-Add-support-for-NOR-flash-device-on-Armada.patch new file mode 100644 index 0000000000..22f8ad0124 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0003-ARM-mvebu-Add-support-for-NOR-flash-device-on-Armada.patch @@ -0,0 +1,71 @@ +From 74cd8c09ae416261d7595021fc8062836dc750a2 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Date: Fri, 17 May 2013 08:09:58 -0300 +Subject: [PATCH 003/203] ARM: mvebu: Add support for NOR flash device on + Armada XP-DB board + +The Armada XP Development Board (DB-78460-BP) has a NOR flash device +connected to the Device Bus. This commit adds the device tree node +to support this device. + +This SoC supports a flexible and dynamic decoding window allocation +scheme; but since this feature is still not implemented we need +to specify the window base address in the device tree node itself. + +This base address has been selected in a completely arbitrary fashion. + +Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + arch/arm/boot/dts/armada-xp-db.dts | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +--- a/arch/arm/boot/dts/armada-xp-db.dts ++++ b/arch/arm/boot/dts/armada-xp-db.dts +@@ -30,6 +30,9 @@ + }; + + soc { ++ ranges = <0 0 0xd0000000 0x100000 /* Internal registers 1MiB */ ++ 0xf0000000 0 0xf0000000 0x1000000>; /* Device Bus, NOR 16MiB */ ++ + internal-regs { + serial@12000 { + clock-frequency = <250000000>; +@@ -156,6 +159,35 @@ + status = "okay"; + }; + }; ++ ++ devbus-bootcs@10400 { ++ status = "okay"; ++ ranges = <0 0xf0000000 0x1000000>; ++ ++ /* Device Bus parameters are required */ ++ ++ /* Read parameters */ ++ devbus,bus-width = <8>; ++ devbus,turn-off-ps = <60000>; ++ devbus,badr-skew-ps = <0>; ++ devbus,acc-first-ps = <124000>; ++ devbus,acc-next-ps = <248000>; ++ devbus,rd-setup-ps = <0>; ++ devbus,rd-hold-ps = <0>; ++ ++ /* Write parameters */ ++ devbus,sync-enable = <0>; ++ devbus,wr-high-ps = <60000>; ++ devbus,wr-low-ps = <60000>; ++ devbus,ale-wr-ps = <60000>; ++ ++ /* NOR 16 MiB */ ++ nor@0 { ++ compatible = "cfi-flash"; ++ reg = <0 0x1000000>; ++ bank-width = <2>; ++ }; ++ }; + }; + }; + }; diff --git a/target/linux/mvebu/patches-3.10/0004-of-pci-Provide-support-for-parsing-PCI-DT-ranges-pro.patch b/target/linux/mvebu/patches-3.10/0004-of-pci-Provide-support-for-parsing-PCI-DT-ranges-pro.patch new file mode 100644 index 0000000000..6c8207080a --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0004-of-pci-Provide-support-for-parsing-PCI-DT-ranges-pro.patch @@ -0,0 +1,196 @@ +From 7d375772a601bdf227902454705e402fc65b8bdf Mon Sep 17 00:00:00 2001 +From: Andrew Murray <Andrew.Murray@arm.com> +Date: Tue, 7 May 2013 16:31:12 +0100 +Subject: [PATCH 004/203] of/pci: Provide support for parsing PCI DT ranges + property + +This patch factors out common implementation patterns to reduce overall kernel +code and provide a means for host bridge drivers to directly obtain struct +resources from the DT's ranges property without relying on architecture specific +DT handling. This will make it easier to write archiecture independent host bridge +drivers and mitigate against further duplication of DT parsing code. + +This patch can be used in the following way: + + struct of_pci_range_parser parser; + struct of_pci_range range; + + if (of_pci_range_parser_init(&parser, np)) + ; //no ranges property + + for_each_of_pci_range(&parser, &range) { + + /* + directly access properties of the address range, e.g.: + range.pci_space, range.pci_addr, range.cpu_addr, + range.size, range.flags + + alternatively obtain a struct resource, e.g.: + struct resource res; + of_pci_range_to_resource(&range, np, &res); + */ + } + +Additionally the implementation takes care of adjacent ranges and merges them +into a single range (as was the case with powerpc and microblaze). + +Signed-off-by: Andrew Murray <Andrew.Murray@arm.com> +Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Reviewed-by: Rob Herring <rob.herring@calxeda.com> +Tested-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Tested-by: Linus Walleij <linus.walleij@linaro.org> +Tested-by: Jingoo Han <jg1.han@samsung.com> +Acked-by: Grant Likely <grant.likely@secretlab.ca> +--- + drivers/of/address.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++ + include/linux/of_address.h | 48 +++++++++++++++++++++++++++++++++ + 2 files changed, 115 insertions(+) + +--- a/drivers/of/address.c ++++ b/drivers/of/address.c +@@ -223,6 +223,73 @@ int of_pci_address_to_resource(struct de + return __of_address_to_resource(dev, addrp, size, flags, NULL, r); + } + EXPORT_SYMBOL_GPL(of_pci_address_to_resource); ++ ++int of_pci_range_parser_init(struct of_pci_range_parser *parser, ++ struct device_node *node) ++{ ++ const int na = 3, ns = 2; ++ int rlen; ++ ++ parser->node = node; ++ parser->pna = of_n_addr_cells(node); ++ parser->np = parser->pna + na + ns; ++ ++ parser->range = of_get_property(node, "ranges", &rlen); ++ if (parser->range == NULL) ++ return -ENOENT; ++ ++ parser->end = parser->range + rlen / sizeof(__be32); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(of_pci_range_parser_init); ++ ++struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser, ++ struct of_pci_range *range) ++{ ++ const int na = 3, ns = 2; ++ ++ if (!range) ++ return NULL; ++ ++ if (!parser->range || parser->range + parser->np > parser->end) ++ return NULL; ++ ++ range->pci_space = parser->range[0]; ++ range->flags = of_bus_pci_get_flags(parser->range); ++ range->pci_addr = of_read_number(parser->range + 1, ns); ++ range->cpu_addr = of_translate_address(parser->node, ++ parser->range + na); ++ range->size = of_read_number(parser->range + parser->pna + na, ns); ++ ++ parser->range += parser->np; ++ ++ /* Now consume following elements while they are contiguous */ ++ while (parser->range + parser->np <= parser->end) { ++ u32 flags, pci_space; ++ u64 pci_addr, cpu_addr, size; ++ ++ pci_space = be32_to_cpup(parser->range); ++ flags = of_bus_pci_get_flags(parser->range); ++ pci_addr = of_read_number(parser->range + 1, ns); ++ cpu_addr = of_translate_address(parser->node, ++ parser->range + na); ++ size = of_read_number(parser->range + parser->pna + na, ns); ++ ++ if (flags != range->flags) ++ break; ++ if (pci_addr != range->pci_addr + range->size || ++ cpu_addr != range->cpu_addr + range->size) ++ break; ++ ++ range->size += size; ++ parser->range += parser->np; ++ } ++ ++ return range; ++} ++EXPORT_SYMBOL_GPL(of_pci_range_parser_one); ++ + #endif /* CONFIG_PCI */ + + /* +--- a/include/linux/of_address.h ++++ b/include/linux/of_address.h +@@ -4,6 +4,36 @@ + #include <linux/errno.h> + #include <linux/of.h> + ++struct of_pci_range_parser { ++ struct device_node *node; ++ const __be32 *range; ++ const __be32 *end; ++ int np; ++ int pna; ++}; ++ ++struct of_pci_range { ++ u32 pci_space; ++ u64 pci_addr; ++ u64 cpu_addr; ++ u64 size; ++ u32 flags; ++}; ++ ++#define for_each_of_pci_range(parser, range) \ ++ for (; of_pci_range_parser_one(parser, range);) ++ ++static inline void of_pci_range_to_resource(struct of_pci_range *range, ++ struct device_node *np, ++ struct resource *res) ++{ ++ res->flags = range->flags; ++ res->start = range->cpu_addr; ++ res->end = range->cpu_addr + range->size - 1; ++ res->parent = res->child = res->sibling = NULL; ++ res->name = np->full_name; ++} ++ + #ifdef CONFIG_OF_ADDRESS + extern u64 of_translate_address(struct device_node *np, const __be32 *addr); + extern bool of_can_translate_address(struct device_node *dev); +@@ -27,6 +57,11 @@ static inline unsigned long pci_address_ + #define pci_address_to_pio pci_address_to_pio + #endif + ++extern int of_pci_range_parser_init(struct of_pci_range_parser *parser, ++ struct device_node *node); ++extern struct of_pci_range *of_pci_range_parser_one( ++ struct of_pci_range_parser *parser, ++ struct of_pci_range *range); + #else /* CONFIG_OF_ADDRESS */ + #ifndef of_address_to_resource + static inline int of_address_to_resource(struct device_node *dev, int index, +@@ -53,6 +88,19 @@ static inline const __be32 *of_get_addre + { + return NULL; + } ++ ++static inline int of_pci_range_parser_init(struct of_pci_range_parser *parser, ++ struct device_node *node) ++{ ++ return -1; ++} ++ ++static inline struct of_pci_range *of_pci_range_parser_one( ++ struct of_pci_range_parser *parser, ++ struct of_pci_range *range) ++{ ++ return NULL; ++} + #endif /* CONFIG_OF_ADDRESS */ + + diff --git a/target/linux/mvebu/patches-3.10/0006-of-pci-Add-of_pci_parse_bus_range-function.patch b/target/linux/mvebu/patches-3.10/0006-of-pci-Add-of_pci_parse_bus_range-function.patch new file mode 100644 index 0000000000..ae07e8387f --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0006-of-pci-Add-of_pci_parse_bus_range-function.patch @@ -0,0 +1,54 @@ +From 3f368ae1994efc17b59ffd34307c76b1f642527e Mon Sep 17 00:00:00 2001 +From: Thierry Reding <thierry.reding@avionic-design.de> +Date: Mon, 11 Feb 2013 09:22:20 +0100 +Subject: [PATCH 006/203] of/pci: Add of_pci_parse_bus_range() function + +This function can be used to parse a bus-range property as specified by +device nodes representing PCI bridges. + +Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de> +--- + drivers/of/of_pci.c | 25 +++++++++++++++++++++++++ + include/linux/of_pci.h | 1 + + 2 files changed, 26 insertions(+) + +--- a/drivers/of/of_pci.c ++++ b/drivers/of/of_pci.c +@@ -64,3 +64,28 @@ int of_pci_get_devfn(struct device_node + return (be32_to_cpup(reg) >> 8) & 0xff; + } + EXPORT_SYMBOL_GPL(of_pci_get_devfn); ++ ++/** ++ * of_pci_parse_bus_range() - parse the bus-range property of a PCI device ++ * @node: device node ++ * @res: address to a struct resource to return the bus-range ++ * ++ * Returns 0 on success or a negative error-code on failure. ++ */ ++int of_pci_parse_bus_range(struct device_node *node, struct resource *res) ++{ ++ const __be32 *values; ++ int len; ++ ++ values = of_get_property(node, "bus-range", &len); ++ if (!values || len < sizeof(*values) * 2) ++ return -EINVAL; ++ ++ res->name = node->name; ++ res->start = be32_to_cpup(values++); ++ res->end = be32_to_cpup(values); ++ res->flags = IORESOURCE_BUS; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(of_pci_parse_bus_range); +--- a/include/linux/of_pci.h ++++ b/include/linux/of_pci.h +@@ -11,5 +11,6 @@ struct device_node; + struct device_node *of_pci_find_child_device(struct device_node *parent, + unsigned int devfn); + int of_pci_get_devfn(struct device_node *np); ++int of_pci_parse_bus_range(struct device_node *node, struct resource *res); + + #endif diff --git a/target/linux/mvebu/patches-3.10/0007-clk-mvebu-create-parent-child-relation-for-PCIe-cloc.patch b/target/linux/mvebu/patches-3.10/0007-clk-mvebu-create-parent-child-relation-for-PCIe-cloc.patch new file mode 100644 index 0000000000..c556c2755c --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0007-clk-mvebu-create-parent-child-relation-for-PCIe-cloc.patch @@ -0,0 +1,30 @@ +From f12aa05cbfb88e5541814ffa7be7e195471568bd Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Fri, 7 Dec 2012 20:35:20 +0100 +Subject: [PATCH 007/203] clk: mvebu: create parent-child relation for PCIe + clocks on Armada 370 + +The Armada 370 has two gatable clocks for each PCIe interface, and we +want both of them to be enabled. We therefore make one of the two +clocks a child of the other, as we did for the sataX and sataXlnk +clocks on Armada XP. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Cc: Mike Turquette <mturquette@linaro.org> +--- + drivers/clk/mvebu/clk-gating-ctrl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/clk/mvebu/clk-gating-ctrl.c ++++ b/drivers/clk/mvebu/clk-gating-ctrl.c +@@ -119,8 +119,8 @@ static const struct mvebu_soc_descr __in + { "pex1_en", NULL, 2 }, + { "ge1", NULL, 3 }, + { "ge0", NULL, 4 }, +- { "pex0", NULL, 5 }, +- { "pex1", NULL, 9 }, ++ { "pex0", "pex0_en", 5 }, ++ { "pex1", "pex1_en", 9 }, + { "sata0", NULL, 15 }, + { "sdio", NULL, 17 }, + { "tdm", NULL, 25 }, diff --git a/target/linux/mvebu/patches-3.10/0008-clk-mvebu-add-more-PCIe-clocks-for-Armada-XP.patch b/target/linux/mvebu/patches-3.10/0008-clk-mvebu-add-more-PCIe-clocks-for-Armada-XP.patch new file mode 100644 index 0000000000..871aa3d21d --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0008-clk-mvebu-add-more-PCIe-clocks-for-Armada-XP.patch @@ -0,0 +1,50 @@ +From 5006da299ae65cadf92932f2f7b062b5a8c65798 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Fri, 18 Jan 2013 16:42:01 +0100 +Subject: [PATCH 008/203] clk: mvebu: add more PCIe clocks for Armada XP + +The current revision of the datasheet only mentions the gatable clocks +for the PCIe 0.0, 0.1, 0.2 and 0.3 interfaces, and forgot to mention +the ones for the PCIe 1.0, 1.1, 1.2, 1.3, 2.0 and 3.0 +interfaces. After confirmation with Marvell engineers, this patch adds +the missing gatable clocks for those PCIe interfaces. + +It also changes the name of the previously existing PCIe gatable +clocks, in order to match the naming using the datasheets. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Cc: Mike Turquette <mturquette@linaro.org> +--- + drivers/clk/mvebu/clk-gating-ctrl.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +--- a/drivers/clk/mvebu/clk-gating-ctrl.c ++++ b/drivers/clk/mvebu/clk-gating-ctrl.c +@@ -137,10 +137,14 @@ static const struct mvebu_soc_descr __in + { "ge2", NULL, 2 }, + { "ge1", NULL, 3 }, + { "ge0", NULL, 4 }, +- { "pex0", NULL, 5 }, +- { "pex1", NULL, 6 }, +- { "pex2", NULL, 7 }, +- { "pex3", NULL, 8 }, ++ { "pex00", NULL, 5 }, ++ { "pex01", NULL, 6 }, ++ { "pex02", NULL, 7 }, ++ { "pex03", NULL, 8 }, ++ { "pex10", NULL, 9 }, ++ { "pex11", NULL, 10 }, ++ { "pex12", NULL, 11 }, ++ { "pex13", NULL, 12 }, + { "bp", NULL, 13 }, + { "sata0lnk", NULL, 14 }, + { "sata0", "sata0lnk", 15 }, +@@ -152,6 +156,8 @@ static const struct mvebu_soc_descr __in + { "xor0", NULL, 22 }, + { "crypto", NULL, 23 }, + { "tdm", NULL, 25 }, ++ { "pex20", NULL, 26 }, ++ { "pex30", NULL, 27 }, + { "xor1", NULL, 28 }, + { "sata1lnk", NULL, 29 }, + { "sata1", "sata1lnk", 30 }, diff --git a/target/linux/mvebu/patches-3.10/0009-pci-PCIe-driver-for-Marvell-Armada-370-XP-systems.patch b/target/linux/mvebu/patches-3.10/0009-pci-PCIe-driver-for-Marvell-Armada-370-XP-systems.patch new file mode 100644 index 0000000000..13ddae8c96 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0009-pci-PCIe-driver-for-Marvell-Armada-370-XP-systems.patch @@ -0,0 +1,1177 @@ +From cf7b5cb15e46b5357c60188b75b213a7f0b5fd32 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Fri, 18 Jan 2013 17:42:58 +0100 +Subject: [PATCH 009/203] pci: PCIe driver for Marvell Armada 370/XP systems + +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 mvebu-mbus driver. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Acked-by: Bjorn Helgaas <bhelgaas@google.com> +--- + .../devicetree/bindings/pci/mvebu-pci.txt | 220 ++++++ + drivers/pci/Kconfig | 2 + + drivers/pci/Makefile | 3 + + drivers/pci/host/Kconfig | 8 + + drivers/pci/host/Makefile | 1 + + drivers/pci/host/pci-mvebu.c | 880 +++++++++++++++++++++ + 6 files changed, 1114 insertions(+) + create mode 100644 Documentation/devicetree/bindings/pci/mvebu-pci.txt + create mode 100644 drivers/pci/host/Kconfig + create mode 100644 drivers/pci/host/Makefile + create mode 100644 drivers/pci/host/pci-mvebu.c + +--- /dev/null ++++ b/Documentation/devicetree/bindings/pci/mvebu-pci.txt +@@ -0,0 +1,220 @@ ++* Marvell EBU PCIe interfaces ++ ++Mandatory properties: ++- compatible: one of the following values: ++ marvell,armada-370-pcie ++ marvell,armada-xp-pcie ++- #address-cells, set to <3> ++- #size-cells, set to <2> ++- #interrupt-cells, set to <1> ++- bus-range: PCI bus numbers covered ++- device_type, set to "pci" ++- ranges: ranges for the PCI memory and I/O regions, as well as the ++ MMIO registers to control the PCIe interfaces. ++ ++In addition, the Device Tree node must have sub-nodes describing each ++PCIe interface, having the following mandatory properties: ++- reg: used only for interrupt mapping, so only the first four bytes ++ are used to refer to the correct bus number and device number. ++- assigned-addresses: reference to the MMIO registers used to control ++ this PCIe interface. ++- clocks: the clock associated to this PCIe interface ++- marvell,pcie-port: the physical PCIe port number ++- status: either "disabled" or "okay" ++- device_type, set to "pci" ++- #address-cells, set to <3> ++- #size-cells, set to <2> ++- #interrupt-cells, set to <1> ++- ranges, empty property. ++- interrupt-map-mask and interrupt-map, standard PCI properties to ++ define the mapping of the PCIe interface to interrupt numbers. ++ ++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-xp-pcie"; ++ status = "disabled"; ++ device_type = "pci"; ++ ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ++ bus-range = <0x00 0xff>; ++ ++ ranges = <0x82000000 0 0xd0040000 0xd0040000 0 0x00002000 /* Port 0.0 registers */ ++ 0x82000000 0 0xd0042000 0xd0042000 0 0x00002000 /* Port 2.0 registers */ ++ 0x82000000 0 0xd0044000 0xd0044000 0 0x00002000 /* Port 0.1 registers */ ++ 0x82000000 0 0xd0048000 0xd0048000 0 0x00002000 /* Port 0.2 registers */ ++ 0x82000000 0 0xd004c000 0xd004c000 0 0x00002000 /* Port 0.3 registers */ ++ 0x82000000 0 0xd0080000 0xd0080000 0 0x00002000 /* Port 1.0 registers */ ++ 0x82000000 0 0xd0082000 0xd0082000 0 0x00002000 /* Port 3.0 registers */ ++ 0x82000000 0 0xd0084000 0xd0084000 0 0x00002000 /* Port 1.1 registers */ ++ 0x82000000 0 0xd0088000 0xd0088000 0 0x00002000 /* Port 1.2 registers */ ++ 0x82000000 0 0xd008c000 0xd008c000 0 0x00002000 /* Port 1.3 registers */ ++ 0x82000000 0 0xe0000000 0xe0000000 0 0x08000000 /* non-prefetchable memory */ ++ 0x81000000 0 0 0xe8000000 0 0x00100000>; /* downstream I/O */ ++ ++ pcie@1,0 { ++ device_type = "pci"; ++ assigned-addresses = <0x82000800 0 0xd0040000 0 0x2000>; ++ reg = <0x0800 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &mpic 58>; ++ marvell,pcie-port = <0>; ++ marvell,pcie-lane = <0>; ++ clocks = <&gateclk 5>; ++ status = "disabled"; ++ }; ++ ++ pcie@2,0 { ++ device_type = "pci"; ++ assigned-addresses = <0x82001000 0 0xd0044000 0 0x2000>; ++ reg = <0x1000 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &mpic 59>; ++ marvell,pcie-port = <0>; ++ marvell,pcie-lane = <1>; ++ clocks = <&gateclk 6>; ++ status = "disabled"; ++ }; ++ ++ pcie@3,0 { ++ device_type = "pci"; ++ assigned-addresses = <0x82001800 0 0xd0048000 0 0x2000>; ++ reg = <0x1800 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &mpic 60>; ++ marvell,pcie-port = <0>; ++ marvell,pcie-lane = <2>; ++ clocks = <&gateclk 7>; ++ status = "disabled"; ++ }; ++ ++ pcie@4,0 { ++ device_type = "pci"; ++ assigned-addresses = <0x82002000 0 0xd004c000 0 0x2000>; ++ reg = <0x2000 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &mpic 61>; ++ marvell,pcie-port = <0>; ++ marvell,pcie-lane = <3>; ++ clocks = <&gateclk 8>; ++ status = "disabled"; ++ }; ++ ++ pcie@5,0 { ++ device_type = "pci"; ++ assigned-addresses = <0x82002800 0 0xd0080000 0 0x2000>; ++ reg = <0x2800 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &mpic 62>; ++ marvell,pcie-port = <1>; ++ marvell,pcie-lane = <0>; ++ clocks = <&gateclk 9>; ++ status = "disabled"; ++ }; ++ ++ pcie@6,0 { ++ device_type = "pci"; ++ assigned-addresses = <0x82003000 0 0xd0084000 0 0x2000>; ++ reg = <0x3000 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &mpic 63>; ++ marvell,pcie-port = <1>; ++ marvell,pcie-lane = <1>; ++ clocks = <&gateclk 10>; ++ status = "disabled"; ++ }; ++ ++ pcie@7,0 { ++ device_type = "pci"; ++ assigned-addresses = <0x82003800 0 0xd0088000 0 0x2000>; ++ reg = <0x3800 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &mpic 64>; ++ marvell,pcie-port = <1>; ++ marvell,pcie-lane = <2>; ++ clocks = <&gateclk 11>; ++ status = "disabled"; ++ }; ++ ++ pcie@8,0 { ++ device_type = "pci"; ++ assigned-addresses = <0x82004000 0 0xd008c000 0 0x2000>; ++ reg = <0x4000 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &mpic 65>; ++ marvell,pcie-port = <1>; ++ marvell,pcie-lane = <3>; ++ clocks = <&gateclk 12>; ++ status = "disabled"; ++ }; ++ pcie@9,0 { ++ device_type = "pci"; ++ assigned-addresses = <0x82004800 0 0xd0042000 0 0x2000>; ++ reg = <0x4800 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &mpic 99>; ++ marvell,pcie-port = <2>; ++ marvell,pcie-lane = <0>; ++ clocks = <&gateclk 26>; ++ status = "disabled"; ++ }; ++ ++ pcie@10,0 { ++ device_type = "pci"; ++ assigned-addresses = <0x82005000 0 0xd0082000 0 0x2000>; ++ reg = <0x5000 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &mpic 103>; ++ marvell,pcie-port = <3>; ++ marvell,pcie-lane = <0>; ++ clocks = <&gateclk 27>; ++ status = "disabled"; ++ }; ++}; +--- a/drivers/pci/Kconfig ++++ b/drivers/pci/Kconfig +@@ -125,3 +125,5 @@ config PCI_IOAPIC + config PCI_LABEL + def_bool y if (DMI || ACPI) + select NLS ++ ++source "drivers/pci/host/Kconfig" +--- a/drivers/pci/Makefile ++++ b/drivers/pci/Makefile +@@ -67,3 +67,6 @@ obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen + obj-$(CONFIG_OF) += of.o + + ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG ++ ++# PCI host controller drivers ++obj-y += host/ +--- /dev/null ++++ b/drivers/pci/host/Kconfig +@@ -0,0 +1,8 @@ ++menu "PCI host controller drivers" ++ depends on PCI ++ ++config PCI_MVEBU ++ bool "Marvell EBU PCIe controller" ++ depends on ARCH_MVEBU ++ ++endmenu +--- /dev/null ++++ b/drivers/pci/host/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o +--- /dev/null ++++ b/drivers/pci/host/pci-mvebu.c +@@ -0,0 +1,880 @@ ++/* ++ * 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/mbus.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> ++ ++/* ++ * PCIe unit register offsets. ++ */ ++#define PCIE_DEV_ID_OFF 0x0000 ++#define PCIE_CMD_OFF 0x0004 ++#define PCIE_DEV_REV_OFF 0x0008 ++#define PCIE_BAR_LO_OFF(n) (0x0010 + ((n) << 3)) ++#define PCIE_BAR_HI_OFF(n) (0x0014 + ((n) << 3)) ++#define PCIE_HEADER_LOG_4_OFF 0x0128 ++#define PCIE_BAR_CTRL_OFF(n) (0x1804 + (((n) - 1) * 4)) ++#define PCIE_WIN04_CTRL_OFF(n) (0x1820 + ((n) << 4)) ++#define PCIE_WIN04_BASE_OFF(n) (0x1824 + ((n) << 4)) ++#define PCIE_WIN04_REMAP_OFF(n) (0x182c + ((n) << 4)) ++#define PCIE_WIN5_CTRL_OFF 0x1880 ++#define PCIE_WIN5_BASE_OFF 0x1884 ++#define PCIE_WIN5_REMAP_OFF 0x188c ++#define PCIE_CONF_ADDR_OFF 0x18f8 ++#define PCIE_CONF_ADDR_EN 0x80000000 ++#define PCIE_CONF_REG(r) ((((r) & 0xf00) << 16) | ((r) & 0xfc)) ++#define PCIE_CONF_BUS(b) (((b) & 0xff) << 16) ++#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 11) ++#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 8) ++#define PCIE_CONF_ADDR(bus, devfn, where) \ ++ (PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn)) | \ ++ PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where) | \ ++ PCIE_CONF_ADDR_EN) ++#define PCIE_CONF_DATA_OFF 0x18fc ++#define PCIE_MASK_OFF 0x1910 ++#define PCIE_MASK_ENABLE_INTS 0x0f000000 ++#define PCIE_CTRL_OFF 0x1a00 ++#define PCIE_CTRL_X1_MODE 0x0001 ++#define PCIE_STAT_OFF 0x1a04 ++#define PCIE_STAT_BUS 0xff00 ++#define PCIE_STAT_LINK_DOWN BIT(0) ++#define PCIE_DEBUG_CTRL 0x1a60 ++#define PCIE_DEBUG_SOFT_RESET BIT(20) ++ ++/* ++ * This product ID is registered by Marvell, and used when the Marvell ++ * SoC is not the root complex, but an endpoint on the PCIe bus. It is ++ * therefore safe to re-use this PCI ID for our emulated PCI-to-PCI ++ * bridge. ++ */ ++#define MARVELL_EMULATED_PCI_PCI_BRIDGE_ID 0x7846 ++ ++/* PCI configuration space of a PCI-to-PCI bridge */ ++struct mvebu_sw_pci_bridge { ++ u16 vendor; ++ u16 device; ++ u16 command; ++ u16 status; ++ u16 class; ++ u8 interface; ++ u8 revision; ++ u8 bist; ++ u8 header_type; ++ u8 latency_timer; ++ u8 cache_line_size; ++ u32 bar[2]; ++ u8 primary_bus; ++ u8 secondary_bus; ++ u8 subordinate_bus; ++ u8 secondary_latency_timer; ++ u8 iobase; ++ u8 iolimit; ++ u16 secondary_status; ++ u16 membase; ++ u16 memlimit; ++ u16 prefmembase; ++ u16 prefmemlimit; ++ u32 prefbaseupper; ++ u32 preflimitupper; ++ u16 iobaseupper; ++ u16 iolimitupper; ++ u8 cappointer; ++ u8 reserved1; ++ u16 reserved2; ++ u32 romaddr; ++ u8 intline; ++ u8 intpin; ++ u16 bridgectrl; ++}; ++ ++struct mvebu_pcie_port; ++ ++/* Structure representing all PCIe interfaces */ ++struct mvebu_pcie { ++ struct platform_device *pdev; ++ struct mvebu_pcie_port *ports; ++ struct resource io; ++ struct resource realio; ++ struct resource mem; ++ struct resource busn; ++ int nports; ++}; ++ ++/* Structure representing one PCIe interface */ ++struct mvebu_pcie_port { ++ char *name; ++ void __iomem *base; ++ spinlock_t conf_lock; ++ int haslink; ++ u32 port; ++ u32 lane; ++ int devfn; ++ struct clk *clk; ++ struct mvebu_sw_pci_bridge bridge; ++ struct device_node *dn; ++ struct mvebu_pcie *pcie; ++ phys_addr_t memwin_base; ++ size_t memwin_size; ++ phys_addr_t iowin_base; ++ size_t iowin_size; ++}; ++ ++static bool mvebu_pcie_link_up(struct mvebu_pcie_port *port) ++{ ++ return !(readl(port->base + PCIE_STAT_OFF) & PCIE_STAT_LINK_DOWN); ++} ++ ++static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie_port *port, int nr) ++{ ++ u32 stat; ++ ++ stat = readl(port->base + PCIE_STAT_OFF); ++ stat &= ~PCIE_STAT_BUS; ++ stat |= nr << 8; ++ writel(stat, port->base + PCIE_STAT_OFF); ++} ++ ++/* ++ * Setup PCIE BARs and Address Decode Wins: ++ * BAR[0,2] -> disabled, BAR[1] -> covers all DRAM banks ++ * WIN[0-3] -> DRAM bank[0-3] ++ */ ++static void __init mvebu_pcie_setup_wins(struct mvebu_pcie_port *port) ++{ ++ const struct mbus_dram_target_info *dram; ++ u32 size; ++ int i; ++ ++ dram = mv_mbus_dram_info(); ++ ++ /* First, disable and clear BARs and windows. */ ++ for (i = 1; i < 3; i++) { ++ writel(0, port->base + PCIE_BAR_CTRL_OFF(i)); ++ writel(0, port->base + PCIE_BAR_LO_OFF(i)); ++ writel(0, port->base + PCIE_BAR_HI_OFF(i)); ++ } ++ ++ for (i = 0; i < 5; i++) { ++ writel(0, port->base + PCIE_WIN04_CTRL_OFF(i)); ++ writel(0, port->base + PCIE_WIN04_BASE_OFF(i)); ++ writel(0, port->base + PCIE_WIN04_REMAP_OFF(i)); ++ } ++ ++ writel(0, port->base + PCIE_WIN5_CTRL_OFF); ++ writel(0, port->base + PCIE_WIN5_BASE_OFF); ++ writel(0, port->base + PCIE_WIN5_REMAP_OFF); ++ ++ /* Setup windows for DDR banks. Count total DDR size on the fly. */ ++ size = 0; ++ for (i = 0; i < dram->num_cs; i++) { ++ const struct mbus_dram_window *cs = dram->cs + i; ++ ++ writel(cs->base & 0xffff0000, ++ port->base + PCIE_WIN04_BASE_OFF(i)); ++ writel(0, port->base + PCIE_WIN04_REMAP_OFF(i)); ++ writel(((cs->size - 1) & 0xffff0000) | ++ (cs->mbus_attr << 8) | ++ (dram->mbus_dram_target_id << 4) | 1, ++ port->base + PCIE_WIN04_CTRL_OFF(i)); ++ ++ size += cs->size; ++ } ++ ++ /* Round up 'size' to the nearest power of two. */ ++ if ((size & (size - 1)) != 0) ++ size = 1 << fls(size); ++ ++ /* Setup BAR[1] to all DRAM banks. */ ++ writel(dram->cs[0].base, port->base + PCIE_BAR_LO_OFF(1)); ++ writel(0, port->base + PCIE_BAR_HI_OFF(1)); ++ writel(((size - 1) & 0xffff0000) | 1, ++ port->base + PCIE_BAR_CTRL_OFF(1)); ++} ++ ++static void __init mvebu_pcie_setup_hw(struct mvebu_pcie_port *port) ++{ ++ u16 cmd; ++ u32 mask; ++ ++ /* Point PCIe unit MBUS decode windows to DRAM space. */ ++ mvebu_pcie_setup_wins(port); ++ ++ /* Master + slave enable. */ ++ cmd = readw(port->base + PCIE_CMD_OFF); ++ cmd |= PCI_COMMAND_IO; ++ cmd |= PCI_COMMAND_MEMORY; ++ cmd |= PCI_COMMAND_MASTER; ++ writew(cmd, port->base + PCIE_CMD_OFF); ++ ++ /* Enable interrupt lines A-D. */ ++ mask = readl(port->base + PCIE_MASK_OFF); ++ mask |= PCIE_MASK_ENABLE_INTS; ++ writel(mask, port->base + PCIE_MASK_OFF); ++} ++ ++static int mvebu_pcie_hw_rd_conf(struct mvebu_pcie_port *port, ++ struct pci_bus *bus, ++ u32 devfn, int where, int size, u32 *val) ++{ ++ writel(PCIE_CONF_ADDR(bus->number, devfn, where), ++ port->base + PCIE_CONF_ADDR_OFF); ++ ++ *val = readl(port->base + PCIE_CONF_DATA_OFF); ++ ++ if (size == 1) ++ *val = (*val >> (8 * (where & 3))) & 0xff; ++ else if (size == 2) ++ *val = (*val >> (8 * (where & 3))) & 0xffff; ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static int mvebu_pcie_hw_wr_conf(struct mvebu_pcie_port *port, ++ struct pci_bus *bus, ++ u32 devfn, int where, int size, u32 val) ++{ ++ int ret = PCIBIOS_SUCCESSFUL; ++ ++ writel(PCIE_CONF_ADDR(bus->number, devfn, where), ++ port->base + PCIE_CONF_ADDR_OFF); ++ ++ if (size == 4) ++ writel(val, port->base + PCIE_CONF_DATA_OFF); ++ else if (size == 2) ++ writew(val, port->base + PCIE_CONF_DATA_OFF + (where & 3)); ++ else if (size == 1) ++ writeb(val, port->base + PCIE_CONF_DATA_OFF + (where & 3)); ++ else ++ ret = PCIBIOS_BAD_REGISTER_NUMBER; ++ ++ return ret; ++} ++ ++static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) ++{ ++ phys_addr_t iobase; ++ ++ /* Are the new iobase/iolimit values invalid? */ ++ if (port->bridge.iolimit < port->bridge.iobase || ++ port->bridge.iolimitupper < port->bridge.iobaseupper) { ++ ++ /* If a window was configured, remove it */ ++ if (port->iowin_base) { ++ mvebu_mbus_del_window(port->iowin_base, ++ port->iowin_size); ++ port->iowin_base = 0; ++ port->iowin_size = 0; ++ } ++ ++ return; ++ } ++ ++ /* ++ * We read the PCI-to-PCI bridge emulated registers, and ++ * calculate the base address and size of the address decoding ++ * window to setup, according to the PCI-to-PCI bridge ++ * specifications. iobase is the bus address, port->iowin_base ++ * is the CPU address. ++ */ ++ iobase = ((port->bridge.iobase & 0xF0) << 8) | ++ (port->bridge.iobaseupper << 16); ++ port->iowin_base = port->pcie->io.start + iobase; ++ port->iowin_size = ((0xFFF | ((port->bridge.iolimit & 0xF0) << 8) | ++ (port->bridge.iolimitupper << 16)) - ++ iobase); ++ ++ mvebu_mbus_add_window_remap_flags(port->name, port->iowin_base, ++ port->iowin_size, ++ iobase, ++ MVEBU_MBUS_PCI_IO); ++ ++ pci_ioremap_io(iobase, port->iowin_base); ++} ++ ++static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port) ++{ ++ /* Are the new membase/memlimit values invalid? */ ++ if (port->bridge.memlimit < port->bridge.membase) { ++ ++ /* If a window was configured, remove it */ ++ if (port->memwin_base) { ++ mvebu_mbus_del_window(port->memwin_base, ++ port->memwin_size); ++ port->memwin_base = 0; ++ port->memwin_size = 0; ++ } ++ ++ return; ++ } ++ ++ /* ++ * We read the PCI-to-PCI bridge emulated registers, and ++ * calculate the base address and size of the address decoding ++ * window to setup, according to the PCI-to-PCI bridge ++ * specifications. ++ */ ++ port->memwin_base = ((port->bridge.membase & 0xFFF0) << 16); ++ port->memwin_size = ++ (((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) - ++ port->memwin_base; ++ ++ mvebu_mbus_add_window_remap_flags(port->name, port->memwin_base, ++ port->memwin_size, ++ MVEBU_MBUS_NO_REMAP, ++ MVEBU_MBUS_PCI_MEM); ++} ++ ++/* ++ * Initialize the configuration space of the PCI-to-PCI bridge ++ * associated with the given PCIe interface. ++ */ ++static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port) ++{ ++ struct mvebu_sw_pci_bridge *bridge = &port->bridge; ++ ++ memset(bridge, 0, sizeof(struct mvebu_sw_pci_bridge)); ++ ++ bridge->status = PCI_STATUS_CAP_LIST; ++ bridge->class = PCI_CLASS_BRIDGE_PCI; ++ bridge->vendor = PCI_VENDOR_ID_MARVELL; ++ bridge->device = MARVELL_EMULATED_PCI_PCI_BRIDGE_ID; ++ bridge->header_type = PCI_HEADER_TYPE_BRIDGE; ++ bridge->cache_line_size = 0x10; ++ ++ /* We support 32 bits I/O addressing */ ++ bridge->iobase = PCI_IO_RANGE_TYPE_32; ++ bridge->iolimit = PCI_IO_RANGE_TYPE_32; ++} ++ ++/* ++ * Read the configuration space of the PCI-to-PCI bridge associated to ++ * the given PCIe interface. ++ */ ++static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port, ++ unsigned int where, int size, u32 *value) ++{ ++ struct mvebu_sw_pci_bridge *bridge = &port->bridge; ++ ++ switch (where & ~3) { ++ case PCI_VENDOR_ID: ++ *value = bridge->device << 16 | bridge->vendor; ++ break; ++ ++ case PCI_COMMAND: ++ *value = bridge->status << 16 | bridge->command; ++ break; ++ ++ case PCI_CLASS_REVISION: ++ *value = bridge->class << 16 | bridge->interface << 8 | ++ bridge->revision; ++ break; ++ ++ case PCI_CACHE_LINE_SIZE: ++ *value = bridge->bist << 24 | bridge->header_type << 16 | ++ bridge->latency_timer << 8 | bridge->cache_line_size; ++ break; ++ ++ case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1: ++ *value = bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4]; ++ break; ++ ++ case PCI_PRIMARY_BUS: ++ *value = (bridge->secondary_latency_timer << 24 | ++ bridge->subordinate_bus << 16 | ++ bridge->secondary_bus << 8 | ++ bridge->primary_bus); ++ break; ++ ++ case PCI_IO_BASE: ++ *value = (bridge->secondary_status << 16 | ++ bridge->iolimit << 8 | ++ bridge->iobase); ++ break; ++ ++ case PCI_MEMORY_BASE: ++ *value = (bridge->memlimit << 16 | bridge->membase); ++ break; ++ ++ case PCI_PREF_MEMORY_BASE: ++ *value = (bridge->prefmemlimit << 16 | bridge->prefmembase); ++ break; ++ ++ case PCI_PREF_BASE_UPPER32: ++ *value = bridge->prefbaseupper; ++ break; ++ ++ case PCI_PREF_LIMIT_UPPER32: ++ *value = bridge->preflimitupper; ++ break; ++ ++ case PCI_IO_BASE_UPPER16: ++ *value = (bridge->iolimitupper << 16 | bridge->iobaseupper); ++ break; ++ ++ case PCI_ROM_ADDRESS1: ++ *value = 0; ++ break; ++ ++ default: ++ *value = 0xffffffff; ++ return PCIBIOS_BAD_REGISTER_NUMBER; ++ } ++ ++ if (size == 2) ++ *value = (*value >> (8 * (where & 3))) & 0xffff; ++ else if (size == 1) ++ *value = (*value >> (8 * (where & 3))) & 0xff; ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++/* Write to the PCI-to-PCI bridge configuration space */ ++static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port, ++ unsigned int where, int size, u32 value) ++{ ++ struct mvebu_sw_pci_bridge *bridge = &port->bridge; ++ u32 mask, reg; ++ int err; ++ ++ if (size == 4) ++ mask = 0x0; ++ else if (size == 2) ++ mask = ~(0xffff << ((where & 3) * 8)); ++ else if (size == 1) ++ mask = ~(0xff << ((where & 3) * 8)); ++ else ++ return PCIBIOS_BAD_REGISTER_NUMBER; ++ ++ err = mvebu_sw_pci_bridge_read(port, where & ~3, 4, ®); ++ if (err) ++ return err; ++ ++ value = (reg & mask) | value << ((where & 3) * 8); ++ ++ switch (where & ~3) { ++ case PCI_COMMAND: ++ bridge->command = value & 0xffff; ++ bridge->status = value >> 16; ++ break; ++ ++ case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1: ++ bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4] = value; ++ break; ++ ++ case PCI_IO_BASE: ++ /* ++ * We also keep bit 1 set, it is a read-only bit that ++ * indicates we support 32 bits addressing for the ++ * I/O ++ */ ++ bridge->iobase = (value & 0xff) | PCI_IO_RANGE_TYPE_32; ++ bridge->iolimit = ((value >> 8) & 0xff) | PCI_IO_RANGE_TYPE_32; ++ bridge->secondary_status = value >> 16; ++ mvebu_pcie_handle_iobase_change(port); ++ break; ++ ++ case PCI_MEMORY_BASE: ++ bridge->membase = value & 0xffff; ++ bridge->memlimit = value >> 16; ++ mvebu_pcie_handle_membase_change(port); ++ break; ++ ++ case PCI_PREF_MEMORY_BASE: ++ bridge->prefmembase = value & 0xffff; ++ bridge->prefmemlimit = value >> 16; ++ break; ++ ++ case PCI_PREF_BASE_UPPER32: ++ bridge->prefbaseupper = value; ++ break; ++ ++ case PCI_PREF_LIMIT_UPPER32: ++ bridge->preflimitupper = value; ++ break; ++ ++ case PCI_IO_BASE_UPPER16: ++ bridge->iobaseupper = value & 0xffff; ++ bridge->iolimitupper = value >> 16; ++ mvebu_pcie_handle_iobase_change(port); ++ break; ++ ++ case PCI_PRIMARY_BUS: ++ bridge->primary_bus = value & 0xff; ++ bridge->secondary_bus = (value >> 8) & 0xff; ++ bridge->subordinate_bus = (value >> 16) & 0xff; ++ bridge->secondary_latency_timer = (value >> 24) & 0xff; ++ mvebu_pcie_set_local_bus_nr(port, bridge->secondary_bus); ++ break; ++ ++ default: ++ break; ++ } ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static inline struct mvebu_pcie *sys_to_pcie(struct pci_sys_data *sys) ++{ ++ return sys->private_data; ++} ++ ++static struct mvebu_pcie_port * ++mvebu_pcie_find_port(struct mvebu_pcie *pcie, struct pci_bus *bus, ++ int devfn) ++{ ++ int i; ++ ++ for (i = 0; i < pcie->nports; i++) { ++ struct mvebu_pcie_port *port = &pcie->ports[i]; ++ if (bus->number == 0 && port->devfn == devfn) ++ return port; ++ if (bus->number != 0 && ++ port->bridge.secondary_bus == bus->number) ++ return port; ++ } ++ ++ return NULL; ++} ++ ++/* 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); ++ struct mvebu_pcie_port *port; ++ unsigned long flags; ++ int ret; ++ ++ port = mvebu_pcie_find_port(pcie, bus, devfn); ++ if (!port) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ /* Access the emulated PCI-to-PCI bridge */ ++ if (bus->number == 0) ++ return mvebu_sw_pci_bridge_write(port, where, size, val); ++ ++ if (!port->haslink || PCI_SLOT(devfn) != 0) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ /* Access the real PCIe interface */ ++ spin_lock_irqsave(&port->conf_lock, flags); ++ ret = mvebu_pcie_hw_wr_conf(port, bus, ++ PCI_DEVFN(1, PCI_FUNC(devfn)), ++ where, size, val); ++ spin_unlock_irqrestore(&port->conf_lock, flags); ++ ++ return ret; ++} ++ ++/* 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); ++ struct mvebu_pcie_port *port; ++ unsigned long flags; ++ int ret; ++ ++ port = mvebu_pcie_find_port(pcie, bus, devfn); ++ if (!port) { ++ *val = 0xffffffff; ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ } ++ ++ /* Access the emulated PCI-to-PCI bridge */ ++ if (bus->number == 0) ++ return mvebu_sw_pci_bridge_read(port, where, size, val); ++ ++ if (!port->haslink || PCI_SLOT(devfn) != 0) { ++ *val = 0xffffffff; ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ } ++ ++ /* Access the real PCIe interface */ ++ spin_lock_irqsave(&port->conf_lock, flags); ++ ret = mvebu_pcie_hw_rd_conf(port, bus, ++ PCI_DEVFN(1, PCI_FUNC(devfn)), ++ where, size, val); ++ spin_unlock_irqrestore(&port->conf_lock, flags); ++ ++ return ret; ++} ++ ++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->realio, sys->io_offset); ++ pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset); ++ pci_add_resource(&sys->resources, &pcie->busn); ++ ++ for (i = 0; i < pcie->nports; i++) { ++ struct mvebu_pcie_port *port = &pcie->ports[i]; ++ mvebu_pcie_setup_hw(port); ++ } ++ ++ return 1; ++} ++ ++static int __init mvebu_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ struct of_irq oirq; ++ int ret; ++ ++ ret = of_irq_map_pci(dev, &oirq); ++ if (ret) ++ return ret; ++ ++ return irq_create_of_mapping(oirq.controller, oirq.specifier, ++ oirq.size); ++} ++ ++static struct pci_bus *mvebu_pcie_scan_bus(int nr, struct pci_sys_data *sys) ++{ ++ struct mvebu_pcie *pcie = sys_to_pcie(sys); ++ struct pci_bus *bus; ++ ++ bus = pci_create_root_bus(&pcie->pdev->dev, sys->busnr, ++ &mvebu_pcie_ops, sys, &sys->resources); ++ if (!bus) ++ return NULL; ++ ++ pci_scan_child_bus(bus); ++ ++ return bus; ++} ++ ++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 (dev->bus->number != 0) ++ return start; ++ ++ /* ++ * On the PCI-to-PCI bridge side, the I/O windows must have at ++ * least a 64 KB size and be aligned on their size, and the ++ * memory windows must have at least a 1 MB size and be ++ * aligned on their size ++ */ ++ if (res->flags & IORESOURCE_IO) ++ return round_up(start, max((resource_size_t)SZ_64K, size)); ++ else if (res->flags & IORESOURCE_MEM) ++ return round_up(start, max((resource_size_t)SZ_1M, size)); ++ else ++ return start; ++} ++ ++static void __init 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.scan = mvebu_pcie_scan_bus; ++ hw.map_irq = mvebu_pcie_map_irq; ++ hw.ops = &mvebu_pcie_ops; ++ hw.align_resource = mvebu_pcie_align_resource; ++ ++ pci_common_init(&hw); ++} ++ ++/* ++ * Looks up the list of register addresses encoded into the reg = ++ * <...> property for one that matches the given port/lane. Once ++ * found, maps it. ++ */ ++static void __iomem * __init ++mvebu_pcie_map_registers(struct platform_device *pdev, ++ struct device_node *np, ++ struct mvebu_pcie_port *port) ++{ ++ struct resource regs; ++ int ret = 0; ++ ++ ret = of_address_to_resource(np, 0, ®s); ++ if (ret) ++ return NULL; ++ ++ return devm_request_and_ioremap(&pdev->dev, ®s); ++} ++ ++static int __init mvebu_pcie_probe(struct platform_device *pdev) ++{ ++ struct mvebu_pcie *pcie; ++ struct device_node *np = pdev->dev.of_node; ++ struct of_pci_range range; ++ struct of_pci_range_parser parser; ++ struct device_node *child; ++ int i, ret; ++ ++ pcie = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pcie), ++ GFP_KERNEL); ++ if (!pcie) ++ return -ENOMEM; ++ ++ pcie->pdev = pdev; ++ ++ if (of_pci_range_parser_init(&parser, np)) ++ return -EINVAL; ++ ++ /* Get the I/O and memory ranges from DT */ ++ for_each_of_pci_range(&parser, &range) { ++ unsigned long restype = range.flags & IORESOURCE_TYPE_BITS; ++ if (restype == IORESOURCE_IO) { ++ of_pci_range_to_resource(&range, np, &pcie->io); ++ of_pci_range_to_resource(&range, np, &pcie->realio); ++ pcie->io.name = "I/O"; ++ pcie->realio.start = max_t(resource_size_t, ++ PCIBIOS_MIN_IO, ++ range.pci_addr); ++ pcie->realio.end = min_t(resource_size_t, ++ IO_SPACE_LIMIT, ++ range.pci_addr + range.size); ++ } ++ if (restype == IORESOURCE_MEM) { ++ of_pci_range_to_resource(&range, np, &pcie->mem); ++ 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; ++ ++ port->pcie = pcie; ++ ++ 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->name = kasprintf(GFP_KERNEL, "pcie%d.%d", ++ port->port, port->lane); ++ ++ port->devfn = of_pci_get_devfn(child); ++ if (port->devfn < 0) ++ continue; ++ ++ port->base = mvebu_pcie_map_registers(pdev, child, port); ++ if (!port->base) { ++ dev_err(&pdev->dev, "PCIe%d.%d: cannot map registers\n", ++ port->port, port->lane); ++ continue; ++ } ++ ++ if (mvebu_pcie_link_up(port)) { ++ 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); ++ ++ mvebu_sw_pci_bridge_init(port); ++ ++ i++; ++ } ++ ++ mvebu_pcie_enable(pcie); ++ ++ return 0; ++} ++ ++static const struct of_device_id mvebu_pcie_of_match_table[] = { ++ { .compatible = "marvell,armada-xp-pcie", }, ++ { .compatible = "marvell,armada-370-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 __init 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("GPLv2"); diff --git a/target/linux/mvebu/patches-3.10/0010-arm-mvebu-PCIe-support-is-now-available-on-mvebu.patch b/target/linux/mvebu/patches-3.10/0010-arm-mvebu-PCIe-support-is-now-available-on-mvebu.patch new file mode 100644 index 0000000000..2e90b7d8d1 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0010-arm-mvebu-PCIe-support-is-now-available-on-mvebu.patch @@ -0,0 +1,25 @@ +From 430d545623552ddc6b68785032cc9129d0a00b43 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Fri, 7 Dec 2012 20:56:52 +0100 +Subject: [PATCH 010/203] arm: mvebu: PCIe support is now available on mvebu + +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(+) + +--- a/arch/arm/mach-mvebu/Kconfig ++++ b/arch/arm/mach-mvebu/Kconfig +@@ -16,6 +16,8 @@ config ARCH_MVEBU + select MVEBU_MBUS + select ZONE_DMA if ARM_LPAE + select ARCH_REQUIRE_GPIOLIB ++ select MIGHT_HAVE_PCI ++ select PCI_QUIRKS if PCI + + if ARCH_MVEBU + diff --git a/target/linux/mvebu/patches-3.10/0011-arm-mvebu-update-defconfig-with-PCI-and-USB-support.patch b/target/linux/mvebu/patches-3.10/0011-arm-mvebu-update-defconfig-with-PCI-and-USB-support.patch new file mode 100644 index 0000000000..3aeeb47e69 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0011-arm-mvebu-update-defconfig-with-PCI-and-USB-support.patch @@ -0,0 +1,36 @@ +From c3da1bb20af37c09a07756d54420470788f131c7 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Fri, 7 Dec 2012 22:49:57 +0100 +Subject: [PATCH 011/203] arm: mvebu: update defconfig with PCI and USB support + +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 | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/arch/arm/configs/mvebu_defconfig ++++ b/arch/arm/configs/mvebu_defconfig +@@ -13,6 +13,8 @@ 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_PCI_MVEBU=y + CONFIG_SMP=y + CONFIG_AEABI=y + CONFIG_HIGHMEM=y +@@ -61,6 +63,7 @@ CONFIG_USB=y + CONFIG_USB_EHCI_HCD=y + CONFIG_USB_EHCI_ROOT_HUB_TT=y + CONFIG_USB_STORAGE=y ++CONFIG_USB_XHCI_HCD=y + CONFIG_MMC=y + CONFIG_MMC_MVSDIO=y + CONFIG_NEW_LEDS=y diff --git a/target/linux/mvebu/patches-3.10/0012-arm-mvebu-mark-functions-of-armada-370-xp.c-as-stati.patch b/target/linux/mvebu/patches-3.10/0012-arm-mvebu-mark-functions-of-armada-370-xp.c-as-stati.patch new file mode 100644 index 0000000000..bbb5ceb790 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0012-arm-mvebu-mark-functions-of-armada-370-xp.c-as-stati.patch @@ -0,0 +1,40 @@ +From f865fd0e1c10bb044d56037eaa6ac4a4a122c62a Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Tue, 21 May 2013 12:33:28 +0200 +Subject: [PATCH 012/203] arm: mvebu: mark functions of armada-370-xp.c as + static + +All the functions in armada-370-xp.c are called from the +DT_MACHINE_START function pointers, so there is no need for them to be +visible outside of this file, and we therefore mark them as static. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + arch/arm/mach-mvebu/armada-370-xp.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/arch/arm/mach-mvebu/armada-370-xp.c ++++ b/arch/arm/mach-mvebu/armada-370-xp.c +@@ -38,18 +38,18 @@ static struct map_desc armada_370_xp_io_ + }, + }; + +-void __init armada_370_xp_map_io(void) ++static void __init armada_370_xp_map_io(void) + { + iotable_init(armada_370_xp_io_desc, ARRAY_SIZE(armada_370_xp_io_desc)); + } + +-void __init armada_370_xp_timer_and_clk_init(void) ++static void __init armada_370_xp_timer_and_clk_init(void) + { + mvebu_clocks_init(); + armada_370_xp_timer_init(); + } + +-void __init armada_370_xp_init_early(void) ++static void __init armada_370_xp_init_early(void) + { + char *mbus_soc_name; + diff --git a/target/linux/mvebu/patches-3.10/0013-drivers-memory-Introduce-Marvell-EBU-Device-Bus-driv.patch b/target/linux/mvebu/patches-3.10/0013-drivers-memory-Introduce-Marvell-EBU-Device-Bus-driv.patch new file mode 100644 index 0000000000..5f00e9f36e --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0013-drivers-memory-Introduce-Marvell-EBU-Device-Bus-driv.patch @@ -0,0 +1,568 @@ +From 8b417cc752ac4158dcfcf02beafce80b90fd827d Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Date: Tue, 23 Apr 2013 16:21:26 -0300 +Subject: [PATCH 013/203] drivers: memory: Introduce Marvell EBU Device Bus + driver + +Marvell EBU SoCs such as Armada 370/XP, Orion5x (88f5xxx) and +Discovery (mv78xx0) supports a Device Bus controller to access several +kinds of memories and I/O devices (NOR, NAND, SRAM, FPGA). + +This commit adds a driver to handle this controller. So far only +Armada 370, Armada XP and Discovery SoCs are supported. + +The driver must be registered through a device tree node; +as explained in the binding document. + +For each child node in the device tree, this driver will: + * set timing parameters + * register a child device + * setup an address decoding window, using the mbus driver + +Keep in mind the address decoding window setup is only a temporary hack. +This code will be removed from this devbus driver as soon as a proper device +tree binding for the mbus driver is added. + +Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Acked-by: Jason Cooper <jason@lakedaemon.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + .../bindings/memory-controllers/mvebu-devbus.txt | 156 ++++++++++ + drivers/memory/Kconfig | 10 + + drivers/memory/Makefile | 1 + + drivers/memory/mvebu-devbus.c | 340 +++++++++++++++++++++ + 4 files changed, 507 insertions(+) + create mode 100644 Documentation/devicetree/bindings/memory-controllers/mvebu-devbus.txt + create mode 100644 drivers/memory/mvebu-devbus.c + +--- /dev/null ++++ b/Documentation/devicetree/bindings/memory-controllers/mvebu-devbus.txt +@@ -0,0 +1,156 @@ ++Device tree bindings for MVEBU Device Bus controllers ++ ++The Device Bus controller available in some Marvell's SoC allows to control ++different types of standard memory and I/O devices such as NOR, NAND, and FPGA. ++The actual devices are instantiated from the child nodes of a Device Bus node. ++ ++Required properties: ++ ++ - compatible: Currently only Armada 370/XP SoC are supported, ++ with this compatible string: ++ ++ marvell,mvebu-devbus ++ ++ - reg: A resource specifier for the register space. ++ This is the base address of a chip select within ++ the controller's register space. ++ (see the example below) ++ ++ - #address-cells: Must be set to 1 ++ - #size-cells: Must be set to 1 ++ - ranges: Must be set up to reflect the memory layout with four ++ integer values for each chip-select line in use: ++ 0 <physical address of mapping> <size> ++ ++Mandatory timing properties for child nodes: ++ ++Read parameters: ++ ++ - devbus,turn-off-ps: Defines the time during which the controller does not ++ drive the AD bus after the completion of a device read. ++ This prevents contentions on the Device Bus after a read ++ cycle from a slow device. ++ ++ - devbus,bus-width: Defines the bus width (e.g. <16>) ++ ++ - devbus,badr-skew-ps: Defines the time delay from from A[2:0] toggle, ++ to read data sample. This parameter is useful for ++ synchronous pipelined devices, where the address ++ precedes the read data by one or two cycles. ++ ++ - devbus,acc-first-ps: Defines the time delay from the negation of ++ ALE[0] to the cycle that the first read data is sampled ++ by the controller. ++ ++ - devbus,acc-next-ps: Defines the time delay between the cycle that ++ samples data N and the cycle that samples data N+1 ++ (in burst accesses). ++ ++ - devbus,rd-setup-ps: Defines the time delay between DEV_CSn assertion to ++ DEV_OEn assertion. If set to 0 (default), ++ DEV_OEn and DEV_CSn are asserted at the same cycle. ++ This parameter has no affect on <acc-first-ps> parameter ++ (no affect on first data sample). Set <rd-setup-ps> ++ to a value smaller than <acc-first-ps>. ++ ++ - devbus,rd-hold-ps: Defines the time between the last data sample to the ++ de-assertion of DEV_CSn. If set to 0 (default), ++ DEV_OEn and DEV_CSn are de-asserted at the same cycle ++ (the cycle of the last data sample). ++ This parameter has no affect on DEV_OEn de-assertion. ++ DEV_OEn is always de-asserted the next cycle after ++ last data sampled. Also this parameter has no ++ affect on <turn-off-ps> parameter. ++ Set <rd-hold-ps> to a value smaller than <turn-off-ps>. ++ ++Write parameters: ++ ++ - devbus,ale-wr-ps: Defines the time delay from the ALE[0] negation cycle ++ to the DEV_WEn assertion. ++ ++ - devbus,wr-low-ps: Defines the time during which DEV_WEn is active. ++ A[2:0] and Data are kept valid as long as DEV_WEn ++ is active. This parameter defines the setup time of ++ address and data to DEV_WEn rise. ++ ++ - devbus,wr-high-ps: Defines the time during which DEV_WEn is kept ++ inactive (high) between data beats of a burst write. ++ DEV_A[2:0] and Data are kept valid (do not toggle) for ++ <wr-high-ps> - <tick> ps. ++ This parameter defines the hold time of address and ++ data after DEV_WEn rise. ++ ++ - devbus,sync-enable: Synchronous device enable. ++ 1: True ++ 0: False ++ ++An example for an Armada XP GP board, with a 16 MiB NOR device as child ++is showed below. Note that the Device Bus driver is in charge of allocating ++the mbus address decoding window for each of its child devices. ++The window is created using the chip select specified in the child ++device node together with the base address and size specified in the ranges ++property. For instance, in the example below the allocated decoding window ++will start at base address 0xf0000000, with a size 0x1000000 (16 MiB) ++for chip select 0 (a.k.a DEV_BOOTCS). ++ ++This address window handling is done in this mvebu-devbus only as a temporary ++solution. It will be removed when the support for mbus device tree binding is ++added. ++ ++The reg property implicitly specifies the chip select as this: ++ ++ 0x10400: DEV_BOOTCS ++ 0x10408: DEV_CS0 ++ 0x10410: DEV_CS1 ++ 0x10418: DEV_CS2 ++ 0x10420: DEV_CS3 ++ ++Example: ++ ++ devbus-bootcs@d0010400 { ++ status = "okay"; ++ ranges = <0 0xf0000000 0x1000000>; /* @addr 0xf0000000, size 0x1000000 */ ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ /* Device Bus parameters are required */ ++ ++ /* Read parameters */ ++ devbus,bus-width = <8>; ++ devbus,turn-off-ps = <60000>; ++ devbus,badr-skew-ps = <0>; ++ devbus,acc-first-ps = <124000>; ++ devbus,acc-next-ps = <248000>; ++ devbus,rd-setup-ps = <0>; ++ devbus,rd-hold-ps = <0>; ++ ++ /* Write parameters */ ++ devbus,sync-enable = <0>; ++ devbus,wr-high-ps = <60000>; ++ devbus,wr-low-ps = <60000>; ++ devbus,ale-wr-ps = <60000>; ++ ++ flash@0 { ++ compatible = "cfi-flash"; ++ ++ /* 16 MiB */ ++ reg = <0 0x1000000>; ++ bank-width = <2>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ /* ++ * We split the 16 MiB in two partitions, ++ * just as an example. ++ */ ++ partition@0 { ++ label = "First"; ++ reg = <0 0x800000>; ++ }; ++ ++ partition@800000 { ++ label = "Second"; ++ reg = <0x800000 0x800000>; ++ }; ++ }; ++ }; +--- a/drivers/memory/Kconfig ++++ b/drivers/memory/Kconfig +@@ -20,6 +20,16 @@ config TI_EMIF + parameters and other settings during frequency, voltage and + temperature changes + ++config MVEBU_DEVBUS ++ bool "Marvell EBU Device Bus Controller" ++ default y ++ depends on PLAT_ORION && OF ++ help ++ This driver is for the Device Bus controller available in some ++ Marvell EBU SoCs such as Discovery (mv78xx0), Orion (88f5xxx) and ++ Armada 370 and Armada XP. This controller allows to handle flash ++ devices such as NOR, NAND, SRAM, and FPGA. ++ + config TEGRA20_MC + bool "Tegra20 Memory Controller(MC) driver" + default y +--- a/drivers/memory/Makefile ++++ b/drivers/memory/Makefile +@@ -6,5 +6,6 @@ ifeq ($(CONFIG_DDR),y) + obj-$(CONFIG_OF) += of_memory.o + endif + obj-$(CONFIG_TI_EMIF) += emif.o ++obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o + obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o + obj-$(CONFIG_TEGRA30_MC) += tegra30-mc.o +--- /dev/null ++++ b/drivers/memory/mvebu-devbus.c +@@ -0,0 +1,340 @@ ++/* ++ * Marvell EBU SoC Device Bus Controller ++ * (memory controller for NOR/NAND/SRAM/FPGA devices) ++ * ++ * Copyright (C) 2013 Marvell ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ * ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/slab.h> ++#include <linux/err.h> ++#include <linux/io.h> ++#include <linux/clk.h> ++#include <linux/mbus.h> ++#include <linux/of_platform.h> ++#include <linux/of_address.h> ++#include <linux/platform_device.h> ++ ++/* Register definitions */ ++#define DEV_WIDTH_BIT 30 ++#define BADR_SKEW_BIT 28 ++#define RD_HOLD_BIT 23 ++#define ACC_NEXT_BIT 17 ++#define RD_SETUP_BIT 12 ++#define ACC_FIRST_BIT 6 ++ ++#define SYNC_ENABLE_BIT 24 ++#define WR_HIGH_BIT 16 ++#define WR_LOW_BIT 8 ++ ++#define READ_PARAM_OFFSET 0x0 ++#define WRITE_PARAM_OFFSET 0x4 ++ ++static const char * const devbus_wins[] = { ++ "devbus-boot", ++ "devbus-cs0", ++ "devbus-cs1", ++ "devbus-cs2", ++ "devbus-cs3", ++}; ++ ++struct devbus_read_params { ++ u32 bus_width; ++ u32 badr_skew; ++ u32 turn_off; ++ u32 acc_first; ++ u32 acc_next; ++ u32 rd_setup; ++ u32 rd_hold; ++}; ++ ++struct devbus_write_params { ++ u32 sync_enable; ++ u32 wr_high; ++ u32 wr_low; ++ u32 ale_wr; ++}; ++ ++struct devbus { ++ struct device *dev; ++ void __iomem *base; ++ unsigned long tick_ps; ++}; ++ ++static int get_timing_param_ps(struct devbus *devbus, ++ struct device_node *node, ++ const char *name, ++ u32 *ticks) ++{ ++ u32 time_ps; ++ int err; ++ ++ err = of_property_read_u32(node, name, &time_ps); ++ if (err < 0) { ++ dev_err(devbus->dev, "%s has no '%s' property\n", ++ name, node->full_name); ++ return err; ++ } ++ ++ *ticks = (time_ps + devbus->tick_ps - 1) / devbus->tick_ps; ++ ++ dev_dbg(devbus->dev, "%s: %u ps -> 0x%x\n", ++ name, time_ps, *ticks); ++ return 0; ++} ++ ++static int devbus_set_timing_params(struct devbus *devbus, ++ struct device_node *node) ++{ ++ struct devbus_read_params r; ++ struct devbus_write_params w; ++ u32 value; ++ int err; ++ ++ dev_dbg(devbus->dev, "Setting timing parameter, tick is %lu ps\n", ++ devbus->tick_ps); ++ ++ /* Get read timings */ ++ err = of_property_read_u32(node, "devbus,bus-width", &r.bus_width); ++ if (err < 0) { ++ dev_err(devbus->dev, ++ "%s has no 'devbus,bus-width' property\n", ++ node->full_name); ++ return err; ++ } ++ /* Convert bit width to byte width */ ++ r.bus_width /= 8; ++ ++ err = get_timing_param_ps(devbus, node, "devbus,badr-skew-ps", ++ &r.badr_skew); ++ if (err < 0) ++ return err; ++ ++ err = get_timing_param_ps(devbus, node, "devbus,turn-off-ps", ++ &r.turn_off); ++ if (err < 0) ++ return err; ++ ++ err = get_timing_param_ps(devbus, node, "devbus,acc-first-ps", ++ &r.acc_first); ++ if (err < 0) ++ return err; ++ ++ err = get_timing_param_ps(devbus, node, "devbus,acc-next-ps", ++ &r.acc_next); ++ if (err < 0) ++ return err; ++ ++ err = get_timing_param_ps(devbus, node, "devbus,rd-setup-ps", ++ &r.rd_setup); ++ if (err < 0) ++ return err; ++ ++ err = get_timing_param_ps(devbus, node, "devbus,rd-hold-ps", ++ &r.rd_hold); ++ if (err < 0) ++ return err; ++ ++ /* Get write timings */ ++ err = of_property_read_u32(node, "devbus,sync-enable", ++ &w.sync_enable); ++ if (err < 0) { ++ dev_err(devbus->dev, ++ "%s has no 'devbus,sync-enable' property\n", ++ node->full_name); ++ return err; ++ } ++ ++ err = get_timing_param_ps(devbus, node, "devbus,ale-wr-ps", ++ &w.ale_wr); ++ if (err < 0) ++ return err; ++ ++ err = get_timing_param_ps(devbus, node, "devbus,wr-low-ps", ++ &w.wr_low); ++ if (err < 0) ++ return err; ++ ++ err = get_timing_param_ps(devbus, node, "devbus,wr-high-ps", ++ &w.wr_high); ++ if (err < 0) ++ return err; ++ ++ /* Set read timings */ ++ value = r.bus_width << DEV_WIDTH_BIT | ++ r.badr_skew << BADR_SKEW_BIT | ++ r.rd_hold << RD_HOLD_BIT | ++ r.acc_next << ACC_NEXT_BIT | ++ r.rd_setup << RD_SETUP_BIT | ++ r.acc_first << ACC_FIRST_BIT | ++ r.turn_off; ++ ++ dev_dbg(devbus->dev, "read parameters register 0x%p = 0x%x\n", ++ devbus->base + READ_PARAM_OFFSET, ++ value); ++ ++ writel(value, devbus->base + READ_PARAM_OFFSET); ++ ++ /* Set write timings */ ++ value = w.sync_enable << SYNC_ENABLE_BIT | ++ w.wr_low << WR_LOW_BIT | ++ w.wr_high << WR_HIGH_BIT | ++ w.ale_wr; ++ ++ dev_dbg(devbus->dev, "write parameters register: 0x%p = 0x%x\n", ++ devbus->base + WRITE_PARAM_OFFSET, ++ value); ++ ++ writel(value, devbus->base + WRITE_PARAM_OFFSET); ++ ++ return 0; ++} ++ ++static int mvebu_devbus_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *node = pdev->dev.of_node; ++ struct device_node *parent; ++ struct devbus *devbus; ++ struct resource *res; ++ struct clk *clk; ++ unsigned long rate; ++ const __be32 *ranges; ++ int err, cs; ++ int addr_cells, p_addr_cells, size_cells; ++ int ranges_len, tuple_len; ++ u32 base, size; ++ ++ devbus = devm_kzalloc(&pdev->dev, sizeof(struct devbus), GFP_KERNEL); ++ if (!devbus) ++ return -ENOMEM; ++ ++ devbus->dev = dev; ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ devbus->base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(devbus->base)) ++ return PTR_ERR(devbus->base); ++ ++ clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(clk)) ++ return PTR_ERR(clk); ++ clk_prepare_enable(clk); ++ ++ /* ++ * Obtain clock period in picoseconds, ++ * we need this in order to convert timing ++ * parameters from cycles to picoseconds. ++ */ ++ rate = clk_get_rate(clk) / 1000; ++ devbus->tick_ps = 1000000000 / rate; ++ ++ /* Read the device tree node and set the new timing parameters */ ++ err = devbus_set_timing_params(devbus, node); ++ if (err < 0) ++ return err; ++ ++ /* ++ * Allocate an address window for this device. ++ * If the device probing fails, then we won't be able to ++ * remove the allocated address decoding window. ++ * ++ * FIXME: This is only a temporary hack! We need to do this here ++ * because we still don't have device tree bindings for mbus. ++ * Once that support is added, we will declare these address windows ++ * statically in the device tree, and remove the window configuration ++ * from here. ++ */ ++ ++ /* ++ * Get the CS to choose the window string. ++ * This is a bit hacky, but it will be removed once the ++ * address windows are declared in the device tree. ++ */ ++ cs = (((unsigned long)devbus->base) % 0x400) / 8; ++ ++ /* ++ * Parse 'ranges' property to obtain a (base,size) window tuple. ++ * This will be removed once the address windows ++ * are declared in the device tree. ++ */ ++ parent = of_get_parent(node); ++ if (!parent) ++ return -EINVAL; ++ ++ p_addr_cells = of_n_addr_cells(parent); ++ of_node_put(parent); ++ ++ addr_cells = of_n_addr_cells(node); ++ size_cells = of_n_size_cells(node); ++ tuple_len = (p_addr_cells + addr_cells + size_cells) * sizeof(__be32); ++ ++ ranges = of_get_property(node, "ranges", &ranges_len); ++ if (ranges == NULL || ranges_len != tuple_len) ++ return -EINVAL; ++ ++ base = of_translate_address(node, ranges + addr_cells); ++ if (base == OF_BAD_ADDR) ++ return -EINVAL; ++ size = of_read_number(ranges + addr_cells + p_addr_cells, size_cells); ++ ++ /* ++ * Create an mbus address windows. ++ * FIXME: Remove this, together with the above code, once the ++ * address windows are declared in the device tree. ++ */ ++ err = mvebu_mbus_add_window(devbus_wins[cs], base, size); ++ if (err < 0) ++ return err; ++ ++ /* ++ * We need to create a child device explicitly from here to ++ * guarantee that the child will be probed after the timing ++ * parameters for the bus are written. ++ */ ++ err = of_platform_populate(node, NULL, NULL, dev); ++ if (err < 0) { ++ mvebu_mbus_del_window(base, size); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static const struct of_device_id mvebu_devbus_of_match[] = { ++ { .compatible = "marvell,mvebu-devbus" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mvebu_devbus_of_match); ++ ++static struct platform_driver mvebu_devbus_driver = { ++ .probe = mvebu_devbus_probe, ++ .driver = { ++ .name = "mvebu-devbus", ++ .owner = THIS_MODULE, ++ .of_match_table = mvebu_devbus_of_match, ++ }, ++}; ++ ++static int __init mvebu_devbus_init(void) ++{ ++ return platform_driver_register(&mvebu_devbus_driver); ++} ++module_init(mvebu_devbus_init); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@free-electrons.com>"); ++MODULE_DESCRIPTION("Marvell EBU SoC Device Bus controller"); diff --git a/target/linux/mvebu/patches-3.10/0014-arm-mvebu-enable-two-USB-interfaces-on-the-Armada-XP.patch b/target/linux/mvebu/patches-3.10/0014-arm-mvebu-enable-two-USB-interfaces-on-the-Armada-XP.patch new file mode 100644 index 0000000000..120e14d8ed --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0014-arm-mvebu-enable-two-USB-interfaces-on-the-Armada-XP.patch @@ -0,0 +1,35 @@ +From 348fc73a301b88ec3f2da8c1f02858c75e79455e Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Tue, 21 May 2013 19:53:09 +0200 +Subject: [PATCH 014/203] arm: mvebu: enable two USB interfaces on the Armada + XP GP board + +The Armada XP GP board has two USB slots: one on the front side and +one on the back side. This commit enables the two USB host controllers +that correspond to those wo USB slots. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + arch/arm/boot/dts/armada-xp-gp.dts | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/arch/arm/boot/dts/armada-xp-gp.dts ++++ b/arch/arm/boot/dts/armada-xp-gp.dts +@@ -105,6 +105,16 @@ + phy-mode = "rgmii-id"; + }; + ++ /* Front-side USB slot */ ++ usb@50000 { ++ status = "okay"; ++ }; ++ ++ /* Back-side USB slot */ ++ usb@51000 { ++ status = "okay"; ++ }; ++ + spi0: spi@10600 { + status = "okay"; + diff --git a/target/linux/mvebu/patches-3.10/0015-pci-mvebu-no-longer-fake-the-slot-location-of-downst.patch b/target/linux/mvebu/patches-3.10/0015-pci-mvebu-no-longer-fake-the-slot-location-of-downst.patch new file mode 100644 index 0000000000..c3dd1f1320 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0015-pci-mvebu-no-longer-fake-the-slot-location-of-downst.patch @@ -0,0 +1,97 @@ +From 34361044442206dd7d10ff3309f8e0713e0fd856 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Thu, 23 May 2013 16:32:51 +0200 +Subject: [PATCH 015/203] pci: mvebu: no longer fake the slot location of + downstream devices + +By default, the Marvell hardware, for each PCIe interface, exhibits +the following devices: + + * On slot 0, a "Marvell Memory controller", identical on all PCIe + interfaces, and which isn't useful when the Marvell SoC is the PCIe + root complex (i.e, the normal case when we run Linux on the Marvell + SoC). + + * On slot 1, the real PCIe card connected into the PCIe slot of the + board. + +So, what the Marvell PCIe driver was doing in its PCI-to-PCI bridge +emulation is that when the Linux PCI core was trying to access the +device in slot 0, we were in fact forwarding the configuration +transaction to the device in slot 1. For all other slots, we were +telling the Linux PCI core that there was no device connected. + +However, new versions of bootloaders from Marvell change the default +PCIe configuration, and make the real device appear in slot 0, and the +"Marvell Memory controller" in slot 1. + +Therefore, this commit modifies the Marvell PCIe driver to adjust the +PCIe hardware configuration to make sure that this behavior (real +device in slot 0, "Marvell Memory controller" in slot 1) is the one +we'll see regardless of what the bootloader has done. It allows to +remove the little hack that was forwarding configuration transactions +on slot 0 to slot 1, which is nice. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Acked-by: Bjorn Helgaas <bhelgaas@google.com> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + drivers/pci/host/pci-mvebu.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +--- a/drivers/pci/host/pci-mvebu.c ++++ b/drivers/pci/host/pci-mvebu.c +@@ -51,6 +51,7 @@ + #define PCIE_CTRL_X1_MODE 0x0001 + #define PCIE_STAT_OFF 0x1a04 + #define PCIE_STAT_BUS 0xff00 ++#define PCIE_STAT_DEV 0x1f0000 + #define PCIE_STAT_LINK_DOWN BIT(0) + #define PCIE_DEBUG_CTRL 0x1a60 + #define PCIE_DEBUG_SOFT_RESET BIT(20) +@@ -148,6 +149,16 @@ static void mvebu_pcie_set_local_bus_nr( + writel(stat, port->base + PCIE_STAT_OFF); + } + ++static void mvebu_pcie_set_local_dev_nr(struct mvebu_pcie_port *port, int nr) ++{ ++ u32 stat; ++ ++ stat = readl(port->base + PCIE_STAT_OFF); ++ stat &= ~PCIE_STAT_DEV; ++ stat |= nr << 16; ++ writel(stat, port->base + PCIE_STAT_OFF); ++} ++ + /* + * Setup PCIE BARs and Address Decode Wins: + * BAR[0,2] -> disabled, BAR[1] -> covers all DRAM banks +@@ -572,8 +583,7 @@ static int mvebu_pcie_wr_conf(struct pci + + /* Access the real PCIe interface */ + spin_lock_irqsave(&port->conf_lock, flags); +- ret = mvebu_pcie_hw_wr_conf(port, bus, +- PCI_DEVFN(1, PCI_FUNC(devfn)), ++ ret = mvebu_pcie_hw_wr_conf(port, bus, devfn, + where, size, val); + spin_unlock_irqrestore(&port->conf_lock, flags); + +@@ -606,8 +616,7 @@ static int mvebu_pcie_rd_conf(struct pci + + /* Access the real PCIe interface */ + spin_lock_irqsave(&port->conf_lock, flags); +- ret = mvebu_pcie_hw_rd_conf(port, bus, +- PCI_DEVFN(1, PCI_FUNC(devfn)), ++ ret = mvebu_pcie_hw_rd_conf(port, bus, devfn, + where, size, val); + spin_unlock_irqrestore(&port->conf_lock, flags); + +@@ -817,6 +826,8 @@ static int __init mvebu_pcie_probe(struc + continue; + } + ++ mvebu_pcie_set_local_dev_nr(port, 1); ++ + if (mvebu_pcie_link_up(port)) { + port->haslink = 1; + dev_info(&pdev->dev, "PCIe%d.%d: link up\n", diff --git a/target/linux/mvebu/patches-3.10/0016-pci-mvebu-allow-the-enumeration-of-devices-beyond-ph.patch b/target/linux/mvebu/patches-3.10/0016-pci-mvebu-allow-the-enumeration-of-devices-beyond-ph.patch new file mode 100644 index 0000000000..bda383a105 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0016-pci-mvebu-allow-the-enumeration-of-devices-beyond-ph.patch @@ -0,0 +1,97 @@ +From 10f725e3a9e73aab2e5601206c88cf9cbc599243 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Thu, 23 May 2013 16:32:52 +0200 +Subject: [PATCH 016/203] pci: mvebu: allow the enumeration of devices beyond + physical bridges + +Until now, the Marvell PCIe driver was only allowing the enumeration +of the devices in the secondary bus of the emulated PCI-to-PCI +bridge. This works fine when a PCIe device is directly connected into +a PCIe slot of the Marvell board. + +However, when the device connected in the PCIe slot is a physical PCIe +bridge, beyond which a real PCIe device is connected, it no longer +worked, as the driver was preventing the Linux PCI core from seeing +such devices. + +This commit fixes that by ensuring that configuration transactions on +subordinate busses are properly forwarded on the right PCIe interface. + +Thanks to this patch, a PCIe card beyond a PCIe bridge, itself beyond +the emulated PCI-to-PCI bridge is properly detected, with the +following layout: + +-[0000:00]-+-01.0-[01]----00.0 + +-09.0-[02-07]----00.0-[03-07]--+-01.0-[04]-- + | +-05.0-[05]-- + | +-07.0-[06]-- + | \-09.0-[07]----00.0 + \-0a.0-[08]----00.0 + +Where the PCIe interface that sits beyond the emulated PCI-to-PCI +bridge at 09.0 allows to access the secondary bus 02, on which there +is a PCIe bridge that allows to access the 3 to 7 busses, that are +subordinates to this bridge. And on one of this bus (bus 7), there is +one real PCIe device connected. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Acked-by: Bjorn Helgaas <bhelgaas@google.com> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + drivers/pci/host/pci-mvebu.c | 31 ++++++++++++++++++++++++++++--- + 1 file changed, 28 insertions(+), 3 deletions(-) + +--- a/drivers/pci/host/pci-mvebu.c ++++ b/drivers/pci/host/pci-mvebu.c +@@ -554,7 +554,8 @@ mvebu_pcie_find_port(struct mvebu_pcie * + if (bus->number == 0 && port->devfn == devfn) + return port; + if (bus->number != 0 && +- port->bridge.secondary_bus == bus->number) ++ bus->number >= port->bridge.secondary_bus && ++ bus->number <= port->bridge.subordinate_bus) + return port; + } + +@@ -578,7 +579,18 @@ static int mvebu_pcie_wr_conf(struct pci + if (bus->number == 0) + return mvebu_sw_pci_bridge_write(port, where, size, val); + +- if (!port->haslink || PCI_SLOT(devfn) != 0) ++ if (!port->haslink) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ /* ++ * On the secondary bus, we don't want to expose any other ++ * device than the device physically connected in the PCIe ++ * slot, visible in slot 0. In slot 1, there's a special ++ * Marvell device that only makes sense when the Armada is ++ * used as a PCIe endpoint. ++ */ ++ if (bus->number == port->bridge.secondary_bus && ++ PCI_SLOT(devfn) != 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* Access the real PCIe interface */ +@@ -609,7 +621,20 @@ static int mvebu_pcie_rd_conf(struct pci + if (bus->number == 0) + return mvebu_sw_pci_bridge_read(port, where, size, val); + +- if (!port->haslink || PCI_SLOT(devfn) != 0) { ++ if (!port->haslink) { ++ *val = 0xffffffff; ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ } ++ ++ /* ++ * On the secondary bus, we don't want to expose any other ++ * device than the device physically connected in the PCIe ++ * slot, visible in slot 0. In slot 1, there's a special ++ * Marvell device that only makes sense when the Armada is ++ * used as a PCIe endpoint. ++ */ ++ if (bus->number == port->bridge.secondary_bus && ++ PCI_SLOT(devfn) != 0) { + *val = 0xffffffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } diff --git a/target/linux/mvebu/patches-3.10/0017-pci-mvebu-fix-the-emulation-of-the-status-register.patch b/target/linux/mvebu/patches-3.10/0017-pci-mvebu-fix-the-emulation-of-the-status-register.patch new file mode 100644 index 0000000000..9da0c58f13 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0017-pci-mvebu-fix-the-emulation-of-the-status-register.patch @@ -0,0 +1,87 @@ +From 33e771556f5e1a59c7dbcd953ce858dd3e50ed66 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Thu, 23 May 2013 16:32:53 +0200 +Subject: [PATCH 017/203] pci: mvebu: fix the emulation of the status register + +The status register of the PCI configuration space of PCI-to-PCI +bridges contain some read-only bits, and so write-1-to-clear bits. So, +the Linux PCI core sometimes writes 0xffff to this status register, +and in the current PCI-to-PCI bridge emulation code of the Marvell +driver, we do take all those 1s being written. Even the read-only bits +are being overwritten. + +For now, all the read-only bits should be emulated to have the zero +value. + +The other bits, that are write-1-to-clear bits are used to report +various kind of errors, and are never set by the emulated bridge, so +there is no need to support this write-1-to-clear bits mechanism. + +As a conclusion, the easiest solution is to simply emulate this status +register by returning zero when read, and ignore the writes to it. + +This has two visible effects: + + * The devsel is no longer 'unknown' in, i.e + + Flags: bus master, 66MHz, user-definable features, ?? devsel, latency 0 + + becomes: + + Flags: bus master, 66MHz, user-definable features, fast devsel, latency 0 + + in lspci -v. + + This was caused by a value of 11b being read for devsel, which is + an invalid value. This 11b value being read was due to a previous + write of 0xffff into the status register. + + * The capability list is no longer broken, because we indicate to the + Linux PCI core that we don't have a Capabilities Pointer in the PCI + configuration space of this bridge. The following message is + therefore no longer visible in lspci -v: + + Capabilities: [fc] <chain broken> + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Acked-by: Bjorn Helgaas <bhelgaas@google.com> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + drivers/pci/host/pci-mvebu.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +--- a/drivers/pci/host/pci-mvebu.c ++++ b/drivers/pci/host/pci-mvebu.c +@@ -69,7 +69,6 @@ struct mvebu_sw_pci_bridge { + u16 vendor; + u16 device; + u16 command; +- u16 status; + u16 class; + u8 interface; + u8 revision; +@@ -359,7 +358,6 @@ static void mvebu_sw_pci_bridge_init(str + + memset(bridge, 0, sizeof(struct mvebu_sw_pci_bridge)); + +- bridge->status = PCI_STATUS_CAP_LIST; + bridge->class = PCI_CLASS_BRIDGE_PCI; + bridge->vendor = PCI_VENDOR_ID_MARVELL; + bridge->device = MARVELL_EMULATED_PCI_PCI_BRIDGE_ID; +@@ -386,7 +384,7 @@ static int mvebu_sw_pci_bridge_read(stru + break; + + case PCI_COMMAND: +- *value = bridge->status << 16 | bridge->command; ++ *value = bridge->command; + break; + + case PCI_CLASS_REVISION: +@@ -479,7 +477,6 @@ static int mvebu_sw_pci_bridge_write(str + switch (where & ~3) { + case PCI_COMMAND: + bridge->command = value & 0xffff; +- bridge->status = value >> 16; + break; + + case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1: diff --git a/target/linux/mvebu/patches-3.10/0018-arm-mvebu-fix-length-of-SATA-registers-area-in-.dtsi.patch b/target/linux/mvebu/patches-3.10/0018-arm-mvebu-fix-length-of-SATA-registers-area-in-.dtsi.patch new file mode 100644 index 0000000000..5a78cc5113 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0018-arm-mvebu-fix-length-of-SATA-registers-area-in-.dtsi.patch @@ -0,0 +1,30 @@ +From fc7dfe5cd096f5b5343f01f679a96ebc23e9da67 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Tue, 21 May 2013 12:33:26 +0200 +Subject: [PATCH 018/203] arm: mvebu: fix length of SATA registers area in + .dtsi + +The length of the registers area for the Marvell 370/XP SATA +controller was incorrect in the .dtsi: 0x2400 while it should have +been 0x5000. Until now, this problem wasn't noticed because there was +a large static mapping for all I/Os set up by ->map_io(). But since +we're going to get rid of this static mapping, we need to ensure that +the register areas are properly sized. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + arch/arm/boot/dts/armada-370-xp.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/armada-370-xp.dtsi ++++ b/arch/arm/boot/dts/armada-370-xp.dtsi +@@ -80,7 +80,7 @@ + + sata@a0000 { + compatible = "marvell,orion-sata"; +- reg = <0xa0000 0x2400>; ++ reg = <0xa0000 0x5000>; + interrupts = <55>; + clocks = <&gateclk 15>, <&gateclk 30>; + clock-names = "0", "1"; diff --git a/target/linux/mvebu/patches-3.10/0019-arm-mvebu-fix-length-of-Ethernet-registers-area-in-..patch b/target/linux/mvebu/patches-3.10/0019-arm-mvebu-fix-length-of-Ethernet-registers-area-in-..patch new file mode 100644 index 0000000000..193d87c1ab --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0019-arm-mvebu-fix-length-of-Ethernet-registers-area-in-..patch @@ -0,0 +1,63 @@ +From d887da014c3fabf5fa4da47b143edc069e72fd62 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Tue, 21 May 2013 12:33:27 +0200 +Subject: [PATCH 019/203] arm: mvebu: fix length of Ethernet registers area in + .dtsi + +The length of the registers area for the Marvell 370/XP Ethernet +controller was incorrect in the .dtsi: 0x2400 while it should have +been 0x4000. Until now, this problem wasn't noticed because there was +a large static mapping for all I/Os set up by ->map_io(). But since +we're going to get rid of this static mapping, we need to ensure that +the register areas are properly sized. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + arch/arm/boot/dts/armada-370-xp.dtsi | 4 ++-- + arch/arm/boot/dts/armada-xp-mv78460.dtsi | 2 +- + arch/arm/boot/dts/armada-xp.dtsi | 2 +- + 3 files changed, 4 insertions(+), 4 deletions(-) + +--- a/arch/arm/boot/dts/armada-370-xp.dtsi ++++ b/arch/arm/boot/dts/armada-370-xp.dtsi +@@ -96,7 +96,7 @@ + + ethernet@70000 { + compatible = "marvell,armada-370-neta"; +- reg = <0x70000 0x2500>; ++ reg = <0x70000 0x4000>; + interrupts = <8>; + clocks = <&gateclk 4>; + status = "disabled"; +@@ -104,7 +104,7 @@ + + ethernet@74000 { + compatible = "marvell,armada-370-neta"; +- reg = <0x74000 0x2500>; ++ reg = <0x74000 0x4000>; + interrupts = <10>; + clocks = <&gateclk 3>; + status = "disabled"; +--- a/arch/arm/boot/dts/armada-xp-mv78460.dtsi ++++ b/arch/arm/boot/dts/armada-xp-mv78460.dtsi +@@ -107,7 +107,7 @@ + + ethernet@34000 { + compatible = "marvell,armada-370-neta"; +- reg = <0x34000 0x2500>; ++ reg = <0x34000 0x4000>; + interrupts = <14>; + clocks = <&gateclk 1>; + status = "disabled"; +--- a/arch/arm/boot/dts/armada-xp.dtsi ++++ b/arch/arm/boot/dts/armada-xp.dtsi +@@ -88,7 +88,7 @@ + + ethernet@30000 { + compatible = "marvell,armada-370-neta"; +- reg = <0x30000 0x2500>; ++ reg = <0x30000 0x4000>; + interrupts = <12>; + clocks = <&gateclk 2>; + status = "disabled"; diff --git a/target/linux/mvebu/patches-3.10/0020-net-mvneta-read-MAC-address-from-hardware-when-avail.patch b/target/linux/mvebu/patches-3.10/0020-net-mvneta-read-MAC-address-from-hardware-when-avail.patch new file mode 100644 index 0000000000..9866f0c537 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0020-net-mvneta-read-MAC-address-from-hardware-when-avail.patch @@ -0,0 +1,112 @@ +From 25d3318a445c4f4360f86bf6d1d1a320d9646bb5 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Tue, 4 Jun 2013 04:52:23 +0000 +Subject: [PATCH 020/203] net: mvneta: read MAC address from hardware when + available + +This patch improves the logic used by the mvneta driver to find a MAC +address for a particular interface. Until now, it was only looking at +the Device Tree, and if no address was found, was falling back to +generating a random MAC address. + +This patch adds the intermediate solution of reading the MAC address +from the hardware registers, in case it has been set by the +bootloader. So the order is now: + + 1) MAC address from the Device Tree + 2) MAC address from the hardware registers + 3) Random MAC address + +This requires moving the MAC address initialization a little bit later +in the ->probe() code, because it now requires the hardware registers +to be remapped. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Cc: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> +Cc: Joe Perches <joe@perches.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +--- + drivers/net/ethernet/marvell/mvneta.c | 44 ++++++++++++++++++++++++++++------- + 1 file changed, 35 insertions(+), 9 deletions(-) + +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -2260,6 +2260,21 @@ static int mvneta_change_mtu(struct net_ + return 0; + } + ++/* Get mac address */ ++static void mvneta_get_mac_addr(struct mvneta_port *pp, unsigned char *addr) ++{ ++ u32 mac_addr_l, mac_addr_h; ++ ++ mac_addr_l = mvreg_read(pp, MVNETA_MAC_ADDR_LOW); ++ mac_addr_h = mvreg_read(pp, MVNETA_MAC_ADDR_HIGH); ++ addr[0] = (mac_addr_h >> 24) & 0xFF; ++ addr[1] = (mac_addr_h >> 16) & 0xFF; ++ addr[2] = (mac_addr_h >> 8) & 0xFF; ++ addr[3] = mac_addr_h & 0xFF; ++ addr[4] = (mac_addr_l >> 8) & 0xFF; ++ addr[5] = mac_addr_l & 0xFF; ++} ++ + /* Handle setting mac address */ + static int mvneta_set_mac_addr(struct net_device *dev, void *addr) + { +@@ -2678,7 +2693,9 @@ static int mvneta_probe(struct platform_ + u32 phy_addr; + struct mvneta_port *pp; + struct net_device *dev; +- const char *mac_addr; ++ const char *dt_mac_addr; ++ char hw_mac_addr[ETH_ALEN]; ++ const char *mac_from; + int phy_mode; + int err; + +@@ -2714,13 +2731,6 @@ static int mvneta_probe(struct platform_ + goto err_free_irq; + } + +- mac_addr = of_get_mac_address(dn); +- +- if (!mac_addr || !is_valid_ether_addr(mac_addr)) +- eth_hw_addr_random(dev); +- else +- memcpy(dev->dev_addr, mac_addr, ETH_ALEN); +- + dev->tx_queue_len = MVNETA_MAX_TXD; + dev->watchdog_timeo = 5 * HZ; + dev->netdev_ops = &mvneta_netdev_ops; +@@ -2751,6 +2761,21 @@ static int mvneta_probe(struct platform_ + + clk_prepare_enable(pp->clk); + ++ dt_mac_addr = of_get_mac_address(dn); ++ if (dt_mac_addr && is_valid_ether_addr(dt_mac_addr)) { ++ mac_from = "device tree"; ++ memcpy(dev->dev_addr, dt_mac_addr, ETH_ALEN); ++ } else { ++ mvneta_get_mac_addr(pp, hw_mac_addr); ++ if (is_valid_ether_addr(hw_mac_addr)) { ++ mac_from = "hardware"; ++ memcpy(dev->dev_addr, hw_mac_addr, ETH_ALEN); ++ } else { ++ mac_from = "random"; ++ eth_hw_addr_random(dev); ++ } ++ } ++ + pp->tx_done_timer.data = (unsigned long)dev; + + pp->tx_ring_size = MVNETA_MAX_TXD; +@@ -2783,7 +2808,8 @@ static int mvneta_probe(struct platform_ + goto err_deinit; + } + +- netdev_info(dev, "mac: %pM\n", dev->dev_addr); ++ netdev_info(dev, "Using %s mac address %pM\n", mac_from, ++ dev->dev_addr); + + platform_set_drvdata(pdev, pp->dev); + diff --git a/target/linux/mvebu/patches-3.10/0021-arm-mvebu-armada-xp-db-ensure-PCIe-range-is-specifie.patch b/target/linux/mvebu/patches-3.10/0021-arm-mvebu-armada-xp-db-ensure-PCIe-range-is-specifie.patch new file mode 100644 index 0000000000..a57b6c8d06 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0021-arm-mvebu-armada-xp-db-ensure-PCIe-range-is-specifie.patch @@ -0,0 +1,31 @@ +From 67373874e07eb8c54ab27f8fe9998690e50b1e91 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Thu, 6 Jun 2013 11:21:23 +0200 +Subject: [PATCH 021/203] arm: mvebu: armada-xp-db: ensure PCIe range is + specified + +The ranges DT entry needed by the PCIe controller is defined at the +SoC .dtsi level. However, some boards have a NOR flash, and to support +it, they need to override the SoC-level ranges property to add an +additional range. Since PCIe and NOR support came separately, some +boards were not properly changed to include the PCIe range in their +ranges property at the .dts level. + +This commit fixes those platforms. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + arch/arm/boot/dts/armada-xp-db.dts | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/boot/dts/armada-xp-db.dts ++++ b/arch/arm/boot/dts/armada-xp-db.dts +@@ -31,6 +31,7 @@ + + soc { + ranges = <0 0 0xd0000000 0x100000 /* Internal registers 1MiB */ ++ 0xe0000000 0 0xe0000000 0x8100000 /* PCIe */ + 0xf0000000 0 0xf0000000 0x1000000>; /* Device Bus, NOR 16MiB */ + + internal-regs { diff --git a/target/linux/mvebu/patches-3.10/0022-bus-mvebu-mbus-Use-pr_fmt.patch b/target/linux/mvebu/patches-3.10/0022-bus-mvebu-mbus-Use-pr_fmt.patch new file mode 100644 index 0000000000..ab2e7b469b --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0022-bus-mvebu-mbus-Use-pr_fmt.patch @@ -0,0 +1,54 @@ +From 35e8d985e056f583290406258e3f17789bd05bce Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Date: Fri, 7 Jun 2013 13:47:38 -0300 +Subject: [PATCH 022/203] bus: mvebu-mbus: Use pr_fmt + +In order to clean message printing, we replace pr_info with pr_fmt. +This is purely cosmetic change, with the sole purpose of making +the code a bit more readable. + +Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Acked-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + drivers/bus/mvebu-mbus.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/drivers/bus/mvebu-mbus.c ++++ b/drivers/bus/mvebu-mbus.c +@@ -49,6 +49,8 @@ + * configuration (file 'devices'). + */ + ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ + #include <linux/kernel.h> + #include <linux/module.h> + #include <linux/init.h> +@@ -762,7 +764,7 @@ int mvebu_mbus_add_window_remap_flags(co + break; + + if (!s->soc->map[i].name) { +- pr_err("mvebu-mbus: unknown device '%s'\n", devname); ++ pr_err("unknown device '%s'\n", devname); + return -ENODEV; + } + +@@ -775,7 +777,7 @@ int mvebu_mbus_add_window_remap_flags(co + attr |= 0x28; + + if (!mvebu_mbus_window_conflicts(s, base, size, target, attr)) { +- pr_err("mvebu-mbus: cannot add window '%s', conflicts with another window\n", ++ pr_err("cannot add window '%s', conflicts with another window\n", + devname); + return -EINVAL; + } +@@ -842,7 +844,7 @@ int __init mvebu_mbus_init(const char *s + break; + + if (!of_id->compatible) { +- pr_err("mvebu-mbus: could not find a matching SoC family\n"); ++ pr_err("could not find a matching SoC family\n"); + return -ENODEV; + } + diff --git a/target/linux/mvebu/patches-3.10/0023-ARM-mvebu-Remove-device-tree-unused-properties-on-A3.patch b/target/linux/mvebu/patches-3.10/0023-ARM-mvebu-Remove-device-tree-unused-properties-on-A3.patch new file mode 100644 index 0000000000..39270c758c --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0023-ARM-mvebu-Remove-device-tree-unused-properties-on-A3.patch @@ -0,0 +1,28 @@ +From df8ceea297967c3452a514bbde715acebf3bda29 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Date: Fri, 7 Jun 2013 13:47:49 -0300 +Subject: [PATCH 023/203] ARM: mvebu: Remove device tree unused properties on + A370 + +These properties are not needed so it's safe to remove them. + +Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Acked-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + arch/arm/boot/dts/armada-370.dtsi | 4 ---- + 1 file changed, 4 deletions(-) + +--- a/arch/arm/boot/dts/armada-370.dtsi ++++ b/arch/arm/boot/dts/armada-370.dtsi +@@ -180,10 +180,6 @@ + + bus-range = <0x00 0xff>; + +- reg = <0x40000 0x2000>, <0x80000 0x2000>; +- +- reg-names = "pcie0.0", "pcie1.0"; +- + ranges = <0x82000000 0 0x40000 0x40000 0 0x00002000 /* Port 0.0 registers */ + 0x82000000 0 0x80000 0x80000 0 0x00002000 /* Port 1.0 registers */ + 0x82000000 0 0xe0000000 0xe0000000 0 0x08000000 /* non-prefetchable memory */ diff --git a/target/linux/mvebu/patches-3.10/0024-arm-mvebu-remove-dependency-of-SMP-init-on-static-I-.patch b/target/linux/mvebu/patches-3.10/0024-arm-mvebu-remove-dependency-of-SMP-init-on-static-I-.patch new file mode 100644 index 0000000000..38c908fb8c --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0024-arm-mvebu-remove-dependency-of-SMP-init-on-static-I-.patch @@ -0,0 +1,99 @@ +From 9398729313b826469fede3acda5fedd1eb21cb3e Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Wed, 5 Jun 2013 09:04:54 +0200 +Subject: [PATCH 024/203] arm: mvebu: remove dependency of SMP init on static + I/O mapping + +The ->smp_init_cpus() function is called very early during boot, at a +point where dynamic I/O mappings are not yet possible. However, in the +Armada 370/XP implementation of this function, we have to get the +number of CPUs. We used to do that by accessing a hardware register, +which requires relying on a static I/O mapping set up by +->map_io(). Not only this requires hardcoding a virtual address, but +it also prevents us from removing the static I/O mapping. + +So this commit changes the way used to get the number of CPUs: we now +use the Device Tree, which is a representation of the hardware, and +provides us the number of available CPUs. This is also more accurate, +because it potentially allows to boot the Linux kernel on only a +number of CPUs given by the Device Tree, instead of unconditionally on +all CPUs. + +As a consequence, the coherency_get_cpu_count() function becomes no +longer used, so we remove it. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + arch/arm/mach-mvebu/coherency.c | 12 ------------ + arch/arm/mach-mvebu/coherency.h | 4 ---- + arch/arm/mach-mvebu/common.h | 2 ++ + arch/arm/mach-mvebu/platsmp.c | 10 +++++++++- + 4 files changed, 11 insertions(+), 17 deletions(-) + +--- a/arch/arm/mach-mvebu/coherency.c ++++ b/arch/arm/mach-mvebu/coherency.c +@@ -47,18 +47,6 @@ static struct of_device_id of_coherency_ + { /* end of list */ }, + }; + +-#ifdef CONFIG_SMP +-int coherency_get_cpu_count(void) +-{ +- int reg, cnt; +- +- reg = readl(coherency_base + COHERENCY_FABRIC_CFG_OFFSET); +- cnt = (reg & 0xF) + 1; +- +- return cnt; +-} +-#endif +- + /* Function defined in coherency_ll.S */ + int ll_set_cpu_coherent(void __iomem *base_addr, unsigned int hw_cpu_id); + +--- a/arch/arm/mach-mvebu/coherency.h ++++ b/arch/arm/mach-mvebu/coherency.h +@@ -14,10 +14,6 @@ + #ifndef __MACH_370_XP_COHERENCY_H + #define __MACH_370_XP_COHERENCY_H + +-#ifdef CONFIG_SMP +-int coherency_get_cpu_count(void); +-#endif +- + int set_cpu_coherent(int cpu_id, int smp_group_id); + int coherency_init(void); + +--- a/arch/arm/mach-mvebu/common.h ++++ b/arch/arm/mach-mvebu/common.h +@@ -15,6 +15,8 @@ + #ifndef __ARCH_MVEBU_COMMON_H + #define __ARCH_MVEBU_COMMON_H + ++#define ARMADA_XP_MAX_CPUS 4 ++ + void mvebu_restart(char mode, const char *cmd); + + void armada_370_xp_init_irq(void); +--- a/arch/arm/mach-mvebu/platsmp.c ++++ b/arch/arm/mach-mvebu/platsmp.c +@@ -88,8 +88,16 @@ static int __cpuinit armada_xp_boot_seco + + static void __init armada_xp_smp_init_cpus(void) + { ++ struct device_node *np; + unsigned int i, ncores; +- ncores = coherency_get_cpu_count(); ++ ++ np = of_find_node_by_name(NULL, "cpus"); ++ if (!np) ++ panic("No 'cpus' node found\n"); ++ ++ ncores = of_get_child_count(np); ++ if (ncores == 0 || ncores > ARMADA_XP_MAX_CPUS) ++ panic("Invalid number of CPUs in DT\n"); + + /* Limit possible CPUs to defconfig */ + if (ncores > nr_cpu_ids) { diff --git a/target/linux/mvebu/patches-3.10/0025-arm-mvebu-avoid-hardcoded-virtual-address-in-coheren.patch b/target/linux/mvebu/patches-3.10/0025-arm-mvebu-avoid-hardcoded-virtual-address-in-coheren.patch new file mode 100644 index 0000000000..b6c3722e34 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0025-arm-mvebu-avoid-hardcoded-virtual-address-in-coheren.patch @@ -0,0 +1,81 @@ +From a4dd628f515f361cecfae08e568891442042e4e2 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Wed, 5 Jun 2013 09:04:55 +0200 +Subject: [PATCH 025/203] arm: mvebu: avoid hardcoded virtual address in + coherency code + +Now that the coherency_get_cpu_count() function no longer requires a +very early mapping of the coherency unit registers, we can avoid the +hardcoded virtual address in coherency.c. However, the coherency +features are still used quite early, so we need to do the of_iomap() +early enough, at the ->init_timer() level, so we have the call of +coherency_init() at this point. + +Unfortunately, at ->init_timer() time, it is not possible to register +a bus notifier, so we add a separate coherency_late_init() function +that gets called as as postcore_initcall(), when bus notifiers are +available. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + arch/arm/mach-mvebu/armada-370-xp.c | 2 +- + arch/arm/mach-mvebu/coherency.c | 20 ++++++++++---------- + 2 files changed, 11 insertions(+), 11 deletions(-) + +--- a/arch/arm/mach-mvebu/armada-370-xp.c ++++ b/arch/arm/mach-mvebu/armada-370-xp.c +@@ -47,6 +47,7 @@ static void __init armada_370_xp_timer_a + { + mvebu_clocks_init(); + armada_370_xp_timer_init(); ++ coherency_init(); + } + + static void __init armada_370_xp_init_early(void) +@@ -76,7 +77,6 @@ static void __init armada_370_xp_init_ea + static void __init armada_370_xp_dt_init(void) + { + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); +- coherency_init(); + } + + static const char * const armada_370_xp_dt_compat[] = { +--- a/arch/arm/mach-mvebu/coherency.c ++++ b/arch/arm/mach-mvebu/coherency.c +@@ -27,14 +27,7 @@ + #include <asm/smp_plat.h> + #include "armada-370-xp.h" + +-/* +- * Some functions in this file are called very early during SMP +- * initialization. At that time the device tree framework is not yet +- * ready, and it is not possible to get the register address to +- * ioremap it. That's why the pointer below is given with an initial +- * value matching its virtual mapping +- */ +-static void __iomem *coherency_base = ARMADA_370_XP_REGS_VIRT_BASE + 0x20200; ++static void __iomem *coherency_base; + static void __iomem *coherency_cpu_base; + + /* Coherency fabric registers */ +@@ -135,9 +128,16 @@ int __init coherency_init(void) + coherency_base = of_iomap(np, 0); + coherency_cpu_base = of_iomap(np, 1); + set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0); +- bus_register_notifier(&platform_bus_type, +- &mvebu_hwcc_platform_nb); + } + + return 0; + } ++ ++static int __init coherency_late_init(void) ++{ ++ bus_register_notifier(&platform_bus_type, ++ &mvebu_hwcc_platform_nb); ++ return 0; ++} ++ ++postcore_initcall(coherency_late_init); diff --git a/target/linux/mvebu/patches-3.10/0026-arm-mvebu-move-cache-and-mvebu-mbus-initialization-l.patch b/target/linux/mvebu/patches-3.10/0026-arm-mvebu-move-cache-and-mvebu-mbus-initialization-l.patch new file mode 100644 index 0000000000..de2ed7377c --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0026-arm-mvebu-move-cache-and-mvebu-mbus-initialization-l.patch @@ -0,0 +1,54 @@ +From c7c7e6309ae12f2cb0d9053875876b57bb7587e4 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Wed, 5 Jun 2013 09:04:56 +0200 +Subject: [PATCH 026/203] arm: mvebu: move cache and mvebu-mbus initialization + later + +Current, the L2 cache and the mvebu-mbus drivers are initialized at +->init_early() time. However, at ->init_early() time, ioremap() only +works if a static I/O mapping has already been put in place. If it's +not the case, it tries to do a memory allocation with kmalloc() which +is not possible so early at this stage of the initialization. + +Since we want to get rid of the static I/O mapping, we cannot +initialize the L2 cache driver and the mvebu-mbus driver so early. So, +we move their initialization to the ->init_time() level, which is +slightly later (so ioremap() works properly), but sufficiently early +to be before the call of the ->smp_prepare_cpus() hook, which creates +an address decoding window for the BootROM, which requires the +mvebu-mbus driver to be properly initialized. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + arch/arm/mach-mvebu/armada-370-xp.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +--- a/arch/arm/mach-mvebu/armada-370-xp.c ++++ b/arch/arm/mach-mvebu/armada-370-xp.c +@@ -45,14 +45,11 @@ static void __init armada_370_xp_map_io( + + static void __init armada_370_xp_timer_and_clk_init(void) + { ++ char *mbus_soc_name; ++ + mvebu_clocks_init(); + armada_370_xp_timer_init(); + coherency_init(); +-} +- +-static void __init armada_370_xp_init_early(void) +-{ +- char *mbus_soc_name; + + /* + * This initialization will be replaced by a DT-based +@@ -88,7 +85,6 @@ DT_MACHINE_START(ARMADA_XP_DT, "Marvell + .smp = smp_ops(armada_xp_smp_ops), + .init_machine = armada_370_xp_dt_init, + .map_io = armada_370_xp_map_io, +- .init_early = armada_370_xp_init_early, + .init_irq = irqchip_init, + .init_time = armada_370_xp_timer_and_clk_init, + .restart = mvebu_restart, diff --git a/target/linux/mvebu/patches-3.10/0027-arm-mvebu-remove-hardcoded-static-I-O-mapping.patch b/target/linux/mvebu/patches-3.10/0027-arm-mvebu-remove-hardcoded-static-I-O-mapping.patch new file mode 100644 index 0000000000..78905927d0 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0027-arm-mvebu-remove-hardcoded-static-I-O-mapping.patch @@ -0,0 +1,52 @@ +From fe4fce3c521f5d9f3a64c4d06a73a5e6b7324116 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Wed, 5 Jun 2013 09:04:57 +0200 +Subject: [PATCH 027/203] arm: mvebu: remove hardcoded static I/O mapping + +Now that we have removed the need of the static I/O mapping for early +initialization reasons, and fixed the registers area length that were +broken, we can get rid of the static I/O mapping. Only the earlyprintk +mapping needs to be set up, using the debug_ll_io_init() helper +function. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + arch/arm/mach-mvebu/armada-370-xp.c | 11 +---------- + arch/arm/mach-mvebu/armada-370-xp.h | 2 -- + 2 files changed, 1 insertion(+), 12 deletions(-) + +--- a/arch/arm/mach-mvebu/armada-370-xp.c ++++ b/arch/arm/mach-mvebu/armada-370-xp.c +@@ -29,18 +29,9 @@ + #include "common.h" + #include "coherency.h" + +-static struct map_desc armada_370_xp_io_desc[] __initdata = { +- { +- .virtual = (unsigned long) ARMADA_370_XP_REGS_VIRT_BASE, +- .pfn = __phys_to_pfn(ARMADA_370_XP_REGS_PHYS_BASE), +- .length = ARMADA_370_XP_REGS_SIZE, +- .type = MT_DEVICE, +- }, +-}; +- + static void __init armada_370_xp_map_io(void) + { +- iotable_init(armada_370_xp_io_desc, ARRAY_SIZE(armada_370_xp_io_desc)); ++ debug_ll_io_init(); + } + + static void __init armada_370_xp_timer_and_clk_init(void) +--- a/arch/arm/mach-mvebu/armada-370-xp.h ++++ b/arch/arm/mach-mvebu/armada-370-xp.h +@@ -16,8 +16,6 @@ + #define __MACH_ARMADA_370_XP_H + + #define ARMADA_370_XP_REGS_PHYS_BASE 0xd0000000 +-#define ARMADA_370_XP_REGS_VIRT_BASE IOMEM(0xfec00000) +-#define ARMADA_370_XP_REGS_SIZE SZ_1M + + /* These defines can go away once mvebu-mbus has a DT binding */ + #define ARMADA_370_XP_MBUS_WINS_BASE (ARMADA_370_XP_REGS_PHYS_BASE + 0x20000) diff --git a/target/linux/mvebu/patches-3.10/0028-arm-mvebu-don-t-hardcode-a-physical-address-in-heads.patch b/target/linux/mvebu/patches-3.10/0028-arm-mvebu-don-t-hardcode-a-physical-address-in-heads.patch new file mode 100644 index 0000000000..af98e9dae8 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0028-arm-mvebu-don-t-hardcode-a-physical-address-in-heads.patch @@ -0,0 +1,91 @@ +From 88260610ea7a2c5a164721af28f59856880221b4 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Thu, 6 Jun 2013 12:24:28 +0200 +Subject: [PATCH 028/203] arm: mvebu: don't hardcode a physical address in + headsmp.S + +Now that the coherency_init() function is called a bit earlier, we can +actually read the physical address of the coherency unit registers +from the Device Tree, and communicate that to the headsmp.S code, +which avoids hardcoding a physical address. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Reviewed-by: Will Deacon <will.deacon@arm.com> +Acked-by: Nicolas Pitre <nico@linaro.org> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + arch/arm/mach-mvebu/coherency.c | 12 ++++++++++++ + arch/arm/mach-mvebu/headsmp.S | 16 ++++++++-------- + 2 files changed, 20 insertions(+), 8 deletions(-) + +--- a/arch/arm/mach-mvebu/coherency.c ++++ b/arch/arm/mach-mvebu/coherency.c +@@ -25,8 +25,10 @@ + #include <linux/dma-mapping.h> + #include <linux/platform_device.h> + #include <asm/smp_plat.h> ++#include <asm/cacheflush.h> + #include "armada-370-xp.h" + ++unsigned long __cpuinitdata coherency_phys_base; + static void __iomem *coherency_base; + static void __iomem *coherency_cpu_base; + +@@ -124,7 +126,17 @@ int __init coherency_init(void) + + np = of_find_matching_node(NULL, of_coherency_table); + if (np) { ++ struct resource res; + pr_info("Initializing Coherency fabric\n"); ++ of_address_to_resource(np, 0, &res); ++ coherency_phys_base = res.start; ++ /* ++ * Ensure secondary CPUs will see the updated value, ++ * which they read before they join the coherency ++ * fabric, and therefore before they are coherent with ++ * the boot CPU cache. ++ */ ++ sync_cache_w(&coherency_phys_base); + coherency_base = of_iomap(np, 0); + coherency_cpu_base = of_iomap(np, 1); + set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0); +--- a/arch/arm/mach-mvebu/headsmp.S ++++ b/arch/arm/mach-mvebu/headsmp.S +@@ -21,12 +21,6 @@ + #include <linux/linkage.h> + #include <linux/init.h> + +-/* +- * At this stage the secondary CPUs don't have acces yet to the MMU, so +- * we have to provide physical addresses +- */ +-#define ARMADA_XP_CFB_BASE 0xD0020200 +- + __CPUINIT + + /* +@@ -35,15 +29,21 @@ + * startup + */ + ENTRY(armada_xp_secondary_startup) ++ /* Get coherency fabric base physical address */ ++ adr r0, 1f ++ ldr r1, [r0] ++ ldr r0, [r0, r1] + + /* Read CPU id */ + mrc p15, 0, r1, c0, c0, 5 + and r1, r1, #0xF + + /* Add CPU to coherency fabric */ +- ldr r0, =ARMADA_XP_CFB_BASE +- + bl ll_set_cpu_coherent + b secondary_startup + + ENDPROC(armada_xp_secondary_startup) ++ ++ .align 2 ++1: ++ .long coherency_phys_base - . diff --git a/target/linux/mvebu/patches-3.10/0029-arm-mvebu-don-t-hardcode-the-physical-address-for-mv.patch b/target/linux/mvebu/patches-3.10/0029-arm-mvebu-don-t-hardcode-the-physical-address-for-mv.patch new file mode 100644 index 0000000000..62c6bcbead --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0029-arm-mvebu-don-t-hardcode-the-physical-address-for-mv.patch @@ -0,0 +1,109 @@ +From 070469397154c87b14fab48d2fc231ba83007c1b Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Wed, 5 Jun 2013 09:04:59 +0200 +Subject: [PATCH 029/203] arm: mvebu: don't hardcode the physical address for + mvebu-mbus + +Since the mvebu-mbus driver doesn't yet have a DT binding (and this DT +binding may not necessarily be ready for 3.11), the physical address +of the mvebu-mbus registers are currently hardcoded. This doesn't play +well with the fact that the internal registers base address may be +different depending on the bootloader. + +In order to have only one central place for the physical address of +the internal registers, we now use of_translate_address() to translate +the mvebu-mbus register offsets into the real physical address, by +using DT-based address translation. This will go away once the +mvebu-mbus driver gains a proper DT binding. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + arch/arm/mach-mvebu/armada-370-xp.c | 38 ++++++++++++++++++++++++++----------- + arch/arm/mach-mvebu/armada-370-xp.h | 8 -------- + 2 files changed, 27 insertions(+), 19 deletions(-) + +--- a/arch/arm/mach-mvebu/armada-370-xp.c ++++ b/arch/arm/mach-mvebu/armada-370-xp.c +@@ -14,6 +14,7 @@ + + #include <linux/kernel.h> + #include <linux/init.h> ++#include <linux/of_address.h> + #include <linux/of_platform.h> + #include <linux/io.h> + #include <linux/time-armada-370-xp.h> +@@ -34,29 +35,44 @@ static void __init armada_370_xp_map_io( + debug_ll_io_init(); + } + +-static void __init armada_370_xp_timer_and_clk_init(void) ++/* ++ * This initialization will be replaced by a DT-based ++ * initialization once the mvebu-mbus driver gains DT support. ++ */ ++ ++#define ARMADA_370_XP_MBUS_WINS_OFFS 0x20000 ++#define ARMADA_370_XP_MBUS_WINS_SIZE 0x100 ++#define ARMADA_370_XP_SDRAM_WINS_OFFS 0x20180 ++#define ARMADA_370_XP_SDRAM_WINS_SIZE 0x20 ++ ++static void __init armada_370_xp_mbus_init(void) + { + char *mbus_soc_name; ++ struct device_node *dn; ++ const __be32 mbus_wins_offs = cpu_to_be32(ARMADA_370_XP_MBUS_WINS_OFFS); ++ const __be32 sdram_wins_offs = cpu_to_be32(ARMADA_370_XP_SDRAM_WINS_OFFS); + +- mvebu_clocks_init(); +- armada_370_xp_timer_init(); +- coherency_init(); +- +- /* +- * This initialization will be replaced by a DT-based +- * initialization once the mvebu-mbus driver gains DT support. +- */ + if (of_machine_is_compatible("marvell,armada370")) + mbus_soc_name = "marvell,armada370-mbus"; + else + mbus_soc_name = "marvell,armadaxp-mbus"; + ++ dn = of_find_node_by_name(NULL, "internal-regs"); ++ BUG_ON(!dn); ++ + mvebu_mbus_init(mbus_soc_name, +- ARMADA_370_XP_MBUS_WINS_BASE, ++ of_translate_address(dn, &mbus_wins_offs), + ARMADA_370_XP_MBUS_WINS_SIZE, +- ARMADA_370_XP_SDRAM_WINS_BASE, ++ of_translate_address(dn, &sdram_wins_offs), + ARMADA_370_XP_SDRAM_WINS_SIZE); ++} + ++static void __init armada_370_xp_timer_and_clk_init(void) ++{ ++ mvebu_clocks_init(); ++ armada_370_xp_timer_init(); ++ coherency_init(); ++ armada_370_xp_mbus_init(); + #ifdef CONFIG_CACHE_L2X0 + l2x0_of_init(0, ~0UL); + #endif +--- a/arch/arm/mach-mvebu/armada-370-xp.h ++++ b/arch/arm/mach-mvebu/armada-370-xp.h +@@ -15,14 +15,6 @@ + #ifndef __MACH_ARMADA_370_XP_H + #define __MACH_ARMADA_370_XP_H + +-#define ARMADA_370_XP_REGS_PHYS_BASE 0xd0000000 +- +-/* These defines can go away once mvebu-mbus has a DT binding */ +-#define ARMADA_370_XP_MBUS_WINS_BASE (ARMADA_370_XP_REGS_PHYS_BASE + 0x20000) +-#define ARMADA_370_XP_MBUS_WINS_SIZE 0x100 +-#define ARMADA_370_XP_SDRAM_WINS_BASE (ARMADA_370_XP_REGS_PHYS_BASE + 0x20180) +-#define ARMADA_370_XP_SDRAM_WINS_SIZE 0x20 +- + #ifdef CONFIG_SMP + #include <linux/cpumask.h> + diff --git a/target/linux/mvebu/patches-3.10/0030-arm-mvebu-add-another-earlyprintk-Kconfig-option.patch b/target/linux/mvebu/patches-3.10/0030-arm-mvebu-add-another-earlyprintk-Kconfig-option.patch new file mode 100644 index 0000000000..7faeb986a0 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0030-arm-mvebu-add-another-earlyprintk-Kconfig-option.patch @@ -0,0 +1,85 @@ +From 70c30ca997919a4b8c9051a3903f30c79c735f12 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Wed, 5 Jun 2013 09:05:00 +0200 +Subject: [PATCH 030/203] arm: mvebu: add another earlyprintk Kconfig option + +In order to support both old and new bootloaders, we add a new Kconfig +option for the earlyprintk UART selection. The existing option allows +to work with old bootloaders (that keep the internal registers mapped +at 0xd0000000), while the newly introduced option allows to work with +new bootloaders (that remap the internal registers at 0xf1000000). + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + arch/arm/Kconfig.debug | 30 ++++++++++++++++++++++++++++-- + arch/arm/include/debug/mvebu.S | 5 +++++ + 2 files changed, 33 insertions(+), 2 deletions(-) + +--- a/arch/arm/Kconfig.debug ++++ b/arch/arm/Kconfig.debug +@@ -303,12 +303,37 @@ choice + their output to the serial port on MSM 8960 devices. + + config DEBUG_MVEBU_UART +- bool "Kernel low-level debugging messages via MVEBU UART" ++ bool "Kernel low-level debugging messages via MVEBU UART (old bootloaders)" + depends on ARCH_MVEBU + help + Say Y here if you want kernel low-level debugging support + on MVEBU based platforms. + ++ This option should be used with the old bootloaders ++ that left the internal registers mapped at ++ 0xd0000000. As of today, this is the case on ++ platforms such as the Globalscale Mirabox or the ++ Plathome OpenBlocks AX3, when using the original ++ bootloader. ++ ++ If the wrong DEBUG_MVEBU_UART* option is selected, ++ when u-boot hands over to the kernel, the system ++ silently crashes, with no serial output at all. ++ ++ config DEBUG_MVEBU_UART_ALTERNATE ++ bool "Kernel low-level debugging messages via MVEBU UART (new bootloaders)" ++ depends on ARCH_MVEBU ++ help ++ Say Y here if you want kernel low-level debugging support ++ on MVEBU based platforms. ++ ++ This option should be used with the new bootloaders ++ that remap the internal registers at 0xf1000000. ++ ++ If the wrong DEBUG_MVEBU_UART* option is selected, ++ when u-boot hands over to the kernel, the system ++ silently crashes, with no serial output at all. ++ + config DEBUG_NOMADIK_UART + bool "Kernel low-level debugging messages via NOMADIK UART" + depends on ARCH_NOMADIK +@@ -632,7 +657,8 @@ config DEBUG_LL_INCLUDE + DEBUG_IMX51_UART || \ + DEBUG_IMX53_UART ||\ + DEBUG_IMX6Q_UART +- default "debug/mvebu.S" if DEBUG_MVEBU_UART ++ default "debug/mvebu.S" if DEBUG_MVEBU_UART || \ ++ DEBUG_MVEBU_UART_ALTERNATE + default "debug/mxs.S" if DEBUG_IMX23_UART || DEBUG_IMX28_UART + default "debug/nomadik.S" if DEBUG_NOMADIK_UART + default "debug/omap2plus.S" if DEBUG_OMAP2PLUS_UART +--- a/arch/arm/include/debug/mvebu.S ++++ b/arch/arm/include/debug/mvebu.S +@@ -11,7 +11,12 @@ + * published by the Free Software Foundation. + */ + ++#ifdef CONFIG_DEBUG_MVEBU_UART_ALTERNATE ++#define ARMADA_370_XP_REGS_PHYS_BASE 0xf1000000 ++#else + #define ARMADA_370_XP_REGS_PHYS_BASE 0xd0000000 ++#endif ++ + #define ARMADA_370_XP_REGS_VIRT_BASE 0xfec00000 + + .macro addruart, rp, rv, tmp diff --git a/target/linux/mvebu/patches-3.10/0031-arm-mvebu-disable-DEBUG_LL-EARLY_PRINTK-in-defconfig.patch b/target/linux/mvebu/patches-3.10/0031-arm-mvebu-disable-DEBUG_LL-EARLY_PRINTK-in-defconfig.patch new file mode 100644 index 0000000000..e1e2e6233f --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0031-arm-mvebu-disable-DEBUG_LL-EARLY_PRINTK-in-defconfig.patch @@ -0,0 +1,27 @@ +From 7a3b99b8d16f2eb9ae5ac4ddf5e201eacdfacbf4 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Wed, 5 Jun 2013 09:05:01 +0200 +Subject: [PATCH 031/203] arm: mvebu: disable DEBUG_LL/EARLY_PRINTK in + defconfig + +Now that we have two different addresses for the UART, depending on +which bootloader is used, it is no longer desirable to enable +earlyprintk by default in the defconfig. Users who need earlyprintk +support will have to enable it explicitly, and select the right UART +configuration depending on their platform. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + arch/arm/configs/mvebu_defconfig | 2 -- + 1 file changed, 2 deletions(-) + +--- a/arch/arm/configs/mvebu_defconfig ++++ b/arch/arm/configs/mvebu_defconfig +@@ -100,5 +100,3 @@ CONFIG_TIMER_STATS=y + # CONFIG_DEBUG_BUGVERBOSE is not set + CONFIG_DEBUG_INFO=y + CONFIG_DEBUG_USER=y +-CONFIG_DEBUG_LL=y +-CONFIG_EARLY_PRINTK=y diff --git a/target/linux/mvebu/patches-3.10/0032-arm-mvebu-enable-mini-PCIe-connectors-on-Armada-370-.patch b/target/linux/mvebu/patches-3.10/0032-arm-mvebu-enable-mini-PCIe-connectors-on-Armada-370-.patch new file mode 100644 index 0000000000..81ab352d9f --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0032-arm-mvebu-enable-mini-PCIe-connectors-on-Armada-370-.patch @@ -0,0 +1,42 @@ +From e552d168344e941a1781682207269dbfd27850b1 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Tue, 18 Jun 2013 15:37:41 +0200 +Subject: [PATCH 032/203] arm: mvebu: enable mini-PCIe connectors on Armada 370 + RD + +The Armada 370 RD board has two internal mini-PCIe connectors. This +commit adds the necessary Device Tree informations to enable the usage +of those mini-PCIe connectors. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Cc: Florian Fainelli <florian@openwrt.org> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + arch/arm/boot/dts/armada-370-rd.dts | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +--- a/arch/arm/boot/dts/armada-370-rd.dts ++++ b/arch/arm/boot/dts/armada-370-rd.dts +@@ -85,6 +85,22 @@ + gpios = <&gpio0 6 1>; + }; + }; ++ ++ pcie-controller { ++ status = "okay"; ++ ++ /* Internal mini-PCIe connector */ ++ pcie@1,0 { ++ /* Port 0, Lane 0 */ ++ status = "okay"; ++ }; ++ ++ /* Internal mini-PCIe connector */ ++ pcie@2,0 { ++ /* Port 1, Lane 0 */ ++ status = "okay"; ++ }; ++ }; + }; + }; + }; diff --git a/target/linux/mvebu/patches-3.10/0033-arm-mvebu-fix-coherency_late_init-for-multiplatform.patch b/target/linux/mvebu/patches-3.10/0033-arm-mvebu-fix-coherency_late_init-for-multiplatform.patch new file mode 100644 index 0000000000..21fad3e856 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0033-arm-mvebu-fix-coherency_late_init-for-multiplatform.patch @@ -0,0 +1,41 @@ +From 3891658a01af7e875d4c176ebb5d713d74a6e998 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Thu, 20 Jun 2013 09:45:26 +0200 +Subject: [PATCH 033/203] arm: mvebu: fix coherency_late_init() for + multiplatform + +As noticed by Arnaud Patard (Rtp) <arnaud.patard@rtp-net.org>, commit +865e0527d2d7 ('arm: mvebu: avoid hardcoded virtual address in +coherency code') added a postcore_initcall() to register the bus +notifier that the mvebu code needs to apply correct DMA operations on +its platform devices breaks the multiplatform boot on other platforms, +because the bus notifier registration is unconditional. + +This commit fixes that by registering the bus notifier only if we have +the mvebu coherency unit described in the Device Tree. The conditional +used is exactly the same in which the bus_register_notifier() call was +originally enclosed before 865e0527d2d7 ('arm: mvebu: avoid hardcoded +virtual address in coherency code'). + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Reported-by: Arnaud Patard (Rtp) <arnaud.patard@rtp-net.org> +Acked-by: Andrew Lunn <andrew@lunn.ch> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + arch/arm/mach-mvebu/coherency.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/arch/arm/mach-mvebu/coherency.c ++++ b/arch/arm/mach-mvebu/coherency.c +@@ -147,8 +147,9 @@ int __init coherency_init(void) + + static int __init coherency_late_init(void) + { +- bus_register_notifier(&platform_bus_type, +- &mvebu_hwcc_platform_nb); ++ if (of_find_matching_node(NULL, of_coherency_table)) ++ bus_register_notifier(&platform_bus_type, ++ &mvebu_hwcc_platform_nb); + return 0; + } + diff --git a/target/linux/mvebu/patches-3.10/0034-ARM-mvebu-fix-length-of-ethernet-registers-in-mv7826.patch b/target/linux/mvebu/patches-3.10/0034-ARM-mvebu-fix-length-of-ethernet-registers-in-mv7826.patch new file mode 100644 index 0000000000..6ee5835943 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0034-ARM-mvebu-fix-length-of-ethernet-registers-in-mv7826.patch @@ -0,0 +1,53 @@ +From 4f6da1286d2602e00c049c29eb9e816587c752a5 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Date: Sat, 22 Jun 2013 13:52:27 -0300 +Subject: [PATCH 034/203] ARM: mvebu: fix length of ethernet registers in + mv78260 dtsi + +The length of the registers area for the Marvell 370/XP Ethernet controller +was incorrect in the .dtsi: 0x2500, while it should have been 0x4000. +This problem wasn't noticed because there used to be a static mapping for +all the MMIO register region set up by ->map_io(). + +The register length was fixed in all the other device tree files, +except from the armada-xp-mv78260.dtsi, in the following commit: + + commit cf8088c5cac6ce20d914b9131533844b9291a054 + Author: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> + Date: Tue May 21 12:33:27 2013 +0200 + + arm: mvebu: fix length of Ethernet registers area in .dtsi + +This commit fixes a kernel panic in mvneta_probe(), when the kernel +tries to access the unmapped registers: + +[ 163.639092] mvneta d0070000.ethernet eth0: mac: 6e:3c:4f:87:17:2e +[ 163.646962] mvneta d0074000.ethernet eth1: mac: 6a:04:4e:6f:f5:ef +[ 163.654853] mvneta d0030000.ethernet eth2: mac: 2a:99:19:19:fc:4c +[ 163.661258] Unable to handle kernel paging request at virtual address f011bcf0 +[ 163.668523] pgd = c0004000 +[ 163.671237] [f011bcf0] *pgd=2f006811, *pte=00000000, *ppte=00000000 +[ 163.677565] Internal error: Oops: 807 [#1] SMP ARM +[ 163.682370] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.10.0-rc6-01850-gba0682e #11 +[ 163.690046] task: ef04c000 ti: ef03e000 task.ti: ef03e000 +[ 163.695467] PC is at mvneta_probe+0x34c/0xabc +[...] + +Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Acked-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + arch/arm/boot/dts/armada-xp-mv78260.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/armada-xp-mv78260.dtsi ++++ b/arch/arm/boot/dts/armada-xp-mv78260.dtsi +@@ -92,7 +92,7 @@ + + ethernet@34000 { + compatible = "marvell,armada-370-neta"; +- reg = <0x34000 0x2500>; ++ reg = <0x34000 0x4000>; + interrupts = <14>; + clocks = <&gateclk 1>; + status = "disabled"; diff --git a/target/linux/mvebu/patches-3.10/0035-i2c-mv64xxx-Set-bus-frequency-to-100kHz-if-clock-fre.patch b/target/linux/mvebu/patches-3.10/0035-i2c-mv64xxx-Set-bus-frequency-to-100kHz-if-clock-fre.patch new file mode 100644 index 0000000000..4de7da9828 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0035-i2c-mv64xxx-Set-bus-frequency-to-100kHz-if-clock-fre.patch @@ -0,0 +1,51 @@ +From 76de914223ec09274a7857e0d8cd7b739205dc3c Mon Sep 17 00:00:00 2001 +From: Gregory CLEMENT <gregory.clement@free-electrons.com> +Date: Fri, 21 Jun 2013 15:32:06 +0200 +Subject: [PATCH 035/203] i2c: mv64xxx: Set bus frequency to 100kHz if + clock-frequency is not provided + +This commit adds checking whether clock-frequency property acquisition +has succeeded. If not, the frequency is set to 100kHz by default. + +The Device Tree binding documentation is updated accordingly. + +Based on the intials patches from Zbigniew Bodek + +Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> +Signed-off-by: Zbigniew Bodek <zbb@semihalf.com> +Signed-off-by: Wolfram Sang <wsa@the-dreams.de> +--- + Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt | 6 +++++- + drivers/i2c/busses/i2c-mv64xxx.c | 6 +++++- + 2 files changed, 10 insertions(+), 2 deletions(-) + +--- a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt ++++ b/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt +@@ -6,7 +6,11 @@ Required properties : + - reg : Offset and length of the register set for the device + - compatible : Should be "marvell,mv64xxx-i2c" + - interrupts : The interrupt number +- - clock-frequency : Desired I2C bus clock frequency in Hz. ++ ++Optional properties : ++ ++ - clock-frequency : Desired I2C bus clock frequency in Hz. If not set the ++default frequency is 100kHz + + Examples: + +--- a/drivers/i2c/busses/i2c-mv64xxx.c ++++ b/drivers/i2c/busses/i2c-mv64xxx.c +@@ -580,7 +580,11 @@ mv64xxx_of_config(struct mv64xxx_i2c_dat + goto out; + } + tclk = clk_get_rate(drv_data->clk); +- of_property_read_u32(np, "clock-frequency", &bus_freq); ++ ++ rc = of_property_read_u32(np, "clock-frequency", &bus_freq); ++ if (rc) ++ bus_freq = 100000; /* 100kHz by default */ ++ + if (!mv64xxx_find_baud_factors(bus_freq, tclk, + &drv_data->freq_n, &drv_data->freq_m)) { + rc = -EINVAL; diff --git a/target/linux/mvebu/patches-3.10/0036-PCI-mvebu-Disable-prefetchable-memory-support-in-PCI.patch b/target/linux/mvebu/patches-3.10/0036-PCI-mvebu-Disable-prefetchable-memory-support-in-PCI.patch new file mode 100644 index 0000000000..afb104a581 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0036-PCI-mvebu-Disable-prefetchable-memory-support-in-PCI.patch @@ -0,0 +1,91 @@ +From 71a32c9519ba223d1dafcbe58d1699710720c5a8 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Thu, 1 Aug 2013 15:44:19 +0200 +Subject: [PATCH 036/203] PCI: mvebu: Disable prefetchable memory support in + PCI-to-PCI bridge + +The Marvell PCIe driver uses an emulated PCI-to-PCI bridge to be able +to dynamically set up MBus address decoding windows for PCI I/O and +memory regions depending on the PCI devices enumerated by Linux. + +However, this emulated PCI-to-PCI bridge logic makes the Linux PCI +core believe that prefetchable memory regions are supported (because +the registers are read/write), while in fact no adress decoding window +is ever created for such regions. Since the Marvell MBus address +decoding windows do not distinguish memory regions and prefetchable +memory regions, this patch takes a simple approach: change the +PCI-to-PCI bridge emulation to let the Linux PCI core know that we +don't support prefetchable memory regions. + +To achieve this, we simply make the prefetchable memory base a +read-only register that always returns 0. Reading/writing all the +other prefetchable memory related registers has no effect. + +This problem was originally reported by Finn Hoffmann +<finn@uni-bremen.de>, who couldn't get a RTL8111/8168B PCI NIC working +on the NSA310 Kirkwood platform after updating to 3.11-rc. The problem +was that the PCI-to-PCI bridge emulation was making the Linux PCI core +believe that we support prefetchable memory, so the Linux PCI core was +only filling the prefetchable memory base and limit registers, which +does not lead to a MBus window being created. The below patch has been +confirmed by Finn Hoffmann to fix his problem on Kirkwood, and has +otherwise been successfully tested on the Armada XP GP platform with a +e1000e PCIe NIC and a Marvell SATA PCIe card. + +Reported-by: Finn Hoffmann <finn@uni-bremen.de> +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> +--- + drivers/pci/host/pci-mvebu.c | 27 +-------------------------- + 1 file changed, 1 insertion(+), 26 deletions(-) + +--- a/drivers/pci/host/pci-mvebu.c ++++ b/drivers/pci/host/pci-mvebu.c +@@ -86,10 +86,6 @@ struct mvebu_sw_pci_bridge { + u16 secondary_status; + u16 membase; + u16 memlimit; +- u16 prefmembase; +- u16 prefmemlimit; +- u32 prefbaseupper; +- u32 preflimitupper; + u16 iobaseupper; + u16 iolimitupper; + u8 cappointer; +@@ -419,15 +415,7 @@ static int mvebu_sw_pci_bridge_read(stru + break; + + case PCI_PREF_MEMORY_BASE: +- *value = (bridge->prefmemlimit << 16 | bridge->prefmembase); +- break; +- +- case PCI_PREF_BASE_UPPER32: +- *value = bridge->prefbaseupper; +- break; +- +- case PCI_PREF_LIMIT_UPPER32: +- *value = bridge->preflimitupper; ++ *value = 0; + break; + + case PCI_IO_BASE_UPPER16: +@@ -501,19 +489,6 @@ static int mvebu_sw_pci_bridge_write(str + mvebu_pcie_handle_membase_change(port); + break; + +- case PCI_PREF_MEMORY_BASE: +- bridge->prefmembase = value & 0xffff; +- bridge->prefmemlimit = value >> 16; +- break; +- +- case PCI_PREF_BASE_UPPER32: +- bridge->prefbaseupper = value; +- break; +- +- case PCI_PREF_LIMIT_UPPER32: +- bridge->preflimitupper = value; +- break; +- + case PCI_IO_BASE_UPPER16: + bridge->iobaseupper = value & 0xffff; + bridge->iolimitupper = value >> 16; diff --git a/target/linux/mvebu/patches-3.10/0037-memory-mvebu-devbus-Remove-address-decoding-window-w.patch b/target/linux/mvebu/patches-3.10/0037-memory-mvebu-devbus-Remove-address-decoding-window-w.patch new file mode 100644 index 0000000000..1983016ddf --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0037-memory-mvebu-devbus-Remove-address-decoding-window-w.patch @@ -0,0 +1,109 @@ +From 9760aafa716292050a96d71a4bd7bd4e66053975 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Date: Tue, 21 May 2013 10:24:48 -0300 +Subject: [PATCH 037/203] memory: mvebu-devbus: Remove address decoding window + workaround + +Now that mbus device tree binding has been introduced, remove the address +decoding window management from this driver. +A suitable 'ranges' entry should be added to the devbus-compatible node in +the device tree, as described by the mbus binding documentation. + +Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Tested-by: Andrew Lunn <andrew@lunn.ch> +Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> +--- + drivers/memory/mvebu-devbus.c | 64 ++----------------------------------------- + 1 file changed, 2 insertions(+), 62 deletions(-) + +--- a/drivers/memory/mvebu-devbus.c ++++ b/drivers/memory/mvebu-devbus.c +@@ -208,16 +208,11 @@ static int mvebu_devbus_probe(struct pla + { + struct device *dev = &pdev->dev; + struct device_node *node = pdev->dev.of_node; +- struct device_node *parent; + struct devbus *devbus; + struct resource *res; + struct clk *clk; + unsigned long rate; +- const __be32 *ranges; +- int err, cs; +- int addr_cells, p_addr_cells, size_cells; +- int ranges_len, tuple_len; +- u32 base, size; ++ int err; + + devbus = devm_kzalloc(&pdev->dev, sizeof(struct devbus), GFP_KERNEL); + if (!devbus) +@@ -248,68 +243,13 @@ static int mvebu_devbus_probe(struct pla + return err; + + /* +- * Allocate an address window for this device. +- * If the device probing fails, then we won't be able to +- * remove the allocated address decoding window. +- * +- * FIXME: This is only a temporary hack! We need to do this here +- * because we still don't have device tree bindings for mbus. +- * Once that support is added, we will declare these address windows +- * statically in the device tree, and remove the window configuration +- * from here. +- */ +- +- /* +- * Get the CS to choose the window string. +- * This is a bit hacky, but it will be removed once the +- * address windows are declared in the device tree. +- */ +- cs = (((unsigned long)devbus->base) % 0x400) / 8; +- +- /* +- * Parse 'ranges' property to obtain a (base,size) window tuple. +- * This will be removed once the address windows +- * are declared in the device tree. +- */ +- parent = of_get_parent(node); +- if (!parent) +- return -EINVAL; +- +- p_addr_cells = of_n_addr_cells(parent); +- of_node_put(parent); +- +- addr_cells = of_n_addr_cells(node); +- size_cells = of_n_size_cells(node); +- tuple_len = (p_addr_cells + addr_cells + size_cells) * sizeof(__be32); +- +- ranges = of_get_property(node, "ranges", &ranges_len); +- if (ranges == NULL || ranges_len != tuple_len) +- return -EINVAL; +- +- base = of_translate_address(node, ranges + addr_cells); +- if (base == OF_BAD_ADDR) +- return -EINVAL; +- size = of_read_number(ranges + addr_cells + p_addr_cells, size_cells); +- +- /* +- * Create an mbus address windows. +- * FIXME: Remove this, together with the above code, once the +- * address windows are declared in the device tree. +- */ +- err = mvebu_mbus_add_window(devbus_wins[cs], base, size); +- if (err < 0) +- return err; +- +- /* + * We need to create a child device explicitly from here to + * guarantee that the child will be probed after the timing + * parameters for the bus are written. + */ + err = of_platform_populate(node, NULL, NULL, dev); +- if (err < 0) { +- mvebu_mbus_del_window(base, size); ++ if (err < 0) + return err; +- } + + return 0; + } diff --git a/target/linux/mvebu/patches-3.10/0038-bus-mvebu-mbus-Add-new-API-for-window-creation.patch b/target/linux/mvebu/patches-3.10/0038-bus-mvebu-mbus-Add-new-API-for-window-creation.patch new file mode 100644 index 0000000000..4ebb3f3216 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0038-bus-mvebu-mbus-Add-new-API-for-window-creation.patch @@ -0,0 +1,90 @@ +From 93b6bd1bf81cffd3e5739478c4434bf25458ec7d Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Fri, 5 Jul 2013 14:54:16 +0200 +Subject: [PATCH 038/203] bus: mvebu-mbus: Add new API for window creation + +We add an API to create MBus address decoding windows from the target +ID and attribute. This function will be used later and deprecate the +current name based scheme. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Tested-by: Andrew Lunn <andrew@lunn.ch> +Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> +--- + drivers/bus/mvebu-mbus.c | 33 +++++++++++++++++++++++++-------- + include/linux/mbus.h | 6 ++++++ + 2 files changed, 31 insertions(+), 8 deletions(-) + +--- a/drivers/bus/mvebu-mbus.c ++++ b/drivers/bus/mvebu-mbus.c +@@ -748,6 +748,22 @@ static const struct of_device_id of_mveb + /* + * Public API of the driver + */ ++int mvebu_mbus_add_window_remap_by_id(unsigned int target, ++ unsigned int attribute, ++ phys_addr_t base, size_t size, ++ phys_addr_t remap) ++{ ++ struct mvebu_mbus_state *s = &mbus_state; ++ ++ if (!mvebu_mbus_window_conflicts(s, base, size, target, attribute)) { ++ pr_err("cannot add window '%x:%x', conflicts with another window\n", ++ target, attribute); ++ return -EINVAL; ++ } ++ ++ return mvebu_mbus_alloc_window(s, base, size, remap, target, attribute); ++} ++ + int mvebu_mbus_add_window_remap_flags(const char *devname, phys_addr_t base, + size_t size, phys_addr_t remap, + unsigned int flags) +@@ -776,14 +792,8 @@ int mvebu_mbus_add_window_remap_flags(co + else if (flags == MVEBU_MBUS_PCI_WA) + attr |= 0x28; + +- if (!mvebu_mbus_window_conflicts(s, base, size, target, attr)) { +- pr_err("cannot add window '%s', conflicts with another window\n", +- devname); +- return -EINVAL; +- } +- +- return mvebu_mbus_alloc_window(s, base, size, remap, target, attr); +- ++ return mvebu_mbus_add_window_remap_by_id(target, attr, base, ++ size, remap); + } + + int mvebu_mbus_add_window(const char *devname, phys_addr_t base, size_t size) +@@ -792,6 +802,13 @@ int mvebu_mbus_add_window(const char *de + MVEBU_MBUS_NO_REMAP, 0); + } + ++int mvebu_mbus_add_window_by_id(unsigned int target, unsigned int attribute, ++ phys_addr_t base, size_t size) ++{ ++ return mvebu_mbus_add_window_remap_by_id(target, attribute, base, ++ size, MVEBU_MBUS_NO_REMAP); ++} ++ + int mvebu_mbus_del_window(phys_addr_t base, size_t size) + { + int win; +--- a/include/linux/mbus.h ++++ b/include/linux/mbus.h +@@ -62,8 +62,14 @@ static inline const struct mbus_dram_tar + int mvebu_mbus_add_window_remap_flags(const char *devname, phys_addr_t base, + size_t size, phys_addr_t remap, + unsigned int flags); ++int mvebu_mbus_add_window_remap_by_id(unsigned int target, ++ unsigned int attribute, ++ phys_addr_t base, size_t size, ++ phys_addr_t remap); + int mvebu_mbus_add_window(const char *devname, phys_addr_t base, + size_t size); ++int mvebu_mbus_add_window_by_id(unsigned int target, unsigned int attribute, ++ phys_addr_t base, size_t size); + int mvebu_mbus_del_window(phys_addr_t base, size_t size); + int mvebu_mbus_init(const char *soc, phys_addr_t mbus_phys_base, + size_t mbus_size, phys_addr_t sdram_phys_base, diff --git a/target/linux/mvebu/patches-3.10/0043-bus-mvebu-mbus-Factor-out-initialization-details.patch b/target/linux/mvebu/patches-3.10/0043-bus-mvebu-mbus-Factor-out-initialization-details.patch new file mode 100644 index 0000000000..e6a9032f15 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0043-bus-mvebu-mbus-Factor-out-initialization-details.patch @@ -0,0 +1,81 @@ +From 5be79ea0d2bcec8c7360cfe3e7a491e5f176fa84 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Date: Tue, 21 May 2013 10:44:54 -0300 +Subject: [PATCH 043/203] bus: mvebu-mbus: Factor out initialization details + +We introduce a common initialization function mvebu_mbus_common_init() +that will be used by both legacy and device-tree initialization code. +This patch is an intermediate step, which will allow to introduce the +DT binding for this driver in a less intrusive way. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Tested-by: Andrew Lunn <andrew@lunn.ch> +Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> +--- + drivers/bus/mvebu-mbus.c | 47 ++++++++++++++++++++++++++++++----------------- + 1 file changed, 30 insertions(+), 17 deletions(-) + +--- a/drivers/bus/mvebu-mbus.c ++++ b/drivers/bus/mvebu-mbus.c +@@ -847,26 +847,14 @@ static __init int mvebu_mbus_debugfs_ini + } + fs_initcall(mvebu_mbus_debugfs_init); + +-int __init mvebu_mbus_init(const char *soc, phys_addr_t mbuswins_phys_base, +- size_t mbuswins_size, +- phys_addr_t sdramwins_phys_base, +- size_t sdramwins_size) ++static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus, ++ phys_addr_t mbuswins_phys_base, ++ size_t mbuswins_size, ++ phys_addr_t sdramwins_phys_base, ++ size_t sdramwins_size) + { +- struct mvebu_mbus_state *mbus = &mbus_state; +- const struct of_device_id *of_id; + int win; + +- for (of_id = of_mvebu_mbus_ids; of_id->compatible; of_id++) +- if (!strcmp(of_id->compatible, soc)) +- break; +- +- if (!of_id->compatible) { +- pr_err("could not find a matching SoC family\n"); +- return -ENODEV; +- } +- +- mbus->soc = of_id->data; +- + mbus->mbuswins_base = ioremap(mbuswins_phys_base, mbuswins_size); + if (!mbus->mbuswins_base) + return -ENOMEM; +@@ -887,3 +875,28 @@ int __init mvebu_mbus_init(const char *s + + return 0; + } ++ ++int __init mvebu_mbus_init(const char *soc, phys_addr_t mbuswins_phys_base, ++ size_t mbuswins_size, ++ phys_addr_t sdramwins_phys_base, ++ size_t sdramwins_size) ++{ ++ const struct of_device_id *of_id; ++ ++ for (of_id = of_mvebu_mbus_ids; of_id->compatible; of_id++) ++ if (!strcmp(of_id->compatible, soc)) ++ break; ++ ++ if (!of_id->compatible) { ++ pr_err("could not find a matching SoC family\n"); ++ return -ENODEV; ++ } ++ ++ mbus_state.soc = of_id->data; ++ ++ return mvebu_mbus_common_init(&mbus_state, ++ mbuswins_phys_base, ++ mbuswins_size, ++ sdramwins_phys_base, ++ sdramwins_size); ++} diff --git a/target/linux/mvebu/patches-3.10/0044-bus-mvebu-mbus-Introduce-device-tree-binding.patch b/target/linux/mvebu/patches-3.10/0044-bus-mvebu-mbus-Introduce-device-tree-binding.patch new file mode 100644 index 0000000000..ef2d1b4792 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0044-bus-mvebu-mbus-Introduce-device-tree-binding.patch @@ -0,0 +1,83 @@ +From e4123095febc94c547c0459db752e7879db79d76 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Date: Tue, 21 May 2013 10:48:54 -0300 +Subject: [PATCH 044/203] bus: mvebu-mbus: Introduce device tree binding + +This patch adds the most fundamental device-tree initialization. +We only introduce what's required to be able to probe the mvebu-mbus +driver from the DT. Follow-up patches will extend the device tree binding, +allowing to describe static address decoding windows. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Tested-by: Andrew Lunn <andrew@lunn.ch> +Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> +--- + drivers/bus/mvebu-mbus.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ + include/linux/mbus.h | 1 + + 2 files changed, 50 insertions(+) + +--- a/drivers/bus/mvebu-mbus.c ++++ b/drivers/bus/mvebu-mbus.c +@@ -900,3 +900,52 @@ int __init mvebu_mbus_init(const char *s + sdramwins_phys_base, + sdramwins_size); + } ++ ++#ifdef CONFIG_OF ++int __init mvebu_mbus_dt_init(void) ++{ ++ struct resource mbuswins_res, sdramwins_res; ++ struct device_node *np, *controller; ++ const struct of_device_id *of_id; ++ const __be32 *prop; ++ int ret; ++ ++ np = of_find_matching_node(NULL, of_mvebu_mbus_ids); ++ if (!np) { ++ pr_err("could not find a matching SoC family\n"); ++ return -ENODEV; ++ } ++ ++ of_id = of_match_node(of_mvebu_mbus_ids, np); ++ mbus_state.soc = of_id->data; ++ ++ prop = of_get_property(np, "controller", NULL); ++ if (!prop) { ++ pr_err("required 'controller' property missing\n"); ++ return -EINVAL; ++ } ++ ++ controller = of_find_node_by_phandle(be32_to_cpup(prop)); ++ if (!controller) { ++ pr_err("could not find an 'mbus-controller' node\n"); ++ return -ENODEV; ++ } ++ ++ if (of_address_to_resource(controller, 0, &mbuswins_res)) { ++ pr_err("cannot get MBUS register address\n"); ++ return -EINVAL; ++ } ++ ++ if (of_address_to_resource(controller, 1, &sdramwins_res)) { ++ pr_err("cannot get SDRAM register address\n"); ++ return -EINVAL; ++ } ++ ++ ret = mvebu_mbus_common_init(&mbus_state, ++ mbuswins_res.start, ++ resource_size(&mbuswins_res), ++ sdramwins_res.start, ++ resource_size(&sdramwins_res)); ++ return ret; ++} ++#endif +--- a/include/linux/mbus.h ++++ b/include/linux/mbus.h +@@ -74,5 +74,6 @@ int mvebu_mbus_del_window(phys_addr_t ba + int mvebu_mbus_init(const char *soc, phys_addr_t mbus_phys_base, + size_t mbus_size, phys_addr_t sdram_phys_base, + size_t sdram_size); ++int mvebu_mbus_dt_init(void); + + #endif /* __LINUX_MBUS_H */ diff --git a/target/linux/mvebu/patches-3.10/0045-bus-mvebu-mbus-Add-static-window-allocation-to-the-D.patch b/target/linux/mvebu/patches-3.10/0045-bus-mvebu-mbus-Add-static-window-allocation-to-the-D.patch new file mode 100644 index 0000000000..d9e783a481 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0045-bus-mvebu-mbus-Add-static-window-allocation-to-the-D.patch @@ -0,0 +1,160 @@ +From ece28a7e105cedb5a9ebd2553aa41d965fb83b64 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Date: Tue, 28 May 2013 07:58:31 -0300 +Subject: [PATCH 045/203] bus: mvebu-mbus: Add static window allocation to the + DT binding + +This patch adds static window allocation to the device tree binding. +Each first-child of the mbus-compatible node, with a suitable 'ranges' +property, declaring an address translation, will trigger an address +decoding window allocation. + +Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Tested-by: Andrew Lunn <andrew@lunn.ch> +Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> +--- + drivers/bus/mvebu-mbus.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 126 insertions(+), 1 deletion(-) + +--- a/drivers/bus/mvebu-mbus.c ++++ b/drivers/bus/mvebu-mbus.c +@@ -902,6 +902,127 @@ int __init mvebu_mbus_init(const char *s + } + + #ifdef CONFIG_OF ++/* ++ * The window IDs in the ranges DT property have the following format: ++ * - bits 28 to 31: MBus custom field ++ * - bits 24 to 27: window target ID ++ * - bits 16 to 23: window attribute ID ++ * - bits 0 to 15: unused ++ */ ++#define CUSTOM(id) (((id) & 0xF0000000) >> 24) ++#define TARGET(id) (((id) & 0x0F000000) >> 24) ++#define ATTR(id) (((id) & 0x00FF0000) >> 16) ++ ++static int __init mbus_dt_setup_win(struct mvebu_mbus_state *mbus, ++ u32 base, u32 size, ++ u8 target, u8 attr) ++{ ++ const struct mvebu_mbus_mapping *map = mbus->soc->map; ++ const char *name; ++ int i; ++ ++ /* Search for a suitable window in the existing mappings */ ++ for (i = 0; map[i].name; i++) ++ if (map[i].target == target && ++ map[i].attr == (attr & map[i].attrmask)) ++ break; ++ ++ name = map[i].name; ++ if (!name) { ++ pr_err("window 0x%x:0x%x is unknown, skipping\n", ++ target, attr); ++ return -EINVAL; ++ } ++ ++ if (!mvebu_mbus_window_conflicts(mbus, base, size, target, attr)) { ++ pr_err("cannot add window '%s', conflicts with another window\n", ++ name); ++ return -EBUSY; ++ } ++ ++ if (mvebu_mbus_alloc_window(mbus, base, size, MVEBU_MBUS_NO_REMAP, ++ target, attr)) { ++ pr_err("cannot add window '%s', too many windows\n", ++ name); ++ return -ENOMEM; ++ } ++ return 0; ++} ++ ++static int __init ++mbus_parse_ranges(struct device_node *node, ++ int *addr_cells, int *c_addr_cells, int *c_size_cells, ++ int *cell_count, const __be32 **ranges_start, ++ const __be32 **ranges_end) ++{ ++ const __be32 *prop; ++ int ranges_len, tuple_len; ++ ++ /* Allow a node with no 'ranges' property */ ++ *ranges_start = of_get_property(node, "ranges", &ranges_len); ++ if (*ranges_start == NULL) { ++ *addr_cells = *c_addr_cells = *c_size_cells = *cell_count = 0; ++ *ranges_start = *ranges_end = NULL; ++ return 0; ++ } ++ *ranges_end = *ranges_start + ranges_len / sizeof(__be32); ++ ++ *addr_cells = of_n_addr_cells(node); ++ ++ prop = of_get_property(node, "#address-cells", NULL); ++ *c_addr_cells = be32_to_cpup(prop); ++ ++ prop = of_get_property(node, "#size-cells", NULL); ++ *c_size_cells = be32_to_cpup(prop); ++ ++ *cell_count = *addr_cells + *c_addr_cells + *c_size_cells; ++ tuple_len = (*cell_count) * sizeof(__be32); ++ ++ if (ranges_len % tuple_len) { ++ pr_warn("malformed ranges entry '%s'\n", node->name); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int __init mbus_dt_setup(struct mvebu_mbus_state *mbus, ++ struct device_node *np) ++{ ++ int addr_cells, c_addr_cells, c_size_cells; ++ int i, ret, cell_count; ++ const __be32 *r, *ranges_start, *ranges_end; ++ ++ ret = mbus_parse_ranges(np, &addr_cells, &c_addr_cells, ++ &c_size_cells, &cell_count, ++ &ranges_start, &ranges_end); ++ if (ret < 0) ++ return ret; ++ ++ for (i = 0, r = ranges_start; r < ranges_end; r += cell_count, i++) { ++ u32 windowid, base, size; ++ u8 target, attr; ++ ++ /* ++ * An entry with a non-zero custom field do not ++ * correspond to a static window, so skip it. ++ */ ++ windowid = of_read_number(r, 1); ++ if (CUSTOM(windowid)) ++ continue; ++ ++ target = TARGET(windowid); ++ attr = ATTR(windowid); ++ ++ base = of_read_number(r + c_addr_cells, addr_cells); ++ size = of_read_number(r + c_addr_cells + addr_cells, ++ c_size_cells); ++ ret = mbus_dt_setup_win(mbus, base, size, target, attr); ++ if (ret < 0) ++ return ret; ++ } ++ return 0; ++} ++ + int __init mvebu_mbus_dt_init(void) + { + struct resource mbuswins_res, sdramwins_res; +@@ -946,6 +1067,10 @@ int __init mvebu_mbus_dt_init(void) + resource_size(&mbuswins_res), + sdramwins_res.start, + resource_size(&sdramwins_res)); +- return ret; ++ if (ret) ++ return ret; ++ ++ /* Setup statically declared windows in the DT */ ++ return mbus_dt_setup(&mbus_state, np); + } + #endif diff --git a/target/linux/mvebu/patches-3.10/0046-bus-mvebu-mbus-Add-new-API-for-the-PCIe-memory-and-I.patch b/target/linux/mvebu/patches-3.10/0046-bus-mvebu-mbus-Add-new-API-for-the-PCIe-memory-and-I.patch new file mode 100644 index 0000000000..973ffdef46 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0046-bus-mvebu-mbus-Add-new-API-for-the-PCIe-memory-and-I.patch @@ -0,0 +1,121 @@ +From c9646c891dbd07061a9ff5e061f9f9e54c571349 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Date: Tue, 9 Jul 2013 10:41:53 -0300 +Subject: [PATCH 046/203] bus: mvebu-mbus: Add new API for the PCIe memory and + IO aperture + +We add two optional properties to the MBus DT binding, to encode +the PCIe memory and IO aperture. This allows such information to +be retrieved by -for instance- the pci driver to allocate the +MBus decoding windows. + +Correspondingly, and in order to retrieve this information, +we add two new APIs. + +Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Tested-by: Andrew Lunn <andrew@lunn.ch> +Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> +--- + drivers/bus/mvebu-mbus.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ + include/linux/mbus.h | 4 ++++ + 2 files changed, 53 insertions(+) + +--- a/drivers/bus/mvebu-mbus.c ++++ b/drivers/bus/mvebu-mbus.c +@@ -142,6 +142,8 @@ struct mvebu_mbus_state { + struct dentry *debugfs_root; + struct dentry *debugfs_sdram; + struct dentry *debugfs_devs; ++ struct resource pcie_mem_aperture; ++ struct resource pcie_io_aperture; + const struct mvebu_mbus_soc_data *soc; + int hw_io_coherency; + }; +@@ -821,6 +823,20 @@ int mvebu_mbus_del_window(phys_addr_t ba + return 0; + } + ++void mvebu_mbus_get_pcie_mem_aperture(struct resource *res) ++{ ++ if (!res) ++ return; ++ *res = mbus_state.pcie_mem_aperture; ++} ++ ++void mvebu_mbus_get_pcie_io_aperture(struct resource *res) ++{ ++ if (!res) ++ return; ++ *res = mbus_state.pcie_io_aperture; ++} ++ + static __init int mvebu_mbus_debugfs_init(void) + { + struct mvebu_mbus_state *s = &mbus_state; +@@ -1023,6 +1039,35 @@ static int __init mbus_dt_setup(struct m + return 0; + } + ++static void __init mvebu_mbus_get_pcie_resources(struct device_node *np, ++ struct resource *mem, ++ struct resource *io) ++{ ++ u32 reg[2]; ++ int ret; ++ ++ /* ++ * These are optional, so we clear them and they'll ++ * be zero if they are missing from the DT. ++ */ ++ memset(mem, 0, sizeof(struct resource)); ++ memset(io, 0, sizeof(struct resource)); ++ ++ ret = of_property_read_u32_array(np, "pcie-mem-aperture", reg, ARRAY_SIZE(reg)); ++ if (!ret) { ++ mem->start = reg[0]; ++ mem->end = mem->start + reg[1]; ++ mem->flags = IORESOURCE_MEM; ++ } ++ ++ ret = of_property_read_u32_array(np, "pcie-io-aperture", reg, ARRAY_SIZE(reg)); ++ if (!ret) { ++ io->start = reg[0]; ++ io->end = io->start + reg[1]; ++ io->flags = IORESOURCE_IO; ++ } ++} ++ + int __init mvebu_mbus_dt_init(void) + { + struct resource mbuswins_res, sdramwins_res; +@@ -1062,6 +1107,10 @@ int __init mvebu_mbus_dt_init(void) + return -EINVAL; + } + ++ /* Get optional pcie-{mem,io}-aperture properties */ ++ mvebu_mbus_get_pcie_resources(np, &mbus_state.pcie_mem_aperture, ++ &mbus_state.pcie_io_aperture); ++ + ret = mvebu_mbus_common_init(&mbus_state, + mbuswins_res.start, + resource_size(&mbuswins_res), +--- a/include/linux/mbus.h ++++ b/include/linux/mbus.h +@@ -11,6 +11,8 @@ + #ifndef __LINUX_MBUS_H + #define __LINUX_MBUS_H + ++struct resource; ++ + struct mbus_dram_target_info + { + /* +@@ -59,6 +61,8 @@ static inline const struct mbus_dram_tar + } + #endif + ++void mvebu_mbus_get_pcie_mem_aperture(struct resource *res); ++void mvebu_mbus_get_pcie_io_aperture(struct resource *res); + int mvebu_mbus_add_window_remap_flags(const char *devname, phys_addr_t base, + size_t size, phys_addr_t remap, + unsigned int flags); diff --git a/target/linux/mvebu/patches-3.10/0047-PCI-mvebu-Adapt-to-the-new-device-tree-layout.patch b/target/linux/mvebu/patches-3.10/0047-PCI-mvebu-Adapt-to-the-new-device-tree-layout.patch new file mode 100644 index 0000000000..08de63d422 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0047-PCI-mvebu-Adapt-to-the-new-device-tree-layout.patch @@ -0,0 +1,184 @@ +From 90b1f963b07d05e8243e5053a910e8a47222f7a1 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Fri, 5 Jul 2013 14:54:17 +0200 +Subject: [PATCH 047/203] PCI: mvebu: Adapt to the new device tree layout + +The new device tree layout encodes the window's target ID and attribute +in the PCIe controller node's ranges property. This allows to parse +such entries to obtain such information and use the recently introduced +MBus API to create the windows, instead of using the current name based +scheme. + +Acked-by: Bjorn Helgaas <bhelgaas@google.com> +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Tested-by: Andrew Lunn <andrew@lunn.ch> +Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> +--- + drivers/pci/host/pci-mvebu.c | 113 ++++++++++++++++++++++++++++++++----------- + 1 file changed, 84 insertions(+), 29 deletions(-) + +--- a/drivers/pci/host/pci-mvebu.c ++++ b/drivers/pci/host/pci-mvebu.c +@@ -119,6 +119,10 @@ struct mvebu_pcie_port { + u32 port; + u32 lane; + int devfn; ++ unsigned int mem_target; ++ unsigned int mem_attr; ++ unsigned int io_target; ++ unsigned int io_attr; + struct clk *clk; + struct mvebu_sw_pci_bridge bridge; + struct device_node *dn; +@@ -303,10 +307,9 @@ static void mvebu_pcie_handle_iobase_cha + (port->bridge.iolimitupper << 16)) - + iobase); + +- mvebu_mbus_add_window_remap_flags(port->name, port->iowin_base, +- port->iowin_size, +- iobase, +- MVEBU_MBUS_PCI_IO); ++ mvebu_mbus_add_window_remap_by_id(port->io_target, port->io_attr, ++ port->iowin_base, port->iowin_size, ++ iobase); + + pci_ioremap_io(iobase, port->iowin_base); + } +@@ -338,10 +341,8 @@ static void mvebu_pcie_handle_membase_ch + (((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) - + port->memwin_base; + +- mvebu_mbus_add_window_remap_flags(port->name, port->memwin_base, +- port->memwin_size, +- MVEBU_MBUS_NO_REMAP, +- MVEBU_MBUS_PCI_MEM); ++ mvebu_mbus_add_window_by_id(port->mem_target, port->mem_attr, ++ port->memwin_base, port->memwin_size); + } + + /* +@@ -730,12 +731,54 @@ mvebu_pcie_map_registers(struct platform + return devm_request_and_ioremap(&pdev->dev, ®s); + } + ++#define DT_FLAGS_TO_TYPE(flags) (((flags) >> 24) & 0x03) ++#define DT_TYPE_IO 0x1 ++#define DT_TYPE_MEM32 0x2 ++#define DT_CPUADDR_TO_TARGET(cpuaddr) (((cpuaddr) >> 56) & 0xFF) ++#define DT_CPUADDR_TO_ATTR(cpuaddr) (((cpuaddr) >> 48) & 0xFF) ++ ++static int mvebu_get_tgt_attr(struct device_node *np, int devfn, ++ unsigned long type, int *tgt, int *attr) ++{ ++ const int na = 3, ns = 2; ++ const __be32 *range; ++ int rlen, nranges, rangesz, pna, i; ++ ++ range = of_get_property(np, "ranges", &rlen); ++ if (!range) ++ return -EINVAL; ++ ++ pna = of_n_addr_cells(np); ++ rangesz = pna + na + ns; ++ nranges = rlen / sizeof(__be32) / rangesz; ++ ++ for (i = 0; i < nranges; i++) { ++ u32 flags = of_read_number(range, 1); ++ u32 slot = of_read_number(range, 2); ++ u64 cpuaddr = of_read_number(range + na, pna); ++ unsigned long rtype; ++ ++ if (DT_FLAGS_TO_TYPE(flags) == DT_TYPE_IO) ++ rtype = IORESOURCE_IO; ++ else if (DT_FLAGS_TO_TYPE(flags) == DT_TYPE_MEM32) ++ rtype = IORESOURCE_MEM; ++ ++ if (slot == PCI_SLOT(devfn) && type == rtype) { ++ *tgt = DT_CPUADDR_TO_TARGET(cpuaddr); ++ *attr = DT_CPUADDR_TO_ATTR(cpuaddr); ++ return 0; ++ } ++ ++ range += rangesz; ++ } ++ ++ return -ENOENT; ++} ++ + static int __init mvebu_pcie_probe(struct platform_device *pdev) + { + struct mvebu_pcie *pcie; + struct device_node *np = pdev->dev.of_node; +- struct of_pci_range range; +- struct of_pci_range_parser parser; + struct device_node *child; + int i, ret; + +@@ -746,29 +789,25 @@ static int __init mvebu_pcie_probe(struc + + pcie->pdev = pdev; + +- if (of_pci_range_parser_init(&parser, np)) ++ /* Get the PCIe memory and I/O aperture */ ++ mvebu_mbus_get_pcie_mem_aperture(&pcie->mem); ++ if (resource_size(&pcie->mem) == 0) { ++ dev_err(&pdev->dev, "invalid memory aperture size\n"); + return -EINVAL; ++ } + +- /* Get the I/O and memory ranges from DT */ +- for_each_of_pci_range(&parser, &range) { +- unsigned long restype = range.flags & IORESOURCE_TYPE_BITS; +- if (restype == IORESOURCE_IO) { +- of_pci_range_to_resource(&range, np, &pcie->io); +- of_pci_range_to_resource(&range, np, &pcie->realio); +- pcie->io.name = "I/O"; +- pcie->realio.start = max_t(resource_size_t, +- PCIBIOS_MIN_IO, +- range.pci_addr); +- pcie->realio.end = min_t(resource_size_t, +- IO_SPACE_LIMIT, +- range.pci_addr + range.size); +- } +- if (restype == IORESOURCE_MEM) { +- of_pci_range_to_resource(&range, np, &pcie->mem); +- pcie->mem.name = "MEM"; +- } ++ mvebu_mbus_get_pcie_io_aperture(&pcie->io); ++ if (resource_size(&pcie->io) == 0) { ++ dev_err(&pdev->dev, "invalid I/O aperture size\n"); ++ return -EINVAL; + } + ++ pcie->realio.flags = pcie->io.flags; ++ pcie->realio.start = PCIBIOS_MIN_IO; ++ pcie->realio.end = min_t(resource_size_t, ++ IO_SPACE_LIMIT, ++ resource_size(&pcie->io)); ++ + /* Get the bus range */ + ret = of_pci_parse_bus_range(np, &pcie->busn); + if (ret) { +@@ -816,6 +855,22 @@ static int __init mvebu_pcie_probe(struc + if (port->devfn < 0) + continue; + ++ ret = mvebu_get_tgt_attr(np, port->devfn, IORESOURCE_MEM, ++ &port->mem_target, &port->mem_attr); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "PCIe%d.%d: cannot get tgt/attr for mem window\n", ++ port->port, port->lane); ++ continue; ++ } ++ ++ ret = mvebu_get_tgt_attr(np, port->devfn, IORESOURCE_IO, ++ &port->io_target, &port->io_attr); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "PCIe%d.%d: cannot get tgt/attr for io window\n", ++ port->port, port->lane); ++ continue; ++ } ++ + port->base = mvebu_pcie_map_registers(pdev, child, port); + if (!port->base) { + dev_err(&pdev->dev, "PCIe%d.%d: cannot map registers\n", diff --git a/target/linux/mvebu/patches-3.10/0048-PCI-mvebu-Check-valid-base-address-before-port-setup.patch b/target/linux/mvebu/patches-3.10/0048-PCI-mvebu-Check-valid-base-address-before-port-setup.patch new file mode 100644 index 0000000000..c9022bbc77 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0048-PCI-mvebu-Check-valid-base-address-before-port-setup.patch @@ -0,0 +1,29 @@ +From 3dc077a80c71050e198e7884707ece042443fe3c Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Date: Tue, 23 Jul 2013 07:36:00 -0300 +Subject: [PATCH 048/203] PCI: mvebu: Check valid base address before port + setup + +This driver does not fail to probe when it cannot obtain +a port base address. Therefore, add a check for NULL base address +before setting up the port, which prevents a kernel panic in such +cases. + +Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> +Tested-by: Andrew Lunn <andrew@lunn.ch> +Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> +--- + drivers/pci/host/pci-mvebu.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/pci/host/pci-mvebu.c ++++ b/drivers/pci/host/pci-mvebu.c +@@ -637,6 +637,8 @@ static int __init mvebu_pcie_setup(int n + + for (i = 0; i < pcie->nports; i++) { + struct mvebu_pcie_port *port = &pcie->ports[i]; ++ if (!port->base) ++ continue; + mvebu_pcie_setup_hw(port); + } + diff --git a/target/linux/mvebu/patches-3.10/0049-bus-mvebu-mbus-Remove-the-no-longer-used-name-based-.patch b/target/linux/mvebu/patches-3.10/0049-bus-mvebu-mbus-Remove-the-no-longer-used-name-based-.patch new file mode 100644 index 0000000000..ac97c113c4 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0049-bus-mvebu-mbus-Remove-the-no-longer-used-name-based-.patch @@ -0,0 +1,82 @@ +From 1e94a8740cb1f9c328a3ae8ec4727d90bfb2d7f7 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Fri, 5 Jul 2013 14:54:23 +0200 +Subject: [PATCH 049/203] bus: mvebu-mbus: Remove the no longer used name-based + API + +Now that every user of the deprecated name-based API has been +converted to using the ID-based API, let's remove the former one. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Tested-by: Andrew Lunn <andrew@lunn.ch> +Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> +--- + drivers/bus/mvebu-mbus.c | 38 -------------------------------------- + include/linux/mbus.h | 5 ----- + 2 files changed, 43 deletions(-) + +--- a/drivers/bus/mvebu-mbus.c ++++ b/drivers/bus/mvebu-mbus.c +@@ -766,44 +766,6 @@ int mvebu_mbus_add_window_remap_by_id(un + return mvebu_mbus_alloc_window(s, base, size, remap, target, attribute); + } + +-int mvebu_mbus_add_window_remap_flags(const char *devname, phys_addr_t base, +- size_t size, phys_addr_t remap, +- unsigned int flags) +-{ +- struct mvebu_mbus_state *s = &mbus_state; +- u8 target, attr; +- int i; +- +- if (!s->soc->map) +- return -ENODEV; +- +- for (i = 0; s->soc->map[i].name; i++) +- if (!strcmp(s->soc->map[i].name, devname)) +- break; +- +- if (!s->soc->map[i].name) { +- pr_err("unknown device '%s'\n", devname); +- return -ENODEV; +- } +- +- target = s->soc->map[i].target; +- attr = s->soc->map[i].attr; +- +- if (flags == MVEBU_MBUS_PCI_MEM) +- attr |= 0x8; +- else if (flags == MVEBU_MBUS_PCI_WA) +- attr |= 0x28; +- +- return mvebu_mbus_add_window_remap_by_id(target, attr, base, +- size, remap); +-} +- +-int mvebu_mbus_add_window(const char *devname, phys_addr_t base, size_t size) +-{ +- return mvebu_mbus_add_window_remap_flags(devname, base, size, +- MVEBU_MBUS_NO_REMAP, 0); +-} +- + int mvebu_mbus_add_window_by_id(unsigned int target, unsigned int attribute, + phys_addr_t base, size_t size) + { +--- a/include/linux/mbus.h ++++ b/include/linux/mbus.h +@@ -63,15 +63,10 @@ static inline const struct mbus_dram_tar + + void mvebu_mbus_get_pcie_mem_aperture(struct resource *res); + void mvebu_mbus_get_pcie_io_aperture(struct resource *res); +-int mvebu_mbus_add_window_remap_flags(const char *devname, phys_addr_t base, +- size_t size, phys_addr_t remap, +- unsigned int flags); + int mvebu_mbus_add_window_remap_by_id(unsigned int target, + unsigned int attribute, + phys_addr_t base, size_t size, + phys_addr_t remap); +-int mvebu_mbus_add_window(const char *devname, phys_addr_t base, +- size_t size); + int mvebu_mbus_add_window_by_id(unsigned int target, unsigned int attribute, + phys_addr_t base, size_t size); + int mvebu_mbus_del_window(phys_addr_t base, size_t size); diff --git a/target/linux/mvebu/patches-3.10/0050-bus-mvebu-mbus-Remove-name-target-attribute-mapping-.patch b/target/linux/mvebu/patches-3.10/0050-bus-mvebu-mbus-Remove-name-target-attribute-mapping-.patch new file mode 100644 index 0000000000..0b6263309b --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0050-bus-mvebu-mbus-Remove-name-target-attribute-mapping-.patch @@ -0,0 +1,266 @@ +From 08c3b38a75ca47b74c81d14e1715ab9dc7b0e5cb Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Fri, 5 Jul 2013 14:54:24 +0200 +Subject: [PATCH 050/203] bus: mvebu-mbus: Remove name -> target, attribute + mapping tables + +This tables were used together with the name-based MBus window +creation API. Since that's has been removed, we can also remove +the tables. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Tested-by: Andrew Lunn <andrew@lunn.ch> +Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> +--- + drivers/bus/mvebu-mbus.c | 150 +++-------------------------------------------- + 1 file changed, 7 insertions(+), 143 deletions(-) + +--- a/drivers/bus/mvebu-mbus.c ++++ b/drivers/bus/mvebu-mbus.c +@@ -97,33 +97,6 @@ + + #define DOVE_DDR_BASE_CS_OFF(n) ((n) << 4) + +-struct mvebu_mbus_mapping { +- const char *name; +- u8 target; +- u8 attr; +- u8 attrmask; +-}; +- +-/* +- * Masks used for the 'attrmask' field of mvebu_mbus_mapping. They +- * allow to get the real attribute value, discarding the special bits +- * used to select a PCI MEM region or a PCI WA region. This allows the +- * debugfs code to reverse-match the name of a device from its +- * target/attr values. +- * +- * For all devices except PCI, all bits of 'attr' must be +- * considered. For most SoCs, only bit 3 should be ignored (it allows +- * to select between PCI MEM and PCI I/O). On Orion5x however, there +- * is the special bit 5 to select a PCI WA region. +- */ +-#define MAPDEF_NOMASK 0xff +-#define MAPDEF_PCIMASK 0xf7 +-#define MAPDEF_ORIONPCIMASK 0xd7 +- +-/* Macro used to define one mvebu_mbus_mapping entry */ +-#define MAPDEF(__n, __t, __a, __m) \ +- { .name = __n, .target = __t, .attr = __a, .attrmask = __m } +- + struct mvebu_mbus_state; + + struct mvebu_mbus_soc_data { +@@ -133,7 +106,6 @@ struct mvebu_mbus_soc_data { + void (*setup_cpu_target)(struct mvebu_mbus_state *s); + int (*show_cpu_target)(struct mvebu_mbus_state *s, + struct seq_file *seq, void *v); +- const struct mvebu_mbus_mapping *map; + }; + + struct mvebu_mbus_state { +@@ -430,8 +402,7 @@ static int mvebu_devs_debug_show(struct + u64 wbase, wremap; + u32 wsize; + u8 wtarget, wattr; +- int enabled, i; +- const char *name; ++ int enabled; + + mvebu_mbus_read_window(mbus, win, + &enabled, &wbase, &wsize, +@@ -442,18 +413,9 @@ static int mvebu_devs_debug_show(struct + continue; + } + +- +- for (i = 0; mbus->soc->map[i].name; i++) +- if (mbus->soc->map[i].target == wtarget && +- mbus->soc->map[i].attr == +- (wattr & mbus->soc->map[i].attrmask)) +- break; +- +- name = mbus->soc->map[i].name ?: "unknown"; +- +- seq_printf(seq, "[%02d] %016llx - %016llx : %s", ++ seq_printf(seq, "[%02d] %016llx - %016llx : %04x:%04x", + win, (unsigned long long)wbase, +- (unsigned long long)(wbase + wsize), name); ++ (unsigned long long)(wbase + wsize), wtarget, wattr); + + if (win < mbus->soc->num_remappable_wins) { + seq_printf(seq, " (remap %016llx)\n", +@@ -578,45 +540,12 @@ mvebu_mbus_dove_setup_cpu_target(struct + mvebu_mbus_dram_info.num_cs = cs; + } + +-static const struct mvebu_mbus_mapping armada_370_map[] = { +- MAPDEF("bootrom", 1, 0xe0, MAPDEF_NOMASK), +- MAPDEF("devbus-boot", 1, 0x2f, MAPDEF_NOMASK), +- MAPDEF("devbus-cs0", 1, 0x3e, MAPDEF_NOMASK), +- MAPDEF("devbus-cs1", 1, 0x3d, MAPDEF_NOMASK), +- MAPDEF("devbus-cs2", 1, 0x3b, MAPDEF_NOMASK), +- MAPDEF("devbus-cs3", 1, 0x37, MAPDEF_NOMASK), +- MAPDEF("pcie0.0", 4, 0xe0, MAPDEF_PCIMASK), +- MAPDEF("pcie1.0", 8, 0xe0, MAPDEF_PCIMASK), +- {}, +-}; +- + static const struct mvebu_mbus_soc_data armada_370_mbus_data = { + .num_wins = 20, + .num_remappable_wins = 8, + .win_cfg_offset = armada_370_xp_mbus_win_offset, + .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, + .show_cpu_target = mvebu_sdram_debug_show_orion, +- .map = armada_370_map, +-}; +- +-static const struct mvebu_mbus_mapping armada_xp_map[] = { +- MAPDEF("bootrom", 1, 0x1d, MAPDEF_NOMASK), +- MAPDEF("devbus-boot", 1, 0x2f, MAPDEF_NOMASK), +- MAPDEF("devbus-cs0", 1, 0x3e, MAPDEF_NOMASK), +- MAPDEF("devbus-cs1", 1, 0x3d, MAPDEF_NOMASK), +- MAPDEF("devbus-cs2", 1, 0x3b, MAPDEF_NOMASK), +- MAPDEF("devbus-cs3", 1, 0x37, MAPDEF_NOMASK), +- MAPDEF("pcie0.0", 4, 0xe0, MAPDEF_PCIMASK), +- MAPDEF("pcie0.1", 4, 0xd0, MAPDEF_PCIMASK), +- MAPDEF("pcie0.2", 4, 0xb0, MAPDEF_PCIMASK), +- MAPDEF("pcie0.3", 4, 0x70, MAPDEF_PCIMASK), +- MAPDEF("pcie1.0", 8, 0xe0, MAPDEF_PCIMASK), +- MAPDEF("pcie1.1", 8, 0xd0, MAPDEF_PCIMASK), +- MAPDEF("pcie1.2", 8, 0xb0, MAPDEF_PCIMASK), +- MAPDEF("pcie1.3", 8, 0x70, MAPDEF_PCIMASK), +- MAPDEF("pcie2.0", 4, 0xf0, MAPDEF_PCIMASK), +- MAPDEF("pcie3.0", 8, 0xf0, MAPDEF_PCIMASK), +- {}, + }; + + static const struct mvebu_mbus_soc_data armada_xp_mbus_data = { +@@ -625,15 +554,6 @@ static const struct mvebu_mbus_soc_data + .win_cfg_offset = armada_370_xp_mbus_win_offset, + .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, + .show_cpu_target = mvebu_sdram_debug_show_orion, +- .map = armada_xp_map, +-}; +- +-static const struct mvebu_mbus_mapping kirkwood_map[] = { +- MAPDEF("pcie0.0", 4, 0xe0, MAPDEF_PCIMASK), +- MAPDEF("pcie1.0", 4, 0xd0, MAPDEF_PCIMASK), +- MAPDEF("sram", 3, 0x01, MAPDEF_NOMASK), +- MAPDEF("nand", 1, 0x2f, MAPDEF_NOMASK), +- {}, + }; + + static const struct mvebu_mbus_soc_data kirkwood_mbus_data = { +@@ -642,16 +562,6 @@ static const struct mvebu_mbus_soc_data + .win_cfg_offset = orion_mbus_win_offset, + .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, + .show_cpu_target = mvebu_sdram_debug_show_orion, +- .map = kirkwood_map, +-}; +- +-static const struct mvebu_mbus_mapping dove_map[] = { +- MAPDEF("pcie0.0", 0x4, 0xe0, MAPDEF_PCIMASK), +- MAPDEF("pcie1.0", 0x8, 0xe0, MAPDEF_PCIMASK), +- MAPDEF("cesa", 0x3, 0x01, MAPDEF_NOMASK), +- MAPDEF("bootrom", 0x1, 0xfd, MAPDEF_NOMASK), +- MAPDEF("scratchpad", 0xd, 0x0, MAPDEF_NOMASK), +- {}, + }; + + static const struct mvebu_mbus_soc_data dove_mbus_data = { +@@ -660,18 +570,6 @@ static const struct mvebu_mbus_soc_data + .win_cfg_offset = orion_mbus_win_offset, + .setup_cpu_target = mvebu_mbus_dove_setup_cpu_target, + .show_cpu_target = mvebu_sdram_debug_show_dove, +- .map = dove_map, +-}; +- +-static const struct mvebu_mbus_mapping orion5x_map[] = { +- MAPDEF("pcie0.0", 4, 0x51, MAPDEF_ORIONPCIMASK), +- MAPDEF("pci0.0", 3, 0x51, MAPDEF_ORIONPCIMASK), +- MAPDEF("devbus-boot", 1, 0x0f, MAPDEF_NOMASK), +- MAPDEF("devbus-cs0", 1, 0x1e, MAPDEF_NOMASK), +- MAPDEF("devbus-cs1", 1, 0x1d, MAPDEF_NOMASK), +- MAPDEF("devbus-cs2", 1, 0x1b, MAPDEF_NOMASK), +- MAPDEF("sram", 0, 0x00, MAPDEF_NOMASK), +- {}, + }; + + /* +@@ -684,7 +582,6 @@ static const struct mvebu_mbus_soc_data + .win_cfg_offset = orion_mbus_win_offset, + .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, + .show_cpu_target = mvebu_sdram_debug_show_orion, +- .map = orion5x_map, + }; + + static const struct mvebu_mbus_soc_data orion5x_2win_mbus_data = { +@@ -693,21 +590,6 @@ static const struct mvebu_mbus_soc_data + .win_cfg_offset = orion_mbus_win_offset, + .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, + .show_cpu_target = mvebu_sdram_debug_show_orion, +- .map = orion5x_map, +-}; +- +-static const struct mvebu_mbus_mapping mv78xx0_map[] = { +- MAPDEF("pcie0.0", 4, 0xe0, MAPDEF_PCIMASK), +- MAPDEF("pcie0.1", 4, 0xd0, MAPDEF_PCIMASK), +- MAPDEF("pcie0.2", 4, 0xb0, MAPDEF_PCIMASK), +- MAPDEF("pcie0.3", 4, 0x70, MAPDEF_PCIMASK), +- MAPDEF("pcie1.0", 8, 0xe0, MAPDEF_PCIMASK), +- MAPDEF("pcie1.1", 8, 0xd0, MAPDEF_PCIMASK), +- MAPDEF("pcie1.2", 8, 0xb0, MAPDEF_PCIMASK), +- MAPDEF("pcie1.3", 8, 0x70, MAPDEF_PCIMASK), +- MAPDEF("pcie2.0", 4, 0xf0, MAPDEF_PCIMASK), +- MAPDEF("pcie3.0", 8, 0xf0, MAPDEF_PCIMASK), +- {}, + }; + + static const struct mvebu_mbus_soc_data mv78xx0_mbus_data = { +@@ -716,7 +598,6 @@ static const struct mvebu_mbus_soc_data + .win_cfg_offset = mv78xx0_mbus_win_offset, + .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, + .show_cpu_target = mvebu_sdram_debug_show_orion, +- .map = mv78xx0_map, + }; + + /* +@@ -895,33 +776,16 @@ static int __init mbus_dt_setup_win(stru + u32 base, u32 size, + u8 target, u8 attr) + { +- const struct mvebu_mbus_mapping *map = mbus->soc->map; +- const char *name; +- int i; +- +- /* Search for a suitable window in the existing mappings */ +- for (i = 0; map[i].name; i++) +- if (map[i].target == target && +- map[i].attr == (attr & map[i].attrmask)) +- break; +- +- name = map[i].name; +- if (!name) { +- pr_err("window 0x%x:0x%x is unknown, skipping\n", +- target, attr); +- return -EINVAL; +- } +- + if (!mvebu_mbus_window_conflicts(mbus, base, size, target, attr)) { +- pr_err("cannot add window '%s', conflicts with another window\n", +- name); ++ pr_err("cannot add window '%04x:%04x', conflicts with another window\n", ++ target, attr); + return -EBUSY; + } + + if (mvebu_mbus_alloc_window(mbus, base, size, MVEBU_MBUS_NO_REMAP, + target, attr)) { +- pr_err("cannot add window '%s', too many windows\n", +- name); ++ pr_err("cannot add window '%04x:%04x', too many windows\n", ++ target, attr); + return -ENOMEM; + } + return 0; diff --git a/target/linux/mvebu/patches-3.10/0051-bus-mvebu-mbus-Update-main-description.patch b/target/linux/mvebu/patches-3.10/0051-bus-mvebu-mbus-Update-main-description.patch new file mode 100644 index 0000000000..8e10d90105 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0051-bus-mvebu-mbus-Update-main-description.patch @@ -0,0 +1,35 @@ +From 8f14bc2a883316dfd95383900c61d7d9183e8eaf Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Fri, 5 Jul 2013 14:54:25 +0200 +Subject: [PATCH 051/203] bus: mvebu-mbus: Update main description + +After replacing the MBus name-based by the new ID-based API +let's fix the general description of the driver at the beginning +of the file. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Tested-by: Andrew Lunn <andrew@lunn.ch> +Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> +--- + drivers/bus/mvebu-mbus.c | 10 +++------- + 1 file changed, 3 insertions(+), 7 deletions(-) + +--- a/drivers/bus/mvebu-mbus.c ++++ b/drivers/bus/mvebu-mbus.c +@@ -35,13 +35,9 @@ + * + * - Provides an API for platform code or device drivers to + * dynamically add or remove address decoding windows for the CPU -> +- * device accesses. This API is mvebu_mbus_add_window(), +- * mvebu_mbus_add_window_remap_flags() and +- * mvebu_mbus_del_window(). Since the (target, attribute) values +- * differ from one SoC family to another, the API uses a 'const char +- * *' string to identify devices, and this driver is responsible for +- * knowing the mapping between the name of a device and its +- * corresponding (target, attribute) in the current SoC family. ++ * device accesses. This API is mvebu_mbus_add_window_by_id(), ++ * mvebu_mbus_add_window_remap_by_id() and ++ * mvebu_mbus_del_window(). + * + * - Provides a debugfs interface in /sys/kernel/debug/mvebu-mbus/ to + * see the list of CPU -> SDRAM windows and their configuration diff --git a/target/linux/mvebu/patches-3.10/0052-bus-mvebu-mbus-Factorize-Armada-370-XP-data-structur.patch b/target/linux/mvebu/patches-3.10/0052-bus-mvebu-mbus-Factorize-Armada-370-XP-data-structur.patch new file mode 100644 index 0000000000..382aa438b5 --- /dev/null +++ b/target/linux/mvebu/patches-3.10/0052-bus-mvebu-mbus-Factorize-Armada-370-XP-data-structur.patch @@ -0,0 +1,48 @@ +From 2c8f0b1810ff9cd45ed2055441b4c43afcfb7d2a Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Date: Fri, 5 Jul 2013 14:54:26 +0200 +Subject: [PATCH 052/203] bus: mvebu-mbus: Factorize Armada 370/XP data + structures + +These structures were only different in the mapping tables. +Now that those tables have been removed, it doesn't make any sense +to keep different structures. + +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Tested-by: Andrew Lunn <andrew@lunn.ch> +Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> +--- + drivers/bus/mvebu-mbus.c | 14 +++----------- + 1 file changed, 3 insertions(+), 11 deletions(-) + +--- a/drivers/bus/mvebu-mbus.c ++++ b/drivers/bus/mvebu-mbus.c +@@ -536,15 +536,7 @@ mvebu_mbus_dove_setup_cpu_target(struct + mvebu_mbus_dram_info.num_cs = cs; + } + +-static const struct mvebu_mbus_soc_data armada_370_mbus_data = { +- .num_wins = 20, +- .num_remappable_wins = 8, +- .win_cfg_offset = armada_370_xp_mbus_win_offset, +- .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, +- .show_cpu_target = mvebu_sdram_debug_show_orion, +-}; +- +-static const struct mvebu_mbus_soc_data armada_xp_mbus_data = { ++static const struct mvebu_mbus_soc_data armada_370_xp_mbus_data = { + .num_wins = 20, + .num_remappable_wins = 8, + .win_cfg_offset = armada_370_xp_mbus_win_offset, +@@ -604,9 +596,9 @@ static const struct mvebu_mbus_soc_data + */ + static const struct of_device_id of_mvebu_mbus_ids[] = { + { .compatible = "marvell,armada370-mbus", +- .data = &armada_370_mbus_data, }, ++ .data = &armada_370_xp_mbus_data, }, + { .compatible = "marvell,armadaxp-mbus", +- .data = &armada_xp_mbus_data, }, ++ .data = &armada_370_xp_mbus_data, }, + { .compatible = "marvell,kirkwood-mbus", + .data = &kirkwood_mbus_data, }, + { .compatible = "marvell,dove-mbus", |