xref: /openbmc/linux/drivers/acpi/acpi_pcc.c (revision 77e2a04745ff8e391ad402e2d2d1157a5d3a7ebc)
1*77e2a047SSudeep Holla // SPDX-License-Identifier: GPL-2.0-only
2*77e2a047SSudeep Holla /*
3*77e2a047SSudeep Holla  * Author: Sudeep Holla <sudeep.holla@arm.com>
4*77e2a047SSudeep Holla  * Copyright 2021 Arm Limited
5*77e2a047SSudeep Holla  *
6*77e2a047SSudeep Holla  * The PCC Address Space also referred as PCC Operation Region pertains to the
7*77e2a047SSudeep Holla  * region of PCC subspace that succeeds the PCC signature. The PCC Operation
8*77e2a047SSudeep Holla  * Region works in conjunction with the PCC Table(Platform Communications
9*77e2a047SSudeep Holla  * Channel Table). PCC subspaces that are marked for use as PCC Operation
10*77e2a047SSudeep Holla  * Regions must not be used as PCC subspaces for the standard ACPI features
11*77e2a047SSudeep Holla  * such as CPPC, RASF, PDTT and MPST. These standard features must always use
12*77e2a047SSudeep Holla  * the PCC Table instead.
13*77e2a047SSudeep Holla  *
14*77e2a047SSudeep Holla  * This driver sets up the PCC Address Space and installs an handler to enable
15*77e2a047SSudeep Holla  * handling of PCC OpRegion in the firmware.
16*77e2a047SSudeep Holla  *
17*77e2a047SSudeep Holla  */
18*77e2a047SSudeep Holla #include <linux/kernel.h>
19*77e2a047SSudeep Holla #include <linux/acpi.h>
20*77e2a047SSudeep Holla #include <linux/completion.h>
21*77e2a047SSudeep Holla #include <linux/idr.h>
22*77e2a047SSudeep Holla #include <linux/io.h>
23*77e2a047SSudeep Holla 
24*77e2a047SSudeep Holla #include <acpi/pcc.h>
25*77e2a047SSudeep Holla 
26*77e2a047SSudeep Holla struct pcc_data {
27*77e2a047SSudeep Holla 	struct pcc_mbox_chan *pcc_chan;
28*77e2a047SSudeep Holla 	void __iomem *pcc_comm_addr;
29*77e2a047SSudeep Holla 	struct completion done;
30*77e2a047SSudeep Holla 	struct mbox_client cl;
31*77e2a047SSudeep Holla 	struct acpi_pcc_info ctx;
32*77e2a047SSudeep Holla };
33*77e2a047SSudeep Holla 
34*77e2a047SSudeep Holla struct acpi_pcc_info pcc_ctx;
35*77e2a047SSudeep Holla 
36*77e2a047SSudeep Holla static void pcc_rx_callback(struct mbox_client *cl, void *m)
37*77e2a047SSudeep Holla {
38*77e2a047SSudeep Holla 	struct pcc_data *data = container_of(cl, struct pcc_data, cl);
39*77e2a047SSudeep Holla 
40*77e2a047SSudeep Holla 	complete(&data->done);
41*77e2a047SSudeep Holla }
42*77e2a047SSudeep Holla 
43*77e2a047SSudeep Holla static acpi_status
44*77e2a047SSudeep Holla acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,
45*77e2a047SSudeep Holla 			     void *handler_context,  void **region_context)
46*77e2a047SSudeep Holla {
47*77e2a047SSudeep Holla 	struct pcc_data *data;
48*77e2a047SSudeep Holla 	struct acpi_pcc_info *ctx = handler_context;
49*77e2a047SSudeep Holla 	struct pcc_mbox_chan *pcc_chan;
50*77e2a047SSudeep Holla 
51*77e2a047SSudeep Holla 	data = kzalloc(sizeof(*data), GFP_KERNEL);
52*77e2a047SSudeep Holla 	if (!data)
53*77e2a047SSudeep Holla 		return AE_NO_MEMORY;
54*77e2a047SSudeep Holla 
55*77e2a047SSudeep Holla 	data->cl.rx_callback = pcc_rx_callback;
56*77e2a047SSudeep Holla 	data->cl.knows_txdone = true;
57*77e2a047SSudeep Holla 	data->ctx.length = ctx->length;
58*77e2a047SSudeep Holla 	data->ctx.subspace_id = ctx->subspace_id;
59*77e2a047SSudeep Holla 	data->ctx.internal_buffer = ctx->internal_buffer;
60*77e2a047SSudeep Holla 
61*77e2a047SSudeep Holla 	init_completion(&data->done);
62*77e2a047SSudeep Holla 	data->pcc_chan = pcc_mbox_request_channel(&data->cl, ctx->subspace_id);
63*77e2a047SSudeep Holla 	if (IS_ERR(data->pcc_chan)) {
64*77e2a047SSudeep Holla 		pr_err("Failed to find PCC channel for subspace %d\n",
65*77e2a047SSudeep Holla 		       ctx->subspace_id);
66*77e2a047SSudeep Holla 		return AE_NOT_FOUND;
67*77e2a047SSudeep Holla 	}
68*77e2a047SSudeep Holla 
69*77e2a047SSudeep Holla 	pcc_chan = data->pcc_chan;
70*77e2a047SSudeep Holla 	data->pcc_comm_addr = acpi_os_ioremap(pcc_chan->shmem_base_addr,
71*77e2a047SSudeep Holla 					      pcc_chan->shmem_size);
72*77e2a047SSudeep Holla 	if (!data->pcc_comm_addr) {
73*77e2a047SSudeep Holla 		pr_err("Failed to ioremap PCC comm region mem for %d\n",
74*77e2a047SSudeep Holla 		       ctx->subspace_id);
75*77e2a047SSudeep Holla 		return AE_NO_MEMORY;
76*77e2a047SSudeep Holla 	}
77*77e2a047SSudeep Holla 
78*77e2a047SSudeep Holla 	*region_context = data;
79*77e2a047SSudeep Holla 	return AE_OK;
80*77e2a047SSudeep Holla }
81*77e2a047SSudeep Holla 
82*77e2a047SSudeep Holla static acpi_status
83*77e2a047SSudeep Holla acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr,
84*77e2a047SSudeep Holla 			       u32 bits, acpi_integer *value,
85*77e2a047SSudeep Holla 			       void *handler_context, void *region_context)
86*77e2a047SSudeep Holla {
87*77e2a047SSudeep Holla 	int ret;
88*77e2a047SSudeep Holla 	struct pcc_data *data = region_context;
89*77e2a047SSudeep Holla 
90*77e2a047SSudeep Holla 	reinit_completion(&data->done);
91*77e2a047SSudeep Holla 
92*77e2a047SSudeep Holla 	/* Write to Shared Memory */
93*77e2a047SSudeep Holla 	memcpy_toio(data->pcc_comm_addr, (void *)value, data->ctx.length);
94*77e2a047SSudeep Holla 
95*77e2a047SSudeep Holla 	ret = mbox_send_message(data->pcc_chan->mchan, NULL);
96*77e2a047SSudeep Holla 	if (ret < 0)
97*77e2a047SSudeep Holla 		return AE_ERROR;
98*77e2a047SSudeep Holla 
99*77e2a047SSudeep Holla 	if (data->pcc_chan->mchan->mbox->txdone_irq)
100*77e2a047SSudeep Holla 		wait_for_completion(&data->done);
101*77e2a047SSudeep Holla 
102*77e2a047SSudeep Holla 	mbox_client_txdone(data->pcc_chan->mchan, ret);
103*77e2a047SSudeep Holla 
104*77e2a047SSudeep Holla 	memcpy_fromio(value, data->pcc_comm_addr, data->ctx.length);
105*77e2a047SSudeep Holla 
106*77e2a047SSudeep Holla 	return AE_OK;
107*77e2a047SSudeep Holla }
108*77e2a047SSudeep Holla 
109*77e2a047SSudeep Holla void __init acpi_init_pcc(void)
110*77e2a047SSudeep Holla {
111*77e2a047SSudeep Holla 	acpi_status status;
112*77e2a047SSudeep Holla 
113*77e2a047SSudeep Holla 	status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
114*77e2a047SSudeep Holla 						    ACPI_ADR_SPACE_PLATFORM_COMM,
115*77e2a047SSudeep Holla 						    &acpi_pcc_address_space_handler,
116*77e2a047SSudeep Holla 						    &acpi_pcc_address_space_setup,
117*77e2a047SSudeep Holla 						    &pcc_ctx);
118*77e2a047SSudeep Holla 	if (ACPI_FAILURE(status))
119*77e2a047SSudeep Holla 		pr_alert("OperationRegion handler could not be installed\n");
120*77e2a047SSudeep Holla }
121