linux/drivers/staging/dream/camera/msm_vfe7x.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2008-2009 QUALCOMM Incorporated.
   3 */
   4
   5#include <linux/msm_adsp.h>
   6#include <linux/uaccess.h>
   7#include <linux/fs.h>
   8#include <linux/android_pmem.h>
   9#include <mach/msm_adsp.h>
  10#include <linux/delay.h>
  11#include <linux/wait.h>
  12#include "msm_vfe7x.h"
  13
  14#define QDSP_CMDQUEUE QDSP_vfeCommandQueue
  15
  16#define VFE_RESET_CMD 0
  17#define VFE_START_CMD 1
  18#define VFE_STOP_CMD  2
  19#define VFE_FRAME_ACK 20
  20#define STATS_AF_ACK  21
  21#define STATS_WE_ACK  22
  22
  23#define MSG_STOP_ACK  1
  24#define MSG_SNAPSHOT  2
  25#define MSG_OUTPUT1   6
  26#define MSG_OUTPUT2   7
  27#define MSG_STATS_AF  8
  28#define MSG_STATS_WE  9
  29
  30static struct msm_adsp_module *qcam_mod;
  31static struct msm_adsp_module *vfe_mod;
  32static struct msm_vfe_callback *resp;
  33static void *extdata;
  34static uint32_t extlen;
  35
  36struct mutex vfe_lock;
  37static void     *vfe_syncdata;
  38static uint8_t vfestopped;
  39
  40static struct stop_event stopevent;
  41
  42static void vfe_7x_convert(struct msm_vfe_phy_info *pinfo,
  43                enum vfe_resp_msg type,
  44                void *data, void **ext, int32_t *elen)
  45{
  46        switch (type) {
  47        case VFE_MSG_OUTPUT1:
  48        case VFE_MSG_OUTPUT2: {
  49                pinfo->y_phy = ((struct vfe_endframe *)data)->y_address;
  50                pinfo->cbcr_phy =
  51                        ((struct vfe_endframe *)data)->cbcr_address;
  52
  53                CDBG("vfe_7x_convert, y_phy = 0x%x, cbcr_phy = 0x%x\n",
  54                                 pinfo->y_phy, pinfo->cbcr_phy);
  55
  56                ((struct vfe_frame_extra *)extdata)->bl_evencol =
  57                ((struct vfe_endframe *)data)->blacklevelevencolumn;
  58
  59                ((struct vfe_frame_extra *)extdata)->bl_oddcol =
  60                ((struct vfe_endframe *)data)->blackleveloddcolumn;
  61
  62                ((struct vfe_frame_extra *)extdata)->g_def_p_cnt =
  63                ((struct vfe_endframe *)data)->greendefectpixelcount;
  64
  65                ((struct vfe_frame_extra *)extdata)->r_b_def_p_cnt =
  66                ((struct vfe_endframe *)data)->redbluedefectpixelcount;
  67
  68                *ext  = extdata;
  69                *elen = extlen;
  70        }
  71                break;
  72
  73        case VFE_MSG_STATS_AF:
  74        case VFE_MSG_STATS_WE:
  75                pinfo->sbuf_phy = *(uint32_t *)data;
  76                break;
  77
  78        default:
  79                break;
  80        } /* switch */
  81}
  82
  83static void vfe_7x_ops(void *driver_data, unsigned id, size_t len,
  84                void (*getevent)(void *ptr, size_t len))
  85{
  86        uint32_t evt_buf[3];
  87        struct msm_vfe_resp *rp;
  88        void *data;
  89
  90        len = (id == (uint16_t)-1) ? 0 : len;
  91        data = resp->vfe_alloc(sizeof(struct msm_vfe_resp) + len, vfe_syncdata);
  92
  93        if (!data) {
  94                pr_err("rp: cannot allocate buffer\n");
  95                return;
  96        }
  97        rp = (struct msm_vfe_resp *)data;
  98        rp->evt_msg.len = len;
  99
 100        if (id == ((uint16_t)-1)) {
 101                /* event */
 102                rp->type           = VFE_EVENT;
 103                rp->evt_msg.type   = MSM_CAMERA_EVT;
 104                getevent(evt_buf, sizeof(evt_buf));
 105                rp->evt_msg.msg_id = evt_buf[0];
 106                resp->vfe_resp(rp, MSM_CAM_Q_VFE_EVT, vfe_syncdata);
 107        } else {
 108                /* messages */
 109                rp->evt_msg.type   = MSM_CAMERA_MSG;
 110                rp->evt_msg.msg_id = id;
 111                rp->evt_msg.data = rp + 1;
 112                getevent(rp->evt_msg.data, len);
 113
 114                switch (rp->evt_msg.msg_id) {
 115                case MSG_SNAPSHOT:
 116                        rp->type = VFE_MSG_SNAPSHOT;
 117                        break;
 118
 119                case MSG_OUTPUT1:
 120                        rp->type = VFE_MSG_OUTPUT1;
 121                        vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT1,
 122                                rp->evt_msg.data, &(rp->extdata),
 123                                &(rp->extlen));
 124                        break;
 125
 126                case MSG_OUTPUT2:
 127                        rp->type = VFE_MSG_OUTPUT2;
 128                        vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT2,
 129                                        rp->evt_msg.data, &(rp->extdata),
 130                                        &(rp->extlen));
 131                        break;
 132
 133                case MSG_STATS_AF:
 134                        rp->type = VFE_MSG_STATS_AF;
 135                        vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_AF,
 136                                        rp->evt_msg.data, NULL, NULL);
 137                        break;
 138
 139                case MSG_STATS_WE:
 140                        rp->type = VFE_MSG_STATS_WE;
 141                        vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_WE,
 142                                        rp->evt_msg.data, NULL, NULL);
 143
 144                        CDBG("MSG_STATS_WE: phy = 0x%x\n", rp->phy.sbuf_phy);
 145                        break;
 146
 147                case MSG_STOP_ACK:
 148                        rp->type = VFE_MSG_GENERAL;
 149                        stopevent.state = 1;
 150                        wake_up(&stopevent.wait);
 151                        break;
 152
 153
 154                default:
 155                        rp->type = VFE_MSG_GENERAL;
 156                        break;
 157                }
 158                resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, vfe_syncdata);
 159        }
 160}
 161
 162static struct msm_adsp_ops vfe_7x_sync = {
 163        .event = vfe_7x_ops,
 164};
 165
 166static int vfe_7x_enable(struct camera_enable_cmd *enable)
 167{
 168        int rc = -EFAULT;
 169
 170        if (!strcmp(enable->name, "QCAMTASK"))
 171                rc = msm_adsp_enable(qcam_mod);
 172        else if (!strcmp(enable->name, "VFETASK"))
 173                rc = msm_adsp_enable(vfe_mod);
 174
 175        return rc;
 176}
 177
 178static int vfe_7x_disable(struct camera_enable_cmd *enable,
 179                struct platform_device *dev __attribute__((unused)))
 180{
 181        int rc = -EFAULT;
 182
 183        if (!strcmp(enable->name, "QCAMTASK"))
 184                rc = msm_adsp_disable(qcam_mod);
 185        else if (!strcmp(enable->name, "VFETASK"))
 186                rc = msm_adsp_disable(vfe_mod);
 187
 188        return rc;
 189}
 190
 191static int vfe_7x_stop(void)
 192{
 193        int rc = 0;
 194        uint32_t stopcmd = VFE_STOP_CMD;
 195        rc = msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
 196                                &stopcmd, sizeof(uint32_t));
 197        if (rc < 0) {
 198                CDBG("%s:%d: failed rc = %d \n", __func__, __LINE__, rc);
 199                return rc;
 200        }
 201
 202        stopevent.state = 0;
 203        rc = wait_event_timeout(stopevent.wait,
 204                stopevent.state != 0,
 205                msecs_to_jiffies(stopevent.timeout));
 206
 207        return rc;
 208}
 209
 210static void vfe_7x_release(struct platform_device *pdev)
 211{
 212        mutex_lock(&vfe_lock);
 213        vfe_syncdata = NULL;
 214        mutex_unlock(&vfe_lock);
 215
 216        if (!vfestopped) {
 217                CDBG("%s:%d:Calling vfe_7x_stop()\n", __func__, __LINE__);
 218                vfe_7x_stop();
 219        } else
 220                vfestopped = 0;
 221
 222        msm_adsp_disable(qcam_mod);
 223        msm_adsp_disable(vfe_mod);
 224
 225        msm_adsp_put(qcam_mod);
 226        msm_adsp_put(vfe_mod);
 227
 228        msm_camio_disable(pdev);
 229
 230        kfree(extdata);
 231        extlen = 0;
 232}
 233
 234static int vfe_7x_init(struct msm_vfe_callback *presp,
 235        struct platform_device *dev)
 236{
 237        int rc = 0;
 238
 239        init_waitqueue_head(&stopevent.wait);
 240        stopevent.timeout = 200;
 241        stopevent.state = 0;
 242
 243        if (presp && presp->vfe_resp)
 244                resp = presp;
 245        else
 246                return -EFAULT;
 247
 248        /* Bring up all the required GPIOs and Clocks */
 249        rc = msm_camio_enable(dev);
 250        if (rc < 0)
 251                return rc;
 252
 253        msm_camio_camif_pad_reg_reset();
 254
 255        extlen = sizeof(struct vfe_frame_extra);
 256
 257        extdata =
 258                kmalloc(sizeof(extlen), GFP_ATOMIC);
 259        if (!extdata) {
 260                rc = -ENOMEM;
 261                goto init_fail;
 262        }
 263
 264        rc = msm_adsp_get("QCAMTASK", &qcam_mod, &vfe_7x_sync, NULL);
 265        if (rc) {
 266                rc = -EBUSY;
 267                goto get_qcam_fail;
 268        }
 269
 270        rc = msm_adsp_get("VFETASK", &vfe_mod, &vfe_7x_sync, NULL);
 271        if (rc) {
 272                rc = -EBUSY;
 273                goto get_vfe_fail;
 274        }
 275
 276        return 0;
 277
 278get_vfe_fail:
 279        msm_adsp_put(qcam_mod);
 280get_qcam_fail:
 281        kfree(extdata);
 282init_fail:
 283        extlen = 0;
 284        return rc;
 285}
 286
 287static int vfe_7x_config_axi(int mode,
 288        struct axidata *ad, struct axiout *ao)
 289{
 290        struct msm_pmem_region *regptr;
 291        unsigned long *bptr;
 292        int    cnt;
 293
 294        int rc = 0;
 295
 296        if (mode == OUTPUT_1 || mode == OUTPUT_1_AND_2) {
 297                regptr = ad->region;
 298
 299                CDBG("bufnum1 = %d\n", ad->bufnum1);
 300                CDBG("config_axi1: O1, phy = 0x%lx, y_off = %d, cbcr_off =%d\n",
 301                        regptr->paddr, regptr->y_off, regptr->cbcr_off);
 302
 303                bptr = &ao->output1buffer1_y_phy;
 304                for (cnt = 0; cnt < ad->bufnum1; cnt++) {
 305                        *bptr = regptr->paddr + regptr->y_off;
 306                        bptr++;
 307                        *bptr = regptr->paddr + regptr->cbcr_off;
 308
 309                        bptr++;
 310                        regptr++;
 311                }
 312
 313                regptr--;
 314                for (cnt = 0; cnt < (8 - ad->bufnum1); cnt++) {
 315                        *bptr = regptr->paddr + regptr->y_off;
 316                        bptr++;
 317                        *bptr = regptr->paddr + regptr->cbcr_off;
 318                        bptr++;
 319                }
 320        } /* if OUTPUT1 or Both */
 321
 322        if (mode == OUTPUT_2 || mode == OUTPUT_1_AND_2) {
 323                regptr = &(ad->region[ad->bufnum1]);
 324
 325                CDBG("bufnum2 = %d\n", ad->bufnum2);
 326                CDBG("config_axi2: O2, phy = 0x%lx, y_off = %d, cbcr_off =%d\n",
 327                        regptr->paddr, regptr->y_off, regptr->cbcr_off);
 328
 329                bptr = &ao->output2buffer1_y_phy;
 330                for (cnt = 0; cnt < ad->bufnum2; cnt++) {
 331                        *bptr = regptr->paddr + regptr->y_off;
 332                        bptr++;
 333                        *bptr = regptr->paddr + regptr->cbcr_off;
 334
 335                        bptr++;
 336                        regptr++;
 337                }
 338
 339                regptr--;
 340                for (cnt = 0; cnt < (8 - ad->bufnum2); cnt++) {
 341                        *bptr = regptr->paddr + regptr->y_off;
 342                        bptr++;
 343                        *bptr = regptr->paddr + regptr->cbcr_off;
 344                        bptr++;
 345                }
 346        }
 347
 348        return rc;
 349}
 350
 351static int vfe_7x_config(struct msm_vfe_cfg_cmd *cmd, void *data)
 352{
 353        struct msm_pmem_region *regptr;
 354        unsigned char buf[256];
 355
 356        struct vfe_stats_ack sack;
 357        struct axidata *axid;
 358        uint32_t i;
 359
 360        struct vfe_stats_we_cfg *scfg = NULL;
 361        struct vfe_stats_af_cfg *sfcfg = NULL;
 362
 363        struct axiout *axio = NULL;
 364        void   *cmd_data = NULL;
 365        void   *cmd_data_alloc = NULL;
 366        long rc = 0;
 367        struct msm_vfe_command_7k *vfecmd;
 368
 369        vfecmd =
 370                        kmalloc(sizeof(struct msm_vfe_command_7k),
 371                                GFP_ATOMIC);
 372        if (!vfecmd) {
 373                pr_err("vfecmd alloc failed!\n");
 374                return -ENOMEM;
 375        }
 376
 377        if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
 378            cmd->cmd_type != CMD_STATS_BUF_RELEASE &&
 379            cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
 380                if (copy_from_user(vfecmd,
 381                                (void __user *)(cmd->value),
 382                                sizeof(struct msm_vfe_command_7k))) {
 383                        rc = -EFAULT;
 384                        goto config_failure;
 385                }
 386        }
 387
 388        switch (cmd->cmd_type) {
 389        case CMD_STATS_ENABLE:
 390        case CMD_STATS_AXI_CFG: {
 391                axid = data;
 392                if (!axid) {
 393                        rc = -EFAULT;
 394                        goto config_failure;
 395                }
 396
 397                scfg =
 398                        kmalloc(sizeof(struct vfe_stats_we_cfg),
 399                                GFP_ATOMIC);
 400                if (!scfg) {
 401                        rc = -ENOMEM;
 402                        goto config_failure;
 403                }
 404
 405                if (copy_from_user(scfg,
 406                                        (void __user *)(vfecmd->value),
 407                                        vfecmd->length)) {
 408
 409                        rc = -EFAULT;
 410                        goto config_done;
 411                }
 412
 413                CDBG("STATS_ENABLE: bufnum = %d, enabling = %d\n",
 414                        axid->bufnum1, scfg->wb_expstatsenable);
 415
 416                if (axid->bufnum1 > 0) {
 417                        regptr = axid->region;
 418
 419                        for (i = 0; i < axid->bufnum1; i++) {
 420
 421                                CDBG("STATS_ENABLE, phy = 0x%lx\n",
 422                                        regptr->paddr);
 423
 424                                scfg->wb_expstatoutputbuffer[i] =
 425                                        (void *)regptr->paddr;
 426                                regptr++;
 427                        }
 428
 429                        cmd_data = scfg;
 430
 431                } else {
 432                        rc = -EINVAL;
 433                        goto config_done;
 434                }
 435        }
 436                break;
 437
 438        case CMD_STATS_AF_ENABLE:
 439        case CMD_STATS_AF_AXI_CFG: {
 440                axid = data;
 441                if (!axid) {
 442                        rc = -EFAULT;
 443                        goto config_failure;
 444                }
 445
 446                sfcfg =
 447                        kmalloc(sizeof(struct vfe_stats_af_cfg),
 448                                GFP_ATOMIC);
 449
 450                if (!sfcfg) {
 451                        rc = -ENOMEM;
 452                        goto config_failure;
 453                }
 454
 455                if (copy_from_user(sfcfg,
 456                                        (void __user *)(vfecmd->value),
 457                                        vfecmd->length)) {
 458
 459                        rc = -EFAULT;
 460                        goto config_done;
 461                }
 462
 463                CDBG("AF_ENABLE: bufnum = %d, enabling = %d\n",
 464                        axid->bufnum1, sfcfg->af_enable);
 465
 466                if (axid->bufnum1 > 0) {
 467                        regptr = axid->region;
 468
 469                        for (i = 0; i < axid->bufnum1; i++) {
 470
 471                                CDBG("STATS_ENABLE, phy = 0x%lx\n",
 472                                        regptr->paddr);
 473
 474                                sfcfg->af_outbuf[i] =
 475                                        (void *)regptr->paddr;
 476
 477                                regptr++;
 478                        }
 479
 480                        cmd_data = sfcfg;
 481
 482                } else {
 483                        rc = -EINVAL;
 484                        goto config_done;
 485                }
 486        }
 487                break;
 488
 489        case CMD_FRAME_BUF_RELEASE: {
 490                struct msm_frame *b;
 491                unsigned long p;
 492                struct vfe_outputack fack;
 493                if (!data)  {
 494                        rc = -EFAULT;
 495                        goto config_failure;
 496                }
 497
 498                b = (struct msm_frame *)(cmd->value);
 499                p = *(unsigned long *)data;
 500
 501                fack.header = VFE_FRAME_ACK;
 502
 503                fack.output2newybufferaddress =
 504                        (void *)(p + b->y_off);
 505
 506                fack.output2newcbcrbufferaddress =
 507                        (void *)(p + b->cbcr_off);
 508
 509                vfecmd->queue = QDSP_CMDQUEUE;
 510                vfecmd->length = sizeof(struct vfe_outputack);
 511                cmd_data = &fack;
 512        }
 513                break;
 514
 515        case CMD_SNAP_BUF_RELEASE:
 516                break;
 517
 518        case CMD_STATS_BUF_RELEASE: {
 519                CDBG("vfe_7x_config: CMD_STATS_BUF_RELEASE\n");
 520                if (!data) {
 521                        rc = -EFAULT;
 522                        goto config_failure;
 523                }
 524
 525                sack.header = STATS_WE_ACK;
 526                sack.bufaddr = (void *)*(uint32_t *)data;
 527
 528                vfecmd->queue  = QDSP_CMDQUEUE;
 529                vfecmd->length = sizeof(struct vfe_stats_ack);
 530                cmd_data = &sack;
 531        }
 532                break;
 533
 534        case CMD_STATS_AF_BUF_RELEASE: {
 535                CDBG("vfe_7x_config: CMD_STATS_AF_BUF_RELEASE\n");
 536                if (!data) {
 537                        rc = -EFAULT;
 538                        goto config_failure;
 539                }
 540
 541                sack.header = STATS_AF_ACK;
 542                sack.bufaddr = (void *)*(uint32_t *)data;
 543
 544                vfecmd->queue  = QDSP_CMDQUEUE;
 545                vfecmd->length = sizeof(struct vfe_stats_ack);
 546                cmd_data = &sack;
 547        }
 548                break;
 549
 550        case CMD_GENERAL:
 551        case CMD_STATS_DISABLE: {
 552                if (vfecmd->length > 256) {
 553                        cmd_data_alloc =
 554                        cmd_data = kmalloc(vfecmd->length, GFP_ATOMIC);
 555                        if (!cmd_data) {
 556                                rc = -ENOMEM;
 557                                goto config_failure;
 558                        }
 559                } else
 560                        cmd_data = buf;
 561
 562                if (copy_from_user(cmd_data,
 563                                        (void __user *)(vfecmd->value),
 564                                        vfecmd->length)) {
 565
 566                        rc = -EFAULT;
 567                        goto config_done;
 568                }
 569
 570                if (vfecmd->queue == QDSP_CMDQUEUE) {
 571                        switch (*(uint32_t *)cmd_data) {
 572                        case VFE_RESET_CMD:
 573                                msm_camio_vfe_blk_reset();
 574                                msm_camio_camif_pad_reg_reset_2();
 575                                vfestopped = 0;
 576                                break;
 577
 578                        case VFE_START_CMD:
 579                                msm_camio_camif_pad_reg_reset_2();
 580                                vfestopped = 0;
 581                                break;
 582
 583                        case VFE_STOP_CMD:
 584                                vfestopped = 1;
 585                                goto config_send;
 586
 587                        default:
 588                                break;
 589                        }
 590                } /* QDSP_CMDQUEUE */
 591        }
 592                break;
 593
 594        case CMD_AXI_CFG_OUT1: {
 595                axid = data;
 596                if (!axid) {
 597                        rc = -EFAULT;
 598                        goto config_failure;
 599                }
 600
 601                axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
 602                if (!axio) {
 603                        rc = -ENOMEM;
 604                        goto config_failure;
 605                }
 606
 607                if (copy_from_user(axio, (void *)(vfecmd->value),
 608                                        sizeof(struct axiout))) {
 609                        rc = -EFAULT;
 610                        goto config_done;
 611                }
 612
 613                vfe_7x_config_axi(OUTPUT_1, axid, axio);
 614
 615                cmd_data = axio;
 616        }
 617                break;
 618
 619        case CMD_AXI_CFG_OUT2:
 620        case CMD_RAW_PICT_AXI_CFG: {
 621                axid = data;
 622                if (!axid) {
 623                        rc = -EFAULT;
 624                        goto config_failure;
 625                }
 626
 627                axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
 628                if (!axio) {
 629                        rc = -ENOMEM;
 630                        goto config_failure;
 631                }
 632
 633                if (copy_from_user(axio, (void __user *)(vfecmd->value),
 634                                        sizeof(struct axiout))) {
 635                        rc = -EFAULT;
 636                        goto config_done;
 637                }
 638
 639                vfe_7x_config_axi(OUTPUT_2, axid, axio);
 640                cmd_data = axio;
 641        }
 642                break;
 643
 644        case CMD_AXI_CFG_SNAP_O1_AND_O2: {
 645                axid = data;
 646                if (!axid) {
 647                        rc = -EFAULT;
 648                        goto config_failure;
 649                }
 650
 651                axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
 652                if (!axio) {
 653                        rc = -ENOMEM;
 654                        goto config_failure;
 655                }
 656
 657                if (copy_from_user(axio, (void __user *)(vfecmd->value),
 658                                        sizeof(struct axiout))) {
 659                        rc = -EFAULT;
 660                        goto config_done;
 661                }
 662
 663                vfe_7x_config_axi(OUTPUT_1_AND_2, axid, axio);
 664
 665                cmd_data = axio;
 666        }
 667                break;
 668
 669        default:
 670                break;
 671        } /* switch */
 672
 673        if (vfestopped)
 674                goto config_done;
 675
 676config_send:
 677        CDBG("send adsp command = %d\n", *(uint32_t *)cmd_data);
 678        rc = msm_adsp_write(vfe_mod, vfecmd->queue,
 679                                cmd_data, vfecmd->length);
 680
 681config_done:
 682        if (cmd_data_alloc != NULL)
 683                kfree(cmd_data_alloc);
 684
 685config_failure:
 686        kfree(scfg);
 687        kfree(axio);
 688        kfree(vfecmd);
 689        return rc;
 690}
 691
 692void msm_camvfe_fn_init(struct msm_camvfe_fn *fptr, void *data)
 693{
 694        mutex_init(&vfe_lock);
 695        fptr->vfe_init    = vfe_7x_init;
 696        fptr->vfe_enable  = vfe_7x_enable;
 697        fptr->vfe_config  = vfe_7x_config;
 698        fptr->vfe_disable = vfe_7x_disable;
 699        fptr->vfe_release = vfe_7x_release;
 700        vfe_syncdata = data;
 701}
 702