268 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * AMD ACPI support for ACPI2platform device.4 *5 * Copyright (c) 2014,2015 AMD Corporation.6 * Authors: Ken Xue <Ken.Xue@amd.com>7 * Wu, Jeff <Jeff.Wu@amd.com>8 */9 10#include <linux/acpi.h>11#include <linux/clkdev.h>12#include <linux/clk-provider.h>13#include <linux/err.h>14#include <linux/io.h>15#include <linux/platform_data/clk-fch.h>16#include <linux/platform_device.h>17 18#include "internal.h"19 20struct apd_private_data;21 22/**23 * struct apd_device_desc - a descriptor for apd device24 * @fixed_clk_rate: fixed rate input clock source for acpi device;25 * 0 means no fixed rate input clock source26 * @properties: build-in properties of the device such as UART27 * @setup: a hook routine to set device resource during create platform device28 *29 * Device description defined as acpi_device_id.driver_data30 */31struct apd_device_desc {32 unsigned int fixed_clk_rate;33 struct property_entry *properties;34 int (*setup)(struct apd_private_data *pdata);35};36 37struct apd_private_data {38 struct clk *clk;39 struct acpi_device *adev;40 const struct apd_device_desc *dev_desc;41};42 43#if defined(CONFIG_X86_AMD_PLATFORM_DEVICE) || defined(CONFIG_ARM64)44#define APD_ADDR(desc) ((unsigned long)&desc)45 46static int acpi_apd_setup(struct apd_private_data *pdata)47{48 const struct apd_device_desc *dev_desc = pdata->dev_desc;49 struct clk *clk;50 51 if (dev_desc->fixed_clk_rate) {52 clk = clk_register_fixed_rate(&pdata->adev->dev,53 dev_name(&pdata->adev->dev),54 NULL, 0, dev_desc->fixed_clk_rate);55 clk_register_clkdev(clk, NULL, dev_name(&pdata->adev->dev));56 pdata->clk = clk;57 }58 59 return 0;60}61 62#ifdef CONFIG_X86_AMD_PLATFORM_DEVICE63 64static int fch_misc_setup(struct apd_private_data *pdata)65{66 struct acpi_device *adev = pdata->adev;67 const union acpi_object *obj;68 struct platform_device *clkdev;69 struct fch_clk_data *clk_data;70 struct resource_entry *rentry;71 struct list_head resource_list;72 int ret;73 74 clk_data = devm_kzalloc(&adev->dev, sizeof(*clk_data), GFP_KERNEL);75 if (!clk_data)76 return -ENOMEM;77 78 INIT_LIST_HEAD(&resource_list);79 ret = acpi_dev_get_memory_resources(adev, &resource_list);80 if (ret < 0)81 return -ENOENT;82 83 if (!acpi_dev_get_property(adev, "clk-name", ACPI_TYPE_STRING, &obj)) {84 clk_data->name = devm_kzalloc(&adev->dev, obj->string.length,85 GFP_KERNEL);86 if (!clk_data->name)87 return -ENOMEM;88 89 strcpy(clk_data->name, obj->string.pointer);90 } else {91 /* Set default name to mclk if entry missing in firmware */92 clk_data->name = "mclk";93 }94 95 list_for_each_entry(rentry, &resource_list, node) {96 clk_data->base = devm_ioremap(&adev->dev, rentry->res->start,97 resource_size(rentry->res));98 break;99 }100 if (!clk_data->base)101 return -ENOMEM;102 103 acpi_dev_free_resource_list(&resource_list);104 105 clkdev = platform_device_register_data(&adev->dev, "clk-fch",106 PLATFORM_DEVID_NONE, clk_data,107 sizeof(*clk_data));108 return PTR_ERR_OR_ZERO(clkdev);109}110 111static const struct apd_device_desc cz_i2c_desc = {112 .setup = acpi_apd_setup,113 .fixed_clk_rate = 133000000,114};115 116static const struct apd_device_desc wt_i2c_desc = {117 .setup = acpi_apd_setup,118 .fixed_clk_rate = 150000000,119};120 121static const struct apd_device_desc wt_i3c_desc = {122 .setup = acpi_apd_setup,123 .fixed_clk_rate = 125000000,124};125 126static struct property_entry uart_properties[] = {127 PROPERTY_ENTRY_U32("reg-io-width", 4),128 PROPERTY_ENTRY_U32("reg-shift", 2),129 PROPERTY_ENTRY_BOOL("snps,uart-16550-compatible"),130 { },131};132 133static const struct apd_device_desc cz_uart_desc = {134 .setup = acpi_apd_setup,135 .fixed_clk_rate = 48000000,136 .properties = uart_properties,137};138 139static const struct apd_device_desc fch_misc_desc = {140 .setup = fch_misc_setup,141};142#endif /* CONFIG_X86_AMD_PLATFORM_DEVICE */143 144#ifdef CONFIG_ARM64145static const struct apd_device_desc xgene_i2c_desc = {146 .setup = acpi_apd_setup,147 .fixed_clk_rate = 100000000,148};149 150static const struct apd_device_desc vulcan_spi_desc = {151 .setup = acpi_apd_setup,152 .fixed_clk_rate = 133000000,153};154 155static const struct apd_device_desc hip07_i2c_desc = {156 .setup = acpi_apd_setup,157 .fixed_clk_rate = 200000000,158};159 160static const struct apd_device_desc hip08_i2c_desc = {161 .setup = acpi_apd_setup,162 .fixed_clk_rate = 250000000,163};164 165static const struct apd_device_desc hip08_lite_i2c_desc = {166 .setup = acpi_apd_setup,167 .fixed_clk_rate = 125000000,168};169 170static const struct apd_device_desc thunderx2_i2c_desc = {171 .setup = acpi_apd_setup,172 .fixed_clk_rate = 125000000,173};174 175static const struct apd_device_desc nxp_i2c_desc = {176 .setup = acpi_apd_setup,177 .fixed_clk_rate = 350000000,178};179 180static const struct apd_device_desc hip08_spi_desc = {181 .setup = acpi_apd_setup,182 .fixed_clk_rate = 250000000,183};184#endif /* CONFIG_ARM64 */185 186#endif187 188/*189 * Create platform device during acpi scan attach handle.190 * Return value > 0 on success of creating device.191 */192static int acpi_apd_create_device(struct acpi_device *adev,193 const struct acpi_device_id *id)194{195 const struct apd_device_desc *dev_desc = (void *)id->driver_data;196 struct apd_private_data *pdata;197 struct platform_device *pdev;198 int ret;199 200 if (!dev_desc) {201 pdev = acpi_create_platform_device(adev, NULL);202 return IS_ERR_OR_NULL(pdev) ? PTR_ERR(pdev) : 1;203 }204 205 pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);206 if (!pdata)207 return -ENOMEM;208 209 pdata->adev = adev;210 pdata->dev_desc = dev_desc;211 212 if (dev_desc->setup) {213 ret = dev_desc->setup(pdata);214 if (ret)215 goto err_out;216 }217 218 adev->driver_data = pdata;219 pdev = acpi_create_platform_device(adev, dev_desc->properties);220 if (!IS_ERR_OR_NULL(pdev))221 return 1;222 223 ret = PTR_ERR(pdev);224 adev->driver_data = NULL;225 226 err_out:227 kfree(pdata);228 return ret;229}230 231static const struct acpi_device_id acpi_apd_device_ids[] = {232 /* Generic apd devices */233#ifdef CONFIG_X86_AMD_PLATFORM_DEVICE234 { "AMD0010", APD_ADDR(cz_i2c_desc) },235 { "AMD0020", APD_ADDR(cz_uart_desc) },236 { "AMD0030", },237 { "AMD0040", APD_ADDR(fch_misc_desc)},238 { "AMDI0010", APD_ADDR(wt_i2c_desc) },239 { "AMDI0015", APD_ADDR(wt_i3c_desc) },240 { "AMDI0019", APD_ADDR(wt_i2c_desc) },241 { "AMDI0020", APD_ADDR(cz_uart_desc) },242 { "AMDI0022", APD_ADDR(cz_uart_desc) },243 { "HYGO0010", APD_ADDR(wt_i2c_desc) },244#endif245#ifdef CONFIG_ARM64246 { "APMC0D0F", APD_ADDR(xgene_i2c_desc) },247 { "BRCM900D", APD_ADDR(vulcan_spi_desc) },248 { "CAV900D", APD_ADDR(vulcan_spi_desc) },249 { "CAV9007", APD_ADDR(thunderx2_i2c_desc) },250 { "HISI02A1", APD_ADDR(hip07_i2c_desc) },251 { "HISI02A2", APD_ADDR(hip08_i2c_desc) },252 { "HISI02A3", APD_ADDR(hip08_lite_i2c_desc) },253 { "HISI0173", APD_ADDR(hip08_spi_desc) },254 { "NXP0001", APD_ADDR(nxp_i2c_desc) },255#endif256 { }257};258 259static struct acpi_scan_handler apd_handler = {260 .ids = acpi_apd_device_ids,261 .attach = acpi_apd_create_device,262};263 264void __init acpi_apd_init(void)265{266 acpi_scan_add_handler(&apd_handler);267}268