X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=kernel%2Fdrivers%2Fstaging%2Fsm750fb%2Fddk750_chip.c;fp=kernel%2Fdrivers%2Fstaging%2Fsm750fb%2Fddk750_chip.c;h=7b28328c92f851ff8a3362a261c64fbfeaa36fcd;hb=9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00;hp=0000000000000000000000000000000000000000;hpb=98260f3884f4a202f9ca5eabed40b1354c489b29;p=kvmfornfv.git diff --git a/kernel/drivers/staging/sm750fb/ddk750_chip.c b/kernel/drivers/staging/sm750fb/ddk750_chip.c new file mode 100644 index 000000000..7b28328c9 --- /dev/null +++ b/kernel/drivers/staging/sm750fb/ddk750_chip.c @@ -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; +} + +