ARM: SoC platform changes for 3.12

This branch contains mostly additions and changes to platform enablement
 and SoC-level drivers. Since there's sometimes a dependency on device-tree
 changes, there's also a fair amount of those in this branch.
 
 Pieces worth mentioning are:
 
 - Mbus driver for Marvell platforms, allowing kernel configuration
   and resource allocation of on-chip peripherals.
 - Enablement of the mbus infrastructure from Marvell PCI-e drivers.
 - Preparation of MSI support for Marvell platforms.
 - Addition of new PCI-e host controller driver for Tegra platforms
 - Some churn caused by sharing of macro names between i.MX 6Q and 6DL
   platforms in the device tree sources and header files.
 - Various suspend/PM updates for Tegra, including LP1 support.
 - Versatile Express support for MCPM, part of big little support.
 - Allwinner platform support for A20 and A31 SoCs (dual and quad Cortex-A7)
 - OMAP2+ support for DRA7, a new Cortex-A15-based SoC.
 
 The code that touches other architectures are patches moving
 MSI arch-specific functions over to weak symbols and removal of
 ARCH_SUPPORTS_MSI, acked by PCI maintainers.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQIcBAABAgAGBQJSKhYmAAoJEIwa5zzehBx322AP/1ONYs8o8f7/Gzq6lZvTN6T3
 0pBTApg6Jfioi3lwKvUAEIcsW82YKQ+UZkbW66GQH6+Ri4aZJKZHuz0+JPU67OJ4
 LtSLuzVWrymy2VOOUvAnS/SXkOZw/pHhU4cLNHn1dMndhUL1Uqp9/XwuiHEQyFsP
 uOkpcBtIu0EWElov0PKKZ5SWBg8JJs2vy5ydiViGelWHCrZvDDZkWzIsDcBQxJLQ
 juzT4+JE+KOu7vKmfw78o6iHoCS2TBRAN9YUCajRb8Wl+out1hrTahHnDWaZ5Mce
 EskcQNkJROqFbjD4k3ABN4XGTv2VDmrztIwFe0SEQ7Dz/9ypCrBGT69uI9xIqTXr
 GwVRIwAUFTpMupK0gy93z1ajV3N0CXV79out9+jQNUQybYE+czp8QOyhmuc1tZx0
 8fn9jlBQe9Vy6yrs39gEcE7nUwrayeyQ+6UvqqwsE2pWZabNAnCMSPX5+QIu+T/3
 tQ7+jYmfFeserp1sIDOHOnxfhtW9EI6U9d1h/DUCwrsuFdkL9ha4M/vh9Pwgye98
 tBdz0T4yE39AJQwwFWRkv1jcQKcGu6WqJanmvS4KRBksGwuLWxy+ewOnkz2ifS25
 ZYSyxAryZRBvQRqlOK11rXPfRcbGcY0MG9lkKX96rGcyWEizgE1DdjxXD8HoIleN
 R8heV6GX5OzlFLGX2tKK
 =fJ5x
 -----END PGP SIGNATURE-----

Merge tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc

Pull ARM SoC platform changes from Olof Johansson:
 "This branch contains mostly additions and changes to platform
  enablement and SoC-level drivers.  Since there's sometimes a
  dependency on device-tree changes, there's also a fair amount of
  those in this branch.

  Pieces worth mentioning are:

   - Mbus driver for Marvell platforms, allowing kernel configuration
     and resource allocation of on-chip peripherals.
   - Enablement of the mbus infrastructure from Marvell PCI-e drivers.
   - Preparation of MSI support for Marvell platforms.
   - Addition of new PCI-e host controller driver for Tegra platforms
   - Some churn caused by sharing of macro names between i.MX 6Q and 6DL
     platforms in the device tree sources and header files.
   - Various suspend/PM updates for Tegra, including LP1 support.
   - Versatile Express support for MCPM, part of big little support.
   - Allwinner platform support for A20 and A31 SoCs (dual and quad
     Cortex-A7)
   - OMAP2+ support for DRA7, a new Cortex-A15-based SoC.

  The code that touches other architectures are patches moving MSI
  arch-specific functions over to weak symbols and removal of
  ARCH_SUPPORTS_MSI, acked by PCI maintainers"

* tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (266 commits)
  tegra-cpuidle: provide stub when !CONFIG_CPU_IDLE
  PCI: tegra: replace devm_request_and_ioremap by devm_ioremap_resource
  ARM: tegra: Drop ARCH_SUPPORTS_MSI and sort list
  ARM: dts: vf610-twr: enable i2c0 device
  ARM: dts: i.MX51: Add one more I2C2 pinmux entry
  ARM: dts: i.MX51: Move pins configuration under "iomuxc" label
  ARM: dtsi: imx6qdl-sabresd: Add USB OTG vbus pin to pinctrl_hog
  ARM: dtsi: imx6qdl-sabresd: Add USB host 1 VBUS regulator
  ARM: dts: imx27-phytec-phycore-som: Enable AUDMUX
  ARM: dts: i.MX27: Disable AUDMUX in the template
  ARM: dts: wandboard: Add support for SDIO bcm4329
  ARM: i.MX5 clocks: Remove optional clock setup (CKIH1) from i.MX51 template
  ARM: dts: imx53-qsb: Make USBH1 functional
  ARM i.MX6Q: dts: Enable I2C1 with EEPROM and PMIC on Phytec phyFLEX-i.MX6 Ouad module
  ARM i.MX6Q: dts: Enable SPI NOR flash on Phytec phyFLEX-i.MX6 Ouad module
  ARM: dts: imx6qdl-sabresd: Add touchscreen support
  ARM: imx: add ocram clock for imx53
  ARM: dts: imx: ocram size is different between imx6q and imx6dl
  ARM: dts: imx27-phytec-phycore-som: Fix regulator settings
  ARM: dts: i.MX27: Remove clock name from CPU node
  ...
This commit is contained in:
Linus Torvalds 2013-09-06 13:30:06 -07:00
commit b4b50fd78b
288 changed files with 12546 additions and 6424 deletions

View file

@ -8,10 +8,9 @@ config IMX_WEIM
bool "Freescale EIM DRIVER"
depends on ARCH_MXC
help
Driver for i.MX6 WEIM controller.
Driver for i.MX WEIM controller.
The WEIM(Wireless External Interface Module) works like a bus.
You can attach many different devices on it, such as NOR, onenand.
But now, we only support the Parallel NOR.
config MVEBU_MBUS
bool

View file

@ -12,52 +12,83 @@
#include <linux/io.h>
#include <linux/of_device.h>
struct imx_weim {
void __iomem *base;
struct clk *clk;
struct imx_weim_devtype {
unsigned int cs_count;
unsigned int cs_regs_count;
unsigned int cs_stride;
};
static const struct imx_weim_devtype imx1_weim_devtype = {
.cs_count = 6,
.cs_regs_count = 2,
.cs_stride = 0x08,
};
static const struct imx_weim_devtype imx27_weim_devtype = {
.cs_count = 6,
.cs_regs_count = 3,
.cs_stride = 0x10,
};
static const struct imx_weim_devtype imx50_weim_devtype = {
.cs_count = 4,
.cs_regs_count = 6,
.cs_stride = 0x18,
};
static const struct imx_weim_devtype imx51_weim_devtype = {
.cs_count = 6,
.cs_regs_count = 6,
.cs_stride = 0x18,
};
static const struct of_device_id weim_id_table[] = {
{ .compatible = "fsl,imx6q-weim", },
{}
/* i.MX1/21 */
{ .compatible = "fsl,imx1-weim", .data = &imx1_weim_devtype, },
/* i.MX25/27/31/35 */
{ .compatible = "fsl,imx27-weim", .data = &imx27_weim_devtype, },
/* i.MX50/53/6Q */
{ .compatible = "fsl,imx50-weim", .data = &imx50_weim_devtype, },
{ .compatible = "fsl,imx6q-weim", .data = &imx50_weim_devtype, },
/* i.MX51 */
{ .compatible = "fsl,imx51-weim", .data = &imx51_weim_devtype, },
{ }
};
MODULE_DEVICE_TABLE(of, weim_id_table);
#define CS_TIMING_LEN 6
#define CS_REG_RANGE 0x18
/* Parse and set the timing for this device. */
static int
weim_timing_setup(struct platform_device *pdev, struct device_node *np)
static int __init weim_timing_setup(struct device_node *np, void __iomem *base,
const struct imx_weim_devtype *devtype)
{
struct imx_weim *weim = platform_get_drvdata(pdev);
u32 value[CS_TIMING_LEN];
u32 cs_idx;
int ret;
int i;
u32 cs_idx, value[devtype->cs_regs_count];
int i, ret;
/* get the CS index from this child node's "reg" property. */
ret = of_property_read_u32(np, "reg", &cs_idx);
if (ret)
return ret;
/* The weim has four chip selects. */
if (cs_idx > 3)
if (cs_idx >= devtype->cs_count)
return -EINVAL;
ret = of_property_read_u32_array(np, "fsl,weim-cs-timing",
value, CS_TIMING_LEN);
value, devtype->cs_regs_count);
if (ret)
return ret;
/* set the timing for WEIM */
for (i = 0; i < CS_TIMING_LEN; i++)
writel(value[i], weim->base + cs_idx * CS_REG_RANGE + i * 4);
for (i = 0; i < devtype->cs_regs_count; i++)
writel(value[i], base + cs_idx * devtype->cs_stride + i * 4);
return 0;
}
static int weim_parse_dt(struct platform_device *pdev)
static int __init weim_parse_dt(struct platform_device *pdev,
void __iomem *base)
{
const struct of_device_id *of_id = of_match_device(weim_id_table,
&pdev->dev);
const struct imx_weim_devtype *devtype = of_id->data;
struct device_node *child;
int ret;
@ -65,7 +96,7 @@ static int weim_parse_dt(struct platform_device *pdev)
if (!child->name)
continue;
ret = weim_timing_setup(pdev, child);
ret = weim_timing_setup(child, base, devtype);
if (ret) {
dev_err(&pdev->dev, "%s set timing failed.\n",
child->full_name);
@ -80,59 +111,47 @@ static int weim_parse_dt(struct platform_device *pdev)
return ret;
}
static int weim_probe(struct platform_device *pdev)
static int __init weim_probe(struct platform_device *pdev)
{
struct imx_weim *weim;
struct resource *res;
int ret = -EINVAL;
weim = devm_kzalloc(&pdev->dev, sizeof(*weim), GFP_KERNEL);
if (!weim) {
ret = -ENOMEM;
goto weim_err;
}
platform_set_drvdata(pdev, weim);
struct clk *clk;
void __iomem *base;
int ret;
/* get the resource */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
weim->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(weim->base)) {
ret = PTR_ERR(weim->base);
goto weim_err;
}
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
/* get the clock */
weim->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(weim->clk))
goto weim_err;
clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = clk_prepare_enable(weim->clk);
ret = clk_prepare_enable(clk);
if (ret)
goto weim_err;
return ret;
/* parse the device node */
ret = weim_parse_dt(pdev);
if (ret) {
clk_disable_unprepare(weim->clk);
goto weim_err;
}
ret = weim_parse_dt(pdev, base);
if (ret)
clk_disable_unprepare(clk);
else
dev_info(&pdev->dev, "Driver registered.\n");
dev_info(&pdev->dev, "WEIM driver registered.\n");
return 0;
weim_err:
return ret;
}
static struct platform_driver weim_driver = {
.driver = {
.name = "imx-weim",
.of_match_table = weim_id_table,
.name = "imx-weim",
.owner = THIS_MODULE,
.of_match_table = weim_id_table,
},
.probe = weim_probe,
};
module_platform_driver_probe(weim_driver, weim_probe);
module_platform_driver(weim_driver);
MODULE_AUTHOR("Freescale Semiconductor Inc.");
MODULE_DESCRIPTION("i.MX EIM Controller Driver");
MODULE_LICENSE("GPL");

