linux/arch/arm/mach-ux500/mbox-db5500.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) ST-Ericsson SA 2010
   3 * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson.
   4 * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson.
   5 * License terms: GNU General Public License (GPL), version 2.
   6 */
   7
   8/*
   9 * Mailbox nomenclature:
  10 *
  11 *       APE           MODEM
  12 *           mbox pairX
  13 *   ..........................
  14 *   .                       .
  15 *   .           peer        .
  16 *   .     send  ----        .
  17 *   .      -->  |  |        .
  18 *   .           |  |        .
  19 *   .           ----        .
  20 *   .                       .
  21 *   .           local       .
  22 *   .     rec   ----        .
  23 *   .           |  | <--    .
  24 *   .           |  |        .
  25 *   .           ----        .
  26 *   .........................
  27 */
  28
  29#include <linux/init.h>
  30#include <linux/module.h>
  31#include <linux/device.h>
  32#include <linux/interrupt.h>
  33#include <linux/spinlock.h>
  34#include <linux/errno.h>
  35#include <linux/io.h>
  36#include <linux/irq.h>
  37#include <linux/platform_device.h>
  38#include <linux/debugfs.h>
  39#include <linux/seq_file.h>
  40#include <linux/completion.h>
  41#include <mach/mbox-db5500.h>
  42
  43#define MBOX_NAME "mbox"
  44
  45#define MBOX_FIFO_DATA        0x000
  46#define MBOX_FIFO_ADD         0x004
  47#define MBOX_FIFO_REMOVE      0x008
  48#define MBOX_FIFO_THRES_FREE  0x00C
  49#define MBOX_FIFO_THRES_OCCUP 0x010
  50#define MBOX_FIFO_STATUS      0x014
  51
  52#define MBOX_DISABLE_IRQ 0x4
  53#define MBOX_ENABLE_IRQ  0x0
  54#define MBOX_LATCH 1
  55
  56/* Global list of all mailboxes */
  57static struct list_head mboxs = LIST_HEAD_INIT(mboxs);
  58
  59static struct mbox *get_mbox_with_id(u8 id)
  60{
  61        u8 i;
  62        struct list_head *pos = &mboxs;
  63        for (i = 0; i <= id; i++)
  64                pos = pos->next;
  65
  66        return (struct mbox *) list_entry(pos, struct mbox, list);
  67}
  68
  69int mbox_send(struct mbox *mbox, u32 mbox_msg, bool block)
  70{
  71        int res = 0;
  72
  73        spin_lock(&mbox->lock);
  74
  75        dev_dbg(&(mbox->pdev->dev),
  76                "About to buffer 0x%X to mailbox 0x%X."
  77                " ri = %d, wi = %d\n",
  78                mbox_msg, (u32)mbox, mbox->read_index,
  79                mbox->write_index);
  80
  81        /* Check if write buffer is full */
  82        while (((mbox->write_index + 1) % MBOX_BUF_SIZE) == mbox->read_index) {
  83                if (!block) {
  84                        dev_dbg(&(mbox->pdev->dev),
  85                        "Buffer full in non-blocking call! "
  86                        "Returning -ENOMEM!\n");
  87                        res = -ENOMEM;
  88                        goto exit;
  89                }
  90                spin_unlock(&mbox->lock);
  91                dev_dbg(&(mbox->pdev->dev),
  92                        "Buffer full in blocking call! Sleeping...\n");
  93                mbox->client_blocked = 1;
  94                wait_for_completion(&mbox->buffer_available);
  95                dev_dbg(&(mbox->pdev->dev),
  96                        "Blocking send was woken up! Trying again...\n");
  97                spin_lock(&mbox->lock);
  98        }
  99
 100        mbox->buffer[mbox->write_index] = mbox_msg;
 101        mbox->write_index = (mbox->write_index + 1) % MBOX_BUF_SIZE;
 102
 103        /*
 104         * Indicate that we want an IRQ as soon as there is a slot
 105         * in the FIFO
 106         */
 107        writel(MBOX_ENABLE_IRQ, mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
 108
 109exit:
 110        spin_unlock(&mbox->lock);
 111        return res;
 112}
 113EXPORT_SYMBOL(mbox_send);
 114
 115#if defined(CONFIG_DEBUG_FS)
 116/*
 117 * Expected input: <value> <nbr sends>
 118 * Example: "echo 0xdeadbeef 4 > mbox-node" sends 0xdeadbeef 4 times
 119 */
 120static ssize_t mbox_write_fifo(struct device *dev,
 121                               struct device_attribute *attr,
 122                               const char *buf,
 123                               size_t count)
 124{
 125        unsigned long mbox_mess;
 126        unsigned long nbr_sends;
 127        unsigned long i;
 128        char int_buf[16];
 129        char *token;
 130        char *val;
 131
 132        struct mbox *mbox = (struct mbox *) dev->platform_data;
 133
 134        strncpy((char *) &int_buf, buf, sizeof(int_buf));
 135        token = (char *) &int_buf;
 136
 137        /* Parse message */
 138        val = strsep(&token, " ");
 139        if ((val == NULL) || (strict_strtoul(val, 16, &mbox_mess) != 0))
 140                mbox_mess = 0xDEADBEEF;
 141
 142        val = strsep(&token, " ");
 143        if ((val == NULL) || (strict_strtoul(val, 10, &nbr_sends) != 0))
 144                nbr_sends = 1;
 145
 146        dev_dbg(dev, "Will write 0x%lX %ld times using data struct at 0x%X\n",
 147                mbox_mess, nbr_sends, (u32) mbox);
 148
 149        for (i = 0; i < nbr_sends; i++)
 150                mbox_send(mbox, mbox_mess, true);
 151
 152        return count;
 153}
 154
 155static ssize_t mbox_read_fifo(struct device *dev,
 156                              struct device_attribute *attr,
 157                              char *buf)
 158{
 159        int mbox_value;
 160        struct mbox *mbox = (struct mbox *) dev->platform_data;
 161
 162        if ((readl(mbox->virtbase_local + MBOX_FIFO_STATUS) & 0x7) <= 0)
 163                return sprintf(buf, "Mailbox is empty\n");
 164
 165        mbox_value = readl(mbox->virtbase_local + MBOX_FIFO_DATA);
 166        writel(MBOX_LATCH, (mbox->virtbase_local + MBOX_FIFO_REMOVE));
 167
 168        return sprintf(buf, "0x%X\n", mbox_value);
 169}
 170
 171static DEVICE_ATTR(fifo, S_IWUGO | S_IRUGO, mbox_read_fifo, mbox_write_fifo);
 172
 173static int mbox_show(struct seq_file *s, void *data)
 174{
 175        struct list_head *pos;
 176        u8 mbox_index = 0;
 177
 178        list_for_each(pos, &mboxs) {
 179                struct mbox *m =
 180                        (struct mbox *) list_entry(pos, struct mbox, list);
 181                if (m == NULL) {
 182                        seq_printf(s,
 183                                   "Unable to retrieve mailbox %d\n",
 184                                   mbox_index);
 185                        continue;
 186                }
 187
 188                spin_lock(&m->lock);
 189                if ((m->virtbase_peer == NULL) || (m->virtbase_local == NULL)) {
 190                        seq_printf(s, "MAILBOX %d not setup or corrupt\n",
 191                                   mbox_index);
 192                        spin_unlock(&m->lock);
 193                        continue;
 194                }
 195
 196                seq_printf(s,
 197                "===========================\n"
 198                " MAILBOX %d\n"
 199                " PEER MAILBOX DUMP\n"
 200                "---------------------------\n"
 201                "FIFO:                 0x%X (%d)\n"
 202                "Free     Threshold:   0x%.2X (%d)\n"
 203                "Occupied Threshold:   0x%.2X (%d)\n"
 204                "Status:               0x%.2X (%d)\n"
 205                "   Free spaces  (ot):    %d (%d)\n"
 206                "   Occup spaces (ot):    %d (%d)\n"
 207                "===========================\n"
 208                " LOCAL MAILBOX DUMP\n"
 209                "---------------------------\n"
 210                "FIFO:                 0x%.X (%d)\n"
 211                "Free     Threshold:   0x%.2X (%d)\n"
 212                "Occupied Threshold:   0x%.2X (%d)\n"
 213                "Status:               0x%.2X (%d)\n"
 214                "   Free spaces  (ot):    %d (%d)\n"
 215                "   Occup spaces (ot):    %d (%d)\n"
 216                "===========================\n"
 217                "write_index: %d\n"
 218                "read_index : %d\n"
 219                "===========================\n"
 220                "\n",
 221                mbox_index,
 222                readl(m->virtbase_peer + MBOX_FIFO_DATA),
 223                readl(m->virtbase_peer + MBOX_FIFO_DATA),
 224                readl(m->virtbase_peer + MBOX_FIFO_THRES_FREE),
 225                readl(m->virtbase_peer + MBOX_FIFO_THRES_FREE),
 226                readl(m->virtbase_peer + MBOX_FIFO_THRES_OCCUP),
 227                readl(m->virtbase_peer + MBOX_FIFO_THRES_OCCUP),
 228                readl(m->virtbase_peer + MBOX_FIFO_STATUS),
 229                readl(m->virtbase_peer + MBOX_FIFO_STATUS),
 230                (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 4) & 0x7,
 231                (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 7) & 0x1,
 232                (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 0) & 0x7,
 233                (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 3) & 0x1,
 234                readl(m->virtbase_local + MBOX_FIFO_DATA),
 235                readl(m->virtbase_local + MBOX_FIFO_DATA),
 236                readl(m->virtbase_local + MBOX_FIFO_THRES_FREE),
 237                readl(m->virtbase_local + MBOX_FIFO_THRES_FREE),
 238                readl(m->virtbase_local + MBOX_FIFO_THRES_OCCUP),
 239                readl(m->virtbase_local + MBOX_FIFO_THRES_OCCUP),
 240                readl(m->virtbase_local + MBOX_FIFO_STATUS),
 241                readl(m->virtbase_local + MBOX_FIFO_STATUS),
 242                (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 4) & 0x7,
 243                (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 7) & 0x1,
 244                (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 0) & 0x7,
 245                (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 3) & 0x1,
 246                m->write_index, m->read_index);
 247                mbox_index++;
 248                spin_unlock(&m->lock);
 249        }
 250
 251        return 0;
 252}
 253
 254static int mbox_open(struct inode *inode, struct file *file)
 255{
 256        return single_open(file, mbox_show, NULL);
 257}
 258
 259static const struct file_operations mbox_operations = {
 260        .owner = THIS_MODULE,
 261        .open = mbox_open,
 262        .read = seq_read,
 263        .llseek = seq_lseek,
 264        .release = single_release,
 265};
 266#endif
 267
 268static irqreturn_t mbox_irq(int irq, void *arg)
 269{
 270        u32 mbox_value;
 271        int nbr_occup;
 272        int nbr_free;
 273        struct mbox *mbox = (struct mbox *) arg;
 274
 275        spin_lock(&mbox->lock);
 276
 277        dev_dbg(&(mbox->pdev->dev),
 278                "mbox IRQ [%d] received. ri = %d, wi = %d\n",
 279                irq, mbox->read_index, mbox->write_index);
 280
 281        /*
 282         * Check if we have any outgoing messages, and if there is space for
 283         * them in the FIFO.
 284         */
 285        if (mbox->read_index != mbox->write_index) {
 286                /*
 287                 * Check by reading FREE for LOCAL since that indicates
 288                 * OCCUP for PEER
 289                 */
 290                nbr_free = (readl(mbox->virtbase_local + MBOX_FIFO_STATUS)
 291                            >> 4) & 0x7;
 292                dev_dbg(&(mbox->pdev->dev),
 293                        "Status indicates %d empty spaces in the FIFO!\n",
 294                        nbr_free);
 295
 296                while ((nbr_free > 0) &&
 297                       (mbox->read_index != mbox->write_index)) {
 298                        /* Write the message and latch it into the FIFO */
 299                        writel(mbox->buffer[mbox->read_index],
 300                               (mbox->virtbase_peer + MBOX_FIFO_DATA));
 301                        writel(MBOX_LATCH,
 302                               (mbox->virtbase_peer + MBOX_FIFO_ADD));
 303                        dev_dbg(&(mbox->pdev->dev),
 304                                "Wrote message 0x%X to addr 0x%X\n",
 305                                mbox->buffer[mbox->read_index],
 306                                (u32) (mbox->virtbase_peer + MBOX_FIFO_DATA));
 307
 308                        nbr_free--;
 309                        mbox->read_index =
 310                                (mbox->read_index + 1) % MBOX_BUF_SIZE;
 311                }
 312
 313                /*
 314                 * Check if we still want IRQ:s when there is free
 315                 * space to send
 316                 */
 317                if (mbox->read_index != mbox->write_index) {
 318                        dev_dbg(&(mbox->pdev->dev),
 319                                "Still have messages to send, but FIFO full. "
 320                                "Request IRQ again!\n");
 321                        writel(MBOX_ENABLE_IRQ,
 322                               mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
 323                } else {
 324                        dev_dbg(&(mbox->pdev->dev),
 325                                "No more messages to send. "
 326                                "Do not request IRQ again!\n");
 327                        writel(MBOX_DISABLE_IRQ,
 328                               mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
 329                }
 330
 331                /*
 332                 * Check if we can signal any blocked clients that it is OK to
 333                 * start buffering again
 334                 */
 335                if (mbox->client_blocked &&
 336                    (((mbox->write_index + 1) % MBOX_BUF_SIZE)
 337                     != mbox->read_index)) {
 338                        dev_dbg(&(mbox->pdev->dev),
 339                                "Waking up blocked client\n");
 340                        complete(&mbox->buffer_available);
 341                        mbox->client_blocked = 0;
 342                }
 343        }
 344
 345        /* Check if we have any incoming messages */
 346        nbr_occup = readl(mbox->virtbase_local + MBOX_FIFO_STATUS) & 0x7;
 347        if (nbr_occup == 0)
 348                goto exit;
 349
 350        if (mbox->cb == NULL) {
 351                dev_dbg(&(mbox->pdev->dev), "No receive callback registered, "
 352                        "leaving %d incoming messages in fifo!\n", nbr_occup);
 353                goto exit;
 354        }
 355
 356        /* Read and acknowledge the message */
 357        mbox_value = readl(mbox->virtbase_local + MBOX_FIFO_DATA);
 358        writel(MBOX_LATCH, (mbox->virtbase_local + MBOX_FIFO_REMOVE));
 359
 360        /* Notify consumer of new mailbox message */
 361        dev_dbg(&(mbox->pdev->dev), "Calling callback for message 0x%X!\n",
 362                mbox_value);
 363        mbox->cb(mbox_value, mbox->client_data);
 364
 365exit:
 366        dev_dbg(&(mbox->pdev->dev), "Exit mbox IRQ. ri = %d, wi = %d\n",
 367                mbox->read_index, mbox->write_index);
 368        spin_unlock(&mbox->lock);
 369
 370        return IRQ_HANDLED;
 371}
 372
 373/* Setup is executed once for each mbox pair */
 374struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv)
 375{
 376        struct resource *resource;
 377        int irq;
 378        int res;
 379        struct mbox *mbox;
 380
 381        mbox = get_mbox_with_id(mbox_id);
 382        if (mbox == NULL) {
 383                dev_err(&(mbox->pdev->dev), "Incorrect mailbox id: %d!\n",
 384                        mbox_id);
 385                goto exit;
 386        }
 387
 388        /*
 389         * Check if mailbox has been allocated to someone else,
 390         * otherwise allocate it
 391         */
 392        if (mbox->allocated) {
 393                dev_err(&(mbox->pdev->dev), "Mailbox number %d is busy!\n",
 394                        mbox_id);
 395                mbox = NULL;
 396                goto exit;
 397        }
 398        mbox->allocated = true;
 399
 400        dev_dbg(&(mbox->pdev->dev), "Initiating mailbox number %d: 0x%X...\n",
 401                mbox_id, (u32)mbox);
 402
 403        mbox->client_data = priv;
 404        mbox->cb = mbox_cb;
 405
 406        /* Get addr for peer mailbox and ioremap it */
 407        resource = platform_get_resource_byname(mbox->pdev,
 408                                                IORESOURCE_MEM,
 409                                                "mbox_peer");
 410        if (resource == NULL) {
 411                dev_err(&(mbox->pdev->dev),
 412                        "Unable to retrieve mbox peer resource\n");
 413                mbox = NULL;
 414                goto exit;
 415        }
 416        dev_dbg(&(mbox->pdev->dev),
 417                "Resource name: %s start: 0x%X, end: 0x%X\n",
 418                resource->name, resource->start, resource->end);
 419        mbox->virtbase_peer =
 420                ioremap(resource->start, resource->end - resource->start);
 421        if (!mbox->virtbase_peer) {
 422                dev_err(&(mbox->pdev->dev), "Unable to ioremap peer mbox\n");
 423                mbox = NULL;
 424                goto exit;
 425        }
 426        dev_dbg(&(mbox->pdev->dev),
 427                "ioremapped peer physical: (0x%X-0x%X) to virtual: 0x%X\n",
 428                resource->start, resource->end, (u32) mbox->virtbase_peer);
 429
 430        /* Get addr for local mailbox and ioremap it */
 431        resource = platform_get_resource_byname(mbox->pdev,
 432                                                IORESOURCE_MEM,
 433                                                "mbox_local");
 434        if (resource == NULL) {
 435                dev_err(&(mbox->pdev->dev),
 436                        "Unable to retrieve mbox local resource\n");
 437                mbox = NULL;
 438                goto exit;
 439        }
 440        dev_dbg(&(mbox->pdev->dev),
 441                "Resource name: %s start: 0x%X, end: 0x%X\n",
 442                resource->name, resource->start, resource->end);
 443        mbox->virtbase_local =
 444                ioremap(resource->start, resource->end - resource->start);
 445        if (!mbox->virtbase_local) {
 446                dev_err(&(mbox->pdev->dev), "Unable to ioremap local mbox\n");
 447                mbox = NULL;
 448                goto exit;
 449        }
 450        dev_dbg(&(mbox->pdev->dev),
 451                "ioremapped local physical: (0x%X-0x%X) to virtual: 0x%X\n",
 452                resource->start, resource->end, (u32) mbox->virtbase_peer);
 453
 454        init_completion(&mbox->buffer_available);
 455        mbox->client_blocked = 0;
 456
 457        /* Get IRQ for mailbox and allocate it */
 458        irq = platform_get_irq_byname(mbox->pdev, "mbox_irq");
 459        if (irq < 0) {
 460                dev_err(&(mbox->pdev->dev),
 461                        "Unable to retrieve mbox irq resource\n");
 462                mbox = NULL;
 463                goto exit;
 464        }
 465
 466        dev_dbg(&(mbox->pdev->dev), "Allocating irq %d...\n", irq);
 467        res = request_irq(irq, mbox_irq, 0, mbox->name, (void *) mbox);
 468        if (res < 0) {
 469                dev_err(&(mbox->pdev->dev),
 470                        "Unable to allocate mbox irq %d\n", irq);
 471                mbox = NULL;
 472                goto exit;
 473        }
 474
 475        /* Set up mailbox to not launch IRQ on free space in mailbox */
 476        writel(MBOX_DISABLE_IRQ, mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
 477
 478        /*
 479         * Set up mailbox to launch IRQ on new message if we have
 480         * a callback set. If not, do not raise IRQ, but keep message
 481         * in FIFO for manual retrieval
 482         */
 483        if (mbox_cb != NULL)
 484                writel(MBOX_ENABLE_IRQ,
 485                       mbox->virtbase_local + MBOX_FIFO_THRES_OCCUP);
 486        else
 487                writel(MBOX_DISABLE_IRQ,
 488                       mbox->virtbase_local + MBOX_FIFO_THRES_OCCUP);
 489
 490#if defined(CONFIG_DEBUG_FS)
 491        res = device_create_file(&(mbox->pdev->dev), &dev_attr_fifo);
 492        if (res != 0)
 493                dev_warn(&(mbox->pdev->dev),
 494                         "Unable to create mbox sysfs entry");
 495
 496        (void) debugfs_create_file("mbox", S_IFREG | S_IRUGO, NULL,
 497                                   NULL, &mbox_operations);
 498#endif
 499
 500        dev_info(&(mbox->pdev->dev),
 501                 "Mailbox driver with index %d initated!\n", mbox_id);
 502
 503exit:
 504        return mbox;
 505}
 506EXPORT_SYMBOL(mbox_setup);
 507
 508
 509int __init mbox_probe(struct platform_device *pdev)
 510{
 511        struct mbox local_mbox;
 512        struct mbox *mbox;
 513        int res = 0;
 514        dev_dbg(&(pdev->dev), "Probing mailbox (pdev = 0x%X)...\n", (u32) pdev);
 515
 516        memset(&local_mbox, 0x0, sizeof(struct mbox));
 517
 518        /* Associate our mbox data with the platform device */
 519        res = platform_device_add_data(pdev,
 520                                       (void *) &local_mbox,
 521                                       sizeof(struct mbox));
 522        if (res != 0) {
 523                dev_err(&(pdev->dev),
 524                        "Unable to allocate driver platform data!\n");
 525                goto exit;
 526        }
 527
 528        mbox = (struct mbox *) pdev->dev.platform_data;
 529        mbox->pdev = pdev;
 530        mbox->write_index = 0;
 531        mbox->read_index = 0;
 532
 533        INIT_LIST_HEAD(&(mbox->list));
 534        list_add_tail(&(mbox->list), &mboxs);
 535
 536        sprintf(mbox->name, "%s", MBOX_NAME);
 537        spin_lock_init(&mbox->lock);
 538
 539        dev_info(&(pdev->dev), "Mailbox driver loaded\n");
 540
 541exit:
 542        return res;
 543}
 544
 545static struct platform_driver mbox_driver = {
 546        .driver = {
 547                .name = MBOX_NAME,
 548                .owner = THIS_MODULE,
 549        },
 550};
 551
 552static int __init mbox_init(void)
 553{
 554        return platform_driver_probe(&mbox_driver, mbox_probe);
 555}
 556
 557module_init(mbox_init);
 558
 559void __exit mbox_exit(void)
 560{
 561        platform_driver_unregister(&mbox_driver);
 562}
 563
 564module_exit(mbox_exit);
 565
 566MODULE_LICENSE("GPL");
 567MODULE_DESCRIPTION("MBOX driver");
 568