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