View file

@ -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
@ -97,33 +93,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 +102,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 {
@ -142,6 +110,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;
};
@ -428,8 +398,7 @@ static int mvebu_devs_debug_show(struct seq_file *seq, void *v)
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,
@ -440,18 +409,9 @@ static int mvebu_devs_debug_show(struct seq_file *seq, void *v)
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",
@ -576,62 +536,12 @@ mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus)
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 = {
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,
.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 = {
.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_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 = {
@ -640,16 +550,6 @@ static const struct mvebu_mbus_soc_data kirkwood_mbus_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 = {
@ -658,18 +558,6 @@ static const struct mvebu_mbus_soc_data dove_mbus_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),
{},
};
/*
@ -682,7 +570,6 @@ static const struct mvebu_mbus_soc_data orion5x_4win_mbus_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 = {
@ -691,21 +578,6 @@ static const struct mvebu_mbus_soc_data orion5x_2win_mbus_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 = {
@ -714,7 +586,6 @@ static const struct mvebu_mbus_soc_data mv78xx0_mbus_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,
};
/*
@ -725,9 +596,9 @@ static const struct mvebu_mbus_soc_data mv78xx0_mbus_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",
@ -748,48 +619,27 @@ static const struct of_device_id of_mvebu_mbus_ids[] = {
/*
* Public API of the driver
*/
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)
{
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;
if (!mvebu_mbus_window_conflicts(s, base, size, target, attr)) {
pr_err("cannot add window '%s', conflicts with another window\n",
devname);
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, attr);
return mvebu_mbus_alloc_window(s, base, size, remap, target, attribute);
}
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)
{
return mvebu_mbus_add_window_remap_flags(devname, base, size,
MVEBU_MBUS_NO_REMAP, 0);
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)
@ -804,6 +654,20 @@ int mvebu_mbus_del_window(phys_addr_t base, size_t size)
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;
@ -830,26 +694,14 @@ static __init int mvebu_mbus_debugfs_init(void)
}
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;
@ -870,3 +722,218 @@ int __init mvebu_mbus_init(const char *soc, phys_addr_t mbuswins_phys_base,
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);
}
#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)
{
if (!mvebu_mbus_window_conflicts(mbus, base, size, target, attr)) {
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 '%04x:%04x', too many windows\n",
target, attr);
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;
}
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;
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;
}
/* 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),
sdramwins_res.start,
resource_size(&sdramwins_res));
if (ret)
return ret;
/* Setup statically declared windows in the DT */
return mbus_dt_setup(&mbus_state, np);
}
#endif