1 // SPDX-License-Identifier: GPL-2.0-only
3 * Author: Sudeep Holla <sudeep.holla@arm.com>
4 * Copyright 2021 Arm Limited
6 * The PCC Address Space also referred as PCC Operation Region pertains to the
7 * region of PCC subspace that succeeds the PCC signature. The PCC Operation
8 * Region works in conjunction with the PCC Table(Platform Communications
9 * Channel Table). PCC subspaces that are marked for use as PCC Operation
10 * Regions must not be used as PCC subspaces for the standard ACPI features
11 * such as CPPC, RASF, PDTT and MPST. These standard features must always use
12 * the PCC Table instead.
14 * This driver sets up the PCC Address Space and installs an handler to enable
15 * handling of PCC OpRegion in the firmware.
18 #include <linux/kernel.h>
19 #include <linux/acpi.h>
20 #include <linux/completion.h>
21 #include <linux/idr.h>
27 * Arbitrary retries in case the remote processor is slow to respond
30 #define PCC_CMD_WAIT_RETRIES_NUM 500ULL
33 struct pcc_mbox_chan *pcc_chan;
34 void __iomem *pcc_comm_addr;
35 struct completion done;
36 struct mbox_client cl;
37 struct acpi_pcc_info ctx;
40 static struct acpi_pcc_info pcc_ctx;
42 static void pcc_rx_callback(struct mbox_client *cl, void *m)
44 struct pcc_data *data = container_of(cl, struct pcc_data, cl);
46 complete(&data->done);
50 acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,
51 void *handler_context, void **region_context)
53 struct pcc_data *data;
54 struct acpi_pcc_info *ctx = handler_context;
55 struct pcc_mbox_chan *pcc_chan;
57 data = kzalloc(sizeof(*data), GFP_KERNEL);
61 data->cl.rx_callback = pcc_rx_callback;
62 data->cl.knows_txdone = true;
63 data->ctx.length = ctx->length;
64 data->ctx.subspace_id = ctx->subspace_id;
65 data->ctx.internal_buffer = ctx->internal_buffer;
67 init_completion(&data->done);
68 data->pcc_chan = pcc_mbox_request_channel(&data->cl, ctx->subspace_id);
69 if (IS_ERR(data->pcc_chan)) {
70 pr_err("Failed to find PCC channel for subspace %d\n",
76 pcc_chan = data->pcc_chan;
77 data->pcc_comm_addr = acpi_os_ioremap(pcc_chan->shmem_base_addr,
78 pcc_chan->shmem_size);
79 if (!data->pcc_comm_addr) {
80 pr_err("Failed to ioremap PCC comm region mem for %d\n",
82 pcc_mbox_free_channel(data->pcc_chan);
87 *region_context = data;
92 acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr,
93 u32 bits, acpi_integer *value,
94 void *handler_context, void *region_context)
97 struct pcc_data *data = region_context;
100 reinit_completion(&data->done);
102 /* Write to Shared Memory */
103 memcpy_toio(data->pcc_comm_addr, (void *)value, data->ctx.length);
105 ret = mbox_send_message(data->pcc_chan->mchan, NULL);
109 if (data->pcc_chan->mchan->mbox->txdone_irq) {
111 * pcc_chan->latency is just a Nominal value. In reality the remote
112 * processor could be much slower to reply. So add an arbitrary
113 * amount of wait on top of Nominal.
115 usecs_lat = PCC_CMD_WAIT_RETRIES_NUM * data->pcc_chan->latency;
116 ret = wait_for_completion_timeout(&data->done,
117 usecs_to_jiffies(usecs_lat));
119 pr_err("PCC command executed timeout!\n");
124 mbox_chan_txdone(data->pcc_chan->mchan, ret);
126 memcpy_fromio(value, data->pcc_comm_addr, data->ctx.length);
131 void __init acpi_init_pcc(void)
135 status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
136 ACPI_ADR_SPACE_PLATFORM_COMM,
137 &acpi_pcc_address_space_handler,
138 &acpi_pcc_address_space_setup,
140 if (ACPI_FAILURE(status))
141 pr_alert("OperationRegion handler could not be installed\n");