18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci/*
48c2ecf20Sopenharmony_ci * ACPI support for platform bus type.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2015, Linaro Ltd
78c2ecf20Sopenharmony_ci * Author: Graeme Gregory <graeme.gregory@linaro.org>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/acpi.h>
118c2ecf20Sopenharmony_ci#include <linux/amba/bus.h>
128c2ecf20Sopenharmony_ci#include <linux/clkdev.h>
138c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
148c2ecf20Sopenharmony_ci#include <linux/device.h>
158c2ecf20Sopenharmony_ci#include <linux/err.h>
168c2ecf20Sopenharmony_ci#include <linux/ioport.h>
178c2ecf20Sopenharmony_ci#include <linux/kernel.h>
188c2ecf20Sopenharmony_ci#include <linux/module.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "internal.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic const struct acpi_device_id amba_id_list[] = {
238c2ecf20Sopenharmony_ci	{"ARMH0061", 0}, /* PL061 GPIO Device */
248c2ecf20Sopenharmony_ci	{"ARMHC500", 0}, /* ARM CoreSight ETM4x */
258c2ecf20Sopenharmony_ci	{"ARMHC501", 0}, /* ARM CoreSight ETR */
268c2ecf20Sopenharmony_ci	{"ARMHC502", 0}, /* ARM CoreSight STM */
278c2ecf20Sopenharmony_ci	{"ARMHC503", 0}, /* ARM CoreSight Debug */
288c2ecf20Sopenharmony_ci	{"ARMHC979", 0}, /* ARM CoreSight TPIU */
298c2ecf20Sopenharmony_ci	{"ARMHC97C", 0}, /* ARM CoreSight SoC-400 TMC, SoC-600 ETF/ETB */
308c2ecf20Sopenharmony_ci	{"ARMHC98D", 0}, /* ARM CoreSight Dynamic Replicator */
318c2ecf20Sopenharmony_ci	{"ARMHC9CA", 0}, /* ARM CoreSight CATU */
328c2ecf20Sopenharmony_ci	{"ARMHC9FF", 0}, /* ARM CoreSight Dynamic Funnel */
338c2ecf20Sopenharmony_ci	{"", 0},
348c2ecf20Sopenharmony_ci};
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic void amba_register_dummy_clk(void)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	static struct clk *amba_dummy_clk;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	/* If clock already registered */
418c2ecf20Sopenharmony_ci	if (amba_dummy_clk)
428c2ecf20Sopenharmony_ci		return;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	amba_dummy_clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, 0, 0);
458c2ecf20Sopenharmony_ci	clk_register_clkdev(amba_dummy_clk, "apb_pclk", NULL);
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic int amba_handler_attach(struct acpi_device *adev,
498c2ecf20Sopenharmony_ci				const struct acpi_device_id *id)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	struct amba_device *dev;
528c2ecf20Sopenharmony_ci	struct resource_entry *rentry;
538c2ecf20Sopenharmony_ci	struct list_head resource_list;
548c2ecf20Sopenharmony_ci	bool address_found = false;
558c2ecf20Sopenharmony_ci	int irq_no = 0;
568c2ecf20Sopenharmony_ci	int ret;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	/* If the ACPI node already has a physical device attached, skip it. */
598c2ecf20Sopenharmony_ci	if (adev->physical_node_count)
608c2ecf20Sopenharmony_ci		return 0;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	dev = amba_device_alloc(dev_name(&adev->dev), 0, 0);
638c2ecf20Sopenharmony_ci	if (!dev) {
648c2ecf20Sopenharmony_ci		dev_err(&adev->dev, "%s(): amba_device_alloc() failed\n",
658c2ecf20Sopenharmony_ci			__func__);
668c2ecf20Sopenharmony_ci		return -ENOMEM;
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&resource_list);
708c2ecf20Sopenharmony_ci	ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
718c2ecf20Sopenharmony_ci	if (ret < 0)
728c2ecf20Sopenharmony_ci		goto err_free;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	list_for_each_entry(rentry, &resource_list, node) {
758c2ecf20Sopenharmony_ci		switch (resource_type(rentry->res)) {
768c2ecf20Sopenharmony_ci		case IORESOURCE_MEM:
778c2ecf20Sopenharmony_ci			if (!address_found) {
788c2ecf20Sopenharmony_ci				dev->res = *rentry->res;
798c2ecf20Sopenharmony_ci				dev->res.name = dev_name(&dev->dev);
808c2ecf20Sopenharmony_ci				address_found = true;
818c2ecf20Sopenharmony_ci			}
828c2ecf20Sopenharmony_ci			break;
838c2ecf20Sopenharmony_ci		case IORESOURCE_IRQ:
848c2ecf20Sopenharmony_ci			if (irq_no < AMBA_NR_IRQS)
858c2ecf20Sopenharmony_ci				dev->irq[irq_no++] = rentry->res->start;
868c2ecf20Sopenharmony_ci			break;
878c2ecf20Sopenharmony_ci		default:
888c2ecf20Sopenharmony_ci			dev_warn(&adev->dev, "Invalid resource\n");
898c2ecf20Sopenharmony_ci			break;
908c2ecf20Sopenharmony_ci		}
918c2ecf20Sopenharmony_ci	}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	acpi_dev_free_resource_list(&resource_list);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	/*
968c2ecf20Sopenharmony_ci	 * If the ACPI node has a parent and that parent has a physical device
978c2ecf20Sopenharmony_ci	 * attached to it, that physical device should be the parent of
988c2ecf20Sopenharmony_ci	 * the amba device we are about to create.
998c2ecf20Sopenharmony_ci	 */
1008c2ecf20Sopenharmony_ci	if (adev->parent)
1018c2ecf20Sopenharmony_ci		dev->dev.parent = acpi_get_first_physical_node(adev->parent);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	ACPI_COMPANION_SET(&dev->dev, adev);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	ret = amba_device_add(dev, &iomem_resource);
1068c2ecf20Sopenharmony_ci	if (ret) {
1078c2ecf20Sopenharmony_ci		dev_err(&adev->dev, "%s(): amba_device_add() failed (%d)\n",
1088c2ecf20Sopenharmony_ci		       __func__, ret);
1098c2ecf20Sopenharmony_ci		goto err_free;
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	return 1;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cierr_free:
1158c2ecf20Sopenharmony_ci	amba_device_put(dev);
1168c2ecf20Sopenharmony_ci	return ret;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic struct acpi_scan_handler amba_handler = {
1208c2ecf20Sopenharmony_ci	.ids = amba_id_list,
1218c2ecf20Sopenharmony_ci	.attach = amba_handler_attach,
1228c2ecf20Sopenharmony_ci};
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_civoid __init acpi_amba_init(void)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	amba_register_dummy_clk();
1278c2ecf20Sopenharmony_ci	acpi_scan_add_handler(&amba_handler);
1288c2ecf20Sopenharmony_ci}
129