From 206351c5c2d9906b0304c5b10d5162707d5d4bcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 16 Jan 2023 12:08:35 +0200 Subject: [PATCH 01/40] mfd: intel-m10-bmc: Add missing includes to header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit linux/mfd/intel-m10-bmc.h is using: - pr_err(), thus include also linux/dev_printk.h - FIELD_GET(), this include also linux/bitfield.h - GENMASK(), thus include also linux/bits.h Signed-off-by: Ilpo Järvinen Reviewed-by: Russ Weight Reviewed-by: Xu Yilun Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230116100845.6153-2-ilpo.jarvinen@linux.intel.com --- include/linux/mfd/intel-m10-bmc.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h index f0044b14136e..0d4db5d9d5af 100644 --- a/include/linux/mfd/intel-m10-bmc.h +++ b/include/linux/mfd/intel-m10-bmc.h @@ -7,6 +7,9 @@ #ifndef __MFD_INTEL_M10_BMC_H #define __MFD_INTEL_M10_BMC_H +#include +#include +#include #include #define M10BMC_LEGACY_BUILD_VER 0x300468 From 16e5d95a5c451027a2e7ef89dd146a1c6c74ca6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 16 Jan 2023 12:08:36 +0200 Subject: [PATCH 02/40] mfd: intel-m10-bmc: Create m10bmc_platform_info for type specific info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BMC type specific info is currently set by a switch/case block. The size of this info is expected to grow as more dev types and features are added which would have made the switch block bloaty. Store type specific info into struct and place them into .driver_data instead because it makes things a bit cleaner. The m10bmc_type enum can be dropped as the differentiation is now fully handled by the platform info. The info member of struct intel_m10bmc that is added here is not used yet in this change but its addition logically still belongs to this change. The CSR map change that comes after this change needs to have the info member. Reviewed-by: Russ Weight Reviewed-by: Xu Yilun Signed-off-by: Ilpo Järvinen Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230116100845.6153-3-ilpo.jarvinen@linux.intel.com --- drivers/mfd/intel-m10-bmc.c | 53 ++++++++++++++----------------- include/linux/mfd/intel-m10-bmc.h | 12 +++++++ 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/drivers/mfd/intel-m10-bmc.c b/drivers/mfd/intel-m10-bmc.c index 7e3319e5b22f..12c522c16d83 100644 --- a/drivers/mfd/intel-m10-bmc.c +++ b/drivers/mfd/intel-m10-bmc.c @@ -13,12 +13,6 @@ #include #include -enum m10bmc_type { - M10_N3000, - M10_D5005, - M10_N5010, -}; - static struct mfd_cell m10bmc_d5005_subdevs[] = { { .name = "d5005bmc-hwmon" }, { .name = "d5005bmc-sec-update" } @@ -162,15 +156,17 @@ static int check_m10bmc_version(struct intel_m10bmc *ddata) static int intel_m10_bmc_spi_probe(struct spi_device *spi) { const struct spi_device_id *id = spi_get_device_id(spi); + const struct intel_m10bmc_platform_info *info; struct device *dev = &spi->dev; - struct mfd_cell *cells; struct intel_m10bmc *ddata; - int ret, n_cell; + int ret; ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); if (!ddata) return -ENOMEM; + info = (struct intel_m10bmc_platform_info *)id->driver_data; + ddata->info = info; ddata->dev = dev; ddata->regmap = @@ -189,24 +185,8 @@ static int intel_m10_bmc_spi_probe(struct spi_device *spi) return ret; } - switch (id->driver_data) { - case M10_N3000: - cells = m10bmc_pacn3000_subdevs; - n_cell = ARRAY_SIZE(m10bmc_pacn3000_subdevs); - break; - case M10_D5005: - cells = m10bmc_d5005_subdevs; - n_cell = ARRAY_SIZE(m10bmc_d5005_subdevs); - break; - case M10_N5010: - cells = m10bmc_n5010_subdevs; - n_cell = ARRAY_SIZE(m10bmc_n5010_subdevs); - break; - default: - return -ENODEV; - } - - ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, cells, n_cell, + ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, + info->cells, info->n_cells, NULL, 0, NULL); if (ret) dev_err(dev, "Failed to register sub-devices: %d\n", ret); @@ -214,10 +194,25 @@ static int intel_m10_bmc_spi_probe(struct spi_device *spi) return ret; } +static const struct intel_m10bmc_platform_info m10bmc_spi_n3000 = { + .cells = m10bmc_pacn3000_subdevs, + .n_cells = ARRAY_SIZE(m10bmc_pacn3000_subdevs), +}; + +static const struct intel_m10bmc_platform_info m10bmc_spi_d5005 = { + .cells = m10bmc_d5005_subdevs, + .n_cells = ARRAY_SIZE(m10bmc_d5005_subdevs), +}; + +static const struct intel_m10bmc_platform_info m10bmc_spi_n5010 = { + .cells = m10bmc_n5010_subdevs, + .n_cells = ARRAY_SIZE(m10bmc_n5010_subdevs), +}; + static const struct spi_device_id m10bmc_spi_id[] = { - { "m10-n3000", M10_N3000 }, - { "m10-d5005", M10_D5005 }, - { "m10-n5010", M10_N5010 }, + { "m10-n3000", (kernel_ulong_t)&m10bmc_spi_n3000 }, + { "m10-d5005", (kernel_ulong_t)&m10bmc_spi_d5005 }, + { "m10-n5010", (kernel_ulong_t)&m10bmc_spi_n5010 }, { } }; MODULE_DEVICE_TABLE(spi, m10bmc_spi_id); diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h index 0d4db5d9d5af..f418cad88e64 100644 --- a/include/linux/mfd/intel-m10-bmc.h +++ b/include/linux/mfd/intel-m10-bmc.h @@ -121,14 +121,26 @@ /* Address of 4KB inverted bit vector containing staging area FLASH count */ #define STAGING_FLASH_COUNT 0x17ffb000 +/** + * struct intel_m10bmc_platform_info - Intel MAX 10 BMC platform specific information + * @cells: MFD cells + * @n_cells: MFD cells ARRAY_SIZE() + */ +struct intel_m10bmc_platform_info { + struct mfd_cell *cells; + int n_cells; +}; + /** * struct intel_m10bmc - Intel MAX 10 BMC parent driver data structure * @dev: this device * @regmap: the regmap used to access registers by m10bmc itself + * @info: the platform information for MAX10 BMC */ struct intel_m10bmc { struct device *dev; struct regmap *regmap; + const struct intel_m10bmc_platform_info *info; }; /* From 85ba469090ed77bfbc14c418ad79646681e6606d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 16 Jan 2023 12:08:37 +0200 Subject: [PATCH 03/40] mfd: intel-m10-bmc: Rename the local variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Local variables directly interact with dev_get_drvdata/dev_set_drvdata should be named ddata. Reviewed-by: Russ Weight Reviewed-by: Xu Yilun Signed-off-by: Ilpo Järvinen Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230116100845.6153-4-ilpo.jarvinen@linux.intel.com --- drivers/mfd/intel-m10-bmc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mfd/intel-m10-bmc.c b/drivers/mfd/intel-m10-bmc.c index 12c522c16d83..2c26203c4799 100644 --- a/drivers/mfd/intel-m10-bmc.c +++ b/drivers/mfd/intel-m10-bmc.c @@ -81,15 +81,15 @@ static DEVICE_ATTR_RO(bmcfw_version); static ssize_t mac_address_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct intel_m10bmc *max10 = dev_get_drvdata(dev); + struct intel_m10bmc *ddata = dev_get_drvdata(dev); unsigned int macaddr_low, macaddr_high; int ret; - ret = m10bmc_sys_read(max10, M10BMC_MAC_LOW, &macaddr_low); + ret = m10bmc_sys_read(ddata, M10BMC_MAC_LOW, &macaddr_low); if (ret) return ret; - ret = m10bmc_sys_read(max10, M10BMC_MAC_HIGH, &macaddr_high); + ret = m10bmc_sys_read(ddata, M10BMC_MAC_HIGH, &macaddr_high); if (ret) return ret; @@ -106,11 +106,11 @@ static DEVICE_ATTR_RO(mac_address); static ssize_t mac_count_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct intel_m10bmc *max10 = dev_get_drvdata(dev); + struct intel_m10bmc *ddata = dev_get_drvdata(dev); unsigned int macaddr_high; int ret; - ret = m10bmc_sys_read(max10, M10BMC_MAC_HIGH, &macaddr_high); + ret = m10bmc_sys_read(ddata, M10BMC_MAC_HIGH, &macaddr_high); if (ret) return ret; From 603aed8ffd4c9cb633c05a514cfb5e8ca6b0751d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 16 Jan 2023 12:08:38 +0200 Subject: [PATCH 04/40] mfd: intel-m10-bmc: Split into core and spi specific parts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split the common code from intel-m10-bmc driver into intel-m10-bmc-core and move the SPI bus parts into an interface specific file. intel-m10-bmc-core becomes the core MFD functions which can support multiple bus interface like SPI bus. Co-developed-by: Tianfei zhang Signed-off-by: Tianfei zhang Reviewed-by: Russ Weight Acked-by: Guenter Roeck # hwmon Reviewed-by: Xu Yilun Signed-off-by: Ilpo Järvinen Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230116100845.6153-5-ilpo.jarvinen@linux.intel.com --- MAINTAINERS | 2 +- drivers/fpga/Kconfig | 2 +- drivers/hwmon/Kconfig | 2 +- drivers/mfd/Kconfig | 28 ++-- drivers/mfd/Makefile | 4 +- drivers/mfd/intel-m10-bmc-core.c | 122 +++++++++++++++++ .../{intel-m10-bmc.c => intel-m10-bmc-spi.c} | 128 +++--------------- include/linux/mfd/intel-m10-bmc.h | 6 + 8 files changed, 171 insertions(+), 123 deletions(-) create mode 100644 drivers/mfd/intel-m10-bmc-core.c rename drivers/mfd/{intel-m10-bmc.c => intel-m10-bmc-spi.c} (59%) diff --git a/MAINTAINERS b/MAINTAINERS index f61eb221415b..261c1dc793bc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10576,7 +10576,7 @@ S: Maintained F: Documentation/ABI/testing/sysfs-driver-intel-m10-bmc F: Documentation/hwmon/intel-m10-bmc-hwmon.rst F: drivers/hwmon/intel-m10-bmc-hwmon.c -F: drivers/mfd/intel-m10-bmc.c +F: drivers/mfd/intel-m10-bmc* F: include/linux/mfd/intel-m10-bmc.h INTEL MENLOW THERMAL DRIVER diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 6ce143dafd04..0a00763b9f28 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -246,7 +246,7 @@ config FPGA_MGR_VERSAL_FPGA config FPGA_M10_BMC_SEC_UPDATE tristate "Intel MAX10 BMC Secure Update driver" - depends on MFD_INTEL_M10_BMC + depends on MFD_INTEL_M10_BMC_CORE select FW_LOADER select FW_UPLOAD help diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 3176c33af6c6..42c28e887df3 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -2341,7 +2341,7 @@ config SENSORS_XGENE config SENSORS_INTEL_M10_BMC_HWMON tristate "Intel MAX10 BMC Hardware Monitoring" - depends on MFD_INTEL_M10_BMC + depends on MFD_INTEL_M10_BMC_CORE help This driver provides support for the hardware monitoring functionality on Intel MAX10 BMC chip. diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 30db49f31866..b6ab85831cde 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -2224,18 +2224,24 @@ config SGI_MFD_IOC3 If you have an SGI Origin, Octane, or a PCI IOC3 card, then say Y. Otherwise say N. -config MFD_INTEL_M10_BMC - tristate "Intel MAX 10 Board Management Controller" - depends on SPI_MASTER - select REGMAP_SPI_AVMM - select MFD_CORE - help - Support for the Intel MAX 10 board management controller using the - SPI interface. +config MFD_INTEL_M10_BMC_CORE + tristate + select MFD_CORE + select REGMAP + default n - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the functionality - of the device. +config MFD_INTEL_M10_BMC_SPI + tristate "Intel MAX 10 Board Management Controller with SPI" + depends on SPI_MASTER + select MFD_INTEL_M10_BMC_CORE + select REGMAP_SPI_AVMM + help + Support for the Intel MAX 10 board management controller using the + SPI interface. + + This driver provides common support for accessing the device, + additional drivers must be enabled in order to use the functionality + of the device. config MFD_RSMU_I2C tristate "Renesas Synchronization Management Unit with I2C" diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 457471478a93..b360b29150b5 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -269,7 +269,9 @@ obj-$(CONFIG_MFD_QCOM_PM8008) += qcom-pm8008.o obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o obj-$(CONFIG_MFD_SIMPLE_MFD_I2C) += simple-mfd-i2c.o obj-$(CONFIG_MFD_SMPRO) += smpro-core.o -obj-$(CONFIG_MFD_INTEL_M10_BMC) += intel-m10-bmc.o + +obj-$(CONFIG_MFD_INTEL_M10_BMC_CORE) += intel-m10-bmc-core.o +obj-$(CONFIG_MFD_INTEL_M10_BMC_SPI) += intel-m10-bmc-spi.o obj-$(CONFIG_MFD_ATC260X) += atc260x-core.o obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x-i2c.o diff --git a/drivers/mfd/intel-m10-bmc-core.c b/drivers/mfd/intel-m10-bmc-core.c new file mode 100644 index 000000000000..dd26e3a6c3ab --- /dev/null +++ b/drivers/mfd/intel-m10-bmc-core.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel MAX 10 Board Management Controller chip - common code + * + * Copyright (C) 2018-2020 Intel Corporation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +static ssize_t bmc_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct intel_m10bmc *ddata = dev_get_drvdata(dev); + unsigned int val; + int ret; + + ret = m10bmc_sys_read(ddata, M10BMC_BUILD_VER, &val); + if (ret) + return ret; + + return sprintf(buf, "0x%x\n", val); +} +static DEVICE_ATTR_RO(bmc_version); + +static ssize_t bmcfw_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct intel_m10bmc *ddata = dev_get_drvdata(dev); + unsigned int val; + int ret; + + ret = m10bmc_sys_read(ddata, NIOS2_FW_VERSION, &val); + if (ret) + return ret; + + return sprintf(buf, "0x%x\n", val); +} +static DEVICE_ATTR_RO(bmcfw_version); + +static ssize_t mac_address_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct intel_m10bmc *ddata = dev_get_drvdata(dev); + unsigned int macaddr_low, macaddr_high; + int ret; + + ret = m10bmc_sys_read(ddata, M10BMC_MAC_LOW, &macaddr_low); + if (ret) + return ret; + + ret = m10bmc_sys_read(ddata, M10BMC_MAC_HIGH, &macaddr_high); + if (ret) + return ret; + + return sysfs_emit(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", + (u8)FIELD_GET(M10BMC_MAC_BYTE1, macaddr_low), + (u8)FIELD_GET(M10BMC_MAC_BYTE2, macaddr_low), + (u8)FIELD_GET(M10BMC_MAC_BYTE3, macaddr_low), + (u8)FIELD_GET(M10BMC_MAC_BYTE4, macaddr_low), + (u8)FIELD_GET(M10BMC_MAC_BYTE5, macaddr_high), + (u8)FIELD_GET(M10BMC_MAC_BYTE6, macaddr_high)); +} +static DEVICE_ATTR_RO(mac_address); + +static ssize_t mac_count_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct intel_m10bmc *ddata = dev_get_drvdata(dev); + unsigned int macaddr_high; + int ret; + + ret = m10bmc_sys_read(ddata, M10BMC_MAC_HIGH, &macaddr_high); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", (u8)FIELD_GET(M10BMC_MAC_COUNT, macaddr_high)); +} +static DEVICE_ATTR_RO(mac_count); + +static struct attribute *m10bmc_attrs[] = { + &dev_attr_bmc_version.attr, + &dev_attr_bmcfw_version.attr, + &dev_attr_mac_address.attr, + &dev_attr_mac_count.attr, + NULL, +}; + +static const struct attribute_group m10bmc_group = { + .attrs = m10bmc_attrs, +}; + +const struct attribute_group *m10bmc_dev_groups[] = { + &m10bmc_group, + NULL, +}; +EXPORT_SYMBOL_GPL(m10bmc_dev_groups); + +int m10bmc_dev_init(struct intel_m10bmc *m10bmc, const struct intel_m10bmc_platform_info *info) +{ + int ret; + + m10bmc->info = info; + dev_set_drvdata(m10bmc->dev, m10bmc); + + ret = devm_mfd_add_devices(m10bmc->dev, PLATFORM_DEVID_AUTO, + info->cells, info->n_cells, + NULL, 0, NULL); + if (ret) + dev_err(m10bmc->dev, "Failed to register sub-devices: %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(m10bmc_dev_init); + +MODULE_DESCRIPTION("Intel MAX 10 BMC core driver"); +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/intel-m10-bmc.c b/drivers/mfd/intel-m10-bmc-spi.c similarity index 59% rename from drivers/mfd/intel-m10-bmc.c rename to drivers/mfd/intel-m10-bmc-spi.c index 2c26203c4799..be1d4ddedabb 100644 --- a/drivers/mfd/intel-m10-bmc.c +++ b/drivers/mfd/intel-m10-bmc-spi.c @@ -5,29 +5,14 @@ * Copyright (C) 2018-2020 Intel Corporation. All rights reserved. */ #include +#include #include #include #include #include -#include #include #include -static struct mfd_cell m10bmc_d5005_subdevs[] = { - { .name = "d5005bmc-hwmon" }, - { .name = "d5005bmc-sec-update" } -}; - -static struct mfd_cell m10bmc_pacn3000_subdevs[] = { - { .name = "n3000bmc-hwmon" }, - { .name = "n3000bmc-retimer" }, - { .name = "n3000bmc-sec-update" }, -}; - -static struct mfd_cell m10bmc_n5010_subdevs[] = { - { .name = "n5010bmc-hwmon" }, -}; - static const struct regmap_range m10bmc_regmap_range[] = { regmap_reg_range(M10BMC_LEGACY_BUILD_VER, M10BMC_LEGACY_BUILD_VER), regmap_reg_range(M10BMC_SYS_BASE, M10BMC_SYS_END), @@ -48,86 +33,6 @@ static struct regmap_config intel_m10bmc_regmap_config = { .max_register = M10BMC_MEM_END, }; -static ssize_t bmc_version_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct intel_m10bmc *ddata = dev_get_drvdata(dev); - unsigned int val; - int ret; - - ret = m10bmc_sys_read(ddata, M10BMC_BUILD_VER, &val); - if (ret) - return ret; - - return sprintf(buf, "0x%x\n", val); -} -static DEVICE_ATTR_RO(bmc_version); - -static ssize_t bmcfw_version_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct intel_m10bmc *ddata = dev_get_drvdata(dev); - unsigned int val; - int ret; - - ret = m10bmc_sys_read(ddata, NIOS2_FW_VERSION, &val); - if (ret) - return ret; - - return sprintf(buf, "0x%x\n", val); -} -static DEVICE_ATTR_RO(bmcfw_version); - -static ssize_t mac_address_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct intel_m10bmc *ddata = dev_get_drvdata(dev); - unsigned int macaddr_low, macaddr_high; - int ret; - - ret = m10bmc_sys_read(ddata, M10BMC_MAC_LOW, &macaddr_low); - if (ret) - return ret; - - ret = m10bmc_sys_read(ddata, M10BMC_MAC_HIGH, &macaddr_high); - if (ret) - return ret; - - return sysfs_emit(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", - (u8)FIELD_GET(M10BMC_MAC_BYTE1, macaddr_low), - (u8)FIELD_GET(M10BMC_MAC_BYTE2, macaddr_low), - (u8)FIELD_GET(M10BMC_MAC_BYTE3, macaddr_low), - (u8)FIELD_GET(M10BMC_MAC_BYTE4, macaddr_low), - (u8)FIELD_GET(M10BMC_MAC_BYTE5, macaddr_high), - (u8)FIELD_GET(M10BMC_MAC_BYTE6, macaddr_high)); -} -static DEVICE_ATTR_RO(mac_address); - -static ssize_t mac_count_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct intel_m10bmc *ddata = dev_get_drvdata(dev); - unsigned int macaddr_high; - int ret; - - ret = m10bmc_sys_read(ddata, M10BMC_MAC_HIGH, &macaddr_high); - if (ret) - return ret; - - return sysfs_emit(buf, "%u\n", - (u8)FIELD_GET(M10BMC_MAC_COUNT, macaddr_high)); -} -static DEVICE_ATTR_RO(mac_count); - -static struct attribute *m10bmc_attrs[] = { - &dev_attr_bmc_version.attr, - &dev_attr_bmcfw_version.attr, - &dev_attr_mac_address.attr, - &dev_attr_mac_count.attr, - NULL, -}; -ATTRIBUTE_GROUPS(m10bmc); - static int check_m10bmc_version(struct intel_m10bmc *ddata) { unsigned int v; @@ -166,11 +71,9 @@ static int intel_m10_bmc_spi_probe(struct spi_device *spi) return -ENOMEM; info = (struct intel_m10bmc_platform_info *)id->driver_data; - ddata->info = info; ddata->dev = dev; - ddata->regmap = - devm_regmap_init_spi_avmm(spi, &intel_m10bmc_regmap_config); + ddata->regmap = devm_regmap_init_spi_avmm(spi, &intel_m10bmc_regmap_config); if (IS_ERR(ddata->regmap)) { ret = PTR_ERR(ddata->regmap); dev_err(dev, "Failed to allocate regmap: %d\n", ret); @@ -185,15 +88,24 @@ static int intel_m10_bmc_spi_probe(struct spi_device *spi) return ret; } - ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, - info->cells, info->n_cells, - NULL, 0, NULL); - if (ret) - dev_err(dev, "Failed to register sub-devices: %d\n", ret); - - return ret; + return m10bmc_dev_init(ddata, info); } +static struct mfd_cell m10bmc_d5005_subdevs[] = { + { .name = "d5005bmc-hwmon" }, + { .name = "d5005bmc-sec-update" }, +}; + +static struct mfd_cell m10bmc_pacn3000_subdevs[] = { + { .name = "n3000bmc-hwmon" }, + { .name = "n3000bmc-retimer" }, + { .name = "n3000bmc-sec-update" }, +}; + +static struct mfd_cell m10bmc_n5010_subdevs[] = { + { .name = "n5010bmc-hwmon" }, +}; + static const struct intel_m10bmc_platform_info m10bmc_spi_n3000 = { .cells = m10bmc_pacn3000_subdevs, .n_cells = ARRAY_SIZE(m10bmc_pacn3000_subdevs), @@ -220,14 +132,14 @@ MODULE_DEVICE_TABLE(spi, m10bmc_spi_id); static struct spi_driver intel_m10bmc_spi_driver = { .driver = { .name = "intel-m10-bmc", - .dev_groups = m10bmc_groups, + .dev_groups = m10bmc_dev_groups, }, .probe = intel_m10_bmc_spi_probe, .id_table = m10bmc_spi_id, }; module_spi_driver(intel_m10bmc_spi_driver); -MODULE_DESCRIPTION("Intel MAX 10 BMC Device Driver"); +MODULE_DESCRIPTION("Intel MAX 10 BMC SPI bus interface"); MODULE_AUTHOR("Intel Corporation"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("spi:intel-m10-bmc"); diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h index f418cad88e64..a80deb61b69a 100644 --- a/include/linux/mfd/intel-m10-bmc.h +++ b/include/linux/mfd/intel-m10-bmc.h @@ -174,4 +174,10 @@ m10bmc_raw_read(struct intel_m10bmc *m10bmc, unsigned int addr, #define m10bmc_sys_read(m10bmc, offset, val) \ m10bmc_raw_read(m10bmc, M10BMC_SYS_BASE + (offset), val) +/* + * MAX10 BMC Core support + */ +int m10bmc_dev_init(struct intel_m10bmc *m10bmc, const struct intel_m10bmc_platform_info *info); +extern const struct attribute_group *m10bmc_dev_groups[]; + #endif /* __MFD_INTEL_M10_BMC_H */ From 6052a005caf9cd484fe6368a31c736ac17ebaf66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 16 Jan 2023 12:08:39 +0200 Subject: [PATCH 05/40] mfd: intel-m10-bmc: Support multiple CSR register layouts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are different addresses for the MAX10 CSR registers. Introducing a new data structure m10bmc_csr_map for the register definition of MAX10 CSR. Provide the csr_map for SPI. Co-developed-by: Tianfei zhang Signed-off-by: Tianfei zhang Reviewed-by: Russ Weight Reviewed-by: Xu Yilun Signed-off-by: Ilpo Järvinen Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230116100845.6153-6-ilpo.jarvinen@linux.intel.com --- drivers/fpga/intel-m10-bmc-sec-update.c | 73 +++++++++++++++++-------- drivers/mfd/intel-m10-bmc-core.c | 10 ++-- drivers/mfd/intel-m10-bmc-spi.c | 23 ++++++++ include/linux/mfd/intel-m10-bmc.h | 38 +++++++++++-- 4 files changed, 111 insertions(+), 33 deletions(-) diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c index 79d48852825e..dbe8aff95da3 100644 --- a/drivers/fpga/intel-m10-bmc-sec-update.c +++ b/drivers/fpga/intel-m10-bmc-sec-update.c @@ -73,16 +73,24 @@ show_root_entry_hash(struct device *dev, u32 exp_magic, return cnt; } -#define DEVICE_ATTR_SEC_REH_RO(_name, _magic, _prog_addr, _reh_addr) \ +#define DEVICE_ATTR_SEC_REH_RO(_name) \ static ssize_t _name##_root_entry_hash_show(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ -{ return show_root_entry_hash(dev, _magic, _prog_addr, _reh_addr, buf); } \ +{ \ + struct m10bmc_sec *sec = dev_get_drvdata(dev); \ + const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; \ + \ + return show_root_entry_hash(dev, csr_map->_name##_magic, \ + csr_map->_name##_prog_addr, \ + csr_map->_name##_reh_addr, \ + buf); \ +} \ static DEVICE_ATTR_RO(_name##_root_entry_hash) -DEVICE_ATTR_SEC_REH_RO(bmc, BMC_PROG_MAGIC, BMC_PROG_ADDR, BMC_REH_ADDR); -DEVICE_ATTR_SEC_REH_RO(sr, SR_PROG_MAGIC, SR_PROG_ADDR, SR_REH_ADDR); -DEVICE_ATTR_SEC_REH_RO(pr, PR_PROG_MAGIC, PR_PROG_ADDR, PR_REH_ADDR); +DEVICE_ATTR_SEC_REH_RO(bmc); +DEVICE_ATTR_SEC_REH_RO(sr); +DEVICE_ATTR_SEC_REH_RO(pr); #define CSK_BIT_LEN 128U #define CSK_32ARRAY_SIZE DIV_ROUND_UP(CSK_BIT_LEN, 32) @@ -122,18 +130,25 @@ show_canceled_csk(struct device *dev, u32 addr, char *buf) return bitmap_print_to_pagebuf(1, buf, csk_map, CSK_BIT_LEN); } -#define DEVICE_ATTR_SEC_CSK_RO(_name, _addr) \ +#define DEVICE_ATTR_SEC_CSK_RO(_name) \ static ssize_t _name##_canceled_csks_show(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ -{ return show_canceled_csk(dev, _addr, buf); } \ +{ \ + struct m10bmc_sec *sec = dev_get_drvdata(dev); \ + const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; \ + \ + return show_canceled_csk(dev, \ + csr_map->_name##_prog_addr + CSK_VEC_OFFSET, \ + buf); \ +} \ static DEVICE_ATTR_RO(_name##_canceled_csks) #define CSK_VEC_OFFSET 0x34 -DEVICE_ATTR_SEC_CSK_RO(bmc, BMC_PROG_ADDR + CSK_VEC_OFFSET); -DEVICE_ATTR_SEC_CSK_RO(sr, SR_PROG_ADDR + CSK_VEC_OFFSET); -DEVICE_ATTR_SEC_CSK_RO(pr, PR_PROG_ADDR + CSK_VEC_OFFSET); +DEVICE_ATTR_SEC_CSK_RO(bmc); +DEVICE_ATTR_SEC_CSK_RO(sr); +DEVICE_ATTR_SEC_CSK_RO(pr); #define FLASH_COUNT_SIZE 4096 /* count stored as inverted bit vector */ @@ -141,6 +156,7 @@ static ssize_t flash_count_show(struct device *dev, struct device_attribute *attr, char *buf) { struct m10bmc_sec *sec = dev_get_drvdata(dev); + const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; unsigned int stride, num_bits; u8 *flash_buf; int cnt, ret; @@ -160,12 +176,12 @@ static ssize_t flash_count_show(struct device *dev, if (!flash_buf) return -ENOMEM; - ret = regmap_bulk_read(sec->m10bmc->regmap, STAGING_FLASH_COUNT, + ret = regmap_bulk_read(sec->m10bmc->regmap, csr_map->rsu_update_counter, flash_buf, FLASH_COUNT_SIZE / stride); if (ret) { dev_err(sec->dev, "failed to read flash count: %x cnt %x: %d\n", - STAGING_FLASH_COUNT, FLASH_COUNT_SIZE / stride, ret); + csr_map->rsu_update_counter, FLASH_COUNT_SIZE / stride, ret); goto exit_free; } cnt = num_bits - bitmap_weight((unsigned long *)flash_buf, num_bits); @@ -200,20 +216,22 @@ static const struct attribute_group *m10bmc_sec_attr_groups[] = { static void log_error_regs(struct m10bmc_sec *sec, u32 doorbell) { + const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; u32 auth_result; dev_err(sec->dev, "RSU error status: 0x%08x\n", doorbell); - if (!m10bmc_sys_read(sec->m10bmc, M10BMC_AUTH_RESULT, &auth_result)) + if (!m10bmc_sys_read(sec->m10bmc, csr_map->auth_result, &auth_result)) dev_err(sec->dev, "RSU auth result: 0x%08x\n", auth_result); } static enum fw_upload_err rsu_check_idle(struct m10bmc_sec *sec) { + const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; u32 doorbell; int ret; - ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell); + ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, &doorbell); if (ret) return FW_UPLOAD_ERR_RW_ERROR; @@ -246,11 +264,12 @@ static inline bool rsu_start_done(u32 doorbell) static enum fw_upload_err rsu_update_init(struct m10bmc_sec *sec) { + const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; u32 doorbell, status; int ret; ret = regmap_update_bits(sec->m10bmc->regmap, - M10BMC_SYS_BASE + M10BMC_DOORBELL, + csr_map->base + csr_map->doorbell, DRBL_RSU_REQUEST | DRBL_HOST_STATUS, DRBL_RSU_REQUEST | FIELD_PREP(DRBL_HOST_STATUS, @@ -259,7 +278,7 @@ static enum fw_upload_err rsu_update_init(struct m10bmc_sec *sec) return FW_UPLOAD_ERR_RW_ERROR; ret = regmap_read_poll_timeout(sec->m10bmc->regmap, - M10BMC_SYS_BASE + M10BMC_DOORBELL, + csr_map->base + csr_map->doorbell, doorbell, rsu_start_done(doorbell), NIOS_HANDSHAKE_INTERVAL_US, @@ -286,11 +305,12 @@ static enum fw_upload_err rsu_update_init(struct m10bmc_sec *sec) static enum fw_upload_err rsu_prog_ready(struct m10bmc_sec *sec) { + const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; unsigned long poll_timeout; u32 doorbell, progress; int ret; - ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell); + ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, &doorbell); if (ret) return FW_UPLOAD_ERR_RW_ERROR; @@ -300,7 +320,7 @@ static enum fw_upload_err rsu_prog_ready(struct m10bmc_sec *sec) if (time_after(jiffies, poll_timeout)) break; - ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell); + ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, &doorbell); if (ret) return FW_UPLOAD_ERR_RW_ERROR; } @@ -319,11 +339,12 @@ static enum fw_upload_err rsu_prog_ready(struct m10bmc_sec *sec) static enum fw_upload_err rsu_send_data(struct m10bmc_sec *sec) { + const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; u32 doorbell; int ret; ret = regmap_update_bits(sec->m10bmc->regmap, - M10BMC_SYS_BASE + M10BMC_DOORBELL, + csr_map->base + csr_map->doorbell, DRBL_HOST_STATUS, FIELD_PREP(DRBL_HOST_STATUS, HOST_STATUS_WRITE_DONE)); @@ -331,7 +352,7 @@ static enum fw_upload_err rsu_send_data(struct m10bmc_sec *sec) return FW_UPLOAD_ERR_RW_ERROR; ret = regmap_read_poll_timeout(sec->m10bmc->regmap, - M10BMC_SYS_BASE + M10BMC_DOORBELL, + csr_map->base + csr_map->doorbell, doorbell, rsu_prog(doorbell) != RSU_PROG_READY, NIOS_HANDSHAKE_INTERVAL_US, @@ -360,7 +381,9 @@ static enum fw_upload_err rsu_send_data(struct m10bmc_sec *sec) static int rsu_check_complete(struct m10bmc_sec *sec, u32 *doorbell) { - if (m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, doorbell)) + const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; + + if (m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, doorbell)) return -EIO; switch (rsu_stat(*doorbell)) { @@ -389,10 +412,11 @@ static int rsu_check_complete(struct m10bmc_sec *sec, u32 *doorbell) static enum fw_upload_err rsu_cancel(struct m10bmc_sec *sec) { + const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; u32 doorbell; int ret; - ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell); + ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, &doorbell); if (ret) return FW_UPLOAD_ERR_RW_ERROR; @@ -400,7 +424,7 @@ static enum fw_upload_err rsu_cancel(struct m10bmc_sec *sec) return FW_UPLOAD_ERR_BUSY; ret = regmap_update_bits(sec->m10bmc->regmap, - M10BMC_SYS_BASE + M10BMC_DOORBELL, + csr_map->base + csr_map->doorbell, DRBL_HOST_STATUS, FIELD_PREP(DRBL_HOST_STATUS, HOST_STATUS_ABORT_RSU)); @@ -445,6 +469,7 @@ static enum fw_upload_err m10bmc_sec_write(struct fw_upload *fwl, const u8 *data u32 offset, u32 size, u32 *written) { struct m10bmc_sec *sec = fwl->dd_handle; + const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; u32 blk_size, doorbell, extra_offset; unsigned int stride, extra = 0; int ret; @@ -453,7 +478,7 @@ static enum fw_upload_err m10bmc_sec_write(struct fw_upload *fwl, const u8 *data if (sec->cancel_request) return rsu_cancel(sec); - ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell); + ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, &doorbell); if (ret) { return FW_UPLOAD_ERR_RW_ERROR; } else if (rsu_prog(doorbell) != RSU_PROG_READY) { diff --git a/drivers/mfd/intel-m10-bmc-core.c b/drivers/mfd/intel-m10-bmc-core.c index dd26e3a6c3ab..cbea8d4f68fa 100644 --- a/drivers/mfd/intel-m10-bmc-core.c +++ b/drivers/mfd/intel-m10-bmc-core.c @@ -19,7 +19,7 @@ static ssize_t bmc_version_show(struct device *dev, unsigned int val; int ret; - ret = m10bmc_sys_read(ddata, M10BMC_BUILD_VER, &val); + ret = m10bmc_sys_read(ddata, ddata->info->csr_map->build_version, &val); if (ret) return ret; @@ -34,7 +34,7 @@ static ssize_t bmcfw_version_show(struct device *dev, unsigned int val; int ret; - ret = m10bmc_sys_read(ddata, NIOS2_FW_VERSION, &val); + ret = m10bmc_sys_read(ddata, ddata->info->csr_map->fw_version, &val); if (ret) return ret; @@ -49,11 +49,11 @@ static ssize_t mac_address_show(struct device *dev, unsigned int macaddr_low, macaddr_high; int ret; - ret = m10bmc_sys_read(ddata, M10BMC_MAC_LOW, &macaddr_low); + ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_low, &macaddr_low); if (ret) return ret; - ret = m10bmc_sys_read(ddata, M10BMC_MAC_HIGH, &macaddr_high); + ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_high, &macaddr_high); if (ret) return ret; @@ -74,7 +74,7 @@ static ssize_t mac_count_show(struct device *dev, unsigned int macaddr_high; int ret; - ret = m10bmc_sys_read(ddata, M10BMC_MAC_HIGH, &macaddr_high); + ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_high, &macaddr_high); if (ret) return ret; diff --git a/drivers/mfd/intel-m10-bmc-spi.c b/drivers/mfd/intel-m10-bmc-spi.c index be1d4ddedabb..3ed7a71a3267 100644 --- a/drivers/mfd/intel-m10-bmc-spi.c +++ b/drivers/mfd/intel-m10-bmc-spi.c @@ -91,6 +91,26 @@ static int intel_m10_bmc_spi_probe(struct spi_device *spi) return m10bmc_dev_init(ddata, info); } +static const struct m10bmc_csr_map m10bmc_n3000_csr_map = { + .base = M10BMC_SYS_BASE, + .build_version = M10BMC_BUILD_VER, + .fw_version = NIOS2_FW_VERSION, + .mac_low = M10BMC_MAC_LOW, + .mac_high = M10BMC_MAC_HIGH, + .doorbell = M10BMC_DOORBELL, + .auth_result = M10BMC_AUTH_RESULT, + .bmc_prog_addr = BMC_PROG_ADDR, + .bmc_reh_addr = BMC_REH_ADDR, + .bmc_magic = BMC_PROG_MAGIC, + .sr_prog_addr = SR_PROG_ADDR, + .sr_reh_addr = SR_REH_ADDR, + .sr_magic = SR_PROG_MAGIC, + .pr_prog_addr = PR_PROG_ADDR, + .pr_reh_addr = PR_REH_ADDR, + .pr_magic = PR_PROG_MAGIC, + .rsu_update_counter = STAGING_FLASH_COUNT, +}; + static struct mfd_cell m10bmc_d5005_subdevs[] = { { .name = "d5005bmc-hwmon" }, { .name = "d5005bmc-sec-update" }, @@ -109,16 +129,19 @@ static struct mfd_cell m10bmc_n5010_subdevs[] = { static const struct intel_m10bmc_platform_info m10bmc_spi_n3000 = { .cells = m10bmc_pacn3000_subdevs, .n_cells = ARRAY_SIZE(m10bmc_pacn3000_subdevs), + .csr_map = &m10bmc_n3000_csr_map, }; static const struct intel_m10bmc_platform_info m10bmc_spi_d5005 = { .cells = m10bmc_d5005_subdevs, .n_cells = ARRAY_SIZE(m10bmc_d5005_subdevs), + .csr_map = &m10bmc_n3000_csr_map, }; static const struct intel_m10bmc_platform_info m10bmc_spi_n5010 = { .cells = m10bmc_n5010_subdevs, .n_cells = ARRAY_SIZE(m10bmc_n5010_subdevs), + .csr_map = &m10bmc_n3000_csr_map, }; static const struct spi_device_id m10bmc_spi_id[] = { diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h index a80deb61b69a..d569a72c7d4f 100644 --- a/include/linux/mfd/intel-m10-bmc.h +++ b/include/linux/mfd/intel-m10-bmc.h @@ -121,14 +121,39 @@ /* Address of 4KB inverted bit vector containing staging area FLASH count */ #define STAGING_FLASH_COUNT 0x17ffb000 +/** + * struct m10bmc_csr_map - Intel MAX 10 BMC CSR register map + */ +struct m10bmc_csr_map { + unsigned int base; + unsigned int build_version; + unsigned int fw_version; + unsigned int mac_low; + unsigned int mac_high; + unsigned int doorbell; + unsigned int auth_result; + unsigned int bmc_prog_addr; + unsigned int bmc_reh_addr; + unsigned int bmc_magic; + unsigned int sr_prog_addr; + unsigned int sr_reh_addr; + unsigned int sr_magic; + unsigned int pr_prog_addr; + unsigned int pr_reh_addr; + unsigned int pr_magic; + unsigned int rsu_update_counter; +}; + /** * struct intel_m10bmc_platform_info - Intel MAX 10 BMC platform specific information * @cells: MFD cells * @n_cells: MFD cells ARRAY_SIZE() + * @csr_map: the mappings for register definition of MAX10 BMC */ struct intel_m10bmc_platform_info { struct mfd_cell *cells; int n_cells; + const struct m10bmc_csr_map *csr_map; }; /** @@ -167,12 +192,17 @@ m10bmc_raw_read(struct intel_m10bmc *m10bmc, unsigned int addr, * The base of the system registers could be configured by HW developers, and * in HW SPEC, the base is not added to the addresses of the system registers. * - * This macro helps to simplify the accessing of the system registers. And if + * This function helps to simplify the accessing of the system registers. And if * the base is reconfigured in HW, SW developers could simply change the - * M10BMC_SYS_BASE accordingly. + * csr_map's base accordingly. */ -#define m10bmc_sys_read(m10bmc, offset, val) \ - m10bmc_raw_read(m10bmc, M10BMC_SYS_BASE + (offset), val) +static inline int m10bmc_sys_read(struct intel_m10bmc *m10bmc, unsigned int offset, + unsigned int *val) +{ + const struct m10bmc_csr_map *csr_map = m10bmc->info->csr_map; + + return m10bmc_raw_read(m10bmc, csr_map->base + offset, val); +} /* * MAX10 BMC Core support From 3e10c805b382d0a8906a4fed109958cac637f5e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 16 Jan 2023 12:08:40 +0200 Subject: [PATCH 06/40] fpga: intel-m10-bmc: Rework flash read/write MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Access to flash staging area is different for N6000 from that of the SPI interfaced counterparts. To make it easier to differentiate flash access path, move read/write into new functions where the new access path can be easily placed into. Rework the unaligned access such the behavior it matches for both read and write. This change also renames m10bmc_sec_write() to m10bmc_sec_fw_write() as it would have a name conflict otherwise. Co-developed-by: Tianfei zhang Signed-off-by: Tianfei zhang Co-developed-by: Russ Weight Signed-off-by: Russ Weight Acked-by: Xu Yilun Signed-off-by: Ilpo Järvinen Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230116100845.6153-7-ilpo.jarvinen@linux.intel.com --- drivers/fpga/intel-m10-bmc-sec-update.c | 143 +++++++++++++----------- 1 file changed, 79 insertions(+), 64 deletions(-) diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c index dbe8aff95da3..2df24e70012d 100644 --- a/drivers/fpga/intel-m10-bmc-sec-update.c +++ b/drivers/fpga/intel-m10-bmc-sec-update.c @@ -31,6 +31,65 @@ static DEFINE_XARRAY_ALLOC(fw_upload_xa); #define REH_MAGIC GENMASK(15, 0) #define REH_SHA_NUM_BYTES GENMASK(31, 16) +static int m10bmc_sec_write(struct m10bmc_sec *sec, const u8 *buf, u32 offset, u32 size) +{ + struct intel_m10bmc *m10bmc = sec->m10bmc; + unsigned int stride = regmap_get_reg_stride(m10bmc->regmap); + u32 write_count = size / stride; + u32 leftover_offset = write_count * stride; + u32 leftover_size = size - leftover_offset; + u32 leftover_tmp = 0; + int ret; + + if (WARN_ON_ONCE(stride > sizeof(leftover_tmp))) + return -EINVAL; + + ret = regmap_bulk_write(m10bmc->regmap, M10BMC_STAGING_BASE + offset, + buf + offset, write_count); + if (ret) + return ret; + + /* If size is not aligned to stride, handle the remainder bytes with regmap_write() */ + if (leftover_size) { + memcpy(&leftover_tmp, buf + leftover_offset, leftover_size); + ret = regmap_write(m10bmc->regmap, M10BMC_STAGING_BASE + offset + leftover_offset, + leftover_tmp); + if (ret) + return ret; + } + + return 0; +} + +static int m10bmc_sec_read(struct m10bmc_sec *sec, u8 *buf, u32 addr, u32 size) +{ + struct intel_m10bmc *m10bmc = sec->m10bmc; + unsigned int stride = regmap_get_reg_stride(m10bmc->regmap); + u32 read_count = size / stride; + u32 leftover_offset = read_count * stride; + u32 leftover_size = size - leftover_offset; + u32 leftover_tmp; + int ret; + + if (WARN_ON_ONCE(stride > sizeof(leftover_tmp))) + return -EINVAL; + + ret = regmap_bulk_read(m10bmc->regmap, addr, buf, read_count); + if (ret) + return ret; + + /* If size is not aligned to stride, handle the remainder bytes with regmap_read() */ + if (leftover_size) { + ret = regmap_read(m10bmc->regmap, addr + leftover_offset, &leftover_tmp); + if (ret) + return ret; + memcpy(buf + leftover_offset, &leftover_tmp, leftover_size); + } + + return 0; +} + + static ssize_t show_root_entry_hash(struct device *dev, u32 exp_magic, u32 prog_addr, u32 reh_addr, char *buf) @@ -38,11 +97,9 @@ show_root_entry_hash(struct device *dev, u32 exp_magic, struct m10bmc_sec *sec = dev_get_drvdata(dev); int sha_num_bytes, i, ret, cnt = 0; u8 hash[REH_SHA384_SIZE]; - unsigned int stride; u32 magic; - stride = regmap_get_reg_stride(sec->m10bmc->regmap); - ret = m10bmc_raw_read(sec->m10bmc, prog_addr, &magic); + ret = m10bmc_sec_read(sec, (u8 *)&magic, prog_addr, sizeof(magic)); if (ret) return ret; @@ -50,19 +107,16 @@ show_root_entry_hash(struct device *dev, u32 exp_magic, return sysfs_emit(buf, "hash not programmed\n"); sha_num_bytes = FIELD_GET(REH_SHA_NUM_BYTES, magic) / 8; - if ((sha_num_bytes % stride) || - (sha_num_bytes != REH_SHA256_SIZE && - sha_num_bytes != REH_SHA384_SIZE)) { + if (sha_num_bytes != REH_SHA256_SIZE && + sha_num_bytes != REH_SHA384_SIZE) { dev_err(sec->dev, "%s bad sha num bytes %d\n", __func__, sha_num_bytes); return -EINVAL; } - ret = regmap_bulk_read(sec->m10bmc->regmap, reh_addr, - hash, sha_num_bytes / stride); + ret = m10bmc_sec_read(sec, hash, reh_addr, sha_num_bytes); if (ret) { - dev_err(dev, "failed to read root entry hash: %x cnt %x: %d\n", - reh_addr, sha_num_bytes / stride, ret); + dev_err(dev, "failed to read root entry hash\n"); return ret; } @@ -98,27 +152,16 @@ DEVICE_ATTR_SEC_REH_RO(pr); static ssize_t show_canceled_csk(struct device *dev, u32 addr, char *buf) { - unsigned int i, stride, size = CSK_32ARRAY_SIZE * sizeof(u32); + unsigned int i, size = CSK_32ARRAY_SIZE * sizeof(u32); struct m10bmc_sec *sec = dev_get_drvdata(dev); DECLARE_BITMAP(csk_map, CSK_BIT_LEN); __le32 csk_le32[CSK_32ARRAY_SIZE]; u32 csk32[CSK_32ARRAY_SIZE]; int ret; - stride = regmap_get_reg_stride(sec->m10bmc->regmap); - if (size % stride) { - dev_err(sec->dev, - "CSK vector size (0x%x) not aligned to stride (0x%x)\n", - size, stride); - WARN_ON_ONCE(1); - return -EINVAL; - } - - ret = regmap_bulk_read(sec->m10bmc->regmap, addr, csk_le32, - size / stride); + ret = m10bmc_sec_read(sec, (u8 *)&csk_le32, addr, size); if (ret) { - dev_err(sec->dev, "failed to read CSK vector: %x cnt %x: %d\n", - addr, size / stride, ret); + dev_err(sec->dev, "failed to read CSK vector\n"); return ret; } @@ -157,31 +200,20 @@ static ssize_t flash_count_show(struct device *dev, { struct m10bmc_sec *sec = dev_get_drvdata(dev); const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; - unsigned int stride, num_bits; + unsigned int num_bits; u8 *flash_buf; int cnt, ret; - stride = regmap_get_reg_stride(sec->m10bmc->regmap); num_bits = FLASH_COUNT_SIZE * 8; - if (FLASH_COUNT_SIZE % stride) { - dev_err(sec->dev, - "FLASH_COUNT_SIZE (0x%x) not aligned to stride (0x%x)\n", - FLASH_COUNT_SIZE, stride); - WARN_ON_ONCE(1); - return -EINVAL; - } - flash_buf = kmalloc(FLASH_COUNT_SIZE, GFP_KERNEL); if (!flash_buf) return -ENOMEM; - ret = regmap_bulk_read(sec->m10bmc->regmap, csr_map->rsu_update_counter, - flash_buf, FLASH_COUNT_SIZE / stride); + ret = m10bmc_sec_read(sec, flash_buf, csr_map->rsu_update_counter, + FLASH_COUNT_SIZE); if (ret) { - dev_err(sec->dev, - "failed to read flash count: %x cnt %x: %d\n", - csr_map->rsu_update_counter, FLASH_COUNT_SIZE / stride, ret); + dev_err(sec->dev, "failed to read flash count\n"); goto exit_free; } cnt = num_bits - bitmap_weight((unsigned long *)flash_buf, num_bits); @@ -465,20 +497,19 @@ static enum fw_upload_err m10bmc_sec_prepare(struct fw_upload *fwl, #define WRITE_BLOCK_SIZE 0x4000 /* Default write-block size is 0x4000 bytes */ -static enum fw_upload_err m10bmc_sec_write(struct fw_upload *fwl, const u8 *data, - u32 offset, u32 size, u32 *written) +static enum fw_upload_err m10bmc_sec_fw_write(struct fw_upload *fwl, const u8 *data, + u32 offset, u32 size, u32 *written) { struct m10bmc_sec *sec = fwl->dd_handle; const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; - u32 blk_size, doorbell, extra_offset; - unsigned int stride, extra = 0; + struct intel_m10bmc *m10bmc = sec->m10bmc; + u32 blk_size, doorbell; int ret; - stride = regmap_get_reg_stride(sec->m10bmc->regmap); if (sec->cancel_request) return rsu_cancel(sec); - ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, &doorbell); + ret = m10bmc_sys_read(m10bmc, csr_map->doorbell, &doorbell); if (ret) { return FW_UPLOAD_ERR_RW_ERROR; } else if (rsu_prog(doorbell) != RSU_PROG_READY) { @@ -486,28 +517,12 @@ static enum fw_upload_err m10bmc_sec_write(struct fw_upload *fwl, const u8 *data return FW_UPLOAD_ERR_HW_ERROR; } - WARN_ON_ONCE(WRITE_BLOCK_SIZE % stride); + WARN_ON_ONCE(WRITE_BLOCK_SIZE % regmap_get_reg_stride(m10bmc->regmap)); blk_size = min_t(u32, WRITE_BLOCK_SIZE, size); - ret = regmap_bulk_write(sec->m10bmc->regmap, - M10BMC_STAGING_BASE + offset, - (void *)data + offset, - blk_size / stride); + ret = m10bmc_sec_write(sec, data, offset, blk_size); if (ret) return FW_UPLOAD_ERR_RW_ERROR; - /* - * If blk_size is not aligned to stride, then handle the extra - * bytes with regmap_write. - */ - if (blk_size % stride) { - extra_offset = offset + ALIGN_DOWN(blk_size, stride); - memcpy(&extra, (u8 *)(data + extra_offset), blk_size % stride); - ret = regmap_write(sec->m10bmc->regmap, - M10BMC_STAGING_BASE + extra_offset, extra); - if (ret) - return FW_UPLOAD_ERR_RW_ERROR; - } - *written = blk_size; return FW_UPLOAD_ERR_NONE; } @@ -568,7 +583,7 @@ static void m10bmc_sec_cleanup(struct fw_upload *fwl) static const struct fw_upload_ops m10bmc_ops = { .prepare = m10bmc_sec_prepare, - .write = m10bmc_sec_write, + .write = m10bmc_sec_fw_write, .poll_complete = m10bmc_sec_poll_complete, .cancel = m10bmc_sec_cancel, .cleanup = m10bmc_sec_cleanup, From bcababfc60ccc622268b2317a22fabd879fbc0a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 16 Jan 2023 12:08:41 +0200 Subject: [PATCH 07/40] mfd: intel-m10-bmc: Prefix register defines with M10BMC_N3000 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prefix the M10BMC defines register defines with M10BMC_N3000 to make it more obvious these are related to some board type. All current non-N3000 board types have the same layout so they'll be reused. The less generic makes it more obvious they're not meant for the generic/interface agnostic code. Reviewed-by: Russ Weight Reviewed-by: Xu Yilun Signed-off-by: Ilpo Järvinen Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230116100845.6153-8-ilpo.jarvinen@linux.intel.com --- drivers/mfd/intel-m10-bmc-core.c | 14 +++---- drivers/mfd/intel-m10-bmc-spi.c | 52 ++++++++++++------------ include/linux/mfd/intel-m10-bmc.h | 66 +++++++++++++++---------------- 3 files changed, 66 insertions(+), 66 deletions(-) diff --git a/drivers/mfd/intel-m10-bmc-core.c b/drivers/mfd/intel-m10-bmc-core.c index cbea8d4f68fa..dac9cf7bcb4a 100644 --- a/drivers/mfd/intel-m10-bmc-core.c +++ b/drivers/mfd/intel-m10-bmc-core.c @@ -58,12 +58,12 @@ static ssize_t mac_address_show(struct device *dev, return ret; return sysfs_emit(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", - (u8)FIELD_GET(M10BMC_MAC_BYTE1, macaddr_low), - (u8)FIELD_GET(M10BMC_MAC_BYTE2, macaddr_low), - (u8)FIELD_GET(M10BMC_MAC_BYTE3, macaddr_low), - (u8)FIELD_GET(M10BMC_MAC_BYTE4, macaddr_low), - (u8)FIELD_GET(M10BMC_MAC_BYTE5, macaddr_high), - (u8)FIELD_GET(M10BMC_MAC_BYTE6, macaddr_high)); + (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE1, macaddr_low), + (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE2, macaddr_low), + (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE3, macaddr_low), + (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE4, macaddr_low), + (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE5, macaddr_high), + (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE6, macaddr_high)); } static DEVICE_ATTR_RO(mac_address); @@ -78,7 +78,7 @@ static ssize_t mac_count_show(struct device *dev, if (ret) return ret; - return sysfs_emit(buf, "%u\n", (u8)FIELD_GET(M10BMC_MAC_COUNT, macaddr_high)); + return sysfs_emit(buf, "%u\n", (u8)FIELD_GET(M10BMC_N3000_MAC_COUNT, macaddr_high)); } static DEVICE_ATTR_RO(mac_count); diff --git a/drivers/mfd/intel-m10-bmc-spi.c b/drivers/mfd/intel-m10-bmc-spi.c index 3ed7a71a3267..957200e17fed 100644 --- a/drivers/mfd/intel-m10-bmc-spi.c +++ b/drivers/mfd/intel-m10-bmc-spi.c @@ -14,9 +14,9 @@ #include static const struct regmap_range m10bmc_regmap_range[] = { - regmap_reg_range(M10BMC_LEGACY_BUILD_VER, M10BMC_LEGACY_BUILD_VER), - regmap_reg_range(M10BMC_SYS_BASE, M10BMC_SYS_END), - regmap_reg_range(M10BMC_FLASH_BASE, M10BMC_FLASH_END), + regmap_reg_range(M10BMC_N3000_LEGACY_BUILD_VER, M10BMC_N3000_LEGACY_BUILD_VER), + regmap_reg_range(M10BMC_N3000_SYS_BASE, M10BMC_N3000_SYS_END), + regmap_reg_range(M10BMC_N3000_FLASH_BASE, M10BMC_N3000_FLASH_END), }; static const struct regmap_access_table m10bmc_access_table = { @@ -30,7 +30,7 @@ static struct regmap_config intel_m10bmc_regmap_config = { .reg_stride = 4, .wr_table = &m10bmc_access_table, .rd_table = &m10bmc_access_table, - .max_register = M10BMC_MEM_END, + .max_register = M10BMC_N3000_MEM_END, }; static int check_m10bmc_version(struct intel_m10bmc *ddata) @@ -41,16 +41,16 @@ static int check_m10bmc_version(struct intel_m10bmc *ddata) /* * This check is to filter out the very old legacy BMC versions. In the * old BMC chips, the BMC version info is stored in the old version - * register (M10BMC_LEGACY_BUILD_VER), so its read out value would have - * not been M10BMC_VER_LEGACY_INVALID (0xffffffff). But in new BMC + * register (M10BMC_N3000_LEGACY_BUILD_VER), so its read out value would have + * not been M10BMC_N3000_VER_LEGACY_INVALID (0xffffffff). But in new BMC * chips that the driver supports, the value of this register should be - * M10BMC_VER_LEGACY_INVALID. + * M10BMC_N3000_VER_LEGACY_INVALID. */ - ret = m10bmc_raw_read(ddata, M10BMC_LEGACY_BUILD_VER, &v); + ret = m10bmc_raw_read(ddata, M10BMC_N3000_LEGACY_BUILD_VER, &v); if (ret) return -ENODEV; - if (v != M10BMC_VER_LEGACY_INVALID) { + if (v != M10BMC_N3000_VER_LEGACY_INVALID) { dev_err(ddata->dev, "bad version M10BMC detected\n"); return -ENODEV; } @@ -92,23 +92,23 @@ static int intel_m10_bmc_spi_probe(struct spi_device *spi) } static const struct m10bmc_csr_map m10bmc_n3000_csr_map = { - .base = M10BMC_SYS_BASE, - .build_version = M10BMC_BUILD_VER, - .fw_version = NIOS2_FW_VERSION, - .mac_low = M10BMC_MAC_LOW, - .mac_high = M10BMC_MAC_HIGH, - .doorbell = M10BMC_DOORBELL, - .auth_result = M10BMC_AUTH_RESULT, - .bmc_prog_addr = BMC_PROG_ADDR, - .bmc_reh_addr = BMC_REH_ADDR, - .bmc_magic = BMC_PROG_MAGIC, - .sr_prog_addr = SR_PROG_ADDR, - .sr_reh_addr = SR_REH_ADDR, - .sr_magic = SR_PROG_MAGIC, - .pr_prog_addr = PR_PROG_ADDR, - .pr_reh_addr = PR_REH_ADDR, - .pr_magic = PR_PROG_MAGIC, - .rsu_update_counter = STAGING_FLASH_COUNT, + .base = M10BMC_N3000_SYS_BASE, + .build_version = M10BMC_N3000_BUILD_VER, + .fw_version = NIOS2_N3000_FW_VERSION, + .mac_low = M10BMC_N3000_MAC_LOW, + .mac_high = M10BMC_N3000_MAC_HIGH, + .doorbell = M10BMC_N3000_DOORBELL, + .auth_result = M10BMC_N3000_AUTH_RESULT, + .bmc_prog_addr = M10BMC_N3000_BMC_PROG_ADDR, + .bmc_reh_addr = M10BMC_N3000_BMC_REH_ADDR, + .bmc_magic = M10BMC_N3000_BMC_PROG_MAGIC, + .sr_prog_addr = M10BMC_N3000_SR_PROG_ADDR, + .sr_reh_addr = M10BMC_N3000_SR_REH_ADDR, + .sr_magic = M10BMC_N3000_SR_PROG_MAGIC, + .pr_prog_addr = M10BMC_N3000_PR_PROG_ADDR, + .pr_reh_addr = M10BMC_N3000_PR_REH_ADDR, + .pr_magic = M10BMC_N3000_PR_PROG_MAGIC, + .rsu_update_counter = M10BMC_N3000_STAGING_FLASH_COUNT, }; static struct mfd_cell m10bmc_d5005_subdevs[] = { diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h index d569a72c7d4f..470dc3773c01 100644 --- a/include/linux/mfd/intel-m10-bmc.h +++ b/include/linux/mfd/intel-m10-bmc.h @@ -12,38 +12,38 @@ #include #include -#define M10BMC_LEGACY_BUILD_VER 0x300468 -#define M10BMC_SYS_BASE 0x300800 -#define M10BMC_SYS_END 0x300fff -#define M10BMC_FLASH_BASE 0x10000000 -#define M10BMC_FLASH_END 0x1fffffff -#define M10BMC_MEM_END M10BMC_FLASH_END +#define M10BMC_N3000_LEGACY_BUILD_VER 0x300468 +#define M10BMC_N3000_SYS_BASE 0x300800 +#define M10BMC_N3000_SYS_END 0x300fff +#define M10BMC_N3000_FLASH_BASE 0x10000000 +#define M10BMC_N3000_FLASH_END 0x1fffffff +#define M10BMC_N3000_MEM_END M10BMC_N3000_FLASH_END #define M10BMC_STAGING_BASE 0x18000000 #define M10BMC_STAGING_SIZE 0x3800000 /* Register offset of system registers */ -#define NIOS2_FW_VERSION 0x0 -#define M10BMC_MAC_LOW 0x10 -#define M10BMC_MAC_BYTE4 GENMASK(7, 0) -#define M10BMC_MAC_BYTE3 GENMASK(15, 8) -#define M10BMC_MAC_BYTE2 GENMASK(23, 16) -#define M10BMC_MAC_BYTE1 GENMASK(31, 24) -#define M10BMC_MAC_HIGH 0x14 -#define M10BMC_MAC_BYTE6 GENMASK(7, 0) -#define M10BMC_MAC_BYTE5 GENMASK(15, 8) -#define M10BMC_MAC_COUNT GENMASK(23, 16) -#define M10BMC_TEST_REG 0x3c -#define M10BMC_BUILD_VER 0x68 -#define M10BMC_VER_MAJOR_MSK GENMASK(23, 16) -#define M10BMC_VER_PCB_INFO_MSK GENMASK(31, 24) -#define M10BMC_VER_LEGACY_INVALID 0xffffffff +#define NIOS2_N3000_FW_VERSION 0x0 +#define M10BMC_N3000_MAC_LOW 0x10 +#define M10BMC_N3000_MAC_BYTE4 GENMASK(7, 0) +#define M10BMC_N3000_MAC_BYTE3 GENMASK(15, 8) +#define M10BMC_N3000_MAC_BYTE2 GENMASK(23, 16) +#define M10BMC_N3000_MAC_BYTE1 GENMASK(31, 24) +#define M10BMC_N3000_MAC_HIGH 0x14 +#define M10BMC_N3000_MAC_BYTE6 GENMASK(7, 0) +#define M10BMC_N3000_MAC_BYTE5 GENMASK(15, 8) +#define M10BMC_N3000_MAC_COUNT GENMASK(23, 16) +#define M10BMC_N3000_TEST_REG 0x3c +#define M10BMC_N3000_BUILD_VER 0x68 +#define M10BMC_N3000_VER_MAJOR_MSK GENMASK(23, 16) +#define M10BMC_N3000_VER_PCB_INFO_MSK GENMASK(31, 24) +#define M10BMC_N3000_VER_LEGACY_INVALID 0xffffffff /* Secure update doorbell register, in system register region */ -#define M10BMC_DOORBELL 0x400 +#define M10BMC_N3000_DOORBELL 0x400 /* Authorization Result register, in system register region */ -#define M10BMC_AUTH_RESULT 0x404 +#define M10BMC_N3000_AUTH_RESULT 0x404 /* Doorbell register fields */ #define DRBL_RSU_REQUEST BIT(0) @@ -106,20 +106,20 @@ #define RSU_COMPLETE_TIMEOUT_MS (40 * 60 * 1000) /* Addresses for security related data in FLASH */ -#define BMC_REH_ADDR 0x17ffc004 -#define BMC_PROG_ADDR 0x17ffc000 -#define BMC_PROG_MAGIC 0x5746 +#define M10BMC_N3000_BMC_REH_ADDR 0x17ffc004 +#define M10BMC_N3000_BMC_PROG_ADDR 0x17ffc000 +#define M10BMC_N3000_BMC_PROG_MAGIC 0x5746 -#define SR_REH_ADDR 0x17ffd004 -#define SR_PROG_ADDR 0x17ffd000 -#define SR_PROG_MAGIC 0x5253 +#define M10BMC_N3000_SR_REH_ADDR 0x17ffd004 +#define M10BMC_N3000_SR_PROG_ADDR 0x17ffd000 +#define M10BMC_N3000_SR_PROG_MAGIC 0x5253 -#define PR_REH_ADDR 0x17ffe004 -#define PR_PROG_ADDR 0x17ffe000 -#define PR_PROG_MAGIC 0x5250 +#define M10BMC_N3000_PR_REH_ADDR 0x17ffe004 +#define M10BMC_N3000_PR_PROG_ADDR 0x17ffe000 +#define M10BMC_N3000_PR_PROG_MAGIC 0x5250 /* Address of 4KB inverted bit vector containing staging area FLASH count */ -#define STAGING_FLASH_COUNT 0x17ffb000 +#define M10BMC_N3000_STAGING_FLASH_COUNT 0x17ffb000 /** * struct m10bmc_csr_map - Intel MAX 10 BMC CSR register map From da04fa8c40c339da7bb6de463ef83bc141d1111e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 16 Jan 2023 12:08:42 +0200 Subject: [PATCH 08/40] fpga: m10bmc-sec: Create helpers for rsu status/progress checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RSU_STAT_* and RSU_PROG_* checks are done in more than one place in the sec update code. Move the checks into new helper functions. No function changes intended. Co-developed-by: Tianfei zhang Signed-off-by: Tianfei zhang Co-developed-by: Russ Weight Signed-off-by: Russ Weight Acked-by: Xu Yilun Signed-off-by: Ilpo Järvinen Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230116100845.6153-9-ilpo.jarvinen@linux.intel.com --- drivers/fpga/intel-m10-bmc-sec-update.c | 59 +++++++++++++------------ 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c index 2df24e70012d..43d9598d6077 100644 --- a/drivers/fpga/intel-m10-bmc-sec-update.c +++ b/drivers/fpga/intel-m10-bmc-sec-update.c @@ -257,6 +257,28 @@ static void log_error_regs(struct m10bmc_sec *sec, u32 doorbell) dev_err(sec->dev, "RSU auth result: 0x%08x\n", auth_result); } +static bool rsu_status_ok(u32 status) +{ + return (status == RSU_STAT_NORMAL || + status == RSU_STAT_NIOS_OK || + status == RSU_STAT_USER_OK || + status == RSU_STAT_FACTORY_OK); +} + +static bool rsu_progress_done(u32 progress) +{ + return (progress == RSU_PROG_IDLE || + progress == RSU_PROG_RSU_DONE); +} + +static bool rsu_progress_busy(u32 progress) +{ + return (progress == RSU_PROG_AUTHENTICATING || + progress == RSU_PROG_COPYING || + progress == RSU_PROG_UPDATE_CANCEL || + progress == RSU_PROG_PROGRAM_KEY_HASH); +} + static enum fw_upload_err rsu_check_idle(struct m10bmc_sec *sec) { const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; @@ -267,8 +289,7 @@ static enum fw_upload_err rsu_check_idle(struct m10bmc_sec *sec) if (ret) return FW_UPLOAD_ERR_RW_ERROR; - if (rsu_prog(doorbell) != RSU_PROG_IDLE && - rsu_prog(doorbell) != RSU_PROG_RSU_DONE) { + if (!rsu_progress_done(rsu_prog(doorbell))) { log_error_regs(sec, doorbell); return FW_UPLOAD_ERR_BUSY; } @@ -288,7 +309,7 @@ static inline bool rsu_start_done(u32 doorbell) return true; progress = rsu_prog(doorbell); - if (progress != RSU_PROG_IDLE && progress != RSU_PROG_RSU_DONE) + if (!rsu_progress_done(progress)) return true; return false; @@ -397,13 +418,7 @@ static enum fw_upload_err rsu_send_data(struct m10bmc_sec *sec) return FW_UPLOAD_ERR_RW_ERROR; } - switch (rsu_stat(doorbell)) { - case RSU_STAT_NORMAL: - case RSU_STAT_NIOS_OK: - case RSU_STAT_USER_OK: - case RSU_STAT_FACTORY_OK: - break; - default: + if (!rsu_status_ok(rsu_stat(doorbell))) { log_error_regs(sec, doorbell); return FW_UPLOAD_ERR_HW_ERROR; } @@ -418,28 +433,16 @@ static int rsu_check_complete(struct m10bmc_sec *sec, u32 *doorbell) if (m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, doorbell)) return -EIO; - switch (rsu_stat(*doorbell)) { - case RSU_STAT_NORMAL: - case RSU_STAT_NIOS_OK: - case RSU_STAT_USER_OK: - case RSU_STAT_FACTORY_OK: - break; - default: + if (!rsu_status_ok(rsu_stat(*doorbell))) return -EINVAL; - } - switch (rsu_prog(*doorbell)) { - case RSU_PROG_IDLE: - case RSU_PROG_RSU_DONE: + if (rsu_progress_done(rsu_prog(*doorbell))) return 0; - case RSU_PROG_AUTHENTICATING: - case RSU_PROG_COPYING: - case RSU_PROG_UPDATE_CANCEL: - case RSU_PROG_PROGRAM_KEY_HASH: + + if (rsu_progress_busy(rsu_prog(*doorbell))) return -EAGAIN; - default: - return -EINVAL; - } + + return -EINVAL; } static enum fw_upload_err rsu_cancel(struct m10bmc_sec *sec) From 001a734a55d09aa1716eb2cd5ccab8b4d7a068a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 16 Jan 2023 12:08:43 +0200 Subject: [PATCH 09/40] fpga: m10bmc-sec: Make rsu status type specific MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rsu status field moves from the doorbell register to the auth result register in the PMCI implementation of the MAX10 BMC. In order to prepare for that, refactor the sec update driver code to have a type specific ops that provides ->rsu_status(). Co-developed-by: Tianfei zhang Signed-off-by: Tianfei zhang Co-developed-by: Russ Weight Signed-off-by: Russ Weight Signed-off-by: Ilpo Järvinen Acked-by: Xu Yilun Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230116100845.6153-10-ilpo.jarvinen@linux.intel.com --- drivers/fpga/intel-m10-bmc-sec-update.c | 109 +++++++++++++++++------- include/linux/mfd/intel-m10-bmc.h | 1 - 2 files changed, 78 insertions(+), 32 deletions(-) diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c index 43d9598d6077..92145ee7333e 100644 --- a/drivers/fpga/intel-m10-bmc-sec-update.c +++ b/drivers/fpga/intel-m10-bmc-sec-update.c @@ -14,6 +14,12 @@ #include #include +struct m10bmc_sec; + +struct m10bmc_sec_ops { + int (*rsu_status)(struct m10bmc_sec *sec); +}; + struct m10bmc_sec { struct device *dev; struct intel_m10bmc *m10bmc; @@ -21,6 +27,7 @@ struct m10bmc_sec { char *fw_name; u32 fw_name_id; bool cancel_request; + const struct m10bmc_sec_ops *ops; }; static DEFINE_XARRAY_ALLOC(fw_upload_xa); @@ -251,12 +258,25 @@ static void log_error_regs(struct m10bmc_sec *sec, u32 doorbell) const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; u32 auth_result; - dev_err(sec->dev, "RSU error status: 0x%08x\n", doorbell); + dev_err(sec->dev, "Doorbell: 0x%08x\n", doorbell); if (!m10bmc_sys_read(sec->m10bmc, csr_map->auth_result, &auth_result)) dev_err(sec->dev, "RSU auth result: 0x%08x\n", auth_result); } +static int m10bmc_sec_n3000_rsu_status(struct m10bmc_sec *sec) +{ + const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; + u32 doorbell; + int ret; + + ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, &doorbell); + if (ret) + return ret; + + return FIELD_GET(DRBL_RSU_STATUS, doorbell); +} + static bool rsu_status_ok(u32 status) { return (status == RSU_STAT_NORMAL || @@ -279,6 +299,26 @@ static bool rsu_progress_busy(u32 progress) progress == RSU_PROG_PROGRAM_KEY_HASH); } +static int m10bmc_sec_progress_status(struct m10bmc_sec *sec, u32 *doorbell_reg, + u32 *progress, u32 *status) +{ + const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; + int ret; + + ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, doorbell_reg); + if (ret) + return ret; + + ret = sec->ops->rsu_status(sec); + if (ret < 0) + return ret; + + *status = ret; + *progress = rsu_prog(*doorbell_reg); + + return 0; +} + static enum fw_upload_err rsu_check_idle(struct m10bmc_sec *sec) { const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; @@ -297,18 +337,14 @@ static enum fw_upload_err rsu_check_idle(struct m10bmc_sec *sec) return FW_UPLOAD_ERR_NONE; } -static inline bool rsu_start_done(u32 doorbell) +static inline bool rsu_start_done(u32 doorbell_reg, u32 progress, u32 status) { - u32 status, progress; - - if (doorbell & DRBL_RSU_REQUEST) + if (doorbell_reg & DRBL_RSU_REQUEST) return false; - status = rsu_stat(doorbell); if (status == RSU_STAT_ERASE_FAIL || status == RSU_STAT_WEAROUT) return true; - progress = rsu_prog(doorbell); if (!rsu_progress_done(progress)) return true; @@ -318,8 +354,8 @@ static inline bool rsu_start_done(u32 doorbell) static enum fw_upload_err rsu_update_init(struct m10bmc_sec *sec) { const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; - u32 doorbell, status; - int ret; + u32 doorbell_reg, progress, status; + int ret, err; ret = regmap_update_bits(sec->m10bmc->regmap, csr_map->base + csr_map->doorbell, @@ -330,26 +366,25 @@ static enum fw_upload_err rsu_update_init(struct m10bmc_sec *sec) if (ret) return FW_UPLOAD_ERR_RW_ERROR; - ret = regmap_read_poll_timeout(sec->m10bmc->regmap, - csr_map->base + csr_map->doorbell, - doorbell, - rsu_start_done(doorbell), - NIOS_HANDSHAKE_INTERVAL_US, - NIOS_HANDSHAKE_TIMEOUT_US); + ret = read_poll_timeout(m10bmc_sec_progress_status, err, + err < 0 || rsu_start_done(doorbell_reg, progress, status), + NIOS_HANDSHAKE_INTERVAL_US, + NIOS_HANDSHAKE_TIMEOUT_US, + false, + sec, &doorbell_reg, &progress, &status); if (ret == -ETIMEDOUT) { - log_error_regs(sec, doorbell); + log_error_regs(sec, doorbell_reg); return FW_UPLOAD_ERR_TIMEOUT; - } else if (ret) { + } else if (err) { return FW_UPLOAD_ERR_RW_ERROR; } - status = rsu_stat(doorbell); if (status == RSU_STAT_WEAROUT) { dev_warn(sec->dev, "Excessive flash update count detected\n"); return FW_UPLOAD_ERR_WEAROUT; } else if (status == RSU_STAT_ERASE_FAIL) { - log_error_regs(sec, doorbell); + log_error_regs(sec, doorbell_reg); return FW_UPLOAD_ERR_HW_ERROR; } @@ -393,7 +428,7 @@ static enum fw_upload_err rsu_prog_ready(struct m10bmc_sec *sec) static enum fw_upload_err rsu_send_data(struct m10bmc_sec *sec) { const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; - u32 doorbell; + u32 doorbell_reg, status; int ret; ret = regmap_update_bits(sec->m10bmc->regmap, @@ -406,40 +441,45 @@ static enum fw_upload_err rsu_send_data(struct m10bmc_sec *sec) ret = regmap_read_poll_timeout(sec->m10bmc->regmap, csr_map->base + csr_map->doorbell, - doorbell, - rsu_prog(doorbell) != RSU_PROG_READY, + doorbell_reg, + rsu_prog(doorbell_reg) != RSU_PROG_READY, NIOS_HANDSHAKE_INTERVAL_US, NIOS_HANDSHAKE_TIMEOUT_US); if (ret == -ETIMEDOUT) { - log_error_regs(sec, doorbell); + log_error_regs(sec, doorbell_reg); return FW_UPLOAD_ERR_TIMEOUT; } else if (ret) { return FW_UPLOAD_ERR_RW_ERROR; } - if (!rsu_status_ok(rsu_stat(doorbell))) { - log_error_regs(sec, doorbell); + ret = sec->ops->rsu_status(sec); + if (ret < 0) + return ret; + status = ret; + + if (!rsu_status_ok(status)) { + log_error_regs(sec, doorbell_reg); return FW_UPLOAD_ERR_HW_ERROR; } return FW_UPLOAD_ERR_NONE; } -static int rsu_check_complete(struct m10bmc_sec *sec, u32 *doorbell) +static int rsu_check_complete(struct m10bmc_sec *sec, u32 *doorbell_reg) { - const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; + u32 progress, status; - if (m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, doorbell)) + if (m10bmc_sec_progress_status(sec, doorbell_reg, &progress, &status)) return -EIO; - if (!rsu_status_ok(rsu_stat(*doorbell))) + if (!rsu_status_ok(status)) return -EINVAL; - if (rsu_progress_done(rsu_prog(*doorbell))) + if (rsu_progress_done(progress)) return 0; - if (rsu_progress_busy(rsu_prog(*doorbell))) + if (rsu_progress_busy(progress)) return -EAGAIN; return -EINVAL; @@ -592,6 +632,10 @@ static const struct fw_upload_ops m10bmc_ops = { .cleanup = m10bmc_sec_cleanup, }; +static const struct m10bmc_sec_ops m10sec_n3000_ops = { + .rsu_status = m10bmc_sec_n3000_rsu_status, +}; + #define SEC_UPDATE_LEN_MAX 32 static int m10bmc_sec_probe(struct platform_device *pdev) { @@ -607,6 +651,7 @@ static int m10bmc_sec_probe(struct platform_device *pdev) sec->dev = &pdev->dev; sec->m10bmc = dev_get_drvdata(pdev->dev.parent); + sec->ops = (struct m10bmc_sec_ops *)platform_get_device_id(pdev)->driver_data; dev_set_drvdata(&pdev->dev, sec); ret = xa_alloc(&fw_upload_xa, &sec->fw_name_id, sec, @@ -647,9 +692,11 @@ static int m10bmc_sec_remove(struct platform_device *pdev) static const struct platform_device_id intel_m10bmc_sec_ids[] = { { .name = "n3000bmc-sec-update", + .driver_data = (kernel_ulong_t)&m10sec_n3000_ops, }, { .name = "d5005bmc-sec-update", + .driver_data = (kernel_ulong_t)&m10sec_n3000_ops, }, { } }; diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h index 470dc3773c01..1f75b33240ad 100644 --- a/include/linux/mfd/intel-m10-bmc.h +++ b/include/linux/mfd/intel-m10-bmc.h @@ -91,7 +91,6 @@ #define HOST_STATUS_ABORT_RSU 0x2 #define rsu_prog(doorbell) FIELD_GET(DRBL_RSU_PROGRESS, doorbell) -#define rsu_stat(doorbell) FIELD_GET(DRBL_RSU_STATUS, doorbell) /* interval 100ms and timeout 5s */ #define NIOS_HANDSHAKE_INTERVAL_US (100 * 1000) From 869b9eddf0b38a22c27a400e2fa849d2ff2aa7e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 16 Jan 2023 12:08:44 +0200 Subject: [PATCH 10/40] mfd: intel-m10-bmc: Add PMCI driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the mfd driver for the Platform Management Component Interface (PMCI) based interface of Intel MAX10 BMC controller. PMCI is a software-visible interface, connected to card BMC which provided the basic functionality of read/write BMC register. The access to the register is done indirectly via a hardware controller/bridge that handles read/write/clear commands and acknowledgments for the commands. Previously, intel-m10-bmc provided sysfs under /sys/bus/spi/devices/... which is generalized in this change because not all MAX10 BMC appear under SPI anymore. Co-developed-by: Tianfei zhang Signed-off-by: Tianfei zhang Co-developed-by: Russ Weight Signed-off-by: Russ Weight Co-developed-by: Matthew Gerlach Signed-off-by: Matthew Gerlach Reviewed-by: Xu Yilun Signed-off-by: Ilpo Järvinen Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230116100845.6153-11-ilpo.jarvinen@linux.intel.com --- .../ABI/testing/sysfs-driver-intel-m10-bmc | 8 +- drivers/mfd/Kconfig | 12 + drivers/mfd/Makefile | 1 + drivers/mfd/intel-m10-bmc-pmci.c | 219 ++++++++++++++++++ include/linux/mfd/intel-m10-bmc.h | 28 +++ 5 files changed, 264 insertions(+), 4 deletions(-) create mode 100644 drivers/mfd/intel-m10-bmc-pmci.c diff --git a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc index 9773925138af..a8ab58035c95 100644 --- a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc +++ b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc @@ -1,4 +1,4 @@ -What: /sys/bus/spi/devices/.../bmc_version +What: /sys/bus/.../drivers/intel-m10-bmc/.../bmc_version Date: June 2020 KernelVersion: 5.10 Contact: Xu Yilun @@ -6,7 +6,7 @@ Description: Read only. Returns the hardware build version of Intel MAX10 BMC chip. Format: "0x%x". -What: /sys/bus/spi/devices/.../bmcfw_version +What: /sys/bus/.../drivers/intel-m10-bmc/.../bmcfw_version Date: June 2020 KernelVersion: 5.10 Contact: Xu Yilun @@ -14,7 +14,7 @@ Description: Read only. Returns the firmware version of Intel MAX10 BMC chip. Format: "0x%x". -What: /sys/bus/spi/devices/.../mac_address +What: /sys/bus/.../drivers/intel-m10-bmc/.../mac_address Date: January 2021 KernelVersion: 5.12 Contact: Russ Weight @@ -25,7 +25,7 @@ Description: Read only. Returns the first MAC address in a block space. Format: "%02x:%02x:%02x:%02x:%02x:%02x". -What: /sys/bus/spi/devices/.../mac_count +What: /sys/bus/.../drivers/intel-m10-bmc/.../mac_count Date: January 2021 KernelVersion: 5.12 Contact: Russ Weight diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b6ab85831cde..2632ca2162de 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -2243,6 +2243,18 @@ config MFD_INTEL_M10_BMC_SPI additional drivers must be enabled in order to use the functionality of the device. +config MFD_INTEL_M10_BMC_PMCI + tristate "Intel MAX 10 Board Management Controller with PMCI" + depends on FPGA_DFL + select MFD_INTEL_M10_BMC_CORE + select REGMAP + help + Support for the Intel MAX 10 board management controller via PMCI. + + This driver provides common support for accessing the device, + additional drivers must be enabled in order to use the functionality + of the device. + config MFD_RSMU_I2C tristate "Renesas Synchronization Management Unit with I2C" depends on I2C && OF diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index b360b29150b5..81c30d7cf5d4 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -272,6 +272,7 @@ obj-$(CONFIG_MFD_SMPRO) += smpro-core.o obj-$(CONFIG_MFD_INTEL_M10_BMC_CORE) += intel-m10-bmc-core.o obj-$(CONFIG_MFD_INTEL_M10_BMC_SPI) += intel-m10-bmc-spi.o +obj-$(CONFIG_MFD_INTEL_M10_BMC_PMCI) += intel-m10-bmc-pmci.o obj-$(CONFIG_MFD_ATC260X) += atc260x-core.o obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x-i2c.o diff --git a/drivers/mfd/intel-m10-bmc-pmci.c b/drivers/mfd/intel-m10-bmc-pmci.c new file mode 100644 index 000000000000..975019f644b5 --- /dev/null +++ b/drivers/mfd/intel-m10-bmc-pmci.c @@ -0,0 +1,219 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MAX10 BMC Platform Management Component Interface (PMCI) based + * interface. + * + * Copyright (C) 2020-2023 Intel Corporation. + */ + +#include +#include +#include +#include +#include +#include + +struct m10bmc_pmci_device { + void __iomem *base; + struct intel_m10bmc m10bmc; +}; + +/* + * Intel FGPA indirect register access via hardware controller/bridge. + */ +#define INDIRECT_CMD_OFF 0 +#define INDIRECT_CMD_CLR 0 +#define INDIRECT_CMD_RD BIT(0) +#define INDIRECT_CMD_WR BIT(1) +#define INDIRECT_CMD_ACK BIT(2) + +#define INDIRECT_ADDR_OFF 0x4 +#define INDIRECT_RD_OFF 0x8 +#define INDIRECT_WR_OFF 0xc + +#define INDIRECT_INT_US 1 +#define INDIRECT_TIMEOUT_US 10000 + +struct indirect_ctx { + void __iomem *base; + struct device *dev; +}; + +static int indirect_clear_cmd(struct indirect_ctx *ctx) +{ + unsigned int cmd; + int ret; + + writel(INDIRECT_CMD_CLR, ctx->base + INDIRECT_CMD_OFF); + + ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, cmd, + cmd == INDIRECT_CMD_CLR, + INDIRECT_INT_US, INDIRECT_TIMEOUT_US); + if (ret) + dev_err(ctx->dev, "timed out waiting clear cmd (residual cmd=0x%x)\n", cmd); + + return ret; +} + +static int indirect_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct indirect_ctx *ctx = context; + unsigned int cmd, ack, tmpval; + int ret, ret2; + + cmd = readl(ctx->base + INDIRECT_CMD_OFF); + if (cmd != INDIRECT_CMD_CLR) + dev_warn(ctx->dev, "residual cmd 0x%x on read entry\n", cmd); + + writel(reg, ctx->base + INDIRECT_ADDR_OFF); + writel(INDIRECT_CMD_RD, ctx->base + INDIRECT_CMD_OFF); + + ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, ack, + (ack & INDIRECT_CMD_ACK) == INDIRECT_CMD_ACK, + INDIRECT_INT_US, INDIRECT_TIMEOUT_US); + if (ret) + dev_err(ctx->dev, "read timed out on reg 0x%x ack 0x%x\n", reg, ack); + else + tmpval = readl(ctx->base + INDIRECT_RD_OFF); + + ret2 = indirect_clear_cmd(ctx); + + if (ret) + return ret; + if (ret2) + return ret2; + + *val = tmpval; + return 0; +} + +static int indirect_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct indirect_ctx *ctx = context; + unsigned int cmd, ack; + int ret, ret2; + + cmd = readl(ctx->base + INDIRECT_CMD_OFF); + if (cmd != INDIRECT_CMD_CLR) + dev_warn(ctx->dev, "residual cmd 0x%x on write entry\n", cmd); + + writel(val, ctx->base + INDIRECT_WR_OFF); + writel(reg, ctx->base + INDIRECT_ADDR_OFF); + writel(INDIRECT_CMD_WR, ctx->base + INDIRECT_CMD_OFF); + + ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, ack, + (ack & INDIRECT_CMD_ACK) == INDIRECT_CMD_ACK, + INDIRECT_INT_US, INDIRECT_TIMEOUT_US); + if (ret) + dev_err(ctx->dev, "write timed out on reg 0x%x ack 0x%x\n", reg, ack); + + ret2 = indirect_clear_cmd(ctx); + + if (ret) + return ret; + return ret2; +} + +static const struct regmap_range m10bmc_pmci_regmap_range[] = { + regmap_reg_range(M10BMC_N6000_SYS_BASE, M10BMC_N6000_SYS_END), +}; + +static const struct regmap_access_table m10bmc_pmci_access_table = { + .yes_ranges = m10bmc_pmci_regmap_range, + .n_yes_ranges = ARRAY_SIZE(m10bmc_pmci_regmap_range), +}; + +static struct regmap_config m10bmc_pmci_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .wr_table = &m10bmc_pmci_access_table, + .rd_table = &m10bmc_pmci_access_table, + .reg_read = &indirect_reg_read, + .reg_write = &indirect_reg_write, + .max_register = M10BMC_N6000_SYS_END, +}; + +static struct mfd_cell m10bmc_pmci_n6000_bmc_subdevs[] = { + { .name = "n6000bmc-hwmon" }, +}; + +static const struct m10bmc_csr_map m10bmc_n6000_csr_map = { + .base = M10BMC_N6000_SYS_BASE, + .build_version = M10BMC_N6000_BUILD_VER, + .fw_version = NIOS2_N6000_FW_VERSION, + .mac_low = M10BMC_N6000_MAC_LOW, + .mac_high = M10BMC_N6000_MAC_HIGH, + .doorbell = M10BMC_N6000_DOORBELL, + .auth_result = M10BMC_N6000_AUTH_RESULT, + .bmc_prog_addr = M10BMC_N6000_BMC_PROG_ADDR, + .bmc_reh_addr = M10BMC_N6000_BMC_REH_ADDR, + .bmc_magic = M10BMC_N6000_BMC_PROG_MAGIC, + .sr_prog_addr = M10BMC_N6000_SR_PROG_ADDR, + .sr_reh_addr = M10BMC_N6000_SR_REH_ADDR, + .sr_magic = M10BMC_N6000_SR_PROG_MAGIC, + .pr_prog_addr = M10BMC_N6000_PR_PROG_ADDR, + .pr_reh_addr = M10BMC_N6000_PR_REH_ADDR, + .pr_magic = M10BMC_N6000_PR_PROG_MAGIC, + .rsu_update_counter = M10BMC_N6000_STAGING_FLASH_COUNT, +}; + +static const struct intel_m10bmc_platform_info m10bmc_pmci_n6000 = { + .cells = m10bmc_pmci_n6000_bmc_subdevs, + .n_cells = ARRAY_SIZE(m10bmc_pmci_n6000_bmc_subdevs), + .csr_map = &m10bmc_n6000_csr_map, +}; + +static int m10bmc_pmci_probe(struct dfl_device *ddev) +{ + struct device *dev = &ddev->dev; + struct m10bmc_pmci_device *pmci; + struct indirect_ctx *ctx; + + pmci = devm_kzalloc(dev, sizeof(*pmci), GFP_KERNEL); + if (!pmci) + return -ENOMEM; + + pmci->m10bmc.dev = dev; + + pmci->base = devm_ioremap_resource(dev, &ddev->mmio_res); + if (IS_ERR(pmci->base)) + return PTR_ERR(pmci->base); + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->base = pmci->base + M10BMC_N6000_INDIRECT_BASE; + ctx->dev = dev; + indirect_clear_cmd(ctx); + pmci->m10bmc.regmap = devm_regmap_init(dev, NULL, ctx, &m10bmc_pmci_regmap_config); + + if (IS_ERR(pmci->m10bmc.regmap)) + return PTR_ERR(pmci->m10bmc.regmap); + + return m10bmc_dev_init(&pmci->m10bmc, &m10bmc_pmci_n6000); +} + +#define FME_FEATURE_ID_M10BMC_PMCI 0x12 + +static const struct dfl_device_id m10bmc_pmci_ids[] = { + { FME_ID, FME_FEATURE_ID_M10BMC_PMCI }, + { } +}; +MODULE_DEVICE_TABLE(dfl, m10bmc_pmci_ids); + +static struct dfl_driver m10bmc_pmci_driver = { + .drv = { + .name = "intel-m10-bmc", + .dev_groups = m10bmc_dev_groups, + }, + .id_table = m10bmc_pmci_ids, + .probe = m10bmc_pmci_probe, +}; + +module_dfl_driver(m10bmc_pmci_driver); + +MODULE_DESCRIPTION("MAX10 BMC PMCI-based interface"); +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h index 1f75b33240ad..810534b1bd12 100644 --- a/include/linux/mfd/intel-m10-bmc.h +++ b/include/linux/mfd/intel-m10-bmc.h @@ -120,6 +120,34 @@ /* Address of 4KB inverted bit vector containing staging area FLASH count */ #define M10BMC_N3000_STAGING_FLASH_COUNT 0x17ffb000 +#define M10BMC_N6000_INDIRECT_BASE 0x400 + +#define M10BMC_N6000_SYS_BASE 0x0 +#define M10BMC_N6000_SYS_END 0xfff + +#define M10BMC_N6000_DOORBELL 0x1c0 +#define M10BMC_N6000_AUTH_RESULT 0x1c4 + +#define M10BMC_N6000_BUILD_VER 0x0 +#define NIOS2_N6000_FW_VERSION 0x4 +#define M10BMC_N6000_MAC_LOW 0x20 +#define M10BMC_N6000_MAC_HIGH (M10BMC_N6000_MAC_LOW + 4) + +/* Addresses for security related data in FLASH */ +#define M10BMC_N6000_BMC_REH_ADDR 0x7ffc004 +#define M10BMC_N6000_BMC_PROG_ADDR 0x7ffc000 +#define M10BMC_N6000_BMC_PROG_MAGIC 0x5746 + +#define M10BMC_N6000_SR_REH_ADDR 0x7ffd004 +#define M10BMC_N6000_SR_PROG_ADDR 0x7ffd000 +#define M10BMC_N6000_SR_PROG_MAGIC 0x5253 + +#define M10BMC_N6000_PR_REH_ADDR 0x7ffe004 +#define M10BMC_N6000_PR_PROG_ADDR 0x7ffe000 +#define M10BMC_N6000_PR_PROG_MAGIC 0x5250 + +#define M10BMC_N6000_STAGING_FLASH_COUNT 0x7ff5000 + /** * struct m10bmc_csr_map - Intel MAX 10 BMC CSR register map */ From acf63c458b55ecfb2015b33dd6ba3cc8fbc1c5d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 16 Jan 2023 12:08:45 +0200 Subject: [PATCH 11/40] fpga: m10bmc-sec: Add support for N6000 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for PMCI-based flash access path and N6000 sec update support. Access to flash staging area is different for N6000 from that of the SPI interfaced counterparts. Introduce intel_m10bmc_flash_bulk_ops to allow interface specific differentiations for the flash access path for sec update and make m10bmc_sec_read/write() in sec update driver to use the new operations. The .flash_mutex serializes read/read. Flash update (erase+write) must use ->lock/unlock_write() to prevent reads during update (reads would timeout on setting flash MUX as BMC will prevent it). Create a type specific RSU status reg handler for N6000 because the field has moved from doorbell to auth result register. If a failure is detected while altering the flash MUX, it seems safer to try to set it back and doesn't seem harmful. Likely there are enough troubles in that case anyway so setting it back fails too (which is harmless sans the small extra delay) or just confirms that the value wasn't changed. Co-developed-by: Tianfei zhang Signed-off-by: Tianfei zhang Co-developed-by: Russ Weight Signed-off-by: Russ Weight Acked-by: Xu Yilun Signed-off-by: Ilpo Järvinen Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230116100845.6153-12-ilpo.jarvinen@linux.intel.com --- drivers/fpga/intel-m10-bmc-sec-update.c | 51 ++++- drivers/mfd/intel-m10-bmc-pmci.c | 242 +++++++++++++++++++++++- include/linux/mfd/intel-m10-bmc.h | 51 +++++ 3 files changed, 336 insertions(+), 8 deletions(-) diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c index 92145ee7333e..9b4cc75b48c5 100644 --- a/drivers/fpga/intel-m10-bmc-sec-update.c +++ b/drivers/fpga/intel-m10-bmc-sec-update.c @@ -48,6 +48,9 @@ static int m10bmc_sec_write(struct m10bmc_sec *sec, const u8 *buf, u32 offset, u u32 leftover_tmp = 0; int ret; + if (sec->m10bmc->flash_bulk_ops) + return sec->m10bmc->flash_bulk_ops->write(m10bmc, buf, offset, size); + if (WARN_ON_ONCE(stride > sizeof(leftover_tmp))) return -EINVAL; @@ -78,6 +81,9 @@ static int m10bmc_sec_read(struct m10bmc_sec *sec, u8 *buf, u32 addr, u32 size) u32 leftover_tmp; int ret; + if (sec->m10bmc->flash_bulk_ops) + return sec->m10bmc->flash_bulk_ops->read(m10bmc, buf, addr, size); + if (WARN_ON_ONCE(stride > sizeof(leftover_tmp))) return -EINVAL; @@ -277,6 +283,19 @@ static int m10bmc_sec_n3000_rsu_status(struct m10bmc_sec *sec) return FIELD_GET(DRBL_RSU_STATUS, doorbell); } +static int m10bmc_sec_n6000_rsu_status(struct m10bmc_sec *sec) +{ + const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; + u32 auth_result; + int ret; + + ret = m10bmc_sys_read(sec->m10bmc, csr_map->auth_result, &auth_result); + if (ret) + return ret; + + return FIELD_GET(AUTH_RESULT_RSU_STATUS, auth_result); +} + static bool rsu_status_ok(u32 status) { return (status == RSU_STAT_NORMAL || @@ -520,22 +539,33 @@ static enum fw_upload_err m10bmc_sec_prepare(struct fw_upload *fwl, if (!size || size > M10BMC_STAGING_SIZE) return FW_UPLOAD_ERR_INVALID_SIZE; + if (sec->m10bmc->flash_bulk_ops) + if (sec->m10bmc->flash_bulk_ops->lock_write(sec->m10bmc)) + return FW_UPLOAD_ERR_BUSY; + ret = rsu_check_idle(sec); if (ret != FW_UPLOAD_ERR_NONE) - return ret; + goto unlock_flash; ret = rsu_update_init(sec); if (ret != FW_UPLOAD_ERR_NONE) - return ret; + goto unlock_flash; ret = rsu_prog_ready(sec); if (ret != FW_UPLOAD_ERR_NONE) - return ret; + goto unlock_flash; - if (sec->cancel_request) - return rsu_cancel(sec); + if (sec->cancel_request) { + ret = rsu_cancel(sec); + goto unlock_flash; + } return FW_UPLOAD_ERR_NONE; + +unlock_flash: + if (sec->m10bmc->flash_bulk_ops) + sec->m10bmc->flash_bulk_ops->unlock_write(sec->m10bmc); + return ret; } #define WRITE_BLOCK_SIZE 0x4000 /* Default write-block size is 0x4000 bytes */ @@ -622,6 +652,9 @@ static void m10bmc_sec_cleanup(struct fw_upload *fwl) struct m10bmc_sec *sec = fwl->dd_handle; (void)rsu_cancel(sec); + + if (sec->m10bmc->flash_bulk_ops) + sec->m10bmc->flash_bulk_ops->unlock_write(sec->m10bmc); } static const struct fw_upload_ops m10bmc_ops = { @@ -636,6 +669,10 @@ static const struct m10bmc_sec_ops m10sec_n3000_ops = { .rsu_status = m10bmc_sec_n3000_rsu_status, }; +static const struct m10bmc_sec_ops m10sec_n6000_ops = { + .rsu_status = m10bmc_sec_n6000_rsu_status, +}; + #define SEC_UPDATE_LEN_MAX 32 static int m10bmc_sec_probe(struct platform_device *pdev) { @@ -698,6 +735,10 @@ static const struct platform_device_id intel_m10bmc_sec_ids[] = { .name = "d5005bmc-sec-update", .driver_data = (kernel_ulong_t)&m10sec_n3000_ops, }, + { + .name = "n6000bmc-sec-update", + .driver_data = (kernel_ulong_t)&m10sec_n6000_ops, + }, { } }; MODULE_DEVICE_TABLE(platform, intel_m10bmc_sec_ids); diff --git a/drivers/mfd/intel-m10-bmc-pmci.c b/drivers/mfd/intel-m10-bmc-pmci.c index 975019f644b5..8821f1876dd6 100644 --- a/drivers/mfd/intel-m10-bmc-pmci.c +++ b/drivers/mfd/intel-m10-bmc-pmci.c @@ -6,16 +6,20 @@ * Copyright (C) 2020-2023 Intel Corporation. */ +#include #include #include #include #include +#include #include #include struct m10bmc_pmci_device { void __iomem *base; struct intel_m10bmc m10bmc; + struct mutex flash_mutex; /* protects flash_busy and serializes flash read/read */ + bool flash_busy; }; /* @@ -114,6 +118,215 @@ static int indirect_reg_write(void *context, unsigned int reg, unsigned int val) return ret2; } +static void pmci_write_fifo(void __iomem *base, const u32 *buf, size_t count) +{ + while (count--) + writel(*buf++, base); +} + +static void pmci_read_fifo(void __iomem *base, u32 *buf, size_t count) +{ + while (count--) + *buf++ = readl(base); +} + +static u32 pmci_get_write_space(struct m10bmc_pmci_device *pmci) +{ + u32 val; + int ret; + + ret = read_poll_timeout(readl, val, + FIELD_GET(M10BMC_N6000_FLASH_FIFO_SPACE, val) == + M10BMC_N6000_FIFO_MAX_WORDS, + M10BMC_FLASH_INT_US, M10BMC_FLASH_TIMEOUT_US, + false, pmci->base + M10BMC_N6000_FLASH_CTRL); + if (ret == -ETIMEDOUT) + return 0; + + return FIELD_GET(M10BMC_N6000_FLASH_FIFO_SPACE, val) * M10BMC_N6000_FIFO_WORD_SIZE; +} + +static int pmci_flash_bulk_write(struct intel_m10bmc *m10bmc, const u8 *buf, u32 size) +{ + struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc); + u32 blk_size, offset = 0, write_count; + + while (size) { + blk_size = min(pmci_get_write_space(pmci), size); + if (blk_size == 0) { + dev_err(m10bmc->dev, "get FIFO available size fail\n"); + return -EIO; + } + + if (size < M10BMC_N6000_FIFO_WORD_SIZE) + break; + + write_count = blk_size / M10BMC_N6000_FIFO_WORD_SIZE; + pmci_write_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO, + (u32 *)(buf + offset), write_count); + + size -= blk_size; + offset += blk_size; + } + + /* Handle remainder (less than M10BMC_N6000_FIFO_WORD_SIZE bytes) */ + if (size) { + u32 tmp = 0; + + memcpy(&tmp, buf + offset, size); + pmci_write_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO, &tmp, 1); + } + + return 0; +} + +static int pmci_flash_bulk_read(struct intel_m10bmc *m10bmc, u8 *buf, u32 addr, u32 size) +{ + struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc); + u32 blk_size, offset = 0, val, full_read_count, read_count; + int ret; + + while (size) { + blk_size = min_t(u32, size, M10BMC_N6000_READ_BLOCK_SIZE); + full_read_count = blk_size / M10BMC_N6000_FIFO_WORD_SIZE; + + read_count = full_read_count; + if (full_read_count * M10BMC_N6000_FIFO_WORD_SIZE < blk_size) + read_count++; + + writel(addr + offset, pmci->base + M10BMC_N6000_FLASH_ADDR); + writel(FIELD_PREP(M10BMC_N6000_FLASH_READ_COUNT, read_count) | + M10BMC_N6000_FLASH_RD_MODE, + pmci->base + M10BMC_N6000_FLASH_CTRL); + + ret = readl_poll_timeout((pmci->base + M10BMC_N6000_FLASH_CTRL), val, + !(val & M10BMC_N6000_FLASH_BUSY), + M10BMC_FLASH_INT_US, M10BMC_FLASH_TIMEOUT_US); + if (ret) { + dev_err(m10bmc->dev, "read timed out on reading flash 0x%xn", val); + return ret; + } + + pmci_read_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO, + (u32 *)(buf + offset), full_read_count); + + size -= blk_size; + offset += blk_size; + + if (full_read_count < read_count) + break; + + writel(0, pmci->base + M10BMC_N6000_FLASH_CTRL); + } + + /* Handle remainder (less than M10BMC_N6000_FIFO_WORD_SIZE bytes) */ + if (size) { + u32 tmp; + + pmci_read_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO, &tmp, 1); + memcpy(buf + offset, &tmp, size); + + writel(0, pmci->base + M10BMC_N6000_FLASH_CTRL); + } + + return 0; +} + +static int m10bmc_pmci_set_flash_host_mux(struct intel_m10bmc *m10bmc, bool request) +{ + u32 ctrl; + int ret; + + ret = regmap_update_bits(m10bmc->regmap, M10BMC_N6000_FLASH_MUX_CTRL, + M10BMC_N6000_FLASH_HOST_REQUEST, + FIELD_PREP(M10BMC_N6000_FLASH_HOST_REQUEST, request)); + if (ret) + return ret; + + return regmap_read_poll_timeout(m10bmc->regmap, + M10BMC_N6000_FLASH_MUX_CTRL, ctrl, + request ? + (get_flash_mux(ctrl) == M10BMC_N6000_FLASH_MUX_HOST) : + (get_flash_mux(ctrl) != M10BMC_N6000_FLASH_MUX_HOST), + M10BMC_FLASH_INT_US, M10BMC_FLASH_TIMEOUT_US); +} + +static int m10bmc_pmci_flash_read(struct intel_m10bmc *m10bmc, u8 *buf, u32 addr, u32 size) +{ + struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc); + int ret, ret2; + + mutex_lock(&pmci->flash_mutex); + if (pmci->flash_busy) { + ret = -EBUSY; + goto unlock; + } + + ret = m10bmc_pmci_set_flash_host_mux(m10bmc, true); + if (ret) + goto mux_fail; + + ret = pmci_flash_bulk_read(m10bmc, buf, addr, size); + +mux_fail: + ret2 = m10bmc_pmci_set_flash_host_mux(m10bmc, false); + +unlock: + mutex_unlock(&pmci->flash_mutex); + if (ret) + return ret; + return ret2; +} + +static int m10bmc_pmci_flash_write(struct intel_m10bmc *m10bmc, const u8 *buf, u32 offset, u32 size) +{ + struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc); + int ret; + + mutex_lock(&pmci->flash_mutex); + WARN_ON_ONCE(!pmci->flash_busy); + /* On write, firmware manages flash MUX */ + ret = pmci_flash_bulk_write(m10bmc, buf + offset, size); + mutex_unlock(&pmci->flash_mutex); + + return ret; +} + +static int m10bmc_pmci_flash_lock(struct intel_m10bmc *m10bmc) +{ + struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc); + int ret = 0; + + mutex_lock(&pmci->flash_mutex); + if (pmci->flash_busy) { + ret = -EBUSY; + goto unlock; + } + + pmci->flash_busy = true; + +unlock: + mutex_unlock(&pmci->flash_mutex); + return ret; +} + +static void m10bmc_pmci_flash_unlock(struct intel_m10bmc *m10bmc) +{ + struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc); + + mutex_lock(&pmci->flash_mutex); + WARN_ON_ONCE(!pmci->flash_busy); + pmci->flash_busy = false; + mutex_unlock(&pmci->flash_mutex); +} + +static const struct intel_m10bmc_flash_bulk_ops m10bmc_pmci_flash_bulk_ops = { + .read = m10bmc_pmci_flash_read, + .write = m10bmc_pmci_flash_write, + .lock_write = m10bmc_pmci_flash_lock, + .unlock_write = m10bmc_pmci_flash_unlock, +}; + static const struct regmap_range m10bmc_pmci_regmap_range[] = { regmap_reg_range(M10BMC_N6000_SYS_BASE, M10BMC_N6000_SYS_END), }; @@ -136,6 +349,7 @@ static struct regmap_config m10bmc_pmci_regmap_config = { static struct mfd_cell m10bmc_pmci_n6000_bmc_subdevs[] = { { .name = "n6000bmc-hwmon" }, + { .name = "n6000bmc-sec-update" }, }; static const struct m10bmc_csr_map m10bmc_n6000_csr_map = { @@ -169,11 +383,13 @@ static int m10bmc_pmci_probe(struct dfl_device *ddev) struct device *dev = &ddev->dev; struct m10bmc_pmci_device *pmci; struct indirect_ctx *ctx; + int ret; pmci = devm_kzalloc(dev, sizeof(*pmci), GFP_KERNEL); if (!pmci) return -ENOMEM; + pmci->m10bmc.flash_bulk_ops = &m10bmc_pmci_flash_bulk_ops; pmci->m10bmc.dev = dev; pmci->base = devm_ioremap_resource(dev, &ddev->mmio_res); @@ -184,15 +400,34 @@ static int m10bmc_pmci_probe(struct dfl_device *ddev) if (!ctx) return -ENOMEM; + mutex_init(&pmci->flash_mutex); + ctx->base = pmci->base + M10BMC_N6000_INDIRECT_BASE; ctx->dev = dev; indirect_clear_cmd(ctx); pmci->m10bmc.regmap = devm_regmap_init(dev, NULL, ctx, &m10bmc_pmci_regmap_config); - if (IS_ERR(pmci->m10bmc.regmap)) - return PTR_ERR(pmci->m10bmc.regmap); + if (IS_ERR(pmci->m10bmc.regmap)) { + ret = PTR_ERR(pmci->m10bmc.regmap); + goto destroy_mutex; + } - return m10bmc_dev_init(&pmci->m10bmc, &m10bmc_pmci_n6000); + ret = m10bmc_dev_init(&pmci->m10bmc, &m10bmc_pmci_n6000); + if (ret) + goto destroy_mutex; + return 0; + +destroy_mutex: + mutex_destroy(&pmci->flash_mutex); + return ret; +} + +static void m10bmc_pmci_remove(struct dfl_device *ddev) +{ + struct intel_m10bmc *m10bmc = dev_get_drvdata(&ddev->dev); + struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc); + + mutex_destroy(&pmci->flash_mutex); } #define FME_FEATURE_ID_M10BMC_PMCI 0x12 @@ -210,6 +445,7 @@ static struct dfl_driver m10bmc_pmci_driver = { }, .id_table = m10bmc_pmci_ids, .probe = m10bmc_pmci_probe, + .remove = m10bmc_pmci_remove, }; module_dfl_driver(m10bmc_pmci_driver); diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h index 810534b1bd12..1812ebfa11a8 100644 --- a/include/linux/mfd/intel-m10-bmc.h +++ b/include/linux/mfd/intel-m10-bmc.h @@ -127,6 +127,7 @@ #define M10BMC_N6000_DOORBELL 0x1c0 #define M10BMC_N6000_AUTH_RESULT 0x1c4 +#define AUTH_RESULT_RSU_STATUS GENMASK(23, 16) #define M10BMC_N6000_BUILD_VER 0x0 #define NIOS2_N6000_FW_VERSION 0x4 @@ -148,6 +149,35 @@ #define M10BMC_N6000_STAGING_FLASH_COUNT 0x7ff5000 +#define M10BMC_N6000_FLASH_MUX_CTRL 0x1d0 +#define M10BMC_N6000_FLASH_MUX_SELECTION GENMASK(2, 0) +#define M10BMC_N6000_FLASH_MUX_IDLE 0 +#define M10BMC_N6000_FLASH_MUX_NIOS 1 +#define M10BMC_N6000_FLASH_MUX_HOST 2 +#define M10BMC_N6000_FLASH_MUX_PFL 4 +#define get_flash_mux(mux) FIELD_GET(M10BMC_N6000_FLASH_MUX_SELECTION, mux) + +#define M10BMC_N6000_FLASH_NIOS_REQUEST BIT(4) +#define M10BMC_N6000_FLASH_HOST_REQUEST BIT(5) + +#define M10BMC_N6000_FLASH_CTRL 0x40 +#define M10BMC_N6000_FLASH_WR_MODE BIT(0) +#define M10BMC_N6000_FLASH_RD_MODE BIT(1) +#define M10BMC_N6000_FLASH_BUSY BIT(2) +#define M10BMC_N6000_FLASH_FIFO_SPACE GENMASK(13, 4) +#define M10BMC_N6000_FLASH_READ_COUNT GENMASK(25, 16) + +#define M10BMC_N6000_FLASH_ADDR 0x44 +#define M10BMC_N6000_FLASH_FIFO 0x800 +#define M10BMC_N6000_READ_BLOCK_SIZE 0x800 +#define M10BMC_N6000_FIFO_MAX_BYTES 0x800 +#define M10BMC_N6000_FIFO_WORD_SIZE 4 +#define M10BMC_N6000_FIFO_MAX_WORDS (M10BMC_N6000_FIFO_MAX_BYTES / \ + M10BMC_N6000_FIFO_WORD_SIZE) + +#define M10BMC_FLASH_INT_US 1 +#define M10BMC_FLASH_TIMEOUT_US 10000 + /** * struct m10bmc_csr_map - Intel MAX 10 BMC CSR register map */ @@ -183,16 +213,37 @@ struct intel_m10bmc_platform_info { const struct m10bmc_csr_map *csr_map; }; +struct intel_m10bmc; + +/** + * struct intel_m10bmc_flash_bulk_ops - device specific operations for flash R/W + * @read: read a block of data from flash + * @write: write a block of data to flash + * @lock_write: locks flash access for erase+write + * @unlock_write: unlock flash access + * + * Write must be protected with @lock_write and @unlock_write. While the flash + * is locked, @read returns -EBUSY. + */ +struct intel_m10bmc_flash_bulk_ops { + int (*read)(struct intel_m10bmc *m10bmc, u8 *buf, u32 addr, u32 size); + int (*write)(struct intel_m10bmc *m10bmc, const u8 *buf, u32 offset, u32 size); + int (*lock_write)(struct intel_m10bmc *m10bmc); + void (*unlock_write)(struct intel_m10bmc *m10bmc); +}; + /** * struct intel_m10bmc - Intel MAX 10 BMC parent driver data structure * @dev: this device * @regmap: the regmap used to access registers by m10bmc itself * @info: the platform information for MAX10 BMC + * @flash_bulk_ops: optional device specific operations for flash R/W */ struct intel_m10bmc { struct device *dev; struct regmap *regmap; const struct intel_m10bmc_platform_info *info; + const struct intel_m10bmc_flash_bulk_ops *flash_bulk_ops; }; /* From 8d9ef69487e114f80e20ffbec14ca8684953fef0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 26 Jan 2023 16:38:21 +0100 Subject: [PATCH 12/40] mfd: intel_soc_pmic_chtwc: Add Lenovo Yoga Tab 3 X90F to intel_cht_wc_models The drivers for various CHT Whiskey Cove PMIC child-devices need to know the model, since they have model specific behavior. The DMI match table for this is shared between the child-device-drivers inside the MFD driver. Add the Lenovo Yoga Tab 3 X90F, which is a previously unknown tablet model with a CHT Whiskey Cove PMIC, to the intel_cht_wc_models enum and to the DMI match table. Signed-off-by: Hans de Goede Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230126153823.22146-2-hdegoede@redhat.com --- drivers/mfd/intel_soc_pmic_chtwc.c | 8 ++++++++ include/linux/mfd/intel_soc_pmic.h | 1 + 2 files changed, 9 insertions(+) diff --git a/drivers/mfd/intel_soc_pmic_chtwc.c b/drivers/mfd/intel_soc_pmic_chtwc.c index 9216f0d34206..d53dae255490 100644 --- a/drivers/mfd/intel_soc_pmic_chtwc.c +++ b/drivers/mfd/intel_soc_pmic_chtwc.c @@ -165,6 +165,14 @@ static const struct dmi_system_id cht_wc_model_dmi_ids[] = { /* Non exact match to match all versions */ DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9"), }, + }, { + /* Lenovo Yoga Tab 3 Pro YT3-X90F */ + .driver_data = (void *)(long)INTEL_CHT_WC_LENOVO_YT3_X90, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"), + }, }, { } }; diff --git a/include/linux/mfd/intel_soc_pmic.h b/include/linux/mfd/intel_soc_pmic.h index 945bde1fe55c..9ba2c1a8d836 100644 --- a/include/linux/mfd/intel_soc_pmic.h +++ b/include/linux/mfd/intel_soc_pmic.h @@ -18,6 +18,7 @@ enum intel_cht_wc_models { INTEL_CHT_WC_GPD_WIN_POCKET, INTEL_CHT_WC_XIAOMI_MIPAD2, INTEL_CHT_WC_LENOVO_YOGABOOK1, + INTEL_CHT_WC_LENOVO_YT3_X90, }; /** From 0e61637f0fb5578198c8d95c3fb9b893390bc1e7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 26 Jan 2023 16:38:22 +0100 Subject: [PATCH 13/40] i2c: cht-wc: Add charger-chip info for the Lenovo Yoga Tab 3 YT3-X90F On x86 devices with a CHT Whiskey Cove PMIC the driver for the I2C bus coming from the PMIC is responsible for instantiating the i2c_client for the charger chip. Add the necessary i2c_board_info for this. Signed-off-by: Hans de Goede Acked-by: Wolfram Sang Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230126153823.22146-3-hdegoede@redhat.com --- drivers/i2c/busses/i2c-cht-wc.c | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/drivers/i2c/busses/i2c-cht-wc.c b/drivers/i2c/busses/i2c-cht-wc.c index 190abdc46dd3..2b2c3d090089 100644 --- a/drivers/i2c/busses/i2c-cht-wc.c +++ b/drivers/i2c/busses/i2c-cht-wc.c @@ -380,6 +380,49 @@ static struct i2c_board_info lenovo_yogabook1_board_info = { .platform_data = &bq2589x_pdata, }; +/********** Lenovo Yogabook YT3-X90F charger settings **********/ +static const char * const lenovo_yt3_bq25892_1_suppliers[] = { "cht_wcove_pwrsrc" }; + +/* + * bq25892 charger settings for the round li-ion cells in the hinge, + * this is the main / biggest battery. + */ +static const struct property_entry lenovo_yt3_bq25892_1_props[] = { + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", lenovo_yt3_bq25892_1_suppliers), + PROPERTY_ENTRY_STRING("linux,secondary-charger-name", "bq25890-charger-0"), + PROPERTY_ENTRY_U32("linux,iinlim-percentage", 60), + PROPERTY_ENTRY_U32("linux,pump-express-vbus-max", 12000000), + PROPERTY_ENTRY_BOOL("linux,skip-reset"), + /* + * The firmware sets everything to the defaults, leading to a low(ish) + * charge-current and battery-voltage of 2048mA resp 4.2V. Use the + * Android values instead of "linux,read-back-settings" to fix this. + */ + PROPERTY_ENTRY_U32("ti,charge-current", 3072000), + PROPERTY_ENTRY_U32("ti,battery-regulation-voltage", 4352000), + PROPERTY_ENTRY_U32("ti,termination-current", 128000), + PROPERTY_ENTRY_U32("ti,precharge-current", 128000), + PROPERTY_ENTRY_U32("ti,minimum-sys-voltage", 3700000), + PROPERTY_ENTRY_BOOL("ti,use-ilim-pin"), + /* Set 5V boost current-limit to 1.2A (MAX/POR values are 2.45A/1.4A) */ + PROPERTY_ENTRY_U32("ti,boost-voltage", 4998000), + PROPERTY_ENTRY_U32("ti,boost-max-current", 1200000), + { } +}; + +static const struct software_node lenovo_yt3_bq25892_1_node = { + .properties = lenovo_yt3_bq25892_1_props, +}; + +/* bq25892 charger for the round li-ion cells in the hinge */ +static struct i2c_board_info lenovo_yoga_tab3_board_info = { + .type = "bq25892", + .addr = 0x6b, + .dev_name = "bq25892_1", + .swnode = &lenovo_yt3_bq25892_1_node, + .platform_data = &bq2589x_pdata, +}; + static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev) { struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); @@ -459,6 +502,9 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev) case INTEL_CHT_WC_LENOVO_YOGABOOK1: board_info = &lenovo_yogabook1_board_info; break; + case INTEL_CHT_WC_LENOVO_YT3_X90: + board_info = &lenovo_yoga_tab3_board_info; + break; default: dev_warn(&pdev->dev, "Unknown model, not instantiating charger device\n"); break; From 783422d00d7d8f7725dc781fcd3cfcaae13595e5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 26 Jan 2023 16:38:23 +0100 Subject: [PATCH 14/40] extcon: intel-cht-wc: Add support for Lenovo Yoga Tab 3 Pro YT3-X90F The Lenovo Yoga Tab 3 Pro YT3-X90F needs the same handling as the Lenovo Yogabook models. That is it needs the extcon code to: 1. Control the Vbus regulator and USB-role-switch for the micro-USB port's host/device mode switching. 2. Register a power_supply device so that the charger-chip driver can see what sort of charger (SDP/CDP/DCP) is connected. Signed-off-by: Hans de Goede Acked-by: Chanwoo Choi Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230126153823.22146-4-hdegoede@redhat.com --- drivers/extcon/extcon-intel-cht-wc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c index 89a6449e3f4a..2c55f06ba699 100644 --- a/drivers/extcon/extcon-intel-cht-wc.c +++ b/drivers/extcon/extcon-intel-cht-wc.c @@ -537,6 +537,7 @@ static int cht_wc_extcon_probe(struct platform_device *pdev) cht_wc_extcon_set_5v_boost(ext, false); break; case INTEL_CHT_WC_LENOVO_YOGABOOK1: + case INTEL_CHT_WC_LENOVO_YT3_X90: /* Do this first, as it may very well return -EPROBE_DEFER. */ ret = cht_wc_extcon_get_role_sw_and_regulator(ext); if (ret) From 5d69b181cd0db10dc8327d28ce837b3623cd531a Mon Sep 17 00:00:00 2001 From: Tom Fitzhenry Date: Mon, 2 Jan 2023 22:11:47 +1100 Subject: [PATCH 15/40] mfd: rk808: Re-add rk808-clkout to RK818 Fixes RK818 (e.g. on Pinephone Pro) to register its clock, without which dependent devices (e.g. wifi/BT, via sdio-wifi-pwrseq) fail to probe. This line was removed in commit 3633daacea2e ("mfd: rk808: Permit having multiple PMIC instances"), but only from RK818. Fixes: 3633daacea2e ("mfd: rk808: Permit having multiple PMIC instances") Signed-off-by: Tom Fitzhenry Reviewed-by: Javier Martinez Canillas Acked-by: Neil Armstrong Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230102111147.2580861-1-tom@tom-fitzhenry.me.uk --- drivers/mfd/rk808.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index f44fc3f080a8..0f22ef61e817 100644 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -189,6 +189,7 @@ static const struct mfd_cell rk817s[] = { }; static const struct mfd_cell rk818s[] = { + { .name = "rk808-clkout", .id = PLATFORM_DEVID_NONE, }, { .name = "rk808-regulator", .id = PLATFORM_DEVID_NONE, }, { .name = "rk808-rtc", From 725a2acd851dbef94a3e68c1a8a1de2862742ecd Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 18 Nov 2022 09:24:38 +0100 Subject: [PATCH 16/40] dt-bindings: mfd: qcom,spmi-pmic: Document PMICs bundled with SM8550 Document compatible for the pm8550, pm8550b, pm8550ve, pm8550vs, pmk8550. pm8010 & pmr735d SPMI PMICs Signed-off-by: Neil Armstrong Reviewed-by: Krzysztof Kozlowski Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20221114-narmstrong-sm8550-upstream-spmi-v2-1-b839bf2d558a@linaro.org --- Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml index 37d16e16f444..adf88245c409 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml @@ -44,6 +44,7 @@ properties: - qcom,pm8004 - qcom,pm8005 - qcom,pm8009 + - qcom,pm8010 - qcom,pm8019 - qcom,pm8028 - qcom,pm8110 @@ -55,6 +56,10 @@ properties: - qcom,pm8350 - qcom,pm8350b - qcom,pm8350c + - qcom,pm8550 + - qcom,pm8550b + - qcom,pm8550ve + - qcom,pm8550vs - qcom,pm8841 - qcom,pm8909 - qcom,pm8916 @@ -71,10 +76,12 @@ properties: - qcom,pmi8998 - qcom,pmk8002 - qcom,pmk8350 + - qcom,pmk8550 - qcom,pmm8155au - qcom,pmp8074 - qcom,pmr735a - qcom,pmr735b + - qcom,pmr735d - qcom,pms405 - qcom,pmx55 - qcom,pmx65 From 8781ba7f45695af3ab8e8d1b55a31f527c9201a3 Mon Sep 17 00:00:00 2001 From: Aren Moynihan Date: Thu, 8 Dec 2022 17:02:26 -0500 Subject: [PATCH 17/40] mfd: axp20x: Fix order of pek rise and fall events The power button can get "stuck" if the rising edge and falling edge irq are read in the same pass. This can often be triggered when resuming from suspend if the power button is released before the kernel handles the interrupt. Swapping the order of the rise and fall events makes sure that the press event is handled first, which prevents this situation. Signed-off-by: Aren Moynihan Reviewed-by: Samuel Holland Tested-by: Samuel Holland Acked-by: Chen-Yu Tsai Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20221208220225.635414-1-aren@peacevolution.org --- include/linux/mfd/axp20x.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h index 9ab0e2fca7ea..2058194807bd 100644 --- a/include/linux/mfd/axp20x.h +++ b/include/linux/mfd/axp20x.h @@ -432,8 +432,9 @@ enum { AXP152_IRQ_PEK_SHORT, AXP152_IRQ_PEK_LONG, AXP152_IRQ_TIMER, - AXP152_IRQ_PEK_RIS_EDGE, + /* out of bit order to make sure the press event is handled first */ AXP152_IRQ_PEK_FAL_EDGE, + AXP152_IRQ_PEK_RIS_EDGE, AXP152_IRQ_GPIO3_INPUT, AXP152_IRQ_GPIO2_INPUT, AXP152_IRQ_GPIO1_INPUT, @@ -472,8 +473,9 @@ enum { AXP20X_IRQ_LOW_PWR_LVL1, AXP20X_IRQ_LOW_PWR_LVL2, AXP20X_IRQ_TIMER, - AXP20X_IRQ_PEK_RIS_EDGE, + /* out of bit order to make sure the press event is handled first */ AXP20X_IRQ_PEK_FAL_EDGE, + AXP20X_IRQ_PEK_RIS_EDGE, AXP20X_IRQ_GPIO3_INPUT, AXP20X_IRQ_GPIO2_INPUT, AXP20X_IRQ_GPIO1_INPUT, @@ -502,8 +504,9 @@ enum axp22x_irqs { AXP22X_IRQ_LOW_PWR_LVL1, AXP22X_IRQ_LOW_PWR_LVL2, AXP22X_IRQ_TIMER, - AXP22X_IRQ_PEK_RIS_EDGE, + /* out of bit order to make sure the press event is handled first */ AXP22X_IRQ_PEK_FAL_EDGE, + AXP22X_IRQ_PEK_RIS_EDGE, AXP22X_IRQ_GPIO1_INPUT, AXP22X_IRQ_GPIO0_INPUT, }; @@ -571,8 +574,9 @@ enum axp803_irqs { AXP803_IRQ_LOW_PWR_LVL1, AXP803_IRQ_LOW_PWR_LVL2, AXP803_IRQ_TIMER, - AXP803_IRQ_PEK_RIS_EDGE, + /* out of bit order to make sure the press event is handled first */ AXP803_IRQ_PEK_FAL_EDGE, + AXP803_IRQ_PEK_RIS_EDGE, AXP803_IRQ_PEK_SHORT, AXP803_IRQ_PEK_LONG, AXP803_IRQ_PEK_OVER_OFF, @@ -623,8 +627,9 @@ enum axp809_irqs { AXP809_IRQ_LOW_PWR_LVL1, AXP809_IRQ_LOW_PWR_LVL2, AXP809_IRQ_TIMER, - AXP809_IRQ_PEK_RIS_EDGE, + /* out of bit order to make sure the press event is handled first */ AXP809_IRQ_PEK_FAL_EDGE, + AXP809_IRQ_PEK_RIS_EDGE, AXP809_IRQ_PEK_SHORT, AXP809_IRQ_PEK_LONG, AXP809_IRQ_PEK_OVER_OFF, From 5ec32a3e4053c1a726b45381d56aa9e39eaf3911 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 30 Nov 2022 17:25:41 -0800 Subject: [PATCH 18/40] mfd: cs5535: Don't build on UML MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cs5535-mfd driver uses CPU-specific data that is not available for ARCH=um builds, so don't allow it to be built for UML. Prevents these build errors: In file included from ../arch/x86/include/asm/olpc.h:7, from ../drivers/mfd/cs5535-mfd.c:17: ../arch/x86/include/asm/geode.h: In function ‘is_geode_gx’: ../arch/x86/include/asm/geode.h:16:31: error: ‘struct cpuinfo_um’ has no member named ‘x86_vendor’ 16 | return ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC) && ../arch/x86/include/asm/geode.h:16:46: error: ‘X86_VENDOR_NSC’ undeclared (first use in this function); did you mean ‘X86_VENDOR_ANY’? 16 | return ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC) && ../arch/x86/include/asm/geode.h:17:31: error: ‘struct cpuinfo_um’ has no member named ‘x86’ 17 | (boot_cpu_data.x86 == 5) && ../arch/x86/include/asm/geode.h:18:31: error: ‘struct cpuinfo_um’ has no member named ‘x86_model’ 18 | (boot_cpu_data.x86_model == 5)); ../arch/x86/include/asm/geode.h: In function ‘is_geode_lx’: ../arch/x86/include/asm/geode.h:23:31: error: ‘struct cpuinfo_um’ has no member named ‘x86_vendor’ 23 | return ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && ../arch/x86/include/asm/geode.h:23:46: error: ‘X86_VENDOR_AMD’ undeclared (first use in this function); did you mean ‘X86_VENDOR_ANY’? 23 | return ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && ../arch/x86/include/asm/geode.h:24:31: error: ‘struct cpuinfo_um’ has no member named ‘x86’ 24 | (boot_cpu_data.x86 == 5) && ../arch/x86/include/asm/geode.h:25:31: error: ‘struct cpuinfo_um’ has no member named ‘x86_model’ 25 | (boot_cpu_data.x86_model == 10)); Fixes: 68f5d3f3b654 ("um: add PCI over virtio emulation driver") Signed-off-by: Randy Dunlap Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20221201012541.11809-1-rdunlap@infradead.org --- drivers/mfd/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 2632ca2162de..d90b4258fc44 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -15,6 +15,7 @@ config MFD_CS5535 tristate "AMD CS5535 and CS5536 southbridge core functions" select MFD_CORE depends on PCI && (X86_32 || (X86 && COMPILE_TEST)) + depends on !UML help This is the core driver for CS5535/CS5536 MFD functions. This is necessary for using the board's GPIO and MFGPT functionality. From 8cc5e62bae28d02f706a6abc8fd804609579964c Mon Sep 17 00:00:00 2001 From: ye xingchen Date: Fri, 2 Dec 2022 15:28:36 +0800 Subject: [PATCH 19/40] mfd: Use sysfs_emit() to instead of scnprintf() Follow the advice of the Documentation/filesystems/sysfs.rst and show() should only use sysfs_emit() or sysfs_emit_at() when formatting the value to be returned to user space. Signed-off-by: ye xingchen Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/202212021528368292334@zte.com.cn --- drivers/mfd/kempld-core.c | 7 +++---- drivers/mfd/lm3533-core.c | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c index bb26241c73bd..33c6cfe9fe42 100644 --- a/drivers/mfd/kempld-core.c +++ b/drivers/mfd/kempld-core.c @@ -349,7 +349,7 @@ static ssize_t pld_version_show(struct device *dev, { struct kempld_device_data *pld = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%s\n", pld->info.version); + return sysfs_emit(buf, "%s\n", pld->info.version); } static ssize_t pld_specification_show(struct device *dev, @@ -357,8 +357,7 @@ static ssize_t pld_specification_show(struct device *dev, { struct kempld_device_data *pld = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%d.%d\n", pld->info.spec_major, - pld->info.spec_minor); + return sysfs_emit(buf, "%d.%d\n", pld->info.spec_major, pld->info.spec_minor); } static ssize_t pld_type_show(struct device *dev, @@ -366,7 +365,7 @@ static ssize_t pld_type_show(struct device *dev, { struct kempld_device_data *pld = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%s\n", kempld_get_type_string(pld)); + return sysfs_emit(buf, "%s\n", kempld_get_type_string(pld)); } static DEVICE_ATTR_RO(pld_version); diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c index 74a553329416..946f94f3a3c3 100644 --- a/drivers/mfd/lm3533-core.c +++ b/drivers/mfd/lm3533-core.c @@ -286,7 +286,7 @@ static ssize_t show_output(struct device *dev, val = (val & mask) >> shift; - return scnprintf(buf, PAGE_SIZE, "%u\n", val); + return sysfs_emit(buf, "%u\n", val); } static ssize_t store_output(struct device *dev, From 0c8884fe34bb3e2d739c883000691bb665c01843 Mon Sep 17 00:00:00 2001 From: Bhanu Prakash Maiya Date: Wed, 7 Dec 2022 10:40:12 -0700 Subject: [PATCH 20/40] dt-bindings: mfd: cros-ec: Add compatible string for UART support Add a compatible string to support the UART implementation of the cros ec interface. The driver does not support the reg and interrupt properties, so exempt them from being required for UART compatible nodes. Signed-off-by: Bhanu Prakash Maiya Co-developed-by: Mark Hasemeyer Signed-off-by: Mark Hasemeyer Acked-by: Krzysztof Kozlowski Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20221207104005.v10.2.I9e018ecb8bdf341648cb64417085978ff0d22a46@changeid --- .../bindings/mfd/google,cros-ec.yaml | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml index 3d5efa5578d1..cdf1d719efe9 100644 --- a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml +++ b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml @@ -33,6 +33,9 @@ properties: - description: For implementations of the EC connected through RPMSG. const: google,cros-ec-rpmsg + - description: + For implementations of the EC connected through UART. + const: google,cros-ec-uart controller-data: true @@ -187,6 +190,15 @@ allOf: properties: mediatek,rpmsg-name: false + - if: + properties: + compatible: + not: + contains: + enum: + - google,cros-ec-rpmsg + - google,cros-ec-uart + then: required: - reg - interrupts @@ -299,4 +311,12 @@ examples: vdd-supply = <&pp3300_fp_mcu>; }; }; + + # Example for UART + - | + serial { + cros-ec { + compatible = "google,cros-ec-uart"; + }; + }; ... From 3a8678dfa857b671ff56de2573cb236fc6f0f0d2 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 6 Dec 2022 10:50:38 +0000 Subject: [PATCH 21/40] MAINTAINERS: Move MFD from a Supported to Maintaied state No one is funding MFD maintenance. S: *Status*, one of the following: Supported: Someone is actually paid to look after this. Maintained: Someone actually looks after it. Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20221206105038.124613-1-lee@kernel.org --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 261c1dc793bc..58da9de83b63 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14280,7 +14280,7 @@ F: drivers/media/i2c/mt9v111.c MULTIFUNCTION DEVICES (MFD) M: Lee Jones -S: Supported +S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git F: Documentation/devicetree/bindings/mfd/ F: drivers/mfd/ From 8b450dcff23aa254844492831a8e2b508a9d522d Mon Sep 17 00:00:00 2001 From: Qiheng Lin Date: Thu, 8 Dec 2022 14:15:55 +0800 Subject: [PATCH 22/40] mfd: pcf50633-adc: Fix potential memleak in pcf50633_adc_async_read() `req` is allocated in pcf50633_adc_async_read(), but adc_enqueue_request() could fail to insert the `req` into queue. We need to check the return value and free it in the case of failure. Fixes: 08c3e06a5eb2 ("mfd: PCF50633 adc driver") Signed-off-by: Qiheng Lin Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20221208061555.8776-1-linqiheng@huawei.com --- drivers/mfd/pcf50633-adc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c index 5cd653e61512..191b1bc6141c 100644 --- a/drivers/mfd/pcf50633-adc.c +++ b/drivers/mfd/pcf50633-adc.c @@ -136,6 +136,7 @@ int pcf50633_adc_async_read(struct pcf50633 *pcf, int mux, int avg, void *callback_param) { struct pcf50633_adc_request *req; + int ret; /* req is freed when the result is ready, in interrupt handler */ req = kmalloc(sizeof(*req), GFP_KERNEL); @@ -147,7 +148,11 @@ int pcf50633_adc_async_read(struct pcf50633 *pcf, int mux, int avg, req->callback = callback; req->callback_param = callback_param; - return adc_enqueue_request(pcf, req); + ret = adc_enqueue_request(pcf, req); + if (ret) + kfree(req); + + return ret; } EXPORT_SYMBOL_GPL(pcf50633_adc_async_read); From ccc91b3ed3f641efa8e9050c587ef509b0e2be3a Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Thu, 8 Dec 2022 22:57:23 +0100 Subject: [PATCH 23/40] mfd: twl: Fix TWL6032 phy vbus detection TWL6032 has a few charging registers prepended before the charging registers the TWL6030 has. To be able to use common register defines declare the additional registers as additional module. At the moment this affects the access to CHARGERUSB_CTRL1 in phy-twl6030-usb. Without this patch, it is accessing the wrong register on TWL6032. The consequence is that presence of Vbus is not reported. Cc: Bin Liu Cc: Tony Lindgren Signed-off-by: Andreas Kemnade Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20221208215723.217557-1-andreas@kemnade.info --- drivers/mfd/twl-core.c | 9 ++++----- include/linux/mfd/twl.h | 2 ++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 62be2326c9b2..e2d9a93be43b 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -110,8 +110,8 @@ #define TWL6030_BASEADD_PWM 0x00BA #define TWL6030_BASEADD_GASGAUGE 0x00C0 #define TWL6030_BASEADD_PIH 0x00D0 -#define TWL6030_BASEADD_CHARGER 0x00E0 #define TWL6032_BASEADD_CHARGER 0x00DA +#define TWL6030_BASEADD_CHARGER 0x00E0 #define TWL6030_BASEADD_LED 0x00F4 /* subchip/slave 2 0x4A - DFT */ @@ -353,6 +353,9 @@ static struct twl_mapping twl6030_map[] = { { 2, TWL6030_BASEADD_ZERO }, { 1, TWL6030_BASEADD_GPADC_CTRL }, { 1, TWL6030_BASEADD_GASGAUGE }, + + /* TWL6032 specific charger registers */ + { 1, TWL6032_BASEADD_CHARGER }, }; static const struct regmap_config twl6030_regmap_config[3] = { @@ -803,10 +806,6 @@ twl_probe(struct i2c_client *client) if ((id->driver_data) & TWL6030_CLASS) { twl_priv->twl_id = TWL6030_CLASS_ID; twl_priv->twl_map = &twl6030_map[0]; - /* The charger base address is different in twl6032 */ - if ((id->driver_data) & TWL6032_SUBCLASS) - twl_priv->twl_map[TWL_MODULE_MAIN_CHARGE].base = - TWL6032_BASEADD_CHARGER; twl_regmap_config = twl6030_regmap_config; } else { twl_priv->twl_id = TWL4030_CLASS_ID; diff --git a/include/linux/mfd/twl.h b/include/linux/mfd/twl.h index eaa233038254..6e3d99b7a0ee 100644 --- a/include/linux/mfd/twl.h +++ b/include/linux/mfd/twl.h @@ -69,6 +69,8 @@ enum twl6030_module_ids { TWL6030_MODULE_GPADC, TWL6030_MODULE_GASGAUGE, + /* A few extra registers before the registers shared with the 6030 */ + TWL6032_MODULE_CHARGE, TWL6030_MODULE_LAST, }; From 58a3fb991ec21e8cba82062be374c67447496e3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 12 Dec 2022 22:43:52 +0100 Subject: [PATCH 24/40] mfd: twl4030-power: Drop empty platform remove function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A remove callback just returning 0 is equivalent to no remove callback at all. So drop the useless function. Signed-off-by: Uwe Kleine-König Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20221212214352.3776110-1-u.kleine-koenig@pengutronix.de --- drivers/mfd/twl4030-power.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index 6b36932263ba..e35b0f788c50 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -953,18 +953,12 @@ static int twl4030_power_probe(struct platform_device *pdev) return err; } -static int twl4030_power_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver twl4030_power_driver = { .driver = { .name = "twl4030_power", .of_match_table = of_match_ptr(twl4030_power_of_match), }, .probe = twl4030_power_probe, - .remove = twl4030_power_remove, }; module_platform_driver(twl4030_power_driver); From 0b05327947dc68e8901477ced9ea6f8e3fb0c5f5 Mon Sep 17 00:00:00 2001 From: Nick Hawkins Date: Fri, 16 Dec 2022 12:35:29 -0600 Subject: [PATCH 25/40] dt-bindings: mfd: syscon: Document GXP register compatible Document hpe,gxp-sysreg compatible for GXP registers. Signed-off-by: Nick Hawkins Acked-by: Krzysztof Kozlowski Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20221216183532.78933-4-nick.hawkins@hpe.com --- Documentation/devicetree/bindings/mfd/syscon.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml index 1b01bd010431..2f66713f4f7b 100644 --- a/Documentation/devicetree/bindings/mfd/syscon.yaml +++ b/Documentation/devicetree/bindings/mfd/syscon.yaml @@ -46,6 +46,7 @@ properties: - hisilicon,hi6220-sramctrl - hisilicon,pcie-sas-subctrl - hisilicon,peri-subctrl + - hpe,gxp-sysreg - intel,lgm-syscon - marvell,armada-3700-usb2-host-misc - mediatek,mt8135-pctl-a-syscfg From 49184844b6653292b2954304005357ef6828b0fa Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Tue, 27 Dec 2022 16:19:21 +0800 Subject: [PATCH 26/40] mfd: qcom-pm8xxx: Remove set but unused variable 'rev' Variable rev is not effectively used in the function, so delete it. drivers/mfd/qcom-pm8xxx.c:513:6: warning: variable 'rev' set but not used. Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=3558 Reported-by: Abaci Robot Signed-off-by: Jiapeng Chong Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20221227081921.56448-1-jiapeng.chong@linux.alibaba.com --- drivers/mfd/qcom-pm8xxx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/mfd/qcom-pm8xxx.c b/drivers/mfd/qcom-pm8xxx.c index 601106580e2e..9a948df8c28d 100644 --- a/drivers/mfd/qcom-pm8xxx.c +++ b/drivers/mfd/qcom-pm8xxx.c @@ -510,7 +510,6 @@ static int pm8xxx_probe(struct platform_device *pdev) struct regmap *regmap; int irq, rc; unsigned int val; - u32 rev; struct pm_irq_chip *chip; data = of_device_get_match_data(&pdev->dev); @@ -535,7 +534,6 @@ static int pm8xxx_probe(struct platform_device *pdev) return rc; } pr_info("PMIC revision 1: %02X\n", val); - rev = val; /* Read PMIC chip revision 2 */ rc = regmap_read(regmap, REG_HWREV_2, &val); @@ -545,7 +543,6 @@ static int pm8xxx_probe(struct platform_device *pdev) return rc; } pr_info("PMIC revision 2: %02X\n", val); - rev |= val << BITS_PER_BYTE; chip = devm_kzalloc(&pdev->dev, struct_size(chip, config, data->num_irqs), From 8aa06dbe50a612e32b5c367421e2a51ae3f1acc9 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Tue, 27 Dec 2022 16:18:05 +0800 Subject: [PATCH 27/40] mfd: max8925: Remove the unused function irq_to_max8925() The function irq_to_max8925() is defined in the max8925-core.c file, but not called elsewhere, so remove this unused function. drivers/mfd/max8925-core.c:472:40: warning: unused function 'irq_to_max8925'. Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=3561 Reported-by: Abaci Robot Signed-off-by: Jiapeng Chong Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20221227081805.54185-1-jiapeng.chong@linux.alibaba.com --- drivers/mfd/max8925-core.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index eb3f061c8ee6..0246bbe80354 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -469,12 +469,6 @@ static struct max8925_irq_data max8925_irqs[] = { }, }; -static inline struct max8925_irq_data *irq_to_max8925(struct max8925_chip *chip, - int irq) -{ - return &max8925_irqs[irq - chip->irq_base]; -} - static irqreturn_t max8925_irq(int irq, void *data) { struct max8925_chip *chip = data; From 88a32c2c5e98d72765846db83c1739e7b036770a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 9 Jan 2023 14:33:22 +0100 Subject: [PATCH 28/40] mfd: core: Spelling s/compement/complement/ Fix a misspelling of "complement". Signed-off-by: Geert Uytterhoeven Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/aa7abd7103a0e4be954ea63de78f12e8251b2964.1673271092.git.geert+renesas@glider.be --- include/linux/mfd/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h index 0bc7cba798a3..14ca7b471576 100644 --- a/include/linux/mfd/core.h +++ b/include/linux/mfd/core.h @@ -88,7 +88,7 @@ struct mfd_cell { const char *of_compatible; /* - * Address as defined in Device Tree. Used to compement 'of_compatible' + * Address as defined in Device Tree. Used to complement 'of_compatible' * (above) when matching OF nodes with devices that have identical * compatible strings */ From 1b1305e95e85624f538ec56db9acf88e2d3d7397 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 28 Dec 2022 10:27:52 -0600 Subject: [PATCH 29/40] mfd: axp20x: Switch to the sys-off handler API This removes a layer of indirection through pm_power_off() and allows the PMIC handler to be used as a fallback when firmware power off fails. This happens on boards like the Clockwork DevTerm R-01 where OpenSBI does not know how to use the PMIC to power off the board. Move the check for AXP288 to avoid registering a dummy handler. Signed-off-by: Samuel Holland [Lee: Removed superfluous new line] Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20221228162752.14204-1-samuel@sholland.org --- drivers/mfd/axp20x.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 47fd700f284f..01a6bbb6d266 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include @@ -825,17 +825,16 @@ static const struct mfd_cell axp813_cells[] = { }, }; -static struct axp20x_dev *axp20x_pm_power_off; -static void axp20x_power_off(void) +static int axp20x_power_off(struct sys_off_data *data) { - if (axp20x_pm_power_off->variant == AXP288_ID) - return; + struct axp20x_dev *axp20x = data->cb_data; - regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL, - AXP20X_OFF); + regmap_write(axp20x->regmap, AXP20X_OFF_CTRL, AXP20X_OFF); /* Give capacitors etc. time to drain to avoid kernel panic msg. */ mdelay(500); + + return NOTIFY_DONE; } int axp20x_match_device(struct axp20x_dev *axp20x) @@ -1002,10 +1001,11 @@ int axp20x_device_probe(struct axp20x_dev *axp20x) return ret; } - if (!pm_power_off) { - axp20x_pm_power_off = axp20x; - pm_power_off = axp20x_power_off; - } + if (axp20x->variant != AXP288_ID) + devm_register_sys_off_handler(axp20x->dev, + SYS_OFF_MODE_POWER_OFF, + SYS_OFF_PRIO_DEFAULT, + axp20x_power_off, axp20x); dev_info(axp20x->dev, "AXP20X driver loaded\n"); @@ -1015,11 +1015,6 @@ EXPORT_SYMBOL(axp20x_device_probe); void axp20x_device_remove(struct axp20x_dev *axp20x) { - if (axp20x == axp20x_pm_power_off) { - axp20x_pm_power_off = NULL; - pm_power_off = NULL; - } - mfd_remove_devices(axp20x->dev); regmap_del_irq_chip(axp20x->irq, axp20x->regmap_irqc); } From 81435ed2bdea54bef20a898827b127d8ce087495 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 9 Jan 2023 17:26:36 +0000 Subject: [PATCH 30/40] mfd: simple-mfd-i2c: Fix incoherent comment regarding DT registration Signed-off-by: Lee Jones --- drivers/mfd/simple-mfd-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c index f4c8fc3ee463..e31f13fd6a79 100644 --- a/drivers/mfd/simple-mfd-i2c.c +++ b/drivers/mfd/simple-mfd-i2c.c @@ -48,7 +48,7 @@ static int simple_mfd_i2c_probe(struct i2c_client *i2c) if (IS_ERR(regmap)) return PTR_ERR(regmap); - /* If no MFD cells are spedified, use register the DT child nodes instead */ + /* If no MFD cells are specified, register using the DT child nodes instead */ if (!simple_mfd_data || !simple_mfd_data->mfd_cell) return devm_of_platform_populate(&i2c->dev); From 484cd9c0ec63b807227c44c10e47330eba136dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matti=20Lehtim=C3=A4ki?= Date: Thu, 12 Jan 2023 22:26:07 +0200 Subject: [PATCH 31/40] dt-bindings: mfd: qcom,tcsr: Add compatible for MSM8226 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the qcom,msm8226-tcsr compatible. Signed-off-by: Matti Lehtimäki Acked-by: Krzysztof Kozlowski Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230112202612.791455-5-matti.lehtimaki@gmail.com --- Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml b/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml index adcae6c007d9..d463fb47278f 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml +++ b/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml @@ -31,6 +31,7 @@ properties: - qcom,tcsr-ipq6018 - qcom,tcsr-ipq8064 - qcom,tcsr-mdm9615 + - qcom,tcsr-msm8226 - qcom,tcsr-msm8660 - qcom,tcsr-msm8916 - qcom,tcsr-msm8953 From 8e993c5888fa7131b384f3c8ec710209b7be78e6 Mon Sep 17 00:00:00 2001 From: Brad Larson Date: Wed, 18 Jan 2023 19:51:26 -0800 Subject: [PATCH 32/40] dt-bindings: mfd: syscon: Add amd,pensando-elba-syscon compatible Add the AMD Pensando Elba SoC system registers compatible Signed-off-by: Brad Larson Acked-by: Rob Herring Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230119035136.21603-6-blarson@amd.com --- Documentation/devicetree/bindings/mfd/syscon.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml index 2f66713f4f7b..ac111a219427 100644 --- a/Documentation/devicetree/bindings/mfd/syscon.yaml +++ b/Documentation/devicetree/bindings/mfd/syscon.yaml @@ -38,6 +38,7 @@ properties: - allwinner,sun8i-h3-system-controller - allwinner,sun8i-v3s-system-controller - allwinner,sun50i-a64-system-controller + - amd,pensando-elba-syscon - brcm,cru-clkset - freecom,fsg-cs2-system-controller - fsl,imx93-aonmix-ns-syscfg From 0f4d261989a89aa78f309eb0c5cb816028182bca Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Thu, 5 Jan 2023 08:50:09 +0800 Subject: [PATCH 33/40] dt-bindings: mfd/syscon: Add resets property Simple syscon devices may require deassertion of a reset signal in order to access their register set. This change adds the `resets` property from reset.yaml#/properties/resets (referenced through core.yaml), specifying a maxItems of 1 for a single (optional) reset descriptor. This will allow a future change to the syscon driver to implement reset control. Signed-off-by: Jeremy Kerr Acked-by: Rob Herring Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230105005010.124948-2-jk@codeconstruct.com.au --- Documentation/devicetree/bindings/mfd/syscon.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml index ac111a219427..396d78088113 100644 --- a/Documentation/devicetree/bindings/mfd/syscon.yaml +++ b/Documentation/devicetree/bindings/mfd/syscon.yaml @@ -89,6 +89,9 @@ properties: on the device. enum: [1, 2, 4, 8] + resets: + maxItems: 1 + hwlocks: maxItems: 1 description: From 7d1e3bd94828ad9fc86f55253cd6fec8edd65394 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Thu, 5 Jan 2023 08:50:10 +0800 Subject: [PATCH 34/40] mfd: syscon: Allow reset control for syscon devices Simple syscon devices may require deassertion of a reset signal in order to access their register set. Rather than requiring a custom driver to implement this, we can use the generic "resets" specifiers to link a reset line to the syscon. This change adds an optional reset line to the syscon device description, and deasserts the reset if detected. Signed-off-by: Jeremy Kerr Reviewed-by: Arnd Bergmann Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230105005010.124948-3-jk@codeconstruct.com.au --- drivers/mfd/syscon.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index bdb2ce7ff03b..57b29c325131 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,7 @@ static LIST_HEAD(syscon_list); struct syscon { struct device_node *np; struct regmap *regmap; + struct reset_control *reset; struct list_head list; }; @@ -40,7 +42,7 @@ static const struct regmap_config syscon_regmap_config = { .reg_stride = 4, }; -static struct syscon *of_syscon_register(struct device_node *np, bool check_clk) +static struct syscon *of_syscon_register(struct device_node *np, bool check_res) { struct clk *clk; struct syscon *syscon; @@ -50,6 +52,7 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk) int ret; struct regmap_config syscon_config = syscon_regmap_config; struct resource res; + struct reset_control *reset; syscon = kzalloc(sizeof(*syscon), GFP_KERNEL); if (!syscon) @@ -114,7 +117,7 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk) goto err_regmap; } - if (check_clk) { + if (check_res) { clk = of_clk_get(np, 0); if (IS_ERR(clk)) { ret = PTR_ERR(clk); @@ -124,8 +127,18 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk) } else { ret = regmap_mmio_attach_clk(regmap, clk); if (ret) - goto err_attach; + goto err_attach_clk; } + + reset = of_reset_control_get_optional_exclusive(np, NULL); + if (IS_ERR(reset)) { + ret = PTR_ERR(reset); + goto err_attach_clk; + } + + ret = reset_control_deassert(reset); + if (ret) + goto err_reset; } syscon->regmap = regmap; @@ -137,7 +150,9 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk) return syscon; -err_attach: +err_reset: + reset_control_put(reset); +err_attach_clk: if (!IS_ERR(clk)) clk_put(clk); err_clk: @@ -150,7 +165,7 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk) } static struct regmap *device_node_get_regmap(struct device_node *np, - bool check_clk) + bool check_res) { struct syscon *entry, *syscon = NULL; @@ -165,7 +180,7 @@ static struct regmap *device_node_get_regmap(struct device_node *np, spin_unlock(&syscon_list_slock); if (!syscon) - syscon = of_syscon_register(np, check_clk); + syscon = of_syscon_register(np, check_res); if (IS_ERR(syscon)) return ERR_CAST(syscon); From 4414a7ab80cebf715045e3c4d465feefbad21139 Mon Sep 17 00:00:00 2001 From: Liang He Date: Thu, 5 Jan 2023 14:10:55 +0800 Subject: [PATCH 35/40] mfd: arizona: Use pm_runtime_resume_and_get() to prevent refcnt leak In arizona_clk32k_enable(), we should use pm_runtime_resume_and_get() as pm_runtime_get_sync() will increase the refcnt even when it returns an error. Signed-off-by: Liang He Acked-by: Charles Keepax Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230105061055.1509261-1-windhl@126.com --- drivers/mfd/arizona-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index bd7ee3260d53..c166fcd331f1 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -45,7 +45,7 @@ int arizona_clk32k_enable(struct arizona *arizona) if (arizona->clk32k_ref == 1) { switch (arizona->pdata.clk32k_src) { case ARIZONA_32KZ_MCLK1: - ret = pm_runtime_get_sync(arizona->dev); + ret = pm_runtime_resume_and_get(arizona->dev); if (ret != 0) goto err_ref; ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK1]); From ca78476e4888f1f1caac26c48ec715e546baf432 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 5 Jan 2023 14:46:13 +0100 Subject: [PATCH 36/40] mfd: Remove toshiba tmio drivers Four separate mfd drivers are in the "tmio" family, and all of them were used in now-removed PXA machines (eseries, tosa, and hx4700), so the mfd drivers and all its children can be removed as well. Signed-off-by: Arnd Bergmann Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230105134622.254560-19-arnd@kernel.org --- drivers/mfd/Kconfig | 38 -- drivers/mfd/Makefile | 4 - drivers/mfd/asic3.c | 1071 ---------------------------------- drivers/mfd/t7l66xb.c | 427 -------------- drivers/mfd/tc6387xb.c | 228 -------- drivers/mfd/tc6393xb.c | 907 ---------------------------- drivers/mfd/tmio_core.c | 70 --- include/linux/mfd/asic3.h | 313 ---------- include/linux/mfd/t7l66xb.h | 29 - include/linux/mfd/tc6387xb.h | 19 - include/linux/mfd/tc6393xb.h | 53 -- include/linux/mfd/tmio.h | 5 - 12 files changed, 3164 deletions(-) delete mode 100644 drivers/mfd/asic3.c delete mode 100644 drivers/mfd/t7l66xb.c delete mode 100644 drivers/mfd/tc6387xb.c delete mode 100644 drivers/mfd/tc6393xb.c delete mode 100644 drivers/mfd/tmio_core.c delete mode 100644 include/linux/mfd/asic3.h delete mode 100644 include/linux/mfd/t7l66xb.h delete mode 100644 include/linux/mfd/tc6387xb.h delete mode 100644 include/linux/mfd/tc6393xb.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d90b4258fc44..d4fc4ca9fdbd 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -301,15 +301,6 @@ config MFD_CS47L92 help Support for Cirrus Logic CS42L92, CS47L92 and CS47L93 Smart Codecs -config MFD_ASIC3 - bool "Compaq ASIC3" - depends on GPIOLIB - depends on ARM || COMPILE_TEST - select MFD_CORE - help - This driver supports the ASIC3 multifunction chip found on many - PDAs (mainly iPAQ and HTC based ones) - config PMIC_DA903X bool "Dialog Semiconductor DA9030/DA9034 PMIC Support" depends on I2C=y @@ -1796,35 +1787,6 @@ config MFD_TC3589X additional drivers must be enabled in order to use the functionality of the device. -config MFD_TMIO - bool - default n - -config MFD_T7L66XB - bool "Toshiba T7L66XB" - depends on ARM && HAVE_CLK - select MFD_CORE - select MFD_TMIO - help - Support for Toshiba Mobile IO Controller T7L66XB - -config MFD_TC6387XB - bool "Toshiba TC6387XB" - depends on ARM && HAVE_CLK - select MFD_CORE - select MFD_TMIO - help - Support for Toshiba Mobile IO Controller TC6387XB - -config MFD_TC6393XB - bool "Toshiba TC6393XB" - depends on ARM && HAVE_CLK - select GPIOLIB - select MFD_CORE - select MFD_TMIO - help - Support for Toshiba Mobile IO Controller TC6393XB - config MFD_TQMX86 tristate "TQ-Systems IO controller TQMX86" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 81c30d7cf5d4..48cf532848c4 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_MFD_88PM800) += 88pm800.o 88pm80x.o obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o obj-$(CONFIG_MFD_ACT8945A) += act8945a.o obj-$(CONFIG_MFD_SM501) += sm501.o -obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o obj-$(CONFIG_ARCH_BCM2835) += bcm2835-pm.o obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o @@ -30,9 +29,6 @@ obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o obj-$(CONFIG_STMPE_SPI) += stmpe-spi.o obj-$(CONFIG_MFD_SUN6I_PRCM) += sun6i-prcm.o obj-$(CONFIG_MFD_TC3589X) += tc3589x.o -obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o -obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o -obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o obj-$(CONFIG_MFD_TQMX86) += tqmx86.o obj-$(CONFIG_MFD_LOCHNAGAR) += lochnagar-i2c.o diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c deleted file mode 100644 index 4fb7e35eb5ed..000000000000 --- a/drivers/mfd/asic3.c +++ /dev/null @@ -1,1071 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * driver/mfd/asic3.c - * - * Compaq ASIC3 support. - * - * Copyright 2001 Compaq Computer Corporation. - * Copyright 2004-2005 Phil Blundell - * Copyright 2007-2008 OpenedHand Ltd. - * - * Authors: Phil Blundell , - * Samuel Ortiz - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -enum { - ASIC3_CLOCK_SPI, - ASIC3_CLOCK_OWM, - ASIC3_CLOCK_PWM0, - ASIC3_CLOCK_PWM1, - ASIC3_CLOCK_LED0, - ASIC3_CLOCK_LED1, - ASIC3_CLOCK_LED2, - ASIC3_CLOCK_SD_HOST, - ASIC3_CLOCK_SD_BUS, - ASIC3_CLOCK_SMBUS, - ASIC3_CLOCK_EX0, - ASIC3_CLOCK_EX1, -}; - -struct asic3_clk { - int enabled; - unsigned int cdex; - unsigned long rate; -}; - -#define INIT_CDEX(_name, _rate) \ - [ASIC3_CLOCK_##_name] = { \ - .cdex = CLOCK_CDEX_##_name, \ - .rate = _rate, \ - } - -static struct asic3_clk asic3_clk_init[] __initdata = { - INIT_CDEX(SPI, 0), - INIT_CDEX(OWM, 5000000), - INIT_CDEX(PWM0, 0), - INIT_CDEX(PWM1, 0), - INIT_CDEX(LED0, 0), - INIT_CDEX(LED1, 0), - INIT_CDEX(LED2, 0), - INIT_CDEX(SD_HOST, 24576000), - INIT_CDEX(SD_BUS, 12288000), - INIT_CDEX(SMBUS, 0), - INIT_CDEX(EX0, 32768), - INIT_CDEX(EX1, 24576000), -}; - -struct asic3 { - void __iomem *mapping; - unsigned int bus_shift; - unsigned int irq_nr; - unsigned int irq_base; - raw_spinlock_t lock; - u16 irq_bothedge[4]; - struct gpio_chip gpio; - struct device *dev; - void __iomem *tmio_cnf; - - struct asic3_clk clocks[ARRAY_SIZE(asic3_clk_init)]; -}; - -static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset); - -void asic3_write_register(struct asic3 *asic, unsigned int reg, u32 value) -{ - iowrite16(value, asic->mapping + - (reg >> asic->bus_shift)); -} -EXPORT_SYMBOL_GPL(asic3_write_register); - -u32 asic3_read_register(struct asic3 *asic, unsigned int reg) -{ - return ioread16(asic->mapping + - (reg >> asic->bus_shift)); -} -EXPORT_SYMBOL_GPL(asic3_read_register); - -static void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set) -{ - unsigned long flags; - u32 val; - - raw_spin_lock_irqsave(&asic->lock, flags); - val = asic3_read_register(asic, reg); - if (set) - val |= bits; - else - val &= ~bits; - asic3_write_register(asic, reg, val); - raw_spin_unlock_irqrestore(&asic->lock, flags); -} - -/* IRQs */ -#define MAX_ASIC_ISR_LOOPS 20 -#define ASIC3_GPIO_BASE_INCR \ - (ASIC3_GPIO_B_BASE - ASIC3_GPIO_A_BASE) - -static void asic3_irq_flip_edge(struct asic3 *asic, - u32 base, int bit) -{ - u16 edge; - unsigned long flags; - - raw_spin_lock_irqsave(&asic->lock, flags); - edge = asic3_read_register(asic, - base + ASIC3_GPIO_EDGE_TRIGGER); - edge ^= bit; - asic3_write_register(asic, - base + ASIC3_GPIO_EDGE_TRIGGER, edge); - raw_spin_unlock_irqrestore(&asic->lock, flags); -} - -static void asic3_irq_demux(struct irq_desc *desc) -{ - struct asic3 *asic = irq_desc_get_handler_data(desc); - struct irq_data *data = irq_desc_get_irq_data(desc); - int iter, i; - unsigned long flags; - - data->chip->irq_ack(data); - - for (iter = 0 ; iter < MAX_ASIC_ISR_LOOPS; iter++) { - u32 status; - int bank; - - raw_spin_lock_irqsave(&asic->lock, flags); - status = asic3_read_register(asic, - ASIC3_OFFSET(INTR, P_INT_STAT)); - raw_spin_unlock_irqrestore(&asic->lock, flags); - - /* Check all ten register bits */ - if ((status & 0x3ff) == 0) - break; - - /* Handle GPIO IRQs */ - for (bank = 0; bank < ASIC3_NUM_GPIO_BANKS; bank++) { - if (status & (1 << bank)) { - unsigned long base, istat; - - base = ASIC3_GPIO_A_BASE - + bank * ASIC3_GPIO_BASE_INCR; - raw_spin_lock_irqsave(&asic->lock, flags); - istat = asic3_read_register(asic, - base + - ASIC3_GPIO_INT_STATUS); - /* Clearing IntStatus */ - asic3_write_register(asic, - base + - ASIC3_GPIO_INT_STATUS, 0); - raw_spin_unlock_irqrestore(&asic->lock, flags); - - for (i = 0; i < ASIC3_GPIOS_PER_BANK; i++) { - int bit = (1 << i); - unsigned int irqnr; - - if (!(istat & bit)) - continue; - - irqnr = asic->irq_base + - (ASIC3_GPIOS_PER_BANK * bank) - + i; - generic_handle_irq(irqnr); - if (asic->irq_bothedge[bank] & bit) - asic3_irq_flip_edge(asic, base, - bit); - } - } - } - - /* Handle remaining IRQs in the status register */ - for (i = ASIC3_NUM_GPIOS; i < ASIC3_NR_IRQS; i++) { - /* They start at bit 4 and go up */ - if (status & (1 << (i - ASIC3_NUM_GPIOS + 4))) - generic_handle_irq(asic->irq_base + i); - } - } - - if (iter >= MAX_ASIC_ISR_LOOPS) - dev_err(asic->dev, "interrupt processing overrun\n"); -} - -static inline int asic3_irq_to_bank(struct asic3 *asic, int irq) -{ - int n; - - n = (irq - asic->irq_base) >> 4; - - return (n * (ASIC3_GPIO_B_BASE - ASIC3_GPIO_A_BASE)); -} - -static inline int asic3_irq_to_index(struct asic3 *asic, int irq) -{ - return (irq - asic->irq_base) & 0xf; -} - -static void asic3_mask_gpio_irq(struct irq_data *data) -{ - struct asic3 *asic = irq_data_get_irq_chip_data(data); - u32 val, bank, index; - unsigned long flags; - - bank = asic3_irq_to_bank(asic, data->irq); - index = asic3_irq_to_index(asic, data->irq); - - raw_spin_lock_irqsave(&asic->lock, flags); - val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK); - val |= 1 << index; - asic3_write_register(asic, bank + ASIC3_GPIO_MASK, val); - raw_spin_unlock_irqrestore(&asic->lock, flags); -} - -static void asic3_mask_irq(struct irq_data *data) -{ - struct asic3 *asic = irq_data_get_irq_chip_data(data); - int regval; - unsigned long flags; - - raw_spin_lock_irqsave(&asic->lock, flags); - regval = asic3_read_register(asic, - ASIC3_INTR_BASE + - ASIC3_INTR_INT_MASK); - - regval &= ~(ASIC3_INTMASK_MASK0 << - (data->irq - (asic->irq_base + ASIC3_NUM_GPIOS))); - - asic3_write_register(asic, - ASIC3_INTR_BASE + - ASIC3_INTR_INT_MASK, - regval); - raw_spin_unlock_irqrestore(&asic->lock, flags); -} - -static void asic3_unmask_gpio_irq(struct irq_data *data) -{ - struct asic3 *asic = irq_data_get_irq_chip_data(data); - u32 val, bank, index; - unsigned long flags; - - bank = asic3_irq_to_bank(asic, data->irq); - index = asic3_irq_to_index(asic, data->irq); - - raw_spin_lock_irqsave(&asic->lock, flags); - val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK); - val &= ~(1 << index); - asic3_write_register(asic, bank + ASIC3_GPIO_MASK, val); - raw_spin_unlock_irqrestore(&asic->lock, flags); -} - -static void asic3_unmask_irq(struct irq_data *data) -{ - struct asic3 *asic = irq_data_get_irq_chip_data(data); - int regval; - unsigned long flags; - - raw_spin_lock_irqsave(&asic->lock, flags); - regval = asic3_read_register(asic, - ASIC3_INTR_BASE + - ASIC3_INTR_INT_MASK); - - regval |= (ASIC3_INTMASK_MASK0 << - (data->irq - (asic->irq_base + ASIC3_NUM_GPIOS))); - - asic3_write_register(asic, - ASIC3_INTR_BASE + - ASIC3_INTR_INT_MASK, - regval); - raw_spin_unlock_irqrestore(&asic->lock, flags); -} - -static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type) -{ - struct asic3 *asic = irq_data_get_irq_chip_data(data); - u32 bank, index; - u16 trigger, level, edge, bit; - unsigned long flags; - - bank = asic3_irq_to_bank(asic, data->irq); - index = asic3_irq_to_index(asic, data->irq); - bit = 1<lock, flags); - level = asic3_read_register(asic, - bank + ASIC3_GPIO_LEVEL_TRIGGER); - edge = asic3_read_register(asic, - bank + ASIC3_GPIO_EDGE_TRIGGER); - trigger = asic3_read_register(asic, - bank + ASIC3_GPIO_TRIGGER_TYPE); - asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] &= ~bit; - - if (type == IRQ_TYPE_EDGE_RISING) { - trigger |= bit; - edge |= bit; - } else if (type == IRQ_TYPE_EDGE_FALLING) { - trigger |= bit; - edge &= ~bit; - } else if (type == IRQ_TYPE_EDGE_BOTH) { - trigger |= bit; - if (asic3_gpio_get(&asic->gpio, data->irq - asic->irq_base)) - edge &= ~bit; - else - edge |= bit; - asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] |= bit; - } else if (type == IRQ_TYPE_LEVEL_LOW) { - trigger &= ~bit; - level &= ~bit; - } else if (type == IRQ_TYPE_LEVEL_HIGH) { - trigger &= ~bit; - level |= bit; - } else { - /* - * if type == IRQ_TYPE_NONE, we should mask interrupts, but - * be careful to not unmask them if mask was also called. - * Probably need internal state for mask. - */ - dev_notice(asic->dev, "irq type not changed\n"); - } - asic3_write_register(asic, bank + ASIC3_GPIO_LEVEL_TRIGGER, - level); - asic3_write_register(asic, bank + ASIC3_GPIO_EDGE_TRIGGER, - edge); - asic3_write_register(asic, bank + ASIC3_GPIO_TRIGGER_TYPE, - trigger); - raw_spin_unlock_irqrestore(&asic->lock, flags); - return 0; -} - -static int asic3_gpio_irq_set_wake(struct irq_data *data, unsigned int on) -{ - struct asic3 *asic = irq_data_get_irq_chip_data(data); - u32 bank, index; - u16 bit; - - bank = asic3_irq_to_bank(asic, data->irq); - index = asic3_irq_to_index(asic, data->irq); - bit = 1<irq_nr = ret; - - /* turn on clock to IRQ controller */ - clksel |= CLOCK_SEL_CX; - asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), - clksel); - - irq_base = asic->irq_base; - - for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) { - if (irq < asic->irq_base + ASIC3_NUM_GPIOS) - irq_set_chip(irq, &asic3_gpio_irq_chip); - else - irq_set_chip(irq, &asic3_irq_chip); - - irq_set_chip_data(irq, asic); - irq_set_handler(irq, handle_level_irq); - irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); - } - - asic3_write_register(asic, ASIC3_OFFSET(INTR, INT_MASK), - ASIC3_INTMASK_GINTMASK); - - irq_set_chained_handler_and_data(asic->irq_nr, asic3_irq_demux, asic); - irq_set_irq_type(asic->irq_nr, IRQ_TYPE_EDGE_RISING); - - return 0; -} - -static void asic3_irq_remove(struct platform_device *pdev) -{ - struct asic3 *asic = platform_get_drvdata(pdev); - unsigned int irq, irq_base; - - irq_base = asic->irq_base; - - for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) { - irq_set_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); - irq_set_chip_and_handler(irq, NULL, NULL); - irq_set_chip_data(irq, NULL); - } - irq_set_chained_handler(asic->irq_nr, NULL); -} - -/* GPIOs */ -static int asic3_gpio_direction(struct gpio_chip *chip, - unsigned offset, int out) -{ - u32 mask = ASIC3_GPIO_TO_MASK(offset), out_reg; - unsigned int gpio_base; - unsigned long flags; - struct asic3 *asic; - - asic = gpiochip_get_data(chip); - gpio_base = ASIC3_GPIO_TO_BASE(offset); - - if (gpio_base > ASIC3_GPIO_D_BASE) { - dev_err(asic->dev, "Invalid base (0x%x) for gpio %d\n", - gpio_base, offset); - return -EINVAL; - } - - raw_spin_lock_irqsave(&asic->lock, flags); - - out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_DIRECTION); - - /* Input is 0, Output is 1 */ - if (out) - out_reg |= mask; - else - out_reg &= ~mask; - - asic3_write_register(asic, gpio_base + ASIC3_GPIO_DIRECTION, out_reg); - - raw_spin_unlock_irqrestore(&asic->lock, flags); - - return 0; - -} - -static int asic3_gpio_direction_input(struct gpio_chip *chip, - unsigned offset) -{ - return asic3_gpio_direction(chip, offset, 0); -} - -static int asic3_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - return asic3_gpio_direction(chip, offset, 1); -} - -static int asic3_gpio_get(struct gpio_chip *chip, - unsigned offset) -{ - unsigned int gpio_base; - u32 mask = ASIC3_GPIO_TO_MASK(offset); - struct asic3 *asic; - - asic = gpiochip_get_data(chip); - gpio_base = ASIC3_GPIO_TO_BASE(offset); - - if (gpio_base > ASIC3_GPIO_D_BASE) { - dev_err(asic->dev, "Invalid base (0x%x) for gpio %d\n", - gpio_base, offset); - return -EINVAL; - } - - return !!(asic3_read_register(asic, - gpio_base + ASIC3_GPIO_STATUS) & mask); -} - -static void asic3_gpio_set(struct gpio_chip *chip, - unsigned offset, int value) -{ - u32 mask, out_reg; - unsigned int gpio_base; - unsigned long flags; - struct asic3 *asic; - - asic = gpiochip_get_data(chip); - gpio_base = ASIC3_GPIO_TO_BASE(offset); - - if (gpio_base > ASIC3_GPIO_D_BASE) { - dev_err(asic->dev, "Invalid base (0x%x) for gpio %d\n", - gpio_base, offset); - return; - } - - mask = ASIC3_GPIO_TO_MASK(offset); - - raw_spin_lock_irqsave(&asic->lock, flags); - - out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_OUT); - - if (value) - out_reg |= mask; - else - out_reg &= ~mask; - - asic3_write_register(asic, gpio_base + ASIC3_GPIO_OUT, out_reg); - - raw_spin_unlock_irqrestore(&asic->lock, flags); -} - -static int asic3_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct asic3 *asic = gpiochip_get_data(chip); - - return asic->irq_base + offset; -} - -static __init int asic3_gpio_probe(struct platform_device *pdev, - u16 *gpio_config, int num) -{ - struct asic3 *asic = platform_get_drvdata(pdev); - u16 alt_reg[ASIC3_NUM_GPIO_BANKS]; - u16 out_reg[ASIC3_NUM_GPIO_BANKS]; - u16 dir_reg[ASIC3_NUM_GPIO_BANKS]; - int i; - - memset(alt_reg, 0, ASIC3_NUM_GPIO_BANKS * sizeof(u16)); - memset(out_reg, 0, ASIC3_NUM_GPIO_BANKS * sizeof(u16)); - memset(dir_reg, 0, ASIC3_NUM_GPIO_BANKS * sizeof(u16)); - - /* Enable all GPIOs */ - asic3_write_register(asic, ASIC3_GPIO_OFFSET(A, MASK), 0xffff); - asic3_write_register(asic, ASIC3_GPIO_OFFSET(B, MASK), 0xffff); - asic3_write_register(asic, ASIC3_GPIO_OFFSET(C, MASK), 0xffff); - asic3_write_register(asic, ASIC3_GPIO_OFFSET(D, MASK), 0xffff); - - for (i = 0; i < num; i++) { - u8 alt, pin, dir, init, bank_num, bit_num; - u16 config = gpio_config[i]; - - pin = ASIC3_CONFIG_GPIO_PIN(config); - alt = ASIC3_CONFIG_GPIO_ALT(config); - dir = ASIC3_CONFIG_GPIO_DIR(config); - init = ASIC3_CONFIG_GPIO_INIT(config); - - bank_num = ASIC3_GPIO_TO_BANK(pin); - bit_num = ASIC3_GPIO_TO_BIT(pin); - - alt_reg[bank_num] |= (alt << bit_num); - out_reg[bank_num] |= (init << bit_num); - dir_reg[bank_num] |= (dir << bit_num); - } - - for (i = 0; i < ASIC3_NUM_GPIO_BANKS; i++) { - asic3_write_register(asic, - ASIC3_BANK_TO_BASE(i) + - ASIC3_GPIO_DIRECTION, - dir_reg[i]); - asic3_write_register(asic, - ASIC3_BANK_TO_BASE(i) + ASIC3_GPIO_OUT, - out_reg[i]); - asic3_write_register(asic, - ASIC3_BANK_TO_BASE(i) + - ASIC3_GPIO_ALT_FUNCTION, - alt_reg[i]); - } - - return gpiochip_add_data(&asic->gpio, asic); -} - -static void asic3_gpio_remove(struct platform_device *pdev) -{ - struct asic3 *asic = platform_get_drvdata(pdev); - - gpiochip_remove(&asic->gpio); -} - -static void asic3_clk_enable(struct asic3 *asic, struct asic3_clk *clk) -{ - unsigned long flags; - u32 cdex; - - raw_spin_lock_irqsave(&asic->lock, flags); - if (clk->enabled++ == 0) { - cdex = asic3_read_register(asic, ASIC3_OFFSET(CLOCK, CDEX)); - cdex |= clk->cdex; - asic3_write_register(asic, ASIC3_OFFSET(CLOCK, CDEX), cdex); - } - raw_spin_unlock_irqrestore(&asic->lock, flags); -} - -static void asic3_clk_disable(struct asic3 *asic, struct asic3_clk *clk) -{ - unsigned long flags; - u32 cdex; - - WARN_ON(clk->enabled == 0); - - raw_spin_lock_irqsave(&asic->lock, flags); - if (--clk->enabled == 0) { - cdex = asic3_read_register(asic, ASIC3_OFFSET(CLOCK, CDEX)); - cdex &= ~clk->cdex; - asic3_write_register(asic, ASIC3_OFFSET(CLOCK, CDEX), cdex); - } - raw_spin_unlock_irqrestore(&asic->lock, flags); -} - -/* MFD cells (SPI, PWM, LED, DS1WM, MMC) */ -static struct ds1wm_driver_data ds1wm_pdata = { - .active_high = 1, - .reset_recover_delay = 1, -}; - -static struct resource ds1wm_resources[] = { - { - .start = ASIC3_OWM_BASE, - .end = ASIC3_OWM_BASE + 0x13, - .flags = IORESOURCE_MEM, - }, - { - .start = ASIC3_IRQ_OWM, - .end = ASIC3_IRQ_OWM, - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, - }, -}; - -static int ds1wm_enable(struct platform_device *pdev) -{ - struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); - - /* Turn on external clocks and the OWM clock */ - asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX0]); - asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX1]); - asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_OWM]); - usleep_range(1000, 5000); - - /* Reset and enable DS1WM */ - asic3_set_register(asic, ASIC3_OFFSET(EXTCF, RESET), - ASIC3_EXTCF_OWM_RESET, 1); - usleep_range(1000, 5000); - asic3_set_register(asic, ASIC3_OFFSET(EXTCF, RESET), - ASIC3_EXTCF_OWM_RESET, 0); - usleep_range(1000, 5000); - asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), - ASIC3_EXTCF_OWM_EN, 1); - usleep_range(1000, 5000); - - return 0; -} - -static int ds1wm_disable(struct platform_device *pdev) -{ - struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); - - asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), - ASIC3_EXTCF_OWM_EN, 0); - - asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_OWM]); - asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX0]); - asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX1]); - - return 0; -} - -static const struct mfd_cell asic3_cell_ds1wm = { - .name = "ds1wm", - .enable = ds1wm_enable, - .disable = ds1wm_disable, - .platform_data = &ds1wm_pdata, - .pdata_size = sizeof(ds1wm_pdata), - .num_resources = ARRAY_SIZE(ds1wm_resources), - .resources = ds1wm_resources, -}; - -static void asic3_mmc_pwr(struct platform_device *pdev, int state) -{ - struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); - - tmio_core_mmc_pwr(asic->tmio_cnf, 1 - asic->bus_shift, state); -} - -static void asic3_mmc_clk_div(struct platform_device *pdev, int state) -{ - struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); - - tmio_core_mmc_clk_div(asic->tmio_cnf, 1 - asic->bus_shift, state); -} - -static struct tmio_mmc_data asic3_mmc_data = { - .hclk = 24576000, - .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, - .set_pwr = asic3_mmc_pwr, - .set_clk_div = asic3_mmc_clk_div, -}; - -static struct resource asic3_mmc_resources[] = { - DEFINE_RES_MEM(ASIC3_SD_CTRL_BASE, 0x400), - DEFINE_RES_IRQ(0) -}; - -static int asic3_mmc_enable(struct platform_device *pdev) -{ - struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); - - /* Not sure if it must be done bit by bit, but leaving as-is */ - asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), - ASIC3_SDHWCTRL_LEVCD, 1); - asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), - ASIC3_SDHWCTRL_LEVWP, 1); - asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), - ASIC3_SDHWCTRL_SUSPEND, 0); - asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), - ASIC3_SDHWCTRL_PCLR, 0); - - asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX0]); - /* CLK32 used for card detection and for interruption detection - * when HCLK is stopped. - */ - asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX1]); - usleep_range(1000, 5000); - - /* HCLK 24.576 MHz, BCLK 12.288 MHz: */ - asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), - CLOCK_SEL_CX | CLOCK_SEL_SD_HCLK_SEL); - - asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_SD_HOST]); - asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_SD_BUS]); - usleep_range(1000, 5000); - - asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), - ASIC3_EXTCF_SD_MEM_ENABLE, 1); - - /* Enable SD card slot 3.3V power supply */ - asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), - ASIC3_SDHWCTRL_SDPWR, 1); - - /* ASIC3_SD_CTRL_BASE assumes 32-bit addressing, TMIO is 16-bit */ - tmio_core_mmc_enable(asic->tmio_cnf, 1 - asic->bus_shift, - ASIC3_SD_CTRL_BASE >> 1); - - return 0; -} - -static int asic3_mmc_disable(struct platform_device *pdev) -{ - struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); - - /* Put in suspend mode */ - asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), - ASIC3_SDHWCTRL_SUSPEND, 1); - - /* Disable clocks */ - asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_SD_HOST]); - asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_SD_BUS]); - asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX0]); - asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX1]); - return 0; -} - -static const struct mfd_cell asic3_cell_mmc = { - .name = "tmio-mmc", - .enable = asic3_mmc_enable, - .disable = asic3_mmc_disable, - .suspend = asic3_mmc_disable, - .resume = asic3_mmc_enable, - .platform_data = &asic3_mmc_data, - .pdata_size = sizeof(asic3_mmc_data), - .num_resources = ARRAY_SIZE(asic3_mmc_resources), - .resources = asic3_mmc_resources, -}; - -static const int clock_ledn[ASIC3_NUM_LEDS] = { - [0] = ASIC3_CLOCK_LED0, - [1] = ASIC3_CLOCK_LED1, - [2] = ASIC3_CLOCK_LED2, -}; - -static int asic3_leds_enable(struct platform_device *pdev) -{ - const struct mfd_cell *cell = mfd_get_cell(pdev); - struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); - - asic3_clk_enable(asic, &asic->clocks[clock_ledn[cell->id]]); - - return 0; -} - -static int asic3_leds_disable(struct platform_device *pdev) -{ - const struct mfd_cell *cell = mfd_get_cell(pdev); - struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); - - asic3_clk_disable(asic, &asic->clocks[clock_ledn[cell->id]]); - - return 0; -} - -static int asic3_leds_suspend(struct platform_device *pdev) -{ - const struct mfd_cell *cell = mfd_get_cell(pdev); - struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); - - while (asic3_gpio_get(&asic->gpio, ASIC3_GPIO(C, cell->id)) != 0) - usleep_range(1000, 5000); - - asic3_clk_disable(asic, &asic->clocks[clock_ledn[cell->id]]); - - return 0; -} - -static struct mfd_cell asic3_cell_leds[ASIC3_NUM_LEDS] = { - [0] = { - .name = "leds-asic3", - .id = 0, - .enable = asic3_leds_enable, - .disable = asic3_leds_disable, - .suspend = asic3_leds_suspend, - .resume = asic3_leds_enable, - }, - [1] = { - .name = "leds-asic3", - .id = 1, - .enable = asic3_leds_enable, - .disable = asic3_leds_disable, - .suspend = asic3_leds_suspend, - .resume = asic3_leds_enable, - }, - [2] = { - .name = "leds-asic3", - .id = 2, - .enable = asic3_leds_enable, - .disable = asic3_leds_disable, - .suspend = asic3_leds_suspend, - .resume = asic3_leds_enable, - }, -}; - -static int __init asic3_mfd_probe(struct platform_device *pdev, - struct asic3_platform_data *pdata, - struct resource *mem) -{ - struct asic3 *asic = platform_get_drvdata(pdev); - struct resource *mem_sdio; - int irq, ret; - - mem_sdio = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!mem_sdio) - dev_dbg(asic->dev, "no SDIO MEM resource\n"); - - irq = platform_get_irq(pdev, 1); - if (irq < 0) - dev_dbg(asic->dev, "no SDIO IRQ resource\n"); - - /* DS1WM */ - asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), - ASIC3_EXTCF_OWM_SMB, 0); - - ds1wm_resources[0].start >>= asic->bus_shift; - ds1wm_resources[0].end >>= asic->bus_shift; - - /* MMC */ - if (mem_sdio) { - asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> - asic->bus_shift) + mem_sdio->start, - ASIC3_SD_CONFIG_SIZE >> asic->bus_shift); - if (!asic->tmio_cnf) { - ret = -ENOMEM; - dev_dbg(asic->dev, "Couldn't ioremap SD_CONFIG\n"); - goto out; - } - } - asic3_mmc_resources[0].start >>= asic->bus_shift; - asic3_mmc_resources[0].end >>= asic->bus_shift; - - if (pdata->clock_rate) { - ds1wm_pdata.clock_rate = pdata->clock_rate; - ret = mfd_add_devices(&pdev->dev, pdev->id, - &asic3_cell_ds1wm, 1, mem, asic->irq_base, NULL); - if (ret < 0) - goto out_unmap; - } - - if (mem_sdio && (irq >= 0)) { - ret = mfd_add_devices(&pdev->dev, pdev->id, - &asic3_cell_mmc, 1, mem_sdio, irq, NULL); - if (ret < 0) - goto out_unmap; - } - - ret = 0; - if (pdata->leds) { - int i; - - for (i = 0; i < ASIC3_NUM_LEDS; ++i) { - asic3_cell_leds[i].platform_data = &pdata->leds[i]; - asic3_cell_leds[i].pdata_size = sizeof(pdata->leds[i]); - } - ret = mfd_add_devices(&pdev->dev, 0, - asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0, NULL); - } - return ret; - -out_unmap: - if (asic->tmio_cnf) - iounmap(asic->tmio_cnf); -out: - return ret; -} - -static void asic3_mfd_remove(struct platform_device *pdev) -{ - struct asic3 *asic = platform_get_drvdata(pdev); - - mfd_remove_devices(&pdev->dev); - iounmap(asic->tmio_cnf); -} - -/* Core */ -static int __init asic3_probe(struct platform_device *pdev) -{ - struct asic3_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct asic3 *asic; - struct resource *mem; - unsigned long clksel; - int ret = 0; - - asic = devm_kzalloc(&pdev->dev, - sizeof(struct asic3), GFP_KERNEL); - if (!asic) - return -ENOMEM; - - raw_spin_lock_init(&asic->lock); - platform_set_drvdata(pdev, asic); - asic->dev = &pdev->dev; - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(asic->dev, "no MEM resource\n"); - return -ENOMEM; - } - - asic->mapping = ioremap(mem->start, resource_size(mem)); - if (!asic->mapping) { - dev_err(asic->dev, "Couldn't ioremap\n"); - return -ENOMEM; - } - - asic->irq_base = pdata->irq_base; - - /* calculate bus shift from mem resource */ - asic->bus_shift = 2 - (resource_size(mem) >> 12); - - clksel = 0; - asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), clksel); - - ret = asic3_irq_probe(pdev); - if (ret < 0) { - dev_err(asic->dev, "Couldn't probe IRQs\n"); - goto out_unmap; - } - - asic->gpio.label = "asic3"; - asic->gpio.base = pdata->gpio_base; - asic->gpio.ngpio = ASIC3_NUM_GPIOS; - asic->gpio.get = asic3_gpio_get; - asic->gpio.set = asic3_gpio_set; - asic->gpio.direction_input = asic3_gpio_direction_input; - asic->gpio.direction_output = asic3_gpio_direction_output; - asic->gpio.to_irq = asic3_gpio_to_irq; - - ret = asic3_gpio_probe(pdev, - pdata->gpio_config, - pdata->gpio_config_num); - if (ret < 0) { - dev_err(asic->dev, "GPIO probe failed\n"); - goto out_irq; - } - - /* Making a per-device copy is only needed for the - * theoretical case of multiple ASIC3s on one board: - */ - memcpy(asic->clocks, asic3_clk_init, sizeof(asic3_clk_init)); - - asic3_mfd_probe(pdev, pdata, mem); - - asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), - (ASIC3_EXTCF_CF0_BUF_EN|ASIC3_EXTCF_CF0_PWAIT_EN), 1); - - dev_info(asic->dev, "ASIC3 Core driver\n"); - - return 0; - - out_irq: - asic3_irq_remove(pdev); - - out_unmap: - iounmap(asic->mapping); - - return ret; -} - -static int asic3_remove(struct platform_device *pdev) -{ - struct asic3 *asic = platform_get_drvdata(pdev); - - asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), - (ASIC3_EXTCF_CF0_BUF_EN|ASIC3_EXTCF_CF0_PWAIT_EN), 0); - - asic3_mfd_remove(pdev); - - asic3_gpio_remove(pdev); - - asic3_irq_remove(pdev); - - asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), 0); - - iounmap(asic->mapping); - - return 0; -} - -static void asic3_shutdown(struct platform_device *pdev) -{ -} - -static struct platform_driver asic3_device_driver = { - .driver = { - .name = "asic3", - }, - .remove = asic3_remove, - .shutdown = asic3_shutdown, -}; - -static int __init asic3_init(void) -{ - int retval = 0; - - retval = platform_driver_probe(&asic3_device_driver, asic3_probe); - - return retval; -} - -subsys_initcall(asic3_init); diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c deleted file mode 100644 index 1d9d1d38d068..000000000000 --- a/drivers/mfd/t7l66xb.c +++ /dev/null @@ -1,427 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * - * Toshiba T7L66XB core mfd support - * - * Copyright (c) 2005, 2007, 2008 Ian Molton - * Copyright (c) 2008 Dmitry Baryshkov - * - * T7L66 features: - * - * Supported in this driver: - * SD/MMC - * SM/NAND flash controller - * - * As yet not supported - * GPIO interface (on NAND pins) - * Serial interface - * TFT 'interface converter' - * PCMCIA interface logic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -enum { - T7L66XB_CELL_NAND, - T7L66XB_CELL_MMC, -}; - -static const struct resource t7l66xb_mmc_resources[] = { - DEFINE_RES_MEM(0x800, 0x200), - DEFINE_RES_IRQ(IRQ_T7L66XB_MMC) -}; - -#define SCR_REVID 0x08 /* b Revision ID */ -#define SCR_IMR 0x42 /* b Interrupt Mask */ -#define SCR_DEV_CTL 0xe0 /* b Device control */ -#define SCR_ISR 0xe1 /* b Interrupt Status */ -#define SCR_GPO_OC 0xf0 /* b GPO output control */ -#define SCR_GPO_OS 0xf1 /* b GPO output enable */ -#define SCR_GPI_S 0xf2 /* w GPI status */ -#define SCR_APDC 0xf8 /* b Active pullup down ctrl */ - -#define SCR_DEV_CTL_USB BIT(0) /* USB enable */ -#define SCR_DEV_CTL_MMC BIT(1) /* MMC enable */ - -/*--------------------------------------------------------------------------*/ - -struct t7l66xb { - void __iomem *scr; - /* Lock to protect registers requiring read/modify/write ops. */ - raw_spinlock_t lock; - - struct resource rscr; - struct clk *clk48m; - struct clk *clk32k; - int irq; - int irq_base; -}; - -/*--------------------------------------------------------------------------*/ - -static int t7l66xb_mmc_enable(struct platform_device *mmc) -{ - struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent); - unsigned long flags; - u8 dev_ctl; - int ret; - - ret = clk_prepare_enable(t7l66xb->clk32k); - if (ret) - return ret; - - raw_spin_lock_irqsave(&t7l66xb->lock, flags); - - dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL); - dev_ctl |= SCR_DEV_CTL_MMC; - tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL); - - raw_spin_unlock_irqrestore(&t7l66xb->lock, flags); - - tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0, - t7l66xb_mmc_resources[0].start & 0xfffe); - - return 0; -} - -static int t7l66xb_mmc_disable(struct platform_device *mmc) -{ - struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent); - unsigned long flags; - u8 dev_ctl; - - raw_spin_lock_irqsave(&t7l66xb->lock, flags); - - dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL); - dev_ctl &= ~SCR_DEV_CTL_MMC; - tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL); - - raw_spin_unlock_irqrestore(&t7l66xb->lock, flags); - - clk_disable_unprepare(t7l66xb->clk32k); - - return 0; -} - -static void t7l66xb_mmc_pwr(struct platform_device *mmc, int state) -{ - struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent); - - tmio_core_mmc_pwr(t7l66xb->scr + 0x200, 0, state); -} - -static void t7l66xb_mmc_clk_div(struct platform_device *mmc, int state) -{ - struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent); - - tmio_core_mmc_clk_div(t7l66xb->scr + 0x200, 0, state); -} - -/*--------------------------------------------------------------------------*/ - -static struct tmio_mmc_data t7166xb_mmc_data = { - .hclk = 24000000, - .set_pwr = t7l66xb_mmc_pwr, - .set_clk_div = t7l66xb_mmc_clk_div, -}; - -static const struct resource t7l66xb_nand_resources[] = { - { - .start = 0xc00, - .end = 0xc07, - .flags = IORESOURCE_MEM, - }, - { - .start = 0x0100, - .end = 0x01ff, - .flags = IORESOURCE_MEM, - }, - { - .start = IRQ_T7L66XB_NAND, - .end = IRQ_T7L66XB_NAND, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct mfd_cell t7l66xb_cells[] = { - [T7L66XB_CELL_MMC] = { - .name = "tmio-mmc", - .enable = t7l66xb_mmc_enable, - .disable = t7l66xb_mmc_disable, - .platform_data = &t7166xb_mmc_data, - .pdata_size = sizeof(t7166xb_mmc_data), - .num_resources = ARRAY_SIZE(t7l66xb_mmc_resources), - .resources = t7l66xb_mmc_resources, - }, - [T7L66XB_CELL_NAND] = { - .name = "tmio-nand", - .num_resources = ARRAY_SIZE(t7l66xb_nand_resources), - .resources = t7l66xb_nand_resources, - }, -}; - -/*--------------------------------------------------------------------------*/ - -/* Handle the T7L66XB interrupt mux */ -static void t7l66xb_irq(struct irq_desc *desc) -{ - struct t7l66xb *t7l66xb = irq_desc_get_handler_data(desc); - unsigned int isr; - unsigned int i, irq_base; - - irq_base = t7l66xb->irq_base; - - while ((isr = tmio_ioread8(t7l66xb->scr + SCR_ISR) & - ~tmio_ioread8(t7l66xb->scr + SCR_IMR))) - for (i = 0; i < T7L66XB_NR_IRQS; i++) - if (isr & (1 << i)) - generic_handle_irq(irq_base + i); -} - -static void t7l66xb_irq_mask(struct irq_data *data) -{ - struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data); - unsigned long flags; - u8 imr; - - raw_spin_lock_irqsave(&t7l66xb->lock, flags); - imr = tmio_ioread8(t7l66xb->scr + SCR_IMR); - imr |= 1 << (data->irq - t7l66xb->irq_base); - tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR); - raw_spin_unlock_irqrestore(&t7l66xb->lock, flags); -} - -static void t7l66xb_irq_unmask(struct irq_data *data) -{ - struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data); - unsigned long flags; - u8 imr; - - raw_spin_lock_irqsave(&t7l66xb->lock, flags); - imr = tmio_ioread8(t7l66xb->scr + SCR_IMR); - imr &= ~(1 << (data->irq - t7l66xb->irq_base)); - tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR); - raw_spin_unlock_irqrestore(&t7l66xb->lock, flags); -} - -static struct irq_chip t7l66xb_chip = { - .name = "t7l66xb", - .irq_ack = t7l66xb_irq_mask, - .irq_mask = t7l66xb_irq_mask, - .irq_unmask = t7l66xb_irq_unmask, -}; - -/*--------------------------------------------------------------------------*/ - -/* Install the IRQ handler */ -static void t7l66xb_attach_irq(struct platform_device *dev) -{ - struct t7l66xb *t7l66xb = platform_get_drvdata(dev); - unsigned int irq, irq_base; - - irq_base = t7l66xb->irq_base; - - for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { - irq_set_chip_and_handler(irq, &t7l66xb_chip, handle_level_irq); - irq_set_chip_data(irq, t7l66xb); - } - - irq_set_irq_type(t7l66xb->irq, IRQ_TYPE_EDGE_FALLING); - irq_set_chained_handler_and_data(t7l66xb->irq, t7l66xb_irq, t7l66xb); -} - -static void t7l66xb_detach_irq(struct platform_device *dev) -{ - struct t7l66xb *t7l66xb = platform_get_drvdata(dev); - unsigned int irq, irq_base; - - irq_base = t7l66xb->irq_base; - - irq_set_chained_handler_and_data(t7l66xb->irq, NULL, NULL); - - for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { - irq_set_chip(irq, NULL); - irq_set_chip_data(irq, NULL); - } -} - -/*--------------------------------------------------------------------------*/ - -static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state) -{ - struct t7l66xb *t7l66xb = platform_get_drvdata(dev); - struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev); - - if (pdata && pdata->suspend) - pdata->suspend(dev); - clk_disable_unprepare(t7l66xb->clk48m); - - return 0; -} - -static int t7l66xb_resume(struct platform_device *dev) -{ - struct t7l66xb *t7l66xb = platform_get_drvdata(dev); - struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev); - int ret; - - ret = clk_prepare_enable(t7l66xb->clk48m); - if (ret) - return ret; - - if (pdata && pdata->resume) - pdata->resume(dev); - - tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0, - t7l66xb_mmc_resources[0].start & 0xfffe); - - return 0; -} - -/*--------------------------------------------------------------------------*/ - -static int t7l66xb_probe(struct platform_device *dev) -{ - struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev); - struct t7l66xb *t7l66xb; - struct resource *iomem, *rscr; - int ret; - - if (!pdata) - return -EINVAL; - - iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!iomem) - return -EINVAL; - - t7l66xb = kzalloc(sizeof *t7l66xb, GFP_KERNEL); - if (!t7l66xb) - return -ENOMEM; - - raw_spin_lock_init(&t7l66xb->lock); - - platform_set_drvdata(dev, t7l66xb); - - ret = platform_get_irq(dev, 0); - if (ret >= 0) - t7l66xb->irq = ret; - else - goto err_noirq; - - t7l66xb->irq_base = pdata->irq_base; - - t7l66xb->clk32k = clk_get(&dev->dev, "CLK_CK32K"); - if (IS_ERR(t7l66xb->clk32k)) { - ret = PTR_ERR(t7l66xb->clk32k); - goto err_clk32k_get; - } - - t7l66xb->clk48m = clk_get(&dev->dev, "CLK_CK48M"); - if (IS_ERR(t7l66xb->clk48m)) { - ret = PTR_ERR(t7l66xb->clk48m); - goto err_clk48m_get; - } - - rscr = &t7l66xb->rscr; - rscr->name = "t7l66xb-core"; - rscr->start = iomem->start; - rscr->end = iomem->start + 0xff; - rscr->flags = IORESOURCE_MEM; - - ret = request_resource(iomem, rscr); - if (ret) - goto err_request_scr; - - t7l66xb->scr = ioremap(rscr->start, resource_size(rscr)); - if (!t7l66xb->scr) { - ret = -ENOMEM; - goto err_ioremap; - } - - ret = clk_prepare_enable(t7l66xb->clk48m); - if (ret) - goto err_clk_enable; - - if (pdata->enable) - pdata->enable(dev); - - /* Mask all interrupts */ - tmio_iowrite8(0xbf, t7l66xb->scr + SCR_IMR); - - printk(KERN_INFO "%s rev %d @ 0x%08lx, irq %d\n", - dev->name, tmio_ioread8(t7l66xb->scr + SCR_REVID), - (unsigned long)iomem->start, t7l66xb->irq); - - t7l66xb_attach_irq(dev); - - t7l66xb_cells[T7L66XB_CELL_NAND].platform_data = pdata->nand_data; - t7l66xb_cells[T7L66XB_CELL_NAND].pdata_size = sizeof(*pdata->nand_data); - - ret = mfd_add_devices(&dev->dev, dev->id, - t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells), - iomem, t7l66xb->irq_base, NULL); - - if (!ret) - return 0; - - t7l66xb_detach_irq(dev); - clk_disable_unprepare(t7l66xb->clk48m); -err_clk_enable: - iounmap(t7l66xb->scr); -err_ioremap: - release_resource(&t7l66xb->rscr); -err_request_scr: - clk_put(t7l66xb->clk48m); -err_clk48m_get: - clk_put(t7l66xb->clk32k); -err_clk32k_get: -err_noirq: - kfree(t7l66xb); - return ret; -} - -static int t7l66xb_remove(struct platform_device *dev) -{ - struct t7l66xb *t7l66xb = platform_get_drvdata(dev); - - clk_disable_unprepare(t7l66xb->clk48m); - clk_put(t7l66xb->clk48m); - clk_disable_unprepare(t7l66xb->clk32k); - clk_put(t7l66xb->clk32k); - t7l66xb_detach_irq(dev); - iounmap(t7l66xb->scr); - release_resource(&t7l66xb->rscr); - mfd_remove_devices(&dev->dev); - kfree(t7l66xb); - - return 0; -} - -static struct platform_driver t7l66xb_platform_driver = { - .driver = { - .name = "t7l66xb", - }, - .suspend = pm_sleep_ptr(t7l66xb_suspend), - .resume = pm_sleep_ptr(t7l66xb_resume), - .probe = t7l66xb_probe, - .remove = t7l66xb_remove, -}; - -/*--------------------------------------------------------------------------*/ - -module_platform_driver(t7l66xb_platform_driver); - -MODULE_DESCRIPTION("Toshiba T7L66XB core driver"); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Ian Molton"); -MODULE_ALIAS("platform:t7l66xb"); diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c deleted file mode 100644 index 5392da6ba7b0..000000000000 --- a/drivers/mfd/tc6387xb.c +++ /dev/null @@ -1,228 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Toshiba TC6387XB support - * Copyright (c) 2005 Ian Molton - * - * This file contains TC6387XB base support. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -enum { - TC6387XB_CELL_MMC, -}; - -struct tc6387xb { - void __iomem *scr; - struct clk *clk32k; - struct resource rscr; -}; - -static const struct resource tc6387xb_mmc_resources[] = { - { - .start = 0x800, - .end = 0x9ff, - .flags = IORESOURCE_MEM, - }, - { - .start = 0, - .end = 0, - .flags = IORESOURCE_IRQ, - }, -}; - -/*--------------------------------------------------------------------------*/ - -static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state) -{ - struct tc6387xb *tc6387xb = platform_get_drvdata(dev); - struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev); - - if (pdata && pdata->suspend) - pdata->suspend(dev); - clk_disable_unprepare(tc6387xb->clk32k); - - return 0; -} - -static int tc6387xb_resume(struct platform_device *dev) -{ - struct tc6387xb *tc6387xb = platform_get_drvdata(dev); - struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev); - - clk_prepare_enable(tc6387xb->clk32k); - if (pdata && pdata->resume) - pdata->resume(dev); - - tmio_core_mmc_resume(tc6387xb->scr + 0x200, 0, - tc6387xb_mmc_resources[0].start & 0xfffe); - - return 0; -} - -/*--------------------------------------------------------------------------*/ - -static void tc6387xb_mmc_pwr(struct platform_device *mmc, int state) -{ - struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent); - - tmio_core_mmc_pwr(tc6387xb->scr + 0x200, 0, state); -} - -static void tc6387xb_mmc_clk_div(struct platform_device *mmc, int state) -{ - struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent); - - tmio_core_mmc_clk_div(tc6387xb->scr + 0x200, 0, state); -} - - -static int tc6387xb_mmc_enable(struct platform_device *mmc) -{ - struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent); - - clk_prepare_enable(tc6387xb->clk32k); - - tmio_core_mmc_enable(tc6387xb->scr + 0x200, 0, - tc6387xb_mmc_resources[0].start & 0xfffe); - - return 0; -} - -static int tc6387xb_mmc_disable(struct platform_device *mmc) -{ - struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent); - - clk_disable_unprepare(tc6387xb->clk32k); - - return 0; -} - -static struct tmio_mmc_data tc6387xb_mmc_data = { - .hclk = 24000000, - .set_pwr = tc6387xb_mmc_pwr, - .set_clk_div = tc6387xb_mmc_clk_div, -}; - -/*--------------------------------------------------------------------------*/ - -static const struct mfd_cell tc6387xb_cells[] = { - [TC6387XB_CELL_MMC] = { - .name = "tmio-mmc", - .enable = tc6387xb_mmc_enable, - .disable = tc6387xb_mmc_disable, - .platform_data = &tc6387xb_mmc_data, - .pdata_size = sizeof(tc6387xb_mmc_data), - .num_resources = ARRAY_SIZE(tc6387xb_mmc_resources), - .resources = tc6387xb_mmc_resources, - }, -}; - -static int tc6387xb_probe(struct platform_device *dev) -{ - struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev); - struct resource *iomem, *rscr; - struct clk *clk32k; - struct tc6387xb *tc6387xb; - int irq, ret; - - iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!iomem) - return -EINVAL; - - tc6387xb = kzalloc(sizeof(*tc6387xb), GFP_KERNEL); - if (!tc6387xb) - return -ENOMEM; - - ret = platform_get_irq(dev, 0); - if (ret >= 0) - irq = ret; - else - goto err_no_irq; - - clk32k = clk_get(&dev->dev, "CLK_CK32K"); - if (IS_ERR(clk32k)) { - ret = PTR_ERR(clk32k); - goto err_no_clk; - } - - rscr = &tc6387xb->rscr; - rscr->name = "tc6387xb-core"; - rscr->start = iomem->start; - rscr->end = iomem->start + 0xff; - rscr->flags = IORESOURCE_MEM; - - ret = request_resource(iomem, rscr); - if (ret) - goto err_resource; - - tc6387xb->scr = ioremap(rscr->start, resource_size(rscr)); - if (!tc6387xb->scr) { - ret = -ENOMEM; - goto err_ioremap; - } - - tc6387xb->clk32k = clk32k; - platform_set_drvdata(dev, tc6387xb); - - if (pdata && pdata->enable) - pdata->enable(dev); - - dev_info(&dev->dev, "Toshiba tc6387xb initialised\n"); - - ret = mfd_add_devices(&dev->dev, dev->id, tc6387xb_cells, - ARRAY_SIZE(tc6387xb_cells), iomem, irq, NULL); - - if (!ret) - return 0; - - iounmap(tc6387xb->scr); -err_ioremap: - release_resource(&tc6387xb->rscr); -err_resource: - clk_put(clk32k); -err_no_clk: -err_no_irq: - kfree(tc6387xb); - return ret; -} - -static int tc6387xb_remove(struct platform_device *dev) -{ - struct tc6387xb *tc6387xb = platform_get_drvdata(dev); - - mfd_remove_devices(&dev->dev); - iounmap(tc6387xb->scr); - release_resource(&tc6387xb->rscr); - clk_disable_unprepare(tc6387xb->clk32k); - clk_put(tc6387xb->clk32k); - kfree(tc6387xb); - - return 0; -} - - -static struct platform_driver tc6387xb_platform_driver = { - .driver = { - .name = "tc6387xb", - }, - .probe = tc6387xb_probe, - .remove = tc6387xb_remove, - .suspend = pm_sleep_ptr(tc6387xb_suspend), - .resume = pm_sleep_ptr(tc6387xb_resume), -}; - -module_platform_driver(tc6387xb_platform_driver); - -MODULE_DESCRIPTION("Toshiba TC6387XB core driver"); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Ian Molton"); -MODULE_ALIAS("platform:tc6387xb"); - diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c deleted file mode 100644 index 997bb8b5881d..000000000000 --- a/drivers/mfd/tc6393xb.c +++ /dev/null @@ -1,907 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Toshiba TC6393XB SoC support - * - * Copyright(c) 2005-2006 Chris Humbert - * Copyright(c) 2005 Dirk Opfer - * Copyright(c) 2005 Ian Molton - * Copyright(c) 2007 Dmitry Baryshkov - * - * Based on code written by Sharp/Lineo for 2.4 kernels - * Based on locomo.c - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SCR_REVID 0x08 /* b Revision ID */ -#define SCR_ISR 0x50 /* b Interrupt Status */ -#define SCR_IMR 0x52 /* b Interrupt Mask */ -#define SCR_IRR 0x54 /* b Interrupt Routing */ -#define SCR_GPER 0x60 /* w GP Enable */ -#define SCR_GPI_SR(i) (0x64 + (i)) /* b3 GPI Status */ -#define SCR_GPI_IMR(i) (0x68 + (i)) /* b3 GPI INT Mask */ -#define SCR_GPI_EDER(i) (0x6c + (i)) /* b3 GPI Edge Detect Enable */ -#define SCR_GPI_LIR(i) (0x70 + (i)) /* b3 GPI Level Invert */ -#define SCR_GPO_DSR(i) (0x78 + (i)) /* b3 GPO Data Set */ -#define SCR_GPO_DOECR(i) (0x7c + (i)) /* b3 GPO Data OE Control */ -#define SCR_GP_IARCR(i) (0x80 + (i)) /* b3 GP Internal Active Register Control */ -#define SCR_GP_IARLCR(i) (0x84 + (i)) /* b3 GP INTERNAL Active Register Level Control */ -#define SCR_GPI_BCR(i) (0x88 + (i)) /* b3 GPI Buffer Control */ -#define SCR_GPA_IARCR 0x8c /* w GPa Internal Active Register Control */ -#define SCR_GPA_IARLCR 0x90 /* w GPa Internal Active Register Level Control */ -#define SCR_GPA_BCR 0x94 /* w GPa Buffer Control */ -#define SCR_CCR 0x98 /* w Clock Control */ -#define SCR_PLL2CR 0x9a /* w PLL2 Control */ -#define SCR_PLL1CR 0x9c /* l PLL1 Control */ -#define SCR_DIARCR 0xa0 /* b Device Internal Active Register Control */ -#define SCR_DBOCR 0xa1 /* b Device Buffer Off Control */ -#define SCR_FER 0xe0 /* b Function Enable */ -#define SCR_MCR 0xe4 /* w Mode Control */ -#define SCR_CONFIG 0xfc /* b Configuration Control */ -#define SCR_DEBUG 0xff /* b Debug */ - -#define SCR_CCR_CK32K BIT(0) -#define SCR_CCR_USBCK BIT(1) -#define SCR_CCR_UNK1 BIT(4) -#define SCR_CCR_MCLK_MASK (7 << 8) -#define SCR_CCR_MCLK_OFF (0 << 8) -#define SCR_CCR_MCLK_12 (1 << 8) -#define SCR_CCR_MCLK_24 (2 << 8) -#define SCR_CCR_MCLK_48 (3 << 8) -#define SCR_CCR_HCLK_MASK (3 << 12) -#define SCR_CCR_HCLK_24 (0 << 12) -#define SCR_CCR_HCLK_48 (1 << 12) - -#define SCR_FER_USBEN BIT(0) /* USB host enable */ -#define SCR_FER_LCDCVEN BIT(1) /* polysilicon TFT enable */ -#define SCR_FER_SLCDEN BIT(2) /* SLCD enable */ - -#define SCR_MCR_RDY_MASK (3 << 0) -#define SCR_MCR_RDY_OPENDRAIN (0 << 0) -#define SCR_MCR_RDY_TRISTATE (1 << 0) -#define SCR_MCR_RDY_PUSHPULL (2 << 0) -#define SCR_MCR_RDY_UNK BIT(2) -#define SCR_MCR_RDY_EN BIT(3) -#define SCR_MCR_INT_MASK (3 << 4) -#define SCR_MCR_INT_OPENDRAIN (0 << 4) -#define SCR_MCR_INT_TRISTATE (1 << 4) -#define SCR_MCR_INT_PUSHPULL (2 << 4) -#define SCR_MCR_INT_UNK BIT(6) -#define SCR_MCR_INT_EN BIT(7) -/* bits 8 - 16 are unknown */ - -#define TC_GPIO_BIT(i) (1 << (i & 0x7)) - -/*--------------------------------------------------------------------------*/ - -struct tc6393xb { - void __iomem *scr; - struct device *dev; - - struct gpio_chip gpio; - struct gpio_desc *vcc_on; - - struct clk *clk; /* 3,6 Mhz */ - - raw_spinlock_t lock; /* protects RMW cycles */ - - struct { - u8 fer; - u16 ccr; - u8 gpi_bcr[3]; - u8 gpo_dsr[3]; - u8 gpo_doecr[3]; - } suspend_state; - - struct resource rscr; - struct resource *iomem; - int irq; - int irq_base; -}; - -enum { - TC6393XB_CELL_NAND, - TC6393XB_CELL_MMC, - TC6393XB_CELL_OHCI, - TC6393XB_CELL_FB, -}; - -/*--------------------------------------------------------------------------*/ - -static int tc6393xb_nand_enable(struct platform_device *nand) -{ - struct tc6393xb *tc6393xb = dev_get_drvdata(nand->dev.parent); - unsigned long flags; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - - /* SMD buffer on */ - dev_dbg(nand->dev.parent, "SMD buffer on\n"); - tmio_iowrite8(0xff, tc6393xb->scr + SCR_GPI_BCR(1)); - - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); - - return 0; -} - -static const struct resource tc6393xb_nand_resources[] = { - { - .start = 0x1000, - .end = 0x1007, - .flags = IORESOURCE_MEM, - }, - { - .start = 0x0100, - .end = 0x01ff, - .flags = IORESOURCE_MEM, - }, - { - .start = IRQ_TC6393_NAND, - .end = IRQ_TC6393_NAND, - .flags = IORESOURCE_IRQ, - }, -}; - -static const struct resource tc6393xb_mmc_resources[] = { - { - .start = 0x800, - .end = 0x9ff, - .flags = IORESOURCE_MEM, - }, - { - .start = IRQ_TC6393_MMC, - .end = IRQ_TC6393_MMC, - .flags = IORESOURCE_IRQ, - }, -}; - -static const struct resource tc6393xb_ohci_resources[] = { - { - .start = 0x3000, - .end = 0x31ff, - .flags = IORESOURCE_MEM, - }, - { - .start = 0x0300, - .end = 0x03ff, - .flags = IORESOURCE_MEM, - }, - { - .start = 0x010000, - .end = 0x017fff, - .flags = IORESOURCE_MEM, - }, - { - .start = 0x018000, - .end = 0x01ffff, - .flags = IORESOURCE_MEM, - }, - { - .start = IRQ_TC6393_OHCI, - .end = IRQ_TC6393_OHCI, - .flags = IORESOURCE_IRQ, - }, -}; - -static const struct resource tc6393xb_fb_resources[] = { - { - .start = 0x5000, - .end = 0x51ff, - .flags = IORESOURCE_MEM, - }, - { - .start = 0x0500, - .end = 0x05ff, - .flags = IORESOURCE_MEM, - }, - { - .start = 0x100000, - .end = 0x1fffff, - .flags = IORESOURCE_MEM, - }, - { - .start = IRQ_TC6393_FB, - .end = IRQ_TC6393_FB, - .flags = IORESOURCE_IRQ, - }, -}; - -static int tc6393xb_ohci_enable(struct platform_device *dev) -{ - struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); - unsigned long flags; - u16 ccr; - u8 fer; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - - ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); - ccr |= SCR_CCR_USBCK; - tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); - - fer = tmio_ioread8(tc6393xb->scr + SCR_FER); - fer |= SCR_FER_USBEN; - tmio_iowrite8(fer, tc6393xb->scr + SCR_FER); - - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); - - return 0; -} - -static int tc6393xb_ohci_disable(struct platform_device *dev) -{ - struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); - unsigned long flags; - u16 ccr; - u8 fer; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - - fer = tmio_ioread8(tc6393xb->scr + SCR_FER); - fer &= ~SCR_FER_USBEN; - tmio_iowrite8(fer, tc6393xb->scr + SCR_FER); - - ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); - ccr &= ~SCR_CCR_USBCK; - tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); - - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); - - return 0; -} - -static int tc6393xb_ohci_suspend(struct platform_device *dev) -{ - struct tc6393xb_platform_data *tcpd = dev_get_platdata(dev->dev.parent); - - /* We can't properly store/restore OHCI state, so fail here */ - if (tcpd->resume_restore) - return -EBUSY; - - return tc6393xb_ohci_disable(dev); -} - -static int tc6393xb_fb_enable(struct platform_device *dev) -{ - struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); - unsigned long flags; - u16 ccr; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - - ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); - ccr &= ~SCR_CCR_MCLK_MASK; - ccr |= SCR_CCR_MCLK_48; - tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); - - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); - - return 0; -} - -static int tc6393xb_fb_disable(struct platform_device *dev) -{ - struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent); - unsigned long flags; - u16 ccr; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - - ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR); - ccr &= ~SCR_CCR_MCLK_MASK; - ccr |= SCR_CCR_MCLK_OFF; - tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR); - - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); - - return 0; -} - -int tc6393xb_lcd_set_power(struct platform_device *fb, bool on) -{ - struct tc6393xb *tc6393xb = dev_get_drvdata(fb->dev.parent); - u8 fer; - unsigned long flags; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - - fer = ioread8(tc6393xb->scr + SCR_FER); - if (on) - fer |= SCR_FER_SLCDEN; - else - fer &= ~SCR_FER_SLCDEN; - iowrite8(fer, tc6393xb->scr + SCR_FER); - - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); - - return 0; -} -EXPORT_SYMBOL(tc6393xb_lcd_set_power); - -int tc6393xb_lcd_mode(struct platform_device *fb, - const struct fb_videomode *mode) { - struct tc6393xb *tc6393xb = dev_get_drvdata(fb->dev.parent); - unsigned long flags; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - - iowrite16(mode->pixclock, tc6393xb->scr + SCR_PLL1CR + 0); - iowrite16(mode->pixclock >> 16, tc6393xb->scr + SCR_PLL1CR + 2); - - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); - - return 0; -} -EXPORT_SYMBOL(tc6393xb_lcd_mode); - -static int tc6393xb_mmc_enable(struct platform_device *mmc) -{ - struct tc6393xb *tc6393xb = dev_get_drvdata(mmc->dev.parent); - - tmio_core_mmc_enable(tc6393xb->scr + 0x200, 0, - tc6393xb_mmc_resources[0].start & 0xfffe); - - return 0; -} - -static int tc6393xb_mmc_resume(struct platform_device *mmc) -{ - struct tc6393xb *tc6393xb = dev_get_drvdata(mmc->dev.parent); - - tmio_core_mmc_resume(tc6393xb->scr + 0x200, 0, - tc6393xb_mmc_resources[0].start & 0xfffe); - - return 0; -} - -static void tc6393xb_mmc_pwr(struct platform_device *mmc, int state) -{ - struct tc6393xb *tc6393xb = dev_get_drvdata(mmc->dev.parent); - - tmio_core_mmc_pwr(tc6393xb->scr + 0x200, 0, state); -} - -static void tc6393xb_mmc_clk_div(struct platform_device *mmc, int state) -{ - struct tc6393xb *tc6393xb = dev_get_drvdata(mmc->dev.parent); - - tmio_core_mmc_clk_div(tc6393xb->scr + 0x200, 0, state); -} - -static struct tmio_mmc_data tc6393xb_mmc_data = { - .hclk = 24000000, - .set_pwr = tc6393xb_mmc_pwr, - .set_clk_div = tc6393xb_mmc_clk_div, -}; - -static struct mfd_cell tc6393xb_cells[] = { - [TC6393XB_CELL_NAND] = { - .name = "tmio-nand", - .enable = tc6393xb_nand_enable, - .num_resources = ARRAY_SIZE(tc6393xb_nand_resources), - .resources = tc6393xb_nand_resources, - }, - [TC6393XB_CELL_MMC] = { - .name = "tmio-mmc", - .enable = tc6393xb_mmc_enable, - .resume = tc6393xb_mmc_resume, - .platform_data = &tc6393xb_mmc_data, - .pdata_size = sizeof(tc6393xb_mmc_data), - .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources), - .resources = tc6393xb_mmc_resources, - }, - [TC6393XB_CELL_OHCI] = { - .name = "tmio-ohci", - .num_resources = ARRAY_SIZE(tc6393xb_ohci_resources), - .resources = tc6393xb_ohci_resources, - .enable = tc6393xb_ohci_enable, - .suspend = tc6393xb_ohci_suspend, - .resume = tc6393xb_ohci_enable, - .disable = tc6393xb_ohci_disable, - }, - [TC6393XB_CELL_FB] = { - .name = "tmio-fb", - .num_resources = ARRAY_SIZE(tc6393xb_fb_resources), - .resources = tc6393xb_fb_resources, - .enable = tc6393xb_fb_enable, - .suspend = tc6393xb_fb_disable, - .resume = tc6393xb_fb_enable, - .disable = tc6393xb_fb_disable, - }, -}; - -/*--------------------------------------------------------------------------*/ - -static int tc6393xb_gpio_get(struct gpio_chip *chip, - unsigned offset) -{ - struct tc6393xb *tc6393xb = gpiochip_get_data(chip); - - /* XXX: does dsr also represent inputs? */ - return !!(tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)) - & TC_GPIO_BIT(offset)); -} - -static void __tc6393xb_gpio_set(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct tc6393xb *tc6393xb = gpiochip_get_data(chip); - u8 dsr; - - dsr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8)); - if (value) - dsr |= TC_GPIO_BIT(offset); - else - dsr &= ~TC_GPIO_BIT(offset); - - tmio_iowrite8(dsr, tc6393xb->scr + SCR_GPO_DSR(offset / 8)); -} - -static void tc6393xb_gpio_set(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct tc6393xb *tc6393xb = gpiochip_get_data(chip); - unsigned long flags; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - - __tc6393xb_gpio_set(chip, offset, value); - - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); -} - -static int tc6393xb_gpio_direction_input(struct gpio_chip *chip, - unsigned offset) -{ - struct tc6393xb *tc6393xb = gpiochip_get_data(chip); - unsigned long flags; - u8 doecr; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - - doecr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); - doecr &= ~TC_GPIO_BIT(offset); - tmio_iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); - - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); - - return 0; -} - -static int tc6393xb_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct tc6393xb *tc6393xb = gpiochip_get_data(chip); - unsigned long flags; - u8 doecr; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - - __tc6393xb_gpio_set(chip, offset, value); - - doecr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); - doecr |= TC_GPIO_BIT(offset); - tmio_iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8)); - - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); - - return 0; -} - -/* - * TC6393XB GPIOs as used on TOSA, are the only user of this chip. - * GPIOs 2, 5, 8 and 13 are not connected. - */ -#define TOSA_GPIO_TG_ON 0 -#define TOSA_GPIO_L_MUTE 1 -#define TOSA_GPIO_BL_C20MA 3 -#define TOSA_GPIO_CARD_VCC_ON 4 -#define TOSA_GPIO_CHARGE_OFF 6 -#define TOSA_GPIO_CHARGE_OFF_JC 7 -#define TOSA_GPIO_BAT0_V_ON 9 -#define TOSA_GPIO_BAT1_V_ON 10 -#define TOSA_GPIO_BU_CHRG_ON 11 -#define TOSA_GPIO_BAT_SW_ON 12 -#define TOSA_GPIO_BAT0_TH_ON 14 -#define TOSA_GPIO_BAT1_TH_ON 15 - - -GPIO_LOOKUP_SINGLE(tosa_lcd_gpio_lookup, "spi2.0", "tc6393xb", - TOSA_GPIO_TG_ON, "tg #pwr", GPIO_ACTIVE_HIGH); - -GPIO_LOOKUP_SINGLE(tosa_lcd_bl_gpio_lookup, "i2c-tos-bl", "tc6393xb", - TOSA_GPIO_BL_C20MA, "backlight", GPIO_ACTIVE_HIGH); - -GPIO_LOOKUP_SINGLE(tosa_audio_gpio_lookup, "tosa-audio", "tc6393xb", - TOSA_GPIO_L_MUTE, NULL, GPIO_ACTIVE_HIGH); - -static struct gpiod_lookup_table tosa_battery_gpio_lookup = { - .dev_id = "wm97xx-battery", - .table = { - GPIO_LOOKUP("tc6393xb", TOSA_GPIO_CHARGE_OFF, - "main charge off", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("tc6393xb", TOSA_GPIO_CHARGE_OFF_JC, - "jacket charge off", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BAT0_V_ON, - "main battery", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BAT1_V_ON, - "jacket battery", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BU_CHRG_ON, - "backup battery", GPIO_ACTIVE_HIGH), - /* BAT1 and BAT0 thermistors appear to be swapped */ - GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BAT1_TH_ON, - "main battery temp", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BAT0_TH_ON, - "jacket battery temp", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BAT_SW_ON, - "battery switch", GPIO_ACTIVE_HIGH), - { }, - }, -}; - -static struct gpiod_lookup_table *tc6393xb_gpio_lookups[] = { - &tosa_lcd_gpio_lookup, - &tosa_lcd_bl_gpio_lookup, - &tosa_audio_gpio_lookup, - &tosa_battery_gpio_lookup, -}; - -static int tc6393xb_register_gpio(struct tc6393xb *tc6393xb) -{ - struct gpio_chip *gc = &tc6393xb->gpio; - struct device *dev = tc6393xb->dev; - int ret; - - gc->label = "tc6393xb"; - gc->base = -1; /* Dynamic allocation */ - gc->ngpio = 16; - gc->set = tc6393xb_gpio_set; - gc->get = tc6393xb_gpio_get; - gc->direction_input = tc6393xb_gpio_direction_input; - gc->direction_output = tc6393xb_gpio_direction_output; - - ret = devm_gpiochip_add_data(dev, gc, tc6393xb); - if (ret) - return dev_err_probe(dev, ret, "failed to add GPIO chip\n"); - - /* Register descriptor look-ups for consumers */ - gpiod_add_lookup_tables(tc6393xb_gpio_lookups, ARRAY_SIZE(tc6393xb_gpio_lookups)); - - /* Request some of our own GPIOs */ - tc6393xb->vcc_on = gpiochip_request_own_desc(gc, TOSA_GPIO_CARD_VCC_ON, "VCC ON", - GPIO_ACTIVE_HIGH, GPIOD_OUT_HIGH); - if (IS_ERR(tc6393xb->vcc_on)) - return dev_err_probe(dev, PTR_ERR(tc6393xb->vcc_on), - "failed to request VCC ON GPIO\n"); - - return 0; -} - -/*--------------------------------------------------------------------------*/ - -static void tc6393xb_irq(struct irq_desc *desc) -{ - struct tc6393xb *tc6393xb = irq_desc_get_handler_data(desc); - unsigned int isr; - unsigned int i, irq_base; - - irq_base = tc6393xb->irq_base; - - while ((isr = tmio_ioread8(tc6393xb->scr + SCR_ISR) & - ~tmio_ioread8(tc6393xb->scr + SCR_IMR))) - for (i = 0; i < TC6393XB_NR_IRQS; i++) { - if (isr & (1 << i)) - generic_handle_irq(irq_base + i); - } -} - -static void tc6393xb_irq_ack(struct irq_data *data) -{ -} - -static void tc6393xb_irq_mask(struct irq_data *data) -{ - struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data); - unsigned long flags; - u8 imr; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); - imr |= 1 << (data->irq - tc6393xb->irq_base); - tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); -} - -static void tc6393xb_irq_unmask(struct irq_data *data) -{ - struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data); - unsigned long flags; - u8 imr; - - raw_spin_lock_irqsave(&tc6393xb->lock, flags); - imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); - imr &= ~(1 << (data->irq - tc6393xb->irq_base)); - tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); - raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); -} - -static struct irq_chip tc6393xb_chip = { - .name = "tc6393xb", - .irq_ack = tc6393xb_irq_ack, - .irq_mask = tc6393xb_irq_mask, - .irq_unmask = tc6393xb_irq_unmask, -}; - -static void tc6393xb_attach_irq(struct platform_device *dev) -{ - struct tc6393xb *tc6393xb = platform_get_drvdata(dev); - unsigned int irq, irq_base; - - irq_base = tc6393xb->irq_base; - - for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { - irq_set_chip_and_handler(irq, &tc6393xb_chip, handle_edge_irq); - irq_set_chip_data(irq, tc6393xb); - irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); - } - - irq_set_irq_type(tc6393xb->irq, IRQ_TYPE_EDGE_FALLING); - irq_set_chained_handler_and_data(tc6393xb->irq, tc6393xb_irq, - tc6393xb); -} - -static void tc6393xb_detach_irq(struct platform_device *dev) -{ - struct tc6393xb *tc6393xb = platform_get_drvdata(dev); - unsigned int irq, irq_base; - - irq_set_chained_handler_and_data(tc6393xb->irq, NULL, NULL); - - irq_base = tc6393xb->irq_base; - - for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { - irq_set_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); - irq_set_chip(irq, NULL); - irq_set_chip_data(irq, NULL); - } -} - -/*--------------------------------------------------------------------------*/ - -static int tc6393xb_probe(struct platform_device *dev) -{ - struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev); - struct tc6393xb *tc6393xb; - struct resource *iomem, *rscr; - int ret; - - iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!iomem) - return -EINVAL; - - tc6393xb = kzalloc(sizeof *tc6393xb, GFP_KERNEL); - if (!tc6393xb) { - ret = -ENOMEM; - goto err_kzalloc; - } - tc6393xb->dev = &dev->dev; - - raw_spin_lock_init(&tc6393xb->lock); - - platform_set_drvdata(dev, tc6393xb); - - ret = platform_get_irq(dev, 0); - if (ret >= 0) - tc6393xb->irq = ret; - else - goto err_noirq; - - tc6393xb->iomem = iomem; - tc6393xb->irq_base = tcpd->irq_base; - - tc6393xb->clk = clk_get(&dev->dev, "CLK_CK3P6MI"); - if (IS_ERR(tc6393xb->clk)) { - ret = PTR_ERR(tc6393xb->clk); - goto err_clk_get; - } - - rscr = &tc6393xb->rscr; - rscr->name = "tc6393xb-core"; - rscr->start = iomem->start; - rscr->end = iomem->start + 0xff; - rscr->flags = IORESOURCE_MEM; - - ret = request_resource(iomem, rscr); - if (ret) - goto err_request_scr; - - tc6393xb->scr = ioremap(rscr->start, resource_size(rscr)); - if (!tc6393xb->scr) { - ret = -ENOMEM; - goto err_ioremap; - } - - ret = clk_prepare_enable(tc6393xb->clk); - if (ret) - goto err_clk_enable; - - ret = tcpd->enable(dev); - if (ret) - goto err_enable; - - iowrite8(0, tc6393xb->scr + SCR_FER); - iowrite16(tcpd->scr_pll2cr, tc6393xb->scr + SCR_PLL2CR); - iowrite16(SCR_CCR_UNK1 | SCR_CCR_HCLK_48, - tc6393xb->scr + SCR_CCR); - iowrite16(SCR_MCR_RDY_OPENDRAIN | SCR_MCR_RDY_UNK | SCR_MCR_RDY_EN | - SCR_MCR_INT_OPENDRAIN | SCR_MCR_INT_UNK | SCR_MCR_INT_EN | - BIT(15), tc6393xb->scr + SCR_MCR); - iowrite16(tcpd->scr_gper, tc6393xb->scr + SCR_GPER); - iowrite8(0, tc6393xb->scr + SCR_IRR); - iowrite8(0xbf, tc6393xb->scr + SCR_IMR); - - printk(KERN_INFO "Toshiba tc6393xb revision %d at 0x%08lx, irq %d\n", - tmio_ioread8(tc6393xb->scr + SCR_REVID), - (unsigned long) iomem->start, tc6393xb->irq); - - ret = tc6393xb_register_gpio(tc6393xb); - if (ret) - goto err_gpio_add; - - tc6393xb_attach_irq(dev); - - tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = tcpd->nand_data; - tc6393xb_cells[TC6393XB_CELL_NAND].pdata_size = - sizeof(*tcpd->nand_data); - tc6393xb_cells[TC6393XB_CELL_FB].platform_data = tcpd->fb_data; - tc6393xb_cells[TC6393XB_CELL_FB].pdata_size = sizeof(*tcpd->fb_data); - - ret = mfd_add_devices(&dev->dev, dev->id, - tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), - iomem, tcpd->irq_base, NULL); - - if (!ret) - return 0; - - tc6393xb_detach_irq(dev); -err_gpio_add: - tcpd->disable(dev); -err_enable: - clk_disable_unprepare(tc6393xb->clk); -err_clk_enable: - iounmap(tc6393xb->scr); -err_ioremap: - release_resource(&tc6393xb->rscr); -err_request_scr: - clk_put(tc6393xb->clk); -err_noirq: -err_clk_get: - kfree(tc6393xb); -err_kzalloc: - return ret; -} - -static int tc6393xb_remove(struct platform_device *dev) -{ - struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev); - struct tc6393xb *tc6393xb = platform_get_drvdata(dev); - - mfd_remove_devices(&dev->dev); - - tc6393xb_detach_irq(dev); - - tcpd->disable(dev); - clk_disable_unprepare(tc6393xb->clk); - iounmap(tc6393xb->scr); - release_resource(&tc6393xb->rscr); - clk_put(tc6393xb->clk); - kfree(tc6393xb); - - return 0; -} - -static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state) -{ - struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev); - struct tc6393xb *tc6393xb = platform_get_drvdata(dev); - int i, ret; - - tc6393xb->suspend_state.ccr = ioread16(tc6393xb->scr + SCR_CCR); - tc6393xb->suspend_state.fer = ioread8(tc6393xb->scr + SCR_FER); - - for (i = 0; i < 3; i++) { - tc6393xb->suspend_state.gpo_dsr[i] = - ioread8(tc6393xb->scr + SCR_GPO_DSR(i)); - tc6393xb->suspend_state.gpo_doecr[i] = - ioread8(tc6393xb->scr + SCR_GPO_DOECR(i)); - tc6393xb->suspend_state.gpi_bcr[i] = - ioread8(tc6393xb->scr + SCR_GPI_BCR(i)); - } - ret = tcpd->suspend(dev); - clk_disable_unprepare(tc6393xb->clk); - - return ret; -} - -static int tc6393xb_resume(struct platform_device *dev) -{ - struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev); - struct tc6393xb *tc6393xb = platform_get_drvdata(dev); - int ret; - int i; - - ret = clk_prepare_enable(tc6393xb->clk); - if (ret) - return ret; - - ret = tcpd->resume(dev); - if (ret) - return ret; - - if (!tcpd->resume_restore) - return 0; - - iowrite8(tc6393xb->suspend_state.fer, tc6393xb->scr + SCR_FER); - iowrite16(tcpd->scr_pll2cr, tc6393xb->scr + SCR_PLL2CR); - iowrite16(tc6393xb->suspend_state.ccr, tc6393xb->scr + SCR_CCR); - iowrite16(SCR_MCR_RDY_OPENDRAIN | SCR_MCR_RDY_UNK | SCR_MCR_RDY_EN | - SCR_MCR_INT_OPENDRAIN | SCR_MCR_INT_UNK | SCR_MCR_INT_EN | - BIT(15), tc6393xb->scr + SCR_MCR); - iowrite16(tcpd->scr_gper, tc6393xb->scr + SCR_GPER); - iowrite8(0, tc6393xb->scr + SCR_IRR); - iowrite8(0xbf, tc6393xb->scr + SCR_IMR); - - for (i = 0; i < 3; i++) { - iowrite8(tc6393xb->suspend_state.gpo_dsr[i], - tc6393xb->scr + SCR_GPO_DSR(i)); - iowrite8(tc6393xb->suspend_state.gpo_doecr[i], - tc6393xb->scr + SCR_GPO_DOECR(i)); - iowrite8(tc6393xb->suspend_state.gpi_bcr[i], - tc6393xb->scr + SCR_GPI_BCR(i)); - } - - return 0; -} - -static struct platform_driver tc6393xb_driver = { - .probe = tc6393xb_probe, - .remove = tc6393xb_remove, - .suspend = pm_sleep_ptr(tc6393xb_suspend), - .resume = pm_sleep_ptr(tc6393xb_resume), - - .driver = { - .name = "tc6393xb", - }, -}; - -static int __init tc6393xb_init(void) -{ - return platform_driver_register(&tc6393xb_driver); -} - -static void __exit tc6393xb_exit(void) -{ - platform_driver_unregister(&tc6393xb_driver); -} - -subsys_initcall(tc6393xb_init); -module_exit(tc6393xb_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov and Dirk Opfer"); -MODULE_DESCRIPTION("tc6393xb Toshiba Mobile IO Controller"); -MODULE_ALIAS("platform:tc6393xb"); - diff --git a/drivers/mfd/tmio_core.c b/drivers/mfd/tmio_core.c deleted file mode 100644 index 7ee873551482..000000000000 --- a/drivers/mfd/tmio_core.c +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright(c) 2009 Ian Molton - */ - -#include -#include - -#define CNF_CMD 0x04 -#define CNF_CTL_BASE 0x10 -#define CNF_INT_PIN 0x3d -#define CNF_STOP_CLK_CTL 0x40 -#define CNF_GCLK_CTL 0x41 -#define CNF_SD_CLK_MODE 0x42 -#define CNF_PIN_STATUS 0x44 -#define CNF_PWR_CTL_1 0x48 -#define CNF_PWR_CTL_2 0x49 -#define CNF_PWR_CTL_3 0x4a -#define CNF_CARD_DETECT_MODE 0x4c -#define CNF_SD_SLOT 0x50 -#define CNF_EXT_GCLK_CTL_1 0xf0 -#define CNF_EXT_GCLK_CTL_2 0xf1 -#define CNF_EXT_GCLK_CTL_3 0xf9 -#define CNF_SD_LED_EN_1 0xfa -#define CNF_SD_LED_EN_2 0xfe - -#define SDCREN 0x2 /* Enable access to MMC CTL regs. (flag in COMMAND_REG)*/ - -int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base) -{ - /* Enable the MMC/SD Control registers */ - sd_config_write16(cnf, shift, CNF_CMD, SDCREN); - sd_config_write32(cnf, shift, CNF_CTL_BASE, base & 0xfffe); - - /* Disable SD power during suspend */ - sd_config_write8(cnf, shift, CNF_PWR_CTL_3, 0x01); - - /* The below is required but why? FIXME */ - sd_config_write8(cnf, shift, CNF_STOP_CLK_CTL, 0x1f); - - /* Power down SD bus */ - sd_config_write8(cnf, shift, CNF_PWR_CTL_2, 0x00); - - return 0; -} -EXPORT_SYMBOL(tmio_core_mmc_enable); - -int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base) -{ - - /* Enable the MMC/SD Control registers */ - sd_config_write16(cnf, shift, CNF_CMD, SDCREN); - sd_config_write32(cnf, shift, CNF_CTL_BASE, base & 0xfffe); - - return 0; -} -EXPORT_SYMBOL(tmio_core_mmc_resume); - -void tmio_core_mmc_pwr(void __iomem *cnf, int shift, int state) -{ - sd_config_write8(cnf, shift, CNF_PWR_CTL_2, state ? 0x02 : 0x00); -} -EXPORT_SYMBOL(tmio_core_mmc_pwr); - -void tmio_core_mmc_clk_div(void __iomem *cnf, int shift, int state) -{ - sd_config_write8(cnf, shift, CNF_SD_CLK_MODE, state ? 1 : 0); -} -EXPORT_SYMBOL(tmio_core_mmc_clk_div); - diff --git a/include/linux/mfd/asic3.h b/include/linux/mfd/asic3.h deleted file mode 100644 index 61e686dbaa74..000000000000 --- a/include/linux/mfd/asic3.h +++ /dev/null @@ -1,313 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * include/linux/mfd/asic3.h - * - * Compaq ASIC3 headers. - * - * Copyright 2001 Compaq Computer Corporation. - * Copyright 2007-2008 OpenedHand Ltd. - */ - -#ifndef __ASIC3_H__ -#define __ASIC3_H__ - -#include - -struct led_classdev; -struct asic3_led { - const char *name; - const char *default_trigger; - struct led_classdev *cdev; -}; - -struct asic3_platform_data { - u16 *gpio_config; - unsigned int gpio_config_num; - - unsigned int irq_base; - - unsigned int gpio_base; - - unsigned int clock_rate; - - struct asic3_led *leds; -}; - -#define ASIC3_NUM_GPIO_BANKS 4 -#define ASIC3_GPIOS_PER_BANK 16 -#define ASIC3_NUM_GPIOS 64 -#define ASIC3_NR_IRQS ASIC3_NUM_GPIOS + 6 - -#define ASIC3_IRQ_LED0 64 -#define ASIC3_IRQ_LED1 65 -#define ASIC3_IRQ_LED2 66 -#define ASIC3_IRQ_SPI 67 -#define ASIC3_IRQ_SMBUS 68 -#define ASIC3_IRQ_OWM 69 - -#define ASIC3_TO_GPIO(gpio) (NR_BUILTIN_GPIO + (gpio)) - -#define ASIC3_GPIO_BANK_A 0 -#define ASIC3_GPIO_BANK_B 1 -#define ASIC3_GPIO_BANK_C 2 -#define ASIC3_GPIO_BANK_D 3 - -#define ASIC3_GPIO(bank, gpio) \ - ((ASIC3_GPIOS_PER_BANK * ASIC3_GPIO_BANK_##bank) + (gpio)) -#define ASIC3_GPIO_bit(gpio) (1 << (gpio & 0xf)) -/* All offsets below are specified with this address bus shift */ -#define ASIC3_DEFAULT_ADDR_SHIFT 2 - -#define ASIC3_OFFSET(base, reg) (ASIC3_##base##_BASE + ASIC3_##base##_##reg) -#define ASIC3_GPIO_OFFSET(base, reg) \ - (ASIC3_GPIO_##base##_BASE + ASIC3_GPIO_##reg) - -#define ASIC3_GPIO_A_BASE 0x0000 -#define ASIC3_GPIO_B_BASE 0x0100 -#define ASIC3_GPIO_C_BASE 0x0200 -#define ASIC3_GPIO_D_BASE 0x0300 - -#define ASIC3_GPIO_TO_BANK(gpio) ((gpio) >> 4) -#define ASIC3_GPIO_TO_BIT(gpio) ((gpio) - \ - (ASIC3_GPIOS_PER_BANK * ((gpio) >> 4))) -#define ASIC3_GPIO_TO_MASK(gpio) (1 << ASIC3_GPIO_TO_BIT(gpio)) -#define ASIC3_GPIO_TO_BASE(gpio) (ASIC3_GPIO_A_BASE + (((gpio) >> 4) * 0x0100)) -#define ASIC3_BANK_TO_BASE(bank) (ASIC3_GPIO_A_BASE + ((bank) * 0x100)) - -#define ASIC3_GPIO_MASK 0x00 /* R/W 0:don't mask */ -#define ASIC3_GPIO_DIRECTION 0x04 /* R/W 0:input */ -#define ASIC3_GPIO_OUT 0x08 /* R/W 0:output low */ -#define ASIC3_GPIO_TRIGGER_TYPE 0x0c /* R/W 0:level */ -#define ASIC3_GPIO_EDGE_TRIGGER 0x10 /* R/W 0:falling */ -#define ASIC3_GPIO_LEVEL_TRIGGER 0x14 /* R/W 0:low level detect */ -#define ASIC3_GPIO_SLEEP_MASK 0x18 /* R/W 0:don't mask in sleep mode */ -#define ASIC3_GPIO_SLEEP_OUT 0x1c /* R/W level 0:low in sleep mode */ -#define ASIC3_GPIO_BAT_FAULT_OUT 0x20 /* R/W level 0:low in batt_fault */ -#define ASIC3_GPIO_INT_STATUS 0x24 /* R/W 0:none, 1:detect */ -#define ASIC3_GPIO_ALT_FUNCTION 0x28 /* R/W 1:LED register control */ -#define ASIC3_GPIO_SLEEP_CONF 0x2c /* - * R/W bit 1: autosleep - * 0: disable gposlpout in normal mode, - * enable gposlpout in sleep mode. - */ -#define ASIC3_GPIO_STATUS 0x30 /* R Pin status */ - -/* - * ASIC3 GPIO config - * - * Bits 0..6 gpio number - * Bits 7..13 Alternate function - * Bit 14 Direction - * Bit 15 Initial value - * - */ -#define ASIC3_CONFIG_GPIO_PIN(config) ((config) & 0x7f) -#define ASIC3_CONFIG_GPIO_ALT(config) (((config) & (0x7f << 7)) >> 7) -#define ASIC3_CONFIG_GPIO_DIR(config) ((config & (1 << 14)) >> 14) -#define ASIC3_CONFIG_GPIO_INIT(config) ((config & (1 << 15)) >> 15) -#define ASIC3_CONFIG_GPIO(gpio, alt, dir, init) (((gpio) & 0x7f) \ - | (((alt) & 0x7f) << 7) | (((dir) & 0x1) << 14) \ - | (((init) & 0x1) << 15)) -#define ASIC3_CONFIG_GPIO_DEFAULT(gpio, dir, init) \ - ASIC3_CONFIG_GPIO((gpio), 0, (dir), (init)) -#define ASIC3_CONFIG_GPIO_DEFAULT_OUT(gpio, init) \ - ASIC3_CONFIG_GPIO((gpio), 0, 1, (init)) - -/* - * Alternate functions - */ -#define ASIC3_GPIOA11_PWM0 ASIC3_CONFIG_GPIO(11, 1, 1, 0) -#define ASIC3_GPIOA12_PWM1 ASIC3_CONFIG_GPIO(12, 1, 1, 0) -#define ASIC3_GPIOA15_CONTROL_CX ASIC3_CONFIG_GPIO(15, 1, 1, 0) -#define ASIC3_GPIOC0_LED0 ASIC3_CONFIG_GPIO(32, 1, 0, 0) -#define ASIC3_GPIOC1_LED1 ASIC3_CONFIG_GPIO(33, 1, 0, 0) -#define ASIC3_GPIOC2_LED2 ASIC3_CONFIG_GPIO(34, 1, 0, 0) -#define ASIC3_GPIOC3_SPI_RXD ASIC3_CONFIG_GPIO(35, 1, 0, 0) -#define ASIC3_GPIOC4_CF_nCD ASIC3_CONFIG_GPIO(36, 1, 0, 0) -#define ASIC3_GPIOC4_SPI_TXD ASIC3_CONFIG_GPIO(36, 1, 1, 0) -#define ASIC3_GPIOC5_SPI_CLK ASIC3_CONFIG_GPIO(37, 1, 1, 0) -#define ASIC3_GPIOC5_nCIOW ASIC3_CONFIG_GPIO(37, 1, 1, 0) -#define ASIC3_GPIOC6_nCIOR ASIC3_CONFIG_GPIO(38, 1, 1, 0) -#define ASIC3_GPIOC7_nPCE_1 ASIC3_CONFIG_GPIO(39, 1, 0, 0) -#define ASIC3_GPIOC8_nPCE_2 ASIC3_CONFIG_GPIO(40, 1, 0, 0) -#define ASIC3_GPIOC9_nPOE ASIC3_CONFIG_GPIO(41, 1, 0, 0) -#define ASIC3_GPIOC10_nPWE ASIC3_CONFIG_GPIO(42, 1, 0, 0) -#define ASIC3_GPIOC11_PSKTSEL ASIC3_CONFIG_GPIO(43, 1, 0, 0) -#define ASIC3_GPIOC12_nPREG ASIC3_CONFIG_GPIO(44, 1, 0, 0) -#define ASIC3_GPIOC13_nPWAIT ASIC3_CONFIG_GPIO(45, 1, 1, 0) -#define ASIC3_GPIOC14_nPIOIS16 ASIC3_CONFIG_GPIO(46, 1, 1, 0) -#define ASIC3_GPIOC15_nPIOR ASIC3_CONFIG_GPIO(47, 1, 0, 0) -#define ASIC3_GPIOD4_CF_nCD ASIC3_CONFIG_GPIO(52, 1, 0, 0) -#define ASIC3_GPIOD11_nCIOIS16 ASIC3_CONFIG_GPIO(59, 1, 0, 0) -#define ASIC3_GPIOD12_nCWAIT ASIC3_CONFIG_GPIO(60, 1, 0, 0) -#define ASIC3_GPIOD15_nPIOW ASIC3_CONFIG_GPIO(63, 1, 0, 0) - - -#define ASIC3_SPI_Base 0x0400 -#define ASIC3_SPI_Control 0x0000 -#define ASIC3_SPI_TxData 0x0004 -#define ASIC3_SPI_RxData 0x0008 -#define ASIC3_SPI_Int 0x000c -#define ASIC3_SPI_Status 0x0010 - -#define SPI_CONTROL_SPR(clk) ((clk) & 0x0f) /* Clock rate */ - -#define ASIC3_PWM_0_Base 0x0500 -#define ASIC3_PWM_1_Base 0x0600 -#define ASIC3_PWM_TimeBase 0x0000 -#define ASIC3_PWM_PeriodTime 0x0004 -#define ASIC3_PWM_DutyTime 0x0008 - -#define PWM_TIMEBASE_VALUE(x) ((x)&0xf) /* Low 4 bits sets time base */ -#define PWM_TIMEBASE_ENABLE (1 << 4) /* Enable clock */ - -#define ASIC3_NUM_LEDS 3 -#define ASIC3_LED_0_Base 0x0700 -#define ASIC3_LED_1_Base 0x0800 -#define ASIC3_LED_2_Base 0x0900 -#define ASIC3_LED_TimeBase 0x0000 /* R/W 7 bits */ -#define ASIC3_LED_PeriodTime 0x0004 /* R/W 12 bits */ -#define ASIC3_LED_DutyTime 0x0008 /* R/W 12 bits */ -#define ASIC3_LED_AutoStopCount 0x000c /* R/W 16 bits */ - -/* LED TimeBase bits - match ASIC2 */ -#define LED_TBS 0x0f /* Low 4 bits sets time base, max = 13 */ - /* Note: max = 5 on hx4700 */ - /* 0: maximum time base */ - /* 1: maximum time base / 2 */ - /* n: maximum time base / 2^n */ - -#define LED_EN (1 << 4) /* LED ON/OFF 0:off, 1:on */ -#define LED_AUTOSTOP (1 << 5) /* LED ON/OFF auto stop 0:disable, 1:enable */ -#define LED_ALWAYS (1 << 6) /* LED Interrupt Mask 0:No mask, 1:mask */ - -#define ASIC3_CLOCK_BASE 0x0A00 -#define ASIC3_CLOCK_CDEX 0x00 -#define ASIC3_CLOCK_SEL 0x04 - -#define CLOCK_CDEX_SOURCE (1 << 0) /* 2 bits */ -#define CLOCK_CDEX_SOURCE0 (1 << 0) -#define CLOCK_CDEX_SOURCE1 (1 << 1) -#define CLOCK_CDEX_SPI (1 << 2) -#define CLOCK_CDEX_OWM (1 << 3) -#define CLOCK_CDEX_PWM0 (1 << 4) -#define CLOCK_CDEX_PWM1 (1 << 5) -#define CLOCK_CDEX_LED0 (1 << 6) -#define CLOCK_CDEX_LED1 (1 << 7) -#define CLOCK_CDEX_LED2 (1 << 8) - -/* Clocks settings: 1 for 24.576 MHz, 0 for 12.288Mhz */ -#define CLOCK_CDEX_SD_HOST (1 << 9) /* R/W: SD host clock source */ -#define CLOCK_CDEX_SD_BUS (1 << 10) /* R/W: SD bus clock source ctrl */ -#define CLOCK_CDEX_SMBUS (1 << 11) -#define CLOCK_CDEX_CONTROL_CX (1 << 12) - -#define CLOCK_CDEX_EX0 (1 << 13) /* R/W: 32.768 kHz crystal */ -#define CLOCK_CDEX_EX1 (1 << 14) /* R/W: 24.576 MHz crystal */ - -#define CLOCK_SEL_SD_HCLK_SEL (1 << 0) /* R/W: SDIO host clock select */ -#define CLOCK_SEL_SD_BCLK_SEL (1 << 1) /* R/W: SDIO bus clock select */ - -/* R/W: INT clock source control (32.768 kHz) */ -#define CLOCK_SEL_CX (1 << 2) - - -#define ASIC3_INTR_BASE 0x0B00 - -#define ASIC3_INTR_INT_MASK 0x00 /* Interrupt mask control */ -#define ASIC3_INTR_P_INT_STAT 0x04 /* Peripheral interrupt status */ -#define ASIC3_INTR_INT_CPS 0x08 /* Interrupt timer clock pre-scale */ -#define ASIC3_INTR_INT_TBS 0x0c /* Interrupt timer set */ - -#define ASIC3_INTMASK_GINTMASK (1 << 0) /* Global INTs mask 1:enable */ -#define ASIC3_INTMASK_GINTEL (1 << 1) /* 1: rising edge, 0: hi level */ -#define ASIC3_INTMASK_MASK0 (1 << 2) -#define ASIC3_INTMASK_MASK1 (1 << 3) -#define ASIC3_INTMASK_MASK2 (1 << 4) -#define ASIC3_INTMASK_MASK3 (1 << 5) -#define ASIC3_INTMASK_MASK4 (1 << 6) -#define ASIC3_INTMASK_MASK5 (1 << 7) - -#define ASIC3_INTR_PERIPHERAL_A (1 << 0) -#define ASIC3_INTR_PERIPHERAL_B (1 << 1) -#define ASIC3_INTR_PERIPHERAL_C (1 << 2) -#define ASIC3_INTR_PERIPHERAL_D (1 << 3) -#define ASIC3_INTR_LED0 (1 << 4) -#define ASIC3_INTR_LED1 (1 << 5) -#define ASIC3_INTR_LED2 (1 << 6) -#define ASIC3_INTR_SPI (1 << 7) -#define ASIC3_INTR_SMBUS (1 << 8) -#define ASIC3_INTR_OWM (1 << 9) - -#define ASIC3_INTR_CPS(x) ((x)&0x0f) /* 4 bits, max 14 */ -#define ASIC3_INTR_CPS_SET (1 << 4) /* Time base enable */ - - -/* Basic control of the SD ASIC */ -#define ASIC3_SDHWCTRL_BASE 0x0E00 -#define ASIC3_SDHWCTRL_SDCONF 0x00 - -#define ASIC3_SDHWCTRL_SUSPEND (1 << 0) /* 1=suspend all SD operations */ -#define ASIC3_SDHWCTRL_CLKSEL (1 << 1) /* 1=SDICK, 0=HCLK */ -#define ASIC3_SDHWCTRL_PCLR (1 << 2) /* All registers of SDIO cleared */ -#define ASIC3_SDHWCTRL_LEVCD (1 << 3) /* SD card detection: 0:low */ - -/* SD card write protection: 0=high */ -#define ASIC3_SDHWCTRL_LEVWP (1 << 4) -#define ASIC3_SDHWCTRL_SDLED (1 << 5) /* SD card LED signal 0=disable */ - -/* SD card power supply ctrl 1=enable */ -#define ASIC3_SDHWCTRL_SDPWR (1 << 6) - -#define ASIC3_EXTCF_BASE 0x1100 - -#define ASIC3_EXTCF_SELECT 0x00 -#define ASIC3_EXTCF_RESET 0x04 - -#define ASIC3_EXTCF_SMOD0 (1 << 0) /* slot number of mode 0 */ -#define ASIC3_EXTCF_SMOD1 (1 << 1) /* slot number of mode 1 */ -#define ASIC3_EXTCF_SMOD2 (1 << 2) /* slot number of mode 2 */ -#define ASIC3_EXTCF_OWM_EN (1 << 4) /* enable onewire module */ -#define ASIC3_EXTCF_OWM_SMB (1 << 5) /* OWM bus selection */ -#define ASIC3_EXTCF_OWM_RESET (1 << 6) /* ?? used by OWM and CF */ -#define ASIC3_EXTCF_CF0_SLEEP_MODE (1 << 7) /* CF0 sleep state */ -#define ASIC3_EXTCF_CF1_SLEEP_MODE (1 << 8) /* CF1 sleep state */ -#define ASIC3_EXTCF_CF0_PWAIT_EN (1 << 10) /* CF0 PWAIT_n control */ -#define ASIC3_EXTCF_CF1_PWAIT_EN (1 << 11) /* CF1 PWAIT_n control */ -#define ASIC3_EXTCF_CF0_BUF_EN (1 << 12) /* CF0 buffer control */ -#define ASIC3_EXTCF_CF1_BUF_EN (1 << 13) /* CF1 buffer control */ -#define ASIC3_EXTCF_SD_MEM_ENABLE (1 << 14) -#define ASIC3_EXTCF_CF_SLEEP (1 << 15) /* CF sleep mode control */ - -/********************************************* - * The Onewire interface (DS1WM) is handled - * by the ds1wm driver. - * - *********************************************/ - -#define ASIC3_OWM_BASE 0xC00 - -/***************************************************************************** - * The SD configuration registers are at a completely different location - * in memory. They are divided into three sets of registers: - * - * SD_CONFIG Core configuration register - * SD_CTRL Control registers for SD operations - * SDIO_CTRL Control registers for SDIO operations - * - *****************************************************************************/ -#define ASIC3_SD_CONFIG_BASE 0x0400 /* Assumes 32 bit addressing */ -#define ASIC3_SD_CONFIG_SIZE 0x0200 /* Assumes 32 bit addressing */ -#define ASIC3_SD_CTRL_BASE 0x1000 -#define ASIC3_SDIO_CTRL_BASE 0x1200 - -#define ASIC3_MAP_SIZE_32BIT 0x2000 -#define ASIC3_MAP_SIZE_16BIT 0x1000 - -/* Functions needed by leds-asic3 */ - -struct asic3; -extern void asic3_write_register(struct asic3 *asic, unsigned int reg, u32 val); -extern u32 asic3_read_register(struct asic3 *asic, unsigned int reg); - -#endif /* __ASIC3_H__ */ diff --git a/include/linux/mfd/t7l66xb.h b/include/linux/mfd/t7l66xb.h deleted file mode 100644 index ae3e7a5c5219..000000000000 --- a/include/linux/mfd/t7l66xb.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * This file contains the definitions for the T7L66XB - * - * (C) Copyright 2005 Ian Molton - */ -#ifndef MFD_T7L66XB_H -#define MFD_T7L66XB_H - -#include -#include - -struct t7l66xb_platform_data { - int (*enable)(struct platform_device *dev); - int (*suspend)(struct platform_device *dev); - int (*resume)(struct platform_device *dev); - - int irq_base; /* The base for subdevice irqs */ - - struct tmio_nand_data *nand_data; -}; - - -#define IRQ_T7L66XB_MMC (1) -#define IRQ_T7L66XB_NAND (3) - -#define T7L66XB_NR_IRQS 8 - -#endif diff --git a/include/linux/mfd/tc6387xb.h b/include/linux/mfd/tc6387xb.h deleted file mode 100644 index aacf1dcc86b9..000000000000 --- a/include/linux/mfd/tc6387xb.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * This file contains the definitions for the TC6387XB - * - * (C) Copyright 2005 Ian Molton - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - */ -#ifndef MFD_TC6387XB_H -#define MFD_TC6387XB_H - -struct tc6387xb_platform_data { - int (*enable)(struct platform_device *dev); - int (*suspend)(struct platform_device *dev); - int (*resume)(struct platform_device *dev); -}; - -#endif diff --git a/include/linux/mfd/tc6393xb.h b/include/linux/mfd/tc6393xb.h deleted file mode 100644 index d17807f2d0c9..000000000000 --- a/include/linux/mfd/tc6393xb.h +++ /dev/null @@ -1,53 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Toshiba TC6393XB SoC support - * - * Copyright(c) 2005-2006 Chris Humbert - * Copyright(c) 2005 Dirk Opfer - * Copyright(c) 2005 Ian Molton - * Copyright(c) 2007 Dmitry Baryshkov - * - * Based on code written by Sharp/Lineo for 2.4 kernels - * Based on locomo.c - */ - -#ifndef MFD_TC6393XB_H -#define MFD_TC6393XB_H - -#include - -/* Also one should provide the CK3P6MI clock */ -struct tc6393xb_platform_data { - u16 scr_pll2cr; /* PLL2 Control */ - u16 scr_gper; /* GP Enable */ - - int (*enable)(struct platform_device *dev); - void (*disable)(struct platform_device *dev); - int (*suspend)(struct platform_device *dev); - int (*resume)(struct platform_device *dev); - - int irq_base; /* base for subdevice irqs */ - - struct tmio_nand_data *nand_data; - struct tmio_fb_data *fb_data; - - unsigned resume_restore : 1; /* make special actions - to preserve the state - on suspend/resume */ -}; - -extern int tc6393xb_lcd_mode(struct platform_device *fb, - const struct fb_videomode *mode); -extern int tc6393xb_lcd_set_power(struct platform_device *fb, bool on); - -/* - * Relative to irq_base - */ -#define IRQ_TC6393_NAND 0 -#define IRQ_TC6393_MMC 1 -#define IRQ_TC6393_OHCI 2 -#define IRQ_TC6393_FB 4 - -#define TC6393XB_NR_IRQS 8 - -#endif diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h index e8bf90281ba0..eace8ea6cda0 100644 --- a/include/linux/mfd/tmio.h +++ b/include/linux/mfd/tmio.h @@ -84,11 +84,6 @@ /* Some controllers have a CBSY bit */ #define TMIO_MMC_HAVE_CBSY BIT(11) -int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base); -int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base); -void tmio_core_mmc_pwr(void __iomem *cnf, int shift, int state); -void tmio_core_mmc_clk_div(void __iomem *cnf, int shift, int state); - struct dma_chan; /* From 4d83bcbeee12be0842ec99606f08c1c65e986a97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Rosenkr=C3=A4nzer?= Date: Wed, 25 Jan 2023 15:34:57 +0100 Subject: [PATCH 37/40] dt-bindings: mfd: syscon: Add mt8365-syscfg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document Mediatek mt8365-syscfg Signed-off-by: Bernhard Rosenkränzer Acked-by: Krzysztof Kozlowski Reviewed-by: Matthias Brugger Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230125143503.1015424-4-bero@baylibre.com --- Documentation/devicetree/bindings/mfd/syscon.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml index 396d78088113..dd5bb0f9b530 100644 --- a/Documentation/devicetree/bindings/mfd/syscon.yaml +++ b/Documentation/devicetree/bindings/mfd/syscon.yaml @@ -52,6 +52,7 @@ properties: - marvell,armada-3700-usb2-host-misc - mediatek,mt8135-pctl-a-syscfg - mediatek,mt8135-pctl-b-syscfg + - mediatek,mt8365-syscfg - microchip,lan966x-cpu-syscon - microchip,sparx5-cpu-syscon - mstar,msc313-pmsleep From 8a15b4daed3d45c9162f23d393a06df2a7be4778 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Fri, 27 Jan 2023 17:58:28 +0100 Subject: [PATCH 38/40] mfd: ntxec: Add version number for EC in Tolino Vision The EC firmware has a different version number than anything defined until now. Signed-off-by: Andreas Kemnade Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230127165828.3256170-1-andreas@kemnade.info --- drivers/mfd/ntxec.c | 1 + include/linux/mfd/ntxec.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c index e16a7a82a929..b02785b10d48 100644 --- a/drivers/mfd/ntxec.c +++ b/drivers/mfd/ntxec.c @@ -175,6 +175,7 @@ static int ntxec_probe(struct i2c_client *client) /* Bail out if we encounter an unknown firmware version */ switch (version) { case NTXEC_VERSION_KOBO_AURA: + case NTXEC_VERSION_TOLINO_VISION: subdevs = ntxec_subdev; n_subdevs = ARRAY_SIZE(ntxec_subdev); break; diff --git a/include/linux/mfd/ntxec.h b/include/linux/mfd/ntxec.h index cc6f07bfa2b3..e5880c346da9 100644 --- a/include/linux/mfd/ntxec.h +++ b/include/linux/mfd/ntxec.h @@ -34,5 +34,5 @@ static inline u16 ntxec_reg8(u8 value) /* Known firmware versions */ #define NTXEC_VERSION_KOBO_AURA 0xd726 /* found in Kobo Aura */ #define NTXEC_VERSION_TOLINO_SHINE2 0xf110 /* found in Tolino Shine 2 HD */ - +#define NTXEC_VERSION_TOLINO_VISION 0xe135 /* found in Tolino Vision, contains RTC, ADC, PWM, home pad */ #endif From 43be4f662ae23c38d7f29204a3b635d4c6d61646 Mon Sep 17 00:00:00 2001 From: Jacky Bai Date: Sun, 29 Jan 2023 15:08:20 +0800 Subject: [PATCH 39/40] dt-bindings: mfd: Add NXP BBNSM Add binding for NXP BBNSM(Battery-Backed Non-Secure Module). Signed-off-by: Jacky Bai Reviewed-by: Rob Herring Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230129070823.1945489-2-ping.bai@nxp.com --- .../devicetree/bindings/mfd/nxp,bbnsm.yaml | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/nxp,bbnsm.yaml diff --git a/Documentation/devicetree/bindings/mfd/nxp,bbnsm.yaml b/Documentation/devicetree/bindings/mfd/nxp,bbnsm.yaml new file mode 100644 index 000000000000..b1ade64a1554 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/nxp,bbnsm.yaml @@ -0,0 +1,101 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/nxp,bbnsm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP Battery-Backed Non-Secure Module + +maintainers: + - Jacky Bai + +description: | + NXP BBNSM serves as non-volatile logic and storage for the system. + it Intergrates RTC & ON/OFF control. + The RTC can retain its state and continues counting even when the + main chip is power down. A time alarm is generated once the most + significant 32 bits of the real-time counter match the value in the + Time Alarm register. + The ON/OFF logic inside the BBNSM allows for connecting directly to + a PMIC or other voltage regulator device. both smart PMIC mode and + Dumb PMIC mode supported. + +properties: + compatible: + items: + - enum: + - nxp,imx93-bbnsm + - const: syscon + - const: simple-mfd + + reg: + maxItems: 1 + + rtc: + type: object + $ref: /schemas/rtc/rtc.yaml# + + properties: + compatible: + enum: + - nxp,imx93-bbnsm-rtc + + interrupts: + maxItems: 1 + + start-year: true + + required: + - compatible + - interrupts + + additionalProperties: false + + pwrkey: + type: object + $ref: /schemas/input/input.yaml# + + properties: + compatible: + enum: + - nxp,imx93-bbnsm-pwrkey + + interrupts: + maxItems: 1 + + linux,code: true + + required: + - compatible + - interrupts + + additionalProperties: false + +required: + - compatible + - reg + - rtc + - pwrkey + +additionalProperties: false + +examples: + - | + #include + #include + + bbnsm: bbnsm@44440000 { + compatible = "nxp,imx93-bbnsm", "syscon", "simple-mfd"; + reg = <0x44440000 0x10000>; + + bbnsm_rtc: rtc { + compatible = "nxp,imx93-bbnsm-rtc"; + interrupts = ; + }; + + bbnsm_pwrkey: pwrkey { + compatible = "nxp,imx93-bbnsm-pwrkey"; + interrupts = ; + linux,code = ; + }; + }; From 59c54c59974649b2e7bc92faae4a21e2b2408db2 Mon Sep 17 00:00:00 2001 From: Kathiravan T Date: Mon, 30 Jan 2023 22:31:53 +0530 Subject: [PATCH 40/40] dt-bindings: mfd: qcom,tcsr: Add compatible for IPQ5332 Document the qcom,tcsr-ipq5332 compatible. Signed-off-by: Kathiravan T Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230130170155.27266-2-quic_kathirav@quicinc.com --- Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml b/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml index d463fb47278f..2eeebe920e6e 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml +++ b/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml @@ -28,6 +28,7 @@ properties: - qcom,sm8150-tcsr - qcom,tcsr-apq8064 - qcom,tcsr-apq8084 + - qcom,tcsr-ipq5332 - qcom,tcsr-ipq6018 - qcom,tcsr-ipq8064 - qcom,tcsr-mdm9615