diff options
Diffstat (limited to 'drivers/soc')
-rw-r--r-- | drivers/soc/Makefile | 2 | ||||
-rw-r--r-- | drivers/soc/aspeed/Kconfig | 47 | ||||
-rw-r--r-- | drivers/soc/aspeed/Makefile | 1 | ||||
-rw-r--r-- | drivers/soc/aspeed/aspeed-lpc-ctrl.c | 37 | ||||
-rw-r--r-- | drivers/soc/aspeed/aspeed-lpc-snoop.c | 2 | ||||
-rw-r--r-- | drivers/soc/aspeed/aspeed-socinfo.c | 135 |
6 files changed, 204 insertions, 20 deletions
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 36452bed86ef..8fa43a2d17e7 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -4,7 +4,7 @@ # obj-$(CONFIG_ARCH_ACTIONS) += actions/ -obj-$(CONFIG_SOC_ASPEED) += aspeed/ +obj-y += aspeed/ obj-$(CONFIG_ARCH_AT91) += atmel/ obj-y += bcm/ obj-$(CONFIG_ARCH_DOVE) += dove/ diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig index c95fa30f1a76..243ca196e6ad 100644 --- a/drivers/soc/aspeed/Kconfig +++ b/drivers/soc/aspeed/Kconfig @@ -1,32 +1,47 @@ # SPDX-License-Identifier: GPL-2.0-only -menu "Aspeed SoC drivers" -config SOC_ASPEED - def_bool y - depends on ARCH_ASPEED || COMPILE_TEST +if ARCH_ASPEED || COMPILE_TEST + +menu "ASPEED SoC drivers" config ASPEED_LPC_CTRL - depends on SOC_ASPEED && REGMAP && MFD_SYSCON - tristate "Aspeed ast2400/2500 HOST LPC to BMC bridge control" + tristate "ASPEED LPC firmware cycle control" + select REGMAP + select MFD_SYSCON + default ARCH_ASPEED help - Control Aspeed ast2400/2500 HOST LPC to BMC mappings through - ioctl()s, the driver also provides a read/write interface to a BMC ram - region where the host LPC read/write region can be buffered. + Control LPC firmware cycle mappings through ioctl()s. The driver + also provides a read/write interface to a BMC ram region where the + host LPC read/write region can be buffered. config ASPEED_LPC_SNOOP - tristate "Aspeed ast2500 HOST LPC snoop support" - depends on SOC_ASPEED && REGMAP && MFD_SYSCON + tristate "ASPEED LPC snoop support" + select REGMAP + select MFD_SYSCON + default ARCH_ASPEED help Provides a driver to control the LPC snoop interface which allows the BMC to listen on and save the data written by the host to an arbitrary LPC I/O port. config ASPEED_P2A_CTRL - depends on SOC_ASPEED && REGMAP && MFD_SYSCON - tristate "Aspeed ast2400/2500 HOST P2A VGA MMIO to BMC bridge control" + tristate "ASPEED P2A (VGA MMIO to BMC) bridge control" + select REGMAP + select MFD_SYSCON + default ARCH_ASPEED + help + Control ASPEED P2A VGA MMIO to BMC mappings through ioctl()s. The + driver also provides an interface for userspace mappings to a + pre-defined region. + +config ASPEED_SOCINFO + bool "ASPEED SoC Information driver" + default ARCH_ASPEED + select SOC_BUS + default ARCH_ASPEED help - Control Aspeed ast2400/2500 HOST P2A VGA MMIO to BMC mappings through - ioctl()s, the driver also provides an interface for userspace mappings to - a pre-defined region. + Say yes to support decoding of ASPEED BMC information. endmenu + +endif diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile index b64be47f2b1f..fcab7192e1a4 100644 --- a/drivers/soc/aspeed/Makefile +++ b/drivers/soc/aspeed/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o +obj-$(CONFIG_ASPEED_SOCINFO) += aspeed-socinfo.o diff --git a/drivers/soc/aspeed/aspeed-lpc-ctrl.c b/drivers/soc/aspeed/aspeed-lpc-ctrl.c index 01ed21e8bfee..439bcd6b8c4a 100644 --- a/drivers/soc/aspeed/aspeed-lpc-ctrl.c +++ b/drivers/soc/aspeed/aspeed-lpc-ctrl.c @@ -4,6 +4,7 @@ */ #include <linux/clk.h> +#include <linux/log2.h> #include <linux/mfd/syscon.h> #include <linux/miscdevice.h> #include <linux/mm.h> @@ -21,6 +22,9 @@ #define HICR5_ENL2H BIT(8) #define HICR5_ENFWH BIT(10) +#define HICR6 0x4 +#define SW_FWH2AHB BIT(17) + #define HICR7 0x8 #define HICR8 0xc @@ -30,8 +34,9 @@ struct aspeed_lpc_ctrl { struct clk *clk; phys_addr_t mem_base; resource_size_t mem_size; - u32 pnor_size; - u32 pnor_base; + u32 pnor_size; + u32 pnor_base; + bool fwh2ahb; }; static struct aspeed_lpc_ctrl *file_aspeed_lpc_ctrl(struct file *file) @@ -177,6 +182,16 @@ static long aspeed_lpc_ctrl_ioctl(struct file *file, unsigned int cmd, return rc; /* + * Switch to FWH2AHB mode, AST2600 only. + * + * The other bits in this register are interrupt status bits + * that are cleared by writing 1. As we don't want to clear + * them, set only the bit of interest. + */ + if (lpc_ctrl->fwh2ahb) + regmap_write(lpc_ctrl->regmap, HICR6, SW_FWH2AHB); + + /* * Enable LPC FHW cycles. This is required for the host to * access the regions specified. */ @@ -241,6 +256,18 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev) lpc_ctrl->mem_size = resource_size(&resm); lpc_ctrl->mem_base = resm.start; + + if (!is_power_of_2(lpc_ctrl->mem_size)) { + dev_err(dev, "Reserved memory size must be a power of 2, got %u\n", + (unsigned int)lpc_ctrl->mem_size); + return -EINVAL; + } + + if (!IS_ALIGNED(lpc_ctrl->mem_base, lpc_ctrl->mem_size)) { + dev_err(dev, "Reserved memory must be naturally aligned for size %u\n", + (unsigned int)lpc_ctrl->mem_size); + return -EINVAL; + } } lpc_ctrl->regmap = syscon_node_to_regmap( @@ -261,6 +288,9 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev) return rc; } + if (of_device_is_compatible(dev->of_node, "aspeed,ast2600-lpc-ctrl")) + lpc_ctrl->fwh2ahb = true; + lpc_ctrl->miscdev.minor = MISC_DYNAMIC_MINOR; lpc_ctrl->miscdev.name = DEVICE_NAME; lpc_ctrl->miscdev.fops = &aspeed_lpc_ctrl_fops; @@ -291,6 +321,7 @@ static int aspeed_lpc_ctrl_remove(struct platform_device *pdev) static const struct of_device_id aspeed_lpc_ctrl_match[] = { { .compatible = "aspeed,ast2400-lpc-ctrl" }, { .compatible = "aspeed,ast2500-lpc-ctrl" }, + { .compatible = "aspeed,ast2600-lpc-ctrl" }, { }, }; @@ -308,4 +339,4 @@ module_platform_driver(aspeed_lpc_ctrl_driver); MODULE_DEVICE_TABLE(of, aspeed_lpc_ctrl_match); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Cyril Bur <cyrilbur@gmail.com>"); -MODULE_DESCRIPTION("Control for aspeed 2400/2500 LPC HOST to BMC mappings"); +MODULE_DESCRIPTION("Control for ASPEED LPC HOST to BMC mappings"); diff --git a/drivers/soc/aspeed/aspeed-lpc-snoop.c b/drivers/soc/aspeed/aspeed-lpc-snoop.c index f3d8d53ab84d..682ba0eb4eba 100644 --- a/drivers/soc/aspeed/aspeed-lpc-snoop.c +++ b/drivers/soc/aspeed/aspeed-lpc-snoop.c @@ -325,6 +325,8 @@ static const struct of_device_id aspeed_lpc_snoop_match[] = { .data = &ast2400_model_data }, { .compatible = "aspeed,ast2500-lpc-snoop", .data = &ast2500_model_data }, + { .compatible = "aspeed,ast2600-lpc-snoop", + .data = &ast2500_model_data }, { }, }; diff --git a/drivers/soc/aspeed/aspeed-socinfo.c b/drivers/soc/aspeed/aspeed-socinfo.c new file mode 100644 index 000000000000..773930e0cb10 --- /dev/null +++ b/drivers/soc/aspeed/aspeed-socinfo.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright 2019 IBM Corp. */ + +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/sys_soc.h> + +static struct { + const char *name; + const u32 id; +} const rev_table[] = { + /* AST2400 */ + { "AST2400", 0x02000303 }, + { "AST1400", 0x02010103 }, + { "AST1250", 0x02010303 }, + /* AST2500 */ + { "AST2500", 0x04000303 }, + { "AST2510", 0x04000103 }, + { "AST2520", 0x04000203 }, + { "AST2530", 0x04000403 }, + /* AST2600 */ + { "AST2600", 0x05000303 }, + { "AST2620", 0x05010203 }, +}; + +static const char *siliconid_to_name(u32 siliconid) +{ + unsigned int id = siliconid & 0xff00ffff; + unsigned int i; + + for (i = 0 ; i < ARRAY_SIZE(rev_table) ; ++i) { + if (rev_table[i].id == id) + return rev_table[i].name; + } + + return "Unknown"; +} + +static const char *siliconid_to_rev(u32 siliconid) +{ + unsigned int rev = (siliconid >> 16) & 0xff; + + switch (rev) { + case 0: + return "A0"; + case 1: + return "A1"; + case 3: + return "A2"; + } + + return "??"; +} + +static int __init aspeed_socinfo_init(void) +{ + struct soc_device_attribute *attrs; + struct soc_device *soc_dev; + struct device_node *np; + void __iomem *reg; + bool has_chipid = false; + u32 siliconid; + u32 chipid[2]; + const char *machine = NULL; + + np = of_find_compatible_node(NULL, NULL, "aspeed,silicon-id"); + if (!of_device_is_available(np)) { + of_node_put(np); + return -ENODEV; + } + + reg = of_iomap(np, 0); + if (!reg) { + of_node_put(np); + return -ENODEV; + } + siliconid = readl(reg); + iounmap(reg); + + /* This is optional, the ast2400 does not have it */ + reg = of_iomap(np, 1); + if (reg) { + has_chipid = true; + chipid[0] = readl(reg); + chipid[1] = readl(reg + 4); + iounmap(reg); + } + of_node_put(np); + + attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); + if (!attrs) + return -ENODEV; + + /* + * Machine: Romulus BMC + * Family: AST2500 + * Revision: A1 + * SoC ID: raw silicon revision id + * Serial Number: 64-bit chipid + */ + + np = of_find_node_by_path("/"); + of_property_read_string(np, "model", &machine); + if (machine) + attrs->machine = kstrdup(machine, GFP_KERNEL); + of_node_put(np); + + attrs->family = siliconid_to_name(siliconid); + attrs->revision = siliconid_to_rev(siliconid); + attrs->soc_id = kasprintf(GFP_KERNEL, "%08x", siliconid); + + if (has_chipid) + attrs->serial_number = kasprintf(GFP_KERNEL, "%08x%08x", + chipid[1], chipid[0]); + + soc_dev = soc_device_register(attrs); + if (IS_ERR(soc_dev)) { + kfree(attrs->soc_id); + kfree(attrs->serial_number); + kfree(attrs); + return PTR_ERR(soc_dev); + } + + pr_info("ASPEED %s rev %s (%s)\n", + attrs->family, + attrs->revision, + attrs->soc_id); + + return 0; +} +early_initcall(aspeed_socinfo_init); |