Path: blob/master/drivers/firmware/samsung/exynos-acpm.c
26428 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Copyright 2020 Samsung Electronics Co., Ltd.3* Copyright 2020 Google LLC.4* Copyright 2024 Linaro Ltd.5*/67#include <linux/bitfield.h>8#include <linux/bitmap.h>9#include <linux/bits.h>10#include <linux/cleanup.h>11#include <linux/container_of.h>12#include <linux/delay.h>13#include <linux/device.h>14#include <linux/firmware/samsung/exynos-acpm-protocol.h>15#include <linux/io.h>16#include <linux/iopoll.h>17#include <linux/ktime.h>18#include <linux/mailbox/exynos-message.h>19#include <linux/mailbox_client.h>20#include <linux/module.h>21#include <linux/mutex.h>22#include <linux/math.h>23#include <linux/of.h>24#include <linux/of_address.h>25#include <linux/of_platform.h>26#include <linux/platform_device.h>27#include <linux/slab.h>28#include <linux/types.h>2930#include "exynos-acpm.h"31#include "exynos-acpm-pmic.h"3233#define ACPM_PROTOCOL_SEQNUM GENMASK(21, 16)3435#define ACPM_POLL_TIMEOUT_US (100 * USEC_PER_MSEC)36#define ACPM_TX_TIMEOUT_US 5000003738#define ACPM_GS101_INITDATA_BASE 0xa0003940/**41* struct acpm_shmem - shared memory configuration information.42* @reserved: unused fields.43* @chans: offset to array of struct acpm_chan_shmem.44* @reserved1: unused fields.45* @num_chans: number of channels.46*/47struct acpm_shmem {48u32 reserved[2];49u32 chans;50u32 reserved1[3];51u32 num_chans;52};5354/**55* struct acpm_chan_shmem - descriptor of a shared memory channel.56*57* @id: channel ID.58* @reserved: unused fields.59* @rx_rear: rear pointer of APM RX queue (TX for AP).60* @rx_front: front pointer of APM RX queue (TX for AP).61* @rx_base: base address of APM RX queue (TX for AP).62* @reserved1: unused fields.63* @tx_rear: rear pointer of APM TX queue (RX for AP).64* @tx_front: front pointer of APM TX queue (RX for AP).65* @tx_base: base address of APM TX queue (RX for AP).66* @qlen: queue length. Applies to both TX/RX queues.67* @mlen: message length. Applies to both TX/RX queues.68* @reserved2: unused fields.69* @poll_completion: true when the channel works on polling.70*/71struct acpm_chan_shmem {72u32 id;73u32 reserved[3];74u32 rx_rear;75u32 rx_front;76u32 rx_base;77u32 reserved1[3];78u32 tx_rear;79u32 tx_front;80u32 tx_base;81u32 qlen;82u32 mlen;83u32 reserved2[2];84u32 poll_completion;85};8687/**88* struct acpm_queue - exynos acpm queue.89*90* @rear: rear address of the queue.91* @front: front address of the queue.92* @base: base address of the queue.93*/94struct acpm_queue {95void __iomem *rear;96void __iomem *front;97void __iomem *base;98};99100/**101* struct acpm_rx_data - RX queue data.102*103* @cmd: pointer to where the data shall be saved.104* @n_cmd: number of 32-bit commands.105* @response: true if the client expects the RX data.106*/107struct acpm_rx_data {108u32 *cmd;109size_t n_cmd;110bool response;111};112113#define ACPM_SEQNUM_MAX 64114115/**116* struct acpm_chan - driver internal representation of a channel.117* @cl: mailbox client.118* @chan: mailbox channel.119* @acpm: pointer to driver private data.120* @tx: TX queue. The enqueue is done by the host.121* - front index is written by the host.122* - rear index is written by the firmware.123*124* @rx: RX queue. The enqueue is done by the firmware.125* - front index is written by the firmware.126* - rear index is written by the host.127* @tx_lock: protects TX queue.128* @rx_lock: protects RX queue.129* @qlen: queue length. Applies to both TX/RX queues.130* @mlen: message length. Applies to both TX/RX queues.131* @seqnum: sequence number of the last message enqueued on TX queue.132* @id: channel ID.133* @poll_completion: indicates if the transfer needs to be polled for134* completion or interrupt mode is used.135* @bitmap_seqnum: bitmap that tracks the messages on the TX/RX queues.136* @rx_data: internal buffer used to drain the RX queue.137*/138struct acpm_chan {139struct mbox_client cl;140struct mbox_chan *chan;141struct acpm_info *acpm;142struct acpm_queue tx;143struct acpm_queue rx;144struct mutex tx_lock;145struct mutex rx_lock;146147unsigned int qlen;148unsigned int mlen;149u8 seqnum;150u8 id;151bool poll_completion;152153DECLARE_BITMAP(bitmap_seqnum, ACPM_SEQNUM_MAX - 1);154struct acpm_rx_data rx_data[ACPM_SEQNUM_MAX];155};156157/**158* struct acpm_info - driver's private data.159* @shmem: pointer to the SRAM configuration data.160* @sram_base: base address of SRAM.161* @chans: pointer to the ACPM channel parameters retrieved from SRAM.162* @dev: pointer to the exynos-acpm device.163* @handle: instance of acpm_handle to send to clients.164* @num_chans: number of channels available for this controller.165*/166struct acpm_info {167struct acpm_shmem __iomem *shmem;168void __iomem *sram_base;169struct acpm_chan *chans;170struct device *dev;171struct acpm_handle handle;172u32 num_chans;173};174175/**176* struct acpm_match_data - of_device_id data.177* @initdata_base: offset in SRAM where the channels configuration resides.178*/179struct acpm_match_data {180loff_t initdata_base;181};182183#define client_to_acpm_chan(c) container_of(c, struct acpm_chan, cl)184#define handle_to_acpm_info(h) container_of(h, struct acpm_info, handle)185186/**187* acpm_get_saved_rx() - get the response if it was already saved.188* @achan: ACPM channel info.189* @xfer: reference to the transfer to get response for.190* @tx_seqnum: xfer TX sequence number.191*/192static void acpm_get_saved_rx(struct acpm_chan *achan,193const struct acpm_xfer *xfer, u32 tx_seqnum)194{195const struct acpm_rx_data *rx_data = &achan->rx_data[tx_seqnum - 1];196u32 rx_seqnum;197198if (!rx_data->response)199return;200201rx_seqnum = FIELD_GET(ACPM_PROTOCOL_SEQNUM, rx_data->cmd[0]);202203if (rx_seqnum == tx_seqnum) {204memcpy(xfer->rxd, rx_data->cmd, xfer->rxlen);205clear_bit(rx_seqnum - 1, achan->bitmap_seqnum);206}207}208209/**210* acpm_get_rx() - get response from RX queue.211* @achan: ACPM channel info.212* @xfer: reference to the transfer to get response for.213*214* Return: 0 on success, -errno otherwise.215*/216static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer)217{218u32 rx_front, rx_seqnum, tx_seqnum, seqnum;219const void __iomem *base, *addr;220struct acpm_rx_data *rx_data;221u32 i, val, mlen;222bool rx_set = false;223224guard(mutex)(&achan->rx_lock);225226rx_front = readl(achan->rx.front);227i = readl(achan->rx.rear);228229tx_seqnum = FIELD_GET(ACPM_PROTOCOL_SEQNUM, xfer->txd[0]);230231if (i == rx_front) {232acpm_get_saved_rx(achan, xfer, tx_seqnum);233return 0;234}235236base = achan->rx.base;237mlen = achan->mlen;238239/* Drain RX queue. */240do {241/* Read RX seqnum. */242addr = base + mlen * i;243val = readl(addr);244245rx_seqnum = FIELD_GET(ACPM_PROTOCOL_SEQNUM, val);246if (!rx_seqnum)247return -EIO;248/*249* mssg seqnum starts with value 1, whereas the driver considers250* the first mssg at index 0.251*/252seqnum = rx_seqnum - 1;253rx_data = &achan->rx_data[seqnum];254255if (rx_data->response) {256if (rx_seqnum == tx_seqnum) {257__ioread32_copy(xfer->rxd, addr,258xfer->rxlen / 4);259rx_set = true;260clear_bit(seqnum, achan->bitmap_seqnum);261} else {262/*263* The RX data corresponds to another request.264* Save the data to drain the queue, but don't265* clear yet the bitmap. It will be cleared266* after the response is copied to the request.267*/268__ioread32_copy(rx_data->cmd, addr,269xfer->rxlen / 4);270}271} else {272clear_bit(seqnum, achan->bitmap_seqnum);273}274275i = (i + 1) % achan->qlen;276} while (i != rx_front);277278/* We saved all responses, mark RX empty. */279writel(rx_front, achan->rx.rear);280281/*282* If the response was not in this iteration of the queue, check if the283* RX data was previously saved.284*/285if (!rx_set)286acpm_get_saved_rx(achan, xfer, tx_seqnum);287288return 0;289}290291/**292* acpm_dequeue_by_polling() - RX dequeue by polling.293* @achan: ACPM channel info.294* @xfer: reference to the transfer being waited for.295*296* Return: 0 on success, -errno otherwise.297*/298static int acpm_dequeue_by_polling(struct acpm_chan *achan,299const struct acpm_xfer *xfer)300{301struct device *dev = achan->acpm->dev;302ktime_t timeout;303u32 seqnum;304int ret;305306seqnum = FIELD_GET(ACPM_PROTOCOL_SEQNUM, xfer->txd[0]);307308timeout = ktime_add_us(ktime_get(), ACPM_POLL_TIMEOUT_US);309do {310ret = acpm_get_rx(achan, xfer);311if (ret)312return ret;313314if (!test_bit(seqnum - 1, achan->bitmap_seqnum))315return 0;316317/* Determined experimentally. */318udelay(20);319} while (ktime_before(ktime_get(), timeout));320321dev_err(dev, "Timeout! ch:%u s:%u bitmap:%lx.\n",322achan->id, seqnum, achan->bitmap_seqnum[0]);323324return -ETIME;325}326327/**328* acpm_wait_for_queue_slots() - wait for queue slots.329*330* @achan: ACPM channel info.331* @next_tx_front: next front index of the TX queue.332*333* Return: 0 on success, -errno otherwise.334*/335static int acpm_wait_for_queue_slots(struct acpm_chan *achan, u32 next_tx_front)336{337u32 val, ret;338339/*340* Wait for RX front to keep up with TX front. Make sure there's at341* least one element between them.342*/343ret = readl_poll_timeout(achan->rx.front, val, next_tx_front != val, 0,344ACPM_TX_TIMEOUT_US);345if (ret) {346dev_err(achan->acpm->dev, "RX front can not keep up with TX front.\n");347return ret;348}349350ret = readl_poll_timeout(achan->tx.rear, val, next_tx_front != val, 0,351ACPM_TX_TIMEOUT_US);352if (ret)353dev_err(achan->acpm->dev, "TX queue is full.\n");354355return ret;356}357358/**359* acpm_prepare_xfer() - prepare a transfer before writing the message to the360* TX queue.361* @achan: ACPM channel info.362* @xfer: reference to the transfer being prepared.363*/364static void acpm_prepare_xfer(struct acpm_chan *achan,365const struct acpm_xfer *xfer)366{367struct acpm_rx_data *rx_data;368u32 *txd = (u32 *)xfer->txd;369370/* Prevent chan->seqnum from being re-used */371do {372if (++achan->seqnum == ACPM_SEQNUM_MAX)373achan->seqnum = 1;374} while (test_bit(achan->seqnum - 1, achan->bitmap_seqnum));375376txd[0] |= FIELD_PREP(ACPM_PROTOCOL_SEQNUM, achan->seqnum);377378/* Clear data for upcoming responses */379rx_data = &achan->rx_data[achan->seqnum - 1];380memset(rx_data->cmd, 0, sizeof(*rx_data->cmd) * rx_data->n_cmd);381if (xfer->rxd)382rx_data->response = true;383384/* Flag the index based on seqnum. (seqnum: 1~63, bitmap: 0~62) */385set_bit(achan->seqnum - 1, achan->bitmap_seqnum);386}387388/**389* acpm_wait_for_message_response - an helper to group all possible ways of390* waiting for a synchronous message response.391*392* @achan: ACPM channel info.393* @xfer: reference to the transfer being waited for.394*395* Return: 0 on success, -errno otherwise.396*/397static int acpm_wait_for_message_response(struct acpm_chan *achan,398const struct acpm_xfer *xfer)399{400/* Just polling mode supported for now. */401return acpm_dequeue_by_polling(achan, xfer);402}403404/**405* acpm_do_xfer() - do one transfer.406* @handle: pointer to the acpm handle.407* @xfer: transfer to initiate and wait for response.408*409* Return: 0 on success, -errno otherwise.410*/411int acpm_do_xfer(const struct acpm_handle *handle, const struct acpm_xfer *xfer)412{413struct acpm_info *acpm = handle_to_acpm_info(handle);414struct exynos_mbox_msg msg;415struct acpm_chan *achan;416u32 idx, tx_front;417int ret;418419if (xfer->acpm_chan_id >= acpm->num_chans)420return -EINVAL;421422achan = &acpm->chans[xfer->acpm_chan_id];423424if (!xfer->txd || xfer->txlen > achan->mlen || xfer->rxlen > achan->mlen)425return -EINVAL;426427if (!achan->poll_completion) {428dev_err(achan->acpm->dev, "Interrupt mode not supported\n");429return -EOPNOTSUPP;430}431432msg.chan_id = xfer->acpm_chan_id;433msg.chan_type = EXYNOS_MBOX_CHAN_TYPE_DOORBELL;434435scoped_guard(mutex, &achan->tx_lock) {436tx_front = readl(achan->tx.front);437idx = (tx_front + 1) % achan->qlen;438439ret = acpm_wait_for_queue_slots(achan, idx);440if (ret)441return ret;442443acpm_prepare_xfer(achan, xfer);444445/* Write TX command. */446__iowrite32_copy(achan->tx.base + achan->mlen * tx_front,447xfer->txd, xfer->txlen / 4);448449/* Advance TX front. */450writel(idx, achan->tx.front);451452ret = mbox_send_message(achan->chan, (void *)&msg);453if (ret < 0)454return ret;455456mbox_client_txdone(achan->chan, 0);457}458459return acpm_wait_for_message_response(achan, xfer);460}461462/**463* acpm_chan_shmem_get_params() - get channel parameters and addresses of the464* TX/RX queues.465* @achan: ACPM channel info.466* @chan_shmem: __iomem pointer to a channel described in shared memory.467*/468static void acpm_chan_shmem_get_params(struct acpm_chan *achan,469struct acpm_chan_shmem __iomem *chan_shmem)470{471void __iomem *base = achan->acpm->sram_base;472struct acpm_queue *rx = &achan->rx;473struct acpm_queue *tx = &achan->tx;474475achan->mlen = readl(&chan_shmem->mlen);476achan->poll_completion = readl(&chan_shmem->poll_completion);477achan->id = readl(&chan_shmem->id);478achan->qlen = readl(&chan_shmem->qlen);479480tx->base = base + readl(&chan_shmem->rx_base);481tx->rear = base + readl(&chan_shmem->rx_rear);482tx->front = base + readl(&chan_shmem->rx_front);483484rx->base = base + readl(&chan_shmem->tx_base);485rx->rear = base + readl(&chan_shmem->tx_rear);486rx->front = base + readl(&chan_shmem->tx_front);487488dev_vdbg(achan->acpm->dev, "ID = %d poll = %d, mlen = %d, qlen = %d\n",489achan->id, achan->poll_completion, achan->mlen, achan->qlen);490}491492/**493* acpm_achan_alloc_cmds() - allocate buffers for retrieving data from the ACPM494* firmware.495* @achan: ACPM channel info.496*497* Return: 0 on success, -errno otherwise.498*/499static int acpm_achan_alloc_cmds(struct acpm_chan *achan)500{501struct device *dev = achan->acpm->dev;502struct acpm_rx_data *rx_data;503size_t cmd_size, n_cmd;504int i;505506if (achan->mlen == 0)507return 0;508509cmd_size = sizeof(*(achan->rx_data[0].cmd));510n_cmd = DIV_ROUND_UP_ULL(achan->mlen, cmd_size);511512for (i = 0; i < ACPM_SEQNUM_MAX; i++) {513rx_data = &achan->rx_data[i];514rx_data->n_cmd = n_cmd;515rx_data->cmd = devm_kcalloc(dev, n_cmd, cmd_size, GFP_KERNEL);516if (!rx_data->cmd)517return -ENOMEM;518}519520return 0;521}522523/**524* acpm_free_mbox_chans() - free mailbox channels.525* @acpm: pointer to driver data.526*/527static void acpm_free_mbox_chans(struct acpm_info *acpm)528{529int i;530531for (i = 0; i < acpm->num_chans; i++)532if (!IS_ERR_OR_NULL(acpm->chans[i].chan))533mbox_free_channel(acpm->chans[i].chan);534}535536/**537* acpm_channels_init() - initialize channels based on the configuration data in538* the shared memory.539* @acpm: pointer to driver data.540*541* Return: 0 on success, -errno otherwise.542*/543static int acpm_channels_init(struct acpm_info *acpm)544{545struct acpm_shmem __iomem *shmem = acpm->shmem;546struct acpm_chan_shmem __iomem *chans_shmem;547struct device *dev = acpm->dev;548int i, ret;549550acpm->num_chans = readl(&shmem->num_chans);551acpm->chans = devm_kcalloc(dev, acpm->num_chans, sizeof(*acpm->chans),552GFP_KERNEL);553if (!acpm->chans)554return -ENOMEM;555556chans_shmem = acpm->sram_base + readl(&shmem->chans);557558for (i = 0; i < acpm->num_chans; i++) {559struct acpm_chan_shmem __iomem *chan_shmem = &chans_shmem[i];560struct acpm_chan *achan = &acpm->chans[i];561struct mbox_client *cl = &achan->cl;562563achan->acpm = acpm;564565acpm_chan_shmem_get_params(achan, chan_shmem);566567ret = acpm_achan_alloc_cmds(achan);568if (ret)569return ret;570571mutex_init(&achan->rx_lock);572mutex_init(&achan->tx_lock);573574cl->dev = dev;575576achan->chan = mbox_request_channel(cl, 0);577if (IS_ERR(achan->chan)) {578acpm_free_mbox_chans(acpm);579return PTR_ERR(achan->chan);580}581}582583return 0;584}585586/**587* acpm_setup_ops() - setup the operations structures.588* @acpm: pointer to the driver data.589*/590static void acpm_setup_ops(struct acpm_info *acpm)591{592struct acpm_pmic_ops *pmic_ops = &acpm->handle.ops.pmic_ops;593594pmic_ops->read_reg = acpm_pmic_read_reg;595pmic_ops->bulk_read = acpm_pmic_bulk_read;596pmic_ops->write_reg = acpm_pmic_write_reg;597pmic_ops->bulk_write = acpm_pmic_bulk_write;598pmic_ops->update_reg = acpm_pmic_update_reg;599}600601static int acpm_probe(struct platform_device *pdev)602{603const struct acpm_match_data *match_data;604struct device *dev = &pdev->dev;605struct device_node *shmem;606struct acpm_info *acpm;607resource_size_t size;608struct resource res;609int ret;610611acpm = devm_kzalloc(dev, sizeof(*acpm), GFP_KERNEL);612if (!acpm)613return -ENOMEM;614615shmem = of_parse_phandle(dev->of_node, "shmem", 0);616ret = of_address_to_resource(shmem, 0, &res);617of_node_put(shmem);618if (ret)619return dev_err_probe(dev, ret,620"Failed to get shared memory.\n");621622size = resource_size(&res);623acpm->sram_base = devm_ioremap(dev, res.start, size);624if (!acpm->sram_base)625return dev_err_probe(dev, -ENOMEM,626"Failed to ioremap shared memory.\n");627628match_data = of_device_get_match_data(dev);629if (!match_data)630return dev_err_probe(dev, -EINVAL,631"Failed to get match data.\n");632633acpm->shmem = acpm->sram_base + match_data->initdata_base;634acpm->dev = dev;635636ret = acpm_channels_init(acpm);637if (ret)638return ret;639640acpm_setup_ops(acpm);641642platform_set_drvdata(pdev, acpm);643644return devm_of_platform_populate(dev);645}646647/**648* acpm_handle_put() - release the handle acquired by acpm_get_by_phandle.649* @handle: Handle acquired by acpm_get_by_phandle.650*/651static void acpm_handle_put(const struct acpm_handle *handle)652{653struct acpm_info *acpm = handle_to_acpm_info(handle);654struct device *dev = acpm->dev;655656module_put(dev->driver->owner);657/* Drop reference taken with of_find_device_by_node(). */658put_device(dev);659}660661/**662* devm_acpm_release() - devres release method.663* @dev: pointer to device.664* @res: pointer to resource.665*/666static void devm_acpm_release(struct device *dev, void *res)667{668acpm_handle_put(*(struct acpm_handle **)res);669}670671/**672* acpm_get_by_node() - get the ACPM handle using node pointer.673* @dev: device pointer requesting ACPM handle.674* @np: ACPM device tree node.675*676* Return: pointer to handle on success, ERR_PTR(-errno) otherwise.677*/678static const struct acpm_handle *acpm_get_by_node(struct device *dev,679struct device_node *np)680{681struct platform_device *pdev;682struct device_link *link;683struct acpm_info *acpm;684685pdev = of_find_device_by_node(np);686if (!pdev)687return ERR_PTR(-EPROBE_DEFER);688689acpm = platform_get_drvdata(pdev);690if (!acpm) {691platform_device_put(pdev);692return ERR_PTR(-EPROBE_DEFER);693}694695if (!try_module_get(pdev->dev.driver->owner)) {696platform_device_put(pdev);697return ERR_PTR(-EPROBE_DEFER);698}699700link = device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER);701if (!link) {702dev_err(&pdev->dev,703"Failed to create device link to consumer %s.\n",704dev_name(dev));705platform_device_put(pdev);706module_put(pdev->dev.driver->owner);707return ERR_PTR(-EINVAL);708}709710return &acpm->handle;711}712713/**714* devm_acpm_get_by_node() - managed get handle using node pointer.715* @dev: device pointer requesting ACPM handle.716* @np: ACPM device tree node.717*718* Return: pointer to handle on success, ERR_PTR(-errno) otherwise.719*/720const struct acpm_handle *devm_acpm_get_by_node(struct device *dev,721struct device_node *np)722{723const struct acpm_handle **ptr, *handle;724725ptr = devres_alloc(devm_acpm_release, sizeof(*ptr), GFP_KERNEL);726if (!ptr)727return ERR_PTR(-ENOMEM);728729handle = acpm_get_by_node(dev, np);730if (!IS_ERR(handle)) {731*ptr = handle;732devres_add(dev, ptr);733} else {734devres_free(ptr);735}736737return handle;738}739EXPORT_SYMBOL_GPL(devm_acpm_get_by_node);740741static const struct acpm_match_data acpm_gs101 = {742.initdata_base = ACPM_GS101_INITDATA_BASE,743};744745static const struct of_device_id acpm_match[] = {746{747.compatible = "google,gs101-acpm-ipc",748.data = &acpm_gs101,749},750{},751};752MODULE_DEVICE_TABLE(of, acpm_match);753754static struct platform_driver acpm_driver = {755.probe = acpm_probe,756.driver = {757.name = "exynos-acpm-protocol",758.of_match_table = acpm_match,759},760};761module_platform_driver(acpm_driver);762763MODULE_AUTHOR("Tudor Ambarus <[email protected]>");764MODULE_DESCRIPTION("Samsung Exynos ACPM mailbox protocol driver");765MODULE_LICENSE("GPL");766767768