linux/drivers/staging/sm750fb/ddk750_chip.c
<<
>>
Prefs
   1#include <linux/kernel.h>
   2#include <linux/sizes.h>
   3
   4#include "ddk750_help.h"
   5#include "ddk750_reg.h"
   6#include "ddk750_chip.h"
   7#include "ddk750_power.h"
   8
   9/* n / d + 1 / 2 = (2n + d) / 2d */
  10#define roundedDiv(num, denom)  ((2 * (num) + (denom)) / (2 * (denom)))
  11#define MHz(x) ((x) * 1000000)
  12
  13logical_chip_type_t getChipType(void)
  14{
  15        unsigned short physicalID;
  16        char physicalRev;
  17        logical_chip_type_t chip;
  18
  19        physicalID = devId750; /* either 0x718 or 0x750 */
  20        physicalRev = revId750;
  21
  22        if (physicalID == 0x718)
  23                chip = SM718;
  24        else if (physicalID == 0x750) {
  25                chip = SM750;
  26                /* SM750 and SM750LE are different in their revision ID only. */
  27                if (physicalRev == SM750LE_REVISION_ID)
  28                        chip = SM750LE;
  29        } else
  30                chip = SM_UNKNOWN;
  31
  32        return chip;
  33}
  34
  35static unsigned int get_mxclk_freq(void)
  36{
  37        unsigned int pll_reg;
  38        unsigned int M, N, OD, POD;
  39
  40        if (getChipType() == SM750LE)
  41                return MHz(130);
  42
  43        pll_reg = PEEK32(MXCLK_PLL_CTRL);
  44        M = (pll_reg & PLL_CTRL_M_MASK) >> PLL_CTRL_M_SHIFT;
  45        N = (pll_reg & PLL_CTRL_N_MASK) >> PLL_CTRL_M_SHIFT;
  46        OD = (pll_reg & PLL_CTRL_OD_MASK) >> PLL_CTRL_OD_SHIFT;
  47        POD = (pll_reg & PLL_CTRL_POD_MASK) >> PLL_CTRL_POD_SHIFT;
  48
  49        return DEFAULT_INPUT_CLOCK * M / N / (1 << OD) / (1 << POD);
  50}
  51
  52/*
  53 * This function set up the main chip clock.
  54 *
  55 * Input: Frequency to be set.
  56 */
  57static void setChipClock(unsigned int frequency)
  58{
  59        pll_value_t pll;
  60        unsigned int ulActualMxClk;
  61
  62        /* Cheok_0509: For SM750LE, the chip clock is fixed. Nothing to set. */
  63        if (getChipType() == SM750LE)
  64                return;
  65
  66        if (frequency) {
  67                /*
  68                * Set up PLL, a structure to hold the value to be set in clocks.
  69                */
  70                pll.inputFreq = DEFAULT_INPUT_CLOCK; /* Defined in CLOCK.H */
  71                pll.clockType = MXCLK_PLL;
  72
  73                /*
  74                * Call calcPllValue() to fill up the other fields for PLL structure.
  75                * Sometime, the chip cannot set up the exact clock required by User.
  76                * Return value from calcPllValue() gives the actual possible clock.
  77                */
  78                ulActualMxClk = calcPllValue(frequency, &pll);
  79
  80                /* Master Clock Control: MXCLK_PLL */
  81                POKE32(MXCLK_PLL_CTRL, formatPllReg(&pll));
  82        }
  83}
  84
  85static void setMemoryClock(unsigned int frequency)
  86{
  87        unsigned int reg, divisor;
  88
  89        /* Cheok_0509: For SM750LE, the memory clock is fixed. Nothing to set. */
  90        if (getChipType() == SM750LE)
  91                return;
  92
  93        if (frequency) {
  94                /* Set the frequency to the maximum frequency that the DDR Memory can take
  95                which is 336MHz. */
  96                if (frequency > MHz(336))
  97                        frequency = MHz(336);
  98
  99                /* Calculate the divisor */
 100                divisor = roundedDiv(get_mxclk_freq(), frequency);
 101
 102                /* Set the corresponding divisor in the register. */
 103                reg = PEEK32(CURRENT_GATE) & ~CURRENT_GATE_M2XCLK_MASK;
 104                switch (divisor) {
 105                default:
 106                case 1:
 107                        reg |= CURRENT_GATE_M2XCLK_DIV_1;
 108                        break;
 109                case 2:
 110                        reg |= CURRENT_GATE_M2XCLK_DIV_2;
 111                        break;
 112                case 3:
 113                        reg |= CURRENT_GATE_M2XCLK_DIV_3;
 114                        break;
 115                case 4:
 116                        reg |= CURRENT_GATE_M2XCLK_DIV_4;
 117                        break;
 118                }
 119
 120                setCurrentGate(reg);
 121        }
 122}
 123
 124/*
 125 * This function set up the master clock (MCLK).
 126 *
 127 * Input: Frequency to be set.
 128 *
 129 * NOTE:
 130 *      The maximum frequency the engine can run is 168MHz.
 131 */
 132static void setMasterClock(unsigned int frequency)
 133{
 134        unsigned int reg, divisor;
 135
 136        /* Cheok_0509: For SM750LE, the memory clock is fixed. Nothing to set. */
 137        if (getChipType() == SM750LE)
 138                return;
 139
 140        if (frequency) {
 141                /* Set the frequency to the maximum frequency that the SM750 engine can
 142                run, which is about 190 MHz. */
 143                if (frequency > MHz(190))
 144                        frequency = MHz(190);
 145
 146                /* Calculate the divisor */
 147                divisor = roundedDiv(get_mxclk_freq(), frequency);
 148
 149                /* Set the corresponding divisor in the register. */
 150                reg = PEEK32(CURRENT_GATE) & ~CURRENT_GATE_MCLK_MASK;
 151                switch (divisor) {
 152                default:
 153                case 3:
 154                        reg |= CURRENT_GATE_MCLK_DIV_3;
 155                        break;
 156                case 4:
 157                        reg |= CURRENT_GATE_MCLK_DIV_4;
 158                        break;
 159                case 6:
 160                        reg |= CURRENT_GATE_MCLK_DIV_6;
 161                        break;
 162                case 8:
 163                        reg |= CURRENT_GATE_MCLK_DIV_8;
 164                        break;
 165                }
 166
 167                setCurrentGate(reg);
 168                }
 169}
 170
 171unsigned int ddk750_getVMSize(void)
 172{
 173        unsigned int reg;
 174        unsigned int data;
 175
 176        /* sm750le only use 64 mb memory*/
 177        if (getChipType() == SM750LE)
 178                return SZ_64M;
 179
 180        /* for 750,always use power mode0*/
 181        reg = PEEK32(MODE0_GATE);
 182        reg |= MODE0_GATE_GPIO;
 183        POKE32(MODE0_GATE, reg);
 184
 185        /* get frame buffer size from GPIO */
 186        reg = PEEK32(MISC_CTRL) & MISC_CTRL_LOCALMEM_SIZE_MASK;
 187        switch (reg) {
 188        case MISC_CTRL_LOCALMEM_SIZE_8M:
 189                data = SZ_8M;  break; /* 8  Mega byte */
 190        case MISC_CTRL_LOCALMEM_SIZE_16M:
 191                data = SZ_16M; break; /* 16 Mega byte */
 192        case MISC_CTRL_LOCALMEM_SIZE_32M:
 193                data = SZ_32M; break; /* 32 Mega byte */
 194        case MISC_CTRL_LOCALMEM_SIZE_64M:
 195                data = SZ_64M; break; /* 64 Mega byte */
 196        default:
 197                data = 0;
 198                break;
 199        }
 200        return data;
 201}
 202
 203int ddk750_initHw(initchip_param_t *pInitParam)
 204{
 205        unsigned int reg;
 206
 207        if (pInitParam->powerMode != 0)
 208                pInitParam->powerMode = 0;
 209        setPowerMode(pInitParam->powerMode);
 210
 211        /* Enable display power gate & LOCALMEM power gate*/
 212        reg = PEEK32(CURRENT_GATE);
 213        reg |= (CURRENT_GATE_DISPLAY | CURRENT_GATE_LOCALMEM);
 214        setCurrentGate(reg);
 215
 216        if (getChipType() != SM750LE) {
 217                /*      set panel pll and graphic mode via mmio_88 */
 218                reg = PEEK32(VGA_CONFIGURATION);
 219                reg |= (VGA_CONFIGURATION_PLL | VGA_CONFIGURATION_MODE);
 220                POKE32(VGA_CONFIGURATION, reg);
 221        } else {
 222#if defined(__i386__) || defined(__x86_64__)
 223                /* set graphic mode via IO method */
 224                outb_p(0x88, 0x3d4);
 225                outb_p(0x06, 0x3d5);
 226#endif
 227        }
 228
 229        /* Set the Main Chip Clock */
 230        setChipClock(MHz((unsigned int)pInitParam->chipClock));
 231
 232        /* Set up memory clock. */
 233        setMemoryClock(MHz(pInitParam->memClock));
 234
 235        /* Set up master clock */
 236        setMasterClock(MHz(pInitParam->masterClock));
 237
 238
 239        /* Reset the memory controller. If the memory controller is not reset in SM750,
 240           the system might hang when sw accesses the memory.
 241           The memory should be resetted after changing the MXCLK.
 242         */
 243        if (pInitParam->resetMemory == 1) {
 244                reg = PEEK32(MISC_CTRL);
 245                reg &= ~MISC_CTRL_LOCALMEM_RESET;
 246                POKE32(MISC_CTRL, reg);
 247
 248                reg |= MISC_CTRL_LOCALMEM_RESET;
 249                POKE32(MISC_CTRL, reg);
 250        }
 251
 252        if (pInitParam->setAllEngOff == 1) {
 253                enable2DEngine(0);
 254
 255                /* Disable Overlay, if a former application left it on */
 256                reg = PEEK32(VIDEO_DISPLAY_CTRL);
 257                reg &= ~DISPLAY_CTRL_PLANE;
 258                POKE32(VIDEO_DISPLAY_CTRL, reg);
 259
 260                /* Disable video alpha, if a former application left it on */
 261                reg = PEEK32(VIDEO_ALPHA_DISPLAY_CTRL);
 262                reg &= ~DISPLAY_CTRL_PLANE;
 263                POKE32(VIDEO_ALPHA_DISPLAY_CTRL, reg);
 264
 265                /* Disable alpha plane, if a former application left it on */
 266                reg = PEEK32(ALPHA_DISPLAY_CTRL);
 267                reg &= ~DISPLAY_CTRL_PLANE;
 268                POKE32(ALPHA_DISPLAY_CTRL, reg);
 269
 270                /* Disable DMA Channel, if a former application left it on */
 271                reg = PEEK32(DMA_ABORT_INTERRUPT);
 272                reg |= DMA_ABORT_INTERRUPT_ABORT_1;
 273                POKE32(DMA_ABORT_INTERRUPT, reg);
 274
 275                /* Disable DMA Power, if a former application left it on */
 276                enableDMA(0);
 277        }
 278
 279        /* We can add more initialization as needed. */
 280
 281        return 0;
 282}
 283
 284/*
 285        monk liu @ 4/6/2011:
 286                   re-write the calculatePLL function of ddk750.
 287                   the original version function does not use some mathematics tricks and shortcut
 288                   when it doing the calculation of the best N,M,D combination
 289                   I think this version gives a little upgrade in speed
 290
 291        750 pll clock formular:
 292        Request Clock = (Input Clock * M )/(N * X)
 293
 294        Input Clock = 14318181 hz
 295        X = 2 power D
 296        D ={0,1,2,3,4,5,6}
 297        M = {1,...,255}
 298        N = {2,...,15}
 299*/
 300unsigned int calcPllValue(unsigned int request_orig, pll_value_t *pll)
 301{
 302        /* as sm750 register definition, N located in 2,15 and M located in 1,255       */
 303        int N, M, X, d;
 304        int mini_diff;
 305        unsigned int RN, quo, rem, fl_quo;
 306        unsigned int input, request;
 307        unsigned int tmpClock, ret;
 308        const int max_OD = 3;
 309        int max_d;
 310
 311        if (getChipType() == SM750LE) {
 312                /* SM750LE don't have prgrammable PLL and M/N values to work on.
 313                Just return the requested clock. */
 314                return request_orig;
 315        }
 316
 317        ret = 0;
 318        mini_diff = ~0;
 319        request = request_orig / 1000;
 320        input = pll->inputFreq / 1000;
 321
 322        /* for MXCLK register , no POD provided, so need be treated differently */
 323        if (pll->clockType == MXCLK_PLL)
 324                max_d = 3;
 325
 326        for (N = 15; N > 1; N--) {
 327                /* RN will not exceed maximum long if @request <= 285 MHZ (for 32bit cpu) */
 328                RN = N * request;
 329                quo = RN / input;
 330                rem = RN % input;/* rem always small than 14318181 */
 331                fl_quo = (rem * 10000 / input);
 332
 333                for (d = max_d; d >= 0; d--) {
 334                        X = (1 << d);
 335                        M = quo * X;
 336                        M += fl_quo * X / 10000;
 337                        /* round step */
 338                        M += (fl_quo * X % 10000) > 5000 ? 1 : 0;
 339                        if (M < 256 && M > 0) {
 340                                unsigned int diff;
 341
 342                                tmpClock = pll->inputFreq * M / N / X;
 343                                diff = abs(tmpClock - request_orig);
 344                                if (diff < mini_diff) {
 345                                        pll->M = M;
 346                                        pll->N = N;
 347                                        pll->POD = 0;
 348                                        if (d > max_OD)
 349                                                pll->POD = d - max_OD;
 350                                        pll->OD = d - pll->POD;
 351                                        mini_diff = diff;
 352                                        ret = tmpClock;
 353                                }
 354                        }
 355                }
 356        }
 357        return ret;
 358}
 359
 360unsigned int formatPllReg(pll_value_t *pPLL)
 361{
 362#ifndef VALIDATION_CHIP
 363        unsigned int POD = pPLL->POD;
 364#endif
 365        unsigned int OD = pPLL->OD;
 366        unsigned int M = pPLL->M;
 367        unsigned int N = pPLL->N;
 368        unsigned int reg = 0;
 369
 370        /*
 371         * Note that all PLL's have the same format. Here, we just use
 372         * Panel PLL parameter to work out the bit fields in the
 373         * register. On returning a 32 bit number, the value can be
 374         * applied to any PLL in the calling function.
 375         */
 376        reg = PLL_CTRL_POWER |
 377#ifndef VALIDATION_CHIP
 378                ((POD << PLL_CTRL_POD_SHIFT) & PLL_CTRL_POD_MASK) |
 379#endif
 380                ((OD << PLL_CTRL_OD_SHIFT) & PLL_CTRL_OD_MASK) |
 381                ((N << PLL_CTRL_N_SHIFT) & PLL_CTRL_N_MASK) |
 382                ((M << PLL_CTRL_M_SHIFT) & PLL_CTRL_M_MASK);
 383
 384        return reg;
 385}
 386
 387
 388