@@ -123,6 +123,9 @@ int acpi_set_logicio_resource(struct device *child,
/* All the host devices which apply indirect-IO can be listed here. */
static const struct acpi_device_id acpi_indirect_host_id[] = {
+#ifdef CONFIG_HISILICON_LPC
+ {"HISI0191", INDIRECT_IO_INFO(lpc_host_desc)},
+#endif
{""},
};
@@ -18,6 +18,10 @@ struct indirectio_device_desc {
int (*pre_setup)(struct acpi_device *adev, void *pdata);
};
+#ifdef CONFIG_HISILICON_LPC
+extern const struct indirectio_device_desc lpc_host_desc;
+#endif
+
int acpi_set_logicio_resource(struct device *child,
struct device *hostdev, const struct resource **res,
int *num_res);
@@ -438,7 +438,6 @@ static int hisilpc_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct resource *res;
struct hisilpc_dev *lpcdev;
- struct logic_pio_hwaddr *range;
int ret = 0;
lpcdev = devm_kzalloc(dev, sizeof(struct hisilpc_dev), GFP_KERNEL);
@@ -460,21 +459,32 @@ static int hisilpc_probe(struct platform_device *pdev)
}
/* register the LPC host PIO resources */
- range = devm_kzalloc(dev, sizeof(*range), GFP_KERNEL);
- if (!range)
- return -ENOMEM;
- range->fwnode = dev->fwnode;
- range->flags = PIO_INDIRECT;
- range->size = LPC_BUS_IO_SIZE;
- range->hw_start = LPC_MIN_BUS_RANGE;
-
- ret = logic_pio_register_range(range);
- if (ret) {
- kfree(range);
- dev_err(dev, "OF: register IO range FAIL!\n");
- return -ret;
+ if (has_acpi_companion(dev)) {
+ lpcdev->io_host = find_io_range_by_fwnode(dev->fwnode);
+ if (!lpcdev->io_host) {
+ dev_err(dev, "HiSilicon LPC range not registered!\n");
+ return -EFAULT;
+ }
+ } else {
+ struct logic_pio_hwaddr *range;
+
+ range = devm_kzalloc(dev, sizeof(*range), GFP_KERNEL);
+ if (!range)
+ return -ENOMEM;
+ range->fwnode = dev->fwnode;
+ range->flags = PIO_INDIRECT;
+ range->size = LPC_BUS_IO_SIZE;
+ range->hw_start = LPC_MIN_BUS_RANGE;
+
+ ret = logic_pio_register_range(range);
+ if (ret) {
+ kfree(range);
+ dev_err(dev, "OF: register IO range FAIL!\n");
+ return -ret;
+ }
+ lpcdev->io_host = range;
}
- lpcdev->io_host = range;
+
lpcdev->io_host->devpara = lpcdev;
lpcdev->io_host->ops = &hisi_lpc_ops;
@@ -486,8 +496,11 @@ static int hisilpc_probe(struct platform_device *pdev)
* to avoid some children which complete the scanning trigger the
* MMIO accesses which will probably cause panic.
*/
- dev_info(dev, " calling of_platform_populate");
- ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+ if (!has_acpi_companion(dev)) {
+ dev_info(dev, " calling of_platform_populate");
+ ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+ }
+
if (ret) {
/*
* When LPC probing is not completely successful, set 'devpara'
@@ -515,10 +528,127 @@ static const struct of_device_id hisilpc_of_match[] = {
{},
};
+#ifdef CONFIG_ACPI
+#include "../acpi/arm64/acpi_indirectio.h"
+#include <linux/mfd/core.h>
+
+struct lpc_private_data {
+ resource_size_t io_size;
+ resource_size_t io_start;
+};
+
+static struct lpc_private_data lpc_data = {
+ .io_size = LPC_BUS_IO_SIZE,
+ .io_start = LPC_MIN_BUS_RANGE,
+};
+
+static struct mfd_cell_acpi_match hisi_lpc_ipmi_acpi_match = {
+ .pnpid = "IPI0001",
+};
+
+static const char *hisi_lpc_ipmi_name = "hisi_lpc_ipmi";
+
+static int lpc_host_io_setup(struct acpi_device *adev, void *pdata)
+{
+ int ret;
+ struct platform_device *pdev;
+ struct mfd_cell *ipmi_devs;
+ struct logic_pio_hwaddr *range;
+ struct lpc_private_data *lpc_private;
+ struct acpi_device *child;
+ int ipmi_dev_num = 0;
+
+ lpc_private = pdata;
+ range = kzalloc(sizeof(*range), GFP_KERNEL);
+ if (!range)
+ return -ENOMEM;
+ range->fwnode = &adev->fwnode;
+ range->flags = PIO_INDIRECT;
+ range->size = lpc_private->io_size;
+ range->hw_start = lpc_private->io_start;
+
+ ret = logic_pio_register_range(range);
+ if (ret)
+ goto free_range;
+
+ /* count the ipmi children first */
+ list_for_each_entry(child, &adev->children, node) {
+ if (!strcmp(hisi_lpc_ipmi_acpi_match.pnpid,
+ acpi_device_hid(child)))
+ ipmi_dev_num++;
+ }
+
+ /* allocate the mfd cells */
+ ipmi_devs = kcalloc(ipmi_dev_num, sizeof(*ipmi_devs), GFP_KERNEL);
+ if (!ipmi_devs) {
+ dev_err(&adev->dev, "ipmi_devs kzalloc failed!\n");
+ ret = -ENOMEM;
+ goto free_range;
+ }
+
+ ipmi_dev_num = 0;
+ /* For hisilpc, only care about the sons of host. */
+ list_for_each_entry(child, &adev->children, node) {
+ if (!strcmp(hisi_lpc_ipmi_acpi_match.pnpid,
+ acpi_device_hid(child))) {
+ ipmi_devs[ipmi_dev_num].name = hisi_lpc_ipmi_name;
+ ipmi_devs[ipmi_dev_num].acpi_match =
+ &hisi_lpc_ipmi_acpi_match;
+ ret = acpi_set_logicio_resource(&child->dev, &adev->dev,
+ &ipmi_devs[ipmi_dev_num].resources,
+ &ipmi_devs[ipmi_dev_num].num_resources);
+ if (ret) {
+ dev_err(&child->dev, "set resource failed..\n");
+ goto free_ipmi_devs;
+ }
+ ipmi_dev_num++;
+ }
+ }
+
+ pdev = acpi_create_platform_device(adev, NULL);
+ if (IS_ERR_OR_NULL(pdev)) {
+ dev_err(&adev->dev, "Create platform device for host FAIL!\n");
+ ret = -EFAULT;
+ goto free_ipmi_devs;
+ }
+ acpi_device_set_enumerated(adev);
+
+ ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
+ ipmi_devs, ipmi_dev_num, NULL, 0, NULL);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add ipmi mfd cell\n");
+ goto free_ipmi_devs;
+ }
+
+ return ret;
+
+free_ipmi_devs:
+ while (ipmi_dev_num--)
+ kfree(ipmi_devs[ipmi_dev_num].resources);
+ kfree(ipmi_devs);
+free_range:
+ kfree(range);
+
+ return ret;
+}
+
+static const struct acpi_device_id hisilpc_acpi_match[] = {
+ {"HISI0191", },
+ {},
+};
+
+const struct indirectio_device_desc lpc_host_desc = {
+ .pdata = &lpc_data,
+ .pre_setup = lpc_host_io_setup,
+};
+
+#endif
+
static struct platform_driver hisilpc_driver = {
.driver = {
.name = "hisi_lpc",
.of_match_table = hisilpc_of_match,
+ .acpi_match_table = ACPI_PTR(hisilpc_acpi_match),
},
.probe = hisilpc_probe,
};