diff options
author | Tony Lindgren <tony@atomide.com> | 2021-10-06 06:55:44 +0200 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2021-10-06 06:55:44 +0200 |
commit | e700ac213a0f793fb4f83098413303e3dd080892 (patch) | |
tree | 52130e5a24ec9ea55b2f81899b8a45bed0f17f7c /drivers/bus | |
parent | bus: ti-sysc: Add break in switch statement in sysc_init_soc() (diff) | |
parent | soc: ti: omap-prm: Fix external abort for am335x pruss (diff) | |
download | linux-e700ac213a0f793fb4f83098413303e3dd080892.tar.xz linux-e700ac213a0f793fb4f83098413303e3dd080892.zip |
Merge branch 'pruss-fix' into fixes
Merge in a fix for pruss reset issue caused by enabling pruss for am335x.
Diffstat (limited to 'drivers/bus')
-rw-r--r-- | drivers/bus/Kconfig | 11 | ||||
-rw-r--r-- | drivers/bus/Makefile | 1 | ||||
-rw-r--r-- | drivers/bus/fsl-mc/fsl-mc-bus.c | 138 | ||||
-rw-r--r-- | drivers/bus/intel-ixp4xx-eb.c | 429 | ||||
-rw-r--r-- | drivers/bus/mhi/core/boot.c | 17 | ||||
-rw-r--r-- | drivers/bus/mhi/core/init.c | 93 | ||||
-rw-r--r-- | drivers/bus/mhi/core/internal.h | 20 | ||||
-rw-r--r-- | drivers/bus/mhi/core/main.c | 23 | ||||
-rw-r--r-- | drivers/bus/mhi/core/pm.c | 34 | ||||
-rw-r--r-- | drivers/bus/mhi/pci_generic.c | 87 | ||||
-rw-r--r-- | drivers/bus/sunxi-rsb.c | 4 | ||||
-rw-r--r-- | drivers/bus/ti-sysc.c | 17 |
12 files changed, 738 insertions, 136 deletions
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index e7f7eee6ee9a..a5b96f3aad67 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -95,6 +95,17 @@ config IMX_WEIM The WEIM(Wireless External Interface Module) works like a bus. You can attach many different devices on it, such as NOR, onenand. +config INTEL_IXP4XX_EB + bool "Intel IXP4xx expansion bus interface driver" + depends on HAS_IOMEM + depends on ARCH_IXP4XX || COMPILE_TEST + default ARCH_IXP4XX + select MFD_SYSCON + help + Driver for the Intel IXP4xx expansion bus interface. The driver is + needed to set up various chip select configuration parameters before + devices on the expansion bus can be discovered. + config MIPS_CDMM bool "MIPS Common Device Memory Map (CDMM) Driver" depends on CPU_MIPSR2 || CPU_MIPSR5 diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index 397e35392bff..1c29c5e8ffb8 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/ obj-$(CONFIG_BT1_APB) += bt1-apb.o obj-$(CONFIG_BT1_AXI) += bt1-axi.o obj-$(CONFIG_IMX_WEIM) += imx-weim.o +obj-$(CONFIG_INTEL_IXP4XX_EB) += intel-ixp4xx-eb.o obj-$(CONFIG_MIPS_CDMM) += mips_cdmm.o obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 09c8ab5e0959..8fd4a356a86e 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -63,11 +63,14 @@ struct fsl_mc_addr_translation_range { #define FSL_MC_GCR1 0x0 #define GCR1_P1_STOP BIT(31) +#define GCR1_P2_STOP BIT(30) #define FSL_MC_FAPR 0x28 #define MC_FAPR_PL BIT(18) #define MC_FAPR_BMT BIT(17) +static phys_addr_t mc_portal_base_phys_addr; + /** * fsl_mc_bus_match - device to driver matching callback * @dev: the fsl-mc device to match against @@ -220,7 +223,7 @@ static int scan_fsl_mc_bus(struct device *dev, void *data) root_mc_dev = to_fsl_mc_device(dev); root_mc_bus = to_fsl_mc_bus(root_mc_dev); mutex_lock(&root_mc_bus->scan_mutex); - dprc_scan_objects(root_mc_dev, NULL); + dprc_scan_objects(root_mc_dev, false); mutex_unlock(&root_mc_bus->scan_mutex); exit: @@ -703,14 +706,30 @@ static int fsl_mc_device_get_mmio_regions(struct fsl_mc_device *mc_dev, * If base address is in the region_desc use it otherwise * revert to old mechanism */ - if (region_desc.base_address) + if (region_desc.base_address) { regions[i].start = region_desc.base_address + region_desc.base_offset; - else + } else { error = translate_mc_addr(mc_dev, mc_region_type, region_desc.base_offset, ®ions[i].start); + /* + * Some versions of the MC firmware wrongly report + * 0 for register base address of the DPMCP associated + * with child DPRC objects thus rendering them unusable. + * This is particularly troublesome in ACPI boot + * scenarios where the legacy way of extracting this + * base address from the device tree does not apply. + * Given that DPMCPs share the same base address, + * workaround this by using the base address extracted + * from the root DPRC container. + */ + if (is_fsl_mc_bus_dprc(mc_dev) && + regions[i].start == region_desc.base_offset) + regions[i].start += mc_portal_base_phys_addr; + } + if (error < 0) { dev_err(parent_dev, "Invalid MC offset: %#x (for %s.%d\'s region %d)\n", @@ -895,6 +914,8 @@ error_cleanup_dev: } EXPORT_SYMBOL_GPL(fsl_mc_device_add); +static struct notifier_block fsl_mc_nb; + /** * fsl_mc_device_remove - Remove an fsl-mc device from being visible to * Linux @@ -914,7 +935,8 @@ void fsl_mc_device_remove(struct fsl_mc_device *mc_dev) } EXPORT_SYMBOL_GPL(fsl_mc_device_remove); -struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev) +struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev, + u16 if_id) { struct fsl_mc_device *mc_bus_dev, *endpoint; struct fsl_mc_obj_desc endpoint_desc = {{ 0 }}; @@ -925,6 +947,7 @@ struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev) mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); strcpy(endpoint1.type, mc_dev->obj_desc.type); endpoint1.id = mc_dev->obj_desc.id; + endpoint1.if_id = if_id; err = dprc_get_connection(mc_bus_dev->mc_io, 0, mc_bus_dev->mc_handle, @@ -947,10 +970,28 @@ struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev) * We know that the device has an endpoint because we verified by * interrogating the firmware. This is the case when the device was not * yet discovered by the fsl-mc bus, thus the lookup returned NULL. - * Differentiate this case by returning EPROBE_DEFER. + * Force a rescan of the devices in this container and retry the lookup. + */ + if (!endpoint) { + struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); + + if (mutex_trylock(&mc_bus->scan_mutex)) { + err = dprc_scan_objects(mc_bus_dev, true); + mutex_unlock(&mc_bus->scan_mutex); + } + + if (err < 0) + return ERR_PTR(err); + } + + endpoint = fsl_mc_device_lookup(&endpoint_desc, mc_bus_dev); + /* + * This means that the endpoint might reside in a different isolation + * context (DPRC/container). Not much to do, so return a permssion + * error. */ if (!endpoint) - return ERR_PTR(-EPROBE_DEFER); + return ERR_PTR(-EPERM); return endpoint; } @@ -1089,17 +1130,6 @@ static int fsl_mc_bus_probe(struct platform_device *pdev) } if (mc->fsl_mc_regs) { - /* - * Some bootloaders pause the MC firmware before booting the - * kernel so that MC will not cause faults as soon as the - * SMMU probes due to the fact that there's no configuration - * in place for MC. - * At this point MC should have all its SMMU setup done so make - * sure it is resumed. - */ - writel(readl(mc->fsl_mc_regs + FSL_MC_GCR1) & (~GCR1_P1_STOP), - mc->fsl_mc_regs + FSL_MC_GCR1); - if (IS_ENABLED(CONFIG_ACPI) && !dev_of_node(&pdev->dev)) { mc_stream_id = readl(mc->fsl_mc_regs + FSL_MC_FAPR); /* @@ -1113,11 +1143,25 @@ static int fsl_mc_bus_probe(struct platform_device *pdev) error = acpi_dma_configure_id(&pdev->dev, DEV_DMA_COHERENT, &mc_stream_id); + if (error == -EPROBE_DEFER) + return error; if (error) dev_warn(&pdev->dev, "failed to configure dma: %d.\n", error); } + + /* + * Some bootloaders pause the MC firmware before booting the + * kernel so that MC will not cause faults as soon as the + * SMMU probes due to the fact that there's no configuration + * in place for MC. + * At this point MC should have all its SMMU setup done so make + * sure it is resumed. + */ + writel(readl(mc->fsl_mc_regs + FSL_MC_GCR1) & + (~(GCR1_P1_STOP | GCR1_P2_STOP)), + mc->fsl_mc_regs + FSL_MC_GCR1); } /* @@ -1126,6 +1170,8 @@ static int fsl_mc_bus_probe(struct platform_device *pdev) plat_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mc_portal_phys_addr = plat_res->start; mc_portal_size = resource_size(plat_res); + mc_portal_base_phys_addr = mc_portal_phys_addr & ~0x3ffffff; + error = fsl_create_mc_io(&pdev->dev, mc_portal_phys_addr, mc_portal_size, NULL, FSL_MC_IO_ATOMIC_CONTEXT_PORTAL, &mc_io); @@ -1199,9 +1245,26 @@ static int fsl_mc_bus_remove(struct platform_device *pdev) fsl_destroy_mc_io(mc->root_mc_bus_dev->mc_io); mc->root_mc_bus_dev->mc_io = NULL; + bus_unregister_notifier(&fsl_mc_bus_type, &fsl_mc_nb); + + if (mc->fsl_mc_regs) { + /* + * Pause the MC firmware so that it doesn't crash in certain + * scenarios, such as kexec. + */ + writel(readl(mc->fsl_mc_regs + FSL_MC_GCR1) | + (GCR1_P1_STOP | GCR1_P2_STOP), + mc->fsl_mc_regs + FSL_MC_GCR1); + } + return 0; } +static void fsl_mc_bus_shutdown(struct platform_device *pdev) +{ + fsl_mc_bus_remove(pdev); +} + static const struct of_device_id fsl_mc_bus_match_table[] = { {.compatible = "fsl,qoriq-mc",}, {}, @@ -1224,6 +1287,45 @@ static struct platform_driver fsl_mc_bus_driver = { }, .probe = fsl_mc_bus_probe, .remove = fsl_mc_bus_remove, + .shutdown = fsl_mc_bus_shutdown, +}; + +static int fsl_mc_bus_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + struct resource *res; + void __iomem *fsl_mc_regs; + + if (action != BUS_NOTIFY_ADD_DEVICE) + return 0; + + if (!of_match_device(fsl_mc_bus_match_table, dev) && + !acpi_match_device(fsl_mc_bus_acpi_match_table, dev)) + return 0; + + res = platform_get_resource(to_platform_device(dev), IORESOURCE_MEM, 1); + if (!res) + return 0; + + fsl_mc_regs = ioremap(res->start, resource_size(res)); + if (!fsl_mc_regs) + return 0; + + /* + * Make sure that the MC firmware is paused before the IOMMU setup for + * it is done or otherwise the firmware will crash right after the SMMU + * gets probed and enabled. + */ + writel(readl(fsl_mc_regs + FSL_MC_GCR1) | (GCR1_P1_STOP | GCR1_P2_STOP), + fsl_mc_regs + FSL_MC_GCR1); + iounmap(fsl_mc_regs); + + return 0; +} + +static struct notifier_block fsl_mc_nb = { + .notifier_call = fsl_mc_bus_notifier, }; static int __init fsl_mc_bus_driver_init(void) @@ -1250,7 +1352,7 @@ static int __init fsl_mc_bus_driver_init(void) if (error < 0) goto error_cleanup_dprc_driver; - return 0; + return bus_register_notifier(&platform_bus_type, &fsl_mc_nb); error_cleanup_dprc_driver: dprc_driver_exit(); diff --git a/drivers/bus/intel-ixp4xx-eb.c b/drivers/bus/intel-ixp4xx-eb.c new file mode 100644 index 000000000000..a4388440aca7 --- /dev/null +++ b/drivers/bus/intel-ixp4xx-eb.c @@ -0,0 +1,429 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Intel IXP4xx Expansion Bus Controller + * Copyright (C) 2021 Linaro Ltd. + * + * Author: Linus Walleij <linus.walleij@linaro.org> + */ + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/log2.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#define IXP4XX_EXP_NUM_CS 8 + +#define IXP4XX_EXP_TIMING_CS0 0x00 +#define IXP4XX_EXP_TIMING_CS1 0x04 +#define IXP4XX_EXP_TIMING_CS2 0x08 +#define IXP4XX_EXP_TIMING_CS3 0x0c +#define IXP4XX_EXP_TIMING_CS4 0x10 +#define IXP4XX_EXP_TIMING_CS5 0x14 +#define IXP4XX_EXP_TIMING_CS6 0x18 +#define IXP4XX_EXP_TIMING_CS7 0x1c + +/* Bits inside each CS timing register */ +#define IXP4XX_EXP_TIMING_STRIDE 0x04 +#define IXP4XX_EXP_CS_EN BIT(31) +#define IXP456_EXP_PAR_EN BIT(30) /* Only on IXP45x and IXP46x */ +#define IXP4XX_EXP_T1_MASK GENMASK(28, 27) +#define IXP4XX_EXP_T1_SHIFT 28 +#define IXP4XX_EXP_T2_MASK GENMASK(27, 26) +#define IXP4XX_EXP_T2_SHIFT 26 +#define IXP4XX_EXP_T3_MASK GENMASK(25, 22) +#define IXP4XX_EXP_T3_SHIFT 22 +#define IXP4XX_EXP_T4_MASK GENMASK(21, 20) +#define IXP4XX_EXP_T4_SHIFT 20 +#define IXP4XX_EXP_T5_MASK GENMASK(19, 16) +#define IXP4XX_EXP_T5_SHIFT 16 +#define IXP4XX_EXP_CYC_TYPE_MASK GENMASK(15, 14) +#define IXP4XX_EXP_CYC_TYPE_SHIFT 14 +#define IXP4XX_EXP_SIZE_MASK GENMASK(13, 10) +#define IXP4XX_EXP_SIZE_SHIFT 10 +#define IXP4XX_EXP_CNFG_0 BIT(9) /* Always zero */ +#define IXP43X_EXP_SYNC_INTEL BIT(8) /* Only on IXP43x */ +#define IXP43X_EXP_EXP_CHIP BIT(7) /* Only on IXP43x */ +#define IXP4XX_EXP_BYTE_RD16 BIT(6) +#define IXP4XX_EXP_HRDY_POL BIT(5) /* Only on IXP42x */ +#define IXP4XX_EXP_MUX_EN BIT(4) +#define IXP4XX_EXP_SPLT_EN BIT(3) +#define IXP4XX_EXP_WORD BIT(2) /* Always zero */ +#define IXP4XX_EXP_WR_EN BIT(1) +#define IXP4XX_EXP_BYTE_EN BIT(0) +#define IXP42X_RESERVED (BIT(30)|IXP4XX_EXP_CNFG_0|BIT(8)|BIT(7)|IXP4XX_EXP_WORD) +#define IXP43X_RESERVED (BIT(30)|IXP4XX_EXP_CNFG_0|BIT(5)|IXP4XX_EXP_WORD) + +#define IXP4XX_EXP_CNFG0 0x20 +#define IXP4XX_EXP_CNFG0_MEM_MAP BIT(31) +#define IXP4XX_EXP_CNFG1 0x24 + +#define IXP4XX_EXP_BOOT_BASE 0x00000000 +#define IXP4XX_EXP_NORMAL_BASE 0x50000000 +#define IXP4XX_EXP_STRIDE 0x01000000 + +/* Fuses on the IXP43x */ +#define IXP43X_EXP_UNIT_FUSE_RESET 0x28 +#define IXP43x_EXP_FUSE_SPEED_MASK GENMASK(23, 22) + +/* Number of device tree values in "reg" */ +#define IXP4XX_OF_REG_SIZE 3 + +struct ixp4xx_eb { + struct device *dev; + struct regmap *rmap; + u32 bus_base; + bool is_42x; + bool is_43x; +}; + +struct ixp4xx_exp_tim_prop { + const char *prop; + u32 max; + u32 mask; + u16 shift; +}; + +static const struct ixp4xx_exp_tim_prop ixp4xx_exp_tim_props[] = { + { + .prop = "intel,ixp4xx-eb-t1", + .max = 3, + .mask = IXP4XX_EXP_T1_MASK, + .shift = IXP4XX_EXP_T1_SHIFT, + }, + { + .prop = "intel,ixp4xx-eb-t2", + .max = 3, + .mask = IXP4XX_EXP_T2_MASK, + .shift = IXP4XX_EXP_T2_SHIFT, + }, + { + .prop = "intel,ixp4xx-eb-t3", + .max = 15, + .mask = IXP4XX_EXP_T3_MASK, + .shift = IXP4XX_EXP_T3_SHIFT, + }, + { + .prop = "intel,ixp4xx-eb-t4", + .max = 3, + .mask = IXP4XX_EXP_T4_MASK, + .shift = IXP4XX_EXP_T4_SHIFT, + }, + { + .prop = "intel,ixp4xx-eb-t5", + .max = 15, + .mask = IXP4XX_EXP_T5_MASK, + .shift = IXP4XX_EXP_T5_SHIFT, + }, + { + .prop = "intel,ixp4xx-eb-byte-access-on-halfword", + .max = 1, + .mask = IXP4XX_EXP_BYTE_RD16, + }, + { + .prop = "intel,ixp4xx-eb-hpi-hrdy-pol-high", + .max = 1, + .mask = IXP4XX_EXP_HRDY_POL, + }, + { + .prop = "intel,ixp4xx-eb-mux-address-and-data", + .max = 1, + .mask = IXP4XX_EXP_MUX_EN, + }, + { + .prop = "intel,ixp4xx-eb-ahb-split-transfers", + .max = 1, + .mask = IXP4XX_EXP_SPLT_EN, + }, + { + .prop = "intel,ixp4xx-eb-write-enable", + .max = 1, + .mask = IXP4XX_EXP_WR_EN, + }, + { + .prop = "intel,ixp4xx-eb-byte-access", + .max = 1, + .mask = IXP4XX_EXP_BYTE_EN, + }, +}; + +static void ixp4xx_exp_setup_chipselect(struct ixp4xx_eb *eb, + struct device_node *np, + u32 cs_index, + u32 cs_size) +{ + u32 cs_cfg; + u32 val; + u32 cur_cssize; + u32 cs_order; + int ret; + int i; + + if (eb->is_42x && (cs_index > 7)) { + dev_err(eb->dev, + "invalid chipselect %u, we only support 0-7\n", + cs_index); + return; + } + if (eb->is_43x && (cs_index > 3)) { + dev_err(eb->dev, + "invalid chipselect %u, we only support 0-3\n", + cs_index); + return; + } + + /* Several chip selects can be joined into one device */ + if (cs_size > IXP4XX_EXP_STRIDE) + cur_cssize = IXP4XX_EXP_STRIDE; + else + cur_cssize = cs_size; + + + /* + * The following will read/modify/write the configuration for one + * chipselect, attempting to leave the boot defaults in place unless + * something is explicitly defined. + */ + regmap_read(eb->rmap, IXP4XX_EXP_TIMING_CS0 + + IXP4XX_EXP_TIMING_STRIDE * cs_index, &cs_cfg); + dev_info(eb->dev, "CS%d at %#08x, size %#08x, config before: %#08x\n", + cs_index, eb->bus_base + IXP4XX_EXP_STRIDE * cs_index, + cur_cssize, cs_cfg); + + /* Size set-up first align to 2^9 .. 2^24 */ + cur_cssize = roundup_pow_of_two(cur_cssize); + if (cur_cssize < 512) + cur_cssize = 512; + cs_order = ilog2(cur_cssize); + if (cs_order < 9 || cs_order > 24) { + dev_err(eb->dev, "illegal size order %d\n", cs_order); + return; + } + dev_dbg(eb->dev, "CS%d size order: %d\n", cs_index, cs_order); + cs_cfg &= ~(IXP4XX_EXP_SIZE_MASK); + cs_cfg |= ((cs_order - 9) << IXP4XX_EXP_SIZE_SHIFT); + + for (i = 0; i < ARRAY_SIZE(ixp4xx_exp_tim_props); i++) { + const struct ixp4xx_exp_tim_prop *ip = &ixp4xx_exp_tim_props[i]; + + /* All are regular u32 values */ + ret = of_property_read_u32(np, ip->prop, &val); + if (ret) + continue; + + /* Handle bools (single bits) first */ + if (ip->max == 1) { + if (val) + cs_cfg |= ip->mask; + else + cs_cfg &= ~ip->mask; + dev_info(eb->dev, "CS%d %s %s\n", cs_index, + val ? "enabled" : "disabled", + ip->prop); + continue; + } + + if (val > ip->max) { + dev_err(eb->dev, + "CS%d too high value for %s: %u, capped at %u\n", + cs_index, ip->prop, val, ip->max); + val = ip->max; + } + /* This assumes max value fills all the assigned bits (and it does) */ + cs_cfg &= ~ip->mask; + cs_cfg |= (val << ip->shift); + dev_info(eb->dev, "CS%d set %s to %u\n", cs_index, ip->prop, val); + } + + ret = of_property_read_u32(np, "intel,ixp4xx-eb-cycle-type", &val); + if (!ret) { + if (val > 3) { + dev_err(eb->dev, "illegal cycle type %d\n", val); + return; + } + dev_info(eb->dev, "CS%d set cycle type %d\n", cs_index, val); + cs_cfg &= ~IXP4XX_EXP_CYC_TYPE_MASK; + cs_cfg |= val << IXP4XX_EXP_CYC_TYPE_SHIFT; + } + + if (eb->is_42x) + cs_cfg &= ~IXP42X_RESERVED; + if (eb->is_43x) { + cs_cfg &= ~IXP43X_RESERVED; + /* + * This bit for Intel strata flash is currently unused, but let's + * report it if we find one. + */ + if (cs_cfg & IXP43X_EXP_SYNC_INTEL) + dev_info(eb->dev, "claims to be Intel strata flash\n"); + } + cs_cfg |= IXP4XX_EXP_CS_EN; + + regmap_write(eb->rmap, + IXP4XX_EXP_TIMING_CS0 + IXP4XX_EXP_TIMING_STRIDE * cs_index, + cs_cfg); + dev_info(eb->dev, "CS%d wrote %#08x into CS config\n", cs_index, cs_cfg); + + /* + * If several chip selects are joined together into one big + * device area, we call ourselves recursively for each successive + * chip select. For a 32MB flash chip this results in two calls + * for example. + */ + if (cs_size > IXP4XX_EXP_STRIDE) + ixp4xx_exp_setup_chipselect(eb, np, + cs_index + 1, + cs_size - IXP4XX_EXP_STRIDE); +} + +static void ixp4xx_exp_setup_child(struct ixp4xx_eb *eb, + struct device_node *np) +{ + u32 cs_sizes[IXP4XX_EXP_NUM_CS]; + int num_regs; + u32 csindex; + u32 cssize; + int ret; + int i; + + num_regs = of_property_count_elems_of_size(np, "reg", IXP4XX_OF_REG_SIZE); + if (num_regs <= 0) + return; + dev_dbg(eb->dev, "child %s has %d register sets\n", + of_node_full_name(np), num_regs); + + for (csindex = 0; csindex < IXP4XX_EXP_NUM_CS; csindex++) + cs_sizes[csindex] = 0; + + for (i = 0; i < num_regs; i++) { + u32 rbase, rsize; + + ret = of_property_read_u32_index(np, "reg", + i * IXP4XX_OF_REG_SIZE, &csindex); + if (ret) + break; + ret = of_property_read_u32_index(np, "reg", + i * IXP4XX_OF_REG_SIZE + 1, &rbase); + if (ret) + break; + ret = of_property_read_u32_index(np, "reg", + i * IXP4XX_OF_REG_SIZE + 2, &rsize); + if (ret) + break; + + if (csindex >= IXP4XX_EXP_NUM_CS) { + dev_err(eb->dev, "illegal CS %d\n", csindex); + continue; + } + /* + * The memory window always starts from CS base so we need to add + * the start and size to get to the size from the start of the CS + * base. For example if CS0 is at 0x50000000 and the reg is + * <0 0xe40000 0x40000> the size is e80000. + * + * Roof this if we have several regs setting the same CS. + */ + cssize = rbase + rsize; + dev_dbg(eb->dev, "CS%d size %#08x\n", csindex, cssize); + if (cs_sizes[csindex] < cssize) + cs_sizes[csindex] = cssize; + } + + for (csindex = 0; csindex < IXP4XX_EXP_NUM_CS; csindex++) { + cssize = cs_sizes[csindex]; + if (!cssize) + continue; + /* Just this one, so set it up and return */ + ixp4xx_exp_setup_chipselect(eb, np, csindex, cssize); + } +} + +static int ixp4xx_exp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct ixp4xx_eb *eb; + struct device_node *child; + bool have_children = false; + u32 val; + int ret; + + eb = devm_kzalloc(dev, sizeof(*eb), GFP_KERNEL); + if (!eb) + return -ENOMEM; + + eb->dev = dev; + eb->is_42x = of_device_is_compatible(np, "intel,ixp42x-expansion-bus-controller"); + eb->is_43x = of_device_is_compatible(np, "intel,ixp43x-expansion-bus-controller"); + + eb->rmap = syscon_node_to_regmap(np); + if (IS_ERR(eb->rmap)) + return dev_err_probe(dev, PTR_ERR(eb->rmap), "no regmap\n"); + + /* We check that the regmap work only on first read */ + ret = regmap_read(eb->rmap, IXP4XX_EXP_CNFG0, &val); + if (ret) + return dev_err_probe(dev, ret, "cannot read regmap\n"); + if (val & IXP4XX_EXP_CNFG0_MEM_MAP) + eb->bus_base = IXP4XX_EXP_BOOT_BASE; + else + eb->bus_base = IXP4XX_EXP_NORMAL_BASE; + dev_info(dev, "expansion bus at %08x\n", eb->bus_base); + + if (eb->is_43x) { + /* Check some fuses */ + regmap_read(eb->rmap, IXP43X_EXP_UNIT_FUSE_RESET, &val); + switch (FIELD_GET(IXP43x_EXP_FUSE_SPEED_MASK, val)) { + case 0: + dev_info(dev, "IXP43x at 533 MHz\n"); + break; + case 1: + dev_info(dev, "IXP43x at 400 MHz\n"); + break; + case 2: + dev_info(dev, "IXP43x at 667 MHz\n"); + break; + default: + dev_info(dev, "IXP43x unknown speed\n"); + break; + } + } + + /* Walk over the child nodes and see what chipselects we use */ + for_each_available_child_of_node(np, child) { + ixp4xx_exp_setup_child(eb, child); + /* We have at least one child */ + have_children = true; + } + + if (have_children) + return of_platform_default_populate(np, NULL, dev); + + return 0; +} + +static const struct of_device_id ixp4xx_exp_of_match[] = { + { .compatible = "intel,ixp42x-expansion-bus-controller", }, + { .compatible = "intel,ixp43x-expansion-bus-controller", }, + { .compatible = "intel,ixp45x-expansion-bus-controller", }, + { .compatible = "intel,ixp46x-expansion-bus-controller", }, + { } +}; + +static struct platform_driver ixp4xx_exp_driver = { + .probe = ixp4xx_exp_probe, + .driver = { + .name = "intel-extbus", + .of_match_table = ixp4xx_exp_of_match, + }, +}; +module_platform_driver(ixp4xx_exp_driver); +MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); +MODULE_DESCRIPTION("Intel IXP4xx external bus driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/bus/mhi/core/boot.c b/drivers/bus/mhi/core/boot.c index 8100cf51cd09..0a972620a403 100644 --- a/drivers/bus/mhi/core/boot.c +++ b/drivers/bus/mhi/core/boot.c @@ -302,8 +302,8 @@ void mhi_free_bhie_table(struct mhi_controller *mhi_cntrl, struct mhi_buf *mhi_buf = image_info->mhi_buf; for (i = 0; i < image_info->entries; i++, mhi_buf++) - mhi_free_coherent(mhi_cntrl, mhi_buf->len, mhi_buf->buf, - mhi_buf->dma_addr); + dma_free_coherent(mhi_cntrl->cntrl_dev, mhi_buf->len, + mhi_buf->buf, mhi_buf->dma_addr); kfree(image_info->mhi_buf); kfree(image_info); @@ -339,8 +339,8 @@ int mhi_alloc_bhie_table(struct mhi_controller *mhi_cntrl, vec_size = sizeof(struct bhi_vec_entry) * i; mhi_buf->len = vec_size; - mhi_buf->buf = mhi_alloc_coherent(mhi_cntrl, vec_size, - &mhi_buf->dma_addr, + mhi_buf->buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, + vec_size, &mhi_buf->dma_addr, GFP_KERNEL); if (!mhi_buf->buf) goto error_alloc_segment; @@ -354,8 +354,8 @@ int mhi_alloc_bhie_table(struct mhi_controller *mhi_cntrl, error_alloc_segment: for (--i, --mhi_buf; i >= 0; i--, mhi_buf--) - mhi_free_coherent(mhi_cntrl, mhi_buf->len, mhi_buf->buf, - mhi_buf->dma_addr); + dma_free_coherent(mhi_cntrl->cntrl_dev, mhi_buf->len, + mhi_buf->buf, mhi_buf->dma_addr); error_alloc_mhi_buf: kfree(img_info); @@ -442,7 +442,8 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) if (size > firmware->size) size = firmware->size; - buf = mhi_alloc_coherent(mhi_cntrl, size, &dma_addr, GFP_KERNEL); + buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, size, &dma_addr, + GFP_KERNEL); if (!buf) { release_firmware(firmware); goto error_fw_load; @@ -451,7 +452,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) /* Download image using BHI */ memcpy(buf, firmware->data, size); ret = mhi_fw_load_bhi(mhi_cntrl, dma_addr, size); - mhi_free_coherent(mhi_cntrl, size, buf, dma_addr); + dma_free_coherent(mhi_cntrl->cntrl_dev, size, buf, dma_addr); /* Error or in EDL mode, we're done */ if (ret) { diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c index c81b377fca8f..5aaca6d0f52b 100644 --- a/drivers/bus/mhi/core/init.c +++ b/drivers/bus/mhi/core/init.c @@ -129,7 +129,7 @@ static int mhi_alloc_aligned_ring(struct mhi_controller *mhi_cntrl, u64 len) { ring->alloc_size = len + (len - 1); - ring->pre_aligned = mhi_alloc_coherent(mhi_cntrl, ring->alloc_size, + ring->pre_aligned = dma_alloc_coherent(mhi_cntrl->cntrl_dev, ring->alloc_size, &ring->dma_handle, GFP_KERNEL); if (!ring->pre_aligned) return -ENOMEM; @@ -221,13 +221,13 @@ void mhi_deinit_dev_ctxt(struct mhi_controller *mhi_cntrl) mhi_cmd = mhi_cntrl->mhi_cmd; for (i = 0; i < NR_OF_CMD_RINGS; i++, mhi_cmd++) { ring = &mhi_cmd->ring; - mhi_free_coherent(mhi_cntrl, ring->alloc_size, + dma_free_coherent(mhi_cntrl->cntrl_dev, ring->alloc_size, ring->pre_aligned, ring->dma_handle); ring->base = NULL; ring->iommu_base = 0; } - mhi_free_coherent(mhi_cntrl, + dma_free_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->cmd_ctxt) * NR_OF_CMD_RINGS, mhi_ctxt->cmd_ctxt, mhi_ctxt->cmd_ctxt_addr); @@ -237,17 +237,17 @@ void mhi_deinit_dev_ctxt(struct mhi_controller *mhi_cntrl) continue; ring = &mhi_event->ring; - mhi_free_coherent(mhi_cntrl, ring->alloc_size, + dma_free_coherent(mhi_cntrl->cntrl_dev, ring->alloc_size, ring->pre_aligned, ring->dma_handle); ring->base = NULL; ring->iommu_base = 0; } - mhi_free_coherent(mhi_cntrl, sizeof(*mhi_ctxt->er_ctxt) * + dma_free_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->er_ctxt) * mhi_cntrl->total_ev_rings, mhi_ctxt->er_ctxt, mhi_ctxt->er_ctxt_addr); - mhi_free_coherent(mhi_cntrl, sizeof(*mhi_ctxt->chan_ctxt) * + dma_free_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->chan_ctxt) * mhi_cntrl->max_chan, mhi_ctxt->chan_ctxt, mhi_ctxt->chan_ctxt_addr); @@ -275,7 +275,7 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl) return -ENOMEM; /* Setup channel ctxt */ - mhi_ctxt->chan_ctxt = mhi_alloc_coherent(mhi_cntrl, + mhi_ctxt->chan_ctxt = dma_alloc_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->chan_ctxt) * mhi_cntrl->max_chan, &mhi_ctxt->chan_ctxt_addr, @@ -307,7 +307,7 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl) } /* Setup event context */ - mhi_ctxt->er_ctxt = mhi_alloc_coherent(mhi_cntrl, + mhi_ctxt->er_ctxt = dma_alloc_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->er_ctxt) * mhi_cntrl->total_ev_rings, &mhi_ctxt->er_ctxt_addr, @@ -354,7 +354,7 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl) /* Setup cmd context */ ret = -ENOMEM; - mhi_ctxt->cmd_ctxt = mhi_alloc_coherent(mhi_cntrl, + mhi_ctxt->cmd_ctxt = dma_alloc_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->cmd_ctxt) * NR_OF_CMD_RINGS, &mhi_ctxt->cmd_ctxt_addr, @@ -389,10 +389,10 @@ error_alloc_cmd: for (--i, --mhi_cmd; i >= 0; i--, mhi_cmd--) { struct mhi_ring *ring = &mhi_cmd->ring; - mhi_free_coherent(mhi_cntrl, ring->alloc_size, + dma_free_coherent(mhi_cntrl->cntrl_dev, ring->alloc_size, ring->pre_aligned, ring->dma_handle); } - mhi_free_coherent(mhi_cntrl, + dma_free_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->cmd_ctxt) * NR_OF_CMD_RINGS, mhi_ctxt->cmd_ctxt, mhi_ctxt->cmd_ctxt_addr); i = mhi_cntrl->total_ev_rings; @@ -405,15 +405,15 @@ error_alloc_er: if (mhi_event->offload_ev) continue; - mhi_free_coherent(mhi_cntrl, ring->alloc_size, + dma_free_coherent(mhi_cntrl->cntrl_dev, ring->alloc_size, ring->pre_aligned, ring->dma_handle); } - mhi_free_coherent(mhi_cntrl, sizeof(*mhi_ctxt->er_ctxt) * + dma_free_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->er_ctxt) * mhi_cntrl->total_ev_rings, mhi_ctxt->er_ctxt, mhi_ctxt->er_ctxt_addr); error_alloc_er_ctxt: - mhi_free_coherent(mhi_cntrl, sizeof(*mhi_ctxt->chan_ctxt) * + dma_free_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->chan_ctxt) * mhi_cntrl->max_chan, mhi_ctxt->chan_ctxt, mhi_ctxt->chan_ctxt_addr); @@ -567,7 +567,7 @@ void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl, if (!chan_ctxt->rbase) /* Already uninitialized */ return; - mhi_free_coherent(mhi_cntrl, tre_ring->alloc_size, + dma_free_coherent(mhi_cntrl->cntrl_dev, tre_ring->alloc_size, tre_ring->pre_aligned, tre_ring->dma_handle); vfree(buf_ring->base); @@ -610,7 +610,7 @@ int mhi_init_chan_ctxt(struct mhi_controller *mhi_cntrl, buf_ring->base = vzalloc(buf_ring->len); if (!buf_ring->base) { - mhi_free_coherent(mhi_cntrl, tre_ring->alloc_size, + dma_free_coherent(mhi_cntrl->cntrl_dev, tre_ring->alloc_size, tre_ring->pre_aligned, tre_ring->dma_handle); return -ENOMEM; } @@ -885,7 +885,8 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl, if (!mhi_cntrl || !mhi_cntrl->cntrl_dev || !mhi_cntrl->regs || !mhi_cntrl->runtime_get || !mhi_cntrl->runtime_put || !mhi_cntrl->status_cb || !mhi_cntrl->read_reg || - !mhi_cntrl->write_reg || !mhi_cntrl->nr_irqs || !mhi_cntrl->irq) + !mhi_cntrl->write_reg || !mhi_cntrl->nr_irqs || + !mhi_cntrl->irq || !mhi_cntrl->reg_len) return -EINVAL; ret = parse_config(mhi_cntrl, config); @@ -1063,7 +1064,7 @@ EXPORT_SYMBOL_GPL(mhi_free_controller); int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl) { struct device *dev = &mhi_cntrl->mhi_dev->dev; - u32 bhie_off; + u32 bhi_off, bhie_off; int ret; mutex_lock(&mhi_cntrl->pm_mutex); @@ -1072,29 +1073,51 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl) if (ret) goto error_dev_ctxt; - /* - * Allocate RDDM table if specified, this table is for debugging purpose - */ - if (mhi_cntrl->rddm_size) { - mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->rddm_image, - mhi_cntrl->rddm_size); + ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, BHIOFF, &bhi_off); + if (ret) { + dev_err(dev, "Error getting BHI offset\n"); + goto error_reg_offset; + } - /* - * This controller supports RDDM, so we need to manually clear - * BHIE RX registers since POR values are undefined. - */ + if (bhi_off >= mhi_cntrl->reg_len) { + dev_err(dev, "BHI offset: 0x%x is out of range: 0x%zx\n", + bhi_off, mhi_cntrl->reg_len); + ret = -EINVAL; + goto error_reg_offset; + } + mhi_cntrl->bhi = mhi_cntrl->regs + bhi_off; + + if (mhi_cntrl->fbc_download || mhi_cntrl->rddm_size) { ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, BHIEOFF, &bhie_off); if (ret) { dev_err(dev, "Error getting BHIE offset\n"); - goto bhie_error; + goto error_reg_offset; } + if (bhie_off >= mhi_cntrl->reg_len) { + dev_err(dev, + "BHIe offset: 0x%x is out of range: 0x%zx\n", + bhie_off, mhi_cntrl->reg_len); + ret = -EINVAL; + goto error_reg_offset; + } mhi_cntrl->bhie = mhi_cntrl->regs + bhie_off; + } + + if (mhi_cntrl->rddm_size) { + /* + * This controller supports RDDM, so we need to manually clear + * BHIE RX registers since POR values are undefined. + */ memset_io(mhi_cntrl->bhie + BHIE_RXVECADDR_LOW_OFFS, 0, BHIE_RXVECSTATUS_OFFS - BHIE_RXVECADDR_LOW_OFFS + 4); - + /* + * Allocate RDDM table for debugging purpose if specified + */ + mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->rddm_image, + mhi_cntrl->rddm_size); if (mhi_cntrl->rddm_image) mhi_rddm_prepare(mhi_cntrl, mhi_cntrl->rddm_image); } @@ -1103,11 +1126,8 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl) return 0; -bhie_error: - if (mhi_cntrl->rddm_image) { - mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->rddm_image); - mhi_cntrl->rddm_image = NULL; - } +error_reg_offset: + mhi_deinit_dev_ctxt(mhi_cntrl); error_dev_ctxt: mutex_unlock(&mhi_cntrl->pm_mutex); @@ -1128,6 +1148,9 @@ void mhi_unprepare_after_power_down(struct mhi_controller *mhi_cntrl) mhi_cntrl->rddm_image = NULL; } + mhi_cntrl->bhi = NULL; + mhi_cntrl->bhie = NULL; + mhi_deinit_dev_ctxt(mhi_cntrl); } EXPORT_SYMBOL_GPL(mhi_unprepare_after_power_down); diff --git a/drivers/bus/mhi/core/internal.h b/drivers/bus/mhi/core/internal.h index 5b9ea66b92dc..3a732afaf73e 100644 --- a/drivers/bus/mhi/core/internal.h +++ b/drivers/bus/mhi/core/internal.h @@ -690,26 +690,6 @@ void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl, void mhi_reset_chan(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan); -/* Memory allocation methods */ -static inline void *mhi_alloc_coherent(struct mhi_controller *mhi_cntrl, - size_t size, - dma_addr_t *dma_handle, - gfp_t gfp) -{ - void *buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, size, dma_handle, - gfp); - - return buf; -} - -static inline void mhi_free_coherent(struct mhi_controller *mhi_cntrl, - size_t size, - void *vaddr, - dma_addr_t dma_handle) -{ - dma_free_coherent(mhi_cntrl->cntrl_dev, size, vaddr, dma_handle); -} - /* Event processing methods */ void mhi_ctrl_ev_task(unsigned long data); void mhi_ev_task(unsigned long data); diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index 22acde118bc3..b15c5bc37dd4 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -193,7 +193,7 @@ int mhi_map_single_no_bb(struct mhi_controller *mhi_cntrl, int mhi_map_single_use_bb(struct mhi_controller *mhi_cntrl, struct mhi_buf_info *buf_info) { - void *buf = mhi_alloc_coherent(mhi_cntrl, buf_info->len, + void *buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, buf_info->len, &buf_info->p_addr, GFP_ATOMIC); if (!buf) @@ -220,8 +220,8 @@ void mhi_unmap_single_use_bb(struct mhi_controller *mhi_cntrl, if (buf_info->dir == DMA_FROM_DEVICE) memcpy(buf_info->v_addr, buf_info->bb_addr, buf_info->len); - mhi_free_coherent(mhi_cntrl, buf_info->len, buf_info->bb_addr, - buf_info->p_addr); + dma_free_coherent(mhi_cntrl->cntrl_dev, buf_info->len, + buf_info->bb_addr, buf_info->p_addr); } static int get_nr_avail_ring_elements(struct mhi_controller *mhi_cntrl, @@ -773,11 +773,18 @@ static void mhi_process_cmd_completion(struct mhi_controller *mhi_cntrl, cmd_pkt = mhi_to_virtual(mhi_ring, ptr); chan = MHI_TRE_GET_CMD_CHID(cmd_pkt); - mhi_chan = &mhi_cntrl->mhi_chan[chan]; - write_lock_bh(&mhi_chan->lock); - mhi_chan->ccs = MHI_TRE_GET_EV_CODE(tre); - complete(&mhi_chan->completion); - write_unlock_bh(&mhi_chan->lock); + + if (chan < mhi_cntrl->max_chan && + mhi_cntrl->mhi_chan[chan].configured) { + mhi_chan = &mhi_cntrl->mhi_chan[chan]; + write_lock_bh(&mhi_chan->lock); + mhi_chan->ccs = MHI_TRE_GET_EV_CODE(tre); + complete(&mhi_chan->completion); + write_unlock_bh(&mhi_chan->lock); + } else { + dev_err(&mhi_cntrl->mhi_dev->dev, + "Completion packet for invalid channel ID: %d\n", chan); + } mhi_del_ring_element(mhi_cntrl, mhi_ring); } diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c index bbf6cd04861e..fb99e3727155 100644 --- a/drivers/bus/mhi/core/pm.c +++ b/drivers/bus/mhi/core/pm.c @@ -1059,28 +1059,8 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl) if (ret) goto error_setup_irq; - /* Setup BHI offset & INTVEC */ + /* Setup BHI INTVEC */ write_lock_irq(&mhi_cntrl->pm_lock); - ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, BHIOFF, &val); - if (ret) { - write_unlock_irq(&mhi_cntrl->pm_lock); - goto error_bhi_offset; - } - - mhi_cntrl->bhi = mhi_cntrl->regs + val; - - /* Setup BHIE offset */ - if (mhi_cntrl->fbc_download) { - ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, BHIEOFF, &val); - if (ret) { - write_unlock_irq(&mhi_cntrl->pm_lock); - dev_err(dev, "Error reading BHIE offset\n"); - goto error_bhi_offset; - } - - mhi_cntrl->bhie = mhi_cntrl->regs + val; - } - mhi_write_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_INTVEC, 0); mhi_cntrl->pm_state = MHI_PM_POR; mhi_cntrl->ee = MHI_EE_MAX; @@ -1089,12 +1069,16 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl) /* Confirm that the device is in valid exec env */ if (!MHI_IN_PBL(current_ee) && current_ee != MHI_EE_AMSS) { - dev_err(dev, "Not a valid EE for power on\n"); + dev_err(dev, "%s is not a valid EE for power on\n", + TO_MHI_EXEC_STR(current_ee)); ret = -EIO; - goto error_bhi_offset; + goto error_async_power_up; } state = mhi_get_mhi_state(mhi_cntrl); + dev_dbg(dev, "Attempting power on with EE: %s, state: %s\n", + TO_MHI_EXEC_STR(current_ee), TO_MHI_STATE_STR(state)); + if (state == MHI_STATE_SYS_ERR) { mhi_set_mhi_state(mhi_cntrl, MHI_STATE_RESET); ret = wait_event_timeout(mhi_cntrl->state_event, @@ -1110,7 +1094,7 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl) if (!ret) { ret = -EIO; dev_info(dev, "Failed to reset MHI due to syserr state\n"); - goto error_bhi_offset; + goto error_async_power_up; } /* @@ -1132,7 +1116,7 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl) return 0; -error_bhi_offset: +error_async_power_up: mhi_deinit_free_irq(mhi_cntrl); error_setup_irq: diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c index ca3bc40427f8..59a4896a8030 100644 --- a/drivers/bus/mhi/pci_generic.c +++ b/drivers/bus/mhi/pci_generic.c @@ -32,6 +32,9 @@ * @edl: emergency download mode firmware path (if any) * @bar_num: PCI base address register to use for MHI MMIO register space * @dma_data_width: DMA transfer word size (32 or 64 bits) + * @mru_default: default MRU size for MBIM network packets + * @sideband_wake: Devices using dedicated sideband GPIO for wakeup instead + * of inband wake support (such as sdx24) */ struct mhi_pci_dev_info { const struct mhi_controller_config *config; @@ -40,6 +43,8 @@ struct mhi_pci_dev_info { const char *edl; unsigned int bar_num; unsigned int dma_data_width; + unsigned int mru_default; + bool sideband_wake; }; #define MHI_CHANNEL_CONFIG_UL(ch_num, ch_name, el_count, ev_ring) \ @@ -72,6 +77,22 @@ struct mhi_pci_dev_info { .doorbell_mode_switch = false, \ } +#define MHI_CHANNEL_CONFIG_DL_AUTOQUEUE(ch_num, ch_name, el_count, ev_ring) \ + { \ + .num = ch_num, \ + .name = ch_name, \ + .num_elements = el_count, \ + .event_ring = ev_ring, \ + .dir = DMA_FROM_DEVICE, \ + .ee_mask = BIT(MHI_EE_AMSS), \ + .pollcfg = 0, \ + .doorbell = MHI_DB_BRST_DISABLE, \ + .lpm_notify = false, \ + .offload_channel = false, \ + .doorbell_mode_switch = false, \ + .auto_queue = true, \ + } + #define MHI_EVENT_CONFIG_CTRL(ev_ring, el_count) \ { \ .num_elements = el_count, \ @@ -210,7 +231,7 @@ static const struct mhi_channel_config modem_qcom_v1_mhi_channels[] = { MHI_CHANNEL_CONFIG_UL(14, "QMI", 4, 0), MHI_CHANNEL_CONFIG_DL(15, "QMI", 4, 0), MHI_CHANNEL_CONFIG_UL(20, "IPCR", 8, 0), - MHI_CHANNEL_CONFIG_DL(21, "IPCR", 8, 0), + MHI_CHANNEL_CONFIG_DL_AUTOQUEUE(21, "IPCR", 8, 0), MHI_CHANNEL_CONFIG_UL_FP(34, "FIREHOSE", 32, 0), MHI_CHANNEL_CONFIG_DL_FP(35, "FIREHOSE", 32, 0), MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0", 128, 2), @@ -242,7 +263,8 @@ static const struct mhi_pci_dev_info mhi_qcom_sdx65_info = { .edl = "qcom/sdx65m/edl.mbn", .config = &modem_qcom_v1_mhiv_config, .bar_num = MHI_PCI_DEFAULT_BAR_NUM, - .dma_data_width = 32 + .dma_data_width = 32, + .sideband_wake = false, }; static const struct mhi_pci_dev_info mhi_qcom_sdx55_info = { @@ -251,7 +273,9 @@ static const struct mhi_pci_dev_info mhi_qcom_sdx55_info = { .edl = "qcom/sdx55m/edl.mbn", .config = &modem_qcom_v1_mhiv_config, .bar_num = MHI_PCI_DEFAULT_BAR_NUM, - .dma_data_width = 32 + .dma_data_width = 32, + .mru_default = 32768, + .sideband_wake = false, }; static const struct mhi_pci_dev_info mhi_qcom_sdx24_info = { @@ -259,7 +283,8 @@ static const struct mhi_pci_dev_info mhi_qcom_sdx24_info = { .edl = "qcom/prog_firehose_sdx24.mbn", .config = &modem_qcom_v1_mhiv_config, .bar_num = MHI_PCI_DEFAULT_BAR_NUM, - .dma_data_width = 32 + .dma_data_width = 32, + .sideband_wake = true, }; static const struct mhi_channel_config mhi_quectel_em1xx_channels[] = { @@ -301,7 +326,8 @@ static const struct mhi_pci_dev_info mhi_quectel_em1xx_info = { .edl = "qcom/prog_firehose_sdx24.mbn", .config = &modem_quectel_em1xx_config, .bar_num = MHI_PCI_DEFAULT_BAR_NUM, - .dma_data_width = 32 + .dma_data_width = 32, + .sideband_wake = true, }; static const struct mhi_channel_config mhi_foxconn_sdx55_channels[] = { @@ -339,7 +365,42 @@ static const struct mhi_pci_dev_info mhi_foxconn_sdx55_info = { .edl = "qcom/sdx55m/edl.mbn", .config = &modem_foxconn_sdx55_config, .bar_num = MHI_PCI_DEFAULT_BAR_NUM, - .dma_data_width = 32 + .dma_data_width = 32, + .sideband_wake = false, +}; + +static const struct mhi_channel_config mhi_mv31_channels[] = { + MHI_CHANNEL_CONFIG_UL(0, "LOOPBACK", 64, 0), + MHI_CHANNEL_CONFIG_DL(1, "LOOPBACK", 64, 0), + /* MBIM Control Channel */ + MHI_CHANNEL_CONFIG_UL(12, "MBIM", 64, 0), + MHI_CHANNEL_CONFIG_DL(13, "MBIM", 64, 0), + /* MBIM Data Channel */ + MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0_MBIM", 512, 2), + MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0_MBIM", 512, 3), +}; + +static struct mhi_event_config mhi_mv31_events[] = { + MHI_EVENT_CONFIG_CTRL(0, 256), + MHI_EVENT_CONFIG_DATA(1, 256), + MHI_EVENT_CONFIG_HW_DATA(2, 1024, 100), + MHI_EVENT_CONFIG_HW_DATA(3, 1024, 101), +}; + +static const struct mhi_controller_config modem_mv31_config = { + .max_channels = 128, + .timeout_ms = 20000, + .num_channels = ARRAY_SIZE(mhi_mv31_channels), + .ch_cfg = mhi_mv31_channels, + .num_events = ARRAY_SIZE(mhi_mv31_events), + .event_cfg = mhi_mv31_events, +}; + +static const struct mhi_pci_dev_info mhi_mv31_info = { + .name = "cinterion-mv31", + .config = &modem_mv31_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32, }; static const struct pci_device_id mhi_pci_id_table[] = { @@ -362,6 +423,9 @@ static const struct pci_device_id mhi_pci_id_table[] = { /* DW5930e (sdx55), Non-eSIM, It's also T99W175 */ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0b1), .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info }, + /* MV31-W (Cinterion) */ + { PCI_DEVICE(0x1269, 0x00b3), + .driver_data = (kernel_ulong_t) &mhi_mv31_info }, { } }; MODULE_DEVICE_TABLE(pci, mhi_pci_id_table); @@ -463,6 +527,7 @@ static int mhi_pci_claim(struct mhi_controller *mhi_cntrl, return err; } mhi_cntrl->regs = pcim_iomap_table(pdev)[bar_num]; + mhi_cntrl->reg_len = pci_resource_len(pdev, bar_num); err = pci_set_dma_mask(pdev, dma_mask); if (err) { @@ -640,9 +705,13 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) mhi_cntrl->status_cb = mhi_pci_status_cb; mhi_cntrl->runtime_get = mhi_pci_runtime_get; mhi_cntrl->runtime_put = mhi_pci_runtime_put; - mhi_cntrl->wake_get = mhi_pci_wake_get_nop; - mhi_cntrl->wake_put = mhi_pci_wake_put_nop; - mhi_cntrl->wake_toggle = mhi_pci_wake_toggle_nop; + mhi_cntrl->mru = info->mru_default; + + if (info->sideband_wake) { + mhi_cntrl->wake_get = mhi_pci_wake_get_nop; + mhi_cntrl->wake_put = mhi_pci_wake_put_nop; + mhi_cntrl->wake_toggle = mhi_pci_wake_toggle_nop; + } err = mhi_pci_claim(mhi_cntrl, info->bar_num, DMA_BIT_MASK(info->dma_data_width)); if (err) diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c index d46db132d085..6f225dddc74f 100644 --- a/drivers/bus/sunxi-rsb.c +++ b/drivers/bus/sunxi-rsb.c @@ -169,13 +169,11 @@ static int sunxi_rsb_device_probe(struct device *dev) return drv->probe(rdev); } -static int sunxi_rsb_device_remove(struct device *dev) +static void sunxi_rsb_device_remove(struct device *dev) { const struct sunxi_rsb_driver *drv = to_sunxi_rsb_driver(dev->driver); drv->remove(to_sunxi_rsb_device(dev)); - - return 0; } static struct bus_type sunxi_rsb_bus = { diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 10fcb75df68a..484bfe5fdcac 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -855,7 +855,7 @@ static int sysc_check_registers(struct sysc *ddata) } /** - * syc_ioremap - ioremap register space for the interconnect target module + * sysc_ioremap - ioremap register space for the interconnect target module * @ddata: device driver data * * Note that the interconnect target module registers can be anywhere @@ -1446,10 +1446,6 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_OPT_CLKS_IN_RESET), SYSC_QUIRK("sham", 0, 0x100, 0x110, 0x114, 0x40000c03, 0xffffffff, SYSC_QUIRK_LEGACY_IDLE), - SYSC_QUIRK("smartreflex", 0, -ENODEV, 0x24, -ENODEV, 0x00000000, 0xffffffff, - SYSC_QUIRK_LEGACY_IDLE), - SYSC_QUIRK("smartreflex", 0, -ENODEV, 0x38, -ENODEV, 0x00000000, 0xffffffff, - SYSC_QUIRK_LEGACY_IDLE), SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000046, 0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE), SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff, @@ -1501,6 +1497,8 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_MODULE_QUIRK_SGX), SYSC_QUIRK("lcdc", 0, 0, 0x54, -ENODEV, 0x4f201000, 0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), + SYSC_QUIRK("mcasp", 0, 0, 0x4, -ENODEV, 0x44306302, 0xffffffff, + SYSC_QUIRK_SWSUP_SIDLE), SYSC_QUIRK("rtc", 0, 0x74, 0x78, -ENODEV, 0x4eb01908, 0xffff00f0, SYSC_MODULE_QUIRK_RTC_UNLOCK), SYSC_QUIRK("tptc", 0, 0, 0x10, -ENODEV, 0x40006c00, 0xffffefff, @@ -1557,7 +1555,6 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0), SYSC_QUIRK("iss", 0, 0, 0x10, -ENODEV, 0x40000101, 0xffffffff, 0), SYSC_QUIRK("keypad", 0x4a31c000, 0, 0x10, 0x14, 0x00000020, 0xffffffff, 0), - SYSC_QUIRK("mcasp", 0, 0, 0x4, -ENODEV, 0x44306302, 0xffffffff, 0), SYSC_QUIRK("mcasp", 0, 0, 0x4, -ENODEV, 0x44307b02, 0xffffffff, 0), SYSC_QUIRK("mcbsp", 0, -ENODEV, 0x8c, -ENODEV, 0, 0, 0), SYSC_QUIRK("mcspi", 0, 0, 0x10, -ENODEV, 0x40300a0b, 0xffff00ff, 0), @@ -1585,6 +1582,8 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_QUIRK("sdma", 0, 0, 0x2c, 0x28, 0x00010900, 0xffffffff, 0), SYSC_QUIRK("slimbus", 0, 0, 0x10, -ENODEV, 0x40000902, 0xffffffff, 0), SYSC_QUIRK("slimbus", 0, 0, 0x10, -ENODEV, 0x40002903, 0xffffffff, 0), + SYSC_QUIRK("smartreflex", 0, -ENODEV, 0x24, -ENODEV, 0x00000000, 0xffffffff, 0), + SYSC_QUIRK("smartreflex", 0, -ENODEV, 0x38, -ENODEV, 0x00000000, 0xffffffff, 0), SYSC_QUIRK("spinlock", 0, 0, 0x10, -ENODEV, 0x50020000, 0xffffffff, 0), SYSC_QUIRK("rng", 0, 0x1fe0, 0x1fe4, -ENODEV, 0x00000020, 0xffffffff, 0), SYSC_QUIRK("timer", 0, 0, 0x10, 0x14, 0x00000013, 0xffffffff, 0), @@ -3116,9 +3115,8 @@ static int sysc_probe(struct platform_device *pdev) goto unprepare; pm_runtime_enable(ddata->dev); - error = pm_runtime_get_sync(ddata->dev); + error = pm_runtime_resume_and_get(ddata->dev); if (error < 0) { - pm_runtime_put_noidle(ddata->dev); pm_runtime_disable(ddata->dev); goto unprepare; } @@ -3176,9 +3174,8 @@ static int sysc_remove(struct platform_device *pdev) cancel_delayed_work_sync(&ddata->idle_work); - error = pm_runtime_get_sync(ddata->dev); + error = pm_runtime_resume_and_get(ddata->dev); if (error < 0) { - pm_runtime_put_noidle(ddata->dev); pm_runtime_disable(ddata->dev); goto unprepare; } |