linux/drivers/soc/qcom/qcom_aoss.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2019, Linaro Ltd
   4 */
   5#include <dt-bindings/power/qcom-aoss-qmp.h>
   6#include <linux/clk-provider.h>
   7#include <linux/interrupt.h>
   8#include <linux/io.h>
   9#include <linux/mailbox_client.h>
  10#include <linux/module.h>
  11#include <linux/platform_device.h>
  12#include <linux/pm_domain.h>
  13
  14#define QMP_DESC_MAGIC                  0x0
  15#define QMP_DESC_VERSION                0x4
  16#define QMP_DESC_FEATURES               0x8
  17
  18/* AOP-side offsets */
  19#define QMP_DESC_UCORE_LINK_STATE       0xc
  20#define QMP_DESC_UCORE_LINK_STATE_ACK   0x10
  21#define QMP_DESC_UCORE_CH_STATE         0x14
  22#define QMP_DESC_UCORE_CH_STATE_ACK     0x18
  23#define QMP_DESC_UCORE_MBOX_SIZE        0x1c
  24#define QMP_DESC_UCORE_MBOX_OFFSET      0x20
  25
  26/* Linux-side offsets */
  27#define QMP_DESC_MCORE_LINK_STATE       0x24
  28#define QMP_DESC_MCORE_LINK_STATE_ACK   0x28
  29#define QMP_DESC_MCORE_CH_STATE         0x2c
  30#define QMP_DESC_MCORE_CH_STATE_ACK     0x30
  31#define QMP_DESC_MCORE_MBOX_SIZE        0x34
  32#define QMP_DESC_MCORE_MBOX_OFFSET      0x38
  33
  34#define QMP_STATE_UP                    GENMASK(15, 0)
  35#define QMP_STATE_DOWN                  GENMASK(31, 16)
  36
  37#define QMP_MAGIC                       0x4d41494c /* mail */
  38#define QMP_VERSION                     1
  39
  40/* 64 bytes is enough to store the requests and provides padding to 4 bytes */
  41#define QMP_MSG_LEN                     64
  42
  43/**
  44 * struct qmp - driver state for QMP implementation
  45 * @msgram: iomem referencing the message RAM used for communication
  46 * @dev: reference to QMP device
  47 * @mbox_client: mailbox client used to ring the doorbell on transmit
  48 * @mbox_chan: mailbox channel used to ring the doorbell on transmit
  49 * @offset: offset within @msgram where messages should be written
  50 * @size: maximum size of the messages to be transmitted
  51 * @event: wait_queue for synchronization with the IRQ
  52 * @tx_lock: provides synchronization between multiple callers of qmp_send()
  53 * @qdss_clk: QDSS clock hw struct
  54 * @pd_data: genpd data
  55 */
  56struct qmp {
  57        void __iomem *msgram;
  58        struct device *dev;
  59
  60        struct mbox_client mbox_client;
  61        struct mbox_chan *mbox_chan;
  62
  63        size_t offset;
  64        size_t size;
  65
  66        wait_queue_head_t event;
  67
  68        struct mutex tx_lock;
  69
  70        struct clk_hw qdss_clk;
  71        struct genpd_onecell_data pd_data;
  72};
  73
  74struct qmp_pd {
  75        struct qmp *qmp;
  76        struct generic_pm_domain pd;
  77};
  78
  79#define to_qmp_pd_resource(res) container_of(res, struct qmp_pd, pd)
  80
  81static void qmp_kick(struct qmp *qmp)
  82{
  83        mbox_send_message(qmp->mbox_chan, NULL);
  84        mbox_client_txdone(qmp->mbox_chan, 0);
  85}
  86
  87static bool qmp_magic_valid(struct qmp *qmp)
  88{
  89        return readl(qmp->msgram + QMP_DESC_MAGIC) == QMP_MAGIC;
  90}
  91
  92static bool qmp_link_acked(struct qmp *qmp)
  93{
  94        return readl(qmp->msgram + QMP_DESC_MCORE_LINK_STATE_ACK) == QMP_STATE_UP;
  95}
  96
  97static bool qmp_mcore_channel_acked(struct qmp *qmp)
  98{
  99        return readl(qmp->msgram + QMP_DESC_MCORE_CH_STATE_ACK) == QMP_STATE_UP;
 100}
 101
 102static bool qmp_ucore_channel_up(struct qmp *qmp)
 103{
 104        return readl(qmp->msgram + QMP_DESC_UCORE_CH_STATE) == QMP_STATE_UP;
 105}
 106
 107static int qmp_open(struct qmp *qmp)
 108{
 109        int ret;
 110        u32 val;
 111
 112        if (!qmp_magic_valid(qmp)) {
 113                dev_err(qmp->dev, "QMP magic doesn't match\n");
 114                return -EINVAL;
 115        }
 116
 117        val = readl(qmp->msgram + QMP_DESC_VERSION);
 118        if (val != QMP_VERSION) {
 119                dev_err(qmp->dev, "unsupported QMP version %d\n", val);
 120                return -EINVAL;
 121        }
 122
 123        qmp->offset = readl(qmp->msgram + QMP_DESC_MCORE_MBOX_OFFSET);
 124        qmp->size = readl(qmp->msgram + QMP_DESC_MCORE_MBOX_SIZE);
 125        if (!qmp->size) {
 126                dev_err(qmp->dev, "invalid mailbox size\n");
 127                return -EINVAL;
 128        }
 129
 130        /* Ack remote core's link state */
 131        val = readl(qmp->msgram + QMP_DESC_UCORE_LINK_STATE);
 132        writel(val, qmp->msgram + QMP_DESC_UCORE_LINK_STATE_ACK);
 133
 134        /* Set local core's link state to up */
 135        writel(QMP_STATE_UP, qmp->msgram + QMP_DESC_MCORE_LINK_STATE);
 136
 137        qmp_kick(qmp);
 138
 139        ret = wait_event_timeout(qmp->event, qmp_link_acked(qmp), HZ);
 140        if (!ret) {
 141                dev_err(qmp->dev, "ucore didn't ack link\n");
 142                goto timeout_close_link;
 143        }
 144
 145        writel(QMP_STATE_UP, qmp->msgram + QMP_DESC_MCORE_CH_STATE);
 146
 147        qmp_kick(qmp);
 148
 149        ret = wait_event_timeout(qmp->event, qmp_ucore_channel_up(qmp), HZ);
 150        if (!ret) {
 151                dev_err(qmp->dev, "ucore didn't open channel\n");
 152                goto timeout_close_channel;
 153        }
 154
 155        /* Ack remote core's channel state */
 156        writel(QMP_STATE_UP, qmp->msgram + QMP_DESC_UCORE_CH_STATE_ACK);
 157
 158        qmp_kick(qmp);
 159
 160        ret = wait_event_timeout(qmp->event, qmp_mcore_channel_acked(qmp), HZ);
 161        if (!ret) {
 162                dev_err(qmp->dev, "ucore didn't ack channel\n");
 163                goto timeout_close_channel;
 164        }
 165
 166        return 0;
 167
 168timeout_close_channel:
 169        writel(QMP_STATE_DOWN, qmp->msgram + QMP_DESC_MCORE_CH_STATE);
 170
 171timeout_close_link:
 172        writel(QMP_STATE_DOWN, qmp->msgram + QMP_DESC_MCORE_LINK_STATE);
 173        qmp_kick(qmp);
 174
 175        return -ETIMEDOUT;
 176}
 177
 178static void qmp_close(struct qmp *qmp)
 179{
 180        writel(QMP_STATE_DOWN, qmp->msgram + QMP_DESC_MCORE_CH_STATE);
 181        writel(QMP_STATE_DOWN, qmp->msgram + QMP_DESC_MCORE_LINK_STATE);
 182        qmp_kick(qmp);
 183}
 184
 185static irqreturn_t qmp_intr(int irq, void *data)
 186{
 187        struct qmp *qmp = data;
 188
 189        wake_up_interruptible_all(&qmp->event);
 190
 191        return IRQ_HANDLED;
 192}
 193
 194static bool qmp_message_empty(struct qmp *qmp)
 195{
 196        return readl(qmp->msgram + qmp->offset) == 0;
 197}
 198
 199/**
 200 * qmp_send() - send a message to the AOSS
 201 * @qmp: qmp context
 202 * @data: message to be sent
 203 * @len: length of the message
 204 *
 205 * Transmit @data to AOSS and wait for the AOSS to acknowledge the message.
 206 * @len must be a multiple of 4 and not longer than the mailbox size. Access is
 207 * synchronized by this implementation.
 208 *
 209 * Return: 0 on success, negative errno on failure
 210 */
 211static int qmp_send(struct qmp *qmp, const void *data, size_t len)
 212{
 213        long time_left;
 214        int ret;
 215
 216        if (WARN_ON(len + sizeof(u32) > qmp->size))
 217                return -EINVAL;
 218
 219        if (WARN_ON(len % sizeof(u32)))
 220                return -EINVAL;
 221
 222        mutex_lock(&qmp->tx_lock);
 223
 224        /* The message RAM only implements 32-bit accesses */
 225        __iowrite32_copy(qmp->msgram + qmp->offset + sizeof(u32),
 226                         data, len / sizeof(u32));
 227        writel(len, qmp->msgram + qmp->offset);
 228        qmp_kick(qmp);
 229
 230        time_left = wait_event_interruptible_timeout(qmp->event,
 231                                                     qmp_message_empty(qmp), HZ);
 232        if (!time_left) {
 233                dev_err(qmp->dev, "ucore did not ack channel\n");
 234                ret = -ETIMEDOUT;
 235
 236                /* Clear message from buffer */
 237                writel(0, qmp->msgram + qmp->offset);
 238        } else {
 239                ret = 0;
 240        }
 241
 242        mutex_unlock(&qmp->tx_lock);
 243
 244        return ret;
 245}
 246
 247static int qmp_qdss_clk_prepare(struct clk_hw *hw)
 248{
 249        static const char buf[QMP_MSG_LEN] = "{class: clock, res: qdss, val: 1}";
 250        struct qmp *qmp = container_of(hw, struct qmp, qdss_clk);
 251
 252        return qmp_send(qmp, buf, sizeof(buf));
 253}
 254
 255static void qmp_qdss_clk_unprepare(struct clk_hw *hw)
 256{
 257        static const char buf[QMP_MSG_LEN] = "{class: clock, res: qdss, val: 0}";
 258        struct qmp *qmp = container_of(hw, struct qmp, qdss_clk);
 259
 260        qmp_send(qmp, buf, sizeof(buf));
 261}
 262
 263static const struct clk_ops qmp_qdss_clk_ops = {
 264        .prepare = qmp_qdss_clk_prepare,
 265        .unprepare = qmp_qdss_clk_unprepare,
 266};
 267
 268static int qmp_qdss_clk_add(struct qmp *qmp)
 269{
 270        static const struct clk_init_data qdss_init = {
 271                .ops = &qmp_qdss_clk_ops,
 272                .name = "qdss",
 273        };
 274        int ret;
 275
 276        qmp->qdss_clk.init = &qdss_init;
 277        ret = clk_hw_register(qmp->dev, &qmp->qdss_clk);
 278        if (ret < 0) {
 279                dev_err(qmp->dev, "failed to register qdss clock\n");
 280                return ret;
 281        }
 282
 283        ret = of_clk_add_hw_provider(qmp->dev->of_node, of_clk_hw_simple_get,
 284                                     &qmp->qdss_clk);
 285        if (ret < 0) {
 286                dev_err(qmp->dev, "unable to register of clk hw provider\n");
 287                clk_hw_unregister(&qmp->qdss_clk);
 288        }
 289
 290        return ret;
 291}
 292
 293static void qmp_qdss_clk_remove(struct qmp *qmp)
 294{
 295        of_clk_del_provider(qmp->dev->of_node);
 296        clk_hw_unregister(&qmp->qdss_clk);
 297}
 298
 299static int qmp_pd_power_toggle(struct qmp_pd *res, bool enable)
 300{
 301        char buf[QMP_MSG_LEN] = {};
 302
 303        snprintf(buf, sizeof(buf),
 304                 "{class: image, res: load_state, name: %s, val: %s}",
 305                 res->pd.name, enable ? "on" : "off");
 306        return qmp_send(res->qmp, buf, sizeof(buf));
 307}
 308
 309static int qmp_pd_power_on(struct generic_pm_domain *domain)
 310{
 311        return qmp_pd_power_toggle(to_qmp_pd_resource(domain), true);
 312}
 313
 314static int qmp_pd_power_off(struct generic_pm_domain *domain)
 315{
 316        return qmp_pd_power_toggle(to_qmp_pd_resource(domain), false);
 317}
 318
 319static const char * const sdm845_resources[] = {
 320        [AOSS_QMP_LS_CDSP] = "cdsp",
 321        [AOSS_QMP_LS_LPASS] = "adsp",
 322        [AOSS_QMP_LS_MODEM] = "modem",
 323        [AOSS_QMP_LS_SLPI] = "slpi",
 324        [AOSS_QMP_LS_SPSS] = "spss",
 325        [AOSS_QMP_LS_VENUS] = "venus",
 326};
 327
 328static int qmp_pd_add(struct qmp *qmp)
 329{
 330        struct genpd_onecell_data *data = &qmp->pd_data;
 331        struct device *dev = qmp->dev;
 332        struct qmp_pd *res;
 333        size_t num = ARRAY_SIZE(sdm845_resources);
 334        int ret;
 335        int i;
 336
 337        res = devm_kcalloc(dev, num, sizeof(*res), GFP_KERNEL);
 338        if (!res)
 339                return -ENOMEM;
 340
 341        data->domains = devm_kcalloc(dev, num, sizeof(*data->domains),
 342                                     GFP_KERNEL);
 343        if (!data->domains)
 344                return -ENOMEM;
 345
 346        for (i = 0; i < num; i++) {
 347                res[i].qmp = qmp;
 348                res[i].pd.name = sdm845_resources[i];
 349                res[i].pd.power_on = qmp_pd_power_on;
 350                res[i].pd.power_off = qmp_pd_power_off;
 351
 352                ret = pm_genpd_init(&res[i].pd, NULL, true);
 353                if (ret < 0) {
 354                        dev_err(dev, "failed to init genpd\n");
 355                        goto unroll_genpds;
 356                }
 357
 358                data->domains[i] = &res[i].pd;
 359        }
 360
 361        data->num_domains = i;
 362
 363        ret = of_genpd_add_provider_onecell(dev->of_node, data);
 364        if (ret < 0)
 365                goto unroll_genpds;
 366
 367        return 0;
 368
 369unroll_genpds:
 370        for (i--; i >= 0; i--)
 371                pm_genpd_remove(data->domains[i]);
 372
 373        return ret;
 374}
 375
 376static void qmp_pd_remove(struct qmp *qmp)
 377{
 378        struct genpd_onecell_data *data = &qmp->pd_data;
 379        struct device *dev = qmp->dev;
 380        int i;
 381
 382        of_genpd_del_provider(dev->of_node);
 383
 384        for (i = 0; i < data->num_domains; i++)
 385                pm_genpd_remove(data->domains[i]);
 386}
 387
 388static int qmp_probe(struct platform_device *pdev)
 389{
 390        struct resource *res;
 391        struct qmp *qmp;
 392        int irq;
 393        int ret;
 394
 395        qmp = devm_kzalloc(&pdev->dev, sizeof(*qmp), GFP_KERNEL);
 396        if (!qmp)
 397                return -ENOMEM;
 398
 399        qmp->dev = &pdev->dev;
 400        init_waitqueue_head(&qmp->event);
 401        mutex_init(&qmp->tx_lock);
 402
 403        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 404        qmp->msgram = devm_ioremap_resource(&pdev->dev, res);
 405        if (IS_ERR(qmp->msgram))
 406                return PTR_ERR(qmp->msgram);
 407
 408        qmp->mbox_client.dev = &pdev->dev;
 409        qmp->mbox_client.knows_txdone = true;
 410        qmp->mbox_chan = mbox_request_channel(&qmp->mbox_client, 0);
 411        if (IS_ERR(qmp->mbox_chan)) {
 412                dev_err(&pdev->dev, "failed to acquire ipc mailbox\n");
 413                return PTR_ERR(qmp->mbox_chan);
 414        }
 415
 416        irq = platform_get_irq(pdev, 0);
 417        ret = devm_request_irq(&pdev->dev, irq, qmp_intr, IRQF_ONESHOT,
 418                               "aoss-qmp", qmp);
 419        if (ret < 0) {
 420                dev_err(&pdev->dev, "failed to request interrupt\n");
 421                goto err_free_mbox;
 422        }
 423
 424        ret = qmp_open(qmp);
 425        if (ret < 0)
 426                goto err_free_mbox;
 427
 428        ret = qmp_qdss_clk_add(qmp);
 429        if (ret)
 430                goto err_close_qmp;
 431
 432        ret = qmp_pd_add(qmp);
 433        if (ret)
 434                goto err_remove_qdss_clk;
 435
 436        platform_set_drvdata(pdev, qmp);
 437
 438        return 0;
 439
 440err_remove_qdss_clk:
 441        qmp_qdss_clk_remove(qmp);
 442err_close_qmp:
 443        qmp_close(qmp);
 444err_free_mbox:
 445        mbox_free_channel(qmp->mbox_chan);
 446
 447        return ret;
 448}
 449
 450static int qmp_remove(struct platform_device *pdev)
 451{
 452        struct qmp *qmp = platform_get_drvdata(pdev);
 453
 454        qmp_qdss_clk_remove(qmp);
 455        qmp_pd_remove(qmp);
 456
 457        qmp_close(qmp);
 458        mbox_free_channel(qmp->mbox_chan);
 459
 460        return 0;
 461}
 462
 463static const struct of_device_id qmp_dt_match[] = {
 464        { .compatible = "qcom,sdm845-aoss-qmp", },
 465        {}
 466};
 467MODULE_DEVICE_TABLE(of, qmp_dt_match);
 468
 469static struct platform_driver qmp_driver = {
 470        .driver = {
 471                .name           = "qcom_aoss_qmp",
 472                .of_match_table = qmp_dt_match,
 473        },
 474        .probe = qmp_probe,
 475        .remove = qmp_remove,
 476};
 477module_platform_driver(qmp_driver);
 478
 479MODULE_DESCRIPTION("Qualcomm AOSS QMP driver");
 480MODULE_LICENSE("GPL v2");
 481