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
;
56 static acpi_status ret
;
58 data
= kzalloc(sizeof(*data
), GFP_KERNEL
);
62 data
->cl
.rx_callback
= pcc_rx_callback
;
63 data
->cl
.knows_txdone
= true;
64 data
->ctx
.length
= ctx
->length
;
65 data
->ctx
.subspace_id
= ctx
->subspace_id
;
66 data
->ctx
.internal_buffer
= ctx
->internal_buffer
;
68 init_completion(&data
->done
);
69 data
->pcc_chan
= pcc_mbox_request_channel(&data
->cl
, ctx
->subspace_id
);
70 if (IS_ERR(data
->pcc_chan
)) {
71 pr_err("Failed to find PCC channel for subspace %d\n",
77 pcc_chan
= data
->pcc_chan
;
78 if (!pcc_chan
->mchan
->mbox
->txdone_irq
) {
79 pr_err("This channel-%d does not support interrupt.\n",
82 goto err_free_channel
;
84 data
->pcc_comm_addr
= acpi_os_ioremap(pcc_chan
->shmem_base_addr
,
85 pcc_chan
->shmem_size
);
86 if (!data
->pcc_comm_addr
) {
87 pr_err("Failed to ioremap PCC comm region mem for %d\n",
90 goto err_free_channel
;
93 *region_context
= data
;
97 pcc_mbox_free_channel(data
->pcc_chan
);
105 acpi_pcc_address_space_handler(u32 function
, acpi_physical_address addr
,
106 u32 bits
, acpi_integer
*value
,
107 void *handler_context
, void *region_context
)
110 struct pcc_data
*data
= region_context
;
113 reinit_completion(&data
->done
);
115 /* Write to Shared Memory */
116 memcpy_toio(data
->pcc_comm_addr
, (void *)value
, data
->ctx
.length
);
118 ret
= mbox_send_message(data
->pcc_chan
->mchan
, NULL
);
123 * pcc_chan->latency is just a Nominal value. In reality the remote
124 * processor could be much slower to reply. So add an arbitrary
125 * amount of wait on top of Nominal.
127 usecs_lat
= PCC_CMD_WAIT_RETRIES_NUM
* data
->pcc_chan
->latency
;
128 ret
= wait_for_completion_timeout(&data
->done
,
129 usecs_to_jiffies(usecs_lat
));
131 pr_err("PCC command executed timeout!\n");
135 mbox_chan_txdone(data
->pcc_chan
->mchan
, ret
);
137 memcpy_fromio(value
, data
->pcc_comm_addr
, data
->ctx
.length
);
142 void __init
acpi_init_pcc(void)
146 status
= acpi_install_address_space_handler(ACPI_ROOT_OBJECT
,
147 ACPI_ADR_SPACE_PLATFORM_COMM
,
148 &acpi_pcc_address_space_handler
,
149 &acpi_pcc_address_space_setup
,
151 if (ACPI_FAILURE(status
))
152 pr_alert("OperationRegion handler could not be installed\n");