Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / staging / sm750fb / ddk750_chip.c
diff --git a/kernel/drivers/staging/sm750fb/ddk750_chip.c b/kernel/drivers/staging/sm750fb/ddk750_chip.c
new file mode 100644 (file)
index 0000000..7b28328
--- /dev/null
@@ -0,0 +1,622 @@
+#include "ddk750_help.h"
+#include "ddk750_reg.h"
+#include "ddk750_chip.h"
+#include "ddk750_power.h"
+typedef struct _pllcalparam {
+       unsigned char power;/* d : 0~ 6*/
+       unsigned char pod;
+       unsigned char od;
+       unsigned char value;/* value of  2 power d (2^d) */
+}
+pllcalparam;
+
+
+logical_chip_type_t getChipType(void)
+{
+       unsigned short physicalID;
+       char physicalRev;
+       logical_chip_type_t chip;
+
+       physicalID = devId750;//either 0x718 or 0x750
+       physicalRev = revId750;
+
+       if (physicalID == 0x718)
+               chip = SM718;
+       else if (physicalID == 0x750) {
+               chip = SM750;
+               /* SM750 and SM750LE are different in their revision ID only. */
+               if (physicalRev == SM750LE_REVISION_ID)
+                       chip = SM750LE;
+       } else
+               chip = SM_UNKNOWN;
+
+       return chip;
+}
+
+
+inline unsigned int twoToPowerOfx(unsigned long x)
+{
+       unsigned long i;
+       unsigned long result = 1;
+
+       for (i = 1; i <= x; i++)
+               result *= 2;
+       return result;
+}
+
+inline unsigned int calcPLL(pll_value_t *pPLL)
+{
+       return (pPLL->inputFreq * pPLL->M / pPLL->N / twoToPowerOfx(pPLL->OD) / twoToPowerOfx(pPLL->POD));
+}
+
+unsigned int getPllValue(clock_type_t clockType, pll_value_t *pPLL)
+{
+       unsigned int ulPllReg = 0;
+
+       pPLL->inputFreq = DEFAULT_INPUT_CLOCK;
+       pPLL->clockType = clockType;
+
+       switch (clockType) {
+       case MXCLK_PLL:
+               ulPllReg = PEEK32(MXCLK_PLL_CTRL);
+               break;
+       case PRIMARY_PLL:
+               ulPllReg = PEEK32(PANEL_PLL_CTRL);
+               break;
+       case SECONDARY_PLL:
+               ulPllReg = PEEK32(CRT_PLL_CTRL);
+               break;
+       case VGA0_PLL:
+               ulPllReg = PEEK32(VGA_PLL0_CTRL);
+               break;
+       case VGA1_PLL:
+               ulPllReg = PEEK32(VGA_PLL1_CTRL);
+               break;
+       }
+
+       pPLL->M = FIELD_GET(ulPllReg, PANEL_PLL_CTRL, M);
+       pPLL->N = FIELD_GET(ulPllReg, PANEL_PLL_CTRL, N);
+       pPLL->OD = FIELD_GET(ulPllReg, PANEL_PLL_CTRL, OD);
+       pPLL->POD = FIELD_GET(ulPllReg, PANEL_PLL_CTRL, POD);
+
+       return calcPLL(pPLL);
+}
+
+
+unsigned int getChipClock(void)
+{
+       pll_value_t pll;
+#if 1
+       if (getChipType() == SM750LE)
+               return MHz(130);
+#endif
+
+       return getPllValue(MXCLK_PLL, &pll);
+}
+
+
+/*
+ * This function set up the main chip clock.
+ *
+ * Input: Frequency to be set.
+ */
+void setChipClock(unsigned int frequency)
+{
+       pll_value_t pll;
+       unsigned int ulActualMxClk;
+#if 1
+       /* Cheok_0509: For SM750LE, the chip clock is fixed. Nothing to set. */
+       if (getChipType() == SM750LE)
+               return;
+#endif
+
+       if (frequency) {
+               /*
+               * Set up PLL, a structure to hold the value to be set in clocks.
+               */
+               pll.inputFreq = DEFAULT_INPUT_CLOCK; /* Defined in CLOCK.H */
+               pll.clockType = MXCLK_PLL;
+
+               /*
+               * Call calcPllValue() to fill up the other fields for PLL structure.
+               * Sometime, the chip cannot set up the exact clock required by User.
+               * Return value from calcPllValue() gives the actual possible clock.
+               */
+               ulActualMxClk = calcPllValue(frequency, &pll);
+
+               /* Master Clock Control: MXCLK_PLL */
+               POKE32(MXCLK_PLL_CTRL, formatPllReg(&pll));
+       }
+}
+
+
+
+void setMemoryClock(unsigned int frequency)
+{
+       unsigned int ulReg, divisor;
+ #if 1
+       /* Cheok_0509: For SM750LE, the memory clock is fixed. Nothing to set. */
+       if (getChipType() == SM750LE)
+               return;
+#endif
+       if (frequency) {
+               /* Set the frequency to the maximum frequency that the DDR Memory can take
+               which is 336MHz. */
+               if (frequency > MHz(336))
+                       frequency = MHz(336);
+
+               /* Calculate the divisor */
+               divisor = (unsigned int) roundedDiv(getChipClock(), frequency);
+
+               /* Set the corresponding divisor in the register. */
+               ulReg = PEEK32(CURRENT_GATE);
+               switch (divisor) {
+               default:
+               case 1:
+                       ulReg = FIELD_SET(ulReg, CURRENT_GATE, M2XCLK, DIV_1);
+                       break;
+               case 2:
+                       ulReg = FIELD_SET(ulReg, CURRENT_GATE, M2XCLK, DIV_2);
+                       break;
+               case 3:
+                       ulReg = FIELD_SET(ulReg, CURRENT_GATE, M2XCLK, DIV_3);
+                       break;
+               case 4:
+                       ulReg = FIELD_SET(ulReg, CURRENT_GATE, M2XCLK, DIV_4);
+                       break;
+               }
+
+               setCurrentGate(ulReg);
+       }
+}
+
+
+/*
+ * This function set up the master clock (MCLK).
+ *
+ * Input: Frequency to be set.
+ *
+ * NOTE:
+ *      The maximum frequency the engine can run is 168MHz.
+ */
+void setMasterClock(unsigned int frequency)
+{
+       unsigned int ulReg, divisor;
+#if 1
+       /* Cheok_0509: For SM750LE, the memory clock is fixed. Nothing to set. */
+       if (getChipType() == SM750LE)
+               return;
+#endif
+       if (frequency) {
+               /* Set the frequency to the maximum frequency that the SM750 engine can
+               run, which is about 190 MHz. */
+               if (frequency > MHz(190))
+                       frequency = MHz(190);
+
+               /* Calculate the divisor */
+               divisor = (unsigned int) roundedDiv(getChipClock(), frequency);
+
+               /* Set the corresponding divisor in the register. */
+               ulReg = PEEK32(CURRENT_GATE);
+               switch (divisor) {
+               default:
+               case 3:
+                       ulReg = FIELD_SET(ulReg, CURRENT_GATE, MCLK, DIV_3);
+                       break;
+               case 4:
+                       ulReg = FIELD_SET(ulReg, CURRENT_GATE, MCLK, DIV_4);
+                       break;
+               case 6:
+                       ulReg = FIELD_SET(ulReg, CURRENT_GATE, MCLK, DIV_6);
+                       break;
+               case 8:
+                       ulReg = FIELD_SET(ulReg, CURRENT_GATE, MCLK, DIV_8);
+                       break;
+               }
+
+               setCurrentGate(ulReg);
+               }
+}
+
+
+unsigned int ddk750_getVMSize(void)
+{
+       unsigned int reg;
+       unsigned int data;
+
+       /* sm750le only use 64 mb memory*/
+       if (getChipType() == SM750LE)
+               return MB(64);
+
+       /* for 750,always use power mode0*/
+       reg = PEEK32(MODE0_GATE);
+       reg = FIELD_SET(reg, MODE0_GATE, GPIO, ON);
+       POKE32(MODE0_GATE, reg);
+
+       /* get frame buffer size from GPIO */
+       reg = FIELD_GET(PEEK32(MISC_CTRL), MISC_CTRL, LOCALMEM_SIZE);
+       switch (reg) {
+       case MISC_CTRL_LOCALMEM_SIZE_8M:
+               data = MB(8);  break; /* 8  Mega byte */
+       case MISC_CTRL_LOCALMEM_SIZE_16M:
+               data = MB(16); break; /* 16 Mega byte */
+       case MISC_CTRL_LOCALMEM_SIZE_32M:
+               data = MB(32); break; /* 32 Mega byte */
+       case MISC_CTRL_LOCALMEM_SIZE_64M:
+               data = MB(64); break; /* 64 Mega byte */
+       default:
+               data = 0;
+               break;
+       }
+       return data;
+
+}
+
+int ddk750_initHw(initchip_param_t *pInitParam)
+{
+
+       unsigned int ulReg;
+#if 0
+       //move the code to map regiter function.
+       if (getChipType() == SM718) {
+               /* turn on big endian bit*/
+               ulReg = PEEK32(0x74);
+               /* now consider register definition in a big endian pattern*/
+               POKE32(0x74, ulReg|0x80000000);
+       }
+
+#endif
+
+
+       if (pInitParam->powerMode != 0 )
+               pInitParam->powerMode = 0;
+       setPowerMode(pInitParam->powerMode);
+
+       /* Enable display power gate & LOCALMEM power gate*/
+       ulReg = PEEK32(CURRENT_GATE);
+       ulReg = FIELD_SET(ulReg, CURRENT_GATE, DISPLAY, ON);
+       ulReg = FIELD_SET(ulReg, CURRENT_GATE, LOCALMEM, ON);
+       setCurrentGate(ulReg);
+
+       if (getChipType() != SM750LE) {
+               /*      set panel pll and graphic mode via mmio_88 */
+               ulReg = PEEK32(VGA_CONFIGURATION);
+               ulReg = FIELD_SET(ulReg, VGA_CONFIGURATION, PLL, PANEL);
+               ulReg = FIELD_SET(ulReg, VGA_CONFIGURATION, MODE, GRAPHIC);
+               POKE32(VGA_CONFIGURATION, ulReg);
+       } else {
+#if defined(__i386__) || defined( __x86_64__)
+               /* set graphic mode via IO method */
+               outb_p(0x88, 0x3d4);
+               outb_p(0x06, 0x3d5);
+#endif
+       }
+
+       /* Set the Main Chip Clock */
+       setChipClock(MHz((unsigned int)pInitParam->chipClock));
+
+       /* Set up memory clock. */
+       setMemoryClock(MHz(pInitParam->memClock));
+
+       /* Set up master clock */
+       setMasterClock(MHz(pInitParam->masterClock));
+
+
+       /* Reset the memory controller. If the memory controller is not reset in SM750,
+          the system might hang when sw accesses the memory.
+          The memory should be resetted after changing the MXCLK.
+        */
+       if (pInitParam->resetMemory == 1) {
+               ulReg = PEEK32(MISC_CTRL);
+               ulReg = FIELD_SET(ulReg, MISC_CTRL, LOCALMEM_RESET, RESET);
+               POKE32(MISC_CTRL, ulReg);
+
+               ulReg = FIELD_SET(ulReg, MISC_CTRL, LOCALMEM_RESET, NORMAL);
+               POKE32(MISC_CTRL, ulReg);
+       }
+
+       if (pInitParam->setAllEngOff == 1) {
+               enable2DEngine(0);
+
+               /* Disable Overlay, if a former application left it on */
+               ulReg = PEEK32(VIDEO_DISPLAY_CTRL);
+               ulReg = FIELD_SET(ulReg, VIDEO_DISPLAY_CTRL, PLANE, DISABLE);
+               POKE32(VIDEO_DISPLAY_CTRL, ulReg);
+
+               /* Disable video alpha, if a former application left it on */
+               ulReg = PEEK32(VIDEO_ALPHA_DISPLAY_CTRL);
+               ulReg = FIELD_SET(ulReg, VIDEO_ALPHA_DISPLAY_CTRL, PLANE, DISABLE);
+               POKE32(VIDEO_ALPHA_DISPLAY_CTRL, ulReg);
+
+               /* Disable alpha plane, if a former application left it on */
+               ulReg = PEEK32(ALPHA_DISPLAY_CTRL);
+               ulReg = FIELD_SET(ulReg, ALPHA_DISPLAY_CTRL, PLANE, DISABLE);
+               POKE32(ALPHA_DISPLAY_CTRL, ulReg);
+
+#if 0
+               /* Disable LCD hardware cursor, if a former application left it on */
+               ulReg = PEEK32(PANEL_HWC_ADDRESS);
+               ulReg = FIELD_SET(ulReg, PANEL_HWC_ADDRESS, ENABLE, DISABLE);
+               POKE32(PANEL_HWC_ADDRESS, ulReg);
+
+               /* Disable CRT hardware cursor, if a former application left it on */
+               ulReg = PEEK32(CRT_HWC_ADDRESS);
+               ulReg = FIELD_SET(ulReg, CRT_HWC_ADDRESS, ENABLE, DISABLE);
+               POKE32(CRT_HWC_ADDRESS, ulReg);
+
+               /* Disable ZV Port 0, if a former application left it on */
+               ulReg = PEEK32(ZV0_CAPTURE_CTRL);
+               ulReg = FIELD_SET(ulReg, ZV0_CAPTURE_CTRL, CAP, DISABLE);
+               POKE32(ZV0_CAPTURE_CTRL, ulReg);
+
+               /* Disable ZV Port 1, if a former application left it on */
+               ulReg = PEEK32(ZV1_CAPTURE_CTRL);
+               ulReg = FIELD_SET(ulReg, ZV1_CAPTURE_CTRL, CAP, DISABLE);
+               POKE32(ZV1_CAPTURE_CTRL, ulReg);
+
+               /* Disable ZV Port Power, if a former application left it on */
+               enableZVPort(0);
+               /* Disable DMA Channel, if a former application left it on */
+               ulReg = PEEK32(DMA_ABORT_INTERRUPT);
+               ulReg = FIELD_SET(ulReg, DMA_ABORT_INTERRUPT, ABORT_1, ABORT);
+               POKE32(DMA_ABORT_INTERRUPT, ulReg);
+
+               /* Disable i2c */
+               enableI2C(0);
+#endif
+               /* Disable DMA Channel, if a former application left it on */
+               ulReg = PEEK32(DMA_ABORT_INTERRUPT);
+               ulReg = FIELD_SET(ulReg, DMA_ABORT_INTERRUPT, ABORT_1, ABORT);
+               POKE32(DMA_ABORT_INTERRUPT, ulReg);
+
+               /* Disable DMA Power, if a former application left it on */
+               enableDMA(0);
+       }
+
+       /* We can add more initialization as needed. */
+
+       return 0;
+}
+
+#if 0
+
+unsigned int absDiff(unsigned int a, unsigned int b)
+{
+       if ( a > b )
+               return(a - b);
+       else
+               return(b - a);
+}
+
+#endif
+/*
+       monk liu @ 4/6/2011:
+                  re-write the calculatePLL function of ddk750.
+                  the original version function does not use some mathematics tricks and shortcut
+                  when it doing the calculation of the best N,M,D combination
+                  I think this version gives a little upgrade in speed
+
+       750 pll clock formular:
+       Request Clock = (Input Clock * M )/(N * X)
+
+       Input Clock = 14318181 hz
+       X = 2 power D
+       D ={0,1,2,3,4,5,6}
+       M = {1,...,255}
+       N = {2,...,15}
+*/
+unsigned int calcPllValue(unsigned int request_orig, pll_value_t *pll)
+{
+       /* used for primary and secondary channel pixel clock pll */
+       static pllcalparam xparm_PIXEL[] = {
+               /* 2^0 = 1*/                    {0, 0, 0, 1},
+               /* 2^ 1 =2*/                    {1, 0, 1, 2},
+               /* 2^ 2  = 4*/          {2, 0, 2, 4},
+                                                       {3, 0, 3, 8},
+                                                       {4, 1, 3, 16},
+                                                       {5, 2, 3, 32},
+               /* 2^6 = 64  */         {6, 3, 3, 64},
+                                                       };
+
+       /* used for MXCLK (chip clock) */
+       static pllcalparam xparm_MXCLK[] = {
+               /* 2^0 = 1*/                    {0, 0, 0, 1},
+               /* 2^ 1 =2*/                    {1, 0, 1, 2},
+               /* 2^ 2  = 4*/          {2, 0, 2, 4},
+                                                       {3, 0, 3, 8},
+                                                       };
+
+       /* as sm750 register definition, N located in 2,15 and M located in 1,255       */
+       int N, M, X, d;
+       int xcnt;
+       int miniDiff;
+       unsigned int RN, quo, rem, fl_quo;
+       unsigned int input, request;
+       unsigned int tmpClock, ret;
+       pllcalparam * xparm;
+
+#if 1
+       if (getChipType() == SM750LE) {
+               /* SM750LE don't have prgrammable PLL and M/N values to work on.
+               Just return the requested clock. */
+               return request_orig;
+       }
+#endif
+
+       ret = 0;
+       miniDiff = ~0;
+       request = request_orig / 1000;
+       input = pll->inputFreq / 1000;
+
+       /* for MXCLK register , no POD provided, so need be treated differently */
+
+       if (pll->clockType != MXCLK_PLL) {
+               xparm = &xparm_PIXEL[0];
+               xcnt = sizeof(xparm_PIXEL)/sizeof(xparm_PIXEL[0]);
+       } else {
+               xparm = &xparm_MXCLK[0];
+               xcnt = sizeof(xparm_MXCLK)/sizeof(xparm_MXCLK[0]);
+       }
+
+
+       for (N = 15; N > 1; N--) {
+               /* RN will not exceed maximum long if @request <= 285 MHZ (for 32bit cpu) */
+               RN = N * request;
+               quo = RN / input;
+               rem = RN % input;/* rem always small than 14318181 */
+               fl_quo = (rem * 10000 /input);
+
+               for (d = xcnt - 1; d >= 0; d--) {
+                       X = xparm[d].value;
+                       M = quo*X;
+                       M += fl_quo * X / 10000;
+                       /* round step */
+                       M += (fl_quo*X % 10000)>5000?1:0;
+                       if (M < 256 && M > 0) {
+                               unsigned int diff;
+                               tmpClock = pll->inputFreq *M / N / X;
+                               diff = absDiff(tmpClock, request_orig);
+                               if (diff < miniDiff) {
+                                       pll->M = M;
+                                       pll->N = N;
+                                       pll->OD = xparm[d].od;
+                                       pll->POD = xparm[d].pod;
+                                       miniDiff = diff;
+                                       ret = tmpClock;
+                               }
+                       }
+               }
+       }
+
+       //printk("Finally:  pll->n[%lu],m[%lu],od[%lu],pod[%lu]\n",pll->N,pll->M,pll->OD,pll->POD);
+       return ret;
+}
+
+unsigned int calcPllValue2(
+unsigned int ulRequestClk, /* Required pixel clock in Hz unit */
+pll_value_t *pPLL           /* Structure to hold the value to be set in PLL */
+)
+{
+       unsigned int M, N, OD, POD = 0, diff, pllClk, odPower, podPower;
+       unsigned int bestDiff = 0xffffffff; /* biggest 32 bit unsigned number */
+       unsigned int ret;
+    /* Init PLL structure to know states */
+       pPLL->M = 0;
+       pPLL->N = 0;
+       pPLL->OD = 0;
+       pPLL->POD = 0;
+
+    /* Sanity check: None at the moment */
+
+    /* Convert everything in Khz range in order to avoid calculation overflow */
+       pPLL->inputFreq /= 1000;
+       ulRequestClk /= 1000;
+
+#ifndef VALIDATION_CHIP
+    /* The maximum of post divider is 8. */
+       for (POD = 0; POD <= 3; POD++)
+#endif
+               {
+
+#ifndef VALIDATION_CHIP
+       /* MXCLK_PLL does not have post divider. */
+       if ((POD > 0) && (pPLL->clockType == MXCLK_PLL))
+               break;
+#endif
+
+       /* Work out 2 to the power of POD */
+       podPower = twoToPowerOfx(POD);
+
+       /* OD has only 2 bits [15:14] and its value must between 0 to 3 */
+       for (OD = 0; OD <= 3; OD++) {
+               /* Work out 2 to the power of OD */
+               odPower = twoToPowerOfx(OD);
+
+#ifdef VALIDATION_CHIP
+       if (odPower > 4)
+               podPower = 4;
+       else
+               podPower = odPower;
+#endif
+
+               /* N has 4 bits [11:8] and its value must between 2 and 15.
+               The N == 1 will behave differently --> Result is not correct. */
+       for (N = 2; N <= 15; N++) {
+               /* The formula for PLL is ulRequestClk = inputFreq * M / N / (2^OD)
+               In the following steps, we try to work out a best M value given the others are known.
+               To avoid decimal calculation, we use 1000 as multiplier for up to 3 decimal places of accuracy.
+               */
+               M = ulRequestClk * N * odPower * 1000 / pPLL->inputFreq;
+               M = roundedDiv(M, 1000);
+
+               /* M field has only 8 bits, reject value bigger than 8 bits */
+               if (M < 256) {
+                       /* Calculate the actual clock for a given M & N */
+                       pllClk = pPLL->inputFreq * M / N / odPower / podPower;
+
+                       /* How much are we different from the requirement */
+                       diff = absDiff(pllClk, ulRequestClk);
+
+                       if (diff < bestDiff) {
+                               bestDiff = diff;
+
+                               /* Store M and N values */
+                               pPLL->M  = M;
+                               pPLL->N  = N;
+                               pPLL->OD = OD;
+
+#ifdef VALIDATION_CHIP
+                       if (OD > 2)
+                               POD = 2;
+                       else
+                               POD = OD;
+#endif
+
+                       pPLL->POD = POD;
+                       }
+               }
+       }
+       }
+       }
+
+    /* Restore input frequency from Khz to hz unit */
+//    pPLL->inputFreq *= 1000;
+       ulRequestClk *= 1000;
+       pPLL->inputFreq = DEFAULT_INPUT_CLOCK; /* Default reference clock */
+
+    /* Output debug information */
+       //DDKDEBUGPRINT((DISPLAY_LEVEL, "calcPllValue: Requested Frequency = %d\n", ulRequestClk));
+       //DDKDEBUGPRINT((DISPLAY_LEVEL, "calcPllValue: Input CLK = %dHz, M=%d, N=%d, OD=%d, POD=%d\n", pPLL->inputFreq, pPLL->M, pPLL->N, pPLL->OD, pPLL->POD));
+
+    /* Return actual frequency that the PLL can set */
+       ret = calcPLL(pPLL);
+       return ret;
+}
+
+
+
+
+
+unsigned int formatPllReg(pll_value_t *pPLL)
+{
+       unsigned int ulPllReg = 0;
+
+    /* Note that all PLL's have the same format. Here, we just use Panel PLL parameter
+       to work out the bit fields in the register.
+       On returning a 32 bit number, the value can be applied to any PLL in the calling function.
+    */
+       ulPllReg =
+       FIELD_SET(  0, PANEL_PLL_CTRL, BYPASS, OFF)
+       | FIELD_SET(  0, PANEL_PLL_CTRL, POWER,  ON)
+       | FIELD_SET(  0, PANEL_PLL_CTRL, INPUT,  OSC)
+#ifndef VALIDATION_CHIP
+       | FIELD_VALUE(0, PANEL_PLL_CTRL, POD,    pPLL->POD)
+#endif
+       | FIELD_VALUE(0, PANEL_PLL_CTRL, OD,     pPLL->OD)
+       | FIELD_VALUE(0, PANEL_PLL_CTRL, N,      pPLL->N)
+       | FIELD_VALUE(0, PANEL_PLL_CTRL, M,      pPLL->M);
+
+    return ulPllReg;
+}
+
+