linux/drivers/staging/sm750fb/sm750_hw.c
<<
>>
Prefs
   1#include <linux/module.h>
   2#include <linux/kernel.h>
   3#include <linux/errno.h>
   4#include <linux/string.h>
   5#include <linux/mm.h>
   6#include <linux/slab.h>
   7#include <linux/delay.h>
   8#include <linux/fb.h>
   9#include <linux/ioport.h>
  10#include <linux/init.h>
  11#include <linux/pci.h>
  12#include <linux/vmalloc.h>
  13#include <linux/pagemap.h>
  14#include <linux/console.h>
  15#ifdef CONFIG_MTRR
  16#include <asm/mtrr.h>
  17#endif
  18#include <linux/platform_device.h>
  19#include <linux/screen_info.h>
  20#include <linux/sizes.h>
  21
  22#include "sm750.h"
  23#include "ddk750.h"
  24#include "sm750_accel.h"
  25
  26int hw_sm750_map(struct sm750_dev *sm750_dev, struct pci_dev *pdev)
  27{
  28        int ret;
  29
  30        ret = 0;
  31
  32        sm750_dev->vidreg_start  = pci_resource_start(pdev, 1);
  33        sm750_dev->vidreg_size = SZ_2M;
  34
  35        pr_info("mmio phyAddr = %lx\n", sm750_dev->vidreg_start);
  36
  37        /* reserve the vidreg space of smi adaptor
  38         * if you do this, you need to add release region code
  39         * in lynxfb_remove, or memory will not be mapped again
  40         * successfully
  41         */
  42        ret = pci_request_region(pdev, 1, "sm750fb");
  43        if (ret) {
  44                pr_err("Can not request PCI regions.\n");
  45                goto exit;
  46        }
  47
  48        /* now map mmio and vidmem */
  49        sm750_dev->pvReg = ioremap_nocache(sm750_dev->vidreg_start,
  50                                           sm750_dev->vidreg_size);
  51        if (!sm750_dev->pvReg) {
  52                pr_err("mmio failed\n");
  53                ret = -EFAULT;
  54                goto exit;
  55        } else {
  56                pr_info("mmio virtual addr = %p\n", sm750_dev->pvReg);
  57        }
  58
  59        sm750_dev->accel.dprBase = sm750_dev->pvReg + DE_BASE_ADDR_TYPE1;
  60        sm750_dev->accel.dpPortBase = sm750_dev->pvReg + DE_PORT_ADDR_TYPE1;
  61
  62        ddk750_set_mmio(sm750_dev->pvReg, sm750_dev->devid, sm750_dev->revid);
  63
  64        sm750_dev->vidmem_start = pci_resource_start(pdev, 0);
  65        /* don't use pdev_resource[x].end - resource[x].start to
  66         * calculate the resource size, it's only the maximum available
  67         * size but not the actual size, using
  68         * @ddk750_getVMSize function can be safe.
  69         */
  70        sm750_dev->vidmem_size = ddk750_getVMSize();
  71        pr_info("video memory phyAddr = %lx, size = %u bytes\n",
  72                sm750_dev->vidmem_start, sm750_dev->vidmem_size);
  73
  74        /* reserve the vidmem space of smi adaptor */
  75        sm750_dev->pvMem = ioremap_wc(sm750_dev->vidmem_start,
  76                                      sm750_dev->vidmem_size);
  77        if (!sm750_dev->pvMem) {
  78                pr_err("Map video memory failed\n");
  79                ret = -EFAULT;
  80                goto exit;
  81        } else {
  82                pr_info("video memory vaddr = %p\n", sm750_dev->pvMem);
  83        }
  84exit:
  85        return ret;
  86}
  87
  88int hw_sm750_inithw(struct sm750_dev *sm750_dev, struct pci_dev *pdev)
  89{
  90        struct init_status *parm;
  91
  92        parm = &sm750_dev->initParm;
  93        if (parm->chip_clk == 0)
  94                parm->chip_clk = (sm750_get_chip_type() == SM750LE) ?
  95                                                DEFAULT_SM750LE_CHIP_CLOCK :
  96                                                DEFAULT_SM750_CHIP_CLOCK;
  97
  98        if (parm->mem_clk == 0)
  99                parm->mem_clk = parm->chip_clk;
 100        if (parm->master_clk == 0)
 101                parm->master_clk = parm->chip_clk / 3;
 102
 103        ddk750_initHw((initchip_param_t *)&sm750_dev->initParm);
 104        /* for sm718, open pci burst */
 105        if (sm750_dev->devid == 0x718) {
 106                POKE32(SYSTEM_CTRL,
 107                       PEEK32(SYSTEM_CTRL) | SYSTEM_CTRL_PCI_BURST);
 108        }
 109
 110        if (sm750_get_chip_type() != SM750LE) {
 111                unsigned int val;
 112                /* does user need CRT? */
 113                if (sm750_dev->nocrt) {
 114                        POKE32(MISC_CTRL,
 115                               PEEK32(MISC_CTRL) | MISC_CTRL_DAC_POWER_OFF);
 116                        /* shut off dpms */
 117                        val = PEEK32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
 118                        val |= SYSTEM_CTRL_DPMS_VPHN;
 119                        POKE32(SYSTEM_CTRL, val);
 120                } else {
 121                        POKE32(MISC_CTRL,
 122                               PEEK32(MISC_CTRL) & ~MISC_CTRL_DAC_POWER_OFF);
 123                        /* turn on dpms */
 124                        val = PEEK32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
 125                        val |= SYSTEM_CTRL_DPMS_VPHP;
 126                        POKE32(SYSTEM_CTRL, val);
 127                }
 128
 129                val = PEEK32(PANEL_DISPLAY_CTRL) &
 130                        ~(PANEL_DISPLAY_CTRL_DUAL_DISPLAY |
 131                          PANEL_DISPLAY_CTRL_DOUBLE_PIXEL);
 132                switch (sm750_dev->pnltype) {
 133                case sm750_24TFT:
 134                        break;
 135                case sm750_doubleTFT:
 136                        val |= PANEL_DISPLAY_CTRL_DOUBLE_PIXEL;
 137                        break;
 138                case sm750_dualTFT:
 139                        val |= PANEL_DISPLAY_CTRL_DUAL_DISPLAY;
 140                        break;
 141                }
 142                POKE32(PANEL_DISPLAY_CTRL, val);
 143        } else {
 144                /* for 750LE, no DVI chip initialization
 145                 * makes Monitor no signal
 146                 *
 147                 * Set up GPIO for software I2C to program DVI chip in the
 148                 * Xilinx SP605 board, in order to have video signal.
 149                 */
 150                sm750_sw_i2c_init(0, 1);
 151
 152                /* Customer may NOT use CH7301 DVI chip, which has to be
 153                 * initialized differently.
 154                 */
 155                if (sm750_sw_i2c_read_reg(0xec, 0x4a) == 0x95) {
 156                /* The following register values for CH7301 are from
 157                 * Chrontel app note and our experiment.
 158                 */
 159                        pr_info("yes,CH7301 DVI chip found\n");
 160                        sm750_sw_i2c_write_reg(0xec, 0x1d, 0x16);
 161                        sm750_sw_i2c_write_reg(0xec, 0x21, 0x9);
 162                        sm750_sw_i2c_write_reg(0xec, 0x49, 0xC0);
 163                        pr_info("okay,CH7301 DVI chip setup done\n");
 164                }
 165        }
 166
 167        /* init 2d engine */
 168        if (!sm750_dev->accel_off)
 169                hw_sm750_initAccel(sm750_dev);
 170
 171        return 0;
 172}
 173
 174int hw_sm750_output_setMode(struct lynxfb_output *output,
 175                            struct fb_var_screeninfo *var,
 176                            struct fb_fix_screeninfo *fix)
 177{
 178        int ret;
 179        disp_output_t dispSet;
 180        int channel;
 181
 182        ret = 0;
 183        dispSet = 0;
 184        channel = *output->channel;
 185
 186        if (sm750_get_chip_type() != SM750LE) {
 187                if (channel == sm750_primary) {
 188                        pr_info("primary channel\n");
 189                        if (output->paths & sm750_panel)
 190                                dispSet |= do_LCD1_PRI;
 191                        if (output->paths & sm750_crt)
 192                                dispSet |= do_CRT_PRI;
 193
 194                } else {
 195                        pr_info("secondary channel\n");
 196                        if (output->paths & sm750_panel)
 197                                dispSet |= do_LCD1_SEC;
 198                        if (output->paths & sm750_crt)
 199                                dispSet |= do_CRT_SEC;
 200                }
 201                ddk750_setLogicalDispOut(dispSet);
 202        } else {
 203                /* just open DISPLAY_CONTROL_750LE register bit 3:0 */
 204                u32 reg;
 205
 206                reg = PEEK32(DISPLAY_CONTROL_750LE);
 207                reg |= 0xf;
 208                POKE32(DISPLAY_CONTROL_750LE, reg);
 209        }
 210
 211        pr_info("ddk setlogicdispout done\n");
 212        return ret;
 213}
 214
 215int hw_sm750_crtc_checkMode(struct lynxfb_crtc *crtc,
 216                            struct fb_var_screeninfo *var)
 217{
 218        struct sm750_dev *sm750_dev;
 219        struct lynxfb_par *par = container_of(crtc, struct lynxfb_par, crtc);
 220
 221        sm750_dev = par->dev;
 222
 223        switch (var->bits_per_pixel) {
 224        case 8:
 225        case 16:
 226                break;
 227        case 32:
 228                if (sm750_dev->revid == SM750LE_REVISION_ID) {
 229                        pr_debug("750le do not support 32bpp\n");
 230                        return -EINVAL;
 231                }
 232                break;
 233        default:
 234                return -EINVAL;
 235        }
 236
 237        return 0;
 238}
 239
 240/* set the controller's mode for @crtc charged with @var and @fix parameters */
 241int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc,
 242                          struct fb_var_screeninfo *var,
 243                          struct fb_fix_screeninfo *fix)
 244{
 245        int ret, fmt;
 246        u32 reg;
 247        mode_parameter_t modparm;
 248        clock_type_t clock;
 249        struct sm750_dev *sm750_dev;
 250        struct lynxfb_par *par;
 251
 252        ret = 0;
 253        par = container_of(crtc, struct lynxfb_par, crtc);
 254        sm750_dev = par->dev;
 255
 256        if (!sm750_dev->accel_off) {
 257                /* set 2d engine pixel format according to mode bpp */
 258                switch (var->bits_per_pixel) {
 259                case 8:
 260                        fmt = 0;
 261                        break;
 262                case 16:
 263                        fmt = 1;
 264                        break;
 265                case 32:
 266                default:
 267                        fmt = 2;
 268                        break;
 269                }
 270                hw_set2dformat(&sm750_dev->accel, fmt);
 271        }
 272
 273        /* set timing */
 274        modparm.pixel_clock = ps_to_hz(var->pixclock);
 275        modparm.vertical_sync_polarity = (var->sync & FB_SYNC_HOR_HIGH_ACT)
 276                                         ? POS : NEG;
 277        modparm.horizontal_sync_polarity = (var->sync & FB_SYNC_VERT_HIGH_ACT)
 278                                           ? POS : NEG;
 279        modparm.clock_phase_polarity = (var->sync & FB_SYNC_COMP_HIGH_ACT)
 280                                       ? POS : NEG;
 281        modparm.horizontal_display_end = var->xres;
 282        modparm.horizontal_sync_width = var->hsync_len;
 283        modparm.horizontal_sync_start = var->xres + var->right_margin;
 284        modparm.horizontal_total = var->xres + var->left_margin +
 285                                   var->right_margin + var->hsync_len;
 286        modparm.vertical_display_end = var->yres;
 287        modparm.vertical_sync_height = var->vsync_len;
 288        modparm.vertical_sync_start = var->yres + var->lower_margin;
 289        modparm.vertical_total = var->yres + var->upper_margin +
 290                                 var->lower_margin + var->vsync_len;
 291
 292        /* choose pll */
 293        if (crtc->channel != sm750_secondary)
 294                clock = PRIMARY_PLL;
 295        else
 296                clock = SECONDARY_PLL;
 297
 298        pr_debug("Request pixel clock = %lu\n", modparm.pixel_clock);
 299        ret = ddk750_setModeTiming(&modparm, clock);
 300        if (ret) {
 301                pr_err("Set mode timing failed\n");
 302                goto exit;
 303        }
 304
 305        if (crtc->channel != sm750_secondary) {
 306                /* set pitch, offset, width, start address, etc... */
 307                POKE32(PANEL_FB_ADDRESS,
 308                       crtc->oScreen & PANEL_FB_ADDRESS_ADDRESS_MASK);
 309
 310                reg = var->xres * (var->bits_per_pixel >> 3);
 311                /* crtc->channel is not equal to par->index on numeric,
 312                 * be aware of that
 313                 */
 314                reg = ALIGN(reg, crtc->line_pad);
 315                reg = (reg << PANEL_FB_WIDTH_WIDTH_SHIFT) &
 316                       PANEL_FB_WIDTH_WIDTH_MASK;
 317                reg |= (fix->line_length & PANEL_FB_WIDTH_OFFSET_MASK);
 318                POKE32(PANEL_FB_WIDTH, reg);
 319
 320                reg = ((var->xres - 1) << PANEL_WINDOW_WIDTH_WIDTH_SHIFT) &
 321                       PANEL_WINDOW_WIDTH_WIDTH_MASK;
 322                reg |= (var->xoffset & PANEL_WINDOW_WIDTH_X_MASK);
 323                POKE32(PANEL_WINDOW_WIDTH, reg);
 324
 325                reg = (var->yres_virtual - 1) <<
 326                      PANEL_WINDOW_HEIGHT_HEIGHT_SHIFT;
 327                reg &= PANEL_WINDOW_HEIGHT_HEIGHT_MASK;
 328                reg |= (var->yoffset & PANEL_WINDOW_HEIGHT_Y_MASK);
 329                POKE32(PANEL_WINDOW_HEIGHT, reg);
 330
 331                POKE32(PANEL_PLANE_TL, 0);
 332
 333                reg = ((var->yres - 1) << PANEL_PLANE_BR_BOTTOM_SHIFT) &
 334                       PANEL_PLANE_BR_BOTTOM_MASK;
 335                reg |= ((var->xres - 1) & PANEL_PLANE_BR_RIGHT_MASK);
 336                POKE32(PANEL_PLANE_BR, reg);
 337
 338                /* set pixel format */
 339                reg = PEEK32(PANEL_DISPLAY_CTRL);
 340                POKE32(PANEL_DISPLAY_CTRL, reg | (var->bits_per_pixel >> 4));
 341        } else {
 342                /* not implemented now */
 343                POKE32(CRT_FB_ADDRESS, crtc->oScreen);
 344                reg = var->xres * (var->bits_per_pixel >> 3);
 345                /* crtc->channel is not equal to par->index on numeric,
 346                 * be aware of that
 347                 */
 348                reg = ALIGN(reg, crtc->line_pad) << CRT_FB_WIDTH_WIDTH_SHIFT;
 349                reg &= CRT_FB_WIDTH_WIDTH_MASK;
 350                reg |= (fix->line_length & CRT_FB_WIDTH_OFFSET_MASK);
 351                POKE32(CRT_FB_WIDTH, reg);
 352
 353                /* SET PIXEL FORMAT */
 354                reg = PEEK32(CRT_DISPLAY_CTRL);
 355                reg |= ((var->bits_per_pixel >> 4) &
 356                        CRT_DISPLAY_CTRL_FORMAT_MASK);
 357                POKE32(CRT_DISPLAY_CTRL, reg);
 358        }
 359
 360exit:
 361        return ret;
 362}
 363
 364int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index,
 365                       ushort red, ushort green, ushort blue)
 366{
 367        static unsigned int add[] = {PANEL_PALETTE_RAM, CRT_PALETTE_RAM};
 368
 369        POKE32(add[crtc->channel] + index * 4,
 370               (red << 16) | (green << 8) | blue);
 371        return 0;
 372}
 373
 374int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank)
 375{
 376        int dpms, crtdb;
 377
 378        switch (blank) {
 379        case FB_BLANK_UNBLANK:
 380                dpms = CRT_DISPLAY_CTRL_DPMS_0;
 381                crtdb = 0;
 382                break;
 383        case FB_BLANK_NORMAL:
 384                dpms = CRT_DISPLAY_CTRL_DPMS_0;
 385                crtdb = CRT_DISPLAY_CTRL_BLANK;
 386                break;
 387        case FB_BLANK_VSYNC_SUSPEND:
 388                dpms = CRT_DISPLAY_CTRL_DPMS_2;
 389                crtdb = CRT_DISPLAY_CTRL_BLANK;
 390                break;
 391        case FB_BLANK_HSYNC_SUSPEND:
 392                dpms = CRT_DISPLAY_CTRL_DPMS_1;
 393                crtdb = CRT_DISPLAY_CTRL_BLANK;
 394                break;
 395        case FB_BLANK_POWERDOWN:
 396                dpms = CRT_DISPLAY_CTRL_DPMS_3;
 397                crtdb = CRT_DISPLAY_CTRL_BLANK;
 398                break;
 399        default:
 400                return -EINVAL;
 401        }
 402
 403        if (output->paths & sm750_crt) {
 404                unsigned int val;
 405
 406                val = PEEK32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_DPMS_MASK;
 407                POKE32(CRT_DISPLAY_CTRL, val | dpms);
 408
 409                val = PEEK32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_BLANK;
 410                POKE32(CRT_DISPLAY_CTRL, val | crtdb);
 411        }
 412        return 0;
 413}
 414
 415int hw_sm750_setBLANK(struct lynxfb_output *output, int blank)
 416{
 417        unsigned int dpms, pps, crtdb;
 418
 419        dpms = 0;
 420        pps = 0;
 421        crtdb = 0;
 422
 423        switch (blank) {
 424        case FB_BLANK_UNBLANK:
 425                pr_debug("flag = FB_BLANK_UNBLANK\n");
 426                dpms = SYSTEM_CTRL_DPMS_VPHP;
 427                pps = PANEL_DISPLAY_CTRL_DATA;
 428                break;
 429        case FB_BLANK_NORMAL:
 430                pr_debug("flag = FB_BLANK_NORMAL\n");
 431                dpms = SYSTEM_CTRL_DPMS_VPHP;
 432                crtdb = CRT_DISPLAY_CTRL_BLANK;
 433                break;
 434        case FB_BLANK_VSYNC_SUSPEND:
 435                dpms = SYSTEM_CTRL_DPMS_VNHP;
 436                crtdb = CRT_DISPLAY_CTRL_BLANK;
 437                break;
 438        case FB_BLANK_HSYNC_SUSPEND:
 439                dpms = SYSTEM_CTRL_DPMS_VPHN;
 440                crtdb = CRT_DISPLAY_CTRL_BLANK;
 441                break;
 442        case FB_BLANK_POWERDOWN:
 443                dpms = SYSTEM_CTRL_DPMS_VNHN;
 444                crtdb = CRT_DISPLAY_CTRL_BLANK;
 445                break;
 446        }
 447
 448        if (output->paths & sm750_crt) {
 449                unsigned int val = PEEK32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
 450
 451                POKE32(SYSTEM_CTRL, val | dpms);
 452
 453                val = PEEK32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_BLANK;
 454                POKE32(CRT_DISPLAY_CTRL, val | crtdb);
 455        }
 456
 457        if (output->paths & sm750_panel) {
 458                unsigned int val = PEEK32(PANEL_DISPLAY_CTRL);
 459
 460                val &= ~PANEL_DISPLAY_CTRL_DATA;
 461                val |= pps;
 462                POKE32(PANEL_DISPLAY_CTRL, val);
 463        }
 464
 465        return 0;
 466}
 467
 468void hw_sm750_initAccel(struct sm750_dev *sm750_dev)
 469{
 470        u32 reg;
 471
 472        enable2DEngine(1);
 473
 474        if (sm750_get_chip_type() == SM750LE) {
 475                reg = PEEK32(DE_STATE1);
 476                reg |= DE_STATE1_DE_ABORT;
 477                POKE32(DE_STATE1, reg);
 478
 479                reg = PEEK32(DE_STATE1);
 480                reg &= ~DE_STATE1_DE_ABORT;
 481                POKE32(DE_STATE1, reg);
 482
 483        } else {
 484                /* engine reset */
 485                reg = PEEK32(SYSTEM_CTRL);
 486                reg |= SYSTEM_CTRL_DE_ABORT;
 487                POKE32(SYSTEM_CTRL, reg);
 488
 489                reg = PEEK32(SYSTEM_CTRL);
 490                reg &= ~SYSTEM_CTRL_DE_ABORT;
 491                POKE32(SYSTEM_CTRL, reg);
 492        }
 493
 494        /* call 2d init */
 495        sm750_dev->accel.de_init(&sm750_dev->accel);
 496}
 497
 498int hw_sm750le_deWait(void)
 499{
 500        int i = 0x10000000;
 501        unsigned int mask = DE_STATE2_DE_STATUS_BUSY | DE_STATE2_DE_FIFO_EMPTY |
 502                DE_STATE2_DE_MEM_FIFO_EMPTY;
 503
 504        while (i--) {
 505                unsigned int val = PEEK32(DE_STATE2);
 506
 507                if ((val & mask) ==
 508                    (DE_STATE2_DE_FIFO_EMPTY | DE_STATE2_DE_MEM_FIFO_EMPTY))
 509                        return 0;
 510        }
 511        /* timeout error */
 512        return -1;
 513}
 514
 515int hw_sm750_deWait(void)
 516{
 517        int i = 0x10000000;
 518        unsigned int mask = SYSTEM_CTRL_DE_STATUS_BUSY |
 519                SYSTEM_CTRL_DE_FIFO_EMPTY |
 520                SYSTEM_CTRL_DE_MEM_FIFO_EMPTY;
 521
 522        while (i--) {
 523                unsigned int val = PEEK32(SYSTEM_CTRL);
 524
 525                if ((val & mask) ==
 526                    (SYSTEM_CTRL_DE_FIFO_EMPTY | SYSTEM_CTRL_DE_MEM_FIFO_EMPTY))
 527                        return 0;
 528        }
 529        /* timeout error */
 530        return -1;
 531}
 532
 533int hw_sm750_pan_display(struct lynxfb_crtc *crtc,
 534                         const struct fb_var_screeninfo *var,
 535                         const struct fb_info *info)
 536{
 537        u32 total;
 538        /* check params */
 539        if ((var->xoffset + var->xres > var->xres_virtual) ||
 540            (var->yoffset + var->yres > var->yres_virtual)) {
 541                return -EINVAL;
 542        }
 543
 544        total = var->yoffset * info->fix.line_length +
 545                ((var->xoffset * var->bits_per_pixel) >> 3);
 546        total += crtc->oScreen;
 547        if (crtc->channel == sm750_primary) {
 548                POKE32(PANEL_FB_ADDRESS,
 549                       PEEK32(PANEL_FB_ADDRESS) |
 550                       (total & PANEL_FB_ADDRESS_ADDRESS_MASK));
 551        } else {
 552                POKE32(CRT_FB_ADDRESS,
 553                       PEEK32(CRT_FB_ADDRESS) |
 554                       (total & CRT_FB_ADDRESS_ADDRESS_MASK));
 555        }
 556        return 0;
 557}
 558