bus: Add driver for Integrator/AP logic modules

The logic modules on the Integrator/AP (Application Platform)
are logic tiles with (typically) one or a few peripheral
devices. They are most commonly used for FPGA prototyping.

Using the device tree node for logic tiles, we probe them
in order and check if the special system controller register
confirm their presence before populating the node for a tile.

This supercedes the code in arch/arm/mach-integrator/lm.[c|h]
and makes it possible to populate the tiles using the device
tree instead of boardfile-based descriptions.

Tested with all peripherals including graphics and MMC card
working fine with the IM-PD1 example tile from Arm.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
Linus Walleij 2020-02-13 13:41:23 +01:00
parent 03d679bf00
commit ccea5e8a59
4 changed files with 139 additions and 1 deletions

View file

@ -1336,6 +1336,7 @@ F: arch/arm/mach-integrator/
F: arch/arm/mach-realview/
F: arch/arm/mach-versatile/
F: arch/arm/plat-versatile/
F: drivers/bus/arm-integrator-lm.c
F: drivers/clk/versatile/
F: drivers/i2c/busses/i2c-versatile.c
F: drivers/irqchip/irq-versatile-fpga.c

View file

@ -20,6 +20,15 @@ config ARM_CCI400_PORT_CTRL
Low level power management driver for CCI400 cache coherent
interconnect for ARM platforms.
config ARM_INTEGRATOR_LM
bool "ARM Integrator Logic Module bus"
depends on HAS_IOMEM
depends on ARCH_INTEGRATOR || COMPILE_TEST
default ARCH_INTEGRATOR
help
Say y here to enable support for the ARM Logic Module bus
found on the ARM Integrator AP (Application Platform)
config BRCMSTB_GISB_ARB
bool "Broadcom STB GISB bus arbiter"
depends on ARM || ARM64 || MIPS

View file

@ -5,7 +5,7 @@
# Interconnect bus drivers for ARM platforms
obj-$(CONFIG_ARM_CCI) += arm-cci.o
obj-$(CONFIG_ARM_INTEGRATOR_LM) += arm-integrator-lm.o
obj-$(CONFIG_HISILICON_LPC) += hisi_lpc.o
obj-$(CONFIG_BRCMSTB_GISB_ARB) += brcmstb_gisb.o
obj-$(CONFIG_MOXTET) += moxtet.o

View file

@ -0,0 +1,128 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* ARM Integrator Logical Module bus driver
* Copyright (C) 2020 Linaro Ltd.
* Author: Linus Walleij <linus.walleij@linaro.org>
*
* See the device tree bindings for this block for more details on the
* hardware.
*/
#include <linux/module.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/bitops.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
/* All information about the connected logic modules are in here */
#define INTEGRATOR_SC_DEC_OFFSET 0x10
/* Base address for the expansion modules */
#define INTEGRATOR_AP_EXP_BASE 0xc0000000
#define INTEGRATOR_AP_EXP_STRIDE 0x10000000
static int integrator_lm_populate(int num, struct device *dev)
{
struct device_node *np = dev->of_node;
struct device_node *child;
u32 base;
int ret;
base = INTEGRATOR_AP_EXP_BASE + (num * INTEGRATOR_AP_EXP_STRIDE);
/* Walk over the child nodes and see what chipselects we use */
for_each_available_child_of_node(np, child) {
struct resource res;
ret = of_address_to_resource(child, 0, &res);
if (ret) {
dev_info(dev, "no valid address on child\n");
continue;
}
/* First populate the syscon then any devices */
if (res.start == base) {
dev_info(dev, "populate module @0x%08x from DT\n",
base);
ret = of_platform_default_populate(child, NULL, dev);
if (ret) {
dev_err(dev, "failed to populate module\n");
return ret;
}
}
}
return 0;
}
static const struct of_device_id integrator_ap_syscon_match[] = {
{ .compatible = "arm,integrator-ap-syscon"},
{ },
};
static int integrator_ap_lm_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *syscon;
static struct regmap *map;
u32 val;
int ret;
int i;
/* Look up the system controller */
syscon = of_find_matching_node(NULL, integrator_ap_syscon_match);
if (IS_ERR(syscon)) {
dev_err(dev,
"could not find Integrator/AP system controller\n");
return PTR_ERR(syscon);
}
map = syscon_node_to_regmap(syscon);
if (IS_ERR(map)) {
dev_err(dev,
"could not find Integrator/AP system controller\n");
return PTR_ERR(map);
}
ret = regmap_read(map, INTEGRATOR_SC_DEC_OFFSET, &val);
if (ret) {
dev_err(dev, "could not read from Integrator/AP syscon\n");
return ret;
}
/* Loop over the connected modules */
for (i = 0; i < 4; i++) {
if (!(val & BIT(4 + i)))
continue;
dev_info(dev, "detected module in slot %d\n", i);
ret = integrator_lm_populate(i, dev);
if (ret)
return ret;
}
return 0;
}
static const struct of_device_id integrator_ap_lm_match[] = {
{ .compatible = "arm,integrator-ap-lm"},
{ },
};
static struct platform_driver integrator_ap_lm_driver = {
.probe = integrator_ap_lm_probe,
.driver = {
.name = "integratorap-lm",
.of_match_table = integrator_ap_lm_match,
},
};
module_platform_driver(integrator_ap_lm_driver);
MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
MODULE_DESCRIPTION("Integrator AP Logical Module driver");
MODULE_LICENSE("GPL v2");