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