linux/drivers/gpu/drm/radeon/atom.c
<<
>>
Prefs
   1/*
   2 * Copyright 2008 Advanced Micro Devices, Inc.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20 * OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 * Author: Stanislaw Skowronek
  23 */
  24
  25#include <linux/module.h>
  26#include <linux/sched.h>
  27
  28#define ATOM_DEBUG
  29
  30#include "atom.h"
  31#include "atom-names.h"
  32#include "atom-bits.h"
  33
  34#define ATOM_COND_ABOVE         0
  35#define ATOM_COND_ABOVEOREQUAL  1
  36#define ATOM_COND_ALWAYS        2
  37#define ATOM_COND_BELOW         3
  38#define ATOM_COND_BELOWOREQUAL  4
  39#define ATOM_COND_EQUAL         5
  40#define ATOM_COND_NOTEQUAL      6
  41
  42#define ATOM_PORT_ATI   0
  43#define ATOM_PORT_PCI   1
  44#define ATOM_PORT_SYSIO 2
  45
  46#define ATOM_UNIT_MICROSEC      0
  47#define ATOM_UNIT_MILLISEC      1
  48
  49#define PLL_INDEX       2
  50#define PLL_DATA        3
  51
  52typedef struct {
  53        struct atom_context *ctx;
  54
  55        uint32_t *ps, *ws;
  56        int ps_shift;
  57        uint16_t start;
  58} atom_exec_context;
  59
  60int atom_debug = 0;
  61void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params);
  62
  63static uint32_t atom_arg_mask[8] =
  64    { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000,
  650xFF000000 };
  66static int atom_arg_shift[8] = { 0, 0, 8, 16, 0, 8, 16, 24 };
  67
  68static int atom_dst_to_src[8][4] = {
  69        /* translate destination alignment field to the source alignment encoding */
  70        {0, 0, 0, 0},
  71        {1, 2, 3, 0},
  72        {1, 2, 3, 0},
  73        {1, 2, 3, 0},
  74        {4, 5, 6, 7},
  75        {4, 5, 6, 7},
  76        {4, 5, 6, 7},
  77        {4, 5, 6, 7},
  78};
  79static int atom_def_dst[8] = { 0, 0, 1, 2, 0, 1, 2, 3 };
  80
  81static int debug_depth = 0;
  82#ifdef ATOM_DEBUG
  83static void debug_print_spaces(int n)
  84{
  85        while (n--)
  86                printk("   ");
  87}
  88
  89#define DEBUG(...) do if (atom_debug) { printk(KERN_DEBUG __VA_ARGS__); } while (0)
  90#define SDEBUG(...) do if (atom_debug) { printk(KERN_DEBUG); debug_print_spaces(debug_depth); printk(__VA_ARGS__); } while (0)
  91#else
  92#define DEBUG(...) do { } while (0)
  93#define SDEBUG(...) do { } while (0)
  94#endif
  95
  96static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
  97                                 uint32_t index, uint32_t data)
  98{
  99        uint32_t temp = 0xCDCDCDCD;
 100        while (1)
 101                switch (CU8(base)) {
 102                case ATOM_IIO_NOP:
 103                        base++;
 104                        break;
 105                case ATOM_IIO_READ:
 106                        temp = ctx->card->reg_read(ctx->card, CU16(base + 1));
 107                        base += 3;
 108                        break;
 109                case ATOM_IIO_WRITE:
 110                        (void)ctx->card->reg_read(ctx->card, CU16(base + 1));
 111                        ctx->card->reg_write(ctx->card, CU16(base + 1), temp);
 112                        base += 3;
 113                        break;
 114                case ATOM_IIO_CLEAR:
 115                        temp &=
 116                            ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
 117                              CU8(base + 2));
 118                        base += 3;
 119                        break;
 120                case ATOM_IIO_SET:
 121                        temp |=
 122                            (0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base +
 123                                                                        2);
 124                        base += 3;
 125                        break;
 126                case ATOM_IIO_MOVE_INDEX:
 127                        temp &=
 128                            ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
 129                              CU8(base + 2));
 130                        temp |=
 131                            ((index >> CU8(base + 2)) &
 132                             (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
 133                                                                          3);
 134                        base += 4;
 135                        break;
 136                case ATOM_IIO_MOVE_DATA:
 137                        temp &=
 138                            ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
 139                              CU8(base + 2));
 140                        temp |=
 141                            ((data >> CU8(base + 2)) &
 142                             (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
 143                                                                          3);
 144                        base += 4;
 145                        break;
 146                case ATOM_IIO_MOVE_ATTR:
 147                        temp &=
 148                            ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
 149                              CU8(base + 2));
 150                        temp |=
 151                            ((ctx->
 152                              io_attr >> CU8(base + 2)) & (0xFFFFFFFF >> (32 -
 153                                                                          CU8
 154                                                                          (base
 155                                                                           +
 156                                                                           1))))
 157                            << CU8(base + 3);
 158                        base += 4;
 159                        break;
 160                case ATOM_IIO_END:
 161                        return temp;
 162                default:
 163                        printk(KERN_INFO "Unknown IIO opcode.\n");
 164                        return 0;
 165                }
 166}
 167
 168static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
 169                                 int *ptr, uint32_t *saved, int print)
 170{
 171        uint32_t idx, val = 0xCDCDCDCD, align, arg;
 172        struct atom_context *gctx = ctx->ctx;
 173        arg = attr & 7;
 174        align = (attr >> 3) & 7;
 175        switch (arg) {
 176        case ATOM_ARG_REG:
 177                idx = U16(*ptr);
 178                (*ptr) += 2;
 179                if (print)
 180                        DEBUG("REG[0x%04X]", idx);
 181                idx += gctx->reg_block;
 182                switch (gctx->io_mode) {
 183                case ATOM_IO_MM:
 184                        val = gctx->card->reg_read(gctx->card, idx);
 185                        break;
 186                case ATOM_IO_PCI:
 187                        printk(KERN_INFO
 188                               "PCI registers are not implemented.\n");
 189                        return 0;
 190                case ATOM_IO_SYSIO:
 191                        printk(KERN_INFO
 192                               "SYSIO registers are not implemented.\n");
 193                        return 0;
 194                default:
 195                        if (!(gctx->io_mode & 0x80)) {
 196                                printk(KERN_INFO "Bad IO mode.\n");
 197                                return 0;
 198                        }
 199                        if (!gctx->iio[gctx->io_mode & 0x7F]) {
 200                                printk(KERN_INFO
 201                                       "Undefined indirect IO read method %d.\n",
 202                                       gctx->io_mode & 0x7F);
 203                                return 0;
 204                        }
 205                        val =
 206                            atom_iio_execute(gctx,
 207                                             gctx->iio[gctx->io_mode & 0x7F],
 208                                             idx, 0);
 209                }
 210                break;
 211        case ATOM_ARG_PS:
 212                idx = U8(*ptr);
 213                (*ptr)++;
 214                val = le32_to_cpu(ctx->ps[idx]);
 215                if (print)
 216                        DEBUG("PS[0x%02X,0x%04X]", idx, val);
 217                break;
 218        case ATOM_ARG_WS:
 219                idx = U8(*ptr);
 220                (*ptr)++;
 221                if (print)
 222                        DEBUG("WS[0x%02X]", idx);
 223                switch (idx) {
 224                case ATOM_WS_QUOTIENT:
 225                        val = gctx->divmul[0];
 226                        break;
 227                case ATOM_WS_REMAINDER:
 228                        val = gctx->divmul[1];
 229                        break;
 230                case ATOM_WS_DATAPTR:
 231                        val = gctx->data_block;
 232                        break;
 233                case ATOM_WS_SHIFT:
 234                        val = gctx->shift;
 235                        break;
 236                case ATOM_WS_OR_MASK:
 237                        val = 1 << gctx->shift;
 238                        break;
 239                case ATOM_WS_AND_MASK:
 240                        val = ~(1 << gctx->shift);
 241                        break;
 242                case ATOM_WS_FB_WINDOW:
 243                        val = gctx->fb_base;
 244                        break;
 245                case ATOM_WS_ATTRIBUTES:
 246                        val = gctx->io_attr;
 247                        break;
 248                default:
 249                        val = ctx->ws[idx];
 250                }
 251                break;
 252        case ATOM_ARG_ID:
 253                idx = U16(*ptr);
 254                (*ptr) += 2;
 255                if (print) {
 256                        if (gctx->data_block)
 257                                DEBUG("ID[0x%04X+%04X]", idx, gctx->data_block);
 258                        else
 259                                DEBUG("ID[0x%04X]", idx);
 260                }
 261                val = U32(idx + gctx->data_block);
 262                break;
 263        case ATOM_ARG_FB:
 264                idx = U8(*ptr);
 265                (*ptr)++;
 266                if (print)
 267                        DEBUG("FB[0x%02X]", idx);
 268                printk(KERN_INFO "FB access is not implemented.\n");
 269                return 0;
 270        case ATOM_ARG_IMM:
 271                switch (align) {
 272                case ATOM_SRC_DWORD:
 273                        val = U32(*ptr);
 274                        (*ptr) += 4;
 275                        if (print)
 276                                DEBUG("IMM 0x%08X\n", val);
 277                        return val;
 278                case ATOM_SRC_WORD0:
 279                case ATOM_SRC_WORD8:
 280                case ATOM_SRC_WORD16:
 281                        val = U16(*ptr);
 282                        (*ptr) += 2;
 283                        if (print)
 284                                DEBUG("IMM 0x%04X\n", val);
 285                        return val;
 286                case ATOM_SRC_BYTE0:
 287                case ATOM_SRC_BYTE8:
 288                case ATOM_SRC_BYTE16:
 289                case ATOM_SRC_BYTE24:
 290                        val = U8(*ptr);
 291                        (*ptr)++;
 292                        if (print)
 293                                DEBUG("IMM 0x%02X\n", val);
 294                        return val;
 295                }
 296                return 0;
 297        case ATOM_ARG_PLL:
 298                idx = U8(*ptr);
 299                (*ptr)++;
 300                if (print)
 301                        DEBUG("PLL[0x%02X]", idx);
 302                val = gctx->card->pll_read(gctx->card, idx);
 303                break;
 304        case ATOM_ARG_MC:
 305                idx = U8(*ptr);
 306                (*ptr)++;
 307                if (print)
 308                        DEBUG("MC[0x%02X]", idx);
 309                val = gctx->card->mc_read(gctx->card, idx);
 310                break;
 311        }
 312        if (saved)
 313                *saved = val;
 314        val &= atom_arg_mask[align];
 315        val >>= atom_arg_shift[align];
 316        if (print)
 317                switch (align) {
 318                case ATOM_SRC_DWORD:
 319                        DEBUG(".[31:0] -> 0x%08X\n", val);
 320                        break;
 321                case ATOM_SRC_WORD0:
 322                        DEBUG(".[15:0] -> 0x%04X\n", val);
 323                        break;
 324                case ATOM_SRC_WORD8:
 325                        DEBUG(".[23:8] -> 0x%04X\n", val);
 326                        break;
 327                case ATOM_SRC_WORD16:
 328                        DEBUG(".[31:16] -> 0x%04X\n", val);
 329                        break;
 330                case ATOM_SRC_BYTE0:
 331                        DEBUG(".[7:0] -> 0x%02X\n", val);
 332                        break;
 333                case ATOM_SRC_BYTE8:
 334                        DEBUG(".[15:8] -> 0x%02X\n", val);
 335                        break;
 336                case ATOM_SRC_BYTE16:
 337                        DEBUG(".[23:16] -> 0x%02X\n", val);
 338                        break;
 339                case ATOM_SRC_BYTE24:
 340                        DEBUG(".[31:24] -> 0x%02X\n", val);
 341                        break;
 342                }
 343        return val;
 344}
 345
 346static void atom_skip_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr)
 347{
 348        uint32_t align = (attr >> 3) & 7, arg = attr & 7;
 349        switch (arg) {
 350        case ATOM_ARG_REG:
 351        case ATOM_ARG_ID:
 352                (*ptr) += 2;
 353                break;
 354        case ATOM_ARG_PLL:
 355        case ATOM_ARG_MC:
 356        case ATOM_ARG_PS:
 357        case ATOM_ARG_WS:
 358        case ATOM_ARG_FB:
 359                (*ptr)++;
 360                break;
 361        case ATOM_ARG_IMM:
 362                switch (align) {
 363                case ATOM_SRC_DWORD:
 364                        (*ptr) += 4;
 365                        return;
 366                case ATOM_SRC_WORD0:
 367                case ATOM_SRC_WORD8:
 368                case ATOM_SRC_WORD16:
 369                        (*ptr) += 2;
 370                        return;
 371                case ATOM_SRC_BYTE0:
 372                case ATOM_SRC_BYTE8:
 373                case ATOM_SRC_BYTE16:
 374                case ATOM_SRC_BYTE24:
 375                        (*ptr)++;
 376                        return;
 377                }
 378                return;
 379        }
 380}
 381
 382static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr)
 383{
 384        return atom_get_src_int(ctx, attr, ptr, NULL, 1);
 385}
 386
 387static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr,
 388                             int *ptr, uint32_t *saved, int print)
 389{
 390        return atom_get_src_int(ctx,
 391                                arg | atom_dst_to_src[(attr >> 3) &
 392                                                      7][(attr >> 6) & 3] << 3,
 393                                ptr, saved, print);
 394}
 395
 396static void atom_skip_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr)
 397{
 398        atom_skip_src_int(ctx,
 399                          arg | atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) &
 400                                                                 3] << 3, ptr);
 401}
 402
 403static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
 404                         int *ptr, uint32_t val, uint32_t saved)
 405{
 406        uint32_t align =
 407            atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3], old_val =
 408            val, idx;
 409        struct atom_context *gctx = ctx->ctx;
 410        old_val &= atom_arg_mask[align] >> atom_arg_shift[align];
 411        val <<= atom_arg_shift[align];
 412        val &= atom_arg_mask[align];
 413        saved &= ~atom_arg_mask[align];
 414        val |= saved;
 415        switch (arg) {
 416        case ATOM_ARG_REG:
 417                idx = U16(*ptr);
 418                (*ptr) += 2;
 419                DEBUG("REG[0x%04X]", idx);
 420                idx += gctx->reg_block;
 421                switch (gctx->io_mode) {
 422                case ATOM_IO_MM:
 423                        if (idx == 0)
 424                                gctx->card->reg_write(gctx->card, idx,
 425                                                      val << 2);
 426                        else
 427                                gctx->card->reg_write(gctx->card, idx, val);
 428                        break;
 429                case ATOM_IO_PCI:
 430                        printk(KERN_INFO
 431                               "PCI registers are not implemented.\n");
 432                        return;
 433                case ATOM_IO_SYSIO:
 434                        printk(KERN_INFO
 435                               "SYSIO registers are not implemented.\n");
 436                        return;
 437                default:
 438                        if (!(gctx->io_mode & 0x80)) {
 439                                printk(KERN_INFO "Bad IO mode.\n");
 440                                return;
 441                        }
 442                        if (!gctx->iio[gctx->io_mode & 0xFF]) {
 443                                printk(KERN_INFO
 444                                       "Undefined indirect IO write method %d.\n",
 445                                       gctx->io_mode & 0x7F);
 446                                return;
 447                        }
 448                        atom_iio_execute(gctx, gctx->iio[gctx->io_mode & 0xFF],
 449                                         idx, val);
 450                }
 451                break;
 452        case ATOM_ARG_PS:
 453                idx = U8(*ptr);
 454                (*ptr)++;
 455                DEBUG("PS[0x%02X]", idx);
 456                ctx->ps[idx] = cpu_to_le32(val);
 457                break;
 458        case ATOM_ARG_WS:
 459                idx = U8(*ptr);
 460                (*ptr)++;
 461                DEBUG("WS[0x%02X]", idx);
 462                switch (idx) {
 463                case ATOM_WS_QUOTIENT:
 464                        gctx->divmul[0] = val;
 465                        break;
 466                case ATOM_WS_REMAINDER:
 467                        gctx->divmul[1] = val;
 468                        break;
 469                case ATOM_WS_DATAPTR:
 470                        gctx->data_block = val;
 471                        break;
 472                case ATOM_WS_SHIFT:
 473                        gctx->shift = val;
 474                        break;
 475                case ATOM_WS_OR_MASK:
 476                case ATOM_WS_AND_MASK:
 477                        break;
 478                case ATOM_WS_FB_WINDOW:
 479                        gctx->fb_base = val;
 480                        break;
 481                case ATOM_WS_ATTRIBUTES:
 482                        gctx->io_attr = val;
 483                        break;
 484                default:
 485                        ctx->ws[idx] = val;
 486                }
 487                break;
 488        case ATOM_ARG_FB:
 489                idx = U8(*ptr);
 490                (*ptr)++;
 491                DEBUG("FB[0x%02X]", idx);
 492                printk(KERN_INFO "FB access is not implemented.\n");
 493                return;
 494        case ATOM_ARG_PLL:
 495                idx = U8(*ptr);
 496                (*ptr)++;
 497                DEBUG("PLL[0x%02X]", idx);
 498                gctx->card->pll_write(gctx->card, idx, val);
 499                break;
 500        case ATOM_ARG_MC:
 501                idx = U8(*ptr);
 502                (*ptr)++;
 503                DEBUG("MC[0x%02X]", idx);
 504                gctx->card->mc_write(gctx->card, idx, val);
 505                return;
 506        }
 507        switch (align) {
 508        case ATOM_SRC_DWORD:
 509                DEBUG(".[31:0] <- 0x%08X\n", old_val);
 510                break;
 511        case ATOM_SRC_WORD0:
 512                DEBUG(".[15:0] <- 0x%04X\n", old_val);
 513                break;
 514        case ATOM_SRC_WORD8:
 515                DEBUG(".[23:8] <- 0x%04X\n", old_val);
 516                break;
 517        case ATOM_SRC_WORD16:
 518                DEBUG(".[31:16] <- 0x%04X\n", old_val);
 519                break;
 520        case ATOM_SRC_BYTE0:
 521                DEBUG(".[7:0] <- 0x%02X\n", old_val);
 522                break;
 523        case ATOM_SRC_BYTE8:
 524                DEBUG(".[15:8] <- 0x%02X\n", old_val);
 525                break;
 526        case ATOM_SRC_BYTE16:
 527                DEBUG(".[23:16] <- 0x%02X\n", old_val);
 528                break;
 529        case ATOM_SRC_BYTE24:
 530                DEBUG(".[31:24] <- 0x%02X\n", old_val);
 531                break;
 532        }
 533}
 534
 535static void atom_op_add(atom_exec_context *ctx, int *ptr, int arg)
 536{
 537        uint8_t attr = U8((*ptr)++);
 538        uint32_t dst, src, saved;
 539        int dptr = *ptr;
 540        SDEBUG("   dst: ");
 541        dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
 542        SDEBUG("   src: ");
 543        src = atom_get_src(ctx, attr, ptr);
 544        dst += src;
 545        SDEBUG("   dst: ");
 546        atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
 547}
 548
 549static void atom_op_and(atom_exec_context *ctx, int *ptr, int arg)
 550{
 551        uint8_t attr = U8((*ptr)++);
 552        uint32_t dst, src, saved;
 553        int dptr = *ptr;
 554        SDEBUG("   dst: ");
 555        dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
 556        SDEBUG("   src: ");
 557        src = atom_get_src(ctx, attr, ptr);
 558        dst &= src;
 559        SDEBUG("   dst: ");
 560        atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
 561}
 562
 563static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg)
 564{
 565        printk("ATOM BIOS beeped!\n");
 566}
 567
 568static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
 569{
 570        int idx = U8((*ptr)++);
 571        if (idx < ATOM_TABLE_NAMES_CNT)
 572                SDEBUG("   table: %d (%s)\n", idx, atom_table_names[idx]);
 573        else
 574                SDEBUG("   table: %d\n", idx);
 575        if (U16(ctx->ctx->cmd_table + 4 + 2 * idx))
 576                atom_execute_table(ctx->ctx, idx, ctx->ps + ctx->ps_shift);
 577}
 578
 579static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg)
 580{
 581        uint8_t attr = U8((*ptr)++);
 582        uint32_t saved;
 583        int dptr = *ptr;
 584        attr &= 0x38;
 585        attr |= atom_def_dst[attr >> 3] << 6;
 586        atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
 587        SDEBUG("   dst: ");
 588        atom_put_dst(ctx, arg, attr, &dptr, 0, saved);
 589}
 590
 591static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg)
 592{
 593        uint8_t attr = U8((*ptr)++);
 594        uint32_t dst, src;
 595        SDEBUG("   src1: ");
 596        dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
 597        SDEBUG("   src2: ");
 598        src = atom_get_src(ctx, attr, ptr);
 599        ctx->ctx->cs_equal = (dst == src);
 600        ctx->ctx->cs_above = (dst > src);
 601        SDEBUG("   result: %s %s\n", ctx->ctx->cs_equal ? "EQ" : "NE",
 602               ctx->ctx->cs_above ? "GT" : "LE");
 603}
 604
 605static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg)
 606{
 607        uint8_t count = U8((*ptr)++);
 608        SDEBUG("   count: %d\n", count);
 609        if (arg == ATOM_UNIT_MICROSEC)
 610                schedule_timeout_uninterruptible(usecs_to_jiffies(count));
 611        else
 612                schedule_timeout_uninterruptible(msecs_to_jiffies(count));
 613}
 614
 615static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg)
 616{
 617        uint8_t attr = U8((*ptr)++);
 618        uint32_t dst, src;
 619        SDEBUG("   src1: ");
 620        dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
 621        SDEBUG("   src2: ");
 622        src = atom_get_src(ctx, attr, ptr);
 623        if (src != 0) {
 624                ctx->ctx->divmul[0] = dst / src;
 625                ctx->ctx->divmul[1] = dst % src;
 626        } else {
 627                ctx->ctx->divmul[0] = 0;
 628                ctx->ctx->divmul[1] = 0;
 629        }
 630}
 631
 632static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg)
 633{
 634        /* functionally, a nop */
 635}
 636
 637static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
 638{
 639        int execute = 0, target = U16(*ptr);
 640        (*ptr) += 2;
 641        switch (arg) {
 642        case ATOM_COND_ABOVE:
 643                execute = ctx->ctx->cs_above;
 644                break;
 645        case ATOM_COND_ABOVEOREQUAL:
 646                execute = ctx->ctx->cs_above || ctx->ctx->cs_equal;
 647                break;
 648        case ATOM_COND_ALWAYS:
 649                execute = 1;
 650                break;
 651        case ATOM_COND_BELOW:
 652                execute = !(ctx->ctx->cs_above || ctx->ctx->cs_equal);
 653                break;
 654        case ATOM_COND_BELOWOREQUAL:
 655                execute = !ctx->ctx->cs_above;
 656                break;
 657        case ATOM_COND_EQUAL:
 658                execute = ctx->ctx->cs_equal;
 659                break;
 660        case ATOM_COND_NOTEQUAL:
 661                execute = !ctx->ctx->cs_equal;
 662                break;
 663        }
 664        if (arg != ATOM_COND_ALWAYS)
 665                SDEBUG("   taken: %s\n", execute ? "yes" : "no");
 666        SDEBUG("   target: 0x%04X\n", target);
 667        if (execute)
 668                *ptr = ctx->start + target;
 669}
 670
 671static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
 672{
 673        uint8_t attr = U8((*ptr)++);
 674        uint32_t dst, src1, src2, saved;
 675        int dptr = *ptr;
 676        SDEBUG("   dst: ");
 677        dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
 678        SDEBUG("   src1: ");
 679        src1 = atom_get_src(ctx, attr, ptr);
 680        SDEBUG("   src2: ");
 681        src2 = atom_get_src(ctx, attr, ptr);
 682        dst &= src1;
 683        dst |= src2;
 684        SDEBUG("   dst: ");
 685        atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
 686}
 687
 688static void atom_op_move(atom_exec_context *ctx, int *ptr, int arg)
 689{
 690        uint8_t attr = U8((*ptr)++);
 691        uint32_t src, saved;
 692        int dptr = *ptr;
 693        if (((attr >> 3) & 7) != ATOM_SRC_DWORD)
 694                atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
 695        else {
 696                atom_skip_dst(ctx, arg, attr, ptr);
 697                saved = 0xCDCDCDCD;
 698        }
 699        SDEBUG("   src: ");
 700        src = atom_get_src(ctx, attr, ptr);
 701        SDEBUG("   dst: ");
 702        atom_put_dst(ctx, arg, attr, &dptr, src, saved);
 703}
 704
 705static void atom_op_mul(atom_exec_context *ctx, int *ptr, int arg)
 706{
 707        uint8_t attr = U8((*ptr)++);
 708        uint32_t dst, src;
 709        SDEBUG("   src1: ");
 710        dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
 711        SDEBUG("   src2: ");
 712        src = atom_get_src(ctx, attr, ptr);
 713        ctx->ctx->divmul[0] = dst * src;
 714}
 715
 716static void atom_op_nop(atom_exec_context *ctx, int *ptr, int arg)
 717{
 718        /* nothing */
 719}
 720
 721static void atom_op_or(atom_exec_context *ctx, int *ptr, int arg)
 722{
 723        uint8_t attr = U8((*ptr)++);
 724        uint32_t dst, src, saved;
 725        int dptr = *ptr;
 726        SDEBUG("   dst: ");
 727        dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
 728        SDEBUG("   src: ");
 729        src = atom_get_src(ctx, attr, ptr);
 730        dst |= src;
 731        SDEBUG("   dst: ");
 732        atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
 733}
 734
 735static void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg)
 736{
 737        uint8_t val = U8((*ptr)++);
 738        SDEBUG("POST card output: 0x%02X\n", val);
 739}
 740
 741static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg)
 742{
 743        printk(KERN_INFO "unimplemented!\n");
 744}
 745
 746static void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg)
 747{
 748        printk(KERN_INFO "unimplemented!\n");
 749}
 750
 751static void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg)
 752{
 753        printk(KERN_INFO "unimplemented!\n");
 754}
 755
 756static void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg)
 757{
 758        int idx = U8(*ptr);
 759        (*ptr)++;
 760        SDEBUG("   block: %d\n", idx);
 761        if (!idx)
 762                ctx->ctx->data_block = 0;
 763        else if (idx == 255)
 764                ctx->ctx->data_block = ctx->start;
 765        else
 766                ctx->ctx->data_block = U16(ctx->ctx->data_table + 4 + 2 * idx);
 767        SDEBUG("   base: 0x%04X\n", ctx->ctx->data_block);
 768}
 769
 770static void atom_op_setfbbase(atom_exec_context *ctx, int *ptr, int arg)
 771{
 772        uint8_t attr = U8((*ptr)++);
 773        SDEBUG("   fb_base: ");
 774        ctx->ctx->fb_base = atom_get_src(ctx, attr, ptr);
 775}
 776
 777static void atom_op_setport(atom_exec_context *ctx, int *ptr, int arg)
 778{
 779        int port;
 780        switch (arg) {
 781        case ATOM_PORT_ATI:
 782                port = U16(*ptr);
 783                if (port < ATOM_IO_NAMES_CNT)
 784                        SDEBUG("   port: %d (%s)\n", port, atom_io_names[port]);
 785                else
 786                        SDEBUG("   port: %d\n", port);
 787                if (!port)
 788                        ctx->ctx->io_mode = ATOM_IO_MM;
 789                else
 790                        ctx->ctx->io_mode = ATOM_IO_IIO | port;
 791                (*ptr) += 2;
 792                break;
 793        case ATOM_PORT_PCI:
 794                ctx->ctx->io_mode = ATOM_IO_PCI;
 795                (*ptr)++;
 796                break;
 797        case ATOM_PORT_SYSIO:
 798                ctx->ctx->io_mode = ATOM_IO_SYSIO;
 799                (*ptr)++;
 800                break;
 801        }
 802}
 803
 804static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg)
 805{
 806        ctx->ctx->reg_block = U16(*ptr);
 807        (*ptr) += 2;
 808        SDEBUG("   base: 0x%04X\n", ctx->ctx->reg_block);
 809}
 810
 811static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
 812{
 813        uint8_t attr = U8((*ptr)++), shift;
 814        uint32_t saved, dst;
 815        int dptr = *ptr;
 816        attr &= 0x38;
 817        attr |= atom_def_dst[attr >> 3] << 6;
 818        SDEBUG("   dst: ");
 819        dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
 820        shift = U8((*ptr)++);
 821        SDEBUG("   shift: %d\n", shift);
 822        dst <<= shift;
 823        SDEBUG("   dst: ");
 824        atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
 825}
 826
 827static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
 828{
 829        uint8_t attr = U8((*ptr)++), shift;
 830        uint32_t saved, dst;
 831        int dptr = *ptr;
 832        attr &= 0x38;
 833        attr |= atom_def_dst[attr >> 3] << 6;
 834        SDEBUG("   dst: ");
 835        dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
 836        shift = U8((*ptr)++);
 837        SDEBUG("   shift: %d\n", shift);
 838        dst >>= shift;
 839        SDEBUG("   dst: ");
 840        atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
 841}
 842
 843static void atom_op_sub(atom_exec_context *ctx, int *ptr, int arg)
 844{
 845        uint8_t attr = U8((*ptr)++);
 846        uint32_t dst, src, saved;
 847        int dptr = *ptr;
 848        SDEBUG("   dst: ");
 849        dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
 850        SDEBUG("   src: ");
 851        src = atom_get_src(ctx, attr, ptr);
 852        dst -= src;
 853        SDEBUG("   dst: ");
 854        atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
 855}
 856
 857static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg)
 858{
 859        uint8_t attr = U8((*ptr)++);
 860        uint32_t src, val, target;
 861        SDEBUG("   switch: ");
 862        src = atom_get_src(ctx, attr, ptr);
 863        while (U16(*ptr) != ATOM_CASE_END)
 864                if (U8(*ptr) == ATOM_CASE_MAGIC) {
 865                        (*ptr)++;
 866                        SDEBUG("   case: ");
 867                        val =
 868                            atom_get_src(ctx, (attr & 0x38) | ATOM_ARG_IMM,
 869                                         ptr);
 870                        target = U16(*ptr);
 871                        if (val == src) {
 872                                SDEBUG("   target: %04X\n", target);
 873                                *ptr = ctx->start + target;
 874                                return;
 875                        }
 876                        (*ptr) += 2;
 877                } else {
 878                        printk(KERN_INFO "Bad case.\n");
 879                        return;
 880                }
 881        (*ptr) += 2;
 882}
 883
 884static void atom_op_test(atom_exec_context *ctx, int *ptr, int arg)
 885{
 886        uint8_t attr = U8((*ptr)++);
 887        uint32_t dst, src;
 888        SDEBUG("   src1: ");
 889        dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
 890        SDEBUG("   src2: ");
 891        src = atom_get_src(ctx, attr, ptr);
 892        ctx->ctx->cs_equal = ((dst & src) == 0);
 893        SDEBUG("   result: %s\n", ctx->ctx->cs_equal ? "EQ" : "NE");
 894}
 895
 896static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg)
 897{
 898        uint8_t attr = U8((*ptr)++);
 899        uint32_t dst, src, saved;
 900        int dptr = *ptr;
 901        SDEBUG("   dst: ");
 902        dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
 903        SDEBUG("   src: ");
 904        src = atom_get_src(ctx, attr, ptr);
 905        dst ^= src;
 906        SDEBUG("   dst: ");
 907        atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
 908}
 909
 910static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg)
 911{
 912        printk(KERN_INFO "unimplemented!\n");
 913}
 914
 915static struct {
 916        void (*func) (atom_exec_context *, int *, int);
 917        int arg;
 918} opcode_table[ATOM_OP_CNT] = {
 919        {
 920        NULL, 0}, {
 921        atom_op_move, ATOM_ARG_REG}, {
 922        atom_op_move, ATOM_ARG_PS}, {
 923        atom_op_move, ATOM_ARG_WS}, {
 924        atom_op_move, ATOM_ARG_FB}, {
 925        atom_op_move, ATOM_ARG_PLL}, {
 926        atom_op_move, ATOM_ARG_MC}, {
 927        atom_op_and, ATOM_ARG_REG}, {
 928        atom_op_and, ATOM_ARG_PS}, {
 929        atom_op_and, ATOM_ARG_WS}, {
 930        atom_op_and, ATOM_ARG_FB}, {
 931        atom_op_and, ATOM_ARG_PLL}, {
 932        atom_op_and, ATOM_ARG_MC}, {
 933        atom_op_or, ATOM_ARG_REG}, {
 934        atom_op_or, ATOM_ARG_PS}, {
 935        atom_op_or, ATOM_ARG_WS}, {
 936        atom_op_or, ATOM_ARG_FB}, {
 937        atom_op_or, ATOM_ARG_PLL}, {
 938        atom_op_or, ATOM_ARG_MC}, {
 939        atom_op_shl, ATOM_ARG_REG}, {
 940        atom_op_shl, ATOM_ARG_PS}, {
 941        atom_op_shl, ATOM_ARG_WS}, {
 942        atom_op_shl, ATOM_ARG_FB}, {
 943        atom_op_shl, ATOM_ARG_PLL}, {
 944        atom_op_shl, ATOM_ARG_MC}, {
 945        atom_op_shr, ATOM_ARG_REG}, {
 946        atom_op_shr, ATOM_ARG_PS}, {
 947        atom_op_shr, ATOM_ARG_WS}, {
 948        atom_op_shr, ATOM_ARG_FB}, {
 949        atom_op_shr, ATOM_ARG_PLL}, {
 950        atom_op_shr, ATOM_ARG_MC}, {
 951        atom_op_mul, ATOM_ARG_REG}, {
 952        atom_op_mul, ATOM_ARG_PS}, {
 953        atom_op_mul, ATOM_ARG_WS}, {
 954        atom_op_mul, ATOM_ARG_FB}, {
 955        atom_op_mul, ATOM_ARG_PLL}, {
 956        atom_op_mul, ATOM_ARG_MC}, {
 957        atom_op_div, ATOM_ARG_REG}, {
 958        atom_op_div, ATOM_ARG_PS}, {
 959        atom_op_div, ATOM_ARG_WS}, {
 960        atom_op_div, ATOM_ARG_FB}, {
 961        atom_op_div, ATOM_ARG_PLL}, {
 962        atom_op_div, ATOM_ARG_MC}, {
 963        atom_op_add, ATOM_ARG_REG}, {
 964        atom_op_add, ATOM_ARG_PS}, {
 965        atom_op_add, ATOM_ARG_WS}, {
 966        atom_op_add, ATOM_ARG_FB}, {
 967        atom_op_add, ATOM_ARG_PLL}, {
 968        atom_op_add, ATOM_ARG_MC}, {
 969        atom_op_sub, ATOM_ARG_REG}, {
 970        atom_op_sub, ATOM_ARG_PS}, {
 971        atom_op_sub, ATOM_ARG_WS}, {
 972        atom_op_sub, ATOM_ARG_FB}, {
 973        atom_op_sub, ATOM_ARG_PLL}, {
 974        atom_op_sub, ATOM_ARG_MC}, {
 975        atom_op_setport, ATOM_PORT_ATI}, {
 976        atom_op_setport, ATOM_PORT_PCI}, {
 977        atom_op_setport, ATOM_PORT_SYSIO}, {
 978        atom_op_setregblock, 0}, {
 979        atom_op_setfbbase, 0}, {
 980        atom_op_compare, ATOM_ARG_REG}, {
 981        atom_op_compare, ATOM_ARG_PS}, {
 982        atom_op_compare, ATOM_ARG_WS}, {
 983        atom_op_compare, ATOM_ARG_FB}, {
 984        atom_op_compare, ATOM_ARG_PLL}, {
 985        atom_op_compare, ATOM_ARG_MC}, {
 986        atom_op_switch, 0}, {
 987        atom_op_jump, ATOM_COND_ALWAYS}, {
 988        atom_op_jump, ATOM_COND_EQUAL}, {
 989        atom_op_jump, ATOM_COND_BELOW}, {
 990        atom_op_jump, ATOM_COND_ABOVE}, {
 991        atom_op_jump, ATOM_COND_BELOWOREQUAL}, {
 992        atom_op_jump, ATOM_COND_ABOVEOREQUAL}, {
 993        atom_op_jump, ATOM_COND_NOTEQUAL}, {
 994        atom_op_test, ATOM_ARG_REG}, {
 995        atom_op_test, ATOM_ARG_PS}, {
 996        atom_op_test, ATOM_ARG_WS}, {
 997        atom_op_test, ATOM_ARG_FB}, {
 998        atom_op_test, ATOM_ARG_PLL}, {
 999        atom_op_test, ATOM_ARG_MC}, {
1000        atom_op_delay, ATOM_UNIT_MILLISEC}, {
1001        atom_op_delay, ATOM_UNIT_MICROSEC}, {
1002        atom_op_calltable, 0}, {
1003        atom_op_repeat, 0}, {
1004        atom_op_clear, ATOM_ARG_REG}, {
1005        atom_op_clear, ATOM_ARG_PS}, {
1006        atom_op_clear, ATOM_ARG_WS}, {
1007        atom_op_clear, ATOM_ARG_FB}, {
1008        atom_op_clear, ATOM_ARG_PLL}, {
1009        atom_op_clear, ATOM_ARG_MC}, {
1010        atom_op_nop, 0}, {
1011        atom_op_eot, 0}, {
1012        atom_op_mask, ATOM_ARG_REG}, {
1013        atom_op_mask, ATOM_ARG_PS}, {
1014        atom_op_mask, ATOM_ARG_WS}, {
1015        atom_op_mask, ATOM_ARG_FB}, {
1016        atom_op_mask, ATOM_ARG_PLL}, {
1017        atom_op_mask, ATOM_ARG_MC}, {
1018        atom_op_postcard, 0}, {
1019        atom_op_beep, 0}, {
1020        atom_op_savereg, 0}, {
1021        atom_op_restorereg, 0}, {
1022        atom_op_setdatablock, 0}, {
1023        atom_op_xor, ATOM_ARG_REG}, {
1024        atom_op_xor, ATOM_ARG_PS}, {
1025        atom_op_xor, ATOM_ARG_WS}, {
1026        atom_op_xor, ATOM_ARG_FB}, {
1027        atom_op_xor, ATOM_ARG_PLL}, {
1028        atom_op_xor, ATOM_ARG_MC}, {
1029        atom_op_shl, ATOM_ARG_REG}, {
1030        atom_op_shl, ATOM_ARG_PS}, {
1031        atom_op_shl, ATOM_ARG_WS}, {
1032        atom_op_shl, ATOM_ARG_FB}, {
1033        atom_op_shl, ATOM_ARG_PLL}, {
1034        atom_op_shl, ATOM_ARG_MC}, {
1035        atom_op_shr, ATOM_ARG_REG}, {
1036        atom_op_shr, ATOM_ARG_PS}, {
1037        atom_op_shr, ATOM_ARG_WS}, {
1038        atom_op_shr, ATOM_ARG_FB}, {
1039        atom_op_shr, ATOM_ARG_PLL}, {
1040        atom_op_shr, ATOM_ARG_MC}, {
1041atom_op_debug, 0},};
1042
1043void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
1044{
1045        int base = CU16(ctx->cmd_table + 4 + 2 * index);
1046        int len, ws, ps, ptr;
1047        unsigned char op;
1048        atom_exec_context ectx;
1049
1050        if (!base)
1051                return;
1052
1053        len = CU16(base + ATOM_CT_SIZE_PTR);
1054        ws = CU8(base + ATOM_CT_WS_PTR);
1055        ps = CU8(base + ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK;
1056        ptr = base + ATOM_CT_CODE_PTR;
1057
1058        SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps);
1059
1060        /* reset reg block */
1061        ctx->reg_block = 0;
1062        ectx.ctx = ctx;
1063        ectx.ps_shift = ps / 4;
1064        ectx.start = base;
1065        ectx.ps = params;
1066        if (ws)
1067                ectx.ws = kzalloc(4 * ws, GFP_KERNEL);
1068        else
1069                ectx.ws = NULL;
1070
1071        debug_depth++;
1072        while (1) {
1073                op = CU8(ptr++);
1074                if (op < ATOM_OP_NAMES_CNT)
1075                        SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1);
1076                else
1077                        SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1);
1078
1079                if (op < ATOM_OP_CNT && op > 0)
1080                        opcode_table[op].func(&ectx, &ptr,
1081                                              opcode_table[op].arg);
1082                else
1083                        break;
1084
1085                if (op == ATOM_OP_EOT)
1086                        break;
1087        }
1088        debug_depth--;
1089        SDEBUG("<<\n");
1090
1091        if (ws)
1092                kfree(ectx.ws);
1093}
1094
1095static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
1096
1097static void atom_index_iio(struct atom_context *ctx, int base)
1098{
1099        ctx->iio = kzalloc(2 * 256, GFP_KERNEL);
1100        while (CU8(base) == ATOM_IIO_START) {
1101                ctx->iio[CU8(base + 1)] = base + 2;
1102                base += 2;
1103                while (CU8(base) != ATOM_IIO_END)
1104                        base += atom_iio_len[CU8(base)];
1105                base += 3;
1106        }
1107}
1108
1109struct atom_context *atom_parse(struct card_info *card, void *bios)
1110{
1111        int base;
1112        struct atom_context *ctx =
1113            kzalloc(sizeof(struct atom_context), GFP_KERNEL);
1114        char *str;
1115        char name[512];
1116        int i;
1117
1118        ctx->card = card;
1119        ctx->bios = bios;
1120
1121        if (CU16(0) != ATOM_BIOS_MAGIC) {
1122                printk(KERN_INFO "Invalid BIOS magic.\n");
1123                kfree(ctx);
1124                return NULL;
1125        }
1126        if (strncmp
1127            (CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC,
1128             strlen(ATOM_ATI_MAGIC))) {
1129                printk(KERN_INFO "Invalid ATI magic.\n");
1130                kfree(ctx);
1131                return NULL;
1132        }
1133
1134        base = CU16(ATOM_ROM_TABLE_PTR);
1135        if (strncmp
1136            (CSTR(base + ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC,
1137             strlen(ATOM_ROM_MAGIC))) {
1138                printk(KERN_INFO "Invalid ATOM magic.\n");
1139                kfree(ctx);
1140                return NULL;
1141        }
1142
1143        ctx->cmd_table = CU16(base + ATOM_ROM_CMD_PTR);
1144        ctx->data_table = CU16(base + ATOM_ROM_DATA_PTR);
1145        atom_index_iio(ctx, CU16(ctx->data_table + ATOM_DATA_IIO_PTR) + 4);
1146
1147        str = CSTR(CU16(base + ATOM_ROM_MSG_PTR));
1148        while (*str && ((*str == '\n') || (*str == '\r')))
1149                str++;
1150        /* name string isn't always 0 terminated */
1151        for (i = 0; i < 511; i++) {
1152                name[i] = str[i];
1153                if (name[i] < '.' || name[i] > 'z') {
1154                        name[i] = 0;
1155                        break;
1156                }
1157        }
1158        printk(KERN_INFO "ATOM BIOS: %s\n", name);
1159
1160        return ctx;
1161}
1162
1163int atom_asic_init(struct atom_context *ctx)
1164{
1165        int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR);
1166        uint32_t ps[16];
1167        memset(ps, 0, 64);
1168
1169        ps[0] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR));
1170        ps[1] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFMCLK_PTR));
1171        if (!ps[0] || !ps[1])
1172                return 1;
1173
1174        if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT))
1175                return 1;
1176        atom_execute_table(ctx, ATOM_CMD_INIT, ps);
1177
1178        return 0;
1179}
1180
1181void atom_destroy(struct atom_context *ctx)
1182{
1183        if (ctx->iio)
1184                kfree(ctx->iio);
1185        kfree(ctx);
1186}
1187
1188void atom_parse_data_header(struct atom_context *ctx, int index,
1189                            uint16_t * size, uint8_t * frev, uint8_t * crev,
1190                            uint16_t * data_start)
1191{
1192        int offset = index * 2 + 4;
1193        int idx = CU16(ctx->data_table + offset);
1194
1195        if (size)
1196                *size = CU16(idx);
1197        if (frev)
1198                *frev = CU8(idx + 2);
1199        if (crev)
1200                *crev = CU8(idx + 3);
1201        *data_start = idx;
1202        return;
1203}
1204
1205void atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev,
1206                           uint8_t * crev)
1207{
1208        int offset = index * 2 + 4;
1209        int idx = CU16(ctx->cmd_table + offset);
1210
1211        if (frev)
1212                *frev = CU8(idx + 2);
1213        if (crev)
1214                *crev = CU8(idx + 3);
1215        return;
1216}
1217
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.