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