On Fri, Aug 24, 2012 at 10:35:00AM +0800, Aaron.Chen ??? wrote: > Hi, > > >What's with the #ifdef 0 or #ifdef 1? > > >Why is there a bunch of ddkxxx something? Can those header files be squashed > >together? > > We have deleted all the "#ifdef 0 or #ifdef 1" and cut our codes into smaller > parts in order to get reviewed easier. There are less ddkxxx something in > this patch.
Please next time post it inline, not as attachment. Also explain why/where what machines this runs on. >From 35c8c1675e2bf6d8e7a702d61558b99316aaeabe Mon Sep 17 00:00:00 2001 >From: Aaron Chen <aaron.chen at siliconmotion.com> >Date: Fri, 24 Aug 2012 10:03:54 +0800 >Subject: [PATCH] siliconmotion kernel driver initial patch > >This is the initial patch for siliconmotion kernel driver. It can support >SM750 and SM718. It is a framebuffer driver. > >Signed-off-by: Aaron Chen <aaron.chen at siliconmotion.com> >--- > drivers/video/Kconfig | 13 + > drivers/video/Makefile | 1 + > drivers/video/lynxfb/Makefile | 63 ++ > drivers/video/lynxfb/ddk750.h | 31 + > drivers/video/lynxfb/ddk750_chip.c | 586 ++++++++++++ > drivers/video/lynxfb/ddk750_chip.h | 97 ++ > drivers/video/lynxfb/ddk750_display.c | 295 ++++++ > drivers/video/lynxfb/ddk750_display.h | 124 +++ > drivers/video/lynxfb/ddk750_dvi.c | 114 +++ > drivers/video/lynxfb/ddk750_dvi.h | 84 ++ > drivers/video/lynxfb/ddk750_help.c | 37 + > drivers/video/lynxfb/ddk750_help.h | 42 + > drivers/video/lynxfb/ddk750_hwi2c.c | 290 ++++++ > drivers/video/lynxfb/ddk750_hwi2c.h | 28 + > drivers/video/lynxfb/ddk750_mode.c | 213 +++++ > drivers/video/lynxfb/ddk750_mode.h | 59 ++ > drivers/video/lynxfb/ddk750_power.c | 243 +++++ > drivers/video/lynxfb/ddk750_power.h | 85 ++ > drivers/video/lynxfb/ddk750_reg.h | 362 +++++++ > drivers/video/lynxfb/ddk750_sii164.c | 435 +++++++++ > drivers/video/lynxfb/ddk750_sii164.h | 187 ++++ > drivers/video/lynxfb/ddk750_swi2c.c | 522 ++++++++++ > drivers/video/lynxfb/ddk750_swi2c.h | 98 ++ > drivers/video/lynxfb/lynx_accel.c | 417 ++++++++ > drivers/video/lynxfb/lynx_accel.h | 161 ++++ > drivers/video/lynxfb/lynx_cursor.c | 223 +++++ > drivers/video/lynxfb/lynx_cursor.h | 36 + > drivers/video/lynxfb/lynx_drv.c | 1688 +++++++++++++++++++++++++++++++++ > drivers/video/lynxfb/lynx_drv.h | 271 ++++++ > drivers/video/lynxfb/lynx_help.h | 115 +++ > drivers/video/lynxfb/lynx_hw750.c | 633 +++++++++++++ > drivers/video/lynxfb/lynx_hw750.h | 120 +++ > drivers/video/lynxfb/modedb.c | 238 +++++ > drivers/video/lynxfb/ver.h | 38 + > 34 files changed, 7949 insertions(+) > create mode 100644 drivers/video/lynxfb/Makefile > create mode 100644 drivers/video/lynxfb/ddk750.h > create mode 100644 drivers/video/lynxfb/ddk750_chip.c > create mode 100644 drivers/video/lynxfb/ddk750_chip.h > create mode 100644 drivers/video/lynxfb/ddk750_display.c > create mode 100644 drivers/video/lynxfb/ddk750_display.h > create mode 100644 drivers/video/lynxfb/ddk750_dvi.c > create mode 100644 drivers/video/lynxfb/ddk750_dvi.h > create mode 100644 drivers/video/lynxfb/ddk750_help.c > create mode 100644 drivers/video/lynxfb/ddk750_help.h > create mode 100644 drivers/video/lynxfb/ddk750_hwi2c.c > create mode 100644 drivers/video/lynxfb/ddk750_hwi2c.h > create mode 100644 drivers/video/lynxfb/ddk750_mode.c > create mode 100644 drivers/video/lynxfb/ddk750_mode.h > create mode 100644 drivers/video/lynxfb/ddk750_power.c > create mode 100644 drivers/video/lynxfb/ddk750_power.h > create mode 100644 drivers/video/lynxfb/ddk750_reg.h > create mode 100644 drivers/video/lynxfb/ddk750_sii164.c > create mode 100644 drivers/video/lynxfb/ddk750_sii164.h > create mode 100644 drivers/video/lynxfb/ddk750_swi2c.c > create mode 100644 drivers/video/lynxfb/ddk750_swi2c.h > create mode 100644 drivers/video/lynxfb/lynx_accel.c > create mode 100644 drivers/video/lynxfb/lynx_accel.h > create mode 100644 drivers/video/lynxfb/lynx_cursor.c > create mode 100644 drivers/video/lynxfb/lynx_cursor.h > create mode 100644 drivers/video/lynxfb/lynx_drv.c > create mode 100644 drivers/video/lynxfb/lynx_drv.h > create mode 100644 drivers/video/lynxfb/lynx_help.h > create mode 100644 drivers/video/lynxfb/lynx_hw750.c > create mode 100644 drivers/video/lynxfb/lynx_hw750.h > create mode 100644 drivers/video/lynxfb/modedb.c > create mode 100644 drivers/video/lynxfb/ver.h > >diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig >index 0217f74..8c52b1a 100644 >--- a/drivers/video/Kconfig >+++ b/drivers/video/Kconfig >@@ -2444,6 +2444,19 @@ config FB_PUV3_UNIGFX > Choose this option if you want to use the Unigfx device as a > framebuffer device. Without the support of PCI & AGP. > >+config FB_LYNXFB >+ tristate "SMI lynx sm750/718/712/722/502 display support" >+ depends on FB && PCI >+ select FB_CFB_IMAGEBLIT >+ select FB_CFB_FILLRECT >+ select FB_CFB_COPYAREA >+ ---help--- >+ This driver supports graphic board with the siliconmotion >+ sm750/sm718/sm712/sm722/sm502. Say Y if you have such a >+ graphic board. >+ To compile this driver as a module, choose M here: the >+ module will be called lynxfb. >+ > source "drivers/video/omap/Kconfig" > source "drivers/video/omap2/Kconfig" > source "drivers/video/exynos/Kconfig" >diff --git a/drivers/video/Makefile b/drivers/video/Makefile >index ee8dafb..b402bfb 100644 >--- a/drivers/video/Makefile >+++ b/drivers/video/Makefile >@@ -149,6 +149,7 @@ obj-$(CONFIG_FB_MSM) += msm/ > obj-$(CONFIG_FB_NUC900) += nuc900fb.o > obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o > obj-$(CONFIG_FB_PUV3_UNIGFX) += fb-puv3.o >+obj-$(CONFIG_FB_LYNXFB) += lynxfb/ > > # Platform or fallback drivers go here > obj-$(CONFIG_FB_UVESA) += uvesafb.o >diff --git a/drivers/video/lynxfb/Makefile b/drivers/video/lynxfb/Makefile >new file mode 100644 >index 0000000..8853097 >--- /dev/null >+++ b/drivers/video/lynxfb/Makefile >@@ -0,0 +1,63 @@ >+# >+# Makefile for lynx frame buffer >+# -by Monk.liu >+# >+ifeq ($(KERNELRELEASE),) >+ >+ifeq ($(kernel),) >+# build the driver with kernel version currerntly using >+knv :=$(shell uname -r) >+else >+# user want to build the driver based on specific kernel version >+knv :=$(kernel) >+endif >+ >+KERNELDIR :=/lib/modules/$(knv)/build >+PWD := $(shell pwd) >+ >+default: >+ $(MAKE) -C $(KERNELDIR) M=$(PWD) CONFIG_FB_LYNXFB=m modules >+install:default >+ $(MAKE) -C $(KERNELDIR) M=$(PWD) CONFIG_FB_LYNXFB=m modules_install >+clean: >+ $(MAKE) -C $(KERNELDIR) M=$(PWD) clean >+else >+ You don't need all of that. >+obj-$(CONFIG_FB_LYNXFB) += lynxfb.o >+ >+lynxfb-y := lynx_drv.o lynx_hw750.o lynx_accel.o lynx_cursor.o >+lynxfb-y += ddk750_chip.o ddk750_power.o ddk750_mode.o ddk750_display.o >ddk750_help.o >+lynxfb-y += ddk750_swi2c.o Those should suffice. Or perhaps: obj-$(CONFIG_FB_LYNXFB) += lynxfb.o lynx_drv.o lynx_hw750.o lynx_accel.o lynx_cursor.o ddk750_chip.o ddk750_power.o ddk750_mode.o ddk750_display.o ddk750_help.o and that is it. >+ >+ >+EXTRA_CFLAGS += -DOPENSOURCE >+ >+ifneq ($(nodvi),1) >+lynxfb-y += ddk750_sii164.o >+lynxfb-y += ddk750_dvi.o >+EXTRA_CFLAGS += -DUSE_DVICHIP >+else >+endif >+ >+# if user define swi2c=1,then for sm750/sm718,its dvi chip (sii164) will be >initilized by swi2c >+# but for 750le, always swi2c used to setup its 7301 dvi chip >+ifneq ($(swi2c),1) >+lynxfb-y += ddk750_hwi2c.o >+EXTRA_CFLAGS += -DUSE_HW_I2C >+endif >+ >+lynxfb-objs := $(lynxfb-y) >+ >+ifeq ($(debug),1) >+#CONFIG_FB_LYNXFB_DEBUG=y >+EXTRA_CFLAGS += -DDEBUG=1 >+endif >+ >+ifeq ($(debug),2) >+EXTRA_CFLAGS += -DDEBUG=2 >+endif >+ >+#ifdef CONFIG_FB_LYNXFB_DEBUG >+#endif >+ >+endif >diff --git a/drivers/video/lynxfb/ddk750.h b/drivers/video/lynxfb/ddk750.h >new file mode 100644 >index 0000000..fd3e279 >--- /dev/null >+++ b/drivers/video/lynxfb/ddk750.h >@@ -0,0 +1,31 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#ifndef DDK750_H__ >+#define DDK750_H__ >+#include "ddk750_reg.h" >+#include "ddk750_mode.h" >+#include "ddk750_chip.h" >+#include "ddk750_display.h" >+#include "ddk750_power.h" >+#include "ddk750_help.h" >+#ifdef USE_HW_I2C >+#include "ddk750_hwi2c.h" >+#endif >+#include "ddk750_swi2c.h" >+#endif This header file is not adding anyting to the driver. Why don't you just include those #includes in the C code? >diff --git a/drivers/video/lynxfb/ddk750_chip.c >b/drivers/video/lynxfb/ddk750_chip.c >new file mode 100644 >index 0000000..4eff5c6 >--- /dev/null >+++ b/drivers/video/lynxfb/ddk750_chip.c >@@ -0,0 +1,586 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#include "ddk750_help.h" >+#include "ddk750_reg.h" >+#include "ddk750_chip.h" >+#include "ddk750_power.h" >+typedef struct _pllcalparam{ You didn't run cleanpatch on this patch series at all did you? Please do that and then repost it. >+ 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() >+{ >+ 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) I think there is a nice macro for this. Did you search in the code already for this? >+{ >+ 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 = 255&(ulPllReg >> PANEL_PLL_CTRL_M_LSB); >+ pPLL->N = 15&(ulPllReg >> PANEL_PLL_CTRL_N_LSB); >+ pPLL->OD = 3&(ulPllReg >> PANEL_PLL_CTRL_OD_LSB); >+ pPLL->POD = 3&(ulPllReg >> PANEL_PLL_CTRL_POD_LSB); >+ >+ return calcPLL(pPLL); >+} >+ >+ >+unsigned int getChipClock() >+{ >+ pll_value_t pll; >+ if (getChipType() == SM750LE) >+ return MHz(130); >+ >+ 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; >+ >+ /* Cheok_0509: For SM750LE, the chip clock is fixed. Nothing to set. */ >+ if (getChipType() == SM750LE) >+ return; >+ >+ >+ if (frequency != 0) { >+ /* >+ * Set up PLL, a structure to hold the value to be set in >clocks. >+ */ >+ pll.inputFreq = DEFAULT_INPUT_CLOCK; /* Defined in CLOCK.H */ I don't think the 'CLOCK.H' file is present there. >+ 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. So an estimation then? >+ */ >+ ulActualMxClk = calcPllValue(frequency, &pll); >+ >+ /* Master Clock Control: MXCLK_PLL */ >+ POKE32(MXCLK_PLL_CTRL, formatPllReg(&pll)); >+ } >+} >+ >+ >+ >+void setMemoryClock(unsigned int frequency) >+{ >+ unsigned int ulReg, divisor; >+ >+ /* Cheok_0509: For SM750LE, the memory clock is fixed. Nothing to set. >*/ >+ if (getChipType() == SM750LE) >+ return; >+ >+ if (frequency != 0) { >+ /* 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 = ulReg&(~(1 << CURRENT_GATE_M2XCLK_LSB)); >+ break; >+ case 2: >+ ulReg = ulReg|(1 << CURRENT_GATE_M2XCLK_LSB); >+ break; >+ case 3: >+ ulReg = ulReg&(~(3 << CURRENT_GATE_M2XCLK_LSB)); >+ ulReg = ulReg|(2 << CURRENT_GATE_M2XCLK_LSB); >+ break; >+ case 4: >+ ulReg = ulReg|(3 << CURRENT_GATE_M2XCLK_LSB); >+ 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; >+ >+ /* Cheok_0509: For SM750LE, the memory clock is fixed. Nothing to set. >*/ >+ if (getChipType() == SM750LE) >+ return; >+ >+ if (frequency != 0) { >+ /* 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 = ulReg&(~(1 << CURRENT_GATE_MCLK_LSB)); >+ break; >+ case 4: >+ ulReg = ulReg|(1 << CURRENT_GATE_MCLK_LSB); >+ break; >+ case 6: >+ ulReg = ulReg&(~(3 << CURRENT_GATE_MCLK_LSB)); >+ ulReg = ulReg|(2 << CURRENT_GATE_MCLK_LSB); >+ break; >+ case 8: >+ ulReg = ulReg|(3 << CURRENT_GATE_MCLK_LSB); >+ break; >+ } >+ setCurrentGate(ulReg); >+ } >+} >+ >+ >+unsigned int ddk750_getVMSize() >+{ >+ 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 = reg|(1 << MODE0_GATE_GPIO_LSB); >+ POKE32(MODE0_GATE, reg); >+ >+ /* get frame buffer size from GPIO */ >+ reg = 3&(PEEK32(MISC_CTRL) >> MISC_CTRL_LOCALMEM_SIZE_LSB); >+ 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 (pInitParam->powerMode != 0) >+ pInitParam->powerMode = 0; >+ setPowerMode(pInitParam->powerMode); >+ >+ /* Enable display power gate & LOCALMEM power gate*/ >+ ulReg = PEEK32(CURRENT_GATE); >+ ulReg = ulReg|(1 << CURRENT_GATE_DISPLAY_LSB); >+ ulReg = ulReg|(1 << CURRENT_GATE_LOCALMEM_LSB); >+ setCurrentGate(ulReg); >+ >+ if (getChipType() != SM750LE) { >+ /* set panel pll and graphic mode via mmio_88 */ >+ ulReg = PEEK32(VGA_CONFIGURATION); >+ ulReg = ulReg|(1 << VGA_CONFIGURATION_PLL_LSB); >+ ulReg = ulReg|(1 << VGA_CONFIGURATION_MODE_LSB); >+ >+ 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 = ulReg&(~(1 << MISC_CTRL_LOCALMEM_RESET_LSB)); >+ POKE32(MISC_CTRL, ulReg); >+ >+ ulReg = ulReg|(1 << MISC_CTRL_LOCALMEM_RESET_LSB); >+ 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 = ulReg&(~(1 << VIDEO_DISPLAY_CTRL_PLANE_LSB)); >+ POKE32(VIDEO_DISPLAY_CTRL, ulReg); >+ >+ /* Disable video alpha, if a former application left it on */ >+ ulReg = PEEK32(VIDEO_ALPHA_DISPLAY_CTRL); >+ ulReg = ulReg&(~(1 << VIDEO_ALPHA_DISPLAY_CTRL_PLANE_LSB)); >+ POKE32(VIDEO_ALPHA_DISPLAY_CTRL, ulReg); >+ >+ /* Disable alpha plane, if a former application left it on */ >+ ulReg = PEEK32(ALPHA_DISPLAY_CTRL); >+ ulReg = ulReg&(~(1 << ALPHA_DISPLAY_CTRL_PLANE_LSB)); >+ POKE32(ALPHA_DISPLAY_CTRL, ulReg); >+ >+ /* Disable DMA Channel, if a former application left it on */ >+ ulReg = PEEK32(DMA_ABORT_INTERRUPT); >+ ulReg = ulReg|(1 << DMA_ABORT_INTERRUPT_ABORT_1_LSB); >+ 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; >+} >+ >+/* >+ 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 (getChipType() == SM750LE) { >+ /* SM750LE don't have prgrammable PLL and M/N values to work on. >+ Just return the requested clock. */ >+ return request_orig; >+ } >+ >+ >+ 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 So.. what are those? Should these #ifdef's be removed? I stopped here.. You should read the Documentation/Submitting* files and follow what they mention there. Please fix the syntax, remove the usage of templates, and user 'pr_info' instead of 'printk'. >+ /* 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));i >+ 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));i */ >+ >+ /* 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 = >+ (0 << PANEL_PLL_CTRL_BYPASS_LSB) >+ | (1 << PANEL_PLL_CTRL_POWER_LSB) >+ | (0 << PANEL_PLL_CTRL_INPUT_LSB) >+#ifndef VALIDATION_CHIP >+ | (pPLL->POD << PANEL_PLL_CTRL_POD_LSB) >+#endif >+ | (pPLL->OD << PANEL_PLL_CTRL_OD_LSB) >+ | (pPLL->N << PANEL_PLL_CTRL_N_LSB) >+ | (pPLL->M << PANEL_PLL_CTRL_M_LSB); >+ return ulPllReg; >+} >+ >+ >diff --git a/drivers/video/lynxfb/ddk750_chip.h >b/drivers/video/lynxfb/ddk750_chip.h >new file mode 100644 >index 0000000..f24af16 >--- /dev/null >+++ b/drivers/video/lynxfb/ddk750_chip.h >@@ -0,0 +1,97 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#ifndef DDK750_CHIP_H__ >+#define DDK750_CHIP_H__ >+#define DEFAULT_INPUT_CLOCK 14318181 /* Default reference clock */ >+#define SM750LE_REVISION_ID ((char)0xfe) >+ >+/* This is all the chips recognized by this library */ >+typedef enum _logical_chip_type_t{ >+ SM_UNKNOWN, >+ SM718, >+ SM750, >+ SM750LE, >+} >+logical_chip_type_t; >+ >+ >+typedef enum _clock_type_t{ >+ MXCLK_PLL, >+ PRIMARY_PLL, >+ SECONDARY_PLL, >+ VGA0_PLL, >+ VGA1_PLL, >+} >+clock_type_t; >+ >+typedef struct _pll_value_t{ >+ clock_type_t clockType; >+ unsigned long inputFreq; /* Input clock frequency to the PLL */ >+ >+ /* Use this when clockType = PANEL_PLL */ >+ unsigned long M; >+ unsigned long N; >+ unsigned long OD; >+ unsigned long POD; >+} >+pll_value_t; >+ >+/* input struct to initChipParam() function */ >+typedef struct _initchip_param_t{ >+ unsigned short powerMode; /* Use power mode 0 or 1 */ >+ unsigned short chipClock; /* Speed of main chip clock in MHz unit >+ 0 = keep the current clock setting >+ Others = the new main chip clock >+ */ >+ unsigned short memClock; /* Speed of memory clock in MHz unit >+ 0 = keep the current clock setting >+ Others = the new memory clock >+ */ >+ unsigned short masterClock; /* Speed of master clock in MHz unit >+ 0 = keep the current clock setting >+ Others = the new master clock >+ */ >+ unsigned short setAllEngOff; /* 0 = leave all engine state untouched. >+ 1 = make sure they are off: 2D, Overlay, >+ video alpha, alpha, hardware cursors >+ */ >+ unsigned char resetMemory; /* 0 = Do not reset the memory controller >+ 1 = Reset the memory controller >+ */ >+ >+ /* More initialization parameter can be added if needed */ >+} >+initchip_param_t; >+ >+ >+logical_chip_type_t getChipType(void); >+unsigned int calcPllValue(unsigned int request, pll_value_t *pll); >+unsigned int calcPllValue2(unsigned int, pll_value_t *); >+unsigned int formatPllReg(pll_value_t *pPLL); >+void ddk750_set_mmio(volatile unsigned char *, unsigned short, char); >+unsigned int ddk750_getVMSize(void); >+int ddk750_initHw(initchip_param_t *); >+unsigned int getPllValue(clock_type_t clockType, pll_value_t *pPLL); >+unsigned int getChipClock(void); >+void setChipClock(unsigned int); >+void setMemoryClock(unsigned int frequency); >+void setMasterClock(unsigned int frequency); >+ >+ >+#endif >diff --git a/drivers/video/lynxfb/ddk750_display.c >b/drivers/video/lynxfb/ddk750_display.c >new file mode 100644 >index 0000000..6e973cc >--- /dev/null >+++ b/drivers/video/lynxfb/ddk750_display.c >@@ -0,0 +1,295 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#include "ddk750_reg.h" >+#include "ddk750_help.h" >+#include "ddk750_display.h" >+#include "ddk750_power.h" >+#include "ddk750_dvi.h" >+ >+#define primaryWaitVerticalSync(delay) waitNextVerticalSync(0, delay) >+ >+static void setDisplayControl(int ctrl, int dispState) >+{ >+ /* state != 0 means turn on both timing & plane en_bit */ >+ unsigned long ulDisplayCtrlReg, ulReservedBits = 0; >+ int cnt; >+ >+ cnt = 0; >+ >+ /* Set the primary display control */ >+ if (!ctrl) { >+ ulDisplayCtrlReg = PEEK32(PANEL_DISPLAY_CTRL); >+ /* Turn on/off the Panel display control */ >+ if (dispState) { >+ /* Timing should be enabled first before enabling the >plane >+ * because changing at the same time does not guarantee >that >+ * the plane will also enabled or disabled. >+ */ >+ ulDisplayCtrlReg = ulDisplayCtrlReg|(1 << >PANEL_DISPLAY_CTRL_TIMING_LSB); >+ POKE32(PANEL_DISPLAY_CTRL, ulDisplayCtrlReg); >+ >+ ulDisplayCtrlReg = ulDisplayCtrlReg|(1 << >PANEL_DISPLAY_CTRL_PLANE_LSB); >+ /* Added some masks to mask out the reserved bits. >+ * Sometimes, the reserved bits are set/reset randomly >when >+ * writing to the PRIMARY_DISPLAY_CTRL, therefore, the >register >+ * reserved bits are needed to be masked out. >+ */ >+ ulReservedBits = (3 << >PANEL_DISPLAY_CTRL_RESERVED_1_MASK_LSB)| >+ (15 << >PANEL_DISPLAY_CTRL_RESERVED_2_MASK_LSB)| >+ (1 << >PANEL_DISPLAY_CTRL_RESERVED_3_MASK_LSB); >+ >+ /* Somehow the register value on the plane is not set >+ * until a few delay. Need to write >+ * and read it a couple times >+ */ >+ do { >+ cnt++; >+ POKE32(PANEL_DISPLAY_CTRL, ulDisplayCtrlReg); >+ } while ((PEEK32(PANEL_DISPLAY_CTRL) & ~ulReservedBits) >!= >+ (ulDisplayCtrlReg & ~ulReservedBits)); >+ printk("Set Panel Plane enbit:after tried %d times\n", >cnt); >+ } else{ >+ /* When turning off, there is no rule on the programming >+ * sequence since whenever the clock is off, then it >does not >+ * matter whether the plane is enabled or disabled. >+ * Note: Modifying the plane bit will take effect on the >+ * next vertical sync. Need to find out if it is >necessary to >+ * wait for 1 vsync before modifying the timing enable >bit. >+ * */ >+ ulDisplayCtrlReg = ulDisplayCtrlReg&(~(1 << >PANEL_DISPLAY_CTRL_PLANE_LSB)); >+ POKE32(PANEL_DISPLAY_CTRL, ulDisplayCtrlReg); >+ >+ ulDisplayCtrlReg = ulDisplayCtrlReg&(~(1 << >PANEL_DISPLAY_CTRL_TIMING_LSB)); >+ POKE32(PANEL_DISPLAY_CTRL, ulDisplayCtrlReg); >+ } >+ >+ } else{ >+ /* Set the secondary display control */ >+ ulDisplayCtrlReg = PEEK32(CRT_DISPLAY_CTRL); >+ >+ if (dispState) { >+ /* Timing should be enabled first before enabling the >plane because changing at the >+ same time does not guarantee that the plane will >also enabled or disabled. >+ */ >+ ulDisplayCtrlReg = ulDisplayCtrlReg|(1 << >CRT_DISPLAY_CTRL_TIMING_LSB); >+ POKE32(CRT_DISPLAY_CTRL, ulDisplayCtrlReg); >+ >+ ulDisplayCtrlReg = ulDisplayCtrlReg|(1 << >CRT_DISPLAY_CTRL_PLANE_LSB); >+ >+ /* Added some masks to mask out the reserved bits. >+ * Sometimes, the reserved bits are set/reset randomly >when >+ * writing to the PRIMARY_DISPLAY_CTRL, therefore, the >register >+ * reserved bits are needed to be masked out. >+ */ >+ >+ ulReservedBits = (0X1F << >CRT_DISPLAY_CTRL_RESERVED_1_MASK_LSB)| >+ (3 << >CRT_DISPLAY_CTRL_RESERVED_2_MASK_LSB)| >+ (1 << >CRT_DISPLAY_CTRL_RESERVED_3_MASK_LSB)| >+ (1 << >CRT_DISPLAY_CTRL_RESERVED_4_MASK_LSB); >+ do { >+ cnt++; >+ POKE32(CRT_DISPLAY_CTRL, ulDisplayCtrlReg); >+ } while ((PEEK32(CRT_DISPLAY_CTRL) & ~ulReservedBits) != >+ (ulDisplayCtrlReg & ~ulReservedBits)); >+ printk("Set Crt Plane enbit:after tried %d times\n", >cnt); >+ } else{ >+ /* When turning off, there is no rule on the programming >+ * sequence since whenever the clock is off, then it >does not >+ * matter whether the plane is enabled or disabled. >+ * Note: Modifying the plane bit will take effect on >the next >+ * vertical sync. Need to find out if it is necessary to >+ * wait for 1 vsync before modifying the timing enable >bit. >+ */ >+ ulDisplayCtrlReg = ulDisplayCtrlReg&(~(1 << >CRT_DISPLAY_CTRL_PLANE_LSB)); >+ POKE32(CRT_DISPLAY_CTRL, ulDisplayCtrlReg); >+ >+ ulDisplayCtrlReg = ulDisplayCtrlReg&(~(1 << >CRT_DISPLAY_CTRL_TIMING_LSB)); >+ POKE32(CRT_DISPLAY_CTRL, ulDisplayCtrlReg); >+ } >+ } >+} >+ >+ >+static void waitNextVerticalSync(int ctrl, int delay) >+{ >+ unsigned int status; >+ if (!ctrl) { >+ /* primary controller */ >+ >+ /* Do not wait when the Primary PLL is off or display control >is already off. >+ This will prevent the software to wait forever. */ >+ if (((1&(PEEK32(PANEL_PLL_CTRL) >> PANEL_PLL_CTRL_POWER_LSB)) == >+ PANEL_PLL_CTRL_POWER_OFF) || >+ ((1&(PEEK32(PANEL_DISPLAY_CTRL) >> >PANEL_DISPLAY_CTRL_TIMING_LSB)) == >+ PANEL_DISPLAY_CTRL_TIMING_DISABLE)) { >+ return; >+ } >+ while (delay-- > 0) { >+ /* Wait for end of vsync. */ >+ do { >+ status = 1&(PEEK32(SYSTEM_CTRL) >> >SYSTEM_CTRL_PANEL_VSYNC_LSB); >+ } while (status == SYSTEM_CTRL_PANEL_VSYNC_ACTIVE); >+ >+ /* Wait for start of vsync. */ >+ do { >+ status = 1&(PEEK32(SYSTEM_CTRL) >> >SYSTEM_CTRL_PANEL_VSYNC_LSB); >+ } while (status == SYSTEM_CTRL_PANEL_VSYNC_INACTIVE); >+ } >+ >+ } else{ >+ >+ /* Do not wait when the Primary PLL is off or display control >is already off. >+ This will prevent the software to wait forever. */ >+ if ((1&(PEEK32(CRT_PLL_CTRL) >> CRT_PLL_CTRL_POWER_LSB) == >+ CRT_PLL_CTRL_POWER_OFF) || >+ (1&(PEEK32(CRT_DISPLAY_CTRL) >> >CRT_DISPLAY_CTRL_TIMING_LSB) == >+ CRT_DISPLAY_CTRL_TIMING_DISABLE)) { >+ return; >+ } >+ >+ while (delay-- > 0) { >+ /* Wait for end of vsync. */ >+ do { >+ status = 1&(PEEK32(SYSTEM_CTRL) >> >SYSTEM_CTRL_CRT_VSYNC_LSB); >+ } while (status == SYSTEM_CTRL_CRT_VSYNC_ACTIVE); >+ >+ /* Wait for start of vsync. */ >+ do { >+ status = 1&(PEEK32(SYSTEM_CTRL) >> >SYSTEM_CTRL_CRT_VSYNC_LSB); >+ } while (status == SYSTEM_CTRL_CRT_VSYNC_INACTIVE); >+ } >+ } >+} >+ >+static void swPanelPowerSequence_sm750le(int disp, int delay) >+{ >+ unsigned int reg; >+ reg = PEEK32(DISPLAY_CONTROL_750LE); >+ if (disp) >+ reg |= 0xf; >+ else >+ reg &= ~0xf; >+ POKE32(DISPLAY_CONTROL_750LE, reg); >+} >+ >+static void swPanelPowerSequence(int disp, int delay) >+{ >+ unsigned int reg; >+ >+ /* disp should be 1 to open sequence */ >+ reg = PEEK32(PANEL_DISPLAY_CTRL); >+ reg &= ~(1 << PANEL_DISPLAY_CTRL_FPEN_LSB); >+ reg = reg|(disp << PANEL_DISPLAY_CTRL_FPEN_LSB); >+ POKE32(PANEL_DISPLAY_CTRL, reg); >+ primaryWaitVerticalSync(delay); >+ >+ reg = PEEK32(PANEL_DISPLAY_CTRL); >+ reg &= ~(1 << PANEL_DISPLAY_CTRL_DATA_LSB); >+ reg = reg|(disp << PANEL_DISPLAY_CTRL_DATA_LSB); >+ POKE32(PANEL_DISPLAY_CTRL, reg); >+ primaryWaitVerticalSync(delay); >+ >+ reg = PEEK32(PANEL_DISPLAY_CTRL); >+ reg &= ~(1 << PANEL_DISPLAY_CTRL_VBIASEN_LSB); >+ reg = reg|(disp << PANEL_DISPLAY_CTRL_VBIASEN_LSB); >+ POKE32(PANEL_DISPLAY_CTRL, reg); >+ primaryWaitVerticalSync(delay); >+ >+ reg = PEEK32(PANEL_DISPLAY_CTRL); >+ reg &= ~(1 << PANEL_DISPLAY_CTRL_FPEN_LSB); >+ reg = reg|(disp << PANEL_DISPLAY_CTRL_FPEN_LSB); >+ POKE32(PANEL_DISPLAY_CTRL, reg); >+ primaryWaitVerticalSync(delay); >+ >+} >+ >+void ddk750_setLogicalDispOut(disp_output_t output) >+{ >+ unsigned int reg; >+ if (output & PNL_2_USAGE) { >+ /* set panel path controller select */ >+ reg = PEEK32(PANEL_DISPLAY_CTRL); >+ reg &= ~(3 << PANEL_DISPLAY_CTRL_SELECT_LSB); >+ reg = reg|((output & PNL_2_MASK) >> PNL_2_OFFSET) << >PANEL_DISPLAY_CTRL_SELECT_LSB; >+ POKE32(PANEL_DISPLAY_CTRL, reg); >+ } >+ >+ if (output & CRT_2_USAGE) { >+ /* set crt path controller select */ >+ reg = PEEK32(CRT_DISPLAY_CTRL); >+ reg &= ~(3 << CRT_DISPLAY_CTRL_SELECT_LSB); >+ reg = reg|((output & CRT_2_MASK) >> CRT_2_OFFSET) << >CRT_DISPLAY_CTRL_SELECT_LSB; >+ /*se blank off */ >+ reg = reg&(~(1 << CRT_DISPLAY_CTRL_BLANK_LSB)); >+ POKE32(CRT_DISPLAY_CTRL, reg); >+ } >+ if (output & PRI_TP_USAGE) { >+ /* set primary timing and plane en_bit */ >+ setDisplayControl(0, (output&PRI_TP_MASK) >> PRI_TP_OFFSET); >+ } >+ >+ if (output & SEC_TP_USAGE) { >+ /* set secondary timing and plane en_bit*/ >+ setDisplayControl(1, (output&SEC_TP_MASK) >> SEC_TP_OFFSET); >+ } >+ >+ if (output & PNL_SEQ_USAGE) { >+ /* set panel sequence */ >+ swPanelPowerSequence((output&PNL_SEQ_MASK) >> PNL_SEQ_OFFSET, >4); >+ } >+ >+ if (output & DAC_USAGE) >+ setDAC((output & DAC_MASK) >> DAC_OFFSET); >+ >+ if (output & DPMS_USAGE) >+ ddk750_setDPMS((output & DPMS_MASK) >> DPMS_OFFSET); >+} >+ >+ >+int ddk750_initDVIDisp() >+{ >+ /* Initialize DVI. If the dviInit fail and the VendorID or the DeviceID >are >+ not zeroed, then set the failure flag. If it is zeroe, it might mean >+ that the system is in Dual CRT Monitor configuration. */ >+ >+ /* De-skew enabled with default 111b value. >+ This will fix some artifacts problem in some mode on board 2.2. >+ Somehow this fix does not affect board 2.1. >+ */ >+ if ((dviInit(1, /* Select Rising Edge */ >+ 1, /* Select 24-bit bus */ >+ 0, /* Select Single Edge clock */ >+ 1, /* Enable HSync as is */ >+ 1, /* Enable VSync as is */ >+ 1, /* Enable De-skew */ >+ 7, /* Set the de-skew setting to >maximum setup */ >+ 1, /* Enable continuous Sync */ >+ 1, /* Enable PLL Filter */ >+ 4 /* Use the recommended value for >PLL Filter value */ >+ ) != 0) && (dviGetVendorID() != 0x0000) && >(dviGetDeviceID() != 0x0000)) { >+ return -1; >+ } >+ >+ /* TODO: Initialize other display component */ >+ >+ /* Success */ >+ return 0; >+ >+} >+ >diff --git a/drivers/video/lynxfb/ddk750_display.h >b/drivers/video/lynxfb/ddk750_display.h >new file mode 100644 >index 0000000..abc2a93 >--- /dev/null >+++ b/drivers/video/lynxfb/ddk750_display.h >@@ -0,0 +1,124 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#ifndef DDK750_DISPLAY_H__ >+#define DDK750_DISPLAY_H__ >+ >+/* panel path select >+ 80000[29:28] >+ */ >+ >+#define PNL_2_OFFSET 0 >+#define PNL_2_MASK (3 << PNL_2_OFFSET) >+#define PNL_2_USAGE (PNL_2_MASK << 16) >+#define PNL_2_PRI ((0 << PNL_2_OFFSET)|PNL_2_USAGE) >+#define PNL_2_SEC ((2 << PNL_2_OFFSET)|PNL_2_USAGE) >+ >+ >+/* primary timing & plane enable bit >+1: 80000[8] & 80000[2] on >+0: both off >+*/ >+#define PRI_TP_OFFSET 4 >+#define PRI_TP_MASK (1 << PRI_TP_OFFSET) >+#define PRI_TP_USAGE (PRI_TP_MASK << 16) >+#define PRI_TP_ON ((0x1 << PRI_TP_OFFSET)|PRI_TP_USAGE) >+#define PRI_TP_OFF ((0x0 << PRI_TP_OFFSET)|PRI_TP_USAGE) >+ >+ >+/* panel sequency status >+ 80000[27:24] >+ */ >+#define PNL_SEQ_OFFSET 6 >+#define PNL_SEQ_MASK (1 << PNL_SEQ_OFFSET) >+#define PNL_SEQ_USAGE (PNL_SEQ_MASK << 16) >+#define PNL_SEQ_ON ((1 << PNL_SEQ_OFFSET)|PNL_SEQ_USAGE) >+#define PNL_SEQ_OFF ((0 << PNL_SEQ_OFFSET)|PNL_SEQ_USAGE) >+ >+/* dual digital output >+ 80000[19] >+ */ >+#define DUAL_TFT_OFFSET 8 >+#define DUAL_TFT_MASK (1 << DUAL_TFT_OFFSET) >+#define DUAL_TFT_USAGE (DUAL_TFT_MASK << 16) >+#define DUAL_TFT_ON ((1 << DUAL_TFT_OFFSET)|DUAL_TFT_USAGE) >+#define DUAL_TFT_OFF ((0 << DUAL_TFT_OFFSET)|DUAL_TFT_USAGE) >+ >+/* secondary timing & plane enable bit >+1:80200[8] & 80200[2] on >+0: both off >+*/ >+#define SEC_TP_OFFSET 5 >+#define SEC_TP_MASK (1 << SEC_TP_OFFSET) >+#define SEC_TP_USAGE (SEC_TP_MASK << 16) >+#define SEC_TP_ON ((0x1 << SEC_TP_OFFSET)|SEC_TP_USAGE) >+#define SEC_TP_OFF ((0x0 << SEC_TP_OFFSET)|SEC_TP_USAGE) >+ >+/* crt path select >+ 80200[19:18] >+ */ >+#define CRT_2_OFFSET 2 >+#define CRT_2_MASK (3 << CRT_2_OFFSET) >+#define CRT_2_USAGE (CRT_2_MASK << 16) >+#define CRT_2_PRI ((0x0 << CRT_2_OFFSET)|CRT_2_USAGE) >+#define CRT_2_SEC ((0x2 << CRT_2_OFFSET)|CRT_2_USAGE) >+ >+ >+/* DAC affect both DVI and DSUB >+ 4[20] >+ */ >+#define DAC_OFFSET 7 >+#define DAC_MASK (1 << DAC_OFFSET) >+#define DAC_USAGE (DAC_MASK << 16) >+#define DAC_ON ((0x0 << DAC_OFFSET)|DAC_USAGE) >+#define DAC_OFF ((0x1 << DAC_OFFSET)|DAC_USAGE) >+ >+/* DPMS only affect D-SUB head >+ 0[31:30] >+ */ >+#define DPMS_OFFSET 9 >+#define DPMS_MASK (3 << DPMS_OFFSET) >+#define DPMS_USAGE (DPMS_MASK << 16) >+#define DPMS_OFF ((3 << DPMS_OFFSET)|DPMS_USAGE) >+#define DPMS_ON ((0 << DPMS_OFFSET)|DPMS_USAGE) >+ >+ >+ >+/* >+ LCD1 means panel path TFT1 & panel path DVI (so enable DAC) >+ CRT means crt path DSUB >+ */ >+ >+typedef enum _disp_output_t{ >+ do_LCD1_PRI = PNL_2_PRI|PRI_TP_ON|PNL_SEQ_ON|DAC_ON, >+ do_LCD1_SEC = PNL_2_SEC|SEC_TP_ON|PNL_SEQ_ON|DAC_ON, >+ do_LCD2_PRI = CRT_2_PRI|PRI_TP_ON|DUAL_TFT_ON, >+ do_LCD2_SEC = CRT_2_SEC|SEC_TP_ON|DUAL_TFT_ON, >+ /* >+ do_DSUB_PRI = CRT_2_PRI|PRI_TP_ON|DPMS_ON|DAC_ON, >+ do_DSUB_SEC = CRT_2_SEC|SEC_TP_ON|DPMS_ON|DAC_ON, >+ */ >+ do_CRT_PRI = CRT_2_PRI|PRI_TP_ON|DPMS_ON|DAC_ON, >+ do_CRT_SEC = CRT_2_SEC|SEC_TP_ON|DPMS_ON|DAC_ON, >+} >+disp_output_t; >+ >+void ddk750_setLogicalDispOut(disp_output_t); >+int ddk750_initDVIDisp(void); >+ >+#endif >diff --git a/drivers/video/lynxfb/ddk750_dvi.c >b/drivers/video/lynxfb/ddk750_dvi.c >new file mode 100644 >index 0000000..0663009 >--- /dev/null >+++ b/drivers/video/lynxfb/ddk750_dvi.c >@@ -0,0 +1,114 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#ifdef USE_DVICHIP >+#include "ddk750_help.h" >+#include "ddk750_reg.h" >+#include "ddk750_dvi.h" >+#include "ddk750_sii164.h" >+ >+ >+/* This global variable contains all the supported driver and its >corresponding >+ function API. Please set the function pointer to NULL whenever the function >+ is not supported. */ >+static dvi_ctrl_device_t g_dcftSupportedDviController[] = { >+#ifdef DVI_CTRL_SII164 >+ { >+ .pfnInit = sii164InitChip, >+ .pfnGetVendorId = sii164GetVendorID, >+ .pfnGetDeviceId = sii164GetDeviceID, >+#ifdef SII164_FULL_FUNCTIONS >+ .pfnResetChip = sii164ResetChip, >+ .pfnGetChipString = sii164GetChipString, >+ .pfnSetPower = sii164SetPower, >+ .pfnEnableHotPlugDetection = sii164EnableHotPlugDetection, >+ .pfnIsConnected = sii164IsConnected, >+ .pfnCheckInterrupt = sii164CheckInterrupt, >+ .pfnClearInterrupt = sii164ClearInterrupt, >+#endif >+ }, >+#endif >+}; >+ >+ >+int dviInit( >+ unsigned char edgeSelect, >+ unsigned char busSelect, >+ unsigned char dualEdgeClkSelect, >+ unsigned char hsyncEnable, >+ unsigned char vsyncEnable, >+ unsigned char deskewEnable, >+ unsigned char deskewSetting, >+ unsigned char continuousSyncEnable, >+ unsigned char pllFilterEnable, >+ unsigned char pllFilterValue >+ ) >+{ >+ dvi_ctrl_device_t *pCurrentDviCtrl; >+ pCurrentDviCtrl = g_dcftSupportedDviController; >+ if (pCurrentDviCtrl->pfnInit != NULL) { >+ return pCurrentDviCtrl->pfnInit(edgeSelect, busSelect, >dualEdgeClkSelect, hsyncEnable, >+ vsyncEnable, deskewEnable, deskewSetting, >continuousSyncEnable, >+ pllFilterEnable, pllFilterValue); >+ } >+ return -1; /* error */ >+} >+ >+ >+/* >+ * dviGetVendorID >+ * This function gets the vendor ID of the DVI controller chip. >+ * >+ * Output: >+ * Vendor ID >+ */ >+unsigned short dviGetVendorID() >+{ >+ dvi_ctrl_device_t *pCurrentDviCtrl; >+ >+ /*pCurrentDviCtrl = getDviCtrl();*/ >+ pCurrentDviCtrl = g_dcftSupportedDviController; >+ if (pCurrentDviCtrl != (dvi_ctrl_device_t *)0) >+ return pCurrentDviCtrl->pfnGetVendorId(); >+ >+ return 0x0000; >+} >+ >+ >+/* >+ * dviGetDeviceID >+ * This function gets the device ID of the DVI controller chip. >+ * >+ * Output: >+ * Device ID >+ */ >+unsigned short dviGetDeviceID() >+{ >+ dvi_ctrl_device_t *pCurrentDviCtrl; >+ >+ /* pCurrentDviCtrl = getDviCtrl();*/ >+ pCurrentDviCtrl = g_dcftSupportedDviController; >+ if (pCurrentDviCtrl != (dvi_ctrl_device_t *)0) >+ return pCurrentDviCtrl->pfnGetDeviceId(); >+ >+ return 0x0000; >+} >+ >+#endif >+ >+ >diff --git a/drivers/video/lynxfb/ddk750_dvi.h >b/drivers/video/lynxfb/ddk750_dvi.h >new file mode 100644 >index 0000000..64773fd >--- /dev/null >+++ b/drivers/video/lynxfb/ddk750_dvi.h >@@ -0,0 +1,84 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#ifndef DDK750_DVI_H__ >+#define DDK750_DVI_H__ >+ >+/* dvi chip stuffs structros */ >+ >+typedef long (*PFN_DVICTRL_INIT)( >+ unsigned char edgeSelect, >+ unsigned char busSelect, >+ unsigned char dualEdgeClkSelect, >+ unsigned char hsyncEnable, >+ unsigned char vsyncEnable, >+ unsigned char deskewEnable, >+ unsigned char deskewSetting, >+ unsigned char continuousSyncEnable, >+ unsigned char pllFilterEnable, >+ unsigned char pllFilterValue); >+typedef void (*PFN_DVICTRL_RESETCHIP)(void); >+typedef char* (*PFN_DVICTRL_GETCHIPSTRING)(void); >+typedef unsigned short (*PFN_DVICTRL_GETVENDORID)(void); >+typedef unsigned short (*PFN_DVICTRL_GETDEVICEID)(void); >+typedef void (*PFN_DVICTRL_SETPOWER)(unsigned char powerUp); >+typedef void (*PFN_DVICTRL_HOTPLUGDETECTION)(unsigned char enableHotPlug); >+typedef unsigned char (*PFN_DVICTRL_ISCONNECTED)(void); >+typedef unsigned char (*PFN_DVICTRL_CHECKINTERRUPT)(void); >+typedef void (*PFN_DVICTRL_CLEARINTERRUPT)(void); >+ >+ >+ >+/* Structure to hold all the function pointer to the DVI Controller. */ >+typedef struct _dvi_ctrl_device_t{ >+ PFN_DVICTRL_INIT pfnInit; >+ PFN_DVICTRL_RESETCHIP pfnResetChip; >+ PFN_DVICTRL_GETCHIPSTRING pfnGetChipString; >+ PFN_DVICTRL_GETVENDORID pfnGetVendorId; >+ PFN_DVICTRL_GETDEVICEID pfnGetDeviceId; >+ PFN_DVICTRL_SETPOWER pfnSetPower; >+ PFN_DVICTRL_HOTPLUGDETECTION pfnEnableHotPlugDetection; >+ PFN_DVICTRL_ISCONNECTED pfnIsConnected; >+ PFN_DVICTRL_CHECKINTERRUPT pfnCheckInterrupt; >+ PFN_DVICTRL_CLEARINTERRUPT pfnClearInterrupt; >+} dvi_ctrl_device_t; >+#define DVI_CTRL_SII164 >+ >+ >+ >+/* dvi functions prototype */ >+int dviInit( >+ unsigned char edgeSelect, >+ unsigned char busSelect, >+ unsigned char dualEdgeClkSelect, >+ unsigned char hsyncEnable, >+ unsigned char vsyncEnable, >+ unsigned char deskewEnable, >+ unsigned char deskewSetting, >+ unsigned char continuousSyncEnable, >+ unsigned char pllFilterEnable, >+ unsigned char pllFilterValue >+ ); >+ >+unsigned short dviGetVendorID(void); >+unsigned short dviGetDeviceID(void); >+ >+ >+ >+#endif >+ >diff --git a/drivers/video/lynxfb/ddk750_help.c >b/drivers/video/lynxfb/ddk750_help.c >new file mode 100644 >index 0000000..2e95b58 >--- /dev/null >+++ b/drivers/video/lynxfb/ddk750_help.c >@@ -0,0 +1,37 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+/*#include "ddk750_reg.h" */ >+/*#include "ddk750_chip.h" */ >+#include "ddk750_help.h" >+ >+volatile unsigned char __iomem *mmio750; >+char revId750; >+unsigned short devId750; >+ >+/* after driver mapped io registers, use this function first */ >+void ddk750_set_mmio(volatile unsigned char *addr, unsigned short devId, char >revId) >+{ >+ mmio750 = addr; >+ devId750 = devId; >+ revId750 = revId; >+ if (revId == 0xfe) >+ printk("found sm750le\n"); >+} >+ >+ >diff --git a/drivers/video/lynxfb/ddk750_help.h >b/drivers/video/lynxfb/ddk750_help.h >new file mode 100644 >index 0000000..860c0c1 >--- /dev/null >+++ b/drivers/video/lynxfb/ddk750_help.h >@@ -0,0 +1,42 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#ifndef DDK750_HELP_H__ >+#define DDK750_HELP_H__ >+#include "ddk750_chip.h" >+#ifndef USE_INTERNAL_REGISTER_ACCESS >+ >+#include <linux/ioport.h> >+#include <asm/io.h> >+#include <asm/uaccess.h> >+#include "lynx_help.h" >+ >+ >+ /* software control endianess */ >+#define PEEK32(addr) readl((addr)+mmio750) >+#define POKE32(addr, data) writel((data), (addr)+mmio750) >+ >+ >+extern volatile unsigned char __iomem *mmio750; >+extern char revId750; >+extern unsigned short devId750; >+#else >+/* implement if you want use it*/ >+#endif >+ >+#endif >diff --git a/drivers/video/lynxfb/ddk750_hwi2c.c >b/drivers/video/lynxfb/ddk750_hwi2c.c >new file mode 100644 >index 0000000..c37ff82 >--- /dev/null >+++ b/drivers/video/lynxfb/ddk750_hwi2c.c >@@ -0,0 +1,290 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#ifdef USE_HW_I2C >+#include "ddk750_help.h" >+#include "ddk750_reg.h" >+#include "ddk750_hwi2c.h" >+#include "ddk750_power.h" >+ >+#define MAX_HWI2C_FIFO 16 >+#define HWI2C_WAIT_TIMEOUT 0xF0000 >+ >+ >+int hwI2CInit( >+ unsigned char busSpeedMode >+) >+{ >+ unsigned int value; >+ >+ /* Enable GPIO 30 & 31 as IIC clock & data */ >+ value = PEEK32(GPIO_MUX); >+ >+ value |= (1 << GPIO_MUX_30_LSB)|(1 << GPIO_MUX_31_LSB); >+ POKE32(GPIO_MUX, value); >+ >+ /* Enable Hardware I2C power. >+TODO: Check if we need to enable GPIO power? >+*/ >+ enableI2C(1); >+ >+ /* Enable the I2C Controller and set the bus speed mode */ >+ value = PEEK32(I2C_CTRL); >+ >+ if (busSpeedMode == 0) >+ value &= ~(1 << I2C_CTRL_MODE_LSB); >+ else >+ value |= 1 << I2C_CTRL_MODE_LSB; >+ value |= 1 << I2C_CTRL_EN_LSB; >+ >+ POKE32(I2C_CTRL, value); >+ >+ return 0; >+} >+ >+ >+void hwI2CClose(void) >+{ >+ unsigned int value; >+ >+ /* Disable I2C controller */ >+ value = PEEK32(I2C_CTRL); >+ >+ value &= ~(1 << I2C_CTRL_EN_LSB); >+ POKE32(I2C_CTRL, value); >+ >+ /* Disable I2C Power */ >+ enableI2C(0); >+ >+ /* Set GPIO 30 & 31 back as GPIO pins */ >+ value = PEEK32(GPIO_MUX); >+ value &= ~(1 << GPIO_MUX_30_LSB); >+ value &= ~(1 << GPIO_MUX_31_LSB); >+ POKE32(GPIO_MUX, value); >+} >+ >+ >+long hwI2CWaitTXDone(void) >+{ >+ unsigned int timeout; >+ >+ /* Wait until the transfer is completed. */ >+ timeout = HWI2C_WAIT_TIMEOUT; >+ >+ while (((1&(PEEK32(I2C_STATUS) >> I2C_STATUS_TX_LSB)) != >I2C_STATUS_TX_COMPLETED) && >+ (timeout != 0)) >+ timeout--; >+ >+ if (timeout == 0) >+ return -1; >+ >+ return 0; >+} >+ >+ >+ >+/* >+ * This function writes data to the i2c slave device registers. >+ * >+ * Parameters: >+ * deviceAddress - i2c Slave device address >+ * length - Total number of bytes to be written to the device >+ * pBuffer - The buffer that contains the data to be written to >the >+ * i2c device. >+ * >+ * Return Value: >+ * Total number of bytes those are actually written. >+ */ >+unsigned int hwI2CWriteData( >+ unsigned char deviceAddress, >+ unsigned int length, >+ unsigned char *pBuffer >+ ) >+{ >+ unsigned char count, i; >+ unsigned int totalBytes = 0; >+ >+ /* Set the Device Address */ >+ POKE32(I2C_SLAVE_ADDRESS, deviceAddress & ~0x01); >+ >+ /* Write data. >+ * Note: >+ * Only 16 byte can be accessed per i2c start instruction. >+ */ >+ do { >+ /* Reset I2C by writing 0 to I2C_RESET register to clear the >previous status. */ >+ POKE32(I2C_RESET, 0); >+ >+ /* Set the number of bytes to be written */ >+ if (length < MAX_HWI2C_FIFO) >+ count = length - 1; >+ else >+ count = MAX_HWI2C_FIFO - 1; >+ POKE32(I2C_BYTE_COUNT, count); >+ >+ /* Move the data to the I2C data register */ >+ for (i = 0; i <= count; i++) >+ POKE32(I2C_DATA0 + i, *pBuffer++); >+ >+ /* Start the I2C */ >+ >+ POKE32(I2C_CTRL, PEEK32(I2C_CTRL)|(1 << I2C_CTRL_CTRL_LSB)); >+ >+ /* Wait until the transfer is completed. */ >+ if (hwI2CWaitTXDone() != 0) >+ break; >+ >+ /* Substract length */ >+ length -= (count + 1); >+ >+ /* Total byte written */ >+ totalBytes += (count + 1); >+ >+ } while (length > 0); >+ >+ return totalBytes; >+} >+ >+ >+ >+ >+/* >+ * This function reads data from the slave device and stores them >+ * in the given buffer >+ * >+ * Parameters: >+ * deviceAddress - i2c Slave device address >+ * length - Total number of bytes to be read >+ * pBuffer - Pointer to a buffer to be filled with the data read >+ * from the slave device. It has to be the same size as >the >+ * length to make sure that it can keep all the data read. >+ * >+ * Return Value: >+ * Total number of actual bytes read from the slave device >+ */ >+unsigned int hwI2CReadData( >+ unsigned char deviceAddress, >+ unsigned int length, >+ unsigned char *pBuffer >+ ) >+{ >+ unsigned char count, i; >+ unsigned int totalBytes = 0; >+ >+ /* Set the Device Address */ >+ POKE32(I2C_SLAVE_ADDRESS, deviceAddress | 0x01); >+ >+ /* Read data and save them to the buffer. >+ * Note: >+ * Only 16 byte can be accessed per i2c start instruction. >+ */ >+ do { >+ /* Reset I2C by writing 0 to I2C_RESET register to clear all >the status. */ >+ POKE32(I2C_RESET, 0); >+ >+ /* Set the number of bytes to be read */ >+ if (length <= MAX_HWI2C_FIFO) >+ count = length - 1; >+ else >+ count = MAX_HWI2C_FIFO - 1; >+ POKE32(I2C_BYTE_COUNT, count); >+ >+ /* Start the I2C */ >+ POKE32(I2C_CTRL, PEEK32(I2C_CTRL)|(1 << I2C_CTRL_CTRL_LSB)); >+ >+ /* Wait until transaction done. */ >+ if (hwI2CWaitTXDone() != 0) >+ break; >+ >+ /* Save the data to the given buffer */ >+ for (i = 0; i <= count; i++) >+ *pBuffer++ = PEEK32(I2C_DATA0 + i); >+ >+ /* Substract length by 16 */ >+ length -= (count + 1); >+ >+ /* Number of bytes read. */ >+ totalBytes += (count + 1); >+ >+ } while (length > 0); >+ >+ return totalBytes; >+} >+ >+ >+ >+ >+/* >+ * This function reads the slave device's register >+ * >+ * Parameters: >+ * deviceAddress - i2c Slave device address which register >+ * to be read from >+ * registerIndex - Slave device's register to be read >+ * >+ * Return Value: >+ * Register value >+ */ >+unsigned char hwI2CReadReg( >+ unsigned char deviceAddress, >+ unsigned char registerIndex >+ ) >+{ >+ unsigned char value = (0xFF); >+ >+ if (hwI2CWriteData(deviceAddress, 1, ®isterIndex) == 1) >+ hwI2CReadData(deviceAddress, 1, &value); >+ >+ return value; >+} >+ >+ >+ >+ >+ >+/* >+ * This function writes a value to the slave device's register >+ * >+ * Parameters: >+ * deviceAddress - i2c Slave device address which register >+ * to be written >+ * registerIndex - Slave device's register to be written >+ * data - Data to be written to the register >+ * >+ * Result: >+ * 0 - Success >+ * -1 - Fail >+ */ >+int hwI2CWriteReg( >+ unsigned char deviceAddress, >+ unsigned char registerIndex, >+ unsigned char data >+ ) >+{ >+ unsigned char value[2]; >+ >+ value[0] = registerIndex; >+ value[1] = data; >+ if (hwI2CWriteData(deviceAddress, 2, value) == 2) >+ return 0; >+ >+ return -1; >+} >+ >+ >+#endif >diff --git a/drivers/video/lynxfb/ddk750_hwi2c.h >b/drivers/video/lynxfb/ddk750_hwi2c.h >new file mode 100644 >index 0000000..6cbd292 >--- /dev/null >+++ b/drivers/video/lynxfb/ddk750_hwi2c.h >@@ -0,0 +1,28 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#ifndef DDK750_HWI2C_H__ >+#define DDK750_HWI2C_H__ >+ >+/* hwi2c functions */ >+int hwI2CInit(unsigned char busSpeedMode); >+void hwI2CClose(void); >+ >+unsigned char hwI2CReadReg(unsigned char deviceAddress, unsigned char >registerIndex); >+int hwI2CWriteReg(unsigned char deviceAddress, unsigned char registerIndex, >unsigned char data); >+#endif >diff --git a/drivers/video/lynxfb/ddk750_mode.c >b/drivers/video/lynxfb/ddk750_mode.c >new file mode 100644 >index 0000000..ecb55c2 >--- /dev/null >+++ b/drivers/video/lynxfb/ddk750_mode.c >@@ -0,0 +1,213 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#include "ddk750_help.h" >+#include "ddk750_reg.h" >+#include "ddk750_mode.h" >+#include "ddk750_chip.h" >+ >+/* >+ SM750LE only: >+ This function takes care extra registers and bit fields required to set >+ up a mode in SM750LE >+ >+ Explanation about Display Control register: >+ HW only supports 7 predefined pixel clocks, and clock select is >+ in bit 29:27 of Display Control register. >+ */ >+static unsigned long displayControlAdjust_SM750LE(mode_parameter_t >*pModeParam, unsigned long dispControl) >+{ >+ unsigned long x, y; >+ >+ x = pModeParam->horizontal_display_end; >+ y = pModeParam->vertical_display_end; >+ >+ /* SM750LE has to set up the top-left and bottom-right >+ registers as well. >+ Note that normal SM750/SM718 only use those two register for >+ auto-centering mode. >+ */ >+ POKE32(CRT_AUTO_CENTERING_TL, >+ (~(0x7FF << CRT_AUTO_CENTERING_TL_TOP_LSB))& >+ (~(0x7FF << CRT_AUTO_CENTERING_TL_LEFT_LSB))); >+ >+ /*clear*/ >+ POKE32(CRT_AUTO_CENTERING_BR, >+ (~(0x7FF << CRT_AUTO_CENTERING_BR_BOTTOM_LSB))| >+ (~(0x7FF << CRT_AUTO_CENTERING_BR_RIGHT_LSB))); >+ POKE32(CRT_AUTO_CENTERING_BR, >+ (y-1 << CRT_AUTO_CENTERING_BR_BOTTOM_LSB)| >+ (x-1 << CRT_AUTO_CENTERING_BR_RIGHT_LSB)); >+ /* Clear bit 29:27 of display control register */ >+ dispControl &= ~(7 << CRT_DISPLAY_CTRL_CLK_LSB); >+ /* Assume common fields in dispControl have been properly set before >+ calling this function. >+ This function only sets the extra fields in dispControl. >+ */ >+ >+ >+ /* Set bit 29:27 of display control register for the right clock */ >+ /* Note that SM750LE only need to supported 7 resoluitons. */ >+ dispControl &= (~(7 << CRT_DISPLAY_CTRL_CLK_LSB)); >+ if (x == 800 && y == 600) >+ dispControl |= 1 << CRT_DISPLAY_CTRL_CLK_LSB; >+ else if (x == 1024 && y == 768) >+ dispControl |= 3 << CRT_DISPLAY_CTRL_CLK_LSB; >+ else if (x == 1152 && y == 864) >+ dispControl |= 5 << CRT_DISPLAY_CTRL_CLK_LSB; >+ else if (x == 1280 && y == 768) >+ dispControl |= 5 << CRT_DISPLAY_CTRL_CLK_LSB; >+ else if (x == 1280 && y == 720) >+ dispControl |= 4 << CRT_DISPLAY_CTRL_CLK_LSB; >+ else if (x == 1280 && y == 960) >+ dispControl |= 6 << CRT_DISPLAY_CTRL_CLK_LSB; >+ else if (x == 1280 && y == 1024) >+ dispControl |= 6 << CRT_DISPLAY_CTRL_CLK_LSB; >+ else /* default to VGA clock */ >+ dispControl &= ~(7 << CRT_DISPLAY_CTRL_CLK_LSB); >+ >+ /* Set bit 25:24 of display controller */ >+ dispControl |= 1 << CRT_DISPLAY_CTRL_CRTSELECT_LSB; >+ dispControl &= ~(1 << CRT_DISPLAY_CTRL_RGBBIT_LSB); >+ >+ /* Set bit 14 of display controller */ >+ dispControl |= 1 << CRT_DISPLAY_CTRL_CLOCK_PHASE_LSB; >+ POKE32(CRT_DISPLAY_CTRL, dispControl); >+ >+ return dispControl; >+ >+} >+ >+ >+ >+/* only timing related registers will be programed */ >+static int programModeRegisters(mode_parameter_t *pModeParam, pll_value_t >*pll) >+{ >+ int ret = 0; >+ int cnt = 0; >+ unsigned int ulTmpValue, ulReg; >+ if (pll->clockType == SECONDARY_PLL) { >+ /* programe secondary pixel clock */ >+ POKE32(CRT_PLL_CTRL, formatPllReg(pll)); >+ POKE32(CRT_HORIZONTAL_TOTAL, >+ ((pModeParam->horizontal_total - 1) << >CRT_HORIZONTAL_TOTAL_TOTAL_LSB) >+ |((pModeParam->horizontal_display_end - 1) << >CRT_HORIZONTAL_TOTAL_DISPLAY_END_LSB)); >+ >+ POKE32(CRT_HORIZONTAL_SYNC, >+ (pModeParam->horizontal_sync_width << >CRT_HORIZONTAL_SYNC_WIDTH_LSB) >+ |((pModeParam->horizontal_sync_start - 1) << >CRT_HORIZONTAL_SYNC_START_LSB)); >+ >+ POKE32(CRT_VERTICAL_TOTAL, >+ ((pModeParam->vertical_total - 1) << >CRT_VERTICAL_TOTAL_TOTAL_LSB) >+ |((pModeParam->vertical_display_end - 1) << >CRT_VERTICAL_TOTAL_DISPLAY_END_LSB)); >+ POKE32(CRT_VERTICAL_SYNC, >+ (pModeParam->vertical_sync_height << >CRT_VERTICAL_SYNC_HEIGHT_LSB) >+ |((pModeParam->vertical_sync_start - 1) << >CRT_VERTICAL_SYNC_START_LSB)); >+ >+ >+ ulTmpValue = (pModeParam->vertical_sync_polarity << >CRT_DISPLAY_CTRL_VSYNC_PHASE_LSB)| >+ (pModeParam->horizontal_sync_polarity << >CRT_DISPLAY_CTRL_HSYNC_PHASE_LSB)| >+ (1 << CRT_DISPLAY_CTRL_TIMING_LSB)| >+ (1 << CRT_DISPLAY_CTRL_PLANE_LSB); >+ >+ if (getChipType() == SM750LE) { >+ displayControlAdjust_SM750LE(pModeParam, ulTmpValue); >+ } else{ >+ ulReg = PEEK32(CRT_DISPLAY_CTRL) >+ & (~(1 << CRT_DISPLAY_CTRL_VSYNC_PHASE_LSB)) >+ & (~(1 << CRT_DISPLAY_CTRL_HSYNC_PHASE_LSB)) >+ & (~(1 << CRT_DISPLAY_CTRL_TIMING_LSB)) >+ & (~(1 << CRT_DISPLAY_CTRL_PLANE_LSB)); >+ POKE32(CRT_DISPLAY_CTRL, ulTmpValue|ulReg); >+ } >+ >+ } else if (pll->clockType == PRIMARY_PLL) { >+ unsigned int ulReservedBits; >+ POKE32(PANEL_PLL_CTRL, formatPllReg(pll)); >+ POKE32(PANEL_HORIZONTAL_TOTAL, >+ ((pModeParam->horizontal_total - 1) << >PANEL_HORIZONTAL_TOTAL_TOTAL_LSB) >+ |((pModeParam->horizontal_display_end - 1) << >PANEL_HORIZONTAL_TOTAL_DISPLAY_END_LSB)); >+ >+ POKE32(PANEL_HORIZONTAL_SYNC, >+ (pModeParam->horizontal_sync_width << >PANEL_HORIZONTAL_SYNC_WIDTH_LSB) >+ |((pModeParam->horizontal_sync_start - 1) << >PANEL_HORIZONTAL_SYNC_START_LSB)); >+ >+ POKE32(PANEL_VERTICAL_TOTAL, >+ ((pModeParam->vertical_total - 1) << >PANEL_VERTICAL_TOTAL_TOTAL_LSB) >+ |((pModeParam->vertical_display_end - 1) << >PANEL_VERTICAL_TOTAL_DISPLAY_END_LSB)); >+ >+ POKE32(PANEL_VERTICAL_SYNC, >+ (pModeParam->vertical_sync_height << >PANEL_VERTICAL_SYNC_HEIGHT_LSB) >+ |((pModeParam->vertical_sync_start - 1) << >PANEL_VERTICAL_SYNC_START_LSB)); >+ ulTmpValue |= (pModeParam->vertical_sync_polarity << >PANEL_DISPLAY_CTRL_VSYNC_PHASE_LSB) >+ |(pModeParam->horizontal_sync_polarity << >PANEL_DISPLAY_CTRL_HSYNC_PHASE_LSB) >+ |(pModeParam->clock_phase_polarity << >PANEL_DISPLAY_CTRL_CLOCK_PHASE_LSB) >+ |(1 << PANEL_DISPLAY_CTRL_TIMING_LSB) >+ |(1 << PANEL_DISPLAY_CTRL_PLANE_LSB); >+ ulReservedBits = (3 << PANEL_DISPLAY_CTRL_RESERVED_1_MASK_LSB)| >+ (15 << PANEL_DISPLAY_CTRL_RESERVED_2_MASK_LSB)| >+ (1 << PANEL_DISPLAY_CTRL_RESERVED_3_MASK_LSB)| >+ (1 << PANEL_DISPLAY_CTRL_VSYNC_LSB); >+ ulReg = (PEEK32(PANEL_DISPLAY_CTRL) & ~ulReservedBits) >+ & (~(1 << PANEL_DISPLAY_CTRL_CLOCK_PHASE_LSB)) >+ & (~(1 << PANEL_DISPLAY_CTRL_VSYNC_PHASE_LSB)) >+ & (~(1 << PANEL_DISPLAY_CTRL_HSYNC_PHASE_LSB)) >+ & (~(1 << PANEL_DISPLAY_CTRL_TIMING_LSB)) >+ & (~(1 << PANEL_DISPLAY_CTRL_PLANE_LSB)); >+ >+ /* May a hardware bug or just my test chip (not confirmed). >+ * PANEL_DISPLAY_CTRL register seems requiring few writes >+ * before a value can be succesfully written in. >+ * Added some masks to mask out the reserved bits. >+ * Note: This problem happens by design. The hardware will wait >for the >+ * next vertical sync to turn on/off the plane. >+ */ >+ >+ POKE32(PANEL_DISPLAY_CTRL, ulTmpValue|ulReg); >+ >+ while ((PEEK32(PANEL_DISPLAY_CTRL) & ~ulReservedBits) != >(ulTmpValue|ulReg)) { >+ cnt++; >+ if (cnt > 1000) >+ break; >+ POKE32(PANEL_DISPLAY_CTRL, ulTmpValue|ulReg); >+ } >+ >+ } else{ >+ ret = -1; >+ } >+ return ret; >+} >+ >+int ddk750_setModeTiming(mode_parameter_t *parm, clock_type_t clock) >+{ >+ pll_value_t pll; >+ unsigned int uiActualPixelClk; >+ pll.inputFreq = DEFAULT_INPUT_CLOCK; >+ pll.clockType = clock; >+ >+ uiActualPixelClk = calcPllValue(parm->pixel_clock, &pll); >+ if (getChipType() == SM750LE) { >+ /* set graphic mode via IO method */ >+ outb_p(0x88, 0x3d4); >+ outb_p(0x06, 0x3d5); >+ } >+ programModeRegisters(parm, &pll); >+ return 0; >+} >+ >+ >diff --git a/drivers/video/lynxfb/ddk750_mode.h >b/drivers/video/lynxfb/ddk750_mode.h >new file mode 100644 >index 0000000..7c12b46 >--- /dev/null >+++ b/drivers/video/lynxfb/ddk750_mode.h >@@ -0,0 +1,59 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#ifndef DDK750_MODE_H__ >+#define DDK750_MODE_H__ >+ >+#include "ddk750_chip.h" >+ >+typedef enum _spolarity_t{ >+ POS = 0, /* positive */ >+ NEG, /* negative */ >+} >+spolarity_t; >+ >+ >+typedef struct _mode_parameter_t{ >+ /* Horizontal timing. */ >+ unsigned long horizontal_total; >+ unsigned long horizontal_display_end; >+ unsigned long horizontal_sync_start; >+ unsigned long horizontal_sync_width; >+ spolarity_t horizontal_sync_polarity; >+ >+ /* Vertical timing. */ >+ unsigned long vertical_total; >+ unsigned long vertical_display_end; >+ unsigned long vertical_sync_start; >+ unsigned long vertical_sync_height; >+ spolarity_t vertical_sync_polarity; >+ >+ /* Refresh timing. */ >+ unsigned long pixel_clock; >+ unsigned long horizontal_frequency; >+ unsigned long vertical_frequency; >+ >+ /* Clock Phase. This clock phase only applies to Panel. */ >+ spolarity_t clock_phase_polarity; >+} >+mode_parameter_t; >+ >+int ddk750_setModeTiming(mode_parameter_t *, clock_type_t); >+ >+ >+#endif >diff --git a/drivers/video/lynxfb/ddk750_power.c >b/drivers/video/lynxfb/ddk750_power.c >new file mode 100644 >index 0000000..ad4fbd1 >--- /dev/null >+++ b/drivers/video/lynxfb/ddk750_power.c >@@ -0,0 +1,243 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALLMill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#include "ddk750_help.h" >+#include "ddk750_reg.h" >+#include "ddk750_power.h" >+ >+void ddk750_setDPMS(DPMS_t state) >+{ >+ unsigned int value; >+ if (getChipType() == SM750LE) { >+ value = PEEK32(CRT_DISPLAY_CTRL); >+ value &= (~(3 << CRT_DISPLAY_CTRL_DPMS_LSB)); >+ POKE32(CRT_DISPLAY_CTRL, value|(state << >CRT_DISPLAY_CTRL_DPMS_LSB)); >+ } else{ >+ value = PEEK32(SYSTEM_CTRL); >+ value &= (~(3 << SYSTEM_CTRL_DPMS_LSB)); >+ value |= state << SYSTEM_CTRL_DPMS_LSB; >+ POKE32(SYSTEM_CTRL, value); >+ } >+} >+ >+unsigned int getPowerMode() >+{ >+ if (getChipType() == SM750LE) >+ return 0; >+ return 2&(PEEK32(POWER_MODE_CTRL) >> POWER_MODE_CTRL_MODE_LSB); >+} >+ >+ >+/* >+ * SM50x can operate in one of three modes: 0, 1 or Sleep. >+ * On hardware reset, power mode 0 is default. >+ */ >+void setPowerMode(unsigned int powerMode) >+{ >+ unsigned int control_value = 0; >+ >+ control_value = PEEK32(POWER_MODE_CTRL); >+ control_value &= (~(3 << POWER_MODE_CTRL_MODE_LSB)); >+ if (getChipType() == SM750LE) >+ return; >+ >+ switch (powerMode) { >+ case POWER_MODE_CTRL_MODE_MODE0: >+ control_value &= (~(3 << POWER_MODE_CTRL_MODE_LSB)); >+ break; >+ case POWER_MODE_CTRL_MODE_MODE1: >+ control_value |= 1 << POWER_MODE_CTRL_MODE_LSB; >+ break; >+ >+ case POWER_MODE_CTRL_MODE_SLEEP: >+ control_value |= 2 << POWER_MODE_CTRL_MODE_LSB; >+ break; >+ >+ default: >+ break; >+ } >+ >+ /* Set up other fields in Power Control Register */ >+ if (powerMode == POWER_MODE_CTRL_MODE_SLEEP) { >+ control_value &= >+#ifdef VALIDATION_CHIP >+ (~(1 << POWER_MODE_CTRL_336CLK_LSB))| >+#endif >+ (~(1 << POWER_MODE_CTRL_OSC_INPUT_LSB)); >+ } else{ >+ control_value |= >+#ifdef VALIDATION_CHIP >+ (1 << POWER_MODE_CTRL_336CLK_LSB)| >+#endif >+ (1 << POWER_MODE_CTRL_OSC_INPUT_LSB); >+ } >+ >+ /* Program new power mode. */ >+ POKE32(POWER_MODE_CTRL, control_value); >+} >+ >+void setCurrentGate(unsigned int gate) >+{ >+ unsigned int gate_reg; >+ unsigned int mode; >+ >+ /* Get current power mode. */ >+ mode = getPowerMode(); >+ >+ switch (mode) { >+ case POWER_MODE_CTRL_MODE_MODE0: >+ gate_reg = MODE0_GATE; >+ break; >+ >+ case POWER_MODE_CTRL_MODE_MODE1: >+ gate_reg = MODE1_GATE; >+ break; >+ >+ default: >+ gate_reg = MODE0_GATE; >+ break; >+ } >+ POKE32(gate_reg, gate); >+} >+ >+ >+ >+/* >+ * This function enable/disable the 2D engine. >+ */ >+void enable2DEngine(unsigned int enable) >+{ >+ uint32_t gate; >+ >+ gate = PEEK32(CURRENT_GATE); >+ if (enable) { >+ gate |= 1 << CURRENT_GATE_DE_LSB; >+ gate |= 1 << CURRENT_GATE_CSC_LSB; >+ } else{ >+ gate &= (~(1 << CURRENT_GATE_DE_LSB)); >+ gate &= (~(1 << CURRENT_GATE_CSC_LSB)); >+ } >+ setCurrentGate(gate); >+} >+ >+ >+/* >+ * This function enable/disable the ZV Port. >+ */ >+void enableZVPort(unsigned int enable) >+{ >+ uint32_t gate; >+ >+ /* Enable ZV Port Gate */ >+ gate = PEEK32(CURRENT_GATE); >+ if (enable) { >+ gate |= 1 << CURRENT_GATE_ZVPORT_LSB; >+ >+ /* Using Software I2C */ >+ gate |= 1 << CURRENT_GATE_GPIO_LSB; >+ >+ } else{ >+ /* Disable ZV Port Gate. There is no way to know whether the >GPIO pins are being used >+ or not. Therefore, do not disable the GPIO gate. */ >+ gate &= (~(1 << CURRENT_GATE_ZVPORT_LSB)); >+ } >+ >+ setCurrentGate(gate); >+} >+ >+ >+void enableSSP(unsigned int enable) >+{ >+ uint32_t gate; >+ >+ /* Enable SSP Gate */ >+ gate = PEEK32(CURRENT_GATE); >+ if (enable) >+ gate |= 1 << CURRENT_GATE_SSP_LSB; >+ else >+ gate &= (~(1 << CURRENT_GATE_SSP_LSB)); >+ >+ setCurrentGate(gate); >+} >+ >+void enableDMA(unsigned int enable) >+{ >+ uint32_t gate; >+ >+ /* Enable DMA Gate */ >+ gate = PEEK32(CURRENT_GATE); >+ if (enable) >+ gate |= 1 << CURRENT_GATE_DMA_LSB; >+ else >+ gate &= (~(1 << CURRENT_GATE_DMA_LSB)); >+ >+ setCurrentGate(gate); >+} >+ >+/* >+ * This function enable/disable the GPIO Engine >+ */ >+void enableGPIO(unsigned int enable) >+{ >+ uint32_t gate; >+ >+ /* Enable GPIO Gate */ >+ gate = PEEK32(CURRENT_GATE); >+ if (enable) >+ gate |= 1 << CURRENT_GATE_GPIO_LSB; >+ else >+ gate &= (~(1 << CURRENT_GATE_GPIO_LSB)); >+ >+ setCurrentGate(gate); >+} >+ >+/* >+ * This function enable/disable the PWM Engine >+ */ >+void enablePWM(unsigned int enable) >+{ >+ uint32_t gate; >+ >+ /* Enable PWM Gate */ >+ gate = PEEK32(CURRENT_GATE); >+ if (enable) >+ gate |= 1 << CURRENT_GATE_PWM_LSB; >+ else >+ gate &= (~(1 << CURRENT_GATE_PWM_LSB)); >+ >+ setCurrentGate(gate); >+} >+ >+/* >+ * This function enable/disable the I2C Engine >+ */ >+void enableI2C(unsigned int enable) >+{ >+ uint32_t gate; >+ >+ /* Enable I2C Gate */ >+ gate = PEEK32(CURRENT_GATE); >+ if (enable) >+ gate |= 1 << CURRENT_GATE_I2C_LSB; >+ else >+ gate &= (~(1 << CURRENT_GATE_I2C_LSB)); >+ >+ setCurrentGate(gate); >+} >+ >+ >diff --git a/drivers/video/lynxfb/ddk750_power.h >b/drivers/video/lynxfb/ddk750_power.h >new file mode 100644 >index 0000000..da65b00 >--- /dev/null >+++ b/drivers/video/lynxfb/ddk750_power.h >@@ -0,0 +1,85 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#ifndef DDK750_POWER_H__ >+#define DDK750_POWER_H__ >+ >+typedef enum _DPMS_t{ >+ crtDPMS_ON = 0x0, >+ crtDPMS_STANDBY = 0x1, >+ crtDPMS_SUSPEND = 0x2, >+ crtDPMS_OFF = 0x3, >+} >+DPMS_t; >+ >+#define setDAC(off) \ >+{ \ >+ POKE32(MISC_CTRL, PEEK32(MISC_CTRL)|(off << MISC_CTRL_DAC_POWER_LSB)); >\ >+} >+ >+void ddk750_setDPMS(DPMS_t); >+ >+unsigned int getPowerMode(void); >+ >+/* >+ * This function sets the current power mode >+ */ >+void setPowerMode(unsigned int powerMode); >+ >+/* >+ * This function sets current gate >+ */ >+void setCurrentGate(unsigned int gate); >+ >+/* >+ * This function enable/disable the 2D engine. >+ */ >+void enable2DEngine(unsigned int enable); >+ >+/* >+ * This function enable/disable the ZV Port >+ */ >+void enableZVPort(unsigned int enable); >+ >+/* >+ * This function enable/disable the DMA Engine >+ */ >+void enableDMA(unsigned int enable); >+ >+/* >+ * This function enable/disable the GPIO Engine >+ */ >+void enableGPIO(unsigned int enable); >+ >+/* >+ * This function enable/disable the PWM Engine >+ */ >+void enablePWM(unsigned int enable); >+ >+/* >+ * This function enable/disable the I2C Engine >+ */ >+void enableI2C(unsigned int enable); >+ >+/* >+ * This function enable/disable the SSP. >+ */ >+void enableSSP(unsigned int enable); >+ >+ >+#endif >diff --git a/drivers/video/lynxfb/ddk750_reg.h >b/drivers/video/lynxfb/ddk750_reg.h >new file mode 100644 >index 0000000..e2560bf >--- /dev/null >+++ b/drivers/video/lynxfb/ddk750_reg.h >@@ -0,0 +1,362 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#ifndef DDK750_REG_H__ >+#define DDK750_REG_H__ >+ >+/* New register for SM750LE */ >+#ifdef OPENSOURCE >+#define MISC_CTRL 0x000004 >+#define MISC_CTRL_DAC_POWER_LSB 20 >+#define MISC_CTRL_LOCALMEM_SIZE_LSB 12 >+#define MISC_CTRL_LOCALMEM_SIZE_8M 3 >+#define MISC_CTRL_LOCALMEM_SIZE_16M 0 >+#define MISC_CTRL_LOCALMEM_SIZE_32M 1 >+#define MISC_CTRL_LOCALMEM_SIZE_64M 2 >+#define MISC_CTRL_LOCALMEM_RESET_LSB 6 >+#define SYSTEM_CTRL 0x000000 >+#define SYSTEM_CTRL_DPMS_LSB 30 >+#define SYSTEM_CTRL_DPMS_VPHP 0 >+#define SYSTEM_CTRL_DPMS_VPHN 1 >+#define SYSTEM_CTRL_DPMS_VNHP 2 >+#define SYSTEM_CTRL_DPMS_VNHN 3 >+#define SYSTEM_CTRL_PCI_BURST_LSB 29 >+#define SYSTEM_CTRL_DE_FIFO_LSB 23 >+#define SYSTEM_CTRL_DE_FIFO_NOTEMPTY 0 >+#define SYSTEM_CTRL_DE_FIFO_EMPTY 1 >+#define SYSTEM_CTRL_DE_STATUS_LSB 22 >+#define SYSTEM_CTRL_DE_STATUS_IDLE 0 >+#define SYSTEM_CTRL_DE_STATUS_BUSY 1 >+#define SYSTEM_CTRL_DE_MEM_FIFO_LSB 21 >+#define SYSTEM_CTRL_DE_MEM_FIFO_NOTEMPTY 0 >+#define SYSTEM_CTRL_DE_MEM_FIFO_EMPTY 1 >+#define SYSTEM_CTRL_PANEL_VSYNC_LSB 18 >+#define SYSTEM_CTRL_PANEL_VSYNC_INACTIVE 0 >+#define SYSTEM_CTRL_PANEL_VSYNC_ACTIVE 1 >+#define SYSTEM_CTRL_CRT_VSYNC_LSB 19 >+#define SYSTEM_CTRL_CRT_VSYNC_INACTIVE 0 >+#define SYSTEM_CTRL_CRT_VSYNC_ACTIVE 1 >+#define SYSTEM_CTRL_DE_ABORT_LSB 13 >+ >+#define DE_STATE1 0x100054 >+#define DE_STATE1_DE_ABORT_LSB 0 >+ >+#define DE_STATE2 0x100058 >+#define DE_STATE2_DE_FIFO_LSB 3 >+#define DE_STATE2_DE_FIFO_NOTEMPTY 0 >+#define DE_STATE2_DE_FIFO_EMPTY 1 >+#define DE_STATE2_DE_STATUS_LSB 2 >+#define DE_STATE2_DE_STATUS_IDLE 0 >+#define DE_STATE2_DE_STATUS_BUSY 1 >+#define DE_STATE2_DE_MEM_FIFO_LSB 1 >+#define DE_STATE2_DE_MEM_FIFO_NOTEMPTY 0 >+#define DE_STATE2_DE_MEM_FIFO_EMPTY 1 >+#endif >+ >+#ifdef OPENSOURCE >+#define GPIO_MUX 0x000008 >+#define GPIO_MUX_31_LSB 31 >+#define GPIO_MUX_30_LSB 30 >+#endif >+#define CURRENT_GATE 0x000040 >+#ifdef OPENSOURCE >+#define CURRENT_GATE_M2XCLK_LSB 12 >+#define CURRENT_GATE_MCLK_LSB 14 >+#define CURRENT_GATE_PWM_LSB 9 >+#define CURRENT_GATE_I2C_LSB 8 >+#define CURRENT_GATE_SSP_LSB 7 >+#define CURRENT_GATE_GPIO_LSB 6 >+#define CURRENT_GATE_ZVPORT_LSB 5 >+#define CURRENT_GATE_CSC_LSB 4 >+#define CURRENT_GATE_DE_LSB 3 >+#define MODE0_GATE 0x000044 >+#define CURRENT_GATE_DISPLAY_LSB 2 >+#define CURRENT_GATE_LOCALMEM_LSB 1 >+#define CURRENT_GATE_DMA_LSB 0 >+#endif >+#ifdef OPENSOURCE >+#define MODE0_GATE 0x000044 >+#define MODE0_GATE_I2C_LSB 8 >+#define MODE0_GATE_GPIO_LSB 6 >+#endif >+ >+ >+#ifdef OPENSOURCE >+#define MODE1_GATE 0x000048 >+#define POWER_MODE_CTRL 0x00004C >+#define POWER_MODE_CTRL_MODE_LSB 0 >+#define POWER_MODE_CTRL_MODE_MODE0 0 >+#define POWER_MODE_CTRL_MODE_MODE1 1 >+#define POWER_MODE_CTRL_MODE_SLEEP 2 >+#ifdef VALIDATION_CHIP >+ #define POWER_MODE_CTRL_336CLK_LSB 4 >+#endif >+#define POWER_MODE_CTRL_OSC_INPUT_LSB 3 >+#endif >+ >+#define PLL_CLK_COUNT 0x000058 >+ >+#ifdef OPENSOURCE >+#define PANEL_PLL_CTRL 0x00005C >+#ifdef VALIDATION_CHIP >+ #define PANEL_PLL_CTRL_OD_LSB 14 >+#else >+ #define PANEL_PLL_CTRL_POD_LSB 14 >+ #define PANEL_PLL_CTRL_OD_LSB 12 >+#endif >+#define PANEL_PLL_CTRL_N_LSB 8 >+#define PANEL_PLL_CTRL 0x00005C >+#define PANEL_PLL_CTRL_BYPASS_LSB 18 >+#define PANEL_PLL_CTRL_POWER_LSB 17 >+#define PANEL_PLL_CTRL_POWER_OFF 0 >+#define PANEL_PLL_CTRL_POWER_ON 1 >+#define PANEL_PLL_CTRL_INPUT_LSB 16 >+#ifdef VALIDATION_CHIP >+ #define PANEL_PLL_CTRL_OD_LSB 14 >+#else >+ #define PANEL_PLL_CTRL_POD_LSB 14 >+ #define PANEL_PLL_CTRL_OD_LSB 12 >+#endif >+#define PANEL_PLL_CTRL_N_LSB 8 >+#define PANEL_PLL_CTRL_M_LSB 0 >+#define CRT_PLL_CTRL_POWER_LSB 17 >+#define CRT_PLL_CTRL_POWER_OFF 0 >+#define CRT_PLL_CTRL_POWER_ON 1 >+#endif >+#define MXCLK_PLL_CTRL 0x000070 >+#define CRT_PLL_CTRL 0x000060 >+#define VGA_PLL0_CTRL 0x000064 >+#define VGA_PLL1_CTRL 0x000068 >+ >+#ifdef OPENSOURCE >+#define VGA_CONFIGURATION 0x000088 >+#define VGA_CONFIGURATION_PLL_LSB 2 >+#define VGA_CONFIGURATION_MODE_LSB 1 >+#endif >+ >+#define GPIO_DATA 0x010000 >+#define GPIO_DATA_DIRECTION 0x010004 >+ >+ >+#ifdef OPENSOURCE >+#define PANEL_DISPLAY_CTRL 0x080000 >+#define PANEL_DISPLAY_CTRL_RESERVED_1_MASK_LSB 30 >+#define PANEL_DISPLAY_CTRL_SELECT_LSB 28 >+#define PANEL_DISPLAY_CTRL_RESERVED_2_MASK_LSB 20 >+#define PANEL_DISPLAY_CTRL_RESERVED_3_MASK_LSB 15 >+#define PANEL_DISPLAY_CTRL_FPEN_LSB 27 >+#define PANEL_DISPLAY_CTRL_VBIASEN_LSB 26 >+#define PANEL_DISPLAY_CTRL_DATA_LSB 25 >+#define PANEL_DISPLAY_CTRL_DATA_DISABLE 0 >+#define PANEL_DISPLAY_CTRL_DATA_ENABLE 1 >+#define PANEL_DISPLAY_CTRL_TFT_DISP_LSB 18 >+#define PANEL_DISPLAY_CTRL_TIMING_LSB 8 >+#define PANEL_DISPLAY_CTRL_TIMING_DISABLE 0 >+#define PANEL_DISPLAY_CTRL_TIMING_ENABLE 1 >+#define PANEL_DISPLAY_CTRL_CLOCK_PHASE_LSB 14 >+#define PANEL_DISPLAY_CTRL_VSYNC_PHASE_LSB 13 >+#define PANEL_DISPLAY_CTRL_HSYNC_PHASE_LSB 12 >+#define PANEL_DISPLAY_CTRL_VSYNC_LSB 11 >+#define PANEL_DISPLAY_CTRL_PLANE_LSB 2 >+#define PANEL_DISPLAY_CTRL_FORMAT_LSB 0 >+#endif >+ >+ >+#ifdef OPENSOURCE >+#define PANEL_FB_ADDRESS 0x08000C >+#define PANEL_FB_ADDRESS_STATUS_LSB 31 >+#define PANEL_FB_ADDRESS_EXT_LSB 27 >+#define PANEL_FB_ADDRESS_ADDRESS_LSB 0 >+ >+#define PANEL_FB_WIDTH 0x080010 >+#define PANEL_FB_WIDTH_WIDTH_LSB 16 >+#define PANEL_FB_WIDTH_OFFSET_LSB 0 >+ >+#define PANEL_WINDOW_WIDTH 0x080014 >+#define PANEL_WINDOW_WIDTH_WIDTH_LSB 16 >+#define PANEL_WINDOW_WIDTH_X_LSB 0 >+ >+#define PANEL_WINDOW_HEIGHT 0x080018 >+#define PANEL_WINDOW_HEIGHT_HEIGHT_LSB 16 >+#define PANEL_WINDOW_HEIGHT_Y_LSB 0 >+ >+#define PANEL_PLANE_TL 0x08001C >+#define PANEL_PLANE_TL_TOP_LSB 16 >+#define PANEL_PLANE_TL_LEFT_LSB 0 >+ >+#define PANEL_PLANE_BR 0x080020 >+#define PANEL_PLANE_BR_BOTTOM_LSB 16 >+#define PANEL_PLANE_BR_RIGHT_LSB 0 >+#endif >+ >+ >+#ifdef OPENSOURCE >+#define PANEL_HORIZONTAL_TOTAL 0x080024 >+#define PANEL_HORIZONTAL_TOTAL_TOTAL_LSB 16 >+#define PANEL_HORIZONTAL_TOTAL_DISPLAY_END_LSB 0 >+#define PANEL_HORIZONTAL_SYNC 0x080028 >+#define PANEL_HORIZONTAL_SYNC_WIDTH_LSB 16 >+#define PANEL_HORIZONTAL_SYNC_START_LSB 0 >+#define PANEL_VERTICAL_TOTAL 0x08002C >+#define PANEL_VERTICAL_TOTAL_TOTAL_LSB 16 >+#define PANEL_VERTICAL_TOTAL_DISPLAY_END_LSB 0 >+#define PANEL_VERTICAL_SYNC 0x080030 >+#define PANEL_VERTICAL_SYNC_HEIGHT_LSB 16 >+#define PANEL_VERTICAL_SYNC_START_LSB 0 >+#endif >+ >+ >+/* Video Control */ >+#ifdef OPENSOURCE >+#define VIDEO_DISPLAY_CTRL 0x080040 >+#define VIDEO_DISPLAY_CTRL_PLANE_LSB 2 >+#endif >+/* Alpha Control */ >+#ifdef OPENSOURCE >+#define ALPHA_DISPLAY_CTRL 0x080100 >+#define ALPHA_DISPLAY_CTRL_PLANE_LSB 2 >+#endif >+ >+/* Video Alpha Control */ >+#ifdef OPENSOURCE >+#define VIDEO_ALPHA_DISPLAY_CTRL 0x080080 >+#define VIDEO_ALPHA_DISPLAY_CTRL_PLANE_LSB 2 >+#endif >+ >+/* CRT Graphics Control */ >+#ifdef OPENSOURCE >+#define CRT_DISPLAY_CTRL 0x080200 >+#define CRT_DISPLAY_CTRL_TIMING_LSB 8 >+#define CRT_DISPLAY_CTRL_TIMING_DISABLE 0 >+#define CRT_DISPLAY_CTRL_TIMING_ENABLE 1 >+#define CRT_DISPLAY_CTRL_PLANE_LSB 2 >+#define CRT_DISPLAY_CTRL_CLK_LSB 27 >+#define CRT_DISPLAY_CTRL_RESERVED_1_MASK_LSB 27 >+#define CRT_DISPLAY_CTRL_RESERVED_2_MASK_LSB 24 >+#define CRT_DISPLAY_CTRL_SELECT_LSB 18 >+#define CRT_DISPLAY_CTRL_RESERVED_3_MASK_LSB 15 >+#define CRT_DISPLAY_CTRL_CLOCK_PHASE_LSB 14 >+#define CRT_DISPLAY_CTRL_BLANK_LSB 10 >+#define CRT_DISPLAY_CTRL_BLANK_OFF 0 >+#define CRT_DISPLAY_CTRL_BLANK_ON 1 >+#define CRT_DISPLAY_CTRL_RESERVED_4_MASK_LSB 9 >+/* SM750LE definition */ >+#define CRT_DISPLAY_CTRL_DPMS_LSB 30 >+#define CRT_DISPLAY_CTRL_DPMS_0 0 >+#define CRT_DISPLAY_CTRL_DPMS_1 1 >+#define CRT_DISPLAY_CTRL_DPMS_2 2 >+#define CRT_DISPLAY_CTRL_DPMS_3 3 >+#define CRT_DISPLAY_CTRL_CLK_LSB 27 >+#define CRT_DISPLAY_CTRL_CRTSELECT_LSB 25 >+#define CRT_DISPLAY_CTRL_RGBBIT_LSB 24 >+#define CRT_DISPLAY_CTRL_VSYNC_PHASE_LSB 13 >+#define CRT_DISPLAY_CTRL_HSYNC_PHASE_LSB 12 >+#define CRT_DISPLAY_CTRL_FORMAT_LSB 0 >+#endif >+ >+ >+#ifdef OPENSOURCE >+#define CRT_FB_ADDRESS 0x080204 >+#define CRT_FB_ADDRESS_STATUS_LSB 31 >+#define CRT_FB_ADDRESS_STATUS_CURRENT 0 >+#define CRT_FB_ADDRESS_STATUS_PENDING 1 >+#define CRT_FB_ADDRESS_EXT_LSB 27 >+#define CRT_FB_ADDRESS_EXT_LOCAL 0 >+#define CRT_FB_ADDRESS_EXT_EXTERNAL 1 >+#define CRT_FB_ADDRESS_ADDRESS_LSB 0 >+#endif >+ >+ >+#ifdef OPENSOURCE >+#define CRT_FB_WIDTH 0x080208 >+#define CRT_FB_WIDTH_WIDTH_LSB 16 >+#define CRT_FB_WIDTH_OFFSET_LSB 0 >+#endif >+ >+#ifdef OPENSOURCE >+#define CRT_HORIZONTAL_TOTAL 0x08020C >+#define CRT_HORIZONTAL_TOTAL_TOTAL_LSB 16 >+#define CRT_HORIZONTAL_TOTAL_DISPLAY_END_LSB 0 >+#define CRT_HORIZONTAL_SYNC 0x080210 >+#define CRT_HORIZONTAL_SYNC_WIDTH_LSB 16 >+#define CRT_HORIZONTAL_SYNC_START_LSB 0 >+#define CRT_VERTICAL_TOTAL 0x080214 >+#define CRT_VERTICAL_TOTAL_TOTAL_LSB 16 >+#define CRT_VERTICAL_TOTAL_DISPLAY_END_LSB 0 >+#define CRT_VERTICAL_SYNC 0x080218 >+#define CRT_VERTICAL_SYNC_HEIGHT_LSB 16 >+#define CRT_VERTICAL_SYNC_START_LSB 0 >+#endif >+ >+ >+#ifndef VALIDATION_CHIP >+ /* Auto Centering */ >+#ifdef OPENSOURCE >+ #define CRT_AUTO_CENTERING_TL 0x080280 >+ #define CRT_AUTO_CENTERING_TL_TOP_LSB 16 >+ #define CRT_AUTO_CENTERING_TL_LEFT_LSB 0 >+ #define CRT_AUTO_CENTERING_BR 0x080284 >+ #define CRT_AUTO_CENTERING_BR_BOTTOM_LSB 16 >+ #define CRT_AUTO_CENTERING_BR_RIGHT_LSB 0 >+#endif >+#endif >+ >+/* sm750le new register to control panel output */ >+#define DISPLAY_CONTROL_750LE 0x80288 >+/* Palette RAM */ >+ >+/* Panel Pallete register starts at 0x080400 ~ 0x0807FC */ >+#define PANEL_PALETTE_RAM 0x080400 >+ >+/* Panel Pallete register starts at 0x080C00 ~ 0x080FFC */ >+#define CRT_PALETTE_RAM 0x080C00 >+ >+/* 2D registers >+ * move their defination into general lynx_accel.h file >+ * because all smi graphic chip share the same drawing engine >+ * register format */ >+ >+#ifdef OPENSOURCE >+#define I2C_CTRL 0x010041 >+#define I2C_CTRL_MODE_LSB 1 >+#define I2C_CTRL_EN_LSB 0 >+#define I2C_STATUS 0x010042 >+#define I2C_STATUS_TX_LSB 3 >+#define I2C_CTRL_CTRL_LSB 2 >+#define I2C_STATUS_TX_COMPLETED 1 >+#define I2C_SLAVE_ADDRESS 0x010043 >+#define I2C_RESET 0x010042 >+#define I2C_SLAVE_ADDRESS 0x010043 >+#define I2C_DATA0 0x010044 >+#define I2C_BYTE_COUNT 0x010040 >+#endif >+ >+#ifdef OPENSOURCE >+#define DMA_ABORT_INTERRUPT 0x0D0020 >+#define DMA_ABORT_INTERRUPT_ABORT_1_LSB 5 >+#endif >+ >+ >+ >+/* Default i2c CLK and Data GPIO. These are the default i2c pins */ >+#define DEFAULT_I2C_SCL 30 >+#define DEFAULT_I2C_SDA 31 >+ >+#define GPIO_DATA_SM750LE 0x020018 >+#define GPIO_DATA_DIRECTION_SM750LE 0x02001C >+#endif >diff --git a/drivers/video/lynxfb/ddk750_sii164.c >b/drivers/video/lynxfb/ddk750_sii164.c >new file mode 100644 >index 0000000..6915939 >--- /dev/null >+++ b/drivers/video/lynxfb/ddk750_sii164.c >@@ -0,0 +1,435 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#ifdef USE_DVICHIP >+ >+#include "ddk750_sii164.h" >+#include "ddk750_hwi2c.h" >+ >+/* I2C Address of each SII164 chip */ >+#define SII164_I2C_ADDRESS 0x70 >+ >+/* Define this definition to use hardware i2c. */ >+/*#define USE_HW_I2C*/ >+#ifdef USE_HW_I2C >+#define i2cWriteReg hwI2CWriteReg >+#define i2cReadReg hwI2CReadReg >+#else >+#define i2cWriteReg swI2CWriteReg >+#define i2cReadReg swI2CReadReg >+#endif >+ >+/* SII164 Vendor and Device ID */ >+#define SII164_VENDOR_ID 0x0001 >+#define SII164_DEVICE_ID 0x0006 >+ >+#ifdef SII164_FULL_FUNCTIONS >+/* Name of the DVI Controller chip */ >+static char *gDviCtrlChipName = "Silicon Image SiI 164"; >+#endif >+ >+/* >+ * sii164GetVendorID >+ * This function gets the vendor ID of the DVI controller chip. >+ * >+ * Output: >+ * Vendor ID >+ */ >+unsigned short sii164GetVendorID() >+{ >+ unsigned short vendorID; >+ >+ vendorID = ((unsigned short) i2cReadReg(SII164_I2C_ADDRESS, >SII164_VENDOR_ID_HIGH) << 8) | >+ (unsigned short) i2cReadReg(SII164_I2C_ADDRESS, >SII164_VENDOR_ID_LOW); >+ >+ return vendorID; >+} >+ >+/* >+ * sii164GetDeviceID >+ * This function gets the device ID of the DVI controller chip. >+ * >+ * Output: >+ * Device ID >+ */ >+unsigned short sii164GetDeviceID() >+{ >+ unsigned short deviceID; >+ >+ deviceID = ((unsigned short) i2cReadReg(SII164_I2C_ADDRESS, >SII164_DEVICE_ID_HIGH) << 8) | >+ (unsigned short) i2cReadReg(SII164_I2C_ADDRESS, >SII164_DEVICE_ID_LOW); >+ >+ return deviceID; >+} >+ >+ >+ >+/* DVI.C will handle all SiI164 chip stuffs and try it best to make code >minimal and useful */ >+ >+/* >+ * sii164InitChip >+ * This function initialize and detect the DVI controller chip. >+ * >+ * Input: >+ * edgeSelect - Edge Select: >+ * 0 = Input data is falling edge latched >(falling edge >+ * latched first in dual edge mode) >+ * 1 = Input data is rising edge latched (rising >edge >+ * latched first in dual edge mode) >+ * busSelect - Input Bus Select: >+ * 0 = Input data bus is 12-bits wide >+ * 1 = Input data bus is 24-bits wide >+ * dualEdgeClkSelect - Dual Edge Clock Select >+ * 0 = Input data is single edge latched >+ * 1 = Input data is dual edge latched >+ * hsyncEnable - Horizontal Sync Enable: >+ * 0 = HSYNC input is transmitted as fixed LOW >+ * 1 = HSYNC input is transmitted as is >+ * vsyncEnable - Vertical Sync Enable: >+ * 0 = VSYNC input is transmitted as fixed LOW >+ * 1 = VSYNC input is transmitted as is >+ * deskewEnable - De-skewing Enable: >+ * 0 = De-skew disabled >+ * 1 = De-skew enabled >+ * deskewSetting - De-skewing Setting (increment of 260psec) >+ * 0 = 1 step --> minimum setup / maximum hold >+ * 1 = 2 step >+ * 2 = 3 step >+ * 3 = 4 step >+ * 4 = 5 step >+ * 5 = 6 step >+ * 6 = 7 step >+ * 7 = 8 step --> maximum setup / minimum hold >+ * continuousSyncEnable- SYNC Continuous: >+ * 0 = Disable >+ * 1 = Enable >+ * pllFilterEnable - PLL Filter Enable >+ * 0 = Disable PLL Filter >+ * 1 = Enable PLL Filter >+ * pllFilterValue - PLL Filter characteristics: >+ * 0~7 (recommended value is 4) >+ * >+ * Output: >+ * 0 - Success >+ * -1 - Fail. >+ */ >+long sii164InitChip( >+ unsigned char edgeSelect, >+ unsigned char busSelect, >+ unsigned char dualEdgeClkSelect, >+ unsigned char hsyncEnable, >+ unsigned char vsyncEnable, >+ unsigned char deskewEnable, >+ unsigned char deskewSetting, >+ unsigned char continuousSyncEnable, >+ unsigned char pllFilterEnable, >+ unsigned char pllFilterValue >+ ) >+{ >+ /* unsigned char ucRegIndex, ucRegValue; >+ unsigned char ucDeviceAddress, */ >+ unsigned char config; >+ /* unsigned long delayCount; */ >+ >+ /* Initialize the i2c bus */ >+#ifdef USE_HW_I2C >+ /* Use fast mode. */ >+ hwI2CInit(1); >+#else >+ swI2CInit(DEFAULT_I2C_SCL, DEFAULT_I2C_SDA); >+#endif >+ >+ /* Check if SII164 Chip exists */ >+ if ((sii164GetVendorID() == SII164_VENDOR_ID) && (sii164GetDeviceID() >== SII164_DEVICE_ID)) { >+ >+#ifdef DDKDEBUG >+ /* sii164PrintRegisterValues(); */ >+#endif >+ /* >+ * Initialize SII164 controller chip. >+ */ >+ >+ /* Select the edge */ >+ if (edgeSelect == 0) >+ config = SII164_CONFIGURATION_LATCH_FALLING; >+ else >+ config = SII164_CONFIGURATION_LATCH_RISING; >+ >+ /* Select bus wide */ >+ if (busSelect == 0) >+ config |= SII164_CONFIGURATION_BUS_12BITS; >+ else >+ config |= SII164_CONFIGURATION_BUS_24BITS; >+ >+ /* Select Dual/Single Edge Clock */ >+ if (dualEdgeClkSelect == 0) >+ config |= SII164_CONFIGURATION_CLOCK_SINGLE; >+ else >+ config |= SII164_CONFIGURATION_CLOCK_DUAL; >+ >+ /* Select HSync Enable */ >+ if (hsyncEnable == 0) >+ config |= SII164_CONFIGURATION_HSYNC_FORCE_LOW; >+ else >+ config |= SII164_CONFIGURATION_HSYNC_AS_IS; >+ >+ /* Select VSync Enable */ >+ if (vsyncEnable == 0) >+ config |= SII164_CONFIGURATION_VSYNC_FORCE_LOW; >+ else >+ config |= SII164_CONFIGURATION_VSYNC_AS_IS; >+ >+ i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); >+ >+ /* De-skew enabled with default 111b value. >+ This will fix some artifacts problem in some mode on board >2.2. >+ Somehow this fix does not affect board 2.1. >+ */ >+ if (deskewEnable == 0) >+ config = SII164_DESKEW_DISABLE; >+ else >+ config = SII164_DESKEW_ENABLE; >+ >+ switch (deskewSetting) { >+ case 0: >+ config |= SII164_DESKEW_1_STEP; >+ break; >+ case 1: >+ config |= SII164_DESKEW_2_STEP; >+ break; >+ case 2: >+ config |= SII164_DESKEW_3_STEP; >+ break; >+ case 3: >+ config |= SII164_DESKEW_4_STEP; >+ break; >+ case 4: >+ config |= SII164_DESKEW_5_STEP; >+ break; >+ case 5: >+ config |= SII164_DESKEW_6_STEP; >+ break; >+ case 6: >+ config |= SII164_DESKEW_7_STEP; >+ break; >+ case 7: >+ config |= SII164_DESKEW_8_STEP; >+ break; >+ } >+ i2cWriteReg(SII164_I2C_ADDRESS, SII164_DESKEW, config); >+ >+ /* Enable/Disable Continuous Sync. */ >+ if (continuousSyncEnable == 0) >+ config = SII164_PLL_FILTER_SYNC_CONTINUOUS_DISABLE; >+ else >+ config = SII164_PLL_FILTER_SYNC_CONTINUOUS_ENABLE; >+ >+ /* Enable/Disable PLL Filter */ >+ if (pllFilterEnable == 0) >+ config |= SII164_PLL_FILTER_DISABLE; >+ else >+ config |= SII164_PLL_FILTER_ENABLE; >+ >+ /* Set the PLL Filter value */ >+ config |= ((pllFilterValue & 0x07) << 1); >+ >+ i2cWriteReg(SII164_I2C_ADDRESS, SII164_PLL, config); >+ >+ /* Recover from Power Down and enable output. */ >+ config = i2cReadReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION); >+ config |= SII164_CONFIGURATION_POWER_NORMAL; >+ i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); >+ >+#ifdef DDKDEBUG >+ /* sii164PrintRegisterValues(); */ >+#endif >+ >+ return 0; >+ } >+ >+ /* Return -1 if initialization fails. */ >+ return -1; >+} >+ >+ >+ >+ >+ >+/* below sii164 function is not neccessary */ >+ >+#ifdef SII164_FULL_FUNCTIONS >+ >+/* >+ * sii164ResetChip >+ * This function resets the DVI Controller Chip. >+ */ >+void sii164ResetChip() >+{ >+ /* Power down */ >+ sii164SetPower(0); >+ sii164SetPower(1); >+} >+ >+ >+/* >+ * sii164GetChipString >+ * This function returns a char string name of the current DVI >Controller chip. >+ * It's convenient for application need to display the chip name. >+ */ >+char *sii164GetChipString() >+{ >+ return gDviCtrlChipName; >+} >+ >+ >+/* >+ * sii164SetPower >+ * This function sets the power configuration of the DVI Controller Chip. >+ * >+ * Input: >+ * powerUp - Flag to set the power down or up >+ */ >+void sii164SetPower( >+ unsigned char powerUp >+ ) >+{ >+ unsigned char config; >+ >+ config = i2cReadReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION); >+ if (powerUp == 1) { >+ /* Power up the chip */ >+ config &= ~SII164_CONFIGURATION_POWER_MASK; >+ config |= SII164_CONFIGURATION_POWER_NORMAL; >+ i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); >+ } else{ >+ /* Power down the chip */ >+ config &= ~SII164_CONFIGURATION_POWER_MASK; >+ config |= SII164_CONFIGURATION_POWER_DOWN; >+ i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); >+ } >+} >+ >+ >+/* >+ * sii164SelectHotPlugDetectionMode >+ * This function selects the mode of the hot plug detection. >+ */ >+static void sii164SelectHotPlugDetectionMode( >+ sii164_hot_plug_mode_t hotPlugMode >+ ) >+{ >+ unsigned char detectReg; >+ >+ detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) & >~SII164_DETECT_MONITOR_SENSE_OUTPUT_FLAG; >+ switch (hotPlugMode) { >+ case SII164_HOTPLUG_DISABLE: >+ detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_HIGH; >+ break; >+ case SII164_HOTPLUG_USE_MDI: >+ detectReg &= ~SII164_DETECT_INTERRUPT_MASK; >+ detectReg |= SII164_DETECT_INTERRUPT_BY_HTPLG_PIN; >+ detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_MDI; >+ break; >+ case SII164_HOTPLUG_USE_RSEN: >+ detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_RSEN; >+ break; >+ case SII164_HOTPLUG_USE_HTPLG: >+ detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_HTPLG; >+ break; >+ } >+ >+ i2cWriteReg(SII164_I2C_ADDRESS, SII164_DETECT, detectReg); >+} >+ >+/* >+ * sii164EnableHotPlugDetection >+ * This function enables the Hot Plug detection. >+ * >+ * enableHotPlug - Enable (=1) / disable (=0) Hot Plug detection >+ */ >+void sii164EnableHotPlugDetection( >+ unsigned char enableHotPlug >+ ) >+{ >+ unsigned char detectReg; >+ detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT); >+ >+ /* Depending on each DVI controller, need to enable the hot plug based >on each >+ individual chip design. */ >+ if (enableHotPlug != 0) >+ sii164SelectHotPlugDetectionMode(SII164_HOTPLUG_USE_MDI); >+ else >+ sii164SelectHotPlugDetectionMode(SII164_HOTPLUG_DISABLE); >+} >+ >+/* >+ * sii164IsConnected >+ * Check if the DVI Monitor is connected. >+ * >+ * Output: >+ * 0 - Not Connected >+ * 1 - Connected >+ */ >+unsigned char sii164IsConnected() >+{ >+ unsigned char hotPlugValue; >+ >+ hotPlugValue = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) & >SII164_DETECT_HOT_PLUG_STATUS_MASK; >+ if (hotPlugValue == SII164_DETECT_HOT_PLUG_STATUS_ON) >+ return 1; >+ else >+ return 0; >+} >+ >+/* >+ * sii164CheckInterrupt >+ * Checks if interrupt has occured. >+ * >+ * Output: >+ * 0 - No interrupt >+ * 1 - Interrupt occurs >+ */ >+unsigned char sii164CheckInterrupt() >+{ >+ unsigned char detectReg; >+ >+ detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) & >SII164_DETECT_MONITOR_STATE_MASK; >+ if (detectReg == SII164_DETECT_MONITOR_STATE_CHANGE) >+ return 1; >+ else >+ return 0; >+} >+ >+/* >+ * sii164ClearInterrupt >+ * Clear the hot plug interrupt. >+ */ >+void sii164ClearInterrupt() >+{ >+ unsigned char detectReg; >+ >+ /* Clear the MDI interrupt */ >+ detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT); >+ i2cWriteReg(SII164_I2C_ADDRESS, SII164_DETECT, detectReg | >SII164_DETECT_MONITOR_STATE_CLEAR); >+} >+ >+#endif >+ >+#endif >+ >+ >diff --git a/drivers/video/lynxfb/ddk750_sii164.h >b/drivers/video/lynxfb/ddk750_sii164.h >new file mode 100644 >index 0000000..a279286 >--- /dev/null >+++ b/drivers/video/lynxfb/ddk750_sii164.h >@@ -0,0 +1,187 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#ifndef DDK750_SII164_H__ >+#define DDK750_SII164_H__ >+ >+/* Hot Plug detection mode structure */ >+typedef enum _sii164_hot_plug_mode_t{ >+ SII164_HOTPLUG_DISABLE = 0, /* Disable Hot Plug output bit >(always high). */ >+ SII164_HOTPLUG_USE_MDI, /* Use Monitor Detect Interrupt bit. >*/ >+ SII164_HOTPLUG_USE_RSEN, /* Use Receiver Sense detect bit. */ >+ SII164_HOTPLUG_USE_HTPLG /* Use Hot Plug detect bit. */ >+} sii164_hot_plug_mode_t; >+ >+ >+/* Silicon Image SiI164 chip prototype */ >+long sii164InitChip( >+ unsigned char edgeSelect, >+ unsigned char busSelect, >+ unsigned char dualEdgeClkSelect, >+ unsigned char hsyncEnable, >+ unsigned char vsyncEnable, >+ unsigned char deskewEnable, >+ unsigned char deskewSetting, >+ unsigned char continuousSyncEnable, >+ unsigned char pllFilterEnable, >+ unsigned char pllFilterValue >+); >+ >+unsigned short sii164GetVendorID(void); >+unsigned short sii164GetDeviceID(void); >+ >+ >+#ifdef SII164_FULL_FUNCTIONS >+void sii164ResetChip(void); >+char *sii164GetChipString(void); >+void sii164SetPower(unsigned char powerUp); >+void sii164EnableHotPlugDetection(unsigned char enableHotPlug); >+unsigned char sii164IsConnected(void); >+unsigned char sii164CheckInterrupt(void); >+void sii164ClearInterrupt(void); >+#endif >+/* below register definination is used for Silicon Image SiI164 DVI >controller chip */ >+/* >+ * Vendor ID registers >+ */ >+#define SII164_VENDOR_ID_LOW 0x00 >+#define SII164_VENDOR_ID_HIGH 0x01 >+ >+/* >+ * Device ID registers >+ */ >+#define SII164_DEVICE_ID_LOW 0x02 >+#define SII164_DEVICE_ID_HIGH 0x03 >+ >+/* >+ * Device Revision >+ */ >+#define SII164_DEVICE_REVISION 0x04 >+ >+/* >+ * Frequency Limitation registers >+ */ >+#define SII164_FREQUENCY_LIMIT_LOW 0x06 >+#define SII164_FREQUENCY_LIMIT_HIGH 0x07 >+ >+/* >+ * Power Down and Input Signal Configuration registers >+ */ >+#define SII164_CONFIGURATION 0x08 >+ >+/* Power down (PD) */ >+#define SII164_CONFIGURATION_POWER_DOWN 0x00 >+#define SII164_CONFIGURATION_POWER_NORMAL 0x01 >+#define SII164_CONFIGURATION_POWER_MASK 0x01 >+ >+/* Input Edge Latch Select (EDGE) */ >+#define SII164_CONFIGURATION_LATCH_FALLING 0x00 >+#define SII164_CONFIGURATION_LATCH_RISING 0x02 >+ >+/* Bus Select (BSEL) */ >+#define SII164_CONFIGURATION_BUS_12BITS 0x00 >+#define SII164_CONFIGURATION_BUS_24BITS 0x04 >+ >+/* Dual Edge Clock Select (DSEL) */ >+#define SII164_CONFIGURATION_CLOCK_SINGLE 0x00 >+#define SII164_CONFIGURATION_CLOCK_DUAL 0x08 >+ >+/* Horizontal Sync Enable (HEN) */ >+#define SII164_CONFIGURATION_HSYNC_FORCE_LOW 0x00 >+#define SII164_CONFIGURATION_HSYNC_AS_IS 0x10 >+ >+/* Vertical Sync Enable (VEN) */ >+#define SII164_CONFIGURATION_VSYNC_FORCE_LOW 0x00 >+#define SII164_CONFIGURATION_VSYNC_AS_IS 0x20 >+ >+/* >+ * Detection registers >+ */ >+#define SII164_DETECT 0x09 >+ >+/* Monitor Detect Interrupt (MDI) */ >+#define SII164_DETECT_MONITOR_STATE_CHANGE 0x00 >+#define SII164_DETECT_MONITOR_STATE_NO_CHANGE 0x01 >+#define SII164_DETECT_MONITOR_STATE_CLEAR 0x01 >+#define SII164_DETECT_MONITOR_STATE_MASK 0x01 >+ >+/* Hot Plug detect Input (HTPLG) */ >+#define SII164_DETECT_HOT_PLUG_STATUS_OFF 0x00 >+#define SII164_DETECT_HOT_PLUG_STATUS_ON 0x02 >+#define SII164_DETECT_HOT_PLUG_STATUS_MASK 0x02 >+ >+/* Receiver Sense (RSEN) */ >+#define SII164_DETECT_RECEIVER_SENSE_NOT_DETECTED 0x00 >+#define SII164_DETECT_RECEIVER_SENSE_DETECTED 0x04 >+ >+/* Interrupt Generation Method (TSEL) */ >+#define SII164_DETECT_INTERRUPT_BY_RSEN_PIN 0x00 >+#define SII164_DETECT_INTERRUPT_BY_HTPLG_PIN 0x08 >+#define SII164_DETECT_INTERRUPT_MASK 0x08 >+ >+/* Monitor Sense Output (MSEN) */ >+#define SII164_DETECT_MONITOR_SENSE_OUTPUT_HIGH 0x00 >+#define SII164_DETECT_MONITOR_SENSE_OUTPUT_MDI 0x10 >+#define SII164_DETECT_MONITOR_SENSE_OUTPUT_RSEN 0x20 >+#define SII164_DETECT_MONITOR_SENSE_OUTPUT_HTPLG 0x30 >+#define SII164_DETECT_MONITOR_SENSE_OUTPUT_FLAG 0x30 >+ >+/* >+ * Skewing registers >+ */ >+#define SII164_DESKEW 0x0A >+ >+/* General Purpose Input (CTL[3:1]) */ >+#define SII164_DESKEW_GENERAL_PURPOSE_INPUT_MASK 0x0E >+ >+/* De-skewing Enable bit (DKEN) */ >+#define SII164_DESKEW_DISABLE 0x00 >+#define SII164_DESKEW_ENABLE 0x10 >+ >+/* De-skewing Setting (DK[3:1])*/ >+#define SII164_DESKEW_1_STEP 0x00 >+#define SII164_DESKEW_2_STEP 0x20 >+#define SII164_DESKEW_3_STEP 0x40 >+#define SII164_DESKEW_4_STEP 0x60 >+#define SII164_DESKEW_5_STEP 0x80 >+#define SII164_DESKEW_6_STEP 0xA0 >+#define SII164_DESKEW_7_STEP 0xC0 >+#define SII164_DESKEW_8_STEP 0xE0 >+ >+/* >+ * User Configuration Data registers (CFG 7:0) >+ */ >+#define SII164_USER_CONFIGURATION 0x0B >+ >+/* >+ * PLL registers >+ */ >+#define SII164_PLL 0x0C >+ >+/* PLL Filter Value (PLLF) */ >+#define SII164_PLL_FILTER_VALUE_MASK 0x0E >+ >+/* PLL Filter Enable (PFEN) */ >+#define SII164_PLL_FILTER_DISABLE 0x00 >+#define SII164_PLL_FILTER_ENABLE 0x01 >+ >+/* Sync Continuous (SCNT) */ >+#define SII164_PLL_FILTER_SYNC_CONTINUOUS_DISABLE 0x00 >+#define SII164_PLL_FILTER_SYNC_CONTINUOUS_ENABLE 0x80 >+ >+#endif >diff --git a/drivers/video/lynxfb/ddk750_swi2c.c >b/drivers/video/lynxfb/ddk750_swi2c.c >new file mode 100644 >index 0000000..ff532c7 >--- /dev/null >+++ b/drivers/video/lynxfb/ddk750_swi2c.c >@@ -0,0 +1,522 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#include "ddk750_help.h" >+#include "ddk750_reg.h" >+#include "ddk750_swi2c.h" >+#include "ddk750_power.h" >+ >+ >+/******************************************************************* >+ * I2C Software Master Driver: >+ * =========================== >+ * Each i2c cycle is split into 4 sections. Each of these section marks >+ * a point in time where the SCL or SDA may be changed. >+ * >+ * 1 Cycle == | Section I. | Section 2. | Section 3. | Section 4. | >+ * +-------------+-------------+-------------+-------------+ >+ * | SCL set LOW |SCL no change| SCL set HIGH|SCL no change| >+ * >+ * ____________ _____________ >+ * SCL == XXXX _____________ ____________ / >+ * >+ * I.e. the SCL may only be changed in section 1. and section 3. while >+ * the SDA may only be changed in section 2. and section 4. The table >+ * below gives the changes for these 2 lines in the varios sections. >+ * >+ * Section changes Table: >+ * ====================== >+ * blank = no change, L = set bit LOW, H = set bit HIGH >+ * >+ * | 1.| 2.| 3.| 4.| >+ * ---------------+---+---+---+---+ >+ * Tx Start SDA | | H | | L | >+ * SCL | L | | H | | >+ * ---------------+---+---+---+---+ >+ * Tx Stop SDA | | L | | H | >+ * SCL | L | | H | | >+ * ---------------+---+---+---+---+ >+ * Tx bit H SDA | | H | | | >+ * SCL | L | | H | | >+ * ---------------+---+---+---+---+ >+ * Tx bit L SDA | | L | | | >+ * SCL | L | | H | | >+ * ---------------+---+---+---+---+ >+ * >+ ******************************************************************/ >+ >+/* GPIO pins used for this I2C. It ranges from 0 to 63. */ >+static unsigned char g_i2cClockGPIO = DEFAULT_I2C_SCL; >+static unsigned char g_i2cDataGPIO = DEFAULT_I2C_SDA; >+ >+/* >+ * Below is the variable declaration for the GPIO pin register usage >+ * for the i2c Clock and i2c Data. >+ * >+ * Note: >+ * Notice that the GPIO usage for the i2c clock and i2c Data are >+ * separated. This is to make this code flexible enough when >+ * two separate GPIO pins for the clock and data are located >+ * in two different GPIO register set (worst case). >+ */ >+ >+/* i2c Clock GPIO Register usage */ >+static unsigned long g_i2cClkGPIOMuxReg = GPIO_MUX; >+static unsigned long g_i2cClkGPIODataReg = GPIO_DATA; >+static unsigned long g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION; >+ >+/* i2c Data GPIO Register usage */ >+static unsigned long g_i2cDataGPIOMuxReg = GPIO_MUX; >+static unsigned long g_i2cDataGPIODataReg = GPIO_DATA; >+static unsigned long g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION; >+ >+static unsigned char peekIO(unsigned short port, unsigned short index) >+{ >+#if defined(__i386__) || defined(__x86_64__) >+ outb_p(index, port); >+ return inb_p(port+1); >+#endif >+} >+ >+/* >+ * This function puts a delay between command >+ */ >+static void swI2CWait(void) >+{ >+ /* find a bug: >+ * peekIO method works well before suspend/resume >+ * but after suspend, peekIO(0x3ce,0x61) & 0x10 >+ * always be non-zero,which makes the while loop >+ * never finish. >+ * use non-ultimate for loop below is safe >+ * */ >+ int i, Temp; >+ >+ for (i = 0; i < 600; i++) { >+ Temp = i; >+ Temp += i; >+ } >+} >+ >+/* >+ * This function set/reset the SCL GPIO pin >+ * >+ * Parameters: >+ * value - Bit value to set to the SCL or SDA (0 = low, 1 = high) >+ * >+ * Notes: >+ * When setting SCL to high, just set the GPIO as input where the pull up >+ * resistor will pull the signal up. Do not use software to pull up the >+ * signal because the i2c will fail when other device try to drive the >+ * signal due to SM50x will drive the signal to always high. >+ */ >+void swI2CSCL(unsigned char value) >+{ >+ unsigned long ulGPIOData; >+ unsigned long ulGPIODirection; >+ >+ ulGPIODirection = PEEK32(g_i2cClkGPIODataDirReg); >+ if (value) { /* High */ >+ /* Set direction as input. This will automatically pull the >signal up. */ >+ ulGPIODirection &= ~(1 << g_i2cClockGPIO); >+ POKE32(g_i2cClkGPIODataDirReg, ulGPIODirection); >+ } else{ /* Low */ >+ /* Set the signal down */ >+ ulGPIOData = PEEK32(g_i2cClkGPIODataReg); >+ ulGPIOData &= ~(1 << g_i2cClockGPIO); >+ POKE32(g_i2cClkGPIODataReg, ulGPIOData); >+ >+ /* Set direction as output */ >+ ulGPIODirection |= (1 << g_i2cClockGPIO); >+ POKE32(g_i2cClkGPIODataDirReg, ulGPIODirection); >+ } >+} >+ >+/* >+ * This function set/reset the SDA GPIO pin >+ * >+ * Parameters: >+ * value - Bit value to set to the SCL or SDA (0 = low, 1 = high) >+ * >+ * Notes: >+ * When setting SCL to high, just set the GPIO as input where the pull up >+ * resistor will pull the signal up. Do not use software to pull up the >+ * signal because the i2c will fail when other device try to drive the >+ * signal due to SM50x will drive the signal to always high. >+ */ >+void swI2CSDA(unsigned char value) >+{ >+ unsigned long ulGPIOData; >+ unsigned long ulGPIODirection; >+ >+ ulGPIODirection = PEEK32(g_i2cDataGPIODataDirReg); >+ if (value) { /* High */ >+ /* Set direction as input. This will automatically pull the >signal up. */ >+ ulGPIODirection &= ~(1 << g_i2cDataGPIO); >+ POKE32(g_i2cDataGPIODataDirReg, ulGPIODirection); >+ } else{ /* Low */ >+ /* Set the signal down */ >+ ulGPIOData = PEEK32(g_i2cDataGPIODataReg); >+ ulGPIOData &= ~(1 << g_i2cDataGPIO); >+ POKE32(g_i2cDataGPIODataReg, ulGPIOData); >+ >+ /* Set direction as output */ >+ ulGPIODirection |= (1 << g_i2cDataGPIO); >+ POKE32(g_i2cDataGPIODataDirReg, ulGPIODirection); >+ } >+} >+ >+/* >+ * This function read the data from the SDA GPIO pin >+ * >+ * Return Value: >+ * The SDA data bit sent by the Slave >+ */ >+static unsigned char swI2CReadSDA() >+{ >+ unsigned long ulGPIODirection; >+ unsigned long ulGPIOData; >+ >+ /* Make sure that the direction is input (High) */ >+ ulGPIODirection = PEEK32(g_i2cDataGPIODataDirReg); >+ if ((ulGPIODirection & (1 << g_i2cDataGPIO)) >+ != (~(1 << g_i2cDataGPIO))) { >+ ulGPIODirection &= ~(1 << g_i2cDataGPIO); >+ POKE32(g_i2cDataGPIODataDirReg, ulGPIODirection); >+ } >+ >+ /* Now read the SDA line */ >+ ulGPIOData = PEEK32(g_i2cDataGPIODataReg); >+ if (ulGPIOData & (1 << g_i2cDataGPIO)) >+ return 1; >+ else >+ return 0; >+} >+ >+#pragma optimize("", off) >+ >+/* >+ * This function sends ACK signal >+ */ >+static void swI2CAck(void) >+{ >+ return; /* Single byte read is ok without it. */ >+} >+ >+/* >+ * This function sends the start command to the slave device >+ */ >+void swI2CStart(void) >+{ >+ /* Start I2C */ >+ swI2CSDA(1); >+ swI2CSCL(1); >+ swI2CSDA(0); >+} >+ >+/* >+ * This function sends the stop command to the slave device >+ */ >+void swI2CStop() >+{ >+ /* Stop the I2C */ >+ swI2CSCL(1); >+ swI2CSDA(0); >+ swI2CSDA(1); >+} >+ >+/* >+ * This function writes one byte to the slave device >+ * >+ * Parameters: >+ * data - Data to be write to the slave device >+ * >+ * Return Value: >+ * 0 - Success >+ * -1 - Fail to write byte >+ */ >+long swI2CWriteByte(unsigned char data) >+{ >+ unsigned char value = data; >+ int i; >+ >+ /* Sending the data bit by bit */ >+ for (i = 0; i < 8; i++) { >+ /* Set SCL to low */ >+ swI2CSCL(0); >+ >+ /* Send data bit */ >+ if ((value & 0x80) != 0) >+ swI2CSDA(1); >+ else >+ swI2CSDA(0); >+ >+ swI2CWait(); >+ >+ /* Toggle clk line to one */ >+ swI2CSCL(1); >+ swI2CWait(); >+ >+ /* Shift byte to be sent */ >+ value = value << 1; >+ } >+ >+ /* Set the SCL Low and SDA High (prepare to get input) */ >+ swI2CSCL(0); >+ swI2CSDA(1); >+ >+ /* Set the SCL High for ack */ >+ swI2CWait(); >+ swI2CSCL(1); >+ swI2CWait(); >+ >+ /* Read SDA, until SDA==0 */ >+ for (i = 0; i < 0xff; i++) { >+ if (!swI2CReadSDA()) >+ break; >+ >+ swI2CSCL(0); >+ swI2CWait(); >+ swI2CSCL(1); >+ swI2CWait(); >+ } >+ >+ /* Set the SCL Low and SDA High */ >+ swI2CSCL(0); >+ swI2CSDA(1); >+ >+ if (i < 0xff) >+ return 0; >+ else >+ return -1; >+} >+ >+/* >+ * This function reads one byte from the slave device >+ * >+ * Parameters: >+ * ack - Flag to indicate either to send the acknowledge >+ * message to the slave device or not >+ * >+ * Return Value: >+ * One byte data read from the Slave device >+ */ >+unsigned char swI2CReadByte(unsigned char ack) >+{ >+ int i; >+ unsigned char data = 0; >+ >+ for (i = 7; i >= 0; i--) { >+ /* Set the SCL to Low and SDA to High (Input) */ >+ swI2CSCL(0); >+ swI2CSDA(1); >+ swI2CWait(); >+ >+ /* Set the SCL High */ >+ swI2CSCL(1); >+ swI2CWait(); >+ >+ /* Read data bits from SDA */ >+ data |= (swI2CReadSDA() << i); >+ } >+ >+ if (ack) >+ swI2CAck(); >+ >+ /* Set the SCL Low and SDA High */ >+ swI2CSCL(0); >+ swI2CSDA(1); >+ >+ return data; >+} >+#pragma optimize("", on) >+ >+/* >+ * This function initializes GPIO port for SW I2C communication. >+ * >+ * Parameters: >+ * i2cClkGPIO - The GPIO pin to be used as i2c SCL >+ * i2cDataGPIO - The GPIO pin to be used as i2c SDA >+ * >+ * Return Value: >+ * -1 - Fail to initialize the i2c >+ * 0 - Success >+ */ >+long swI2CInit_SM750LE( >+ unsigned char i2cClkGPIO, >+ unsigned char i2cDataGPIO >+ ) >+{ >+ int i; >+ >+ /* Initialize the GPIO pin for the i2c Clock Register */ >+ g_i2cClkGPIODataReg = GPIO_DATA_SM750LE; >+ g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION_SM750LE; >+ >+ /* Initialize the Clock GPIO Offset */ >+ g_i2cClockGPIO = i2cClkGPIO; >+ >+ /* Initialize the GPIO pin for the i2c Data Register */ >+ g_i2cDataGPIODataReg = GPIO_DATA_SM750LE; >+ g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION_SM750LE; >+ >+ /* Initialize the Data GPIO Offset */ >+ g_i2cDataGPIO = i2cDataGPIO; >+ >+ /* Note that SM750LE don't have GPIO MUX and power is always on */ >+ >+ /* Clear the i2c lines. */ >+ for (i = 0; i < 9; i++) >+ swI2CStop(); >+ >+ return 0; >+} >+ >+/* >+ * This function initializes the i2c attributes and bus >+ * >+ * Parameters: >+ * i2cClkGPIO - The GPIO pin to be used as i2c SCL >+ * i2cDataGPIO - The GPIO pin to be used as i2c SDA >+ * >+ * Return Value: >+ * -1 - Fail to initialize the i2c >+ * 0 - Success >+ */ >+long swI2CInit( >+ unsigned char i2cClkGPIO, >+ unsigned char i2cDataGPIO >+ ) >+{ >+ int i; >+ >+ /* Return 0 if the GPIO pins to be used is out of range. The range is >only from [0..63] */ >+ if ((i2cClkGPIO > 31) || (i2cDataGPIO > 31)) >+ return -1; >+ >+ if (getChipType() == SM750LE) >+ return swI2CInit_SM750LE(i2cClkGPIO, i2cDataGPIO); >+ >+ /* Initialize the GPIO pin for the i2c Clock Register */ >+ g_i2cClkGPIOMuxReg = GPIO_MUX; >+ g_i2cClkGPIODataReg = GPIO_DATA; >+ g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION; >+ >+ /* Initialize the Clock GPIO Offset */ >+ g_i2cClockGPIO = i2cClkGPIO; >+ >+ /* Initialize the GPIO pin for the i2c Data Register */ >+ g_i2cDataGPIOMuxReg = GPIO_MUX; >+ g_i2cDataGPIODataReg = GPIO_DATA; >+ g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION; >+ >+ /* Initialize the Data GPIO Offset */ >+ g_i2cDataGPIO = i2cDataGPIO; >+ >+ /* Enable the GPIO pins for the i2c Clock and Data (GPIO MUX) */ >+ POKE32(g_i2cClkGPIOMuxReg, >+ PEEK32(g_i2cClkGPIOMuxReg) & ~(1 << g_i2cClockGPIO)); >+ POKE32(g_i2cDataGPIOMuxReg, >+ PEEK32(g_i2cDataGPIOMuxReg) & ~(1 << g_i2cDataGPIO)); >+ >+ /* Enable GPIO power */ >+ enableGPIO(1); >+ >+ /* Clear the i2c lines. */ >+ for (i = 0; i < 9; i++) >+ swI2CStop(); >+ >+ return 0; >+} >+ >+/* >+ * This function reads the slave device's register >+ * >+ * Parameters: >+ * deviceAddress - i2c Slave device address which register >+ * to be read from >+ * registerIndex - Slave device's register to be read >+ * >+ * Return Value: >+ * Register value >+ */ >+unsigned char swI2CReadReg( >+ unsigned char deviceAddress, >+ unsigned char registerIndex >+ ) >+{ >+ unsigned char data; >+ >+ /* Send the Start signal */ >+ swI2CStart(); >+ >+ /* Send the device address */ >+ swI2CWriteByte(deviceAddress); >+ >+ /* Send the register index */ >+ swI2CWriteByte(registerIndex); >+ >+ /* Get the bus again and get the data from the device read address */ >+ swI2CStart(); >+ swI2CWriteByte(deviceAddress + 1); >+ data = swI2CReadByte(1); >+ >+ /* Stop swI2C and release the bus */ >+ swI2CStop(); >+ >+ return data; >+} >+ >+/* >+ * This function writes a value to the slave device's register >+ * >+ * Parameters: >+ * deviceAddress - i2c Slave device address which register >+ * to be written >+ * registerIndex - Slave device's register to be written >+ * data - Data to be written to the register >+ * >+ * Result: >+ * 0 - Success >+ * -1 - Fail >+ */ >+long swI2CWriteReg( >+ unsigned char deviceAddress, >+ unsigned char registerIndex, >+ unsigned char data >+ ) >+{ >+ long returnValue = 0; >+ >+ /* Send the Start signal */ >+ swI2CStart(); >+ >+ /* Send the device address and read the data. All should return success >+ in order for the writing processed to be successful >+ */ >+ if ((swI2CWriteByte(deviceAddress) != 0) || >+ (swI2CWriteByte(registerIndex) != 0) || >+ (swI2CWriteByte(data) != 0)) { >+ returnValue = -1; >+ } >+ >+ /* Stop i2c and release the bus */ >+ swI2CStop(); >+ >+ return returnValue; >+} >diff --git a/drivers/video/lynxfb/ddk750_swi2c.h >b/drivers/video/lynxfb/ddk750_swi2c.h >new file mode 100644 >index 0000000..cf42753 >--- /dev/null >+++ b/drivers/video/lynxfb/ddk750_swi2c.h >@@ -0,0 +1,98 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#ifndef _SWI2C_H_ >+#define _SWI2C_H_ >+ >+/* Default i2c CLK and Data GPIO. These are the default i2c pins */ >+#define DEFAULT_I2C_SCL 30 >+#define DEFAULT_I2C_SDA 31 >+ >+/* >+ * This function initializes the i2c attributes and bus >+ * >+ * Parameters: >+ * i2cClkGPIO - The GPIO pin to be used as i2c SCL >+ * i2cDataGPIO - The GPIO pin to be used as i2c SDA >+ * >+ * Return Value: >+ * -1 - Fail to initialize the i2c >+ * 0 - Success >+ */ >+long swI2CInit( >+ unsigned char i2cClkGPIO, >+ unsigned char i2cDataGPIO >+); >+ >+/* >+ * This function reads the slave device's register >+ * >+ * Parameters: >+ * deviceAddress - i2c Slave device address which register >+ * to be read from >+ * registerIndex - Slave device's register to be read >+ * >+ * Return Value: >+ * Register value >+ */ >+unsigned char swI2CReadReg( >+ unsigned char deviceAddress, >+ unsigned char registerIndex >+); >+ >+/* >+ * This function writes a value to the slave device's register >+ * >+ * Parameters: >+ * deviceAddress - i2c Slave device address which register >+ * to be written >+ * registerIndex - Slave device's register to be written >+ * data - Data to be written to the register >+ * >+ * Result: >+ * 0 - Success >+ * -1 - Fail >+ */ >+long swI2CWriteReg( >+ unsigned char deviceAddress, >+ unsigned char registerIndex, >+ unsigned char data >+); >+ >+/* >+ * These two functions are used to toggle the data on the SCL and SDA I2C >lines. >+ * The used of these two functions are not recommended unless it is >necessary. >+ */ >+ >+/* >+ * This function set/reset the SCL GPIO pin >+ * >+ * Parameters: >+ * value - Bit value to set to the SCL or SDA (0 = low, 1 = high) >+ */ >+void swI2CSCL(unsigned char value); >+ >+/* >+ * This function set/reset the SDA GPIO pin >+ * >+ * Parameters: >+ * value - Bit value to set to the SCL or SDA (0 = low, 1 = high) >+ */ >+void swI2CSDA(unsigned char value); >+ >+#endif /* _SWI2C_H_ */ >diff --git a/drivers/video/lynxfb/lynx_accel.c >b/drivers/video/lynxfb/lynx_accel.c >new file mode 100644 >index 0000000..844f90e >--- /dev/null >+++ b/drivers/video/lynxfb/lynx_accel.c >@@ -0,0 +1,417 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#include <linux/version.h> >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) >+#include <linux/config.h> >+#endif >+#include <linux/module.h> >+#include <linux/kernel.h> >+#include <linux/errno.h> >+#include <linux/string.h> >+#include <linux/mm.h> >+#include <linux/slab.h> >+#include <linux/delay.h> >+#include <linux/fb.h> >+#include <linux/ioport.h> >+#include <linux/init.h> >+#include <linux/pci.h> >+#include <linux/vmalloc.h> >+#include <linux/pagemap.h> >+#include <linux/console.h> >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+/* no below two header files in 2.6.9 */ >+#include <linux/platform_device.h> >+#include <linux/screen_info.h> >+#else >+/* nothing by far */ >+#endif >+ >+#include "lynx_drv.h" >+#include "lynx_accel.h" >+#include "lynx_help.h" >+static inline void write_dpr(struct lynx_accel *accel, int offset, u32 >regValue) >+{ >+ writel(regValue, accel->dprBase + offset); >+} >+ >+static inline u32 read_dpr(struct lynx_accel *accel, int offset) >+{ >+ return readl(accel->dprBase + offset); >+} >+ >+static inline void write_dpPort(struct lynx_accel *accel, u32 data) >+{ >+ writel(data, accel->dpPortBase); >+} >+ >+void hw_de_init(struct lynx_accel *accel) >+{ >+ /* setup 2d engine registers */ >+ u32 reg, clr; >+ ENTER(); >+ write_dpr(accel, DE_MASKS, 0xFFFFFFFF); >+ >+ /* dpr1c */ >+ reg = (~(1 << DE_STRETCH_FORMAT_PATTERN_XY_LSB))& >+ (~(1 << DE_STRETCH_FORMAT_PATTERN_Y_LSB))& >+ (~(1 << DE_STRETCH_FORMAT_PATTERN_X_LSB))& >+ (~(15 << DE_STRETCH_FORMAT_ADDRESSING_LSB))| >+ (3 << DE_STRETCH_FORMAT_SOURCE_HEIGHT_LSB); >+ >+ clr &= (~(1 << DE_STRETCH_FORMAT_PATTERN_XY_LSB))& >+ (~(7 << DE_STRETCH_FORMAT_PATTERN_Y_LSB))& >+ (~(7 << DE_STRETCH_FORMAT_PATTERN_X_LSB))& >+ (~(15 << DE_STRETCH_FORMAT_ADDRESSING_LSB))& >+ (~(0xFFF << DE_STRETCH_FORMAT_SOURCE_HEIGHT_LSB)); >+ >+ /* DE_STRETCH bpp format need be initilized in setMode routine */ >+ write_dpr(accel, DE_STRETCH_FORMAT, (read_dpr(accel, DE_STRETCH_FORMAT) >& clr) | reg); >+ >+ /* disable clipping and transparent */ >+ write_dpr(accel, DE_CLIP_TL, 0); >+ write_dpr(accel, DE_CLIP_BR, 0); >+ >+ write_dpr(accel, DE_COLOR_COMPARE_MASK, 0); >+ write_dpr(accel, DE_COLOR_COMPARE, 0); >+ >+ reg = (~(1 << DE_CONTROL_TRANSPARENCY_LSB))& >+ (~(1 << DE_CONTROL_TRANSPARENCY_MATCH_LSB))& >+ (~(1 << DE_CONTROL_TRANSPARENCY_SELECT_LSB)); >+ >+ clr = (~(1 << DE_CONTROL_TRANSPARENCY_LSB))& >+ (~(1 << DE_CONTROL_TRANSPARENCY_MATCH_LSB))& >+ (~(1 << DE_CONTROL_TRANSPARENCY_SELECT_LSB)); >+ >+ /* dpr0c */ >+ write_dpr(accel, DE_CONTROL, (read_dpr(accel, DE_CONTROL)&clr)|reg); >+ LEAVE(); >+} >+ >+/* set2dformat only be called from setmode functions >+ * but if you need dual framebuffer driver, need call set2dformat >+ * every time you use 2d function */ >+ >+void hw_set2dformat(struct lynx_accel *accel, int fmt) >+{ >+ u32 reg; >+ ENTER(); >+ /* fmt=0, 1, 2 for 8, 16, 32, bpp on sm718/750/502 */ >+ reg = read_dpr(accel, DE_STRETCH_FORMAT); >+ reg &= (~(3 << DE_STRETCH_FORMAT_PIXEL_FORMAT_LSB)); >+ reg |= fmt << DE_STRETCH_FORMAT_PIXEL_FORMAT_LSB; >+ write_dpr(accel, DE_STRETCH_FORMAT, reg); >+ LEAVE(); >+} >+ >+int hw_fillrect(struct lynx_accel *accel, >+ u32 base, u32 pitch, u32 Bpp, >+ u32 x, u32 y, u32 width, u32 height, >+ u32 color, u32 rop) >+{ >+ u32 deCtrl; >+ >+ if (accel->de_wait() != 0) { >+ /* int time wait and always busy, seems hardware >+ * got something error */ >+ dbg_msg("%s:De engine always bussy\n", __func__); >+ return -1; >+ } >+ >+ write_dpr(accel, DE_WINDOW_DESTINATION_BASE, base); >+ write_dpr(accel, DE_PITCH, >+ (pitch/Bpp << DE_PITCH_DESTINATION_LSB)| >+ (pitch/Bpp << DE_PITCH_SOURCE_LSB)); >+ >+ write_dpr(accel, DE_WINDOW_WIDTH, >+ (pitch/Bpp << DE_WINDOW_WIDTH_DESTINATION_LSB)| >+ (pitch/Bpp << DE_WINDOW_WIDTH_SOURCE_LSB)); >+ write_dpr(accel, DE_FOREGROUND, color); >+ >+ write_dpr(accel, DE_DESTINATION, (x << DE_DESTINATION_X_LSB)| >+ (y << DE_DESTINATION_Y_LSB)); >+ >+ write_dpr(accel, DE_DIMENSION, >+ (width << DE_DIMENSION_X_LSB)| >+ (height << DE_DIMENSION_Y_ET_LSB)); >+ >+ deCtrl |= >+ (1 << DE_CONTROL_STATUS_LSB)& >+ (~(1 << DE_CONTROL_DIRECTION_LSB))| >+ (1 << DE_CONTROL_LAST_PIXEL_LSB)| >+ (1 << DE_CONTROL_COMMAND_LSB)| >+ (1 << DE_CONTROL_ROP_SELECT_LSB)| >+ (rop << DE_CONTROL_ROP_LSB); >+ write_dpr(accel, DE_CONTROL, deCtrl); >+ return 0; >+} >+ >+int hw_copyarea( >+ struct lynx_accel *accel, >+ unsigned int sBase, /* Address of source: offset in frame >buffer */ >+ unsigned int sPitch, /* Pitch value of source surface in BYTE */ >+ unsigned int sx, >+ unsigned int sy, /* Starting coordinate of source surface */ >+ unsigned int dBase, /* Address of destination: offset in frame >buffer */ >+ unsigned int dPitch, /* Pitch value of destination surface in >BYTE */ >+ unsigned int Bpp, /* Color depth of destination surface */ >+ unsigned int dx, >+ unsigned int dy, /* Starting coordinate of destination surface >*/ >+ unsigned int width, >+ unsigned int height, /* width and height of rectangle in pixel >value */ >+ unsigned int rop2) /* ROP value */ >+{ >+ unsigned int nDirection, de_ctrl; >+ int opSign; >+ nDirection = LEFT_TO_RIGHT; >+ /* Direction of ROP2 operation: 1 = Left to Right, (-1) = Right to Left >*/ >+ opSign = 1; >+ de_ctrl = 0; >+ >+ /* If source and destination are the same surface, need to check for >overlay cases */ >+ if (sBase == dBase && sPitch == dPitch) { >+ >+ /* Determine direction of operation */ >+ if (sy < dy) { >+ >+ /* +----------+ >+ |S | >+ | +----------+ >+ | | | | >+ | | | | >+ +---|------+ | >+ | D| >+ +----------+ */ >+ >+ nDirection = BOTTOM_TO_TOP; >+ } else if (sy > dy) { >+ >+ /* +----------+ >+ |D | >+ | +----------+ >+ | | | | >+ | | | | >+ +---|------+ | >+ | S| >+ +----------+ */ >+ >+ nDirection = TOP_TO_BOTTOM; >+ } else{ >+ >+ /* sy == dy */ >+ >+ if (sx <= dx) { >+ >+ /* +------+---+------+ >+ |S | | D| >+ | | | | >+ | | | | >+ | | | | >+ +------+---+------+ */ >+ >+ nDirection = RIGHT_TO_LEFT; >+ } else{ >+ >+ /* sx > dx */ >+ >+ /* +------+---+------+ >+ |D | | S| >+ | | | | >+ | | | | >+ | | | | >+ +------+---+------+ */ >+ >+ nDirection = LEFT_TO_RIGHT; >+ } >+ } >+ } >+ >+ if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) { >+ >+ sx += width - 1; >+ sy += height - 1; >+ dx += width - 1; >+ dy += height - 1; >+ opSign = (-1); >+ } >+ >+ /* Note: >+ DE_FOREGROUND are DE_BACKGROUND are don't care. >+ DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set >deSetTransparency(). >+ */ >+ >+ /* 2D Source Base. >+ It is an address offset (128 bit aligned) from the beginning of >frame buffer. >+ */ >+ write_dpr(accel, DE_WINDOW_SOURCE_BASE, sBase); >+ >+ /* 2D Destination Base. >+ It is an address offset (128 bit aligned) from the beginning of >frame buffer. >+ */ >+ write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase); >+ >+ >+ { >+ write_dpr(accel, DE_PITCH, >+ ((dPitch/Bpp) << DE_PITCH_DESTINATION_LSB) | >+ ((sPitch/Bpp) << DE_PITCH_SOURCE_LSB)); >+ } >+ >+ /* Screen Window width in Pixels. >+ 2D engine uses this value to calculate the linear address in frame >buffer for a given point. >+ */ >+ write_dpr(accel, DE_WINDOW_WIDTH, >+ ((dPitch/Bpp) << DE_WINDOW_WIDTH_DESTINATION_LSB) | >+ ((sPitch/Bpp) << DE_WINDOW_WIDTH_SOURCE_LSB)); >+ >+ if (accel->de_wait() != 0) { >+ return -1; >+ } >+ >+ { >+ write_dpr(accel, DE_SOURCE, (~(1 << DE_SOURCE_WRAP_LSB))& >+ (sx << DE_SOURCE_X_K1_LSB)| >+ (sy << DE_SOURCE_Y_K2_LSB)); >+ >+ write_dpr(accel, DE_DESTINATION, (dx << DE_DESTINATION_X_LSB)| >+ (dy << DE_DESTINATION_Y_LSB)); >+ >+ write_dpr(accel, DE_DIMENSION, >+ (width << DE_DIMENSION_X_LSB)| >+ (height << DE_DIMENSION_Y_ET_LSB)); >+ >+ de_ctrl = (rop2 << DE_CONTROL_ROP_LSB)| >+ (1 << DE_CONTROL_ROP_SELECT_LSB)& >+ (~(0x1f << DE_CONTROL_COMMAND_LSB))| >+ (1 << DE_CONTROL_STATUS_LSB); >+ >+ if (nDirection == RIGHT_TO_LEFT) >+ de_ctrl |= 1 << DE_CONTROL_DIRECTION_LSB; >+ else >+ de_ctrl &= ~(1 << DE_CONTROL_DIRECTION_LSB); >+ >+ write_dpr(accel, DE_CONTROL, de_ctrl); >+ } >+ >+ return 0; >+} >+ >+static unsigned int deGetTransparency(struct lynx_accel *accel) >+{ >+ unsigned int de_ctrl; >+ >+ de_ctrl = read_dpr(accel, DE_CONTROL); >+ de_ctrl &= >+ (1 << DE_CONTROL_TRANSPARENCY_MATCH_LSB) | >+ (1 << DE_CONTROL_TRANSPARENCY_SELECT_LSB)| >+ (1 << DE_CONTROL_TRANSPARENCY_LSB); >+ return de_ctrl; >+} >+ >+int hw_imageblit( >+ struct lynx_accel *accel, >+ unsigned char *pSrcbuf, /* pointer to start of source buffer in >system memory */ >+ int srcDelta, /* Pitch value (in bytes) of the source buffer, >+ive means top down and -ive mean button up */ >+ unsigned int startBit, /* Mono data can start at any bit in a >byte, this value should be 0 to 7 */ >+ unsigned int dBase, /* Address of destination: offset in frame >buffer */ >+ unsigned int dPitch, /* Pitch value of destination surface in >BYTE */ >+ unsigned int bytePerPixel, /* Color depth of destination >surface */ >+ unsigned int dx, >+ unsigned int dy, /* Starting coordinate of destination surface >*/ >+ unsigned int width, >+ unsigned int height, /* width and height of rectange in pixel >value */ >+ unsigned int fColor, /* Foreground color (corresponding to a 1 >in the monochrome data */ >+ unsigned int bColor, /* Background color (corresponding to a 0 >in the monochrome data */ >+ unsigned int rop2) /* ROP value */ >+{ >+ unsigned int ulBytesPerScan; >+ unsigned int ul4BytesPerScan; >+ unsigned int ulBytesRemain; >+ unsigned int de_ctrl = 0; >+ unsigned char ajRemain[4]; >+ int i, j; >+ >+ startBit &= 7; /* Just make sure the start bit is within legal range */ >+ ulBytesPerScan = (width + startBit + 7) / 8; >+ ul4BytesPerScan = ulBytesPerScan & ~3; >+ ulBytesRemain = ulBytesPerScan & 3; >+ >+ if (accel->de_wait() != 0) { >+ /* inf_msg("*** ImageBlit return -1 ***\n"); */ >+ return -1; >+ } >+ >+ /* 2D Source Base. >+ Use 0 for HOST Blt. >+ */ >+ write_dpr(accel, DE_WINDOW_SOURCE_BASE, 0); >+ >+ /* 2D Destination Base. >+ It is an address offset (128 bit aligned) from the beginning of >frame buffer. >+ */ >+ write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase); >+ { >+ write_dpr(accel, DE_PITCH, >+ (dPitch/bytePerPixel << >DE_PITCH_DESTINATION_LSB) | >+ (dPitch/bytePerPixel << DE_PITCH_SOURCE_LSB)); >+ } >+ >+ /* Screen Window width in Pixels. >+ 2D engine uses this value to calculate the linear address in frame >buffer for a given point. >+ */ >+ write_dpr(accel, DE_WINDOW_WIDTH, >+ ((dPitch/bytePerPixel) << >DE_WINDOW_WIDTH_DESTINATION_LSB) | >+ ((dPitch/bytePerPixel) << DE_WINDOW_WIDTH_SOURCE_LSB)); >+ >+ /* Note: For 2D Source in Host Write, only X_K1_MONO field is needed, >and Y_K2 field is not used. >+ For mono bitmap, use startBit for X_K1. */ >+ write_dpr(accel, DE_SOURCE, startBit << DE_SOURCE_X_K1_MONO); >+ write_dpr(accel, DE_DESTINATION, (dx << DE_DESTINATION_X_LSB)| >+ (dy << DE_DESTINATION_Y_LSB)); >+ >+ write_dpr(accel, DE_DIMENSION, >+ (width << DE_DIMENSION_X_LSB)| >+ (height << DE_DIMENSION_Y_ET_LSB)); >+ write_dpr(accel, DE_FOREGROUND, fColor); >+ write_dpr(accel, DE_BACKGROUND, bColor); >+ >+ de_ctrl = (rop2 << DE_CONTROL_ROP_LSB)| >+ (1 << DE_CONTROL_ROP_SELECT_LSB)| >+ (8 << DE_CONTROL_COMMAND_LSB)| >+ (1 << DE_CONTROL_HOST_LSB)| >+ (1 << DE_CONTROL_STATUS_LSB); >+ write_dpr(accel, DE_CONTROL, de_ctrl | deGetTransparency(accel)); >+ >+ /* Write MONO data (line by line) to 2D Engine data port */ >+ for (i = 0; i < height; i++) { >+ /* For each line, send the data in chunks of 4 bytes */ >+ for (j = 0; j < (ul4BytesPerScan/4); j++) { >+ write_dpPort(accel, *(unsigned int *)(pSrcbuf + (j * >4))); >+ } >+ >+ if (ulBytesRemain) { >+ memcpy(ajRemain, pSrcbuf+ul4BytesPerScan, >ulBytesRemain); >+ write_dpPort(accel, *(unsigned int *)ajRemain); >+ } >+ >+ pSrcbuf += srcDelta; >+ } >+ >+ return 0; >+} >+ >diff --git a/drivers/video/lynxfb/lynx_accel.h >b/drivers/video/lynxfb/lynx_accel.h >new file mode 100644 >index 0000000..328157c >--- /dev/null >+++ b/drivers/video/lynxfb/lynx_accel.h >@@ -0,0 +1,161 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#ifndef ACCEL_H__ >+#define ACCEL_H__ >+ >+#define HW_ROP2_COPY 0xc >+#define HW_ROP2_XOR 0x6 >+ >+/* notes: below address are the offset value from de_base_address (0x100000)*/ >+ >+/* for sm718/750/502 de_base is at mmreg_1mb*/ >+#define DE_BASE_ADDR_TYPE1 0x100000 >+/* for sm712, de_base is at mmreg_32kb */ >+#define DE_BASE_ADDR_TYPE2 0x8000 >+/* for sm722, de_base is at mmreg_0 */ >+#define DE_BASE_ADDR_TYPE3 0 >+ >+/* type1 data port address is at mmreg_0x110000*/ >+#define DE_PORT_ADDR_TYPE1 0x110000 >+/* for sm712, data port address is at mmreg_0 */ >+#define DE_PORT_ADDR_TYPE2 0x100000 >+/* for sm722, data port address is at mmreg_1mb */ >+#define DE_PORT_ADDR_TYPE3 0x100000 >+ >+#define DE_SOURCE 0 >+#define DE_SOURCE_WRAP_LSB 31 >+#define DE_SOURCE_X_K1_LSB 16 >+#define DE_SOURCE_Y_K2_LSB 0 >+#define DE_SOURCE_X_K1_MONO 0 >+ >+#define DE_DESTINATION 0x4 >+#define DE_DESTINATION_WRAP_LSB 31 >+#define DE_DESTINATION_X_LSB 16 >+#define DE_DESTINATION_Y_LSB 0 >+ >+#define DE_DIMENSION 0x8 >+#define DE_DIMENSION_X_LSB 16 >+#define DE_DIMENSION_Y_ET_LSB 0 >+ >+#define DE_CONTROL 0xC >+#define DE_CONTROL_STATUS_LSB 31 >+#define DE_CONTROL_DIRECTION_LSB 27 >+#define DE_CONTROL_HOST_LSB 22 >+#define DE_CONTROL_LAST_PIXEL_LSB 21 >+#define DE_CONTROL_COMMAND_LSB 16 >+#define DE_CONTROL_ROP_SELECT_LSB 15 >+#define DE_CONTROL_ROP2_SOURCE_LSB 14 >+#define DE_CONTROL_TRANSPARENCY_MATCH_LSB 10 >+#define DE_CONTROL_TRANSPARENCY_SELECT_LSB 9 >+#define DE_CONTROL_TRANSPARENCY_LSB 8 >+#define DE_CONTROL_ROP_LSB 0 >+#define DE_MASKS 0x000028 >+#define DE_CLIP_TL 0x00002C >+#define DE_CLIP_BR 0x000030 >+#define DE_COLOR_COMPARE 0x000020 >+#define DE_COLOR_COMPARE_MASK 0x000024 >+#define DE_MONO_PATTERN_LOW 0x000034 >+#define DE_MONO_PATTERN_HIGH 0x000038 >+#define DE_WINDOW_SOURCE_BASE 0x000040 >+#define DE_WINDOW_DESTINATION_BASE 0x000044 >+ >+#define DE_PITCH 0x000010 >+#define DE_PITCH_DESTINATION_LSB 16 >+#define DE_PITCH_SOURCE_LSB 0 >+ >+ >+#define DE_FOREGROUND 0x000014 >+#define DE_BACKGROUND 0x000018 >+ >+#define DE_STRETCH_FORMAT 0x00001C >+#define DE_STRETCH_FORMAT_PATTERN_XY_LSB 30 >+#define DE_STRETCH_FORMAT_PATTERN_Y_LSB 27 >+#define DE_STRETCH_FORMAT_PATTERN_X_LSB 23 >+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_LSB 20 >+#define DE_STRETCH_FORMAT_ADDRESSING_LSB 16 >+#define DE_STRETCH_FORMAT_SOURCE_HEIGHT_LSB 0 >+#define DE_MASKS 0x000028 >+#define DE_CLIP_TL 0x00002C >+#define DE_CLIP_BR 0x000030 >+#define DE_COLOR_COMPARE 0x000020 >+#define DE_COLOR_COMPARE_MASK 0x000024 >+#define DE_MONO_PATTERN_LOW 0x000034 >+#define DE_MONO_PATTERN_HIGH 0x000038 >+#define DE_WINDOW_SOURCE_BASE 0x000040 >+#define DE_WINDOW_DESTINATION_BASE 0x000044 >+ >+ >+ >+#define DE_WINDOW_WIDTH 0x00003C >+#define DE_WINDOW_WIDTH_DESTINATION_LSB 16 >+#define DE_WINDOW_WIDTH_SOURCE_LSB 0 >+ >+ >+ >+/* blt direction */ >+#define TOP_TO_BOTTOM 0 >+#define LEFT_TO_RIGHT 0 >+#define BOTTOM_TO_TOP 1 >+#define RIGHT_TO_LEFT 1 >+ >+void hw_set2dformat(struct lynx_accel *accel, int fmt); >+ >+void hw_de_init(struct lynx_accel *accel); >+ >+int hw_fillrect(struct lynx_accel *accel, >+ u32 base, u32 pitch, u32 Bpp, >+ u32 x, u32 y, u32 width, u32 height, >+ u32 color, u32 rop); >+ >+int hw712_fillrect(struct lynx_accel *accel, >+ u32 base, u32 pitch, u32 Bpp, >+ u32 x, u32 y, u32 width, u32 height, >+ u32 color, u32 rop); >+ >+int hw_copyarea( >+struct lynx_accel *accel, >+unsigned int sBase, /* Address of source: offset in frame buffer */ >+unsigned int sPitch, /* Pitch value of source surface in BYTE */ >+unsigned int sx, >+unsigned int sy, /* Starting coordinate of source surface */ >+unsigned int dBase, /* Address of destination: offset in frame buffer */ >+unsigned int dPitch, /* Pitch value of destination surface in BYTE */ >+unsigned int bpp, /* Color depth of destination surface */ >+unsigned int dx, >+unsigned int dy, /* Starting coordinate of destination surface */ >+unsigned int width, >+unsigned int height, /* width and height of rectangle in pixel value */ >+unsigned int rop2); >+ >+int hw_imageblit( >+struct lynx_accel *accel, >+unsigned char *pSrcbuf, /* pointer to start of source buffer in system memory >*/ >+int srcDelta, /* Pitch value (in bytes) of the source buffer, +ive >means top down and -ive mean button up */ >+unsigned int startBit, /* Mono data can start at any bit in a byte, this >value should be 0 to 7 */ >+unsigned int dBase, /* Address of destination: offset in frame buffer */ >+unsigned int dPitch, /* Pitch value of destination surface in BYTE */ >+unsigned int bytePerPixel, /* Color depth of destination surface */ >+unsigned int dx, >+unsigned int dy, /* Starting coordinate of destination surface */ >+unsigned int width, >+unsigned int height, /* width and height of rectange in pixel value */ >+unsigned int fColor, /* Foreground color (corresponding to a 1 in the >monochrome data */ >+unsigned int bColor, /* Background color (corresponding to a 0 in the >monochrome data */ >+unsigned int rop2); >+#endif >diff --git a/drivers/video/lynxfb/lynx_cursor.c >b/drivers/video/lynxfb/lynx_cursor.c >new file mode 100644 >index 0000000..8aa471f >--- /dev/null >+++ b/drivers/video/lynxfb/lynx_cursor.c >@@ -0,0 +1,223 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#include <linux/version.h> >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) >+#include <linux/config.h> >+#endif >+#include <linux/module.h> >+#include <linux/kernel.h> >+#include <linux/errno.h> >+#include <linux/string.h> >+#include <linux/mm.h> >+#include <linux/slab.h> >+#include <linux/delay.h> >+#include <linux/fb.h> >+#include <linux/ioport.h> >+#include <linux/init.h> >+#include <linux/pci.h> >+#include <linux/vmalloc.h> >+#include <linux/pagemap.h> >+#include <linux/console.h> >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+/* no below two header files in 2.6.9 */ >+#include <linux/platform_device.h> >+#include <linux/screen_info.h> >+#else >+/* nothing by far */ >+#endif >+ >+#include "lynx_drv.h" >+#include "lynx_help.h" >+#include "lynx_cursor.h" >+ >+#define PEEK32(addr) \ >+readl(cursor->mmio + (addr)) >+ >+#define POKE32(addr, data) \ >+writel((data), cursor->mmio + (addr)) >+ >+/* cursor control for voyager and 718/750*/ >+ >+#define HWC_ADDRESS 0x0 >+#define HWC_ADDRESS_ENABLE_LSB 31 >+#define HWC_ADDRESS_EXT_LSB 27 >+#define HWC_ADDRESS_CS 26 >+#define HWC_ADDRESS_ADDRESS_LSB 0 >+#define HWC_LOCATION 0x4 >+#define HWC_LOCATION_TOP_LSB 27 >+#define HWC_LOCATION_Y_LSB 16 >+#define HWC_LOCATION_LEFT 11 >+#define HWC_LOCATION_X_LSB 0 >+#define HWC_COLOR_12 0x8 >+#define HWC_COLOR_3 0xC >+ >+/* hw_cursor_xxx works for voyager, 718 and 750 */ >+void hw_cursor_enable(struct lynx_cursor *cursor) >+{ >+ u32 reg; >+ reg = (cursor->offset << HWC_ADDRESS_ADDRESS_LSB)& >+ (~(1 << HWC_ADDRESS_EXT_LSB))| >+ (1 << HWC_ADDRESS_ENABLE_LSB); >+ POKE32(HWC_ADDRESS, reg); >+} >+void hw_cursor_disable(struct lynx_cursor *cursor) >+{ >+ POKE32(HWC_ADDRESS, 0); >+} >+ >+void hw_cursor_setSize(struct lynx_cursor *cursor, >+ int w, int h) >+{ >+ cursor->w = w; >+ cursor->h = h; >+} >+void hw_cursor_setPos(struct lynx_cursor *cursor, >+ int x, int y) >+{ >+ u32 reg; >+ reg = (y << HWC_LOCATION_Y_LSB)| >+ (x << HWC_LOCATION_X_LSB); >+ POKE32(HWC_LOCATION, reg); >+} >+void hw_cursor_setColor(struct lynx_cursor *cursor, >+ u32 fg, u32 bg) >+{ >+ POKE32(HWC_COLOR_12, (fg<<16)|(bg&0xffff)); >+ POKE32(HWC_COLOR_3, 0xffe0); >+} >+ >+void hw_cursor_setData(struct lynx_cursor *cursor, >+ u16 rop, const u8 *pcol, const u8 *pmsk) >+{ >+ int i, j, count, pitch, offset; >+ u8 color, mask, opr; >+ u16 data; >+ u16 *pbuffer, *pstart; >+ static ulong odd; >+ >+ /* in byte*/ >+ pitch = cursor->w >> 3; >+ >+ /* in byte */ >+ count = pitch * cursor->h; >+ >+ /* in ushort */ >+ offset = cursor->maxW * 2 / 8 / 2; >+ >+ data = 0; >+ pstart = (u16 *)cursor->vstart; >+ pbuffer = pstart; >+ >+/* >+ if (odd &1) { >+ hw_cursor_setData2(cursor, rop, pcol, pmsk); >+ } >+ odd++; >+ if (odd > 0xfffffff0) >+ odd=0; >+*/ >+ >+ for (i = 0; i < count; i++) { >+ >+ color = *pcol++; >+ mask = *pmsk++; >+ data = 0; >+ >+ /* either method below works well, >+ * but method 2 shows no lag >+ * and method 1 seems a bit wrong*/ >+ >+ for (j = 0; j < 8; j++) { >+ if (mask & (0x80>>j)) { >+ if (rop == ROP_XOR) >+ opr = mask ^ color; >+ else >+ opr = mask & color; >+ >+ /* 2 stands for forecolor and 1 for backcolor */ >+ data |= ((opr & (0x80>>j)) ? 2 : 1)<<(j*2); >+ } >+ } >+ >+ *pbuffer = data; >+ >+ /* assume pitch is 1, 2, 4, 8, ...*/ >+ if ((i+1) % pitch == 0) { >+ /* need a return */ >+ pstart += offset; >+ pbuffer = pstart; >+ } else{ >+ pbuffer++; >+ } >+ >+ } >+ >+ >+} >+ >+void hw_cursor_setData2(struct lynx_cursor *cursor, >+ u16 rop, const u8 *pcol, const u8 *pmsk) >+{ >+ int i, j, count, pitch, offset; >+ u8 color, mask, opr; >+ u16 data; >+ u16 *pbuffer, *pstart; >+ >+ /* in byte*/ >+ pitch = cursor->w >> 3; >+ >+ /* in byte */ >+ count = pitch * cursor->h; >+ >+ /* in ushort */ >+ offset = cursor->maxW * 2 / 8 / 2; >+ >+ data = 0; >+ pstart = (u16 *)cursor->vstart; >+ pbuffer = pstart; >+ >+ for (i = 0; i < count; i++) { >+ >+ color = *pcol++; >+ mask = *pmsk++; >+ data = 0; >+ >+ /* either method below works well, but method 2 shows no lag */ >+ >+ for (j = 0; j < 8; j++) { >+ if (mask & (1 << j)) >+ data |= ((color & (1<<j)) ? 1 : 2)<<(j*2); >+ } >+ >+ *pbuffer = data; >+ >+ /* assume pitch is 1, 2, 4, 8, ...*/ >+ if (!(i&(pitch-1))) { >+ >+ >+ /* need a return */ >+ pstart += offset; >+ pbuffer = pstart; >+ } else{ >+ pbuffer++; >+ } >+ >+ } >+ return 0; >+} >diff --git a/drivers/video/lynxfb/lynx_cursor.h >b/drivers/video/lynxfb/lynx_cursor.h >new file mode 100644 >index 0000000..c9aa096 >--- /dev/null >+++ b/drivers/video/lynxfb/lynx_cursor.h >@@ -0,0 +1,36 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#ifndef LYNX_CURSOR_H__ >+#define LYNX_CURSOR_H__ >+ >+/* hw_cursor_xxx works for voyager, 718 and 750 */ >+void hw_cursor_enable(struct lynx_cursor *cursor); >+void hw_cursor_disable(struct lynx_cursor *cursor); >+void hw_cursor_setSize(struct lynx_cursor *cursor, >+ int w, int h); >+void hw_cursor_setPos(struct lynx_cursor *cursor, >+ int x, int y); >+void hw_cursor_setColor(struct lynx_cursor *cursor, >+ u32 fg, u32 bg); >+void hw_cursor_setData(struct lynx_cursor *cursor, >+ u16 rop, const u8 *data, const u8 *mask); >+void hw_cursor_setData2(struct lynx_cursor *cursor, >+ u16 rop, const u8 *data, const u8 *mask); >+ >+#endif >diff --git a/drivers/video/lynxfb/lynx_drv.c b/drivers/video/lynxfb/lynx_drv.c >new file mode 100644 >index 0000000..556902d >--- /dev/null >+++ b/drivers/video/lynxfb/lynx_drv.c >@@ -0,0 +1,1688 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#include <linux/version.h> >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) >+#include <linux/config.h> >+#endif >+#include <linux/kernel.h> >+#include <linux/module.h> >+#include <linux/errno.h> >+#include <linux/string.h> >+#include <linux/mm.h> >+#include <linux/slab.h> >+#include <linux/delay.h> >+#include <linux/fb.h> >+#include <linux/ioport.h> >+#include <linux/init.h> >+#include <linux/pci.h> >+ >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+/* no below two header files in 2.6.9 */ >+#include <linux/platform_device.h> >+#include <linux/vmalloc.h> >+#include <linux/pagemap.h> >+#include <linux/screen_info.h> >+#else >+/* nothing by far */ >+#endif >+#include <linux/vmalloc.h> #include<linux/pagemap.h> >+#include <linux/console.h> >+#ifdef CONFIG_MTRR >+#include <asm/mtrr.h> >+#endif >+ >+#include "lynx_drv.h" >+#include "ver.h" >+#include "lynx_hw750.h" >+#include "lynx_accel.h" >+#include "lynx_cursor.h" >+ >+#include "modedb.c" >+ >+int smi_indent; >+#ifdef MODULE >+static void __exit lynxfb_exit(void); >+#endif >+ >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+static int lynxfb_setup(char *); >+static int __init lynxfb_init(void); >+#else >+int __init lynxfb_setup(char *); >+int __init lynxfb_init(void); >+#endif >+ >+/* chip specific setup routine */ >+static void sm750fb_setup(struct lynx_share *, char *); >+static int __devinit lynxfb_pci_probe(struct pci_dev *, const struct >pci_device_id *); >+static void __devexit lynxfb_pci_remove(struct pci_dev *); >+ >+#ifdef CONFIG_PM >+static int lynxfb_suspend(struct pci_dev *, pm_message_t); >+static int lynxfb_resume(struct pci_dev *); >+#endif >+ >+static int __devinit lynxfb_set_fbinfo(struct fb_info *, int); >+static int lynxfb_ops_check_var(struct fb_var_screeninfo *, struct fb_info *); >+static int lynxfb_ops_set_par(struct fb_info *); >+static int lynxfb_ops_setcolreg(unsigned, unsigned, unsigned, unsigned, >unsigned, struct fb_info *); >+static int lynxfb_ops_blank(int, struct fb_info *); >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+static int lynxfb_ops_cursor(struct fb_info *, struct fb_cursor *); >+#endif >+/* >+#ifdef __BIG_ENDIAN >+ssize_t lynxfb_ops_write(struct fb_info *info, const char __user *buf, >+size_t count, loff_t *ppos); >+ssize_t lynxfb_ops_read(struct fb_info *info, char __user *buf, >+size_t count, loff_t *ppos); >+#endif >+*/ >+ >+typedef void (*PROC_SPEC_SETUP)(struct lynx_share *, char *); >+typedef int (*PROC_SPEC_MAP)(struct lynx_share *, struct pci_dev *); >+typedef int (*PROC_SPEC_INITHW)(struct lynx_share *, struct pci_dev *); >+ >+/* common var for all device */ >+int g_hwcursor = 1; >+int g_noaccel; >+#ifdef CONFIG_MTRR >+int g_nomtrr; >+#endif >+const char *g_fbmode[] = {NULL, NULL}; >+const char *g_def_fbmode = "800x600-16 at 60"; >+char *g_settings; >+int g_dualview; >+#ifdef MODULE >+char *g_option; >+#endif >+ >+/* if not use spin_lock, system will die if user load driver >+ *and immediatly unload driver frequently (dual)*/ >+static inline void myspin_lock(spinlock_t *sl) >+{ >+ struct lynx_share *share; >+ share = container_of(sl, struct lynx_share, slock); >+ if (share->dual) { >+ spin_lock(sl); >+ } >+} >+ >+static inline void myspin_unlock(spinlock_t *sl) >+{ >+ struct lynx_share *share; >+ share = container_of(sl, struct lynx_share, slock); >+ if (share->dual) { >+ spin_unlock(sl); >+ } >+} >+ >+static const struct fb_videomode lynx750_ext[] = { >+ /* 1024x600-60 VESA [1.71:1] */ >+ {NULL, 60, 1024, 600, 20423, 144, 40, 18, 1, 104, 3, >+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, >FB_VMODE_NONINTERLACED}, >+ >+ /* 1024x600-70 VESA */ >+ {NULL, 70, 1024, 600, 17211, 152, 48, 21, 1, 104, 3, >+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, >FB_VMODE_NONINTERLACED}, >+ >+ /* 1024x600-75 VESA */ >+ {NULL, 75, 1024, 600, 15822, 160, 56, 23, 1, 104, 3, >+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, >FB_VMODE_NONINTERLACED}, >+ >+ /* 1024x600-85 VESA */ >+ {NULL, 85, 1024, 600, 13730, 168, 56, 26, 1, 112, 3, >+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, >FB_VMODE_NONINTERLACED}, >+ >+ /* 720x480 */ >+ {NULL, 60, 720, 480, 37427, 88, 16, 13, 1, 72, 3, >+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, >FB_VMODE_NONINTERLACED}, >+ >+ /* 1280x720 [1.78:1] */ >+ {NULL, 60, 1280, 720, 13426, 162, 86, 22, 1, 136, 3, >+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, >FB_VMODE_NONINTERLACED}, >+ >+ /* 1280x768 at 60 */ >+ {NULL, 60, 1280, 768, 12579, 192, 64, 20, 3, 128, 7, >+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, >FB_VMODE_NONINTERLACED}, >+ >+ {NULL, 60, 1360, 768, 11804, 208, 64, 23, 1, 144, 3, >+ FB_SYNC_HOR_HIGH_ACT|FB_VMODE_NONINTERLACED}, >+ >+ /* 1360 x 768 [1.77083:1] */ >+ {NULL, 60, 1360, 768, 11804, 208, 64, 23, 1, 144, 3, >+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, >FB_VMODE_NONINTERLACED}, >+ >+ /* 1368 x 768 [1.78:1] */ >+ {NULL, 60, 1368, 768, 11647, 216, 72, 23, 1, 144, 3, >+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, >FB_VMODE_NONINTERLACED}, >+ >+ /* 1440 x 900 [16:10] */ >+ {NULL, 60, 1440, 900, 9392, 232, 80, 28, 1, 152, 3, >+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED}, >+ >+ /* 1440x960 [15:10] */ >+ {NULL, 60, 1440, 960, 8733, 240, 88, 30, 1, 152, 3, >+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, >FB_VMODE_NONINTERLACED}, >+ >+ /* 1920x1080 [16:9] */ >+ {NULL, 60, 1920, 1080, 6734, 148, 88, 41, 1, 44, 3, >+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED}, >+}; >+ >+ >+static struct pci_device_id smi_pci_table[] = { >+ {PCI_VENDOR_ID_SMI, PCI_DEVID_LYNX_EXP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, >0}, >+ {PCI_VENDOR_ID_SMI, PCI_DEVID_LYNX_SE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, >+ {PCI_VENDOR_ID_SMI, PCI_DEVID_LYNX_EM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, >+ {PCI_VENDOR_ID_SMI, PCI_DEVID_LYNX_3DM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, >0}, >+ {PCI_VENDOR_ID_SMI, PCI_DEVID_VOYAGER, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, >+ {0, } >+}; >+ >+static struct pci_driver lynxfb_driver = { >+ .name = _moduleName_, >+ .id_table = smi_pci_table, >+ .probe = lynxfb_pci_probe, >+ .remove = __devexit_p(lynxfb_pci_remove), >+#ifdef CONFIG_PM >+ .suspend = lynxfb_suspend, >+ .resume = lynxfb_resume, >+#endif >+}; >+ >+ >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+/* no hardware cursor supported under version 2.6.10, kernel bug */ >+static int lynxfb_ops_cursor(struct fb_info *info, struct fb_cursor *fbcursor) >+{ >+ struct lynxfb_par *par; >+ struct lynxfb_crtc *crtc; >+ struct lynx_cursor *cursor; >+ >+ par = info->par; >+ crtc = &par->crtc; >+ cursor = &crtc->cursor; >+ >+ if (fbcursor->image.width > cursor->maxW || >+ fbcursor->image.height > cursor->maxH || >+ fbcursor->image.depth > 1) { >+ return -ENXIO; >+ } >+ >+ cursor->disable(cursor); >+ if (fbcursor->set & FB_CUR_SETSIZE) { >+ cursor->setSize(cursor, fbcursor->image.width, >fbcursor->image.height); >+ } >+ >+ if (fbcursor->set & FB_CUR_SETPOS) { >+ cursor->setPos(cursor, fbcursor->image.dx - info->var.xoffset, >+ fbcursor->image.dy - info->var.yoffset); >+ } >+ >+ if (fbcursor->set & FB_CUR_SETCMAP) { >+ /* get the 16bit color of kernel means */ >+ u16 fg, bg; >+ fg = ((info->cmap.red[fbcursor->image.fg_color] & 0xf800))| >+ ((info->cmap.green[fbcursor->image.fg_color] & 0xfc00) >>> 5)| >+ ((info->cmap.blue[fbcursor->image.fg_color] & 0xf800) >>> 11); >+ >+ bg = ((info->cmap.red[fbcursor->image.bg_color] & 0xf800))| >+ ((info->cmap.green[fbcursor->image.bg_color] & 0xfc00) >>> 5)| >+ ((info->cmap.blue[fbcursor->image.bg_color] & 0xf800) >>> 11); >+ >+ cursor->setColor(cursor, fg, bg); >+ } >+ >+ >+ if (fbcursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { >+ >+ cursor->setData(cursor, >+ fbcursor->rop, >+ fbcursor->image.data, >+ fbcursor->mask); >+ } >+ >+ if (fbcursor->enable) { >+ cursor->enable(cursor); >+ } >+ >+ return 0; >+} >+ >+#endif >+ >+static void lynxfb_ops_fillrect(struct fb_info *info, const struct >fb_fillrect *region) >+{ >+ struct lynxfb_par *par; >+ struct lynx_share *share; >+ unsigned int base, pitch, Bpp, rop; >+ u32 color; >+ >+ if (info->state != FBINFO_STATE_RUNNING) { >+ return; >+ } >+ >+ par = info->par; >+ share = par->share; >+ >+ /* each time 2d function begin to work, below three variable always need >+ *be set, seems we can put them together in some place */ >+ base = par->crtc.oScreen; >+ pitch = info->fix.line_length; >+ Bpp = info->var.bits_per_pixel >> 3; >+ >+ color = (Bpp == 1) ? region->color : ((u32 >*)info->pseudo_palette)[region->color]; >+ rop = (region->rop != ROP_COPY) ? HW_ROP2_XOR : HW_ROP2_COPY; >+ >+ myspin_lock(&share->slock); >+ share->accel.de_fillrect(&share->accel, >+ base, pitch, Bpp, >+ region->dx, region->dy, >+ region->width, region->height, >+ color, rop); >+ myspin_unlock(&share->slock); >+} >+ >+static void lynxfb_ops_copyarea(struct fb_info *info, const struct >fb_copyarea *region) >+{ >+ struct lynxfb_par *par; >+ struct lynx_share *share; >+ unsigned int base, pitch, Bpp; >+ >+ par = info->par; >+ share = par->share; >+ >+ /* each time 2d function begin to work, below three variable always need >+ *be set, seems we can put them together in some place */ >+ base = par->crtc.oScreen; >+ pitch = info->fix.line_length; >+ Bpp = info->var.bits_per_pixel >> 3; >+ >+ myspin_lock(&share->slock); >+ share->accel.de_copyarea(&share->accel, >+ base, pitch, region->sx, region->sy, >+ base, pitch, Bpp, region->dx, region->dy, >+ region->width, region->height, HW_ROP2_COPY); >+ myspin_unlock(&share->slock); >+} >+ >+static void lynxfb_ops_imageblit(struct fb_info *info, const struct fb_image >*image) >+{ >+ unsigned int base, pitch, Bpp; >+ unsigned int fgcol, bgcol; >+ struct lynxfb_par *par; >+ struct lynx_share *share; >+ >+ par = info->par; >+ share = par->share; >+ /* each time 2d function begin to work, below three variable always need >+ *be set, seems we can put them together in some place */ >+ base = par->crtc.oScreen; >+ pitch = info->fix.line_length; >+ Bpp = info->var.bits_per_pixel >> 3; >+ >+ if (image->depth == 1) { >+ if (info->fix.visual == FB_VISUAL_TRUECOLOR || >+ info->fix.visual == FB_VISUAL_DIRECTCOLOR) { >+ fgcol = ((u32 *)info->pseudo_palette)[image->fg_color]; >+ bgcol = ((u32 *)info->pseudo_palette)[image->bg_color]; >+ } else{ >+ fgcol = image->fg_color; >+ bgcol = image->bg_color; >+ } >+ goto _do_work; >+ } >+ return; >+_do_work: >+ myspin_lock(&share->slock); >+ share->accel.de_imageblit(&share->accel, >+ image->data, image->width>>3, 0, >+ base, pitch, Bpp, >+ image->dx, image->dy, >+ image->width, image->height, >+ fgcol, bgcol, HW_ROP2_COPY); >+ myspin_unlock(&share->slock); >+} >+ >+static int lynxfb_ops_pan_display(struct fb_var_screeninfo *var, >+ struct fb_info *info) >+{ >+ struct lynxfb_par *par; >+ struct lynxfb_crtc *crtc; >+ int ret; >+ ENTER(); >+ >+ if (!info) >+ LEAVE(-EINVAL); >+ >+ ret = 0; >+ par = info->par; >+ crtc = &par->crtc; >+ ret = crtc->proc_panDisplay(crtc, var, info); >+ >+ LEAVE(ret); >+} >+ >+static struct fb_ops lynxfb_ops = { >+ .owner = THIS_MODULE, >+ .fb_check_var = lynxfb_ops_check_var, >+ .fb_set_par = lynxfb_ops_set_par, >+ .fb_setcolreg = lynxfb_ops_setcolreg, >+ .fb_blank = lynxfb_ops_blank, >+ /* will be hooked by hardware */ >+ .fb_fillrect = cfb_fillrect, >+ .fb_imageblit = cfb_imageblit, >+ .fb_copyarea = cfb_copyarea, >+ /* cursor */ >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+ .fb_cursor = lynxfb_ops_cursor, >+#else >+ .fb_cursor = soft_cursor, >+#endif >+}; >+ >+static size_t spec_size[] = { >+ [SPC_SM750] = sizeof(struct sm750_share), >+}; >+ >+static PROC_SPEC_SETUP setup_rout[] = { >+ [SPC_SM750] = sm750fb_setup, >+}; >+ >+static PROC_SPEC_MAP map_rout[] = { >+ [SPC_SM750] = hw_sm750_map, >+}; >+ >+static PROC_SPEC_INITHW inithw_rout[] = { >+ [SPC_SM750] = hw_sm750_inithw, >+}; >+static int g_specId; >+ >+#ifdef CONFIG_PM >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) >+static u32 pci_state[16]; >+ >+static int lynxfb_suspend(struct pci_dev *pdev, pm_message_t mesg) >+{ >+ int ret; >+ struct fb_info *info; >+ struct lynx_share *share; >+ >+ ENTER(); >+ ret = 0; >+ share = pci_get_drvdata(pdev); >+ >+ if (mesg != 2 || mesg == pdev->dev.power_state) >+ return ret; >+ >+ /* suspend */ >+ acquire_console_sem(); >+ >+ info = share->fbinfo[0]; >+ if (info) { >+ fb_set_suspend(info, 1); >+ } >+ >+ info = share->fbinfo[1]; >+ >+ if (info) { >+ fb_set_suspend(info, 1); >+ } >+ >+ /* hardware suspend stuffs */ >+ if (mesg == 2 && share->suspend) >+ share->suspend(share); >+ >+ pci_save_state(pdev, &pci_state); >+ pci_disable_device(pdev); >+ ret = pci_set_power_state(pdev, mesg); >+ >+ release_console_sem(); >+ pdev->dev.power_state = mesg; >+ LEAVE(ret); >+} >+ >+static int lynxfb_resume(struct pci_dev *pdev) >+{ >+ int ret; >+ struct fb_info *info; >+ struct lynx_share *share; >+ struct lynxfb_par *par; >+ struct lynxfb_crtc *crtc; >+ struct lynx_cursor *cursor; >+ >+ ENTER(); >+ share = pci_get_drvdata(pdev); >+ ret = 0; >+ >+ acquire_console_sem(); >+ >+ pci_set_power_state(pdev, 0); >+ pci_restore_state(pdev, &pci_state); >+ pci_enable_device(pdev); >+ >+ if (pdev->dev.power_state == 2 && share->resume) >+ share->resume(share); >+ >+ (*inithw_rout[g_specId])(share, pdev); >+ >+ info = share->fbinfo[0]; >+ if (info) { >+ par = info->par; >+ crtc = &par->crtc; >+ cursor = &crtc->cursor; >+ memset(cursor->vstart, 0x0, cursor->size); >+ memset(crtc->vScreen, 0x0, crtc->vidmem_size); >+ lynxfb_ops_set_par(info); >+ fb_set_suspend(info, 0); >+ } >+ >+ info = share->fbinfo[1]; >+ >+ if (info) { >+ par = info->par; >+ crtc = &par->crtc; >+ cursor = &crtc->cursor; >+ memset(cursor->vstart, 0x0, cursor->size); >+ memset(crtc->vScreen, 0x0, crtc->vidmem_size); >+ lynxfb_ops_set_par(info); >+ fb_set_suspend(info, 0); >+ } >+ >+ release_console_sem(); >+ pdev->dev.power_state = 0; >+ LEAVE(ret); >+} >+ >+ >+#else >+static int lynxfb_suspend(struct pci_dev *pdev, pm_message_t mesg) >+{ >+ struct fb_info *info; >+ struct lynx_share *share; >+ int ret; >+ ENTER(); >+ >+ if (mesg.event == pdev->dev.power.power_state.event) >+ LEAVE(0); >+ >+ ret = 0; >+ share = pci_get_drvdata(pdev); >+ switch (mesg.event) { >+ case PM_EVENT_FREEZE: >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) >+ case PM_EVENT_PRETHAW: >+#endif >+ pdev->dev.power.power_state = mesg; >+ LEAVE(0); >+ } >+ >+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35) >+ acquire_console_sem(); >+#else >+ console_lock(); >+#endif >+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24) >+ if (mesg.event & PM_EVENT_SUSPEND) { >+#else >+ if (mesg.event & PM_EVENT_SLEEP) { >+#endif >+ info = share->fbinfo[0]; >+ if (info) >+ fb_set_suspend(info, 1);/* 1 means do suspend*/ >+ >+ info = share->fbinfo[1]; >+ if (info) >+ fb_set_suspend(info, 1);/* 1 means do suspend*/ >+ >+ ret = pci_save_state(pdev); >+ if (ret) { >+ err_msg("error:%d occured in pci_save_state\n", >ret); >+ LEAVE(ret); >+ } >+ >+ /* set chip to sleep mode */ >+ if (share->suspend) >+ (*share->suspend)(share); >+ >+ pci_disable_device(pdev); >+ ret = pci_set_power_state(pdev, pci_choose_state(pdev, >mesg)); >+ if (ret) { >+ err_msg("error:%d occured in >pci_set_power_state\n", ret); >+ LEAVE(ret); >+ } >+ } >+ >+ pdev->dev.power.power_state = mesg; >+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35) >+ release_console_sem(); >+#else >+ console_unlock(); >+#endif >+ LEAVE(ret); >+ } >+ >+ static int lynxfb_resume(struct pci_dev *pdev) >+ { >+ struct fb_info *info; >+ struct lynx_share *share; >+ >+ struct lynxfb_par *par; >+ struct lynxfb_crtc *crtc; >+ struct lynx_cursor *cursor; >+ >+ int ret; >+ ENTER(); >+ >+ ret = 0; >+ share = pci_get_drvdata(pdev); >+ >+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35) >+ acquire_console_sem(); >+#else >+ console_lock(); >+#endif >+ >+ ret = pci_set_power_state(pdev, PCI_D0); >+ if (ret != 0) { >+ err_msg("error:%d occured in pci_set_power_state\n", >ret); >+ LEAVE(ret); >+ } >+ >+ >+ if (pdev->dev.power.power_state.event != PM_EVENT_FREEZE) { >+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35) >+ /* for linux 2.6.35 and lower */ >+ ret = pci_restore_state(pdev); >+ if (ret != 0) { >+ err_msg("error:%d occured in >pci_restore_state\n", ret); >+ LEAVE(ret); >+ } >+#else >+ pci_restore_state(pdev); >+#endif >+ ret = pci_enable_device(pdev); >+ if (ret != 0) { >+ err_msg("error:%d occured in >pci_enable_device\n", ret); >+ LEAVE(ret); >+ } >+ pci_set_master(pdev); >+ } >+ if (share->resume) >+ (*share->resume)(share); >+ >+ (*inithw_rout[g_specId])(share, pdev); >+ >+ >+ info = share->fbinfo[0]; >+ >+ if (info) { >+ par = info->par; >+ crtc = &par->crtc; >+ cursor = &crtc->cursor; >+ memset(cursor->vstart, 0x0, cursor->size); >+ memset(crtc->vScreen, 0x0, crtc->vidmem_size); >+ lynxfb_ops_set_par(info); >+ fb_set_suspend(info, 0); >+ } >+ >+ info = share->fbinfo[1]; >+ >+ if (info) { >+ par = info->par; >+ crtc = &par->crtc; >+ cursor = &crtc->cursor; >+ memset(cursor->vstart, 0x0, cursor->size); >+ memset(crtc->vScreen, 0x0, crtc->vidmem_size); >+ lynxfb_ops_set_par(info); >+ fb_set_suspend(info, 0); >+ } >+ >+ >+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35) >+ release_console_sem(); >+#else >+ console_unlock(); >+#endif >+ LEAVE(ret); >+ } >+#endif >+#endif >+ >+static int lynxfb_ops_check_var(struct fb_var_screeninfo *var, struct fb_info >*info) >+{ >+ struct lynxfb_par *par; >+ struct lynxfb_crtc *crtc; >+ struct lynxfb_output *output; >+ struct lynx_share *share; >+ int ret; >+ resource_size_t request; >+ >+ ENTER(); >+ par = info->par; >+ crtc = &par->crtc; >+ output = &par->output; >+ share = par->share; >+ ret = 0; >+ >+ dbg_msg("check var:%dx%d-%d\n", >+ var->xres, >+ var->yres, >+ var->bits_per_pixel); >+ >+ >+ switch (var->bits_per_pixel) { >+ case 8: >+ case 16: >+ case 24: /* support 24 bpp for only lynx712/722/720 */ >+ case 32: >+ break; >+ default: >+ err_msg("bpp %d not supported\n", var->bits_per_pixel); >+ ret = -EINVAL; >+ goto exit; >+ } >+ >+ switch (var->bits_per_pixel) { >+ case 8: >+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR; >+ var->red.offset = 0; >+ var->red.length = 8; >+ var->green.offset = 0; >+ var->green.length = 8; >+ var->blue.offset = 0; >+ var->blue.length = 8; >+ var->transp.length = 0; >+ var->transp.offset = 0; >+ break; >+ case 16: >+ var->red.offset = 11; >+ var->red.length = 5; >+ var->green.offset = 5; >+ var->green.length = 6; >+ var->blue.offset = 0; >+ var->blue.length = 5; >+ var->transp.length = 0; >+ var->transp.offset = 0; >+ info->fix.visual = FB_VISUAL_TRUECOLOR; >+ break; >+ case 24: >+ case 32: >+ var->red.offset = 16; >+ var->red.length = 8; >+ var->green.offset = 8; >+ var->green.length = 8; >+ var->blue.offset = 0 ; >+ var->blue.length = 8; >+ info->fix.visual = FB_VISUAL_TRUECOLOR; >+ break; >+ default: >+ ret = -EINVAL; >+ break; >+ } >+ var->height = var->width = -1; >+ var->accel_flags = FB_ACCELF_TEXT; >+ >+ /* check if current fb's video memory big enought to hold the onscreen >*/ >+ request = var->xres_virtual * (var->bits_per_pixel >> 3); >+ /* defaulty crtc->channel go with par->index */ >+ >+ request = PADDING(crtc->line_pad, request); >+ request = request * var->yres_virtual; >+ if (crtc->vidmem_size < request) { >+ err_msg("not enough video memory for mode\n"); >+ LEAVE(-ENOMEM); >+ } >+ >+ ret = output->proc_checkMode(output, var); >+ if (!ret) >+ ret = crtc->proc_checkMode(crtc, var); >+exit: >+ LEAVE(ret); >+} >+ >+static int lynxfb_ops_set_par(struct fb_info *info) >+{ >+ struct lynxfb_par *par; >+ struct lynx_share *share; >+ struct lynxfb_crtc *crtc; >+ struct lynxfb_output *output; >+ struct fb_var_screeninfo *var; >+ struct fb_fix_screeninfo *fix; >+ int ret; >+ unsigned int line_length; >+ ENTER(); >+ >+ if (!info) >+ LEAVE(-EINVAL); >+ >+ ret = 0; >+ par = info->par; >+ share = par->share; >+ crtc = &par->crtc; >+ output = &par->output; >+ var = &info->var; >+ fix = &info->fix; >+ >+ /* fix structur is not so FIX ... */ >+ line_length = var->xres_virtual * var->bits_per_pixel / 8; >+ line_length = PADDING(crtc->line_pad, line_length); >+ fix->line_length = line_length; >+ err_msg("fix->line_length = %d\n", fix->line_length); >+ >+ /* var->red, green, blue, transp are need to be set by driver >+ *and these data should be set before setcolreg routine >+ **/ >+ >+ switch (var->bits_per_pixel) { >+ case 8: >+ fix->visual = FB_VISUAL_PSEUDOCOLOR; >+ var->red.offset = 0; >+ var->red.length = 8; >+ var->green.offset = 0; >+ var->green.length = 8; >+ var->blue.offset = 0; >+ var->blue.length = 8; >+ var->transp.length = 0; >+ var->transp.offset = 0; >+ break; >+ case 16: >+ var->red.offset = 11; >+ var->red.length = 5; >+ var->green.offset = 5; >+ var->green.length = 6; >+ var->blue.offset = 0; >+ var->blue.length = 5; >+ var->transp.length = 0; >+ var->transp.offset = 0; >+ fix->visual = FB_VISUAL_TRUECOLOR; >+ break; >+ case 24: >+ case 32: >+ var->red.offset = 16; >+ var->red.length = 8; >+ var->green.offset = 8; >+ var->green.length = 8; >+ var->blue.offset = 0 ; >+ var->blue.length = 8; >+ fix->visual = FB_VISUAL_TRUECOLOR; >+ break; >+ default: >+ ret = -EINVAL; >+ break; >+ } >+ var->height = var->width = -1; >+ var->accel_flags = FB_ACCELF_TEXT; >+ >+ if (ret) { >+ err_msg("pixel bpp format not satisfied\n."); >+ LEAVE(ret); >+ } >+ ret = crtc->proc_setMode(crtc, var, fix); >+ if (!ret) >+ ret = output->proc_setMode(output, var, fix); >+ LEAVE(ret); >+} >+static inline unsigned int chan_to_field(unsigned int chan, struct >fb_bitfield *bf) >+{ >+ chan &= 0xffff; >+ chan >>= 16 - bf->length; >+ return chan << bf->offset; >+} >+ >+static int lynxfb_ops_setcolreg(unsigned regno, unsigned red, >+ unsigned green, unsigned blue, >+ unsigned transp, struct fb_info *info) >+{ >+ struct lynxfb_par *par; >+ struct lynxfb_crtc *crtc; >+ struct fb_var_screeninfo *var; >+ int ret; >+ >+ par = info->par; >+ crtc = &par->crtc; >+ var = &info->var; >+ ret = 0; >+ >+ /*dbg_msg("regno=%d, red=%d, green=%d, blue=%d\n", regno, red, green, >blue);*/ >+ if (regno > 256) { >+ err_msg("regno = %d\n", regno); >+ LEAVE(-EINVAL); >+ } >+ >+ if (info->var.grayscale) >+ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; >+ >+ if (var->bits_per_pixel == 8 && info->fix.visual == >FB_VISUAL_PSEUDOCOLOR) { >+ red >>= 8; >+ green >>= 8; >+ blue >>= 8; >+ ret = crtc->proc_setColReg(crtc, regno, red, green, blue); >+ goto exit; >+ } >+ >+ >+ if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 256) { >+ u32 val; >+ if (var->bits_per_pixel == 16 || >+ var->bits_per_pixel == 32 || >+ var->bits_per_pixel == 24) { >+ val = chan_to_field(red, &var->red); >+ val |= chan_to_field(green, &var->green); >+ val |= chan_to_field(blue, &var->blue); >+ par->pseudo_palette[regno] = val; >+ goto exit; >+ } >+ } >+ >+ ret = -EINVAL; >+ >+exit: >+ return ret; >+ LEAVE(ret); >+ >+} >+ >+static int lynxfb_ops_blank(int blank, struct fb_info *info) >+{ >+ struct lynxfb_par *par; >+ struct lynxfb_output *output; >+ ENTER(); >+ dbg_msg("blank = %d.\n", blank); >+ par = info->par; >+ output = &par->output; >+ LEAVE(output->proc_setBLANK(output, blank)); >+} >+static int sm750fb_set_drv(struct lynxfb_par *par) >+{ >+ int ret; >+ struct lynx_share *share; >+ struct sm750_share *spec_share; >+ struct lynxfb_output *output; >+ struct lynxfb_crtc *crtc; >+ ENTER(); >+ ret = 0; >+ >+ share = par->share; >+ spec_share = container_of(share, struct sm750_share, share); >+ output = &par->output; >+ crtc = &par->crtc; >+ >+ crtc->vidmem_size = (share->dual) ? share->vidmem_size>>1 : >share->vidmem_size; >+ /* setup crtc and output member */ >+ spec_share->hwCursor = g_hwcursor; >+ >+ crtc->proc_setMode = hw_sm750_crtc_setMode; >+ crtc->proc_checkMode = hw_sm750_crtc_checkMode; >+ crtc->proc_setColReg = hw_sm750_setColReg; >+ crtc->proc_panDisplay = hw_sm750_pan_display; >+ crtc->clear = hw_sm750_crtc_clear; >+ crtc->line_pad = 16; >+ /*crtc->xpanstep = crtc->ypanstep = crtc->ywrapstep = 0;*/ >+ crtc->xpanstep = 8; >+ crtc->ypanstep = 1; >+ crtc->ywrapstep = 0; >+ >+ output->proc_setMode = hw_sm750_output_setMode; >+ output->proc_checkMode = hw_sm750_output_checkMode; >+ >+ output->proc_setBLANK = (share->revid == SM750LE_REVISION_ID) ? >hw_sm750le_setBLANK : hw_sm750_setBLANK; >+ output->clear = hw_sm750_output_clear; >+ /* chip specific phase */ >+ share->accel.de_wait = (share->revid == SM750LE_REVISION_ID) ? >hw_sm750le_deWait : hw_sm750_deWait; >+ switch (spec_share->state.dataflow) { >+ case sm750_simul_pri: >+ output->paths = sm750_pnc; >+ crtc->channel = sm750_primary; >+ crtc->oScreen = 0; >+ crtc->vScreen = share->pvMem; >+ inf_msg("use simul primary mode\n"); >+ break; >+ case sm750_simul_sec: >+ output->paths = sm750_pnc; >+ crtc->channel = sm750_secondary; >+ crtc->oScreen = 0; >+ crtc->vScreen = share->pvMem; >+ break; >+ case sm750_dual_normal: >+ if (par->index == 0) { >+ output->paths = sm750_panel; >+ crtc->channel = sm750_primary; >+ crtc->oScreen = 0; >+ crtc->vScreen = share->pvMem; >+ } else{ >+ output->paths = sm750_crt; >+ crtc->channel = sm750_secondary; >+ /* not consider of padding stuffs for oScreen, >need fix*/ >+ crtc->oScreen = (share->vidmem_size >> 1); >+ crtc->vScreen = share->pvMem + crtc->oScreen; >+ } >+ break; >+ case sm750_dual_swap: >+ if (par->index == 0) { >+ output->paths = sm750_panel; >+ crtc->channel = sm750_secondary; >+ crtc->oScreen = 0; >+ crtc->vScreen = share->pvMem; >+ } else{ >+ output->paths = sm750_crt; >+ crtc->channel = sm750_primary; >+ /* not consider of padding stuffs for oScreen, >need fix*/ >+ crtc->oScreen = (share->vidmem_size >> 1); >+ crtc->vScreen = share->pvMem + crtc->oScreen; >+ } >+ break; >+ default: >+ ret = -EINVAL; >+ } >+ >+ LEAVE(ret); >+} >+ >+static int __devinit lynxfb_set_fbinfo(struct fb_info *info, int index) >+{ >+ int i; >+ struct lynxfb_par *par; >+ struct lynx_share *share; >+ struct lynxfb_crtc *crtc; >+ struct lynxfb_output *output; >+ struct fb_var_screeninfo *var; >+ struct fb_fix_screeninfo *fix; >+ >+ const struct fb_videomode *pdb[] = { >+ NULL, NULL, vesa_modes, >+ }; >+ int cdb[] = {0, 0, VESA_MODEDB_SIZE}; >+ static const char *mdb_desc[] = { >+ "driver prepared modes", >+ "kernel prepared default modedb", >+ "kernel HELPERS prepared vesa_modes", >+ }; >+ >+#define sm502_ext lynx750_ext >+ static const struct fb_videomode *ext_table[] = {lynx750_ext, NULL, >sm502_ext}; >+ static size_t ext_size[] = {ARRAY_SIZE(lynx750_ext), 0, >ARRAY_SIZE(sm502_ext)}; >+ >+ static const char *fixId[][2] = { >+ {"sm750_fb1", "sm750_fb2"}, >+ }; >+ >+ int ret, line_length; >+ ENTER(); >+ ret = 0; >+ par = (struct lynxfb_par *)info->par; >+ share = par->share; >+ crtc = &par->crtc; >+ output = &par->output; >+ var = &info->var; >+ fix = &info->fix; >+ >+ /* set index */ >+ par->index = index; >+ output->channel = &crtc->channel; >+ >+ sm750fb_set_drv(par); >+ lynxfb_ops.fb_pan_display = lynxfb_ops_pan_display; >+ >+ /* set current cursor variable and proc pointer, >+ *must be set after crtc member initialized */ >+ >+ crtc->cursor.offset = crtc->oScreen + crtc->vidmem_size - 1024; >+ crtc->cursor.mmio = share->pvReg + 0x800f0 + (int)crtc->channel * 0x140; >+ >+ inf_msg("crtc->cursor.mmio = %p\n", crtc->cursor.mmio); >+ crtc->cursor.maxH = crtc->cursor.maxW = 64; >+ crtc->cursor.size = crtc->cursor.maxH*crtc->cursor.maxW*2/8; >+ crtc->cursor.disable = hw_cursor_disable; >+ crtc->cursor.enable = hw_cursor_enable; >+ crtc->cursor.setColor = hw_cursor_setColor; >+ crtc->cursor.setPos = hw_cursor_setPos; >+ crtc->cursor.setSize = hw_cursor_setSize; >+ crtc->cursor.setData = hw_cursor_setData; >+ crtc->cursor.vstart = share->pvMem + crtc->cursor.offset; >+ >+ crtc->cursor.share = share; >+ memset(crtc->cursor.vstart, 0, crtc->cursor.size); >+ if (!g_hwcursor) { >+ lynxfb_ops.fb_cursor = NULL; >+ crtc->cursor.disable(&crtc->cursor); >+ } >+ >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) >+ /* hardware cursor broken under low version kernel*/ >+ lynxfb_ops.fb_cursor = soft_cursor; >+#endif >+ >+ /* set info->fbops, must be set before fb_find_mode */ >+ if (!share->accel_off) { >+ /* use 2d acceleration */ >+ lynxfb_ops.fb_fillrect = lynxfb_ops_fillrect; >+ lynxfb_ops.fb_copyarea = lynxfb_ops_copyarea; >+ lynxfb_ops.fb_imageblit = lynxfb_ops_imageblit; >+ } >+ info->fbops = &lynxfb_ops; >+ >+ if (!g_fbmode[index]) { >+ g_fbmode[index] = g_def_fbmode; >+ if (index) >+ g_fbmode[index] = g_fbmode[0]; >+ } >+ >+ pdb[0] = ext_table[g_specId]; >+ cdb[0] = ext_size[g_specId]; >+ >+ for (i = 0; i < 3; i++) { >+ /* no NULL pointer passed to fb_find_mode @4 */ >+ if (pdb[i] == NULL) { >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) >+ pdb[i] = &modedb2[0]; >+ cdb[i] = nmodedb2; >+#endif >+ } >+ >+ ret = fb_find_mode(var, info, g_fbmode[index], >+ pdb[i], cdb[i], NULL, 8); >+ >+ if (ret == 1) { >+ inf_msg("success! use specified mode:%s in >%s\n", >+ g_fbmode[index], >+ mdb_desc[i]); >+ break; >+ } else if (ret == 2) { >+ war_msg("use specified mode:%s in %s, with an >ignored refresh rate\n", >+ g_fbmode[index], >+ mdb_desc[i]); >+ break; >+ } else if (ret == 3) { >+ war_msg("wanna use default mode\n"); >+ /* break;*/ >+ } else if (ret == 4) { >+ war_msg("fall back to any valid mode\n"); >+ } else{ >+ war_msg("ret = %d, fb_find_mode failed, with >%s\n", ret, mdb_desc[i]); >+ } >+ } >+ >+ /* some member of info->var had been set by fb_find_mode */ >+ >+ inf_msg("Member of info->var is :\n\ >+ xres=%d\n\ >+ yres=%d\n\ >+ xres_virtual=%d\n\ >+ yres_virtual=%d\n\ >+ xoffset=%d\n\ >+ yoffset=%d\n\ >+ bits_per_pixel=%d\n \ >+ ...\n", var->xres, var->yres, >var->xres_virtual, var->yres_virtual, >+ var->xoffset, var->yoffset, >var->bits_per_pixel); >+ >+ /* set par */ >+ par->info = info; >+ >+ /* set info */ >+ line_length = PADDING(crtc->line_pad, >+ (var->xres_virtual * var->bits_per_pixel/8)); >+ >+ info->pseudo_palette = &par->pseudo_palette[0]; >+ info->screen_base = crtc->vScreen; >+ dbg_msg("screen_base vaddr = %p\n", info->screen_base); >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10) >+ info->screen_size = line_length * var->yres_virtual; >+#endif >+ info->flags = FBINFO_FLAG_DEFAULT|0; >+ >+ /* set info->fix */ >+ fix->type = FB_TYPE_PACKED_PIXELS; >+ fix->type_aux = 0; >+ fix->xpanstep = crtc->xpanstep; >+ fix->ypanstep = crtc->ypanstep; >+ fix->ywrapstep = crtc->ywrapstep; >+ fix->accel = FB_ACCEL_NONE; >+ >+ strlcpy(fix->id, fixId[g_specId][index], sizeof(fix->id)); >+ >+ >+ fix->smem_start = crtc->oScreen + share->vidmem_start; >+ inf_msg("fix->smem_start = %lx\n", fix->smem_start); >+ >+ /* according to mmap experiment from user space application, >+ *fix->mmio_len should not larger than virtual size >+ *(xres_virtual x yres_virtual x ByPP) >+ *Below line maybe buggy when user mmap fb dev node and write >+ *data into the bound over virtual size >+ **/ >+ fix->smem_len = crtc->vidmem_size; >+ inf_msg("fix->smem_len = %x\n", fix->smem_len); >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10) >+ info->screen_size = fix->smem_len; >+#endif >+ >+ fix->line_length = line_length; >+ fix->mmio_start = share->vidreg_start; >+ inf_msg("fix->mmio_start = %lx\n", fix->mmio_start); >+ fix->mmio_len = share->vidreg_size; >+ inf_msg("fix->mmio_len = %x\n", fix->mmio_len); >+ switch (var->bits_per_pixel) { >+ case 8: >+ fix->visual = FB_VISUAL_PSEUDOCOLOR; >+ break; >+ case 16: >+ case 32: >+ fix->visual = FB_VISUAL_TRUECOLOR; >+ break; >+ } >+ >+ /* set var */ >+ var->activate = FB_ACTIVATE_NOW; >+ var->accel_flags = 0; >+ var->vmode = FB_VMODE_NONINTERLACED; >+ >+ dbg_msg("#1 show info->cmap : \nstart=%d, len=%d, red=%p, >green=%p, blue=%p, transp=%p\n", >+ info->cmap.start, info->cmap.len, >+ info->cmap.red, info->cmap.green, >info->cmap.blue, >+ info->cmap.transp); >+ >+ ret = fb_alloc_cmap(&info->cmap, 256, 0); >+ if (ret < 0) { >+ err_msg("Could not allcate memory for cmap.\n"); >+ goto exit; >+ } >+ >+ dbg_msg("#2 show info->cmap : \nstart=%d, len=%d, red=%p, >green=%p, blue=%p, transp=%p\n", >+ info->cmap.start, info->cmap.len, >+ info->cmap.red, info->cmap.green, >info->cmap.blue, >+ info->cmap.transp); >+ >+exit: >+ lynxfb_ops_check_var(var, info); >+ /* lynxfb_ops_set_par(info);*/ >+ LEAVE(ret); >+ } >+ >+ static int __devinit lynxfb_pci_probe(struct pci_dev *pdev, >+ const struct pci_device_id *ent) >+ { >+ struct fb_info *info[] = {NULL, NULL}; >+ struct lynx_share *share = NULL; >+ >+ void *spec_share = NULL; >+ size_t spec_offset = 0; >+ int fbidx; >+ ENTER(); >+ >+ /* enable device */ >+ if (pci_enable_device(pdev)) { >+ err_msg("can not enable device.\n"); >+ goto err_enable; >+ } >+ >+ switch (ent->device) { >+ case PCI_DEVID_LYNX_EXP: >+ case PCI_DEVID_LYNX_SE: >+ g_specId = SPC_SM750; >+ /* though offset of share in sm750_share is 0, >+ *we use this marcro as the same */ >+ spec_offset = offsetof(struct sm750_share, share); >+ break; >+ default: >+ break; >+ } >+ >+ dbg_msg("spec_offset = %d\n", spec_offset); >+ spec_share = kzalloc(spec_size[g_specId], GFP_KERNEL); >+ if (!spec_share) { >+ err_msg("Could not allocate memory for share.\n"); >+ goto err_share; >+ } >+ >+ /* setting share structure */ >+ share = (struct lynx_share *)(spec_share + spec_offset); >+ share->fbinfo[0] = share->fbinfo[1] = NULL; >+ share->devid = pdev->device; >+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22) >+ u32 temp; >+ pci_read_config_dword(pdev, PCI_CLASS_REVISION, &temp); >+ share->revid = temp&0xFF; >+#else >+ share->revid = pdev->revision; >+#endif >+ >+ inf_msg("share->revid = %02x\n", share->revid); >+ share->pdev = pdev; >+#ifdef CONFIG_MTRR >+ share->mtrr_off = g_nomtrr; >+ share->mtrr.vram = 0; >+ share->mtrr.vram_added = 0; >+#endif >+ share->accel_off = g_noaccel; >+ share->dual = g_dualview; >+ spin_lock_init(&share->slock); >+ >+ if (!share->accel_off) { >+ /* hook deInit and 2d routines, notes that below hw_xxx >+ *routine can work on most of lynx chips >+ *if some chip need specific function, please hook it >in smXXX_set_drv >+ *routine */ >+ share->accel.de_init = hw_de_init; >+ share->accel.de_fillrect = hw_fillrect; >+ share->accel.de_copyarea = hw_copyarea; >+ share->accel.de_imageblit = hw_imageblit; >+ inf_msg("enable 2d acceleration\n"); >+ } else{ >+ inf_msg("disable 2d acceleration\n"); >+ } >+ >+ /* call chip specific setup routine */ >+ (*setup_rout[g_specId])(share, g_settings); >+ >+ /* call chip specific mmap routine */ >+ if ((*map_rout[g_specId])(share, pdev)) { >+ err_msg("Memory map failed\n"); >+ goto err_map; >+ } >+ >+#ifdef CONFIG_MTRR >+ if (!share->mtrr_off) { >+ inf_msg("enable mtrr\n"); >+ share->mtrr.vram = mtrr_add(share->vidmem_start, >+ share->vidmem_size, >+ MTRR_TYPE_WRCOMB, 1); >+ >+ if (share->mtrr.vram < 0) { >+ /* don't block driver with the failure of MTRR >*/ >+ err_msg("Unable to setup MTRR.\n"); >+ } else{ >+ share->mtrr.vram_added = 1; >+ inf_msg("MTRR added succesfully\n"); >+ } >+ } >+#endif >+ >+ memset(share->pvMem, 0, share->vidmem_size); >+ >+ inf_msg("sm%3x mmio address = %p\n", share->devid, >share->pvReg); >+ >+ pci_set_drvdata(pdev, share); >+ >+ /* call chipInit routine */ >+ (*inithw_rout[g_specId])(share, pdev); >+ >+ /* detect 502 need no disp driver >+ *beware that other chips except 502 should not touch >g_502nodisp >+ *(remain g_502nodisp always 0) >+ *so regularily, below if line will not affect other chips' >behaviour >+ **/ >+ /* if (!g_no502disp) {*/ >+ /* allocate frame buffer info structor according to >g_dualview */ >+ fbidx = 0; >+ALLOC_FB: >+ info[fbidx] = framebuffer_alloc(sizeof(struct >lynxfb_par), &pdev->dev); >+ if (!info[fbidx]) { >+ err_msg("Could not allocate framebuffer >#%d.\n", fbidx); >+ if (fbidx == 0) >+ goto err_info0_alloc; >+ else >+ goto err_info1_alloc; >+ } else{ >+ struct lynxfb_par *par; >+ inf_msg("framebuffer #%d alloc okay\n", fbidx); >+ share->fbinfo[fbidx] = info[fbidx]; >+ par = info[fbidx]->par; >+ par->share = share; >+ >+ /* set fb_info structure */ >+ if (lynxfb_set_fbinfo(info[fbidx], fbidx)) { >+ err_msg("Failed to initial fb_info >#%d.\n", fbidx); >+ if (fbidx == 0) >+ goto err_info0_set; >+ else >+ goto err_info1_set; >+ } >+ >+ /* register frame buffer*/ >+ inf_msg("Ready to register framebuffer #%d.\n", >fbidx); >+ int errno = register_framebuffer(info[fbidx]); >+ if (errno < 0) { >+ err_msg("Failed to register fb_info >#%d. err %d\n", fbidx, errno); >+ if (fbidx == 0) >+ goto err_register0; >+ else >+ goto err_register1; >+ } >+ inf_msg("Accomplished register framebuffer >#%d.\n", fbidx); >+ } >+ >+ /* no dual view by far */ >+ fbidx++; >+ if (share->dual && fbidx < 2) >+ goto ALLOC_FB; >+/* }*/ >+ >+ LEAVE(0); >+ >+err_register1: >+err_info1_set: >+ framebuffer_release(info[1]); >+err_info1_alloc: >+ unregister_framebuffer(info[0]); >+err_register0: >+err_info0_set: >+ framebuffer_release(info[0]); >+err_info0_alloc: >+err_map: >+ kfree(spec_share); >+err_share: >+err_enable: >+ LEAVE(-ENODEV); >+ } >+ >+static void __devexit lynxfb_pci_remove(struct pci_dev *pdev) >+{ >+ struct fb_info *info; >+ struct lynx_share *share; >+ void *spec_share; >+ struct lynxfb_par *par; >+ int cnt; >+ ENTER(); >+ >+ cnt = 2; >+ share = pci_get_drvdata(pdev); >+ >+ while (cnt-- > 0) { >+ info = share->fbinfo[cnt]; >+ if (!info) >+ continue; >+ par = info->par; >+ >+ unregister_framebuffer(info); >+ /* clean crtc & output allocations*/ >+ par->crtc.clear(&par->crtc); >+ par->output.clear(&par->output); >+ /* release frame buffer*/ >+ framebuffer_release(info); >+ } >+#ifdef CONFIG_MTRR >+ if (share->mtrr.vram_added) >+ mtrr_del(share->mtrr.vram, share->vidmem_start, >share->vidmem_size); >+#endif >+ /* pci_release_regions(pdev);*/ >+ >+ iounmap(share->pvReg); >+ iounmap(share->pvMem); >+ >+ switch (share->devid) { >+ case PCI_DEVID_LYNX_EXP: >+ case PCI_DEVID_LYNX_SE: >+ spec_share = container_of(share, struct sm750_share, >share); >+ break; >+ default: >+ spec_share = share; >+ } >+ kfree(g_settings); >+ kfree(spec_share); >+ pci_set_drvdata(pdev, NULL); >+ LEAVE(); >+} >+ >+ >+/* chip specific g_option configuration routine */ >+static void sm750fb_setup(struct lynx_share *share, char *src) >+{ >+ struct sm750_share *spec_share; >+ char *opt; >+#ifdef CAP_EXPENSION >+ char *exp_res; >+#endif >+ int swap; >+ ENTER(); >+ >+ spec_share = container_of(share, struct sm750_share, share); >+#ifdef CAP_EXPENSIION >+ exp_res = NULL; >+#endif >+ swap = 0; >+ >+ spec_share->state.initParm.chip_clk = 0; >+ spec_share->state.initParm.mem_clk = 0; >+ spec_share->state.initParm.master_clk = 0; >+ spec_share->state.initParm.powerMode = 0; >+ spec_share->state.initParm.setAllEngOff = 0; >+ spec_share->state.initParm.resetMemory = 1; >+ >+ /*defaultly turn g_hwcursor on for both view */ >+ g_hwcursor = 3; >+ >+ if (!src || !*src) { >+ war_msg("no specific g_option.\n"); >+ goto NO_PARAM; >+ } >+ >+ while ((opt = strsep(&src, ":")) != NULL && *opt != NULL) { >+ err_msg("opt=%s\n", opt); >+ err_msg("src=%s\n", src); >+ >+ if (!strncmp(opt, "swap", strlen("swap"))) >+ swap = 1; >+ else if (!strncmp(opt, "nocrt", strlen("nocrt"))) >+ spec_share->state.nocrt = 1; >+ else if (!strncmp(opt, "36bit", strlen("36bit"))) >+ spec_share->state.pnltype = sm750_doubleTFT; >+ else if (!strncmp(opt, "18bit", strlen("18bit"))) >+ spec_share->state.pnltype = sm750_dualTFT; >+ else if (!strncmp(opt, "24bit", strlen("24bit"))) >+ spec_share->state.pnltype = sm750_24TFT; >+#ifdef CAP_EXPANSION >+ else if (!strncmp(opt, "exp:", strlen("exp:"))) >+ exp_res = opt + strlen("exp:"); >+#endif >+ else if (!strncmp(opt, "nohwc0", strlen("nohwc0"))) >+ g_hwcursor &= ~0x1; >+ else if (!strncmp(opt, "nohwc1", strlen("nohwc1"))) >+ g_hwcursor &= ~0x2; >+ else if (!strncmp(opt, "nohwc", strlen("nohwc"))) >+ g_hwcursor = 0; >+ else{ >+ if (!g_fbmode[0]) { >+ g_fbmode[0] = opt; >+ inf_msg("find fbmode0 : %s\n", g_fbmode[0]); >+ } else if (!g_fbmode[1]) { >+ g_fbmode[1] = opt; >+ inf_msg("find fbmode1 : %s\n", g_fbmode[1]); >+ } else{ >+ war_msg("How many view you wann set?\n"); >+ } >+ } >+ } >+#ifdef CAP_EXPANSION >+ if (getExpRes(exp_res, &spec_share->state.xLCD, >&spec_share->state.yLCD)) { >+ /* seems exp_res is not valid*/ >+ spec_share->state.xLCD = spec_share->state.yLCD = 0; >+ } >+#endif >+ >+NO_PARAM: >+ if (share->revid != SM750LE_REVISION_ID) { >+ if (share->dual) { >+ if (swap) >+ spec_share->state.dataflow = sm750_dual_swap; >+ else >+ spec_share->state.dataflow = sm750_dual_normal; >+ } else{ >+ if (swap) >+ spec_share->state.dataflow = sm750_simul_sec; >+ else >+ spec_share->state.dataflow = sm750_simul_pri; >+ } >+ } else{ >+ /* SM750LE only have one crt channel */ >+ spec_share->state.dataflow = sm750_simul_sec; >+ /* sm750le do not have complex attributes*/ >+ spec_share->state.nocrt = 0; >+ } >+ >+ LEAVE(); >+} >+ >+ >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+static int __init lynxfb_setup(char *options) >+#else >+int __init lynxfb_setup(char *options) >+#endif >+{ >+ int len; >+ char *opt, *tmp; >+ ENTER(); >+ >+ if (!options || !*options) { >+ war_msg("no options.\n"); >+ LEAVE(0); >+ } >+ >+ inf_msg("options:%s\n", options); >+ >+ len = strlen(options) + 1; >+ g_settings = kmalloc(len, GFP_KERNEL); >+ if (!g_settings) >+ LEAVE(-ENOMEM); >+ >+ memset(g_settings, 0, len); >+ tmp = g_settings; >+ >+ /* Notes: >+ char *strsep(char **s, const char *ct); >+ @s: the string to be searched >+ @ct :the characters to search for >+ >+ strsep() updates @options to pointer after the first found token >+ it also returns the pointer ahead the token. >+ */ >+ while ((opt = strsep(&options, ":")) != NULL) { >+ /* options that mean for any lynx chips are configured here */ >+ if (!strncmp(opt, "noaccel", strlen("noaccel"))) >+ g_noaccel = 1; >+#ifdef CONFIG_MTRR >+ else if (!strncmp(opt, "nomtrr", strlen("nomtrr"))) >+ g_nomtrr = 1; >+#endif >+ else if (!strncmp(opt, "dual", strlen("dual"))) >+ g_dualview = 1; >+ else{ >+ strcat(tmp, opt); >+ tmp += strlen(opt); >+ if (options != NULL) >+ *tmp++ = ':'; >+ else >+ *tmp++ = 0; >+ } >+ } >+ >+ /* misc g_settings are transport to chip specific routines */ >+ inf_msg("parameter left for chip specific analysis:%s\n", g_settings); >+ LEAVE(0); >+} >+ >+ >+static void claim(void) >+{ >+ inf_msg("+-------------SMI Driver Information------------+"); >+ inf_msg("Release type : " RELEASE_TYPE "\n"); >+ inf_msg("Driver version: v" _version_ "\n"); >+ inf_msg("Support products:\n" >+ SUPPORT_CHIP); >+ inf_msg("Support OS:\n" >+ SUPPORT_OS); >+ inf_msg("Support ARCH: " SUPPORT_ARCH "\n"); >+ inf_msg("+-----------------------------------------------+"); >+} >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+static int __init lynxfb_init() >+{ >+ char *option ; >+ int ret; >+ smi_indent = 0; >+ ENTER(); >+ claim(); >+#ifdef MODULE >+ option = g_option; >+#else >+ if (fb_get_options("lynxfb", &option)) >+ LEAVE(-ENODEV); >+#endif >+ >+ lynxfb_setup(option); >+ ret = pci_register_driver(&lynxfb_driver); >+ LEAVE(ret); >+} >+#else /* kernel version >= 2.6.10*/ >+int __init lynxfb_init(void) >+{ >+ char *option; >+ int ret; >+ smi_indent = 0; >+ ENTER(); >+ claim(); >+#ifdef MODULE >+ option = g_option; >+ lynxfb_setup(option); >+#else >+ /* do nothing */ >+#endif >+ ret = pci_register_driver(&lynxfb_driver); >+ LEAVE(ret); >+} >+#endif >+ module_init(lynxfb_init); >+ >+#ifdef MODULE >+static void __exit lynxfb_exit() >+{ >+ ENTER(); >+ inf_msg(_moduleName_ " exit\n"); >+ pci_unregister_driver(&lynxfb_driver); >+ LEAVE(); >+} >+ module_exit(lynxfb_exit); >+#endif >+ >+#ifdef MODULE >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10) >+ module_param(g_option, charp, S_IRUGO); >+#else >+ /* be ware that PARM and param */ >+ MODULE_PARM(g_option, "s"); >+#endif >+ >+ MODULE_PARM_DESC(g_option, >+ "\n\t\tCommon options:\n" >+ "\t\tnoaccel:disable 2d capabilities\n" >+ "\t\tnomtrr:disable MTRR attribute for video memory\n" >+ "\t\tdualview:dual frame buffer feature enabled\n" >+ "\t\tnohwc:disable hardware cursor\n" >+ "\t\tUsual example:\n" >+ "\t\tinsmod ./lynxfb.ko g_option=\"noaccel, nohwc, >1280x1024-8 at 60\"\n" >+ "\t\tFor more detail chip specific options, please >refer to \"Lynxfb User Mnual\" or readme\n" >+ ); >+#endif >+ >+ MODULE_AUTHOR("monk liu<monk.liu at siliconmotion.com>"); >+ MODULE_DESCRIPTION("Frame buffer driver for SMI(R) " SUPPORT_CHIP " >chipsets"); >+ MODULE_LICENSE("Dual BSD/GPL"); >+ MODULE_DEVICE_TABLE(pci, smi_pci_table); >diff --git a/drivers/video/lynxfb/lynx_drv.h b/drivers/video/lynxfb/lynx_drv.h >new file mode 100644 >index 0000000..7cf5f1b >--- /dev/null >+++ b/drivers/video/lynxfb/lynx_drv.h >@@ -0,0 +1,271 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#ifndef LYNXDRV_H_ >+#define LYNXDRV_H_ >+ >+ >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17) >+#else >+typedef unsigned long resource_size_t; >+#endif >+ >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+#else >+#define SEPARATOR 1 >+typedef int pm_message_t; >+#endif >+ >+/* please use revision id to distinguish sm750le and sm750*/ >+#define SPC_SM750 0 >+#define SPC_SM712 1 >+#define SPC_SM502 2 >+/*#define SPC_SM750LE 8*/ >+ >+#define PCI_VENDOR_ID_SMI 0x126f >+#define PCI_DEVID_LYNX_EXP 0x0750 >+#define PCI_DEVID_LYNX_SE 0x0718 >+#define PCI_DEVID_LYNX_EM 0x0712 >+#define PCI_DEVID_LYNX_3DM 0x0720 >+#define PCI_DEVID_VOYAGER 0x0501 >+ >+/*#define SUPPORT_ARCH "x86, x86_64"*/ >+/*#define SUPPORT_CHIP "lynx Express(750)/lynx 750LE/Lynx SE(718)/Lynx >EM(712)/lynx 3DM(720/722) voyager(502/107)"*/ >+ >+/*#define _version_ "4.0.1"*/ >+#define _moduleName_ "lynxfb" >+#define PFX _moduleName_ ": " >+#define err_msg(fmt, args...) printk(KERN_ERR PFX fmt, ## args) >+#define war_msg(fmt, args...) printk(KERN_WARNING PFX fmt, ## args) >+#define inf_msg(fmt, args...) printk(KERN_INFO PFX fmt, ## args) >+/* below code also works ok, but there must be no KERN_INFO prefix */ >+/*#define inf_msg(...) printk(__VA_ARGS__)*/ >+ >+#if (DEBUG == 1) >+/* debug level == 1 */ >+#define dbg_msg(fmt, args...) printk(KERN_DEBUG PFX fmt, ## args) >+#define ENTER() printk(KERN_DEBUG PFX "%*c %s\n", smi_indent++, '>', >__func__) >+#define LEAVE(...) \ >+ do { \ >+ printk(KERN_DEBUG PFX "%*c %s\n", --smi_indent, '<', __func__); \ >+ return __VA_ARGS__; \ >+ } while (0) >+ >+#elif (DEBUG == 2) >+/* debug level == 2*/ >+#define dbg_msg(fmt, args...) printk(KERN_ERR PFX fmt, ## args) >+#define ENTER() printk(KERN_ERR PFX "%*c %s\n", smi_indent++, '>', >__func__) >+ >+#define LEAVE(...) \ >+ do { \ >+ printk(KERN_ERR PFX "%*c %s\n", --smi_indent, '<', __func__); \ >+ return __VA_ARGS__; \ >+ } while (0) >+ >+#ifdef inf_msg >+#undef inf_msg >+#endif >+ >+#define inf_msg(fmt, args...) printk(KERN_ERR PFX fmt, ## args) >+#else >+/* no debug */ >+#define dbg_msg(...) >+#define ENTER() >+#define LEAVE(...) \ >+ do { \ >+ return __VA_ARGS__; \ >+ } while (0) \ >+ >+#endif >+ >+#define MB(x) ((x)<<20) >+#define MHZ(x) ((x) * 1000000) >+/* align should be 2, 4, 8, 16 */ >+#define PADDING(align, data) (((data)+(align)-1)&(~((align)-1))) >+extern int smi_indent; >+ >+ >+struct lynx_accel{ >+ /* base virtual address of DPR registers */ >+ volatile unsigned char __iomem *dprBase; >+ /* base virtual address of de data port */ >+ volatile unsigned char __iomem *dpPortBase; >+ >+ /* function fointers */ >+ int (*de_init)(struct lynx_accel *); >+ >+ int (*de_wait)(void);/* see if hardware ready to work */ >+ >+ int (*de_fillrect)(struct lynx_accel *, u32, u32, u32, >+ u32, u32, u32, u32, >u32, u32); >+ >+ int (*de_copyarea)(struct lynx_accel *, u32, u32, u32, u32, >+ u32, u32, u32, u32, >+ u32, u32, u32, u32); >+ >+ int (*de_imageblit)(struct lynx_accel *, const char *, u32, u32, u32, >+ u32, u32, u32, u32, u32, u32, >u32, u32, u32); >+ >+}; >+ >+/* lynx_share stands for a presentation of two frame buffer >+ that use one smi adaptor , it is similar to a basic class of C++ >+*/ >+struct lynx_share{ >+ /* common members */ >+ u16 devid; >+ u8 revid; >+ struct pci_dev *pdev; >+ struct fb_info *fbinfo[2]; >+ struct lynx_accel accel; >+ int accel_off; >+ int dual; >+#ifdef CONFIG_MTRR >+ int mtrr_off; >+ struct{ >+ int vram; >+ int vram_added; >+ } mtrr; >+#endif >+ /* all smi graphic adaptor got below attributes */ >+ resource_size_t vidmem_start; >+ resource_size_t vidreg_start; >+ resource_size_t vidmem_size; >+ resource_size_t vidreg_size; >+ volatile unsigned char __iomem *pvReg; >+ unsigned char __iomem *pvMem; >+ /* locks*/ >+ spinlock_t slock; >+ /* function pointers */ >+ void (*suspend)(struct lynx_share *); >+ void (*resume)(struct lynx_share *); >+}; >+ >+struct lynx_cursor{ >+ /* cursor width , height and size */ >+ int w; >+ int h; >+ int size; >+ /* hardware limitation */ >+ int maxW; >+ int maxH; >+ /* base virtual address and offset of cursor image */ >+ char __iomem *vstart; >+ int offset; >+ /* mmio addr of hw cursor */ >+ volatile char __iomem *mmio; >+ /* the lynx_share of this adaptor */ >+ struct lynx_share *share; >+ /* proc_routines */ >+ void (*enable)(struct lynx_cursor *); >+ void (*disable)(struct lynx_cursor *); >+ void (*setSize)(struct lynx_cursor *, int, int); >+ void (*setPos)(struct lynx_cursor *, int, int); >+ void (*setColor)(struct lynx_cursor *, u32, u32); >+ void (*setData)(struct lynx_cursor *, u16, const u8 *, const u8 *); >+}; >+ >+struct lynxfb_crtc{ >+ unsigned char __iomem *vCursor;/*virtual address of cursor*/ >+ unsigned char __iomem *vScreen;/*virtual address of on_screen*/ >+ int oCursor;/*cursor address offset in vidmem*/ >+ int oScreen;/*onscreen address offset in vidmem*/ >+ int channel;/* which channel this crtc stands for*/ >+ resource_size_t vidmem_size;/* this view's video memory max size */ >+ >+ /* below attributes belong to info->fix, their value depends on >specific adaptor*/ >+ u16 line_pad;/* padding information:0, 1, 2, 4, 8, 16, ... */ >+ u16 xpanstep; >+ u16 ypanstep; >+ u16 ywrapstep; >+ >+ void *priv; >+ >+ int(*proc_setMode)(struct lynxfb_crtc*, >+ struct fb_var_screeninfo*, >+ struct fb_fix_screeninfo*); >+ >+ int(*proc_checkMode)(struct lynxfb_crtc *, struct fb_var_screeninfo *); >+ int(*proc_setColReg)(struct lynxfb_crtc *, ushort, ushort, ushort, >ushort); >+ void (*clear)(struct lynxfb_crtc *); >+ /* pan display */ >+ int(*proc_panDisplay)(struct lynxfb_crtc *, struct fb_var_screeninfo *, >+ struct fb_info *); >+ /* cursor information */ >+ struct lynx_cursor cursor; >+}; >+ >+struct lynxfb_output{ >+ int dpms; >+ int paths; >+ /* which paths(s) this output stands for, for sm750: >+ paths=1:means output for panel paths >+ paths=2:means output for crt paths >+ paths=3:means output for both panel and crt paths >+ */ >+ >+ int *channel; >+ /* which channel these outputs linked with, for sm750: >+ *channel=0 means primary channel >+ *channel=1 means secondary channel >+ output->channel ==> &crtc->channel >+ */ >+ void *priv; >+ >+ int(*proc_setMode)(struct lynxfb_output *, >+ struct fb_var_screeninfo *, >+ struct fb_fix_screeninfo *); >+ >+ int(*proc_checkMode)(struct lynxfb_output *, struct fb_var_screeninfo >*); >+ int(*proc_setBLANK)(struct lynxfb_output *, int); >+ void (*clear)(struct lynxfb_output *); >+}; >+ >+struct lynxfb_par{ >+ /* either 0 or 1 for dual head adaptor, 0 is the older one registered */ >+ int index; >+ unsigned int pseudo_palette[256]; >+ struct lynxfb_crtc crtc; >+ struct lynxfb_output output; >+ struct fb_info *info; >+ struct lynx_share *share; >+}; >+ >+#ifndef offsetof >+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) >+#endif >+ >+ >+#define PS_TO_HZ(ps) \ >+ ({ \ >+ unsigned long long hz = 1000*1000*1000*1000ULL; \ >+ do_div(hz, ps); \ >+ (unsigned long)hz; `}) >+ >+ >+static inline unsigned long ps_to_hz(unsigned int psvalue) >+{ >+ unsigned long long numerator = 1000*1000*1000*1000ULL; >+ /* 10^12 / picosecond period gives frequency in Hz */ >+ do_div(numerator, psvalue); >+ return (unsigned long)numerator; >+} >+ >+ >+ >+#endif >diff --git a/drivers/video/lynxfb/lynx_help.h >b/drivers/video/lynxfb/lynx_help.h >new file mode 100644 >index 0000000..2d80365 >--- /dev/null >+++ b/drivers/video/lynxfb/lynx_help.h >@@ -0,0 +1,115 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#ifndef LYNX_HELP_H__ >+#define LYNX_HELP_H__ >+ /* FIELD MACROS >*/ >+ >+#define _LSB(f) (0 ? f) >+#define _MSB(f) (1 ? f) >+#define _COUNT(f) (_MSB(f) - _LSB(f) + 1) >+ >+#define RAW_MASK(f) (0xFFFFFFFF >> (32 - _COUNT(f))) >+#define GET_MASK(f) (RAW_MASK(f) << _LSB(f)) >+#define GET_FIELD(d, f) (((d) >> _LSB(f)) & RAW_MASK(f)) >+#define TEST_FIELD(d, f, v) (GET_FIELD(d, f) == f ## _ ## v) >+#define SET_FIELD(d, f, v) (((d) & ~GET_MASK(f)) | \ >+ (((f ## _ ## v) & RAW_MASK(f)) << _LSB(f))) >+#define SET_FIELDV(d, f, v) (((d) & ~GET_MASK(f)) | \ >+ (((v) & RAW_MASK(f)) << _LSB(f))) >+ >+ >+/* Internal macros >*/ >+ >+#define _F_START(f) (0 ? f) >+#define _F_END(f) (1 ? f) >+#define _F_SIZE(f) (1 + _F_END(f) - _F_START(f)) >+#define _F_MASK(f) (((1 << _F_SIZE(f)) - 1) << _F_START(f)) >+#define _F_NORMALIZE(v, f) (((v) & _F_MASK(f)) >> _F_START(f)) >+#define _F_DENORMALIZE(v, f) (((v) << _F_START(f)) & _F_MASK(f)) >+ >+ >+/* Global macros >*/ >+ >+#define FIELD_GET(x, reg, field) \ >+ ( \ >+ _F_NORMALIZE((x), reg ## _ ## field) \ >+ ) >+ >+#define FIELD_SET(x, reg, field, value) \ >+ ( \ >+ (x & ~_F_MASK(reg ## _ ## field)) \ >+ | _F_DENORMALIZE(reg ## _ ## field ## _ ## value, reg ## _ ## field) \ >+ ) >+ >+#define FIELD_VALUE(x, reg, field, value) \ >+ ( \ >+ (x & ~_F_MASK(reg ## _ ## field)) \ >+ | _F_DENORMALIZE(value, reg ## _ ## field) \ >+ ) >+ >+#define FIELD_CLEAR(reg, field) \ >+ ( \ >+ ~_F_MASK(reg ## _ ## field) \ >+ ) >+ >+ >+/* Field Macros >*/ >+ >+#define FIELD_START(field) (0 ? field) >+#define FIELD_END(field) (1 ? field) >+#define FIELD_SIZE(field) (1 + FIELD_END(field) - >FIELD_START(field)) >+#define FIELD_MASK(field) (((1 << (FIELD_SIZE(field)-1)) | ((1 ><< (FIELD_SIZE(field)-1)) - 1)) << FIELD_START(field)) >+#define FIELD_NORMALIZE(reg, field) (((reg) & FIELD_MASK(field)) >> >FIELD_START(field)) >+#define FIELD_DENORMALIZE(field, value) (((value) << FIELD_START(field)) & >FIELD_MASK(field)) >+ >+#define FIELD_INIT(reg, field, value) FIELD_DENORMALIZE(reg ## _ ## field, \ >+ reg ## _ ## field ## _ ## value) >+#define FIELD_INIT_VAL(reg, field, value) \ >+ (FIELD_DENORMALIZE(reg ## _ ## field, value)) >+#define FIELD_VAL_SET(x, r, f, v) (x = x & ~FIELD_MASK(r ## _ ## f) \ >+ | FIELD_DENORMALIZE(r ## _ ## f, r >## _ ## f ## _ ## v)) >+ >+#define RGB(r, g, b) \ >+ ( \ >+ (unsigned long) (((r) << 16) | ((g) << 8) | (b)) \ >+ ) >+ >+#define RGB16(r, g, b) \ >+ ( \ >+ (unsigned short) ((((r) & 0xF8) << 8) | (((g) & 0xFC) << 3) | (((b) & >0xF8) >> 3)) \ >+ ) >+ >+static inline unsigned int absDiff(unsigned int a, unsigned int b) >+{ >+ if (a < b) >+ return b-a; >+ else >+ return a-b; >+} >+ >+/* n / d + 1 / 2 = (2n + d) / 2d */ >+#define roundedDiv(num, denom) ((2 * (num) + (denom)) / (2 * (denom))) >+#define MB(x) ((x)<<20) >+#define KB(x) ((x)<<10) >+#define MHz(x) ((x) * 1000000) >+ >+ >+ >+ >+#endif >diff --git a/drivers/video/lynxfb/lynx_hw750.c >b/drivers/video/lynxfb/lynx_hw750.c >new file mode 100644 >index 0000000..019eb68 >--- /dev/null >+++ b/drivers/video/lynxfb/lynx_hw750.c >@@ -0,0 +1,633 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#include<linux/version.h> >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) >+#include<linux/config.h> >+#endif >+#include <linux/version.h> >+#include<linux/module.h> >+#include<linux/kernel.h> >+#include<linux/errno.h> >+#include<linux/string.h> >+#include<linux/mm.h> >+#include<linux/slab.h> >+#include<linux/delay.h> >+#include<linux/fb.h> >+#include<linux/ioport.h> >+#include<linux/init.h> >+#include<linux/pci.h> >+#include<linux/vmalloc.h> >+#include<linux/pagemap.h> >+#include <linux/console.h> >+#ifdef CONFIG_MTRR >+#include <asm/mtrr.h> >+#endif >+ >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+/* no below two header files in 2.6.9 */ >+#include<linux/platform_device.h> >+#include<linux/screen_info.h> >+#else >+/* nothing by far */ >+#endif >+ >+#include "lynx_drv.h" >+#include "lynx_hw750.h" >+#include "ddk750.h" >+#include "lynx_accel.h" >+ >+int hw_sm750_map(struct lynx_share *share, struct pci_dev *pdev) >+{ >+ int ret; >+ struct sm750_share *spec_share; >+ ENTER(); >+ >+ spec_share = container_of(share, struct sm750_share, share); >+ ret = 0; >+ >+ share->vidreg_start = pci_resource_start(pdev, 1); >+ share->vidreg_size = MB(2); >+ >+ /* reserve the vidreg space of smi adaptor >+ * if you do this, u need to add release region code >+ * in lynxfb_remove, or memory will not be mapped again >+ * successfully >+ * */ >+ >+ >+ /* now map mmio and vidmem*/ >+ share->pvReg = ioremap_nocache(share->vidreg_start, share->vidreg_size); >+ if (!share->pvReg) { >+ err_msg("mmio failed\n"); >+ ret = -EFAULT; >+ goto exit; >+ } >+ >+ share->accel.dprBase = share->pvReg + DE_BASE_ADDR_TYPE1; >+ share->accel.dpPortBase = share->pvReg + DE_PORT_ADDR_TYPE1; >+ >+ ddk750_set_mmio(share->pvReg, share->devid, share->revid); >+ >+ share->vidmem_start = pci_resource_start(pdev, 0); >+ /* don't use pdev_resource[x].end - resource[x].start to >+ * calculate the resource size, its only the maximum available >+ * size but not the actual size, use >+ * @hw_sm750_getVMSize function can be safe. >+ * */ >+ share->vidmem_size = hw_sm750_getVMSize(share); >+ inf_msg("video memory size = %d mb\n", share->vidmem_size >> 20); >+ >+ /* reserve the vidmem space of smi adaptor */ >+ >+ share->pvMem = ioremap(share->vidmem_start, >+ share->vidmem_size); >+ >+ if (!share->pvMem) { >+ err_msg("Map video memory failed\n"); >+ ret = -EFAULT; >+ goto exit; >+ } >+ >+ inf_msg("video memory vaddr = %p\n", share->pvMem); >+exit: >+ LEAVE(ret); >+} >+ >+ >+ >+int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev) >+{ >+ struct sm750_share *spec_share; >+ struct init_status *parm; >+ ENTER(); >+ spec_share = container_of(share, struct sm750_share, share); >+ parm = &spec_share->state.initParm; >+ if (parm->chip_clk == 0) >+ parm->chip_clk = (getChipType() == SM750LE) ? >+ DEFAULT_SM750LE_CHIP_CLOCK : >+ DEFAULT_SM750_CHIP_CLOCK; >+ >+ if (parm->mem_clk == 0) >+ parm->mem_clk = parm->chip_clk; >+ if (parm->master_clk == 0) >+ parm->master_clk = parm->chip_clk/3; >+ >+ ddk750_initHw((initchip_param_t *)&spec_share->state.initParm); >+ /* for sm718, open pci burst */ >+ if (share->devid == 0x718) { >+ POKE32(SYSTEM_CTRL, >+ PEEK32(SYSTEM_CTRL)|(1 << SYSTEM_CTRL_PCI_BURST_LSB)); >+ } >+ >+ /* sm750 use sii164, it can be setup with default value >+ * by on power, so initDVIDisp can be skipped */ >+ >+ if (getChipType() != SM750LE) { >+ /* does user need CRT ?*/ >+ if (spec_share->state.nocrt) { >+ POKE32(MISC_CTRL, >+ PEEK32(MISC_CTRL)| >+ (1 << MISC_CTRL_DAC_POWER_LSB)); >+ /* shut off dpms */ >+ POKE32(SYSTEM_CTRL, >+ PEEK32(SYSTEM_CTRL)| >+ (3 << SYSTEM_CTRL_DPMS_LSB)); >+ } else{ >+ POKE32(MISC_CTRL, >+ PEEK32(MISC_CTRL)& >+ (~(1 << MISC_CTRL_DAC_POWER_LSB))); >+ /* turn on dpms */ >+ POKE32(SYSTEM_CTRL, >+ PEEK32(SYSTEM_CTRL)& >+ (~(3 << SYSTEM_CTRL_DPMS_LSB))); >+ } >+ >+ switch (spec_share->state.pnltype) { >+ case sm750_doubleTFT: >+ case sm750_24TFT: >+ case sm750_dualTFT: >+ POKE32(PANEL_DISPLAY_CTRL, >+ PEEK32(PANEL_DISPLAY_CTRL)& >+ (~(3 << >PANEL_DISPLAY_CTRL_TFT_DISP_LSB))); >+ POKE32(PANEL_DISPLAY_CTRL, >+ PEEK32(PANEL_DISPLAY_CTRL)| >+ (spec_share->state.pnltype << >PANEL_DISPLAY_CTRL_TFT_DISP_LSB)); >break; >+ } >+ } else{ >+ /* for 750LE , no DVI chip initilization makes Monitor no >signal */ >+ /* Set up GPIO for software I2C to program DVI chip in the >+ Xilinx SP605 board, in order to have video signal. >+ */ >+ swI2CInit(0, 1); >+ >+ >+ /* Customer may NOT use CH7301 DVI chip, which has to be >+ initialized differently. >+ */ >+ if (swI2CReadReg(0xec, 0x4a) == 0x95) { >+ /* The following register values for CH7301 are from >+ Chrontel app note and our experiment. >+ */ >+ inf_msg("yes, CH7301 DVI chip found\n"); >+ swI2CWriteReg(0xec, 0x1d, 0x16); >+ swI2CWriteReg(0xec, 0x21, 0x9); >+ swI2CWriteReg(0xec, 0x49, 0xC0); >+ inf_msg("okay, CH7301 DVI chip setup done\n"); >+ } >+ } >+ >+ /* init 2d engine */ >+ if (!share->accel_off) { >+ hw_sm750_initAccel(share); >+ } >+ >+ LEAVE(0); >+} >+ >+ >+resource_size_t hw_sm750_getVMSize(struct lynx_share *share) >+{ >+ resource_size_t ret; >+ ENTER(); >+ ret = ddk750_getVMSize(); >+ LEAVE(ret); >+} >+ >+ >+ >+int hw_sm750_output_checkMode(struct lynxfb_output *output, struct >fb_var_screeninfo *var) >+{ >+ ENTER(); >+ LEAVE(0); >+} >+ >+ >+int hw_sm750_output_setMode(struct lynxfb_output *output, >+ struct fb_var_screeninfo *var, struct fb_fix_screeninfo *fix) >+{ >+ int ret; >+ disp_output_t dispSet; >+ int channel; >+ ENTER(); >+ ret = 0; >+ dispSet = 0; >+ channel = *output->channel; >+ >+ >+ if (getChipType() != SM750LE) { >+ if (channel == sm750_primary) { >+ inf_msg("primary channel\n"); >+ if (output->paths & sm750_panel) >+ dispSet |= do_LCD1_PRI; >+ if (output->paths & sm750_crt) >+ dispSet |= do_CRT_PRI; >+ >+ } else{ >+ inf_msg("secondary channel\n"); >+ if (output->paths & sm750_panel) >+ dispSet |= do_LCD1_SEC; >+ if (output->paths & sm750_crt) >+ dispSet |= do_CRT_SEC; >+ >+ } >+ ddk750_setLogicalDispOut(dispSet); >+ } else{ >+ /* just open DISPLAY_CONTROL_750LE register bit 3:0*/ >+ u32 reg; >+ reg = PEEK32(DISPLAY_CONTROL_750LE); >+ reg |= 0xf; >+ POKE32(DISPLAY_CONTROL_750LE, reg); >+ } >+ >+ inf_msg("ddk setlogicdispout done \n"); >+ LEAVE(ret); >+} >+ >+void hw_sm750_output_clear(struct lynxfb_output *output) >+{ >+ ENTER(); >+ LEAVE(); >+} >+ >+int hw_sm750_crtc_checkMode(struct lynxfb_crtc *crtc, struct >fb_var_screeninfo *var) >+{ >+ struct lynx_share *share; >+ ENTER(); >+ >+ share = container_of(crtc, struct lynxfb_par, crtc)->share; >+ >+ switch (var->bits_per_pixel) { >+ case 8: >+ case 16: >+ break; >+ case 32: >+ if (share->revid == (unsigned char)SM750LE_REVISION_ID) { >+ dbg_msg("750le do not support 32bpp\n"); >+ LEAVE (-EINVAL); >+ } >+ break; >+ default: >+ LEAVE(-EINVAL); >+ >+ } >+ >+ LEAVE(0); >+} >+ >+ >+/* >+ set the controller's mode for @crtc charged with @var and @fix parameters >+ */ >+int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc, >+ struct fb_var_screeninfo *var, >+ struct fb_fix_screeninfo *fix) >+{ >+ int ret, fmt; >+ u32 reg; >+ mode_parameter_t modparm; >+ clock_type_t clock; >+ struct lynx_share *share; >+ struct lynxfb_par *par; >+ >+ ENTER(); >+ ret = 0; >+ par = container_of(crtc, struct lynxfb_par, crtc); >+ share = par->share; >+ >+ if (!share->accel_off) { >+ /* set 2d engine pixel format according to mode bpp */ >+ switch (var->bits_per_pixel) { >+ case 8: >+ fmt = 0; >+ break; >+ case 16: >+ fmt = 1; >+ break; >+ case 32: >+ default: >+ fmt = 2; >+ break; >+ } >+ hw_set2dformat(&share->accel, fmt); >+ } >+ >+ >+ /* set timing */ >+ modparm.pixel_clock = ps_to_hz(var->pixclock); >+ modparm.vertical_sync_polarity = (var->sync & FB_SYNC_HOR_HIGH_ACT) ? >POS : NEG; >+ modparm.horizontal_sync_polarity = (var->sync & FB_SYNC_VERT_HIGH_ACT) >? POS : NEG; >+ modparm.clock_phase_polarity = (var->sync & FB_SYNC_COMP_HIGH_ACT) ? >POS : NEG; >+ modparm.horizontal_display_end = var->xres; >+ modparm.horizontal_sync_width = var->hsync_len; >+ modparm.horizontal_sync_start = var->xres + var->right_margin; >+ modparm.horizontal_total = var->xres + var->left_margin + >var->right_margin + var->hsync_len; >+ modparm.vertical_display_end = var->yres; >+ modparm.vertical_sync_height = var->vsync_len; >+ modparm.vertical_sync_start = var->yres + var->lower_margin; >+ modparm.vertical_total = var->yres + var->upper_margin + >var->lower_margin + var->vsync_len; >+ >+ /* choose pll */ >+ if (crtc->channel != sm750_secondary) >+ clock = PRIMARY_PLL; >+ else >+ clock = SECONDARY_PLL; >+ >+ dbg_msg("Request pixel clock = %lu\n", modparm.pixel_clock); >+ ret = ddk750_setModeTiming(&modparm, clock); >+ if (ret) { >+ err_msg("Set mode timing failed\n"); >+ goto exit; >+ } >+ >+ if (crtc->channel != sm750_secondary) { >+ /* set pitch, offset , width, start address , etc... */ >+ POKE32(PANEL_FB_ADDRESS, >+ (~(1 << PANEL_FB_ADDRESS_STATUS_LSB))& >+ (~(1 << PANEL_FB_ADDRESS_EXT_LSB))& >+ (~(0X3FFFFFF << PANEL_FB_ADDRESS_ADDRESS_LSB))| >+ (crtc->oScreen << >PANEL_FB_ADDRESS_ADDRESS_LSB)); >+ reg = var->xres * (var->bits_per_pixel >> 3); >+ /* crtc->channel is not equal to par->index on numeric, be >aware of that */ >+ reg = PADDING(crtc->line_pad, reg); >+ POKE32(PANEL_FB_WIDTH, >+ (reg << PANEL_FB_WIDTH_WIDTH_LSB)| >+ (fix->line_length << >PANEL_FB_WIDTH_OFFSET_LSB)); >+ >+ POKE32(PANEL_WINDOW_WIDTH, >+ (var->xres - 1 << PANEL_WINDOW_WIDTH_WIDTH_LSB)| >+ (var->xoffset << PANEL_WINDOW_WIDTH_X_LSB)); >+ >+ POKE32(PANEL_WINDOW_HEIGHT, >+ (var->yres_virtual - 1 << >PANEL_WINDOW_HEIGHT_HEIGHT_LSB)| >+ (var->yoffset << PANEL_WINDOW_HEIGHT_Y_LSB)); >+ POKE32(PANEL_PLANE_TL, 0); >+ >+ POKE32(PANEL_PLANE_BR, >+ (var->yres - 1 << PANEL_PLANE_BR_BOTTOM_LSB)| >+ (var->xres - 1 << PANEL_PLANE_BR_RIGHT_LSB)); >+ >+ /* set pixel format */ >+ reg = PEEK32(PANEL_DISPLAY_CTRL); >+ POKE32(PANEL_DISPLAY_CTRL, >+ reg&(~(3 << PANEL_DISPLAY_CTRL_FORMAT_LSB))| >+ ((var->bits_per_pixel >> 4) << >PANEL_DISPLAY_CTRL_FORMAT_LSB)); >+ } else{ >+ /* not implemented now */ >+ POKE32(CRT_FB_ADDRESS, crtc->oScreen); >+ reg = var->xres * (var->bits_per_pixel >> 3); >+ /* crtc->channel is not equal to par->index on numeric, be >aware of that */ >+ reg = PADDING(crtc->line_pad, reg); >+ POKE32(CRT_FB_WIDTH, >+ (reg << CRT_FB_WIDTH_WIDTH_LSB)| >+ (fix->line_length << CRT_FB_WIDTH_OFFSET_LSB)); >+ >+ /* SET PIXEL FORMAT */ >+ reg = PEEK32(CRT_DISPLAY_CTRL); >+ reg |= (var->bits_per_pixel >> 4) << >CRT_DISPLAY_CTRL_FORMAT_LSB; >+ POKE32(CRT_DISPLAY_CTRL, reg); >+ } >+ >+ >+exit: >+ LEAVE(ret); >+} >+ >+void hw_sm750_crtc_clear(struct lynxfb_crtc *crtc) >+{ >+ ENTER(); >+ LEAVE(); >+} >+ >+int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index, >+ ushort red, ushort green, ushort blue) >+{ >+ static unsigned int add[] = {PANEL_PALETTE_RAM, CRT_PALETTE_RAM}; >+ POKE32(add[crtc->channel] + index*4, (red<<16)|(green<<8)|blue); >+ return 0; >+} >+ >+int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank) >+{ >+ int dpms, crtdb; >+ ENTER(); >+ switch (blank) { >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+ case FB_BLANK_UNBLANK: >+#else >+ case VESA_NO_BLANKING: >+#endif >+ dpms = CRT_DISPLAY_CTRL_DPMS_0; >+ crtdb = CRT_DISPLAY_CTRL_BLANK_OFF; >+ break; >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+ case FB_BLANK_NORMAL: >+ dpms = CRT_DISPLAY_CTRL_DPMS_0; >+ crtdb = CRT_DISPLAY_CTRL_BLANK_ON; >+ break; >+#endif >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+ case FB_BLANK_VSYNC_SUSPEND: >+#else >+ case VESA_VSYNC_SUSPEND: >+#endif >+ dpms = CRT_DISPLAY_CTRL_DPMS_2; >+ crtdb = CRT_DISPLAY_CTRL_BLANK_ON; >+ break; >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+ case FB_BLANK_HSYNC_SUSPEND: >+#else >+ case VESA_HSYNC_SUSPEND: >+#endif >+ dpms = CRT_DISPLAY_CTRL_DPMS_1; >+ crtdb = CRT_DISPLAY_CTRL_BLANK_ON; >+ break; >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+ case FB_BLANK_POWERDOWN: >+#else >+ case VESA_POWERDOWN: >+#endif >+ dpms = CRT_DISPLAY_CTRL_DPMS_3; >+ crtdb = CRT_DISPLAY_CTRL_BLANK_ON; >+ break; >+ } >+ >+ if (output->paths & sm750_crt) { >+ POKE32(CRT_DISPLAY_CTRL, PEEK32(CRT_DISPLAY_CTRL)&(~(3 << >CRT_DISPLAY_CTRL_DPMS_LSB))|(dpms << CRT_DISPLAY_CTRL_DPMS_LSB)); >+ POKE32(CRT_DISPLAY_CTRL, PEEK32(CRT_DISPLAY_CTRL)&(~(1 << >CRT_DISPLAY_CTRL_BLANK_LSB))|(crtdb << CRT_DISPLAY_CTRL_BLANK_LSB)); >+ } >+ LEAVE(0); >+} >+ >+int hw_sm750_setBLANK(struct lynxfb_output *output, int blank) >+{ >+ unsigned int dpms, pps, crtdb; >+ ENTER(); >+ dpms = pps = crtdb = 0; >+ >+ switch (blank) { >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+ case FB_BLANK_UNBLANK: >+#else >+ case VESA_NO_BLANKING: >+#endif >+ inf_msg("flag = FB_BLANK_UNBLANK \n"); >+ dpms = SYSTEM_CTRL_DPMS_VPHP; >+ pps = PANEL_DISPLAY_CTRL_DATA_ENABLE; >+ crtdb = CRT_DISPLAY_CTRL_BLANK_OFF; >+ break; >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+ case FB_BLANK_NORMAL: >+ inf_msg("flag = FB_BLANK_NORMAL \n"); >+ dpms = SYSTEM_CTRL_DPMS_VPHP; >+ pps = PANEL_DISPLAY_CTRL_DATA_DISABLE; >+ crtdb = CRT_DISPLAY_CTRL_BLANK_ON; >+ break; >+#endif >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+ case FB_BLANK_VSYNC_SUSPEND: >+#else >+ case VESA_VSYNC_SUSPEND: >+#endif >+ dpms = SYSTEM_CTRL_DPMS_VNHP; >+ pps = PANEL_DISPLAY_CTRL_DATA_DISABLE; >+ crtdb = CRT_DISPLAY_CTRL_BLANK_ON; >+ break; >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+ case FB_BLANK_HSYNC_SUSPEND: >+#else >+ case VESA_HSYNC_SUSPEND: >+#endif >+ dpms = SYSTEM_CTRL_DPMS_VPHN; >+ pps = PANEL_DISPLAY_CTRL_DATA_DISABLE; >+ crtdb = CRT_DISPLAY_CTRL_BLANK_ON; >+ break; >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) >+ case FB_BLANK_POWERDOWN: >+#else >+ case VESA_POWERDOWN: >+#endif >+ dpms = SYSTEM_CTRL_DPMS_VNHN; >+ pps = PANEL_DISPLAY_CTRL_DATA_DISABLE; >+ crtdb = CRT_DISPLAY_CTRL_BLANK_ON; >+ break; >+ } >+ >+ if (output->paths & sm750_crt) { >+ POKE32(SYSTEM_CTRL, PEEK32(SYSTEM_CTRL)&(~(3 << >SYSTEM_CTRL_DPMS_LSB)) >+ |(dpms << SYSTEM_CTRL_DPMS_LSB)); >+ POKE32(CRT_DISPLAY_CTRL, PEEK32(CRT_DISPLAY_CTRL)&(~(1 << >CRT_DISPLAY_CTRL_BLANK_LSB)) >+ |(crtdb << CRT_DISPLAY_CTRL_BLANK_LSB)); >+ } >+ >+ if (output->paths & sm750_panel) { >+ POKE32(PANEL_DISPLAY_CTRL, PEEK32(PANEL_DISPLAY_CTRL)&(~(1 << >PANEL_DISPLAY_CTRL_DATA_LSB)) >+ |(pps << PANEL_DISPLAY_CTRL_DATA_LSB)); >+ } >+ >+ LEAVE(0); >+} >+ >+ >+void hw_sm750_initAccel(struct lynx_share *share) >+{ >+ u32 reg; >+ enable2DEngine(1); >+ >+ if (getChipType() == SM750LE) { >+ reg = PEEK32(DE_STATE1); >+ reg |= 1 << DE_STATE1_DE_ABORT_LSB; >+ POKE32(DE_STATE1, reg); >+ >+ reg = PEEK32(DE_STATE1); >+ reg &= ~(1 << DE_STATE1_DE_ABORT_LSB); >+ POKE32(DE_STATE1, reg); >+ >+ } else{ >+ /* engine reset */ >+ reg = PEEK32(SYSTEM_CTRL); >+ reg |= 1 << SYSTEM_CTRL_DE_ABORT_LSB; >+ POKE32(SYSTEM_CTRL, reg); >+ >+ reg = PEEK32(SYSTEM_CTRL); >+ reg &= ~(1 << SYSTEM_CTRL_DE_ABORT_LSB); >+ POKE32(SYSTEM_CTRL, reg); >+ } >+ >+ /* call 2d init */ >+ share->accel.de_init(&share->accel); >+} >+ >+int hw_sm750le_deWait() >+{ >+ int i = 0x10000000; >+ while (i--) { >+ unsigned int dwVal = PEEK32(DE_STATE2); >+ if (((1&(dwVal >> DE_STATE2_DE_STATUS_LSB)) == >DE_STATE2_DE_STATUS_IDLE) && >+ ((1&(dwVal >> DE_STATE2_DE_FIFO_LSB)) == >DE_STATE2_DE_FIFO_EMPTY) && >+ ((1&(dwVal >> DE_STATE2_DE_MEM_FIFO_LSB)) == >DE_STATE2_DE_MEM_FIFO_EMPTY)) { >+ return 0; >+ } >+ } >+ /* timeout error */ >+ return -1; >+} >+ >+ >+int hw_sm750_deWait() >+{ >+ int i = 0x10000000; >+ while (i--) { >+ unsigned int dwVal = PEEK32(SYSTEM_CTRL); >+ if (((1&(dwVal >> SYSTEM_CTRL_DE_STATUS_LSB)) == >SYSTEM_CTRL_DE_STATUS_IDLE) && >+ ((1&(dwVal >> SYSTEM_CTRL_DE_FIFO_LSB)) == >SYSTEM_CTRL_DE_FIFO_EMPTY) && >+ ((1&(dwVal >> SYSTEM_CTRL_DE_MEM_FIFO_LSB)) == >SYSTEM_CTRL_DE_MEM_FIFO_EMPTY)) { >+ return 0; >+ } >+ } >+ /* timeout error */ >+ return -1; >+} >+ >+int hw_sm750_pan_display(struct lynxfb_crtc *crtc, >+ const struct fb_var_screeninfo *var, >+ const struct fb_info *info) >+{ >+ uint32_t total; >+ if ((var->xoffset + var->xres > var->xres_virtual) || >+ (var->yoffset + var->yres > var->yres_virtual)) { >+ return -EINVAL; >+ } >+ >+ total = var->yoffset * info->fix.line_length + >+ ((var->xoffset * var->bits_per_pixel) >> 3); >+ total += crtc->oScreen; >+ if (crtc->channel == sm750_primary) { >+ POKE32(PANEL_FB_ADDRESS, >+ PEEK32(PANEL_FB_ADDRESS)& >+ (~(0x3ffffff << PANEL_FB_ADDRESS_ADDRESS_LSB))| >+ (total << PANEL_FB_ADDRESS_ADDRESS_LSB)); >+ } else{ >+ POKE32(CRT_FB_ADDRESS, >+ PEEK32(CRT_FB_ADDRESS)& >+ (~(0x3ffffff << CRT_FB_ADDRESS_ADDRESS_LSB))| >+ (total << CRT_FB_ADDRESS_ADDRESS_LSB)); >+ } >+ return 0; >+} >+ >diff --git a/drivers/video/lynxfb/lynx_hw750.h >b/drivers/video/lynxfb/lynx_hw750.h >new file mode 100644 >index 0000000..9f91ad1 >--- /dev/null >+++ b/drivers/video/lynxfb/lynx_hw750.h >@@ -0,0 +1,120 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#ifndef LYNX_HW750_H__ >+#define LYNX_HW750_H__ >+ >+ >+#define DEFAULT_SM750_CHIP_CLOCK 290 >+#define DEFAULT_SM750LE_CHIP_CLOCK 333 >+#ifndef SM750LE_REVISION_ID >+#define SM750LE_REVISION_ID ((unsigned char)0xfe) >+#endif >+ >+ >+ >+enum sm750_pnltype{ >+ >+ sm750_24TFT = 0, /* 24bit tft */ >+ >+ sm750_dualTFT = 2, /* dual 18 bit tft */ >+ >+ sm750_doubleTFT = 1, /* 36 bit double pixel tft */ >+}; >+ >+/* vga channel is not concerned */ >+enum sm750_dataflow{ >+ sm750_simul_pri, /* primary => all head */ >+ >+ sm750_simul_sec, /* secondary => all head */ >+ >+ sm750_dual_normal, /* primary => panel head and secondary => crt */ >+ >+ sm750_dual_swap, /* primary => crt head and secondary => panel */ >+}; >+ >+ >+enum sm750_channel{ >+ sm750_primary = 0, >+ /* enum value equal to the register filed data */ >+ sm750_secondary = 1, >+}; >+ >+enum sm750_path{ >+ sm750_panel = 1, >+ sm750_crt = 2, >+ sm750_pnc = 3, /* panel and crt */ >+}; >+ >+struct init_status{ >+ ushort powerMode; >+ /* below three clocks are in unit of MHZ*/ >+ ushort chip_clk; >+ ushort mem_clk; >+ ushort master_clk; >+ ushort setAllEngOff; >+ ushort resetMemory; >+}; >+ >+struct sm750_state{ >+ struct init_status initParm; >+ enum sm750_pnltype pnltype; >+ enum sm750_dataflow dataflow; >+ int nocrt; >+ int xLCD; >+ int yLCD; >+}; >+ >+/* sm750_share stands for a presentation of two frame buffer >+ that use one sm750 adaptor, it is similiar to the super class of >lynx_share >+ in C++ >+*/ >+ >+struct sm750_share{ >+ /* it's better to put lynx_share struct to the first place of >sm750_share */ >+ struct lynx_share share; >+ struct sm750_state state; >+ int hwCursor; >+ /* 0: no hardware cursor >+ 1: primary crtc hw cursor enabled, >+ 2: secondary crtc hw cursor enabled >+ 3: both ctrc hw cursor enabled >+ */ >+}; >+ >+int hw_sm750_map(struct lynx_share *share, struct pci_dev *pdev); >+int hw_sm750_inithw(struct lynx_share *, struct pci_dev *); >+void hw_sm750_initAccel(struct lynx_share *); >+int hw_sm750_deWait(void); >+int hw_sm750le_deWait(void); >+ >+resource_size_t hw_sm750_getVMSize(struct lynx_share *); >+int hw_sm750_output_checkMode(struct lynxfb_output *, struct >fb_var_screeninfo *); >+int hw_sm750_output_setMode(struct lynxfb_output *, struct fb_var_screeninfo >*, struct fb_fix_screeninfo *); >+int hw_sm750_crtc_checkMode(struct lynxfb_crtc *, struct fb_var_screeninfo *); >+int hw_sm750_crtc_setMode(struct lynxfb_crtc *, struct fb_var_screeninfo *, >struct fb_fix_screeninfo *); >+int hw_sm750_setColReg(struct lynxfb_crtc *, ushort, ushort, ushort, ushort); >+int hw_sm750_setBLANK(struct lynxfb_output *, int); >+int hw_sm750le_setBLANK(struct lynxfb_output *, int); >+void hw_sm750_crtc_clear(struct lynxfb_crtc *); >+void hw_sm750_output_clear(struct lynxfb_output *); >+int hw_sm750_pan_display(struct lynxfb_crtc *crtc, >+ const struct fb_var_screeninfo *var, >+ const struct fb_info *info); >+ >+#endif >diff --git a/drivers/video/lynxfb/modedb.c b/drivers/video/lynxfb/modedb.c >new file mode 100644 >index 0000000..50fc8b9 >--- /dev/null >+++ b/drivers/video/lynxfb/modedb.c >@@ -0,0 +1,238 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+static const struct fb_videomode modedb2[] = { >+ { >+ /* 640x400 @ 70 Hz, 31.5 kHz hsync */ >+ NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 640x480 @ 60 Hz, 31.5 kHz hsync */ >+ NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 800x600 @ 56 Hz, 35.15 kHz hsync */ >+ NULL, 56, 800, 600, 27777, 128, 24, 22, 1, 72, 2, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1024x768 @ 87 Hz interlaced, 35.5 kHz hsync */ >+ NULL, 87, 1024, 768, 22271, 56, 24, 33, 8, 160, 8, >+ 0, FB_VMODE_INTERLACED >+ }, { >+ /* 640x400 @ 85 Hz, 37.86 kHz hsync */ >+ NULL, 85, 640, 400, 31746, 96, 32, 41, 1, 64, 3, >+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED >+ }, { >+ /* 640x480 @ 72 Hz, 36.5 kHz hsync */ >+ NULL, 72, 640, 480, 31746, 144, 40, 30, 8, 40, 3, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 640x480 @ 75 Hz, 37.50 kHz hsync */ >+ NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 800x600 @ 60 Hz, 37.8 kHz hsync */ >+ NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4, >+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED >+ }, { >+ /* 640x480 @ 85 Hz, 43.27 kHz hsync */ >+ NULL, 85, 640, 480, 27777, 80, 56, 25, 1, 56, 3, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1152x864 @ 89 Hz interlaced, 44 kHz hsync */ >+ NULL, 69, 1152, 864, 15384, 96, 16, 110, 1, 216, 10, >+ 0, FB_VMODE_INTERLACED >+ }, { >+ /* 800x600 @ 72 Hz, 48.0 kHz hsync */ >+ NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6, >+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1024x768 @ 60 Hz, 48.4 kHz hsync */ >+ NULL, 60, 1024, 768, 15384, 168, 8, 29, 3, 144, 6, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 640x480 @ 100 Hz, 53.01 kHz hsync */ >+ NULL, 100, 640, 480, 21834, 96, 32, 36, 8, 96, 6, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1152x864 @ 60 Hz, 53.5 kHz hsync */ >+ NULL, 60, 1152, 864, 11123, 208, 64, 16, 4, 256, 8, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 800x600 @ 85 Hz, 55.84 kHz hsync */ >+ NULL, 85, 800, 600, 16460, 160, 64, 36, 16, 64, 5, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1024x768 @ 70 Hz, 56.5 kHz hsync */ >+ NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1280x960-60 VESA */ >+ NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3, >+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, >FB_MODE_IS_VESA >+ }, { >+ /* 1280x1024-60 VESA */ >+ NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3, >+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, >FB_MODE_IS_VESA >+ }, { >+ /* 1280x1024 @ 87 Hz interlaced, 51 kHz hsync */ >+ NULL, 87, 1280, 1024, 12500, 56, 16, 128, 1, 216, 12, >+ 0, FB_VMODE_INTERLACED >+ }, { >+ /* 800x600 @ 100 Hz, 64.02 kHz hsync */ >+ NULL, 100, 800, 600, 14357, 160, 64, 30, 4, 64, 6, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1024x768 @ 76 Hz, 62.5 kHz hsync */ >+ NULL, 76, 1024, 768, 11764, 208, 8, 36, 16, 120, 3, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1152x864 @ 70 Hz, 62.4 kHz hsync */ >+ NULL, 70, 1152, 864, 10869, 106, 56, 20, 1, 160, 10, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1280x1024 @ 61 Hz, 64.2 kHz hsync */ >+ NULL, 61, 1280, 1024, 9090, 200, 48, 26, 1, 184, 3, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1400x1050 @ 60Hz, 63.9 kHz hsync */ >+ NULL, 68, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/ >+ NULL, 75, 1400, 1050, 9271, 120, 56, 13, 0, 112, 3, >+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/ >+ NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3, >+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1024x768 @ 85 Hz, 70.24 kHz hsync */ >+ NULL, 85, 1024, 768, 10111, 192, 32, 34, 14, 160, 6, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1152x864 @ 78 Hz, 70.8 kHz hsync */ >+ NULL, 78, 1152, 864, 9090, 228, 88, 32, 0, 84, 12, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1280x1024 @ 70 Hz, 74.59 kHz hsync */ >+ NULL, 70, 1280, 1024, 7905, 224, 32, 28, 8, 160, 8, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1600x1200 @ 60Hz, 75.00 kHz hsync */ >+ NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3, >+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1152x864 @ 84 Hz, 76.0 kHz hsync */ >+ NULL, 84, 1152, 864, 7407, 184, 312, 32, 0, 128, 12, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1280x1024 @ 74 Hz, 78.85 kHz hsync */ >+ NULL, 74, 1280, 1024, 7407, 256, 32, 34, 3, 144, 3, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1024x768 @ 100Hz, 80.21 kHz hsync */ >+ NULL, 100, 1024, 768, 8658, 192, 32, 21, 3, 192, 10, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1280x1024 @ 76 Hz, 81.13 kHz hsync */ >+ NULL, 76, 1280, 1024, 7407, 248, 32, 34, 3, 104, 3, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1600x1200 @ 70 Hz, 87.50 kHz hsync */ >+ NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1152x864 @ 100 Hz, 89.62 kHz hsync */ >+ NULL, 100, 1152, 864, 7264, 224, 32, 17, 2, 128, 19, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1280x1024 @ 85 Hz, 91.15 kHz hsync */ >+ NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3, >+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1600x1200 @ 75 Hz, 93.75 kHz hsync */ >+ NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, >+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1600x1200 @ 85 Hz, 105.77 kHz hsync */ >+ NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3, >+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1280x1024 @ 100 Hz, 107.16 kHz hsync */ >+ NULL, 100, 1280, 1024, 5502, 256, 32, 26, 7, 128, 15, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1800x1440 @ 64Hz, 96.15 kHz hsync */ >+ NULL, 64, 1800, 1440, 4347, 304, 96, 46, 1, 192, 3, >+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED >+ }, { >+ /* 1800x1440 @ 70Hz, 104.52 kHz hsync */ >+ NULL, 70, 1800, 1440, 4000, 304, 96, 46, 1, 192, 3, >+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED >+ }, { >+ /* 512x384 @ 78 Hz, 31.50 kHz hsync */ >+ NULL, 78, 512, 384, 49603, 48, 16, 16, 1, 64, 3, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 512x384 @ 85 Hz, 34.38 kHz hsync */ >+ NULL, 85, 512, 384, 45454, 48, 16, 16, 1, 64, 3, >+ 0, FB_VMODE_NONINTERLACED >+ }, { >+ /* 320x200 @ 70 Hz, 31.5 kHz hsync, 8:5 aspect ratio */ >+ NULL, 70, 320, 200, 79440, 16, 16, 20, 4, 48, 1, >+ 0, FB_VMODE_DOUBLE >+ }, { >+ /* 320x240 @ 60 Hz, 31.5 kHz hsync, 4:3 aspect ratio */ >+ NULL, 60, 320, 240, 79440, 16, 16, 16, 5, 48, 1, >+ 0, FB_VMODE_DOUBLE >+ }, { >+ /* 320x240 @ 72 Hz, 36.5 kHz hsync */ >+ NULL, 72, 320, 240, 63492, 16, 16, 16, 4, 48, 2, >+ 0, FB_VMODE_DOUBLE >+ }, { >+ /* 400x300 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio */ >+ NULL, 56, 400, 300, 55555, 64, 16, 10, 1, 32, 1, >+ 0, FB_VMODE_DOUBLE >+ }, { >+ /* 400x300 @ 60 Hz, 37.8 kHz hsync */ >+ NULL, 60, 400, 300, 50000, 48, 16, 11, 1, 64, 2, >+ 0, FB_VMODE_DOUBLE >+ }, { >+ /* 400x300 @ 72 Hz, 48.0 kHz hsync */ >+ NULL, 72, 400, 300, 40000, 32, 24, 11, 19, 64, 3, >+ 0, FB_VMODE_DOUBLE >+ }, { >+ /* 480x300 @ 56 Hz, 35.2 kHz hsync, 8:5 aspect ratio */ >+ NULL, 56, 480, 300, 46176, 80, 16, 10, 1, 40, 1, >+ 0, FB_VMODE_DOUBLE >+ }, { >+ /* 480x300 @ 60 Hz, 37.8 kHz hsync */ >+ NULL, 60, 480, 300, 41858, 56, 16, 11, 1, 80, 2, >+ 0, FB_VMODE_DOUBLE >+ }, { >+ /* 480x300 @ 63 Hz, 39.6 kHz hsync */ >+ NULL, 63, 480, 300, 40000, 56, 16, 11, 1, 80, 2, >+ 0, FB_VMODE_DOUBLE >+ }, { >+ /* 480x300 @ 72 Hz, 48.0 kHz hsync */ >+ NULL, 72, 480, 300, 33386, 40, 24, 11, 19, 80, 3, >+ 0, FB_VMODE_DOUBLE >+ }, >+}; >+static const int nmodedb2 = sizeof(modedb2); >diff --git a/drivers/video/lynxfb/ver.h b/drivers/video/lynxfb/ver.h >new file mode 100644 >index 0000000..d11362a >--- /dev/null >+++ b/drivers/video/lynxfb/ver.h >@@ -0,0 +1,38 @@ >+/******************************************************************* >+*Copyright (c) 2012 by Silicon Motion, Inc. (SMI) >+*Permission is hereby granted, free of charge, to any person obtaining a copy >+*of this software and associated documentation files (the "Software"), to deal >+*in the Software without restriction, including without limitation the rights >to >+*use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies >+*of the Software, and to permit persons to whom the Software is furnished to >+*do so, subject to the following conditions: >+* >+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >+*NONINFRINGEMENT. IN NO EVENT SHALL Mill.Chen and Monk.Liu OR COPYRIGHT >+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR >+*OTHER DEALINGS IN THE SOFTWARE. >+*******************************************************************/ >+#ifndef __VER_H_ >+#define __VER_H_ >+ >+#define RELEASE_TYPE "Electra(formal release)" >+#define SUPPORT_ARCH "x86,x86_64" >+#define SUPPORT_CHIP "lynx Express(750)/lynx 750LE/Lynx SE(718)" >+/*#define SUPPORT_CHIP " \ >+\tlynx 750LE\n"*/ >+ >+#define SUPPORT_OS " \ >+\tRHEL 4.3 i386 and x86_64\n \ >+\tRHEL 5.3 i386 and x86_64\n \ >+\tRHEL 6.0 i386 and x86_64\n \ >+\tSLES 9 i386 and x86_64\n \ >+\tSLES 10 i386 and x86_64\n \ >+\tSLES 11 i386 and x86_64\n" >+#define _version_ "4.1.3" >+ >+#endif >+ >-- >1.7.9.5 >