summaryrefslogtreecommitdiffstats
path: root/drivers/staging/sm750fb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/sm750fb')
-rw-r--r--drivers/staging/sm750fb/Kconfig15
-rw-r--r--drivers/staging/sm750fb/Makefile7
-rw-r--r--drivers/staging/sm750fb/TODO19
-rw-r--r--drivers/staging/sm750fb/ddk750.h21
-rw-r--r--drivers/staging/sm750fb/ddk750_chip.c407
-rw-r--r--drivers/staging/sm750fb/ddk750_chip.h102
-rw-r--r--drivers/staging/sm750fb/ddk750_display.c159
-rw-r--r--drivers/staging/sm750fb/ddk750_display.h107
-rw-r--r--drivers/staging/sm750fb/ddk750_dvi.c62
-rw-r--r--drivers/staging/sm750fb/ddk750_dvi.h57
-rw-r--r--drivers/staging/sm750fb/ddk750_hwi2c.c247
-rw-r--r--drivers/staging/sm750fb/ddk750_hwi2c.h12
-rw-r--r--drivers/staging/sm750fb/ddk750_mode.c225
-rw-r--r--drivers/staging/sm750fb/ddk750_mode.h37
-rw-r--r--drivers/staging/sm750fb/ddk750_power.c145
-rw-r--r--drivers/staging/sm750fb/ddk750_power.h41
-rw-r--r--drivers/staging/sm750fb/ddk750_reg.h1455
-rw-r--r--drivers/staging/sm750fb/ddk750_sii164.c408
-rw-r--r--drivers/staging/sm750fb/ddk750_sii164.h174
-rw-r--r--drivers/staging/sm750fb/ddk750_swi2c.c504
-rw-r--r--drivers/staging/sm750fb/ddk750_swi2c.h61
-rw-r--r--drivers/staging/sm750fb/readme38
-rw-r--r--drivers/staging/sm750fb/sm750.c1204
-rw-r--r--drivers/staging/sm750fb/sm750.h220
-rw-r--r--drivers/staging/sm750fb/sm750_accel.c414
-rw-r--r--drivers/staging/sm750fb/sm750_accel.h243
-rw-r--r--drivers/staging/sm750fb/sm750_cursor.c176
-rw-r--r--drivers/staging/sm750fb/sm750_cursor.h15
-rw-r--r--drivers/staging/sm750fb/sm750_hw.c569
29 files changed, 7144 insertions, 0 deletions
diff --git a/drivers/staging/sm750fb/Kconfig b/drivers/staging/sm750fb/Kconfig
new file mode 100644
index 000000000..8c0d8a873
--- /dev/null
+++ b/drivers/staging/sm750fb/Kconfig
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0
+config FB_SM750
+ tristate "Silicon Motion SM750 framebuffer support"
+ depends on FB && PCI
+ select FB_MODE_HELPERS
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ Frame buffer driver for the Silicon Motion SM750 chip
+ with 2D accelearion and dual head support.
+
+ This driver is also available as a module. The module will be
+ called sm750fb. If you want to compile it as a module, say M
+ here and read <file:Documentation/kbuild/modules.rst>.
diff --git a/drivers/staging/sm750fb/Makefile b/drivers/staging/sm750fb/Makefile
new file mode 100644
index 000000000..b89aa4c12
--- /dev/null
+++ b/drivers/staging/sm750fb/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_FB_SM750) += sm750fb.o
+
+sm750fb-objs := sm750.o sm750_hw.o sm750_accel.o sm750_cursor.o \
+ ddk750_chip.o ddk750_power.o ddk750_mode.o \
+ ddk750_display.o ddk750_swi2c.o ddk750_sii164.o \
+ ddk750_dvi.o ddk750_hwi2c.o
diff --git a/drivers/staging/sm750fb/TODO b/drivers/staging/sm750fb/TODO
new file mode 100644
index 000000000..481409eb3
--- /dev/null
+++ b/drivers/staging/sm750fb/TODO
@@ -0,0 +1,19 @@
+TODO:
+- lots of checkpatch cleanup
+- use kernel coding style
+- refine the code and remove unused code
+- Implement hardware acceleration for imageblit if image->depth > 1
+- check on hardware effects of removal of USE_HW_I2C and USE_DVICHIP (these two
+ are supposed to be sample code which is given here if someone wants to
+ use those functionalities)
+- must be ported to the atomic kms framework in the drm subsystem (which will
+ give you a basic fbdev driver for free)
+
+Note:
+- This driver will be removed from staging after the drm driver is ready
+- The drm driver is getting ready at https://gitlab.com/sudipm/sm750/tree/sm750
+
+Please send any patches to
+ Greg Kroah-Hartman <greg@kroah.com>
+ Sudip Mukherjee <sudipm.mukherjee@gmail.com>
+ Teddy Wang <teddy.wang@siliconmotion.com>
diff --git a/drivers/staging/sm750fb/ddk750.h b/drivers/staging/sm750fb/ddk750.h
new file mode 100644
index 000000000..64ef4d258
--- /dev/null
+++ b/drivers/staging/sm750fb/ddk750.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+ *
+ * RegSC.h --- SM718 SDK
+ * This file contains the definitions for the System Configuration registers.
+ */
+
+#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"
+#ifdef USE_HW_I2C
+#include "ddk750_hwi2c.h"
+#endif
+#include "ddk750_swi2c.h"
+#endif
diff --git a/drivers/staging/sm750fb/ddk750_chip.c b/drivers/staging/sm750fb/ddk750_chip.c
new file mode 100644
index 000000000..02860d3ec
--- /dev/null
+++ b/drivers/staging/sm750fb/ddk750_chip.c
@@ -0,0 +1,407 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <linux/sizes.h>
+
+#include "ddk750_reg.h"
+#include "ddk750_chip.h"
+#include "ddk750_power.h"
+
+#define MHz(x) ((x) * 1000000)
+
+static enum logical_chip_type chip;
+
+enum logical_chip_type sm750_get_chip_type(void)
+{
+ return chip;
+}
+
+void sm750_set_chip_type(unsigned short dev_id, u8 rev_id)
+{
+ if (dev_id == 0x718) {
+ chip = SM718;
+ } else if (dev_id == 0x750) {
+ chip = SM750;
+ /* SM750 and SM750LE are different in their revision ID only. */
+ if (rev_id == SM750LE_REVISION_ID) {
+ chip = SM750LE;
+ pr_info("found sm750le\n");
+ }
+ } else {
+ chip = SM_UNKNOWN;
+ }
+}
+
+static unsigned int get_mxclk_freq(void)
+{
+ unsigned int pll_reg;
+ unsigned int M, N, OD, POD;
+
+ if (sm750_get_chip_type() == SM750LE)
+ return MHz(130);
+
+ pll_reg = peek32(MXCLK_PLL_CTRL);
+ M = (pll_reg & PLL_CTRL_M_MASK) >> PLL_CTRL_M_SHIFT;
+ N = (pll_reg & PLL_CTRL_N_MASK) >> PLL_CTRL_N_SHIFT;
+ OD = (pll_reg & PLL_CTRL_OD_MASK) >> PLL_CTRL_OD_SHIFT;
+ POD = (pll_reg & PLL_CTRL_POD_MASK) >> PLL_CTRL_POD_SHIFT;
+
+ return DEFAULT_INPUT_CLOCK * M / N / BIT(OD) / BIT(POD);
+}
+
+/*
+ * This function set up the main chip clock.
+ *
+ * Input: Frequency to be set.
+ */
+static void set_chip_clock(unsigned int frequency)
+{
+ struct pll_value pll;
+
+ /* Cheok_0509: For SM750LE, the chip clock is fixed. Nothing to set. */
+ if (sm750_get_chip_type() == SM750LE)
+ return;
+
+ if (frequency) {
+ /*
+ * Set up PLL structure to hold the value to be set in clocks.
+ */
+ pll.input_freq = DEFAULT_INPUT_CLOCK; /* Defined in CLOCK.H */
+ pll.clock_type = MXCLK_PLL;
+
+ /*
+ * Call sm750_calc_pll_value() to fill the other fields
+ * of the PLL structure. Sometimes, the chip cannot set
+ * up the exact clock required by the User.
+ * Return value of sm750_calc_pll_value gives the actual
+ * possible clock.
+ */
+ sm750_calc_pll_value(frequency, &pll);
+
+ /* Master Clock Control: MXCLK_PLL */
+ poke32(MXCLK_PLL_CTRL, sm750_format_pll_reg(&pll));
+ }
+}
+
+static void set_memory_clock(unsigned int frequency)
+{
+ unsigned int reg, divisor;
+
+ /*
+ * Cheok_0509: For SM750LE, the memory clock is fixed.
+ * Nothing to set.
+ */
+ if (sm750_get_chip_type() == SM750LE)
+ return;
+
+ if (frequency) {
+ /*
+ * Set the frequency to the maximum frequency
+ * that the DDR Memory can take which is 336MHz.
+ */
+ if (frequency > MHz(336))
+ frequency = MHz(336);
+
+ /* Calculate the divisor */
+ divisor = DIV_ROUND_CLOSEST(get_mxclk_freq(), frequency);
+
+ /* Set the corresponding divisor in the register. */
+ reg = peek32(CURRENT_GATE) & ~CURRENT_GATE_M2XCLK_MASK;
+ switch (divisor) {
+ default:
+ case 1:
+ reg |= CURRENT_GATE_M2XCLK_DIV_1;
+ break;
+ case 2:
+ reg |= CURRENT_GATE_M2XCLK_DIV_2;
+ break;
+ case 3:
+ reg |= CURRENT_GATE_M2XCLK_DIV_3;
+ break;
+ case 4:
+ reg |= CURRENT_GATE_M2XCLK_DIV_4;
+ break;
+ }
+
+ sm750_set_current_gate(reg);
+ }
+}
+
+/*
+ * This function set up the master clock (MCLK).
+ *
+ * Input: Frequency to be set.
+ *
+ * NOTE:
+ * The maximum frequency the engine can run is 168MHz.
+ */
+static void set_master_clock(unsigned int frequency)
+{
+ unsigned int reg, divisor;
+
+ /*
+ * Cheok_0509: For SM750LE, the memory clock is fixed.
+ * Nothing to set.
+ */
+ if (sm750_get_chip_type() == SM750LE)
+ return;
+
+ if (frequency) {
+ /*
+ * Set the frequency to the maximum frequency
+ * that the SM750 engine can run, which is about 190 MHz.
+ */
+ if (frequency > MHz(190))
+ frequency = MHz(190);
+
+ /* Calculate the divisor */
+ divisor = DIV_ROUND_CLOSEST(get_mxclk_freq(), frequency);
+
+ /* Set the corresponding divisor in the register. */
+ reg = peek32(CURRENT_GATE) & ~CURRENT_GATE_MCLK_MASK;
+ switch (divisor) {
+ default:
+ case 3:
+ reg |= CURRENT_GATE_MCLK_DIV_3;
+ break;
+ case 4:
+ reg |= CURRENT_GATE_MCLK_DIV_4;
+ break;
+ case 6:
+ reg |= CURRENT_GATE_MCLK_DIV_6;
+ break;
+ case 8:
+ reg |= CURRENT_GATE_MCLK_DIV_8;
+ break;
+ }
+
+ sm750_set_current_gate(reg);
+ }
+}
+
+unsigned int ddk750_get_vm_size(void)
+{
+ unsigned int reg;
+ unsigned int data;
+
+ /* sm750le only use 64 mb memory*/
+ if (sm750_get_chip_type() == SM750LE)
+ return SZ_64M;
+
+ /* for 750,always use power mode0*/
+ reg = peek32(MODE0_GATE);
+ reg |= MODE0_GATE_GPIO;
+ poke32(MODE0_GATE, reg);
+
+ /* get frame buffer size from GPIO */
+ reg = peek32(MISC_CTRL) & MISC_CTRL_LOCALMEM_SIZE_MASK;
+ switch (reg) {
+ case MISC_CTRL_LOCALMEM_SIZE_8M:
+ data = SZ_8M; break; /* 8 Mega byte */
+ case MISC_CTRL_LOCALMEM_SIZE_16M:
+ data = SZ_16M; break; /* 16 Mega byte */
+ case MISC_CTRL_LOCALMEM_SIZE_32M:
+ data = SZ_32M; break; /* 32 Mega byte */
+ case MISC_CTRL_LOCALMEM_SIZE_64M:
+ data = SZ_64M; break; /* 64 Mega byte */
+ default:
+ data = 0;
+ break;
+ }
+ return data;
+}
+
+int ddk750_init_hw(struct initchip_param *p_init_param)
+{
+ unsigned int reg;
+
+ if (p_init_param->power_mode != 0)
+ p_init_param->power_mode = 0;
+ sm750_set_power_mode(p_init_param->power_mode);
+
+ /* Enable display power gate & LOCALMEM power gate*/
+ reg = peek32(CURRENT_GATE);
+ reg |= (CURRENT_GATE_DISPLAY | CURRENT_GATE_LOCALMEM);
+ sm750_set_current_gate(reg);
+
+ if (sm750_get_chip_type() != SM750LE) {
+ /* set panel pll and graphic mode via mmio_88 */
+ reg = peek32(VGA_CONFIGURATION);
+ reg |= (VGA_CONFIGURATION_PLL | VGA_CONFIGURATION_MODE);
+ poke32(VGA_CONFIGURATION, reg);
+ } 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 */
+ set_chip_clock(MHz((unsigned int)p_init_param->chip_clock));
+
+ /* Set up memory clock. */
+ set_memory_clock(MHz(p_init_param->mem_clock));
+
+ /* Set up master clock */
+ set_master_clock(MHz(p_init_param->master_clock));
+
+ /*
+ * 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 (p_init_param->reset_memory == 1) {
+ reg = peek32(MISC_CTRL);
+ reg &= ~MISC_CTRL_LOCALMEM_RESET;
+ poke32(MISC_CTRL, reg);
+
+ reg |= MISC_CTRL_LOCALMEM_RESET;
+ poke32(MISC_CTRL, reg);
+ }
+
+ if (p_init_param->set_all_eng_off == 1) {
+ sm750_enable_2d_engine(0);
+
+ /* Disable Overlay, if a former application left it on */
+ reg = peek32(VIDEO_DISPLAY_CTRL);
+ reg &= ~DISPLAY_CTRL_PLANE;
+ poke32(VIDEO_DISPLAY_CTRL, reg);
+
+ /* Disable video alpha, if a former application left it on */
+ reg = peek32(VIDEO_ALPHA_DISPLAY_CTRL);
+ reg &= ~DISPLAY_CTRL_PLANE;
+ poke32(VIDEO_ALPHA_DISPLAY_CTRL, reg);
+
+ /* Disable alpha plane, if a former application left it on */
+ reg = peek32(ALPHA_DISPLAY_CTRL);
+ reg &= ~DISPLAY_CTRL_PLANE;
+ poke32(ALPHA_DISPLAY_CTRL, reg);
+
+ /* Disable DMA Channel, if a former application left it on */
+ reg = peek32(DMA_ABORT_INTERRUPT);
+ reg |= DMA_ABORT_INTERRUPT_ABORT_1;
+ poke32(DMA_ABORT_INTERRUPT, reg);
+
+ /* Disable DMA Power, if a former application left it on */
+ sm750_enable_dma(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 sm750_calc_pll_value(unsigned int request_orig,
+ struct pll_value *pll)
+{
+ /*
+ * as sm750 register definition,
+ * N located in 2,15 and M located in 1,255
+ */
+ int N, M, X, d;
+ int mini_diff;
+ unsigned int RN, quo, rem, fl_quo;
+ unsigned int input, request;
+ unsigned int tmp_clock, ret;
+ const int max_OD = 3;
+ int max_d = 6;
+
+ if (sm750_get_chip_type() == SM750LE) {
+ /*
+ * SM750LE don't have
+ * programmable PLL and M/N values to work on.
+ * Just return the requested clock.
+ */
+ return request_orig;
+ }
+
+ ret = 0;
+ mini_diff = ~0;
+ request = request_orig / 1000;
+ input = pll->input_freq / 1000;
+
+ /*
+ * for MXCLK register,
+ * no POD provided, so need be treated differently
+ */
+ if (pll->clock_type == MXCLK_PLL)
+ max_d = 3;
+
+ 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 = max_d; d >= 0; d--) {
+ X = BIT(d);
+ 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;
+
+ tmp_clock = pll->input_freq * M / N / X;
+ diff = abs(tmp_clock - request_orig);
+ if (diff < mini_diff) {
+ pll->M = M;
+ pll->N = N;
+ pll->POD = 0;
+ if (d > max_OD)
+ pll->POD = d - max_OD;
+ pll->OD = d - pll->POD;
+ mini_diff = diff;
+ ret = tmp_clock;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+unsigned int sm750_format_pll_reg(struct pll_value *p_PLL)
+{
+#ifndef VALIDATION_CHIP
+ unsigned int POD = p_PLL->POD;
+#endif
+ unsigned int OD = p_PLL->OD;
+ unsigned int M = p_PLL->M;
+ unsigned int N = p_PLL->N;
+
+ /*
+ * 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.
+ */
+ return PLL_CTRL_POWER |
+#ifndef VALIDATION_CHIP
+ ((POD << PLL_CTRL_POD_SHIFT) & PLL_CTRL_POD_MASK) |
+#endif
+ ((OD << PLL_CTRL_OD_SHIFT) & PLL_CTRL_OD_MASK) |
+ ((N << PLL_CTRL_N_SHIFT) & PLL_CTRL_N_MASK) |
+ ((M << PLL_CTRL_M_SHIFT) & PLL_CTRL_M_MASK);
+}
diff --git a/drivers/staging/sm750fb/ddk750_chip.h b/drivers/staging/sm750fb/ddk750_chip.h
new file mode 100644
index 000000000..ee2e9d90f
--- /dev/null
+++ b/drivers/staging/sm750fb/ddk750_chip.h
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef DDK750_CHIP_H__
+#define DDK750_CHIP_H__
+#define DEFAULT_INPUT_CLOCK 14318181 /* Default reference clock */
+#ifndef SM750LE_REVISION_ID
+#define SM750LE_REVISION_ID ((unsigned char)0xfe)
+#endif
+
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/uaccess.h>
+
+extern void __iomem *mmio750;
+
+/* software control endianness */
+static inline u32 peek32(u32 addr)
+{
+ return readl(addr + mmio750);
+}
+
+static inline void poke32(u32 addr, u32 data)
+{
+ writel(data, addr + mmio750);
+}
+
+/* This is all the chips recognized by this library */
+enum logical_chip_type {
+ SM_UNKNOWN,
+ SM718,
+ SM750,
+ SM750LE,
+};
+
+enum clock_type {
+ MXCLK_PLL,
+ PRIMARY_PLL,
+ SECONDARY_PLL,
+ VGA0_PLL,
+ VGA1_PLL,
+};
+
+struct pll_value {
+ enum clock_type clock_type;
+ unsigned long input_freq; /* Input clock frequency to the PLL */
+
+ /* Use this when clockType = PANEL_PLL */
+ unsigned long M;
+ unsigned long N;
+ unsigned long OD;
+ unsigned long POD;
+};
+
+/* input struct to initChipParam() function */
+struct initchip_param {
+ /* Use power mode 0 or 1 */
+ unsigned short power_mode;
+
+ /*
+ * Speed of main chip clock in MHz unit
+ * 0 = keep the current clock setting
+ * Others = the new main chip clock
+ */
+ unsigned short chip_clock;
+
+ /*
+ * Speed of memory clock in MHz unit
+ * 0 = keep the current clock setting
+ * Others = the new memory clock
+ */
+ unsigned short mem_clock;
+
+ /*
+ * Speed of master clock in MHz unit
+ * 0 = keep the current clock setting
+ * Others = the new master clock
+ */
+ unsigned short master_clock;
+
+ /*
+ * 0 = leave all engine state untouched.
+ * 1 = make sure they are off: 2D, Overlay,
+ * video alpha, alpha, hardware cursors
+ */
+ unsigned short set_all_eng_off;
+
+ /*
+ * 0 = Do not reset the memory controller
+ * 1 = Reset the memory controller
+ */
+ unsigned char reset_memory;
+
+ /* More initialization parameter can be added if needed */
+};
+
+enum logical_chip_type sm750_get_chip_type(void);
+void sm750_set_chip_type(unsigned short dev_id, u8 rev_id);
+unsigned int sm750_calc_pll_value(unsigned int request, struct pll_value *pll);
+unsigned int sm750_format_pll_reg(struct pll_value *p_PLL);
+unsigned int ddk750_get_vm_size(void);
+int ddk750_init_hw(struct initchip_param *pinit_param);
+
+#endif
diff --git a/drivers/staging/sm750fb/ddk750_display.c b/drivers/staging/sm750fb/ddk750_display.c
new file mode 100644
index 000000000..172624ff9
--- /dev/null
+++ b/drivers/staging/sm750fb/ddk750_display.c
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "ddk750_reg.h"
+#include "ddk750_chip.h"
+#include "ddk750_display.h"
+#include "ddk750_power.h"
+#include "ddk750_dvi.h"
+
+static void set_display_control(int ctrl, int disp_state)
+{
+ /* state != 0 means turn on both timing & plane en_bit */
+ unsigned long reg, val, reserved;
+ int cnt = 0;
+
+ if (!ctrl) {
+ reg = PANEL_DISPLAY_CTRL;
+ reserved = PANEL_DISPLAY_CTRL_RESERVED_MASK;
+ } else {
+ reg = CRT_DISPLAY_CTRL;
+ reserved = CRT_DISPLAY_CTRL_RESERVED_MASK;
+ }
+
+ val = peek32(reg);
+ if (disp_state) {
+ /*
+ * 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.
+ */
+ val |= DISPLAY_CTRL_TIMING;
+ poke32(reg, val);
+
+ val |= DISPLAY_CTRL_PLANE;
+
+ /*
+ * 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(reg, val);
+ } while ((peek32(reg) & ~reserved) != (val & ~reserved));
+ pr_debug("Set 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.
+ */
+ val &= ~DISPLAY_CTRL_PLANE;
+ poke32(reg, val);
+
+ val &= ~DISPLAY_CTRL_TIMING;
+ poke32(reg, val);
+ }
+}
+
+static void primary_wait_vertical_sync(int delay)
+{
+ unsigned int status;
+
+ /*
+ * Do not wait when the Primary PLL is off or display control is
+ * already off. This will prevent the software to wait forever.
+ */
+ if (!(peek32(PANEL_PLL_CTRL) & PLL_CTRL_POWER) ||
+ !(peek32(PANEL_DISPLAY_CTRL) & DISPLAY_CTRL_TIMING))
+ return;
+
+ while (delay-- > 0) {
+ /* Wait for end of vsync. */
+ do {
+ status = peek32(SYSTEM_CTRL);
+ } while (status & SYSTEM_CTRL_PANEL_VSYNC_ACTIVE);
+
+ /* Wait for start of vsync. */
+ do {
+ status = peek32(SYSTEM_CTRL);
+ } while (!(status & SYSTEM_CTRL_PANEL_VSYNC_ACTIVE));
+ }
+}
+
+static void sw_panel_power_sequence(int disp, int delay)
+{
+ unsigned int reg;
+
+ /* disp should be 1 to open sequence */
+ reg = peek32(PANEL_DISPLAY_CTRL);
+ reg |= (disp ? PANEL_DISPLAY_CTRL_FPEN : 0);
+ poke32(PANEL_DISPLAY_CTRL, reg);
+ primary_wait_vertical_sync(delay);
+
+ reg = peek32(PANEL_DISPLAY_CTRL);
+ reg |= (disp ? PANEL_DISPLAY_CTRL_DATA : 0);
+ poke32(PANEL_DISPLAY_CTRL, reg);
+ primary_wait_vertical_sync(delay);
+
+ reg = peek32(PANEL_DISPLAY_CTRL);
+ reg |= (disp ? PANEL_DISPLAY_CTRL_VBIASEN : 0);
+ poke32(PANEL_DISPLAY_CTRL, reg);
+ primary_wait_vertical_sync(delay);
+
+ reg = peek32(PANEL_DISPLAY_CTRL);
+ reg |= (disp ? PANEL_DISPLAY_CTRL_FPEN : 0);
+ poke32(PANEL_DISPLAY_CTRL, reg);
+ primary_wait_vertical_sync(delay);
+}
+
+void ddk750_set_logical_disp_out(enum disp_output output)
+{
+ unsigned int reg;
+
+ if (output & PNL_2_USAGE) {
+ /* set panel path controller select */
+ reg = peek32(PANEL_DISPLAY_CTRL);
+ reg &= ~PANEL_DISPLAY_CTRL_SELECT_MASK;
+ reg |= (((output & PNL_2_MASK) >> PNL_2_OFFSET) <<
+ PANEL_DISPLAY_CTRL_SELECT_SHIFT);
+ poke32(PANEL_DISPLAY_CTRL, reg);
+ }
+
+ if (output & CRT_2_USAGE) {
+ /* set crt path controller select */
+ reg = peek32(CRT_DISPLAY_CTRL);
+ reg &= ~CRT_DISPLAY_CTRL_SELECT_MASK;
+ reg |= (((output & CRT_2_MASK) >> CRT_2_OFFSET) <<
+ CRT_DISPLAY_CTRL_SELECT_SHIFT);
+ /*se blank off */
+ reg &= ~CRT_DISPLAY_CTRL_BLANK;
+ poke32(CRT_DISPLAY_CTRL, reg);
+ }
+
+ if (output & PRI_TP_USAGE) {
+ /* set primary timing and plane en_bit */
+ set_display_control(0, (output & PRI_TP_MASK) >> PRI_TP_OFFSET);
+ }
+
+ if (output & SEC_TP_USAGE) {
+ /* set secondary timing and plane en_bit*/
+ set_display_control(1, (output & SEC_TP_MASK) >> SEC_TP_OFFSET);
+ }
+
+ if (output & PNL_SEQ_USAGE) {
+ /* set panel sequence */
+ sw_panel_power_sequence((output & PNL_SEQ_MASK) >>
+ PNL_SEQ_OFFSET, 4);
+ }
+
+ if (output & DAC_USAGE)
+ set_DAC((output & DAC_MASK) >> DAC_OFFSET);
+
+ if (output & DPMS_USAGE)
+ ddk750_set_dpms((output & DPMS_MASK) >> DPMS_OFFSET);
+}
diff --git a/drivers/staging/sm750fb/ddk750_display.h b/drivers/staging/sm750fb/ddk750_display.h
new file mode 100644
index 000000000..7f713906d
--- /dev/null
+++ b/drivers/staging/sm750fb/ddk750_display.h
@@ -0,0 +1,107 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#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 BIT(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 BIT(PNL_SEQ_OFFSET)
+#define PNL_SEQ_USAGE (PNL_SEQ_MASK << 16)
+#define PNL_SEQ_ON (BIT(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 BIT(DUAL_TFT_OFFSET)
+#define DUAL_TFT_USAGE (DUAL_TFT_MASK << 16)
+#define DUAL_TFT_ON (BIT(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 BIT(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 BIT(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
+ */
+enum disp_output {
+ 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,
+};
+
+void ddk750_set_logical_disp_out(enum disp_output output);
+
+#endif
diff --git a/drivers/staging/sm750fb/ddk750_dvi.c b/drivers/staging/sm750fb/ddk750_dvi.c
new file mode 100644
index 000000000..e0c7ff335
--- /dev/null
+++ b/drivers/staging/sm750fb/ddk750_dvi.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0
+#define USE_DVICHIP
+#ifdef USE_DVICHIP
+#include "ddk750_chip.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 struct dvi_ctrl_device dcft_supported_dvi_controller[] = {
+#ifdef DVI_CTRL_SII164
+ {
+ .init = sii164InitChip,
+ .get_vendor_id = sii164_get_vendor_id,
+ .get_device_id = sii164GetDeviceID,
+#ifdef SII164_FULL_FUNCTIONS
+ .reset_chip = sii164ResetChip,
+ .get_chip_string = sii164GetChipString,
+ .set_power = sii164SetPower,
+ .enable_hot_plug_detection = sii164EnableHotPlugDetection,
+ .is_connected = sii164IsConnected,
+ .check_interrupt = sii164CheckInterrupt,
+ .clear_interrupt = sii164ClearInterrupt,
+#endif
+ },
+#endif
+};
+
+int dvi_init(unsigned char edge_select,
+ unsigned char bus_select,
+ unsigned char dual_edge_clk_select,
+ unsigned char hsync_enable,
+ unsigned char vsync_enable,
+ unsigned char deskew_enable,
+ unsigned char deskew_setting,
+ unsigned char continuous_sync_enable,
+ unsigned char pll_filter_enable,
+ unsigned char pll_filter_value)
+{
+ struct dvi_ctrl_device *current_dvi_ctrl;
+
+ current_dvi_ctrl = dcft_supported_dvi_controller;
+ if (current_dvi_ctrl->init) {
+ return current_dvi_ctrl->init(edge_select,
+ bus_select,
+ dual_edge_clk_select,
+ hsync_enable,
+ vsync_enable,
+ deskew_enable,
+ deskew_setting,
+ continuous_sync_enable,
+ pll_filter_enable,
+ pll_filter_value);
+ }
+ return -1; /* error */
+}
+
+#endif
diff --git a/drivers/staging/sm750fb/ddk750_dvi.h b/drivers/staging/sm750fb/ddk750_dvi.h
new file mode 100644
index 000000000..c2518b73b
--- /dev/null
+++ b/drivers/staging/sm750fb/ddk750_dvi.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef DDK750_DVI_H__
+#define DDK750_DVI_H__
+
+/* dvi chip stuffs structros */
+
+typedef long (*PFN_DVICTRL_INIT)(unsigned char edge_select,
+ unsigned char bus_select,
+ unsigned char dual_edge_clk_select,
+ unsigned char hsync_enable,
+ unsigned char vsync_enable,
+ unsigned char deskew_enable,
+ unsigned char deskew_setting,
+ unsigned char continuous_sync_enable,
+ unsigned char pll_filter_enable,
+ unsigned char pll_filter_value);
+
+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 power_up);
+typedef void (*PFN_DVICTRL_HOTPLUGDETECTION)(unsigned char enable_hot_plug);
+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. */
+struct dvi_ctrl_device {
+ PFN_DVICTRL_INIT init;
+ PFN_DVICTRL_RESETCHIP reset_chip;
+ PFN_DVICTRL_GETCHIPSTRING get_chip_string;
+ PFN_DVICTRL_GETVENDORID get_vendor_id;
+ PFN_DVICTRL_GETDEVICEID get_device_id;
+ PFN_DVICTRL_SETPOWER set_power;
+ PFN_DVICTRL_HOTPLUGDETECTION enable_hot_plug_detection;
+ PFN_DVICTRL_ISCONNECTED is_connected;
+ PFN_DVICTRL_CHECKINTERRUPT check_interrupt;
+ PFN_DVICTRL_CLEARINTERRUPT clear_interrupt;
+};
+
+#define DVI_CTRL_SII164
+
+/* dvi functions prototype */
+int dvi_init(unsigned char edge_select,
+ unsigned char bus_select,
+ unsigned char dual_edge_clk_select,
+ unsigned char hsync_enable,
+ unsigned char vsync_enable,
+ unsigned char deskew_enable,
+ unsigned char deskew_setting,
+ unsigned char continuous_sync_enable,
+ unsigned char pll_filter_enable,
+ unsigned char pll_filter_value);
+
+#endif
+
diff --git a/drivers/staging/sm750fb/ddk750_hwi2c.c b/drivers/staging/sm750fb/ddk750_hwi2c.c
new file mode 100644
index 000000000..8482689b6
--- /dev/null
+++ b/drivers/staging/sm750fb/ddk750_hwi2c.c
@@ -0,0 +1,247 @@
+// SPDX-License-Identifier: GPL-2.0
+#define USE_HW_I2C
+#ifdef USE_HW_I2C
+#include "ddk750_chip.h"
+#include "ddk750_reg.h"
+#include "ddk750_hwi2c.h"
+#include "ddk750_power.h"
+
+#define MAX_HWI2C_FIFO 16
+#define HWI2C_WAIT_TIMEOUT 0xF0000
+
+int sm750_hw_i2c_init(unsigned char bus_speed_mode)
+{
+ unsigned int value;
+
+ /* Enable GPIO 30 & 31 as IIC clock & data */
+ value = peek32(GPIO_MUX);
+
+ value |= (GPIO_MUX_30 | GPIO_MUX_31);
+ poke32(GPIO_MUX, value);
+
+ /*
+ * Enable Hardware I2C power.
+ * TODO: Check if we need to enable GPIO power?
+ */
+ sm750_enable_i2c(1);
+
+ /* Enable the I2C Controller and set the bus speed mode */
+ value = peek32(I2C_CTRL) & ~(I2C_CTRL_MODE | I2C_CTRL_EN);
+ if (bus_speed_mode)
+ value |= I2C_CTRL_MODE;
+ value |= I2C_CTRL_EN;
+ poke32(I2C_CTRL, value);
+
+ return 0;
+}
+
+void sm750_hw_i2c_close(void)
+{
+ unsigned int value;
+
+ /* Disable I2C controller */
+ value = peek32(I2C_CTRL) & ~I2C_CTRL_EN;
+ poke32(I2C_CTRL, value);
+
+ /* Disable I2C Power */
+ sm750_enable_i2c(0);
+
+ /* Set GPIO 30 & 31 back as GPIO pins */
+ value = peek32(GPIO_MUX);
+ value &= ~GPIO_MUX_30;
+ value &= ~GPIO_MUX_31;
+ poke32(GPIO_MUX, value);
+}
+
+static long hw_i2c_wait_tx_done(void)
+{
+ unsigned int timeout;
+
+ /* Wait until the transfer is completed. */
+ timeout = HWI2C_WAIT_TIMEOUT;
+ while (!(peek32(I2C_STATUS) & I2C_STATUS_TX) && (timeout != 0))
+ timeout--;
+
+ if (timeout == 0)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * This function writes data to the i2c slave device registers.
+ *
+ * Parameters:
+ * addr - i2c Slave device address
+ * length - Total number of bytes to be written to the device
+ * buf - The buffer that contains the data to be written to the
+ * i2c device.
+ *
+ * Return Value:
+ * Total number of bytes those are actually written.
+ */
+static unsigned int hw_i2c_write_data(unsigned char addr,
+ unsigned int length,
+ unsigned char *buf)
+{
+ unsigned char count, i;
+ unsigned int total_bytes = 0;
+
+ /* Set the Device Address */
+ poke32(I2C_SLAVE_ADDRESS, addr & ~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, *buf++);
+
+ /* Start the I2C */
+ poke32(I2C_CTRL, peek32(I2C_CTRL) | I2C_CTRL_CTRL);
+
+ /* Wait until the transfer is completed. */
+ if (hw_i2c_wait_tx_done() != 0)
+ break;
+
+ /* Subtract length */
+ length -= (count + 1);
+
+ /* Total byte written */
+ total_bytes += (count + 1);
+
+ } while (length > 0);
+
+ return total_bytes;
+}
+
+/*
+ * This function reads data from the slave device and stores them
+ * in the given buffer
+ *
+ * Parameters:
+ * addr - i2c Slave device address
+ * length - Total number of bytes to be read
+ * buf - 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
+ */
+static unsigned int hw_i2c_read_data(unsigned char addr,
+ unsigned int length,
+ unsigned char *buf)
+{
+ unsigned char count, i;
+ unsigned int total_bytes = 0;
+
+ /* Set the Device Address */
+ poke32(I2C_SLAVE_ADDRESS, addr | 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) | I2C_CTRL_CTRL);
+
+ /* Wait until transaction done. */
+ if (hw_i2c_wait_tx_done() != 0)
+ break;
+
+ /* Save the data to the given buffer */
+ for (i = 0; i <= count; i++)
+ *buf++ = peek32(I2C_DATA0 + i);
+
+ /* Subtract length by 16 */
+ length -= (count + 1);
+
+ /* Number of bytes read. */
+ total_bytes += (count + 1);
+
+ } while (length > 0);
+
+ return total_bytes;
+}
+
+/*
+ * 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 sm750_hw_i2c_read_reg(unsigned char addr, unsigned char reg)
+{
+ unsigned char value = 0xFF;
+
+ if (hw_i2c_write_data(addr, 1, &reg) == 1)
+ hw_i2c_read_data(addr, 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 sm750_hw_i2c_write_reg(unsigned char addr,
+ unsigned char reg,
+ unsigned char data)
+{
+ unsigned char value[2];
+
+ value[0] = reg;
+ value[1] = data;
+ if (hw_i2c_write_data(addr, 2, value) == 2)
+ return 0;
+
+ return -1;
+}
+
+#endif
diff --git a/drivers/staging/sm750fb/ddk750_hwi2c.h b/drivers/staging/sm750fb/ddk750_hwi2c.h
new file mode 100644
index 000000000..337c6493c
--- /dev/null
+++ b/drivers/staging/sm750fb/ddk750_hwi2c.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef DDK750_HWI2C_H__
+#define DDK750_HWI2C_H__
+
+/* hwi2c functions */
+int sm750_hw_i2c_init(unsigned char bus_speed_mode);
+void sm750_hw_i2c_close(void);
+
+unsigned char sm750_hw_i2c_read_reg(unsigned char addr, unsigned char reg);
+int sm750_hw_i2c_write_reg(unsigned char addr, unsigned char reg,
+ unsigned char data);
+#endif
diff --git a/drivers/staging/sm750fb/ddk750_mode.c b/drivers/staging/sm750fb/ddk750_mode.c
new file mode 100644
index 000000000..e00a6cb31
--- /dev/null
+++ b/drivers/staging/sm750fb/ddk750_mode.c
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#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(struct mode_parameter *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, 0);
+
+ poke32(CRT_AUTO_CENTERING_BR,
+ (((y - 1) << CRT_AUTO_CENTERING_BR_BOTTOM_SHIFT) &
+ CRT_AUTO_CENTERING_BR_BOTTOM_MASK) |
+ ((x - 1) & CRT_AUTO_CENTERING_BR_RIGHT_MASK));
+
+ /*
+ * Assume common fields in dispControl have been properly set before
+ * calling this function.
+ * This function only sets the extra fields in dispControl.
+ */
+
+ /* Clear bit 29:27 of display control register */
+ dispControl &= ~CRT_DISPLAY_CTRL_CLK_MASK;
+
+ /* Set bit 29:27 of display control register for the right clock */
+ /* Note that SM750LE only need to supported 7 resolutions. */
+ if (x == 800 && y == 600)
+ dispControl |= CRT_DISPLAY_CTRL_CLK_PLL41;
+ else if (x == 1024 && y == 768)
+ dispControl |= CRT_DISPLAY_CTRL_CLK_PLL65;
+ else if (x == 1152 && y == 864)
+ dispControl |= CRT_DISPLAY_CTRL_CLK_PLL80;
+ else if (x == 1280 && y == 768)
+ dispControl |= CRT_DISPLAY_CTRL_CLK_PLL80;
+ else if (x == 1280 && y == 720)
+ dispControl |= CRT_DISPLAY_CTRL_CLK_PLL74;
+ else if (x == 1280 && y == 960)
+ dispControl |= CRT_DISPLAY_CTRL_CLK_PLL108;
+ else if (x == 1280 && y == 1024)
+ dispControl |= CRT_DISPLAY_CTRL_CLK_PLL108;
+ else /* default to VGA clock */
+ dispControl |= CRT_DISPLAY_CTRL_CLK_PLL25;
+
+ /* Set bit 25:24 of display controller */
+ dispControl |= (CRT_DISPLAY_CTRL_CRTSELECT | CRT_DISPLAY_CTRL_RGBBIT);
+
+ /* Set bit 14 of display controller */
+ dispControl |= DISPLAY_CTRL_CLOCK_PHASE;
+
+ poke32(CRT_DISPLAY_CTRL, dispControl);
+
+ return dispControl;
+}
+
+/* only timing related registers will be programed */
+static int programModeRegisters(struct mode_parameter *pModeParam,
+ struct pll_value *pll)
+{
+ int ret = 0;
+ int cnt = 0;
+ unsigned int tmp, reg;
+
+ if (pll->clock_type == SECONDARY_PLL) {
+ /* programe secondary pixel clock */
+ poke32(CRT_PLL_CTRL, sm750_format_pll_reg(pll));
+
+ tmp = ((pModeParam->horizontal_total - 1) <<
+ CRT_HORIZONTAL_TOTAL_TOTAL_SHIFT) &
+ CRT_HORIZONTAL_TOTAL_TOTAL_MASK;
+ tmp |= (pModeParam->horizontal_display_end - 1) &
+ CRT_HORIZONTAL_TOTAL_DISPLAY_END_MASK;
+
+ poke32(CRT_HORIZONTAL_TOTAL, tmp);
+
+ tmp = (pModeParam->horizontal_sync_width <<
+ CRT_HORIZONTAL_SYNC_WIDTH_SHIFT) &
+ CRT_HORIZONTAL_SYNC_WIDTH_MASK;
+ tmp |= (pModeParam->horizontal_sync_start - 1) &
+ CRT_HORIZONTAL_SYNC_START_MASK;
+
+ poke32(CRT_HORIZONTAL_SYNC, tmp);
+
+ tmp = ((pModeParam->vertical_total - 1) <<
+ CRT_VERTICAL_TOTAL_TOTAL_SHIFT) &
+ CRT_VERTICAL_TOTAL_TOTAL_MASK;
+ tmp |= (pModeParam->vertical_display_end - 1) &
+ CRT_VERTICAL_TOTAL_DISPLAY_END_MASK;
+
+ poke32(CRT_VERTICAL_TOTAL, tmp);
+
+ tmp = ((pModeParam->vertical_sync_height <<
+ CRT_VERTICAL_SYNC_HEIGHT_SHIFT)) &
+ CRT_VERTICAL_SYNC_HEIGHT_MASK;
+ tmp |= (pModeParam->vertical_sync_start - 1) &
+ CRT_VERTICAL_SYNC_START_MASK;
+
+ poke32(CRT_VERTICAL_SYNC, tmp);
+
+ tmp = DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE;
+ if (pModeParam->vertical_sync_polarity)
+ tmp |= DISPLAY_CTRL_VSYNC_PHASE;
+ if (pModeParam->horizontal_sync_polarity)
+ tmp |= DISPLAY_CTRL_HSYNC_PHASE;
+
+ if (sm750_get_chip_type() == SM750LE) {
+ displayControlAdjust_SM750LE(pModeParam, tmp);
+ } else {
+ reg = peek32(CRT_DISPLAY_CTRL) &
+ ~(DISPLAY_CTRL_VSYNC_PHASE |
+ DISPLAY_CTRL_HSYNC_PHASE |
+ DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE);
+
+ poke32(CRT_DISPLAY_CTRL, tmp | reg);
+ }
+
+ } else if (pll->clock_type == PRIMARY_PLL) {
+ unsigned int reserved;
+
+ poke32(PANEL_PLL_CTRL, sm750_format_pll_reg(pll));
+
+ reg = ((pModeParam->horizontal_total - 1) <<
+ PANEL_HORIZONTAL_TOTAL_TOTAL_SHIFT) &
+ PANEL_HORIZONTAL_TOTAL_TOTAL_MASK;
+ reg |= ((pModeParam->horizontal_display_end - 1) &
+ PANEL_HORIZONTAL_TOTAL_DISPLAY_END_MASK);
+ poke32(PANEL_HORIZONTAL_TOTAL, reg);
+
+ poke32(PANEL_HORIZONTAL_SYNC,
+ ((pModeParam->horizontal_sync_width <<
+ PANEL_HORIZONTAL_SYNC_WIDTH_SHIFT) &
+ PANEL_HORIZONTAL_SYNC_WIDTH_MASK) |
+ ((pModeParam->horizontal_sync_start - 1) &
+ PANEL_HORIZONTAL_SYNC_START_MASK));
+
+ poke32(PANEL_VERTICAL_TOTAL,
+ (((pModeParam->vertical_total - 1) <<
+ PANEL_VERTICAL_TOTAL_TOTAL_SHIFT) &
+ PANEL_VERTICAL_TOTAL_TOTAL_MASK) |
+ ((pModeParam->vertical_display_end - 1) &
+ PANEL_VERTICAL_TOTAL_DISPLAY_END_MASK));
+
+ poke32(PANEL_VERTICAL_SYNC,
+ ((pModeParam->vertical_sync_height <<
+ PANEL_VERTICAL_SYNC_HEIGHT_SHIFT) &
+ PANEL_VERTICAL_SYNC_HEIGHT_MASK) |
+ ((pModeParam->vertical_sync_start - 1) &
+ PANEL_VERTICAL_SYNC_START_MASK));
+
+ tmp = DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE;
+ if (pModeParam->vertical_sync_polarity)
+ tmp |= DISPLAY_CTRL_VSYNC_PHASE;
+ if (pModeParam->horizontal_sync_polarity)
+ tmp |= DISPLAY_CTRL_HSYNC_PHASE;
+ if (pModeParam->clock_phase_polarity)
+ tmp |= DISPLAY_CTRL_CLOCK_PHASE;
+
+ reserved = PANEL_DISPLAY_CTRL_RESERVED_MASK |
+ PANEL_DISPLAY_CTRL_VSYNC;
+
+ reg = (peek32(PANEL_DISPLAY_CTRL) & ~reserved) &
+ ~(DISPLAY_CTRL_CLOCK_PHASE | DISPLAY_CTRL_VSYNC_PHASE |
+ DISPLAY_CTRL_HSYNC_PHASE | DISPLAY_CTRL_TIMING |
+ DISPLAY_CTRL_PLANE);
+
+ /*
+ * May a hardware bug or just my test chip (not confirmed).
+ * PANEL_DISPLAY_CTRL register seems requiring few writes
+ * before a value can be successfully 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, tmp | reg);
+
+ while ((peek32(PANEL_DISPLAY_CTRL) & ~reserved) !=
+ (tmp | reg)) {
+ cnt++;
+ if (cnt > 1000)
+ break;
+ poke32(PANEL_DISPLAY_CTRL, tmp | reg);
+ }
+ } else {
+ ret = -1;
+ }
+ return ret;
+}
+
+int ddk750_setModeTiming(struct mode_parameter *parm, enum clock_type clock)
+{
+ struct pll_value pll;
+
+ pll.input_freq = DEFAULT_INPUT_CLOCK;
+ pll.clock_type = clock;
+
+ sm750_calc_pll_value(parm->pixel_clock, &pll);
+ if (sm750_get_chip_type() == SM750LE) {
+ /* set graphic mode via IO method */
+ outb_p(0x88, 0x3d4);
+ outb_p(0x06, 0x3d5);
+ }
+ programModeRegisters(parm, &pll);
+ return 0;
+}
diff --git a/drivers/staging/sm750fb/ddk750_mode.h b/drivers/staging/sm750fb/ddk750_mode.h
new file mode 100644
index 000000000..2df78a093
--- /dev/null
+++ b/drivers/staging/sm750fb/ddk750_mode.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef DDK750_MODE_H__
+#define DDK750_MODE_H__
+
+#include "ddk750_chip.h"
+
+enum spolarity {
+ POS = 0, /* positive */
+ NEG, /* negative */
+};
+
+struct mode_parameter {
+ /* Horizontal timing. */
+ unsigned long horizontal_total;
+ unsigned long horizontal_display_end;
+ unsigned long horizontal_sync_start;
+ unsigned long horizontal_sync_width;
+ enum spolarity horizontal_sync_polarity;
+
+ /* Vertical timing. */
+ unsigned long vertical_total;
+ unsigned long vertical_display_end;
+ unsigned long vertical_sync_start;
+ unsigned long vertical_sync_height;
+ enum spolarity 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. */
+ enum spolarity clock_phase_polarity;
+};
+
+int ddk750_setModeTiming(struct mode_parameter *parm, enum clock_type clock);
+#endif
diff --git a/drivers/staging/sm750fb/ddk750_power.c b/drivers/staging/sm750fb/ddk750_power.c
new file mode 100644
index 000000000..12834f78e
--- /dev/null
+++ b/drivers/staging/sm750fb/ddk750_power.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "ddk750_chip.h"
+#include "ddk750_reg.h"
+#include "ddk750_power.h"
+
+void ddk750_set_dpms(enum dpms state)
+{
+ unsigned int value;
+
+ if (sm750_get_chip_type() == SM750LE) {
+ value = peek32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_DPMS_MASK;
+ value |= (state << CRT_DISPLAY_CTRL_DPMS_SHIFT);
+ poke32(CRT_DISPLAY_CTRL, value);
+ } else {
+ value = peek32(SYSTEM_CTRL);
+ value = (value & ~SYSTEM_CTRL_DPMS_MASK) | state;
+ poke32(SYSTEM_CTRL, value);
+ }
+}
+
+static unsigned int get_power_mode(void)
+{
+ if (sm750_get_chip_type() == SM750LE)
+ return 0;
+ return peek32(POWER_MODE_CTRL) & POWER_MODE_CTRL_MODE_MASK;
+}
+
+/*
+ * SM50x can operate in one of three modes: 0, 1 or Sleep.
+ * On hardware reset, power mode 0 is default.
+ */
+void sm750_set_power_mode(unsigned int mode)
+{
+ unsigned int ctrl = 0;
+
+ ctrl = peek32(POWER_MODE_CTRL) & ~POWER_MODE_CTRL_MODE_MASK;
+
+ if (sm750_get_chip_type() == SM750LE)
+ return;
+
+ switch (mode) {
+ case POWER_MODE_CTRL_MODE_MODE0:
+ ctrl |= POWER_MODE_CTRL_MODE_MODE0;
+ break;
+
+ case POWER_MODE_CTRL_MODE_MODE1:
+ ctrl |= POWER_MODE_CTRL_MODE_MODE1;
+ break;
+
+ case POWER_MODE_CTRL_MODE_SLEEP:
+ ctrl |= POWER_MODE_CTRL_MODE_SLEEP;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Set up other fields in Power Control Register */
+ if (mode == POWER_MODE_CTRL_MODE_SLEEP) {
+ ctrl &= ~POWER_MODE_CTRL_OSC_INPUT;
+#ifdef VALIDATION_CHIP
+ ctrl &= ~POWER_MODE_CTRL_336CLK;
+#endif
+ } else {
+ ctrl |= POWER_MODE_CTRL_OSC_INPUT;
+#ifdef VALIDATION_CHIP
+ ctrl |= POWER_MODE_CTRL_336CLK;
+#endif
+ }
+
+ /* Program new power mode. */
+ poke32(POWER_MODE_CTRL, ctrl);
+}
+
+void sm750_set_current_gate(unsigned int gate)
+{
+ if (get_power_mode() == POWER_MODE_CTRL_MODE_MODE1)
+ poke32(MODE1_GATE, gate);
+ else
+ poke32(MODE0_GATE, gate);
+}
+
+/*
+ * This function enable/disable the 2D engine.
+ */
+void sm750_enable_2d_engine(unsigned int enable)
+{
+ u32 gate;
+
+ gate = peek32(CURRENT_GATE);
+ if (enable)
+ gate |= (CURRENT_GATE_DE | CURRENT_GATE_CSC);
+ else
+ gate &= ~(CURRENT_GATE_DE | CURRENT_GATE_CSC);
+
+ sm750_set_current_gate(gate);
+}
+
+void sm750_enable_dma(unsigned int enable)
+{
+ u32 gate;
+
+ /* Enable DMA Gate */
+ gate = peek32(CURRENT_GATE);
+ if (enable)
+ gate |= CURRENT_GATE_DMA;
+ else
+ gate &= ~CURRENT_GATE_DMA;
+
+ sm750_set_current_gate(gate);
+}
+
+/*
+ * This function enable/disable the GPIO Engine
+ */
+void sm750_enable_gpio(unsigned int enable)
+{
+ u32 gate;
+
+ /* Enable GPIO Gate */
+ gate = peek32(CURRENT_GATE);
+ if (enable)
+ gate |= CURRENT_GATE_GPIO;
+ else
+ gate &= ~CURRENT_GATE_GPIO;
+
+ sm750_set_current_gate(gate);
+}
+
+/*
+ * This function enable/disable the I2C Engine
+ */
+void sm750_enable_i2c(unsigned int enable)
+{
+ u32 gate;
+
+ /* Enable I2C Gate */
+ gate = peek32(CURRENT_GATE);
+ if (enable)
+ gate |= CURRENT_GATE_I2C;
+ else
+ gate &= ~CURRENT_GATE_I2C;
+
+ sm750_set_current_gate(gate);
+}
diff --git a/drivers/staging/sm750fb/ddk750_power.h b/drivers/staging/sm750fb/ddk750_power.h
new file mode 100644
index 000000000..63c9e8b6f
--- /dev/null
+++ b/drivers/staging/sm750fb/ddk750_power.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef DDK750_POWER_H__
+#define DDK750_POWER_H__
+
+enum dpms {
+ crtDPMS_ON = 0x0,
+ crtDPMS_STANDBY = 0x1,
+ crtDPMS_SUSPEND = 0x2,
+ crtDPMS_OFF = 0x3,
+};
+
+#define set_DAC(off) { \
+ poke32(MISC_CTRL, \
+ (peek32(MISC_CTRL) & ~MISC_CTRL_DAC_POWER_OFF) | (off)); \
+}
+
+void ddk750_set_dpms(enum dpms state);
+void sm750_set_power_mode(unsigned int mode);
+void sm750_set_current_gate(unsigned int gate);
+
+/*
+ * This function enable/disable the 2D engine.
+ */
+void sm750_enable_2d_engine(unsigned int enable);
+
+/*
+ * This function enable/disable the DMA Engine
+ */
+void sm750_enable_dma(unsigned int enable);
+
+/*
+ * This function enable/disable the GPIO Engine
+ */
+void sm750_enable_gpio(unsigned int enable);
+
+/*
+ * This function enable/disable the I2C Engine
+ */
+void sm750_enable_i2c(unsigned int enable);
+
+#endif
diff --git a/drivers/staging/sm750fb/ddk750_reg.h b/drivers/staging/sm750fb/ddk750_reg.h
new file mode 100644
index 000000000..fe412ead7
--- /dev/null
+++ b/drivers/staging/sm750fb/ddk750_reg.h
@@ -0,0 +1,1455 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef DDK750_REG_H__
+#define DDK750_REG_H__
+
+/* New register for SM750LE */
+#define DE_STATE1 0x100054
+#define DE_STATE1_DE_ABORT BIT(0)
+
+#define DE_STATE2 0x100058
+#define DE_STATE2_DE_FIFO_EMPTY BIT(3)
+#define DE_STATE2_DE_STATUS_BUSY BIT(2)
+#define DE_STATE2_DE_MEM_FIFO_EMPTY BIT(1)
+
+#define SYSTEM_CTRL 0x000000
+#define SYSTEM_CTRL_DPMS_MASK (0x3 << 30)
+#define SYSTEM_CTRL_DPMS_VPHP (0x0 << 30)
+#define SYSTEM_CTRL_DPMS_VPHN (0x1 << 30)
+#define SYSTEM_CTRL_DPMS_VNHP (0x2 << 30)
+#define SYSTEM_CTRL_DPMS_VNHN (0x3 << 30)
+#define SYSTEM_CTRL_PCI_BURST BIT(29)
+#define SYSTEM_CTRL_PCI_MASTER BIT(25)
+#define SYSTEM_CTRL_LATENCY_TIMER_OFF BIT(24)
+#define SYSTEM_CTRL_DE_FIFO_EMPTY BIT(23)
+#define SYSTEM_CTRL_DE_STATUS_BUSY BIT(22)
+#define SYSTEM_CTRL_DE_MEM_FIFO_EMPTY BIT(21)
+#define SYSTEM_CTRL_CSC_STATUS_BUSY BIT(20)
+#define SYSTEM_CTRL_CRT_VSYNC_ACTIVE BIT(19)
+#define SYSTEM_CTRL_PANEL_VSYNC_ACTIVE BIT(18)
+#define SYSTEM_CTRL_CURRENT_BUFFER_FLIP_PENDING BIT(17)
+#define SYSTEM_CTRL_DMA_STATUS_BUSY BIT(16)
+#define SYSTEM_CTRL_PCI_BURST_READ BIT(15)
+#define SYSTEM_CTRL_DE_ABORT BIT(13)
+#define SYSTEM_CTRL_PCI_SUBSYS_ID_LOCK BIT(11)
+#define SYSTEM_CTRL_PCI_RETRY_OFF BIT(7)
+#define SYSTEM_CTRL_PCI_SLAVE_BURST_READ_SIZE_MASK (0x3 << 4)
+#define SYSTEM_CTRL_PCI_SLAVE_BURST_READ_SIZE_1 (0x0 << 4)
+#define SYSTEM_CTRL_PCI_SLAVE_BURST_READ_SIZE_2 (0x1 << 4)
+#define SYSTEM_CTRL_PCI_SLAVE_BURST_READ_SIZE_4 (0x2 << 4)
+#define SYSTEM_CTRL_PCI_SLAVE_BURST_READ_SIZE_8 (0x3 << 4)
+#define SYSTEM_CTRL_CRT_TRISTATE BIT(3)
+#define SYSTEM_CTRL_PCIMEM_TRISTATE BIT(2)
+#define SYSTEM_CTRL_LOCALMEM_TRISTATE BIT(1)
+#define SYSTEM_CTRL_PANEL_TRISTATE BIT(0)
+
+#define MISC_CTRL 0x000004
+#define MISC_CTRL_DRAM_RERESH_COUNT BIT(27)
+#define MISC_CTRL_DRAM_REFRESH_TIME_MASK (0x3 << 25)
+#define MISC_CTRL_DRAM_REFRESH_TIME_8 (0x0 << 25)
+#define MISC_CTRL_DRAM_REFRESH_TIME_16 (0x1 << 25)
+#define MISC_CTRL_DRAM_REFRESH_TIME_32 (0x2 << 25)
+#define MISC_CTRL_DRAM_REFRESH_TIME_64 (0x3 << 25)
+#define MISC_CTRL_INT_OUTPUT_INVERT BIT(24)
+#define MISC_CTRL_PLL_CLK_COUNT BIT(23)
+#define MISC_CTRL_DAC_POWER_OFF BIT(20)
+#define MISC_CTRL_CLK_SELECT_TESTCLK BIT(16)
+#define MISC_CTRL_DRAM_COLUMN_SIZE_MASK (0x3 << 14)
+#define MISC_CTRL_DRAM_COLUMN_SIZE_256 (0x0 << 14)
+#define MISC_CTRL_DRAM_COLUMN_SIZE_512 (0x1 << 14)
+#define MISC_CTRL_DRAM_COLUMN_SIZE_1024 (0x2 << 14)
+#define MISC_CTRL_LOCALMEM_SIZE_MASK (0x3 << 12)
+#define MISC_CTRL_LOCALMEM_SIZE_8M (0x3 << 12)
+#define MISC_CTRL_LOCALMEM_SIZE_16M (0x0 << 12)
+#define MISC_CTRL_LOCALMEM_SIZE_32M (0x1 << 12)
+#define MISC_CTRL_LOCALMEM_SIZE_64M (0x2 << 12)
+#define MISC_CTRL_DRAM_TWTR BIT(11)
+#define MISC_CTRL_DRAM_TWR BIT(10)
+#define MISC_CTRL_DRAM_TRP BIT(9)
+#define MISC_CTRL_DRAM_TRFC BIT(8)
+#define MISC_CTRL_DRAM_TRAS BIT(7)
+#define MISC_CTRL_LOCALMEM_RESET BIT(6)
+#define MISC_CTRL_LOCALMEM_STATE_INACTIVE BIT(5)
+#define MISC_CTRL_CPU_CAS_LATENCY BIT(4)
+#define MISC_CTRL_DLL_OFF BIT(3)
+#define MISC_CTRL_DRAM_OUTPUT_HIGH BIT(2)
+#define MISC_CTRL_LOCALMEM_BUS_SIZE BIT(1)
+#define MISC_CTRL_EMBEDDED_LOCALMEM_OFF BIT(0)
+
+#define GPIO_MUX 0x000008
+#define GPIO_MUX_31 BIT(31)
+#define GPIO_MUX_30 BIT(30)
+#define GPIO_MUX_29 BIT(29)
+#define GPIO_MUX_28 BIT(28)
+#define GPIO_MUX_27 BIT(27)
+#define GPIO_MUX_26 BIT(26)
+#define GPIO_MUX_25 BIT(25)
+#define GPIO_MUX_24 BIT(24)
+#define GPIO_MUX_23 BIT(23)
+#define GPIO_MUX_22 BIT(22)
+#define GPIO_MUX_21 BIT(21)
+#define GPIO_MUX_20 BIT(20)
+#define GPIO_MUX_19 BIT(19)
+#define GPIO_MUX_18 BIT(18)
+#define GPIO_MUX_17 BIT(17)
+#define GPIO_MUX_16 BIT(16)
+#define GPIO_MUX_15 BIT(15)
+#define GPIO_MUX_14 BIT(14)
+#define GPIO_MUX_13 BIT(13)
+#define GPIO_MUX_12 BIT(12)
+#define GPIO_MUX_11 BIT(11)
+#define GPIO_MUX_10 BIT(10)
+#define GPIO_MUX_9 BIT(9)
+#define GPIO_MUX_8 BIT(8)
+#define GPIO_MUX_7 BIT(7)
+#define GPIO_MUX_6 BIT(6)
+#define GPIO_MUX_5 BIT(5)
+#define GPIO_MUX_4 BIT(4)
+#define GPIO_MUX_3 BIT(3)
+#define GPIO_MUX_2 BIT(2)
+#define GPIO_MUX_1 BIT(1)
+#define GPIO_MUX_0 BIT(0)
+
+#define LOCALMEM_ARBITRATION 0x00000C
+#define LOCALMEM_ARBITRATION_ROTATE BIT(28)
+#define LOCALMEM_ARBITRATION_VGA_MASK (0x7 << 24)
+#define LOCALMEM_ARBITRATION_VGA_OFF (0x0 << 24)
+#define LOCALMEM_ARBITRATION_VGA_PRIORITY_1 (0x1 << 24)
+#define LOCALMEM_ARBITRATION_VGA_PRIORITY_2 (0x2 << 24)
+#define LOCALMEM_ARBITRATION_VGA_PRIORITY_3 (0x3 << 24)
+#define LOCALMEM_ARBITRATION_VGA_PRIORITY_4 (0x4 << 24)
+#define LOCALMEM_ARBITRATION_VGA_PRIORITY_5 (0x5 << 24)
+#define LOCALMEM_ARBITRATION_VGA_PRIORITY_6 (0x6 << 24)
+#define LOCALMEM_ARBITRATION_VGA_PRIORITY_7 (0x7 << 24)
+#define LOCALMEM_ARBITRATION_DMA_MASK (0x7 << 20)
+#define LOCALMEM_ARBITRATION_DMA_OFF (0x0 << 20)
+#define LOCALMEM_ARBITRATION_DMA_PRIORITY_1 (0x1 << 20)
+#define LOCALMEM_ARBITRATION_DMA_PRIORITY_2 (0x2 << 20)
+#define LOCALMEM_ARBITRATION_DMA_PRIORITY_3 (0x3 << 20)
+#define LOCALMEM_ARBITRATION_DMA_PRIORITY_4 (0x4 << 20)
+#define LOCALMEM_ARBITRATION_DMA_PRIORITY_5 (0x5 << 20)
+#define LOCALMEM_ARBITRATION_DMA_PRIORITY_6 (0x6 << 20)
+#define LOCALMEM_ARBITRATION_DMA_PRIORITY_7 (0x7 << 20)
+#define LOCALMEM_ARBITRATION_ZVPORT1_MASK (0x7 << 16)
+#define LOCALMEM_ARBITRATION_ZVPORT1_OFF (0x0 << 16)
+#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_1 (0x1 << 16)
+#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_2 (0x2 << 16)
+#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_3 (0x3 << 16)
+#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_4 (0x4 << 16)
+#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_5 (0x5 << 16)
+#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_6 (0x6 << 16)
+#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_7 (0x7 << 16)
+#define LOCALMEM_ARBITRATION_ZVPORT0_MASK (0x7 << 12)
+#define LOCALMEM_ARBITRATION_ZVPORT0_OFF (0x0 << 12)
+#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_1 (0x1 << 12)
+#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_2 (0x2 << 12)
+#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_3 (0x3 << 12)
+#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_4 (0x4 << 12)
+#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_5 (0x5 << 12)
+#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_6 (0x6 << 12)
+#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_7 (0x7 << 12)
+#define LOCALMEM_ARBITRATION_VIDEO_MASK (0x7 << 8)
+#define LOCALMEM_ARBITRATION_VIDEO_OFF (0x0 << 8)
+#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_1 (0x1 << 8)
+#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_2 (0x2 << 8)
+#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_3 (0x3 << 8)
+#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_4 (0x4 << 8)
+#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_5 (0x5 << 8)
+#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_6 (0x6 << 8)
+#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_7 (0x7 << 8)
+#define LOCALMEM_ARBITRATION_PANEL_MASK (0x7 << 4)
+#define LOCALMEM_ARBITRATION_PANEL_OFF (0x0 << 4)
+#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_1 (0x1 << 4)
+#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_2 (0x2 << 4)
+#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_3 (0x3 << 4)
+#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_4 (0x4 << 4)
+#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_5 (0x5 << 4)
+#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_6 (0x6 << 4)
+#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_7 (0x7 << 4)
+#define LOCALMEM_ARBITRATION_CRT_MASK 0x7
+#define LOCALMEM_ARBITRATION_CRT_OFF 0x0
+#define LOCALMEM_ARBITRATION_CRT_PRIORITY_1 0x1
+#define LOCALMEM_ARBITRATION_CRT_PRIORITY_2 0x2
+#define LOCALMEM_ARBITRATION_CRT_PRIORITY_3 0x3
+#define LOCALMEM_ARBITRATION_CRT_PRIORITY_4 0x4
+#define LOCALMEM_ARBITRATION_CRT_PRIORITY_5 0x5
+#define LOCALMEM_ARBITRATION_CRT_PRIORITY_6 0x6
+#define LOCALMEM_ARBITRATION_CRT_PRIORITY_7 0x7
+
+#define PCIMEM_ARBITRATION 0x000010
+#define PCIMEM_ARBITRATION_ROTATE BIT(28)
+#define PCIMEM_ARBITRATION_VGA_MASK (0x7 << 24)
+#define PCIMEM_ARBITRATION_VGA_OFF (0x0 << 24)
+#define PCIMEM_ARBITRATION_VGA_PRIORITY_1 (0x1 << 24)
+#define PCIMEM_ARBITRATION_VGA_PRIORITY_2 (0x2 << 24)
+#define PCIMEM_ARBITRATION_VGA_PRIORITY_3 (0x3 << 24)
+#define PCIMEM_ARBITRATION_VGA_PRIORITY_4 (0x4 << 24)
+#define PCIMEM_ARBITRATION_VGA_PRIORITY_5 (0x5 << 24)
+#define PCIMEM_ARBITRATION_VGA_PRIORITY_6 (0x6 << 24)
+#define PCIMEM_ARBITRATION_VGA_PRIORITY_7 (0x7 << 24)
+#define PCIMEM_ARBITRATION_DMA_MASK (0x7 << 20)
+#define PCIMEM_ARBITRATION_DMA_OFF (0x0 << 20)
+#define PCIMEM_ARBITRATION_DMA_PRIORITY_1 (0x1 << 20)
+#define PCIMEM_ARBITRATION_DMA_PRIORITY_2 (0x2 << 20)
+#define PCIMEM_ARBITRATION_DMA_PRIORITY_3 (0x3 << 20)
+#define PCIMEM_ARBITRATION_DMA_PRIORITY_4 (0x4 << 20)
+#define PCIMEM_ARBITRATION_DMA_PRIORITY_5 (0x5 << 20)
+#define PCIMEM_ARBITRATION_DMA_PRIORITY_6 (0x6 << 20)
+#define PCIMEM_ARBITRATION_DMA_PRIORITY_7 (0x7 << 20)
+#define PCIMEM_ARBITRATION_ZVPORT1_MASK (0x7 << 16)
+#define PCIMEM_ARBITRATION_ZVPORT1_OFF (0x0 << 16)
+#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_1 (0x1 << 16)
+#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_2 (0x2 << 16)
+#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_3 (0x3 << 16)
+#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_4 (0x4 << 16)
+#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_5 (0x5 << 16)
+#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_6 (0x6 << 16)
+#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_7 (0x7 << 16)
+#define PCIMEM_ARBITRATION_ZVPORT0_MASK (0x7 << 12)
+#define PCIMEM_ARBITRATION_ZVPORT0_OFF (0x0 << 12)
+#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_1 (0x1 << 12)
+#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_2 (0x2 << 12)
+#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_3 (0x3 << 12)
+#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_4 (0x4 << 12)
+#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_5 (0x5 << 12)
+#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_6 (0x6 << 12)
+#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_7 (0x7 << 12)
+#define PCIMEM_ARBITRATION_VIDEO_MASK (0x7 << 8)
+#define PCIMEM_ARBITRATION_VIDEO_OFF (0x0 << 8)
+#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_1 (0x1 << 8)
+#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_2 (0x2 << 8)
+#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_3 (0x3 << 8)
+#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_4 (0x4 << 8)
+#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_5 (0x5 << 8)
+#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_6 (0x6 << 8)
+#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_7 (0x7 << 8)
+#define PCIMEM_ARBITRATION_PANEL_MASK (0x7 << 4)
+#define PCIMEM_ARBITRATION_PANEL_OFF (0x0 << 4)
+#define PCIMEM_ARBITRATION_PANEL_PRIORITY_1 (0x1 << 4)
+#define PCIMEM_ARBITRATION_PANEL_PRIORITY_2 (0x2 << 4)
+#define PCIMEM_ARBITRATION_PANEL_PRIORITY_3 (0x3 << 4)
+#define PCIMEM_ARBITRATION_PANEL_PRIORITY_4 (0x4 << 4)
+#define PCIMEM_ARBITRATION_PANEL_PRIORITY_5 (0x5 << 4)
+#define PCIMEM_ARBITRATION_PANEL_PRIORITY_6 (0x6 << 4)
+#define PCIMEM_ARBITRATION_PANEL_PRIORITY_7 (0x7 << 4)
+#define PCIMEM_ARBITRATION_CRT_MASK 0x7
+#define PCIMEM_ARBITRATION_CRT_OFF 0x0
+#define PCIMEM_ARBITRATION_CRT_PRIORITY_1 0x1
+#define PCIMEM_ARBITRATION_CRT_PRIORITY_2 0x2
+#define PCIMEM_ARBITRATION_CRT_PRIORITY_3 0x3
+#define PCIMEM_ARBITRATION_CRT_PRIORITY_4 0x4
+#define PCIMEM_ARBITRATION_CRT_PRIORITY_5 0x5
+#define PCIMEM_ARBITRATION_CRT_PRIORITY_6 0x6
+#define PCIMEM_ARBITRATION_CRT_PRIORITY_7 0x7
+
+#define RAW_INT 0x000020
+#define RAW_INT_ZVPORT1_VSYNC BIT(4)
+#define RAW_INT_ZVPORT0_VSYNC BIT(3)
+#define RAW_INT_CRT_VSYNC BIT(2)
+#define RAW_INT_PANEL_VSYNC BIT(1)
+#define RAW_INT_VGA_VSYNC BIT(0)
+
+#define INT_STATUS 0x000024
+#define INT_STATUS_GPIO31 BIT(31)
+#define INT_STATUS_GPIO30 BIT(30)
+#define INT_STATUS_GPIO29 BIT(29)
+#define INT_STATUS_GPIO28 BIT(28)
+#define INT_STATUS_GPIO27 BIT(27)
+#define INT_STATUS_GPIO26 BIT(26)
+#define INT_STATUS_GPIO25 BIT(25)
+#define INT_STATUS_I2C BIT(12)
+#define INT_STATUS_PWM BIT(11)
+#define INT_STATUS_DMA1 BIT(10)
+#define INT_STATUS_DMA0 BIT(9)
+#define INT_STATUS_PCI BIT(8)
+#define INT_STATUS_SSP1 BIT(7)
+#define INT_STATUS_SSP0 BIT(6)
+#define INT_STATUS_DE BIT(5)
+#define INT_STATUS_ZVPORT1_VSYNC BIT(4)
+#define INT_STATUS_ZVPORT0_VSYNC BIT(3)
+#define INT_STATUS_CRT_VSYNC BIT(2)
+#define INT_STATUS_PANEL_VSYNC BIT(1)
+#define INT_STATUS_VGA_VSYNC BIT(0)
+
+#define INT_MASK 0x000028
+#define INT_MASK_GPIO31 BIT(31)
+#define INT_MASK_GPIO30 BIT(30)
+#define INT_MASK_GPIO29 BIT(29)
+#define INT_MASK_GPIO28 BIT(28)
+#define INT_MASK_GPIO27 BIT(27)
+#define INT_MASK_GPIO26 BIT(26)
+#define INT_MASK_GPIO25 BIT(25)
+#define INT_MASK_I2C BIT(12)
+#define INT_MASK_PWM BIT(11)
+#define INT_MASK_DMA1 BIT(10)
+#define INT_MASK_DMA BIT(9)
+#define INT_MASK_PCI BIT(8)
+#define INT_MASK_SSP1 BIT(7)
+#define INT_MASK_SSP0 BIT(6)
+#define INT_MASK_DE BIT(5)
+#define INT_MASK_ZVPORT1_VSYNC BIT(4)
+#define INT_MASK_ZVPORT0_VSYNC BIT(3)
+#define INT_MASK_CRT_VSYNC BIT(2)
+#define INT_MASK_PANEL_VSYNC BIT(1)
+#define INT_MASK_VGA_VSYNC BIT(0)
+
+#define CURRENT_GATE 0x000040
+#define CURRENT_GATE_MCLK_MASK (0x3 << 14)
+#ifdef VALIDATION_CHIP
+ #define CURRENT_GATE_MCLK_112MHZ (0x0 << 14)
+ #define CURRENT_GATE_MCLK_84MHZ (0x1 << 14)
+ #define CURRENT_GATE_MCLK_56MHZ (0x2 << 14)
+ #define CURRENT_GATE_MCLK_42MHZ (0x3 << 14)
+#else
+ #define CURRENT_GATE_MCLK_DIV_3 (0x0 << 14)
+ #define CURRENT_GATE_MCLK_DIV_4 (0x1 << 14)
+ #define CURRENT_GATE_MCLK_DIV_6 (0x2 << 14)
+ #define CURRENT_GATE_MCLK_DIV_8 (0x3 << 14)
+#endif
+#define CURRENT_GATE_M2XCLK_MASK (0x3 << 12)
+#ifdef VALIDATION_CHIP
+ #define CURRENT_GATE_M2XCLK_336MHZ (0x0 << 12)
+ #define CURRENT_GATE_M2XCLK_168MHZ (0x1 << 12)
+ #define CURRENT_GATE_M2XCLK_112MHZ (0x2 << 12)
+ #define CURRENT_GATE_M2XCLK_84MHZ (0x3 << 12)
+#else
+ #define CURRENT_GATE_M2XCLK_DIV_1 (0x0 << 12)
+ #define CURRENT_GATE_M2XCLK_DIV_2 (0x1 << 12)
+ #define CURRENT_GATE_M2XCLK_DIV_3 (0x2 << 12)
+ #define CURRENT_GATE_M2XCLK_DIV_4 (0x3 << 12)
+#endif
+#define CURRENT_GATE_VGA BIT(10)
+#define CURRENT_GATE_PWM BIT(9)
+#define CURRENT_GATE_I2C BIT(8)
+#define CURRENT_GATE_SSP BIT(7)
+#define CURRENT_GATE_GPIO BIT(6)
+#define CURRENT_GATE_ZVPORT BIT(5)
+#define CURRENT_GATE_CSC BIT(4)
+#define CURRENT_GATE_DE BIT(3)
+#define CURRENT_GATE_DISPLAY BIT(2)
+#define CURRENT_GATE_LOCALMEM BIT(1)
+#define CURRENT_GATE_DMA BIT(0)
+
+#define MODE0_GATE 0x000044
+#define MODE0_GATE_MCLK_MASK (0x3 << 14)
+#define MODE0_GATE_MCLK_112MHZ (0x0 << 14)
+#define MODE0_GATE_MCLK_84MHZ (0x1 << 14)
+#define MODE0_GATE_MCLK_56MHZ (0x2 << 14)
+#define MODE0_GATE_MCLK_42MHZ (0x3 << 14)
+#define MODE0_GATE_M2XCLK_MASK (0x3 << 12)
+#define MODE0_GATE_M2XCLK_336MHZ (0x0 << 12)
+#define MODE0_GATE_M2XCLK_168MHZ (0x1 << 12)
+#define MODE0_GATE_M2XCLK_112MHZ (0x2 << 12)
+#define MODE0_GATE_M2XCLK_84MHZ (0x3 << 12)
+#define MODE0_GATE_VGA BIT(10)
+#define MODE0_GATE_PWM BIT(9)
+#define MODE0_GATE_I2C BIT(8)
+#define MODE0_GATE_SSP BIT(7)
+#define MODE0_GATE_GPIO BIT(6)
+#define MODE0_GATE_ZVPORT BIT(5)
+#define MODE0_GATE_CSC BIT(4)
+#define MODE0_GATE_DE BIT(3)
+#define MODE0_GATE_DISPLAY BIT(2)
+#define MODE0_GATE_LOCALMEM BIT(1)
+#define MODE0_GATE_DMA BIT(0)
+
+#define MODE1_GATE 0x000048
+#define MODE1_GATE_MCLK_MASK (0x3 << 14)
+#define MODE1_GATE_MCLK_112MHZ (0x0 << 14)
+#define MODE1_GATE_MCLK_84MHZ (0x1 << 14)
+#define MODE1_GATE_MCLK_56MHZ (0x2 << 14)
+#define MODE1_GATE_MCLK_42MHZ (0x3 << 14)
+#define MODE1_GATE_M2XCLK_MASK (0x3 << 12)
+#define MODE1_GATE_M2XCLK_336MHZ (0x0 << 12)
+#define MODE1_GATE_M2XCLK_168MHZ (0x1 << 12)
+#define MODE1_GATE_M2XCLK_112MHZ (0x2 << 12)
+#define MODE1_GATE_M2XCLK_84MHZ (0x3 << 12)
+#define MODE1_GATE_VGA BIT(10)
+#define MODE1_GATE_PWM BIT(9)
+#define MODE1_GATE_I2C BIT(8)
+#define MODE1_GATE_SSP BIT(7)
+#define MODE1_GATE_GPIO BIT(6)
+#define MODE1_GATE_ZVPORT BIT(5)
+#define MODE1_GATE_CSC BIT(4)
+#define MODE1_GATE_DE BIT(3)
+#define MODE1_GATE_DISPLAY BIT(2)
+#define MODE1_GATE_LOCALMEM BIT(1)
+#define MODE1_GATE_DMA BIT(0)
+
+#define POWER_MODE_CTRL 0x00004C
+#ifdef VALIDATION_CHIP
+ #define POWER_MODE_CTRL_336CLK BIT(4)
+#endif
+#define POWER_MODE_CTRL_OSC_INPUT BIT(3)
+#define POWER_MODE_CTRL_ACPI BIT(2)
+#define POWER_MODE_CTRL_MODE_MASK (0x3 << 0)
+#define POWER_MODE_CTRL_MODE_MODE0 (0x0 << 0)
+#define POWER_MODE_CTRL_MODE_MODE1 (0x1 << 0)
+#define POWER_MODE_CTRL_MODE_SLEEP (0x2 << 0)
+
+#define PCI_MASTER_BASE 0x000050
+#define PCI_MASTER_BASE_ADDRESS_MASK 0xff
+
+#define DEVICE_ID 0x000054
+#define DEVICE_ID_DEVICE_ID_MASK (0xffff << 16)
+#define DEVICE_ID_REVISION_ID_MASK 0xff
+
+#define PLL_CLK_COUNT 0x000058
+#define PLL_CLK_COUNT_COUNTER_MASK 0xffff
+
+#define PANEL_PLL_CTRL 0x00005C
+#define PLL_CTRL_BYPASS BIT(18)
+#define PLL_CTRL_POWER BIT(17)
+#define PLL_CTRL_INPUT BIT(16)
+#ifdef VALIDATION_CHIP
+ #define PLL_CTRL_OD_SHIFT 14
+ #define PLL_CTRL_OD_MASK (0x3 << 14)
+#else
+ #define PLL_CTRL_POD_SHIFT 14
+ #define PLL_CTRL_POD_MASK (0x3 << 14)
+ #define PLL_CTRL_OD_SHIFT 12
+ #define PLL_CTRL_OD_MASK (0x3 << 12)
+#endif
+#define PLL_CTRL_N_SHIFT 8
+#define PLL_CTRL_N_MASK (0xf << 8)
+#define PLL_CTRL_M_SHIFT 0
+#define PLL_CTRL_M_MASK 0xff
+
+#define CRT_PLL_CTRL 0x000060
+
+#define VGA_PLL0_CTRL 0x000064
+
+#define VGA_PLL1_CTRL 0x000068
+
+#define SCRATCH_DATA 0x00006c
+
+#ifndef VALIDATION_CHIP
+
+#define MXCLK_PLL_CTRL 0x000070
+
+#define VGA_CONFIGURATION 0x000088
+#define VGA_CONFIGURATION_USER_DEFINE_MASK (0x3 << 4)
+#define VGA_CONFIGURATION_PLL BIT(2)
+#define VGA_CONFIGURATION_MODE BIT(1)
+
+#endif
+
+#define GPIO_DATA 0x010000
+#define GPIO_DATA_31 BIT(31)
+#define GPIO_DATA_30 BIT(30)
+#define GPIO_DATA_29 BIT(29)
+#define GPIO_DATA_28 BIT(28)
+#define GPIO_DATA_27 BIT(27)
+#define GPIO_DATA_26 BIT(26)
+#define GPIO_DATA_25 BIT(25)
+#define GPIO_DATA_24 BIT(24)
+#define GPIO_DATA_23 BIT(23)
+#define GPIO_DATA_22 BIT(22)
+#define GPIO_DATA_21 BIT(21)
+#define GPIO_DATA_20 BIT(20)
+#define GPIO_DATA_19 BIT(19)
+#define GPIO_DATA_18 BIT(18)
+#define GPIO_DATA_17 BIT(17)
+#define GPIO_DATA_16 BIT(16)
+#define GPIO_DATA_15 BIT(15)
+#define GPIO_DATA_14 BIT(14)
+#define GPIO_DATA_13 BIT(13)
+#define GPIO_DATA_12 BIT(12)
+#define GPIO_DATA_11 BIT(11)
+#define GPIO_DATA_10 BIT(10)
+#define GPIO_DATA_9 BIT(9)
+#define GPIO_DATA_8 BIT(8)
+#define GPIO_DATA_7 BIT(7)
+#define GPIO_DATA_6 BIT(6)
+#define GPIO_DATA_5 BIT(5)
+#define GPIO_DATA_4 BIT(4)
+#define GPIO_DATA_3 BIT(3)
+#define GPIO_DATA_2 BIT(2)
+#define GPIO_DATA_1 BIT(1)
+#define GPIO_DATA_0 BIT(0)
+
+#define GPIO_DATA_DIRECTION 0x010004
+#define GPIO_DATA_DIRECTION_31 BIT(31)
+#define GPIO_DATA_DIRECTION_30 BIT(30)
+#define GPIO_DATA_DIRECTION_29 BIT(29)
+#define GPIO_DATA_DIRECTION_28 BIT(28)
+#define GPIO_DATA_DIRECTION_27 BIT(27)
+#define GPIO_DATA_DIRECTION_26 BIT(26)
+#define GPIO_DATA_DIRECTION_25 BIT(25)
+#define GPIO_DATA_DIRECTION_24 BIT(24)
+#define GPIO_DATA_DIRECTION_23 BIT(23)
+#define GPIO_DATA_DIRECTION_22 BIT(22)
+#define GPIO_DATA_DIRECTION_21 BIT(21)
+#define GPIO_DATA_DIRECTION_20 BIT(20)
+#define GPIO_DATA_DIRECTION_19 BIT(19)
+#define GPIO_DATA_DIRECTION_18 BIT(18)
+#define GPIO_DATA_DIRECTION_17 BIT(17)
+#define GPIO_DATA_DIRECTION_16 BIT(16)
+#define GPIO_DATA_DIRECTION_15 BIT(15)
+#define GPIO_DATA_DIRECTION_14 BIT(14)
+#define GPIO_DATA_DIRECTION_13 BIT(13)
+#define GPIO_DATA_DIRECTION_12 BIT(12)
+#define GPIO_DATA_DIRECTION_11 BIT(11)
+#define GPIO_DATA_DIRECTION_10 BIT(10)
+#define GPIO_DATA_DIRECTION_9 BIT(9)
+#define GPIO_DATA_DIRECTION_8 BIT(8)
+#define GPIO_DATA_DIRECTION_7 BIT(7)
+#define GPIO_DATA_DIRECTION_6 BIT(6)
+#define GPIO_DATA_DIRECTION_5 BIT(5)
+#define GPIO_DATA_DIRECTION_4 BIT(4)
+#define GPIO_DATA_DIRECTION_3 BIT(3)
+#define GPIO_DATA_DIRECTION_2 BIT(2)
+#define GPIO_DATA_DIRECTION_1 BIT(1)
+#define GPIO_DATA_DIRECTION_0 BIT(0)
+
+#define GPIO_INTERRUPT_SETUP 0x010008
+#define GPIO_INTERRUPT_SETUP_TRIGGER_31 BIT(22)
+#define GPIO_INTERRUPT_SETUP_TRIGGER_30 BIT(21)
+#define GPIO_INTERRUPT_SETUP_TRIGGER_29 BIT(20)
+#define GPIO_INTERRUPT_SETUP_TRIGGER_28 BIT(19)
+#define GPIO_INTERRUPT_SETUP_TRIGGER_27 BIT(18)
+#define GPIO_INTERRUPT_SETUP_TRIGGER_26 BIT(17)
+#define GPIO_INTERRUPT_SETUP_TRIGGER_25 BIT(16)
+#define GPIO_INTERRUPT_SETUP_ACTIVE_31 BIT(14)
+#define GPIO_INTERRUPT_SETUP_ACTIVE_30 BIT(13)
+#define GPIO_INTERRUPT_SETUP_ACTIVE_29 BIT(12)
+#define GPIO_INTERRUPT_SETUP_ACTIVE_28 BIT(11)
+#define GPIO_INTERRUPT_SETUP_ACTIVE_27 BIT(10)
+#define GPIO_INTERRUPT_SETUP_ACTIVE_26 BIT(9)
+#define GPIO_INTERRUPT_SETUP_ACTIVE_25 BIT(8)
+#define GPIO_INTERRUPT_SETUP_ENABLE_31 BIT(6)
+#define GPIO_INTERRUPT_SETUP_ENABLE_30 BIT(5)
+#define GPIO_INTERRUPT_SETUP_ENABLE_29 BIT(4)
+#define GPIO_INTERRUPT_SETUP_ENABLE_28 BIT(3)
+#define GPIO_INTERRUPT_SETUP_ENABLE_27 BIT(2)
+#define GPIO_INTERRUPT_SETUP_ENABLE_26 BIT(1)
+#define GPIO_INTERRUPT_SETUP_ENABLE_25 BIT(0)
+
+#define GPIO_INTERRUPT_STATUS 0x01000C
+#define GPIO_INTERRUPT_STATUS_31 BIT(22)
+#define GPIO_INTERRUPT_STATUS_30 BIT(21)
+#define GPIO_INTERRUPT_STATUS_29 BIT(20)
+#define GPIO_INTERRUPT_STATUS_28 BIT(19)
+#define GPIO_INTERRUPT_STATUS_27 BIT(18)
+#define GPIO_INTERRUPT_STATUS_26 BIT(17)
+#define GPIO_INTERRUPT_STATUS_25 BIT(16)
+
+#define PANEL_DISPLAY_CTRL 0x080000
+#define PANEL_DISPLAY_CTRL_RESERVED_MASK 0xc0f08000
+#define PANEL_DISPLAY_CTRL_SELECT_SHIFT 28
+#define PANEL_DISPLAY_CTRL_SELECT_MASK (0x3 << 28)
+#define PANEL_DISPLAY_CTRL_SELECT_PANEL (0x0 << 28)
+#define PANEL_DISPLAY_CTRL_SELECT_VGA (0x1 << 28)
+#define PANEL_DISPLAY_CTRL_SELECT_CRT (0x2 << 28)
+#define PANEL_DISPLAY_CTRL_FPEN BIT(27)
+#define PANEL_DISPLAY_CTRL_VBIASEN BIT(26)
+#define PANEL_DISPLAY_CTRL_DATA BIT(25)
+#define PANEL_DISPLAY_CTRL_FPVDDEN BIT(24)
+#define PANEL_DISPLAY_CTRL_DUAL_DISPLAY BIT(19)
+#define PANEL_DISPLAY_CTRL_DOUBLE_PIXEL BIT(18)
+#define PANEL_DISPLAY_CTRL_FIFO (0x3 << 16)
+#define PANEL_DISPLAY_CTRL_FIFO_1 (0x0 << 16)
+#define PANEL_DISPLAY_CTRL_FIFO_3 (0x1 << 16)
+#define PANEL_DISPLAY_CTRL_FIFO_7 (0x2 << 16)
+#define PANEL_DISPLAY_CTRL_FIFO_11 (0x3 << 16)
+#define DISPLAY_CTRL_CLOCK_PHASE BIT(14)
+#define DISPLAY_CTRL_VSYNC_PHASE BIT(13)
+#define DISPLAY_CTRL_HSYNC_PHASE BIT(12)
+#define PANEL_DISPLAY_CTRL_VSYNC BIT(11)
+#define PANEL_DISPLAY_CTRL_CAPTURE_TIMING BIT(10)
+#define PANEL_DISPLAY_CTRL_COLOR_KEY BIT(9)
+#define DISPLAY_CTRL_TIMING BIT(8)
+#define PANEL_DISPLAY_CTRL_VERTICAL_PAN_DIR BIT(7)
+#define PANEL_DISPLAY_CTRL_VERTICAL_PAN BIT(6)
+#define PANEL_DISPLAY_CTRL_HORIZONTAL_PAN_DIR BIT(5)
+#define PANEL_DISPLAY_CTRL_HORIZONTAL_PAN BIT(4)
+#define DISPLAY_CTRL_GAMMA BIT(3)
+#define DISPLAY_CTRL_PLANE BIT(2)
+#define PANEL_DISPLAY_CTRL_FORMAT (0x3 << 0)
+#define PANEL_DISPLAY_CTRL_FORMAT_8 (0x0 << 0)
+#define PANEL_DISPLAY_CTRL_FORMAT_16 (0x1 << 0)
+#define PANEL_DISPLAY_CTRL_FORMAT_32 (0x2 << 0)
+
+#define PANEL_PAN_CTRL 0x080004
+#define PANEL_PAN_CTRL_VERTICAL_PAN_MASK (0xff << 24)
+#define PANEL_PAN_CTRL_VERTICAL_VSYNC_MASK (0x3f << 16)
+#define PANEL_PAN_CTRL_HORIZONTAL_PAN_MASK (0xff << 8)
+#define PANEL_PAN_CTRL_HORIZONTAL_VSYNC_MASK 0x3f
+
+#define PANEL_COLOR_KEY 0x080008
+#define PANEL_COLOR_KEY_MASK_MASK (0xffff << 16)
+#define PANEL_COLOR_KEY_VALUE_MASK 0xffff
+
+#define PANEL_FB_ADDRESS 0x08000C
+#define PANEL_FB_ADDRESS_STATUS BIT(31)
+#define PANEL_FB_ADDRESS_EXT BIT(27)
+#define PANEL_FB_ADDRESS_ADDRESS_MASK 0x1ffffff
+
+#define PANEL_FB_WIDTH 0x080010
+#define PANEL_FB_WIDTH_WIDTH_SHIFT 16
+#define PANEL_FB_WIDTH_WIDTH_MASK (0x3fff << 16)
+#define PANEL_FB_WIDTH_OFFSET_MASK 0x3fff
+
+#define PANEL_WINDOW_WIDTH 0x080014
+#define PANEL_WINDOW_WIDTH_WIDTH_SHIFT 16
+#define PANEL_WINDOW_WIDTH_WIDTH_MASK (0xfff << 16)
+#define PANEL_WINDOW_WIDTH_X_MASK 0xfff
+
+#define PANEL_WINDOW_HEIGHT 0x080018
+#define PANEL_WINDOW_HEIGHT_HEIGHT_SHIFT 16
+#define PANEL_WINDOW_HEIGHT_HEIGHT_MASK (0xfff << 16)
+#define PANEL_WINDOW_HEIGHT_Y_MASK 0xfff
+
+#define PANEL_PLANE_TL 0x08001C
+#define PANEL_PLANE_TL_TOP_SHIFT 16
+#define PANEL_PLANE_TL_TOP_MASK (0x7ff << 16)
+#define PANEL_PLANE_TL_LEFT_MASK 0x7ff
+
+#define PANEL_PLANE_BR 0x080020
+#define PANEL_PLANE_BR_BOTTOM_SHIFT 16
+#define PANEL_PLANE_BR_BOTTOM_MASK (0x7ff << 16)
+#define PANEL_PLANE_BR_RIGHT_MASK 0x7ff
+
+#define PANEL_HORIZONTAL_TOTAL 0x080024
+#define PANEL_HORIZONTAL_TOTAL_TOTAL_SHIFT 16
+#define PANEL_HORIZONTAL_TOTAL_TOTAL_MASK (0xfff << 16)
+#define PANEL_HORIZONTAL_TOTAL_DISPLAY_END_MASK 0xfff
+
+#define PANEL_HORIZONTAL_SYNC 0x080028
+#define PANEL_HORIZONTAL_SYNC_WIDTH_SHIFT 16
+#define PANEL_HORIZONTAL_SYNC_WIDTH_MASK (0xff << 16)
+#define PANEL_HORIZONTAL_SYNC_START_MASK 0xfff
+
+#define PANEL_VERTICAL_TOTAL 0x08002C
+#define PANEL_VERTICAL_TOTAL_TOTAL_SHIFT 16
+#define PANEL_VERTICAL_TOTAL_TOTAL_MASK (0x7ff << 16)
+#define PANEL_VERTICAL_TOTAL_DISPLAY_END_MASK 0x7ff
+
+#define PANEL_VERTICAL_SYNC 0x080030
+#define PANEL_VERTICAL_SYNC_HEIGHT_SHIFT 16
+#define PANEL_VERTICAL_SYNC_HEIGHT_MASK (0x3f << 16)
+#define PANEL_VERTICAL_SYNC_START_MASK 0x7ff
+
+#define PANEL_CURRENT_LINE 0x080034
+#define PANEL_CURRENT_LINE_LINE_MASK 0x7ff
+
+/* Video Control */
+
+#define VIDEO_DISPLAY_CTRL 0x080040
+#define VIDEO_DISPLAY_CTRL_LINE_BUFFER BIT(18)
+#define VIDEO_DISPLAY_CTRL_FIFO_MASK (0x3 << 16)
+#define VIDEO_DISPLAY_CTRL_FIFO_1 (0x0 << 16)
+#define VIDEO_DISPLAY_CTRL_FIFO_3 (0x1 << 16)
+#define VIDEO_DISPLAY_CTRL_FIFO_7 (0x2 << 16)
+#define VIDEO_DISPLAY_CTRL_FIFO_11 (0x3 << 16)
+#define VIDEO_DISPLAY_CTRL_BUFFER BIT(15)
+#define VIDEO_DISPLAY_CTRL_CAPTURE BIT(14)
+#define VIDEO_DISPLAY_CTRL_DOUBLE_BUFFER BIT(13)
+#define VIDEO_DISPLAY_CTRL_BYTE_SWAP BIT(12)
+#define VIDEO_DISPLAY_CTRL_VERTICAL_SCALE BIT(11)
+#define VIDEO_DISPLAY_CTRL_HORIZONTAL_SCALE BIT(10)
+#define VIDEO_DISPLAY_CTRL_VERTICAL_MODE BIT(9)
+#define VIDEO_DISPLAY_CTRL_HORIZONTAL_MODE BIT(8)
+#define VIDEO_DISPLAY_CTRL_PIXEL_MASK (0xf << 4)
+#define VIDEO_DISPLAY_CTRL_GAMMA BIT(3)
+#define VIDEO_DISPLAY_CTRL_FORMAT_MASK 0x3
+#define VIDEO_DISPLAY_CTRL_FORMAT_8 0x0
+#define VIDEO_DISPLAY_CTRL_FORMAT_16 0x1
+#define VIDEO_DISPLAY_CTRL_FORMAT_32 0x2
+#define VIDEO_DISPLAY_CTRL_FORMAT_YUV 0x3
+
+#define VIDEO_FB_0_ADDRESS 0x080044
+#define VIDEO_FB_0_ADDRESS_STATUS BIT(31)
+#define VIDEO_FB_0_ADDRESS_EXT BIT(27)
+#define VIDEO_FB_0_ADDRESS_ADDRESS_MASK 0x3ffffff
+
+#define VIDEO_FB_WIDTH 0x080048
+#define VIDEO_FB_WIDTH_WIDTH_MASK (0x3fff << 16)
+#define VIDEO_FB_WIDTH_OFFSET_MASK 0x3fff
+
+#define VIDEO_FB_0_LAST_ADDRESS 0x08004C
+#define VIDEO_FB_0_LAST_ADDRESS_EXT BIT(27)
+#define VIDEO_FB_0_LAST_ADDRESS_ADDRESS_MASK 0x3ffffff
+
+#define VIDEO_PLANE_TL 0x080050
+#define VIDEO_PLANE_TL_TOP_MASK (0x7ff << 16)
+#define VIDEO_PLANE_TL_LEFT_MASK 0x7ff
+
+#define VIDEO_PLANE_BR 0x080054
+#define VIDEO_PLANE_BR_BOTTOM_MASK (0x7ff << 16)
+#define VIDEO_PLANE_BR_RIGHT_MASK 0x7ff
+
+#define VIDEO_SCALE 0x080058
+#define VIDEO_SCALE_VERTICAL_MODE BIT(31)
+#define VIDEO_SCALE_VERTICAL_SCALE_MASK (0xfff << 16)
+#define VIDEO_SCALE_HORIZONTAL_MODE BIT(15)
+#define VIDEO_SCALE_HORIZONTAL_SCALE_MASK 0xfff
+
+#define VIDEO_INITIAL_SCALE 0x08005C
+#define VIDEO_INITIAL_SCALE_FB_1_MASK (0xfff << 16)
+#define VIDEO_INITIAL_SCALE_FB_0_MASK 0xfff
+
+#define VIDEO_YUV_CONSTANTS 0x080060
+#define VIDEO_YUV_CONSTANTS_Y_MASK (0xff << 24)
+#define VIDEO_YUV_CONSTANTS_R_MASK (0xff << 16)
+#define VIDEO_YUV_CONSTANTS_G_MASK (0xff << 8)
+#define VIDEO_YUV_CONSTANTS_B_MASK 0xff
+
+#define VIDEO_FB_1_ADDRESS 0x080064
+#define VIDEO_FB_1_ADDRESS_STATUS BIT(31)
+#define VIDEO_FB_1_ADDRESS_EXT BIT(27)
+#define VIDEO_FB_1_ADDRESS_ADDRESS_MASK 0x3ffffff
+
+#define VIDEO_FB_1_LAST_ADDRESS 0x080068
+#define VIDEO_FB_1_LAST_ADDRESS_EXT BIT(27)
+#define VIDEO_FB_1_LAST_ADDRESS_ADDRESS_MASK 0x3ffffff
+
+/* Video Alpha Control */
+
+#define VIDEO_ALPHA_DISPLAY_CTRL 0x080080
+#define VIDEO_ALPHA_DISPLAY_CTRL_SELECT BIT(28)
+#define VIDEO_ALPHA_DISPLAY_CTRL_ALPHA_MASK (0xf << 24)
+#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_MASK (0x3 << 16)
+#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_1 (0x0 << 16)
+#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_3 (0x1 << 16)
+#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_7 (0x2 << 16)
+#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_11 (0x3 << 16)
+#define VIDEO_ALPHA_DISPLAY_CTRL_VERT_SCALE BIT(11)
+#define VIDEO_ALPHA_DISPLAY_CTRL_HORZ_SCALE BIT(10)
+#define VIDEO_ALPHA_DISPLAY_CTRL_VERT_MODE BIT(9)
+#define VIDEO_ALPHA_DISPLAY_CTRL_HORZ_MODE BIT(8)
+#define VIDEO_ALPHA_DISPLAY_CTRL_PIXEL_MASK (0xf << 4)
+#define VIDEO_ALPHA_DISPLAY_CTRL_CHROMA_KEY BIT(3)
+#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_MASK 0x3
+#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_8 0x0
+#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_16 0x1
+#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4 0x2
+#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4_4_4 0x3
+
+#define VIDEO_ALPHA_FB_ADDRESS 0x080084
+#define VIDEO_ALPHA_FB_ADDRESS_STATUS BIT(31)
+#define VIDEO_ALPHA_FB_ADDRESS_EXT BIT(27)
+#define VIDEO_ALPHA_FB_ADDRESS_ADDRESS_MASK 0x3ffffff
+
+#define VIDEO_ALPHA_FB_WIDTH 0x080088
+#define VIDEO_ALPHA_FB_WIDTH_WIDTH_MASK (0x3fff << 16)
+#define VIDEO_ALPHA_FB_WIDTH_OFFSET_MASK 0x3fff
+
+#define VIDEO_ALPHA_FB_LAST_ADDRESS 0x08008C
+#define VIDEO_ALPHA_FB_LAST_ADDRESS_EXT BIT(27)
+#define VIDEO_ALPHA_FB_LAST_ADDRESS_ADDRESS_MASK 0x3ffffff
+
+#define VIDEO_ALPHA_PLANE_TL 0x080090
+#define VIDEO_ALPHA_PLANE_TL_TOP_MASK (0x7ff << 16)
+#define VIDEO_ALPHA_PLANE_TL_LEFT_MASK 0x7ff
+
+#define VIDEO_ALPHA_PLANE_BR 0x080094
+#define VIDEO_ALPHA_PLANE_BR_BOTTOM_MASK (0x7ff << 16)
+#define VIDEO_ALPHA_PLANE_BR_RIGHT_MASK 0x7ff
+
+#define VIDEO_ALPHA_SCALE 0x080098
+#define VIDEO_ALPHA_SCALE_VERTICAL_MODE BIT(31)
+#define VIDEO_ALPHA_SCALE_VERTICAL_SCALE_MASK (0xfff << 16)
+#define VIDEO_ALPHA_SCALE_HORIZONTAL_MODE BIT(15)
+#define VIDEO_ALPHA_SCALE_HORIZONTAL_SCALE_MASK 0xfff
+
+#define VIDEO_ALPHA_INITIAL_SCALE 0x08009C
+#define VIDEO_ALPHA_INITIAL_SCALE_VERTICAL_MASK (0xfff << 16)
+#define VIDEO_ALPHA_INITIAL_SCALE_HORIZONTAL_MASK 0xfff
+
+#define VIDEO_ALPHA_CHROMA_KEY 0x0800A0
+#define VIDEO_ALPHA_CHROMA_KEY_MASK_MASK (0xffff << 16)
+#define VIDEO_ALPHA_CHROMA_KEY_VALUE_MASK 0xffff
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_01 0x0800A4
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_1_MASK (0xffff << 16)
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_1_RED_MASK (0x1f << 27)
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_1_GREEN_MASK (0x3f << 21)
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_1_BLUE_MASK (0x1f << 16)
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_0_MASK 0xffff
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_0_RED_MASK (0x1f << 11)
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_0_GREEN_MASK (0x3f << 5)
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_0_BLUE_MASK 0x1f
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_23 0x0800A8
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_3_MASK (0xffff << 16)
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_3_RED_MASK (0x1f << 27)
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_3_GREEN_MASK (0x3f << 21)
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_3_BLUE_MASK (0x1f << 16)
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_2_MASK 0xffff
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_2_RED_MASK (0x1f << 11)
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_2_GREEN_MASK (0x3f << 5)
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_2_BLUE_MASK 0x1f
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_45 0x0800AC
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_5_MASK (0xffff << 16)
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_5_RED_MASK (0x1f << 27)
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_5_GREEN_MASK (0x3f << 21)
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_5_BLUE_MASK (0x1f << 16)
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_4_MASK 0xffff
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_4_RED_MASK (0x1f << 11)
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_4_GREEN_MASK (0x3f << 5)
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_4_BLUE_MASK 0x1f
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_67 0x0800B0
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_7_MASK (0xffff << 16)
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_7_RED_MASK (0x1f << 27)
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_7_GREEN_MASK (0x3f << 21)
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_7_BLUE_MASK (0x1f << 16)
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_6_MASK 0xffff
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_6_RED_MASK (0x1f << 11)
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_6_GREEN_MASK (0x3f << 5)
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_6_BLUE_MASK 0x1f
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_89 0x0800B4
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_9_MASK (0xffff << 16)
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_9_RED_MASK (0x1f << 27)
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_9_GREEN_MASK (0x3f << 21)
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_9_BLUE_MASK (0x1f << 16)
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_8_MASK 0xffff
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_8_RED_MASK (0x1f << 11)
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_8_GREEN_MASK (0x3f << 5)
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_8_BLUE_MASK 0x1f
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB 0x0800B8
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_B_MASK (0xffff << 16)
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_B_RED_MASK (0x1f << 27)
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_B_GREEN_MASK (0x3f << 21)
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_B_BLUE_MASK (0x1f << 16)
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_A_MASK 0xffff
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_A_RED_MASK (0x1f << 11)
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_A_GREEN_MASK (0x3f << 5)
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_A_BLUE_MASK 0x1f
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD 0x0800BC
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_D_MASK (0xffff << 16)
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_D_RED_MASK (0x1f << 27)
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_D_GREEN_MASK (0x3f << 21)
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_D_BLUE_MASK (0x1f << 16)
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_C_MASK 0xffff
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_C_RED_MASK (0x1f << 11)
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_C_GREEN_MASK (0x3f << 5)
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_C_BLUE_MASK 0x1f
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF 0x0800C0
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_F_MASK (0xffff << 16)
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_F_RED_MASK (0x1f << 27)
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_F_GREEN_MASK (0x3f << 21)
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_F_BLUE_MASK (0x1f << 16)
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_E_MASK 0xffff
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_E_RED_MASK (0x1f << 11)
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_E_GREEN_MASK (0x3f << 5)
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_E_BLUE_MASK 0x1f
+
+/* Panel Cursor Control */
+
+#define PANEL_HWC_ADDRESS 0x0800F0
+#define PANEL_HWC_ADDRESS_ENABLE BIT(31)
+#define PANEL_HWC_ADDRESS_EXT BIT(27)
+#define PANEL_HWC_ADDRESS_ADDRESS_MASK 0x3ffffff
+
+#define PANEL_HWC_LOCATION 0x0800F4
+#define PANEL_HWC_LOCATION_TOP BIT(27)
+#define PANEL_HWC_LOCATION_Y_MASK (0x7ff << 16)
+#define PANEL_HWC_LOCATION_LEFT BIT(11)
+#define PANEL_HWC_LOCATION_X_MASK 0x7ff
+
+#define PANEL_HWC_COLOR_12 0x0800F8
+#define PANEL_HWC_COLOR_12_2_RGB565_MASK (0xffff << 16)
+#define PANEL_HWC_COLOR_12_1_RGB565_MASK 0xffff
+
+#define PANEL_HWC_COLOR_3 0x0800FC
+#define PANEL_HWC_COLOR_3_RGB565_MASK 0xffff
+
+/* Old Definitions +++ */
+#define PANEL_HWC_COLOR_01 0x0800F8
+#define PANEL_HWC_COLOR_01_1_RED_MASK (0x1f << 27)
+#define PANEL_HWC_COLOR_01_1_GREEN_MASK (0x3f << 21)
+#define PANEL_HWC_COLOR_01_1_BLUE_MASK (0x1f << 16)
+#define PANEL_HWC_COLOR_01_0_RED_MASK (0x1f << 11)
+#define PANEL_HWC_COLOR_01_0_GREEN_MASK (0x3f << 5)
+#define PANEL_HWC_COLOR_01_0_BLUE_MASK 0x1f
+
+#define PANEL_HWC_COLOR_2 0x0800FC
+#define PANEL_HWC_COLOR_2_RED_MASK (0x1f << 11)
+#define PANEL_HWC_COLOR_2_GREEN_MASK (0x3f << 5)
+#define PANEL_HWC_COLOR_2_BLUE_MASK 0x1f
+/* Old Definitions --- */
+
+/* Alpha Control */
+
+#define ALPHA_DISPLAY_CTRL 0x080100
+#define ALPHA_DISPLAY_CTRL_SELECT BIT(28)
+#define ALPHA_DISPLAY_CTRL_ALPHA_MASK (0xf << 24)
+#define ALPHA_DISPLAY_CTRL_FIFO_MASK (0x3 << 16)
+#define ALPHA_DISPLAY_CTRL_FIFO_1 (0x0 << 16)
+#define ALPHA_DISPLAY_CTRL_FIFO_3 (0x1 << 16)
+#define ALPHA_DISPLAY_CTRL_FIFO_7 (0x2 << 16)
+#define ALPHA_DISPLAY_CTRL_FIFO_11 (0x3 << 16)
+#define ALPHA_DISPLAY_CTRL_PIXEL_MASK (0xf << 4)
+#define ALPHA_DISPLAY_CTRL_CHROMA_KEY BIT(3)
+#define ALPHA_DISPLAY_CTRL_FORMAT_MASK 0x3
+#define ALPHA_DISPLAY_CTRL_FORMAT_16 0x1
+#define ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4 0x2
+#define ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4_4_4 0x3
+
+#define ALPHA_FB_ADDRESS 0x080104
+#define ALPHA_FB_ADDRESS_STATUS BIT(31)
+#define ALPHA_FB_ADDRESS_EXT BIT(27)
+#define ALPHA_FB_ADDRESS_ADDRESS_MASK 0x3ffffff
+
+#define ALPHA_FB_WIDTH 0x080108
+#define ALPHA_FB_WIDTH_WIDTH_MASK (0x3fff << 16)
+#define ALPHA_FB_WIDTH_OFFSET_MASK 0x3fff
+
+#define ALPHA_PLANE_TL 0x08010C
+#define ALPHA_PLANE_TL_TOP_MASK (0x7ff << 16)
+#define ALPHA_PLANE_TL_LEFT_MASK 0x7ff
+
+#define ALPHA_PLANE_BR 0x080110
+#define ALPHA_PLANE_BR_BOTTOM_MASK (0x7ff << 16)
+#define ALPHA_PLANE_BR_RIGHT_MASK 0x7ff
+
+#define ALPHA_CHROMA_KEY 0x080114
+#define ALPHA_CHROMA_KEY_MASK_MASK (0xffff << 16)
+#define ALPHA_CHROMA_KEY_VALUE_MASK 0xffff
+
+#define ALPHA_COLOR_LOOKUP_01 0x080118
+#define ALPHA_COLOR_LOOKUP_01_1_MASK (0xffff << 16)
+#define ALPHA_COLOR_LOOKUP_01_1_RED_MASK (0x1f << 27)
+#define ALPHA_COLOR_LOOKUP_01_1_GREEN_MASK (0x3f << 21)
+#define ALPHA_COLOR_LOOKUP_01_1_BLUE_MASK (0x1f << 16)
+#define ALPHA_COLOR_LOOKUP_01_0_MASK 0xffff
+#define ALPHA_COLOR_LOOKUP_01_0_RED_MASK (0x1f << 11)
+#define ALPHA_COLOR_LOOKUP_01_0_GREEN_MASK (0x3f << 5)
+#define ALPHA_COLOR_LOOKUP_01_0_BLUE_MASK 0x1f
+
+#define ALPHA_COLOR_LOOKUP_23 0x08011C
+#define ALPHA_COLOR_LOOKUP_23_3_MASK (0xffff << 16)
+#define ALPHA_COLOR_LOOKUP_23_3_RED_MASK (0x1f << 27)
+#define ALPHA_COLOR_LOOKUP_23_3_GREEN_MASK (0x3f << 21)
+#define ALPHA_COLOR_LOOKUP_23_3_BLUE_MASK (0x1f << 16)
+#define ALPHA_COLOR_LOOKUP_23_2_MASK 0xffff
+#define ALPHA_COLOR_LOOKUP_23_2_RED_MASK (0x1f << 11)
+#define ALPHA_COLOR_LOOKUP_23_2_GREEN_MASK (0x3f << 5)
+#define ALPHA_COLOR_LOOKUP_23_2_BLUE_MASK 0x1f
+
+#define ALPHA_COLOR_LOOKUP_45 0x080120
+#define ALPHA_COLOR_LOOKUP_45_5_MASK (0xffff << 16)
+#define ALPHA_COLOR_LOOKUP_45_5_RED_MASK (0x1f << 27)
+#define ALPHA_COLOR_LOOKUP_45_5_GREEN_MASK (0x3f << 21)
+#define ALPHA_COLOR_LOOKUP_45_5_BLUE_MASK (0x1f << 16)
+#define ALPHA_COLOR_LOOKUP_45_4_MASK 0xffff
+#define ALPHA_COLOR_LOOKUP_45_4_RED_MASK (0x1f << 11)
+#define ALPHA_COLOR_LOOKUP_45_4_GREEN_MASK (0x3f << 5)
+#define ALPHA_COLOR_LOOKUP_45_4_BLUE_MASK 0x1f
+
+#define ALPHA_COLOR_LOOKUP_67 0x080124
+#define ALPHA_COLOR_LOOKUP_67_7_MASK (0xffff << 16)
+#define ALPHA_COLOR_LOOKUP_67_7_RED_MASK (0x1f << 27)
+#define ALPHA_COLOR_LOOKUP_67_7_GREEN_MASK (0x3f << 21)
+#define ALPHA_COLOR_LOOKUP_67_7_BLUE_MASK (0x1f << 16)
+#define ALPHA_COLOR_LOOKUP_67_6_MASK 0xffff
+#define ALPHA_COLOR_LOOKUP_67_6_RED_MASK (0x1f << 11)
+#define ALPHA_COLOR_LOOKUP_67_6_GREEN_MASK (0x3f << 5)
+#define ALPHA_COLOR_LOOKUP_67_6_BLUE_MASK 0x1f
+
+#define ALPHA_COLOR_LOOKUP_89 0x080128
+#define ALPHA_COLOR_LOOKUP_89_9_MASK (0xffff << 16)
+#define ALPHA_COLOR_LOOKUP_89_9_RED_MASK (0x1f << 27)
+#define ALPHA_COLOR_LOOKUP_89_9_GREEN_MASK (0x3f << 21)
+#define ALPHA_COLOR_LOOKUP_89_9_BLUE_MASK (0x1f << 16)
+#define ALPHA_COLOR_LOOKUP_89_8_MASK 0xffff
+#define ALPHA_COLOR_LOOKUP_89_8_RED_MASK (0x1f << 11)
+#define ALPHA_COLOR_LOOKUP_89_8_GREEN_MASK (0x3f << 5)
+#define ALPHA_COLOR_LOOKUP_89_8_BLUE_MASK 0x1f
+
+#define ALPHA_COLOR_LOOKUP_AB 0x08012C
+#define ALPHA_COLOR_LOOKUP_AB_B_MASK (0xffff << 16)
+#define ALPHA_COLOR_LOOKUP_AB_B_RED_MASK (0x1f << 27)
+#define ALPHA_COLOR_LOOKUP_AB_B_GREEN_MASK (0x3f << 21)
+#define ALPHA_COLOR_LOOKUP_AB_B_BLUE_MASK (0x1f << 16)
+#define ALPHA_COLOR_LOOKUP_AB_A_MASK 0xffff
+#define ALPHA_COLOR_LOOKUP_AB_A_RED_MASK (0x1f << 11)
+#define ALPHA_COLOR_LOOKUP_AB_A_GREEN_MASK (0x3f << 5)
+#define ALPHA_COLOR_LOOKUP_AB_A_BLUE_MASK 0x1f
+
+#define ALPHA_COLOR_LOOKUP_CD 0x080130
+#define ALPHA_COLOR_LOOKUP_CD_D_MASK (0xffff << 16)
+#define ALPHA_COLOR_LOOKUP_CD_D_RED_MASK (0x1f << 27)
+#define ALPHA_COLOR_LOOKUP_CD_D_GREEN_MASK (0x3f << 21)
+#define ALPHA_COLOR_LOOKUP_CD_D_BLUE_MASK (0x1f << 16)
+#define ALPHA_COLOR_LOOKUP_CD_C_MASK 0xffff
+#define ALPHA_COLOR_LOOKUP_CD_C_RED_MASK (0x1f << 11)
+#define ALPHA_COLOR_LOOKUP_CD_C_GREEN_MASK (0x3f << 5)
+#define ALPHA_COLOR_LOOKUP_CD_C_BLUE_MASK 0x1f
+
+#define ALPHA_COLOR_LOOKUP_EF 0x080134
+#define ALPHA_COLOR_LOOKUP_EF_F_MASK (0xffff << 16)
+#define ALPHA_COLOR_LOOKUP_EF_F_RED_MASK (0x1f << 27)
+#define ALPHA_COLOR_LOOKUP_EF_F_GREEN_MASK (0x3f << 21)
+#define ALPHA_COLOR_LOOKUP_EF_F_BLUE_MASK (0x1f << 16)
+#define ALPHA_COLOR_LOOKUP_EF_E_MASK 0xffff
+#define ALPHA_COLOR_LOOKUP_EF_E_RED_MASK (0x1f << 11)
+#define ALPHA_COLOR_LOOKUP_EF_E_GREEN_MASK (0x3f << 5)
+#define ALPHA_COLOR_LOOKUP_EF_E_BLUE_MASK 0x1f
+
+/* CRT Graphics Control */
+
+#define CRT_DISPLAY_CTRL 0x080200
+#define CRT_DISPLAY_CTRL_RESERVED_MASK 0xfb008200
+
+/* SM750LE definition */
+#define CRT_DISPLAY_CTRL_DPMS_SHIFT 30
+#define CRT_DISPLAY_CTRL_DPMS_MASK (0x3 << 30)
+#define CRT_DISPLAY_CTRL_DPMS_0 (0x0 << 30)
+#define CRT_DISPLAY_CTRL_DPMS_1 (0x1 << 30)
+#define CRT_DISPLAY_CTRL_DPMS_2 (0x2 << 30)
+#define CRT_DISPLAY_CTRL_DPMS_3 (0x3 << 30)
+#define CRT_DISPLAY_CTRL_CLK_MASK (0x7 << 27)
+#define CRT_DISPLAY_CTRL_CLK_PLL25 (0x0 << 27)
+#define CRT_DISPLAY_CTRL_CLK_PLL41 (0x1 << 27)
+#define CRT_DISPLAY_CTRL_CLK_PLL62 (0x2 << 27)
+#define CRT_DISPLAY_CTRL_CLK_PLL65 (0x3 << 27)
+#define CRT_DISPLAY_CTRL_CLK_PLL74 (0x4 << 27)
+#define CRT_DISPLAY_CTRL_CLK_PLL80 (0x5 << 27)
+#define CRT_DISPLAY_CTRL_CLK_PLL108 (0x6 << 27)
+#define CRT_DISPLAY_CTRL_CLK_RESERVED (0x7 << 27)
+#define CRT_DISPLAY_CTRL_SHIFT_VGA_DAC BIT(26)
+
+/* SM750LE definition */
+#define CRT_DISPLAY_CTRL_CRTSELECT BIT(25)
+#define CRT_DISPLAY_CTRL_RGBBIT BIT(24)
+
+#ifndef VALIDATION_CHIP
+ #define CRT_DISPLAY_CTRL_CENTERING BIT(24)
+#endif
+#define CRT_DISPLAY_CTRL_LOCK_TIMING BIT(23)
+#define CRT_DISPLAY_CTRL_EXPANSION BIT(22)
+#define CRT_DISPLAY_CTRL_VERTICAL_MODE BIT(21)
+#define CRT_DISPLAY_CTRL_HORIZONTAL_MODE BIT(20)
+#define CRT_DISPLAY_CTRL_SELECT_SHIFT 18
+#define CRT_DISPLAY_CTRL_SELECT_MASK (0x3 << 18)
+#define CRT_DISPLAY_CTRL_SELECT_PANEL (0x0 << 18)
+#define CRT_DISPLAY_CTRL_SELECT_VGA (0x1 << 18)
+#define CRT_DISPLAY_CTRL_SELECT_CRT (0x2 << 18)
+#define CRT_DISPLAY_CTRL_FIFO_MASK (0x3 << 16)
+#define CRT_DISPLAY_CTRL_FIFO_1 (0x0 << 16)
+#define CRT_DISPLAY_CTRL_FIFO_3 (0x1 << 16)
+#define CRT_DISPLAY_CTRL_FIFO_7 (0x2 << 16)
+#define CRT_DISPLAY_CTRL_FIFO_11 (0x3 << 16)
+#define CRT_DISPLAY_CTRL_BLANK BIT(10)
+#define CRT_DISPLAY_CTRL_PIXEL_MASK (0xf << 4)
+#define CRT_DISPLAY_CTRL_FORMAT_MASK (0x3 << 0)
+#define CRT_DISPLAY_CTRL_FORMAT_8 (0x0 << 0)
+#define CRT_DISPLAY_CTRL_FORMAT_16 (0x1 << 0)
+#define CRT_DISPLAY_CTRL_FORMAT_32 (0x2 << 0)
+
+#define CRT_FB_ADDRESS 0x080204
+#define CRT_FB_ADDRESS_STATUS BIT(31)
+#define CRT_FB_ADDRESS_EXT BIT(27)
+#define CRT_FB_ADDRESS_ADDRESS_MASK 0x3ffffff
+
+#define CRT_FB_WIDTH 0x080208
+#define CRT_FB_WIDTH_WIDTH_SHIFT 16
+#define CRT_FB_WIDTH_WIDTH_MASK (0x3fff << 16)
+#define CRT_FB_WIDTH_OFFSET_MASK 0x3fff
+
+#define CRT_HORIZONTAL_TOTAL 0x08020C
+#define CRT_HORIZONTAL_TOTAL_TOTAL_SHIFT 16
+#define CRT_HORIZONTAL_TOTAL_TOTAL_MASK (0xfff << 16)
+#define CRT_HORIZONTAL_TOTAL_DISPLAY_END_MASK 0xfff
+
+#define CRT_HORIZONTAL_SYNC 0x080210
+#define CRT_HORIZONTAL_SYNC_WIDTH_SHIFT 16
+#define CRT_HORIZONTAL_SYNC_WIDTH_MASK (0xff << 16)
+#define CRT_HORIZONTAL_SYNC_START_MASK 0xfff
+
+#define CRT_VERTICAL_TOTAL 0x080214
+#define CRT_VERTICAL_TOTAL_TOTAL_SHIFT 16
+#define CRT_VERTICAL_TOTAL_TOTAL_MASK (0x7ff << 16)
+#define CRT_VERTICAL_TOTAL_DISPLAY_END_MASK (0x7ff)
+
+#define CRT_VERTICAL_SYNC 0x080218
+#define CRT_VERTICAL_SYNC_HEIGHT_SHIFT 16
+#define CRT_VERTICAL_SYNC_HEIGHT_MASK (0x3f << 16)
+#define CRT_VERTICAL_SYNC_START_MASK 0x7ff
+
+#define CRT_SIGNATURE_ANALYZER 0x08021C
+#define CRT_SIGNATURE_ANALYZER_STATUS_MASK (0xffff << 16)
+#define CRT_SIGNATURE_ANALYZER_ENABLE BIT(3)
+#define CRT_SIGNATURE_ANALYZER_RESET BIT(2)
+#define CRT_SIGNATURE_ANALYZER_SOURCE_MASK 0x3
+#define CRT_SIGNATURE_ANALYZER_SOURCE_RED 0
+#define CRT_SIGNATURE_ANALYZER_SOURCE_GREEN 1
+#define CRT_SIGNATURE_ANALYZER_SOURCE_BLUE 2
+
+#define CRT_CURRENT_LINE 0x080220
+#define CRT_CURRENT_LINE_LINE_MASK 0x7ff
+
+#define CRT_MONITOR_DETECT 0x080224
+#define CRT_MONITOR_DETECT_VALUE BIT(25)
+#define CRT_MONITOR_DETECT_ENABLE BIT(24)
+#define CRT_MONITOR_DETECT_RED_MASK (0xff << 16)
+#define CRT_MONITOR_DETECT_GREEN_MASK (0xff << 8)
+#define CRT_MONITOR_DETECT_BLUE_MASK 0xff
+
+#define CRT_SCALE 0x080228
+#define CRT_SCALE_VERTICAL_MODE BIT(31)
+#define CRT_SCALE_VERTICAL_SCALE_MASK (0xfff << 16)
+#define CRT_SCALE_HORIZONTAL_MODE BIT(15)
+#define CRT_SCALE_HORIZONTAL_SCALE_MASK 0xfff
+
+/* CRT Cursor Control */
+
+#define CRT_HWC_ADDRESS 0x080230
+#define CRT_HWC_ADDRESS_ENABLE BIT(31)
+#define CRT_HWC_ADDRESS_EXT BIT(27)
+#define CRT_HWC_ADDRESS_ADDRESS_MASK 0x3ffffff
+
+#define CRT_HWC_LOCATION 0x080234
+#define CRT_HWC_LOCATION_TOP BIT(27)
+#define CRT_HWC_LOCATION_Y_MASK (0x7ff << 16)
+#define CRT_HWC_LOCATION_LEFT BIT(11)
+#define CRT_HWC_LOCATION_X_MASK 0x7ff
+
+#define CRT_HWC_COLOR_12 0x080238
+#define CRT_HWC_COLOR_12_2_RGB565_MASK (0xffff << 16)
+#define CRT_HWC_COLOR_12_1_RGB565_MASK 0xffff
+
+#define CRT_HWC_COLOR_3 0x08023C
+#define CRT_HWC_COLOR_3_RGB565_MASK 0xffff
+
+/* This vertical expansion below start at 0x080240 ~ 0x080264 */
+#define CRT_VERTICAL_EXPANSION 0x080240
+#ifndef VALIDATION_CHIP
+ #define CRT_VERTICAL_CENTERING_VALUE_MASK (0xff << 24)
+#endif
+#define CRT_VERTICAL_EXPANSION_COMPARE_VALUE_MASK (0xff << 16)
+#define CRT_VERTICAL_EXPANSION_LINE_BUFFER_MASK (0xf << 12)
+#define CRT_VERTICAL_EXPANSION_SCALE_FACTOR_MASK 0xfff
+
+/* This horizontal expansion below start at 0x080268 ~ 0x08027C */
+#define CRT_HORIZONTAL_EXPANSION 0x080268
+#ifndef VALIDATION_CHIP
+ #define CRT_HORIZONTAL_CENTERING_VALUE_MASK (0xff << 24)
+#endif
+#define CRT_HORIZONTAL_EXPANSION_COMPARE_VALUE_MASK (0xff << 16)
+#define CRT_HORIZONTAL_EXPANSION_SCALE_FACTOR_MASK 0xfff
+
+#ifndef VALIDATION_CHIP
+ /* Auto Centering */
+ #define CRT_AUTO_CENTERING_TL 0x080280
+ #define CRT_AUTO_CENTERING_TL_TOP_MASK (0x7ff << 16)
+ #define CRT_AUTO_CENTERING_TL_LEFT_MASK 0x7ff
+
+ #define CRT_AUTO_CENTERING_BR 0x080284
+ #define CRT_AUTO_CENTERING_BR_BOTTOM_MASK (0x7ff << 16)
+ #define CRT_AUTO_CENTERING_BR_BOTTOM_SHIFT 16
+ #define CRT_AUTO_CENTERING_BR_RIGHT_MASK 0x7ff
+#endif
+
+/* sm750le new register to control panel output */
+#define DISPLAY_CONTROL_750LE 0x80288
+/* Palette RAM */
+
+/* Panel Palette register starts at 0x080400 ~ 0x0807FC */
+#define PANEL_PALETTE_RAM 0x080400
+
+/* Panel Palette register starts at 0x080C00 ~ 0x080FFC */
+#define CRT_PALETTE_RAM 0x080C00
+
+/* Color Space Conversion registers. */
+
+#define CSC_Y_SOURCE_BASE 0x1000C8
+#define CSC_Y_SOURCE_BASE_EXT BIT(27)
+#define CSC_Y_SOURCE_BASE_CS BIT(26)
+#define CSC_Y_SOURCE_BASE_ADDRESS_MASK 0x3ffffff
+
+#define CSC_CONSTANTS 0x1000CC
+#define CSC_CONSTANTS_Y_MASK (0xff << 24)
+#define CSC_CONSTANTS_R_MASK (0xff << 16)
+#define CSC_CONSTANTS_G_MASK (0xff << 8)
+#define CSC_CONSTANTS_B_MASK 0xff
+
+#define CSC_Y_SOURCE_X 0x1000D0
+#define CSC_Y_SOURCE_X_INTEGER_MASK (0x7ff << 16)
+#define CSC_Y_SOURCE_X_FRACTION_MASK (0x1fff << 3)
+
+#define CSC_Y_SOURCE_Y 0x1000D4
+#define CSC_Y_SOURCE_Y_INTEGER_MASK (0xfff << 16)
+#define CSC_Y_SOURCE_Y_FRACTION_MASK (0x1fff << 3)
+
+#define CSC_U_SOURCE_BASE 0x1000D8
+#define CSC_U_SOURCE_BASE_EXT BIT(27)
+#define CSC_U_SOURCE_BASE_CS BIT(26)
+#define CSC_U_SOURCE_BASE_ADDRESS_MASK 0x3ffffff
+
+#define CSC_V_SOURCE_BASE 0x1000DC
+#define CSC_V_SOURCE_BASE_EXT BIT(27)
+#define CSC_V_SOURCE_BASE_CS BIT(26)
+#define CSC_V_SOURCE_BASE_ADDRESS_MASK 0x3ffffff
+
+#define CSC_SOURCE_DIMENSION 0x1000E0
+#define CSC_SOURCE_DIMENSION_X_MASK (0xffff << 16)
+#define CSC_SOURCE_DIMENSION_Y_MASK 0xffff
+
+#define CSC_SOURCE_PITCH 0x1000E4
+#define CSC_SOURCE_PITCH_Y_MASK (0xffff << 16)
+#define CSC_SOURCE_PITCH_UV_MASK 0xffff
+
+#define CSC_DESTINATION 0x1000E8
+#define CSC_DESTINATION_WRAP BIT(31)
+#define CSC_DESTINATION_X_MASK (0xfff << 16)
+#define CSC_DESTINATION_Y_MASK 0xfff
+
+#define CSC_DESTINATION_DIMENSION 0x1000EC
+#define CSC_DESTINATION_DIMENSION_X_MASK (0xffff << 16)
+#define CSC_DESTINATION_DIMENSION_Y_MASK 0xffff
+
+#define CSC_DESTINATION_PITCH 0x1000F0
+#define CSC_DESTINATION_PITCH_X_MASK (0xffff << 16)
+#define CSC_DESTINATION_PITCH_Y_MASK 0xffff
+
+#define CSC_SCALE_FACTOR 0x1000F4
+#define CSC_SCALE_FACTOR_HORIZONTAL_MASK (0xffff << 16)
+#define CSC_SCALE_FACTOR_VERTICAL_MASK 0xffff
+
+#define CSC_DESTINATION_BASE 0x1000F8
+#define CSC_DESTINATION_BASE_EXT BIT(27)
+#define CSC_DESTINATION_BASE_CS BIT(26)
+#define CSC_DESTINATION_BASE_ADDRESS_MASK 0x3ffffff
+
+#define CSC_CONTROL 0x1000FC
+#define CSC_CONTROL_STATUS BIT(31)
+#define CSC_CONTROL_SOURCE_FORMAT_MASK (0x7 << 28)
+#define CSC_CONTROL_SOURCE_FORMAT_YUV422 (0x0 << 28)
+#define CSC_CONTROL_SOURCE_FORMAT_YUV420I (0x1 << 28)
+#define CSC_CONTROL_SOURCE_FORMAT_YUV420 (0x2 << 28)
+#define CSC_CONTROL_SOURCE_FORMAT_YVU9 (0x3 << 28)
+#define CSC_CONTROL_SOURCE_FORMAT_IYU1 (0x4 << 28)
+#define CSC_CONTROL_SOURCE_FORMAT_IYU2 (0x5 << 28)
+#define CSC_CONTROL_SOURCE_FORMAT_RGB565 (0x6 << 28)
+#define CSC_CONTROL_SOURCE_FORMAT_RGB8888 (0x7 << 28)
+#define CSC_CONTROL_DESTINATION_FORMAT_MASK (0x3 << 26)
+#define CSC_CONTROL_DESTINATION_FORMAT_RGB565 (0x0 << 26)
+#define CSC_CONTROL_DESTINATION_FORMAT_RGB8888 (0x1 << 26)
+#define CSC_CONTROL_HORIZONTAL_FILTER BIT(25)
+#define CSC_CONTROL_VERTICAL_FILTER BIT(24)
+#define CSC_CONTROL_BYTE_ORDER BIT(23)
+
+#define DE_DATA_PORT 0x110000
+
+#define I2C_BYTE_COUNT 0x010040
+#define I2C_BYTE_COUNT_COUNT_MASK 0xf
+
+#define I2C_CTRL 0x010041
+#define I2C_CTRL_INT BIT(4)
+#define I2C_CTRL_DIR BIT(3)
+#define I2C_CTRL_CTRL BIT(2)
+#define I2C_CTRL_MODE BIT(1)
+#define I2C_CTRL_EN BIT(0)
+
+#define I2C_STATUS 0x010042
+#define I2C_STATUS_TX BIT(3)
+#define I2C_STATUS_ERR BIT(2)
+#define I2C_STATUS_ACK BIT(1)
+#define I2C_STATUS_BSY BIT(0)
+
+#define I2C_RESET 0x010042
+#define I2C_RESET_BUS_ERROR BIT(2)
+
+#define I2C_SLAVE_ADDRESS 0x010043
+#define I2C_SLAVE_ADDRESS_ADDRESS_MASK (0x7f << 1)
+#define I2C_SLAVE_ADDRESS_RW BIT(0)
+
+#define I2C_DATA0 0x010044
+#define I2C_DATA1 0x010045
+#define I2C_DATA2 0x010046
+#define I2C_DATA3 0x010047
+#define I2C_DATA4 0x010048
+#define I2C_DATA5 0x010049
+#define I2C_DATA6 0x01004A
+#define I2C_DATA7 0x01004B
+#define I2C_DATA8 0x01004C
+#define I2C_DATA9 0x01004D
+#define I2C_DATA10 0x01004E
+#define I2C_DATA11 0x01004F
+#define I2C_DATA12 0x010050
+#define I2C_DATA13 0x010051
+#define I2C_DATA14 0x010052
+#define I2C_DATA15 0x010053
+
+#define ZV0_CAPTURE_CTRL 0x090000
+#define ZV0_CAPTURE_CTRL_FIELD_INPUT BIT(27)
+#define ZV0_CAPTURE_CTRL_SCAN BIT(26)
+#define ZV0_CAPTURE_CTRL_CURRENT_BUFFER BIT(25)
+#define ZV0_CAPTURE_CTRL_VERTICAL_SYNC BIT(24)
+#define ZV0_CAPTURE_CTRL_ADJ BIT(19)
+#define ZV0_CAPTURE_CTRL_HA BIT(18)
+#define ZV0_CAPTURE_CTRL_VSK BIT(17)
+#define ZV0_CAPTURE_CTRL_HSK BIT(16)
+#define ZV0_CAPTURE_CTRL_FD BIT(15)
+#define ZV0_CAPTURE_CTRL_VP BIT(14)
+#define ZV0_CAPTURE_CTRL_HP BIT(13)
+#define ZV0_CAPTURE_CTRL_CP BIT(12)
+#define ZV0_CAPTURE_CTRL_UVS BIT(11)
+#define ZV0_CAPTURE_CTRL_BS BIT(10)
+#define ZV0_CAPTURE_CTRL_CS BIT(9)
+#define ZV0_CAPTURE_CTRL_CF BIT(8)
+#define ZV0_CAPTURE_CTRL_FS BIT(7)
+#define ZV0_CAPTURE_CTRL_WEAVE BIT(6)
+#define ZV0_CAPTURE_CTRL_BOB BIT(5)
+#define ZV0_CAPTURE_CTRL_DB BIT(4)
+#define ZV0_CAPTURE_CTRL_CC BIT(3)
+#define ZV0_CAPTURE_CTRL_RGB BIT(2)
+#define ZV0_CAPTURE_CTRL_656 BIT(1)
+#define ZV0_CAPTURE_CTRL_CAP BIT(0)
+
+#define ZV0_CAPTURE_CLIP 0x090004
+#define ZV0_CAPTURE_CLIP_EYCLIP_MASK (0x3ff << 16)
+#define ZV0_CAPTURE_CLIP_XCLIP_MASK 0x3ff
+
+#define ZV0_CAPTURE_SIZE 0x090008
+#define ZV0_CAPTURE_SIZE_HEIGHT_MASK (0x7ff << 16)
+#define ZV0_CAPTURE_SIZE_WIDTH_MASK 0x7ff
+
+#define ZV0_CAPTURE_BUF0_ADDRESS 0x09000C
+#define ZV0_CAPTURE_BUF0_ADDRESS_STATUS BIT(31)
+#define ZV0_CAPTURE_BUF0_ADDRESS_EXT BIT(27)
+#define ZV0_CAPTURE_BUF0_ADDRESS_CS BIT(26)
+#define ZV0_CAPTURE_BUF0_ADDRESS_ADDRESS_MASK 0x3ffffff
+
+#define ZV0_CAPTURE_BUF1_ADDRESS 0x090010
+#define ZV0_CAPTURE_BUF1_ADDRESS_STATUS BIT(31)
+#define ZV0_CAPTURE_BUF1_ADDRESS_EXT BIT(27)
+#define ZV0_CAPTURE_BUF1_ADDRESS_CS BIT(26)
+#define ZV0_CAPTURE_BUF1_ADDRESS_ADDRESS_MASK 0x3ffffff
+
+#define ZV0_CAPTURE_BUF_OFFSET 0x090014
+#ifndef VALIDATION_CHIP
+ #define ZV0_CAPTURE_BUF_OFFSET_YCLIP_ODD_FIELD (0x3ff << 16)
+#endif
+#define ZV0_CAPTURE_BUF_OFFSET_OFFSET_MASK 0xffff
+
+#define ZV0_CAPTURE_FIFO_CTRL 0x090018
+#define ZV0_CAPTURE_FIFO_CTRL_FIFO_MASK 0x7
+#define ZV0_CAPTURE_FIFO_CTRL_FIFO_0 0
+#define ZV0_CAPTURE_FIFO_CTRL_FIFO_1 1
+#define ZV0_CAPTURE_FIFO_CTRL_FIFO_2 2
+#define ZV0_CAPTURE_FIFO_CTRL_FIFO_3 3
+#define ZV0_CAPTURE_FIFO_CTRL_FIFO_4 4
+#define ZV0_CAPTURE_FIFO_CTRL_FIFO_5 5
+#define ZV0_CAPTURE_FIFO_CTRL_FIFO_6 6
+#define ZV0_CAPTURE_FIFO_CTRL_FIFO_7 7
+
+#define ZV0_CAPTURE_YRGB_CONST 0x09001C
+#define ZV0_CAPTURE_YRGB_CONST_Y_MASK (0xff << 24)
+#define ZV0_CAPTURE_YRGB_CONST_R_MASK (0xff << 16)
+#define ZV0_CAPTURE_YRGB_CONST_G_MASK (0xff << 8)
+#define ZV0_CAPTURE_YRGB_CONST_B_MASK 0xff
+
+#define ZV0_CAPTURE_LINE_COMP 0x090020
+#define ZV0_CAPTURE_LINE_COMP_LC_MASK 0x7ff
+
+/* ZV1 */
+
+#define ZV1_CAPTURE_CTRL 0x098000
+#define ZV1_CAPTURE_CTRL_FIELD_INPUT BIT(27)
+#define ZV1_CAPTURE_CTRL_SCAN BIT(26)
+#define ZV1_CAPTURE_CTRL_CURRENT_BUFFER BIT(25)
+#define ZV1_CAPTURE_CTRL_VERTICAL_SYNC BIT(24)
+#define ZV1_CAPTURE_CTRL_PANEL BIT(20)
+#define ZV1_CAPTURE_CTRL_ADJ BIT(19)
+#define ZV1_CAPTURE_CTRL_HA BIT(18)
+#define ZV1_CAPTURE_CTRL_VSK BIT(17)
+#define ZV1_CAPTURE_CTRL_HSK BIT(16)
+#define ZV1_CAPTURE_CTRL_FD BIT(15)
+#define ZV1_CAPTURE_CTRL_VP BIT(14)
+#define ZV1_CAPTURE_CTRL_HP BIT(13)
+#define ZV1_CAPTURE_CTRL_CP BIT(12)
+#define ZV1_CAPTURE_CTRL_UVS BIT(11)
+#define ZV1_CAPTURE_CTRL_BS BIT(10)
+#define ZV1_CAPTURE_CTRL_CS BIT(9)
+#define ZV1_CAPTURE_CTRL_CF BIT(8)
+#define ZV1_CAPTURE_CTRL_FS BIT(7)
+#define ZV1_CAPTURE_CTRL_WEAVE BIT(6)
+#define ZV1_CAPTURE_CTRL_BOB BIT(5)
+#define ZV1_CAPTURE_CTRL_DB BIT(4)
+#define ZV1_CAPTURE_CTRL_CC BIT(3)
+#define ZV1_CAPTURE_CTRL_RGB BIT(2)
+#define ZV1_CAPTURE_CTRL_656 BIT(1)
+#define ZV1_CAPTURE_CTRL_CAP BIT(0)
+
+#define ZV1_CAPTURE_CLIP 0x098004
+#define ZV1_CAPTURE_CLIP_YCLIP_MASK (0x3ff << 16)
+#define ZV1_CAPTURE_CLIP_XCLIP_MASK 0x3ff
+
+#define ZV1_CAPTURE_SIZE 0x098008
+#define ZV1_CAPTURE_SIZE_HEIGHT_MASK (0x7ff << 16)
+#define ZV1_CAPTURE_SIZE_WIDTH_MASK 0x7ff
+
+#define ZV1_CAPTURE_BUF0_ADDRESS 0x09800C
+#define ZV1_CAPTURE_BUF0_ADDRESS_STATUS BIT(31)
+#define ZV1_CAPTURE_BUF0_ADDRESS_EXT BIT(27)
+#define ZV1_CAPTURE_BUF0_ADDRESS_CS BIT(26)
+#define ZV1_CAPTURE_BUF0_ADDRESS_ADDRESS_MASK 0x3ffffff
+
+#define ZV1_CAPTURE_BUF1_ADDRESS 0x098010
+#define ZV1_CAPTURE_BUF1_ADDRESS_STATUS BIT(31)
+#define ZV1_CAPTURE_BUF1_ADDRESS_EXT BIT(27)
+#define ZV1_CAPTURE_BUF1_ADDRESS_CS BIT(26)
+#define ZV1_CAPTURE_BUF1_ADDRESS_ADDRESS_MASK 0x3ffffff
+
+#define ZV1_CAPTURE_BUF_OFFSET 0x098014
+#define ZV1_CAPTURE_BUF_OFFSET_OFFSET_MASK 0xffff
+
+#define ZV1_CAPTURE_FIFO_CTRL 0x098018
+#define ZV1_CAPTURE_FIFO_CTRL_FIFO_MASK 0x7
+#define ZV1_CAPTURE_FIFO_CTRL_FIFO_0 0
+#define ZV1_CAPTURE_FIFO_CTRL_FIFO_1 1
+#define ZV1_CAPTURE_FIFO_CTRL_FIFO_2 2
+#define ZV1_CAPTURE_FIFO_CTRL_FIFO_3 3
+#define ZV1_CAPTURE_FIFO_CTRL_FIFO_4 4
+#define ZV1_CAPTURE_FIFO_CTRL_FIFO_5 5
+#define ZV1_CAPTURE_FIFO_CTRL_FIFO_6 6
+#define ZV1_CAPTURE_FIFO_CTRL_FIFO_7 7
+
+#define ZV1_CAPTURE_YRGB_CONST 0x09801C
+#define ZV1_CAPTURE_YRGB_CONST_Y_MASK (0xff << 24)
+#define ZV1_CAPTURE_YRGB_CONST_R_MASK (0xff << 16)
+#define ZV1_CAPTURE_YRGB_CONST_G_MASK (0xff << 8)
+#define ZV1_CAPTURE_YRGB_CONST_B_MASK 0xff
+
+#define DMA_1_SOURCE 0x0D0010
+#define DMA_1_SOURCE_ADDRESS_EXT BIT(27)
+#define DMA_1_SOURCE_ADDRESS_CS BIT(26)
+#define DMA_1_SOURCE_ADDRESS_MASK 0x3ffffff
+
+#define DMA_1_DESTINATION 0x0D0014
+#define DMA_1_DESTINATION_ADDRESS_EXT BIT(27)
+#define DMA_1_DESTINATION_ADDRESS_CS BIT(26)
+#define DMA_1_DESTINATION_ADDRESS_MASK 0x3ffffff
+
+#define DMA_1_SIZE_CONTROL 0x0D0018
+#define DMA_1_SIZE_CONTROL_STATUS BIT(31)
+#define DMA_1_SIZE_CONTROL_SIZE_MASK 0xffffff
+
+#define DMA_ABORT_INTERRUPT 0x0D0020
+#define DMA_ABORT_INTERRUPT_ABORT_1 BIT(5)
+#define DMA_ABORT_INTERRUPT_ABORT_0 BIT(4)
+#define DMA_ABORT_INTERRUPT_INT_1 BIT(1)
+#define DMA_ABORT_INTERRUPT_INT_0 BIT(0)
+
+/* 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_SM750LE_1 BIT(1)
+#define GPIO_DATA_SM750LE_0 BIT(0)
+
+#define GPIO_DATA_DIRECTION_SM750LE 0x02001C
+#define GPIO_DATA_DIRECTION_SM750LE_1 BIT(1)
+#define GPIO_DATA_DIRECTION_SM750LE_0 BIT(0)
+
+#endif
diff --git a/drivers/staging/sm750fb/ddk750_sii164.c b/drivers/staging/sm750fb/ddk750_sii164.c
new file mode 100644
index 000000000..3da1796cd
--- /dev/null
+++ b/drivers/staging/sm750fb/ddk750_sii164.c
@@ -0,0 +1,408 @@
+// SPDX-License-Identifier: GPL-2.0
+#define USE_DVICHIP
+#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 sm750_hw_i2c_write_reg
+ #define i2cReadReg sm750_hw_i2c_read_reg
+#else
+ #define i2cWriteReg sm750_sw_i2c_write_reg
+ #define i2cReadReg sm750_sw_i2c_read_reg
+#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
+
+/*
+ * sii164_get_vendor_id
+ * This function gets the vendor ID of the DVI controller chip.
+ *
+ * Output:
+ * Vendor ID
+ */
+unsigned short sii164_get_vendor_id(void)
+{
+ 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(void)
+{
+ 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 its best to make code
+ * minimal and useful
+ */
+
+/*
+ * sii164InitChip
+ * This function initialize and detect the DVI controller chip.
+ *
+ * Input:
+ * edge_select - 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)
+ * bus_select - Input Bus Select:
+ * 0 = Input data bus is 12-bits wide
+ * 1 = Input data bus is 24-bits wide
+ * dual_edge_clk_select - Dual Edge Clock Select
+ * 0 = Input data is single edge latched
+ * 1 = Input data is dual edge latched
+ * hsync_enable - Horizontal Sync Enable:
+ * 0 = HSYNC input is transmitted as fixed LOW
+ * 1 = HSYNC input is transmitted as is
+ * vsync_enable - Vertical Sync Enable:
+ * 0 = VSYNC input is transmitted as fixed LOW
+ * 1 = VSYNC input is transmitted as is
+ * deskew_enable - De-skewing Enable:
+ * 0 = De-skew disabled
+ * 1 = De-skew enabled
+ * deskew_setting - 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
+ * continuous_sync_enable- SYNC Continuous:
+ * 0 = Disable
+ * 1 = Enable
+ * pll_filter_enable - PLL Filter Enable
+ * 0 = Disable PLL Filter
+ * 1 = Enable PLL Filter
+ * pll_filter_value - PLL Filter characteristics:
+ * 0~7 (recommended value is 4)
+ *
+ * Output:
+ * 0 - Success
+ * -1 - Fail.
+ */
+long sii164InitChip(unsigned char edge_select,
+ unsigned char bus_select,
+ unsigned char dual_edge_clk_select,
+ unsigned char hsync_enable,
+ unsigned char vsync_enable,
+ unsigned char deskew_enable,
+ unsigned char deskew_setting,
+ unsigned char continuous_sync_enable,
+ unsigned char pll_filter_enable,
+ unsigned char pll_filter_value)
+{
+ unsigned char config;
+
+ /* Initialize the i2c bus */
+#ifdef USE_HW_I2C
+ /* Use fast mode. */
+ sm750_hw_i2c_init(1);
+#else
+ sm750_sw_i2c_init(DEFAULT_I2C_SCL, DEFAULT_I2C_SDA);
+#endif
+
+ /* Check if SII164 Chip exists */
+ if ((sii164_get_vendor_id() == SII164_VENDOR_ID) &&
+ (sii164GetDeviceID() == SII164_DEVICE_ID)) {
+ /*
+ * Initialize SII164 controller chip.
+ */
+
+ /* Select the edge */
+ if (edge_select == 0)
+ config = SII164_CONFIGURATION_LATCH_FALLING;
+ else
+ config = SII164_CONFIGURATION_LATCH_RISING;
+
+ /* Select bus wide */
+ if (bus_select == 0)
+ config |= SII164_CONFIGURATION_BUS_12BITS;
+ else
+ config |= SII164_CONFIGURATION_BUS_24BITS;
+
+ /* Select Dual/Single Edge Clock */
+ if (dual_edge_clk_select == 0)
+ config |= SII164_CONFIGURATION_CLOCK_SINGLE;
+ else
+ config |= SII164_CONFIGURATION_CLOCK_DUAL;
+
+ /* Select HSync Enable */
+ if (hsync_enable == 0)
+ config |= SII164_CONFIGURATION_HSYNC_FORCE_LOW;
+ else
+ config |= SII164_CONFIGURATION_HSYNC_AS_IS;
+
+ /* Select VSync Enable */
+ if (vsync_enable == 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 fixes some artifacts problem in some mode on board 2.2.
+ * Somehow this fix does not affect board 2.1.
+ */
+ if (deskew_enable == 0)
+ config = SII164_DESKEW_DISABLE;
+ else
+ config = SII164_DESKEW_ENABLE;
+
+ switch (deskew_setting) {
+ 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 (continuous_sync_enable == 0)
+ config = SII164_PLL_FILTER_SYNC_CONTINUOUS_DISABLE;
+ else
+ config = SII164_PLL_FILTER_SYNC_CONTINUOUS_ENABLE;
+
+ /* Enable/Disable PLL Filter */
+ if (pll_filter_enable == 0)
+ config |= SII164_PLL_FILTER_DISABLE;
+ else
+ config |= SII164_PLL_FILTER_ENABLE;
+
+ /* Set the PLL Filter value */
+ config |= ((pll_filter_value & 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);
+
+ return 0;
+ }
+
+ /* Return -1 if initialization fails. */
+ return -1;
+}
+
+/* below sii164 function is not necessary */
+
+#ifdef SII164_FULL_FUNCTIONS
+
+/*
+ * sii164ResetChip
+ * This function resets the DVI Controller Chip.
+ */
+void sii164ResetChip(void)
+{
+ /* 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(void)
+{
+ 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(enum sii164_hot_plug_mode 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(void)
+{
+ 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 occurred.
+ *
+ * Output:
+ * 0 - No interrupt
+ * 1 - Interrupt occurs
+ */
+unsigned char sii164CheckInterrupt(void)
+{
+ 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(void)
+{
+ 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/staging/sm750fb/ddk750_sii164.h b/drivers/staging/sm750fb/ddk750_sii164.h
new file mode 100644
index 000000000..ca330f6a4
--- /dev/null
+++ b/drivers/staging/sm750fb/ddk750_sii164.h
@@ -0,0 +1,174 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef DDK750_SII164_H__
+#define DDK750_SII164_H__
+
+#define USE_DVICHIP
+
+/* Hot Plug detection mode structure */
+enum sii164_hot_plug_mode {
+ 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. */
+};
+
+/* 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 sii164_get_vendor_id(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 definition 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/staging/sm750fb/ddk750_swi2c.c b/drivers/staging/sm750fb/ddk750_swi2c.c
new file mode 100644
index 000000000..0ef8d4ff2
--- /dev/null
+++ b/drivers/staging/sm750fb/ddk750_swi2c.c
@@ -0,0 +1,504 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+ *
+ * swi2c.c --- SM750/SM718 DDK
+ * This file contains the source code for I2C using software
+ * implementation.
+ */
+
+#include "ddk750_chip.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 sw_i2c_clk_gpio = DEFAULT_I2C_SCL;
+static unsigned char sw_i2c_data_gpio = 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 sw_i2c_clk_gpio_mux_reg = GPIO_MUX;
+static unsigned long sw_i2c_clk_gpio_data_reg = GPIO_DATA;
+static unsigned long sw_i2c_clk_gpio_data_dir_reg = GPIO_DATA_DIRECTION;
+
+/* i2c Data GPIO Register usage */
+static unsigned long sw_i2c_data_gpio_mux_reg = GPIO_MUX;
+static unsigned long sw_i2c_data_gpio_data_reg = GPIO_DATA;
+static unsigned long sw_i2c_data_gpio_data_dir_reg = GPIO_DATA_DIRECTION;
+
+/*
+ * This function puts a delay between command
+ */
+static void sw_i2c_wait(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
+ */
+
+ /* Change wait algorithm to use PCI bus clock,
+ * it's more reliable than counter loop ..
+ * write 0x61 to 0x3ce and read from 0x3cf
+ */
+ int i, tmp;
+
+ for (i = 0; i < 600; i++) {
+ tmp = i;
+ tmp += 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.
+ */
+static void sw_i2c_scl(unsigned char value)
+{
+ unsigned long gpio_data;
+ unsigned long gpio_dir;
+
+ gpio_dir = peek32(sw_i2c_clk_gpio_data_dir_reg);
+ if (value) { /* High */
+ /*
+ * Set direction as input. This will automatically
+ * pull the signal up.
+ */
+ gpio_dir &= ~(1 << sw_i2c_clk_gpio);
+ poke32(sw_i2c_clk_gpio_data_dir_reg, gpio_dir);
+ } else { /* Low */
+ /* Set the signal down */
+ gpio_data = peek32(sw_i2c_clk_gpio_data_reg);
+ gpio_data &= ~(1 << sw_i2c_clk_gpio);
+ poke32(sw_i2c_clk_gpio_data_reg, gpio_data);
+
+ /* Set direction as output */
+ gpio_dir |= (1 << sw_i2c_clk_gpio);
+ poke32(sw_i2c_clk_gpio_data_dir_reg, gpio_dir);
+ }
+}
+
+/*
+ * 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.
+ */
+static void sw_i2c_sda(unsigned char value)
+{
+ unsigned long gpio_data;
+ unsigned long gpio_dir;
+
+ gpio_dir = peek32(sw_i2c_data_gpio_data_dir_reg);
+ if (value) { /* High */
+ /*
+ * Set direction as input. This will automatically
+ * pull the signal up.
+ */
+ gpio_dir &= ~(1 << sw_i2c_data_gpio);
+ poke32(sw_i2c_data_gpio_data_dir_reg, gpio_dir);
+ } else { /* Low */
+ /* Set the signal down */
+ gpio_data = peek32(sw_i2c_data_gpio_data_reg);
+ gpio_data &= ~(1 << sw_i2c_data_gpio);
+ poke32(sw_i2c_data_gpio_data_reg, gpio_data);
+
+ /* Set direction as output */
+ gpio_dir |= (1 << sw_i2c_data_gpio);
+ poke32(sw_i2c_data_gpio_data_dir_reg, gpio_dir);
+ }
+}
+
+/*
+ * This function read the data from the SDA GPIO pin
+ *
+ * Return Value:
+ * The SDA data bit sent by the Slave
+ */
+static unsigned char sw_i2c_read_sda(void)
+{
+ unsigned long gpio_dir;
+ unsigned long gpio_data;
+ unsigned long dir_mask = 1 << sw_i2c_data_gpio;
+
+ /* Make sure that the direction is input (High) */
+ gpio_dir = peek32(sw_i2c_data_gpio_data_dir_reg);
+ if ((gpio_dir & dir_mask) != ~dir_mask) {
+ gpio_dir &= ~(1 << sw_i2c_data_gpio);
+ poke32(sw_i2c_data_gpio_data_dir_reg, gpio_dir);
+ }
+
+ /* Now read the SDA line */
+ gpio_data = peek32(sw_i2c_data_gpio_data_reg);
+ if (gpio_data & (1 << sw_i2c_data_gpio))
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * This function sends ACK signal
+ */
+static void sw_i2c_ack(void)
+{
+ return; /* Single byte read is ok without it. */
+}
+
+/*
+ * This function sends the start command to the slave device
+ */
+static void sw_i2c_start(void)
+{
+ /* Start I2C */
+ sw_i2c_sda(1);
+ sw_i2c_scl(1);
+ sw_i2c_sda(0);
+}
+
+/*
+ * This function sends the stop command to the slave device
+ */
+static void sw_i2c_stop(void)
+{
+ /* Stop the I2C */
+ sw_i2c_scl(1);
+ sw_i2c_sda(0);
+ sw_i2c_sda(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
+ */
+static long sw_i2c_write_byte(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 */
+ sw_i2c_scl(0);
+
+ /* Send data bit */
+ if ((value & 0x80) != 0)
+ sw_i2c_sda(1);
+ else
+ sw_i2c_sda(0);
+
+ sw_i2c_wait();
+
+ /* Toggle clk line to one */
+ sw_i2c_scl(1);
+ sw_i2c_wait();
+
+ /* Shift byte to be sent */
+ value = value << 1;
+ }
+
+ /* Set the SCL Low and SDA High (prepare to get input) */
+ sw_i2c_scl(0);
+ sw_i2c_sda(1);
+
+ /* Set the SCL High for ack */
+ sw_i2c_wait();
+ sw_i2c_scl(1);
+ sw_i2c_wait();
+
+ /* Read SDA, until SDA==0 */
+ for (i = 0; i < 0xff; i++) {
+ if (!sw_i2c_read_sda())
+ break;
+
+ sw_i2c_scl(0);
+ sw_i2c_wait();
+ sw_i2c_scl(1);
+ sw_i2c_wait();
+ }
+
+ /* Set the SCL Low and SDA High */
+ sw_i2c_scl(0);
+ sw_i2c_sda(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
+ */
+static unsigned char sw_i2c_read_byte(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) */
+ sw_i2c_scl(0);
+ sw_i2c_sda(1);
+ sw_i2c_wait();
+
+ /* Set the SCL High */
+ sw_i2c_scl(1);
+ sw_i2c_wait();
+
+ /* Read data bits from SDA */
+ data |= (sw_i2c_read_sda() << i);
+ }
+
+ if (ack)
+ sw_i2c_ack();
+
+ /* Set the SCL Low and SDA High */
+ sw_i2c_scl(0);
+ sw_i2c_sda(1);
+
+ return data;
+}
+
+/*
+ * This function initializes GPIO port for SW I2C communication.
+ *
+ * Parameters:
+ * clk_gpio - The GPIO pin to be used as i2c SCL
+ * data_gpio - The GPIO pin to be used as i2c SDA
+ *
+ * Return Value:
+ * -1 - Fail to initialize the i2c
+ * 0 - Success
+ */
+static long sm750le_i2c_init(unsigned char clk_gpio, unsigned char data_gpio)
+{
+ int i;
+
+ /* Initialize the GPIO pin for the i2c Clock Register */
+ sw_i2c_clk_gpio_data_reg = GPIO_DATA_SM750LE;
+ sw_i2c_clk_gpio_data_dir_reg = GPIO_DATA_DIRECTION_SM750LE;
+
+ /* Initialize the Clock GPIO Offset */
+ sw_i2c_clk_gpio = clk_gpio;
+
+ /* Initialize the GPIO pin for the i2c Data Register */
+ sw_i2c_data_gpio_data_reg = GPIO_DATA_SM750LE;
+ sw_i2c_data_gpio_data_dir_reg = GPIO_DATA_DIRECTION_SM750LE;
+
+ /* Initialize the Data GPIO Offset */
+ sw_i2c_data_gpio = data_gpio;
+
+ /* Note that SM750LE don't have GPIO MUX and power is always on */
+
+ /* Clear the i2c lines. */
+ for (i = 0; i < 9; i++)
+ sw_i2c_stop();
+
+ return 0;
+}
+
+/*
+ * This function initializes the i2c attributes and bus
+ *
+ * Parameters:
+ * clk_gpio - The GPIO pin to be used as i2c SCL
+ * data_gpio - The GPIO pin to be used as i2c SDA
+ *
+ * Return Value:
+ * -1 - Fail to initialize the i2c
+ * 0 - Success
+ */
+long sm750_sw_i2c_init(unsigned char clk_gpio, unsigned char data_gpio)
+{
+ int i;
+
+ /*
+ * Return 0 if the GPIO pins to be used is out of range. The
+ * range is only from [0..63]
+ */
+ if ((clk_gpio > 31) || (data_gpio > 31))
+ return -1;
+
+ if (sm750_get_chip_type() == SM750LE)
+ return sm750le_i2c_init(clk_gpio, data_gpio);
+
+ /* Initialize the GPIO pin for the i2c Clock Register */
+ sw_i2c_clk_gpio_mux_reg = GPIO_MUX;
+ sw_i2c_clk_gpio_data_reg = GPIO_DATA;
+ sw_i2c_clk_gpio_data_dir_reg = GPIO_DATA_DIRECTION;
+
+ /* Initialize the Clock GPIO Offset */
+ sw_i2c_clk_gpio = clk_gpio;
+
+ /* Initialize the GPIO pin for the i2c Data Register */
+ sw_i2c_data_gpio_mux_reg = GPIO_MUX;
+ sw_i2c_data_gpio_data_reg = GPIO_DATA;
+ sw_i2c_data_gpio_data_dir_reg = GPIO_DATA_DIRECTION;
+
+ /* Initialize the Data GPIO Offset */
+ sw_i2c_data_gpio = data_gpio;
+
+ /* Enable the GPIO pins for the i2c Clock and Data (GPIO MUX) */
+ poke32(sw_i2c_clk_gpio_mux_reg,
+ peek32(sw_i2c_clk_gpio_mux_reg) & ~(1 << sw_i2c_clk_gpio));
+ poke32(sw_i2c_data_gpio_mux_reg,
+ peek32(sw_i2c_data_gpio_mux_reg) & ~(1 << sw_i2c_data_gpio));
+
+ /* Enable GPIO power */
+ sm750_enable_gpio(1);
+
+ /* Clear the i2c lines. */
+ for (i = 0; i < 9; i++)
+ sw_i2c_stop();
+
+ return 0;
+}
+
+/*
+ * This function reads the slave device's register
+ *
+ * Parameters:
+ * addr - i2c Slave device address which register
+ * to be read from
+ * reg - Slave device's register to be read
+ *
+ * Return Value:
+ * Register value
+ */
+unsigned char sm750_sw_i2c_read_reg(unsigned char addr, unsigned char reg)
+{
+ unsigned char data;
+
+ /* Send the Start signal */
+ sw_i2c_start();
+
+ /* Send the device address */
+ sw_i2c_write_byte(addr);
+
+ /* Send the register index */
+ sw_i2c_write_byte(reg);
+
+ /* Get the bus again and get the data from the device read address */
+ sw_i2c_start();
+ sw_i2c_write_byte(addr + 1);
+ data = sw_i2c_read_byte(1);
+
+ /* Stop swI2C and release the bus */
+ sw_i2c_stop();
+
+ return data;
+}
+
+/*
+ * This function writes a value to the slave device's register
+ *
+ * Parameters:
+ * addr - i2c Slave device address which register
+ * to be written
+ * reg - Slave device's register to be written
+ * data - Data to be written to the register
+ *
+ * Result:
+ * 0 - Success
+ * -1 - Fail
+ */
+long sm750_sw_i2c_write_reg(unsigned char addr,
+ unsigned char reg,
+ unsigned char data)
+{
+ long ret = 0;
+
+ /* Send the Start signal */
+ sw_i2c_start();
+
+ /* Send the device address and read the data. All should return success
+ * in order for the writing processed to be successful
+ */
+ if ((sw_i2c_write_byte(addr) != 0) ||
+ (sw_i2c_write_byte(reg) != 0) ||
+ (sw_i2c_write_byte(data) != 0)) {
+ ret = -1;
+ }
+
+ /* Stop i2c and release the bus */
+ sw_i2c_stop();
+
+ return ret;
+}
diff --git a/drivers/staging/sm750fb/ddk750_swi2c.h b/drivers/staging/sm750fb/ddk750_swi2c.h
new file mode 100644
index 000000000..dfa166060
--- /dev/null
+++ b/drivers/staging/sm750fb/ddk750_swi2c.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+ *
+ * swi2c.h --- SM750/SM718 DDK
+ * This file contains the definitions for i2c using software
+ * implementation.
+ *
+ */
+
+#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 sm750_sw_i2c_init(unsigned char clk_gpio, unsigned char data_gpio);
+
+/*
+ * This function reads the slave device's register
+ *
+ * Parameters:
+ * addr - i2c Slave device address which register
+ * to be read from
+ * reg - Slave device's register to be read
+ *
+ * Return Value:
+ * Register value
+ */
+unsigned char sm750_sw_i2c_read_reg(unsigned char addr, unsigned char reg);
+
+/*
+ * This function writes a value to the slave device's register
+ *
+ * Parameters:
+ * addr - i2c Slave device address which register
+ * to be written
+ * reg - Slave device's register to be written
+ * data - Data to be written to the register
+ *
+ * Result:
+ * 0 - Success
+ * -1 - Fail
+ */
+long sm750_sw_i2c_write_reg(unsigned char addr,
+ unsigned char reg,
+ unsigned char data);
+
+#endif /* _SWI2C_H_ */
diff --git a/drivers/staging/sm750fb/readme b/drivers/staging/sm750fb/readme
new file mode 100644
index 000000000..cfa45958b
--- /dev/null
+++ b/drivers/staging/sm750fb/readme
@@ -0,0 +1,38 @@
+Introduction:
+ SM750 of Silicon MOtion is pci express display controller device.
+ The SM750 embedded graphics features include:
+ - dual display
+ - 2D acceleration
+ - 16MB integrated video memory
+
+About the kernel module parameter of driver:
+
+ Use 1280,8bpp index color and 60 hz mode:
+ insmod ./sm750fb.ko g_option="1280x1024-8@60"
+
+ Disable MTRR,Disable 2d acceleration,Disable hardware cursor,
+ and use a 800x600 mode :
+ insmod ./sm750fb.ko g_option="noaccel:nomtrr:nohwc:800x600"
+
+ dual frame buffer for driver with "dual" parameter
+ insmod ./sm750fb.ko g_option="dual,800x600:1024x768"
+ it will create fb0 and fb1 (or fb1,fb2 if fb0 already exist) under /dev
+ and user can use con2fb to link fbX and ttyX
+
+ Notes:
+ 1) if you build the driver with built-in method, the parameter
+ you edited in the grub config file will be also the
+ same format as above modular method,but additionally add
+ "video=sm750fb:"
+ ahead of parameters,so,it looks like:
+ video=sm750fb:noaccel,1280x1024@60,otherparam,etc...
+ it equal to modular method with below command:
+ insmod ./sm750fb.ko g_option="noaccel:1280x1024@60:otherparm:etc..."
+
+ 2) if you put 800x600 into the parameter without bpp and
+ refresh rate, kernel driver will defaulty use 16bpp and 60hz
+
+Important:
+ if you have vesafb enabled in your config then /dev/fb0 will be created by vesafb
+ and this driver will use fb1, fb2. In that case, you need to configure your X-server
+ to use fb1. Another simple althernative is to disable vesafb from your config.
diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c
new file mode 100644
index 000000000..168ae2e90
--- /dev/null
+++ b/drivers/staging/sm750fb/sm750.c
@@ -0,0 +1,1204 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/aperture.h>
+#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>
+#include <linux/mm_types.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/screen_info.h>
+#include <linux/console.h>
+#include <asm/fb.h>
+#include "sm750.h"
+#include "sm750_accel.h"
+#include "sm750_cursor.h"
+
+/*
+ * #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
+ */
+
+/* common var for all device */
+static int g_hwcursor = 1;
+static int g_noaccel;
+static int g_nomtrr;
+static const char *g_fbmode[] = {NULL, NULL};
+static const char *g_def_fbmode = "1024x768-32@60";
+static char *g_settings;
+static int g_dualview;
+static char *g_option;
+
+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@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},
+
+ /* 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},
+};
+
+/* 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->max_w ||
+ fbcursor->image.height > cursor->max_h ||
+ fbcursor->image.depth > 1) {
+ return -ENXIO;
+ }
+
+ sm750_hw_cursor_disable(cursor);
+ if (fbcursor->set & FB_CUR_SETSIZE)
+ sm750_hw_cursor_setSize(cursor,
+ fbcursor->image.width,
+ fbcursor->image.height);
+
+ if (fbcursor->set & FB_CUR_SETPOS)
+ sm750_hw_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);
+
+ sm750_hw_cursor_setColor(cursor, fg, bg);
+ }
+
+ if (fbcursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
+ sm750_hw_cursor_setData(cursor,
+ fbcursor->rop,
+ fbcursor->image.data,
+ fbcursor->mask);
+ }
+
+ if (fbcursor->enable)
+ sm750_hw_cursor_enable(cursor);
+
+ return 0;
+}
+
+static void lynxfb_ops_fillrect(struct fb_info *info,
+ const struct fb_fillrect *region)
+{
+ struct lynxfb_par *par;
+ struct sm750_dev *sm750_dev;
+ unsigned int base, pitch, Bpp, rop;
+ u32 color;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return;
+
+ par = info->par;
+ sm750_dev = par->dev;
+
+ /*
+ * 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.o_screen;
+ 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;
+
+ /*
+ * If not use spin_lock, system will die if user load driver
+ * and immediately unload driver frequently (dual)
+ * since they fb_count could change during the lifetime of
+ * this lock, we are holding it for all cases.
+ */
+ spin_lock(&sm750_dev->slock);
+
+ sm750_dev->accel.de_fillrect(&sm750_dev->accel,
+ base, pitch, Bpp,
+ region->dx, region->dy,
+ region->width, region->height,
+ color, rop);
+ spin_unlock(&sm750_dev->slock);
+}
+
+static void lynxfb_ops_copyarea(struct fb_info *info,
+ const struct fb_copyarea *region)
+{
+ struct lynxfb_par *par;
+ struct sm750_dev *sm750_dev;
+ unsigned int base, pitch, Bpp;
+
+ par = info->par;
+ sm750_dev = par->dev;
+
+ /*
+ * 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.o_screen;
+ pitch = info->fix.line_length;
+ Bpp = info->var.bits_per_pixel >> 3;
+
+ /*
+ * If not use spin_lock, system will die if user load driver
+ * and immediately unload driver frequently (dual)
+ * since they fb_count could change during the lifetime of
+ * this lock, we are holding it for all cases.
+ */
+ spin_lock(&sm750_dev->slock);
+
+ sm750_dev->accel.de_copyarea(&sm750_dev->accel,
+ base, pitch, region->sx, region->sy,
+ base, pitch, Bpp, region->dx, region->dy,
+ region->width, region->height,
+ HW_ROP2_COPY);
+ spin_unlock(&sm750_dev->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 sm750_dev *sm750_dev;
+
+ par = info->par;
+ sm750_dev = par->dev;
+ /*
+ * 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.o_screen;
+ pitch = info->fix.line_length;
+ Bpp = info->var.bits_per_pixel >> 3;
+
+ /* TODO: Implement hardware acceleration for image->depth > 1 */
+ if (image->depth != 1) {
+ cfb_imageblit(info, image);
+ return;
+ }
+
+ 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;
+ }
+
+ /*
+ * If not use spin_lock, system will die if user load driver
+ * and immediately unload driver frequently (dual)
+ * since they fb_count could change during the lifetime of
+ * this lock, we are holding it for all cases.
+ */
+ spin_lock(&sm750_dev->slock);
+
+ sm750_dev->accel.de_imageblit(&sm750_dev->accel,
+ image->data, image->width >> 3, 0,
+ base, pitch, Bpp,
+ image->dx, image->dy,
+ image->width, image->height,
+ fgcol, bgcol, HW_ROP2_COPY);
+ spin_unlock(&sm750_dev->slock);
+}
+
+static int lynxfb_ops_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct lynxfb_par *par;
+ struct lynxfb_crtc *crtc;
+
+ if (!info)
+ return -EINVAL;
+
+ par = info->par;
+ crtc = &par->crtc;
+ return hw_sm750_pan_display(crtc, var, info);
+}
+
+static inline void lynxfb_set_visual_mode(struct fb_info *info)
+{
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ break;
+ case 16:
+ case 24:
+ case 32:
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ break;
+ default:
+ break;
+ }
+}
+
+static inline int lynxfb_set_color_offsets(struct fb_info *info)
+{
+ lynxfb_set_visual_mode(info);
+
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ info->var.red.offset = 0;
+ info->var.red.length = 8;
+ info->var.green.offset = 0;
+ info->var.green.length = 8;
+ info->var.blue.offset = 0;
+ info->var.blue.length = 8;
+ info->var.transp.length = 0;
+ info->var.transp.offset = 0;
+ break;
+ case 16:
+ info->var.red.offset = 11;
+ info->var.red.length = 5;
+ info->var.green.offset = 5;
+ info->var.green.length = 6;
+ info->var.blue.offset = 0;
+ info->var.blue.length = 5;
+ info->var.transp.length = 0;
+ info->var.transp.offset = 0;
+ break;
+ case 24:
+ case 32:
+ info->var.red.offset = 16;
+ info->var.red.length = 8;
+ info->var.green.offset = 8;
+ info->var.green.length = 8;
+ info->var.blue.offset = 0;
+ info->var.blue.length = 8;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int lynxfb_ops_set_par(struct fb_info *info)
+{
+ struct lynxfb_par *par;
+ struct lynxfb_crtc *crtc;
+ struct lynxfb_output *output;
+ struct fb_var_screeninfo *var;
+ struct fb_fix_screeninfo *fix;
+ int ret;
+ unsigned int line_length;
+
+ if (!info)
+ return -EINVAL;
+
+ ret = 0;
+ par = info->par;
+ crtc = &par->crtc;
+ output = &par->output;
+ var = &info->var;
+ fix = &info->fix;
+
+ /* fix structure is not so FIX ... */
+ line_length = var->xres_virtual * var->bits_per_pixel / 8;
+ line_length = ALIGN(line_length, crtc->line_pad);
+ fix->line_length = line_length;
+ pr_info("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
+ */
+
+ ret = lynxfb_set_color_offsets(info);
+
+ var->height = -1;
+ var->width = -1;
+ var->accel_flags = 0;/*FB_ACCELF_TEXT;*/
+
+ if (ret) {
+ pr_err("bpp %d not supported\n", var->bits_per_pixel);
+ return ret;
+ }
+ ret = hw_sm750_crtc_setMode(crtc, var, fix);
+ if (!ret)
+ ret = hw_sm750_output_setMode(output, var, fix);
+ return 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 __maybe_unused lynxfb_suspend(struct device *dev)
+{
+ struct fb_info *info;
+ struct sm750_dev *sm750_dev;
+
+ sm750_dev = dev_get_drvdata(dev);
+
+ console_lock();
+ info = sm750_dev->fbinfo[0];
+ if (info)
+ /* 1 means do suspend */
+ fb_set_suspend(info, 1);
+ info = sm750_dev->fbinfo[1];
+ if (info)
+ /* 1 means do suspend */
+ fb_set_suspend(info, 1);
+
+ console_unlock();
+ return 0;
+}
+
+static int __maybe_unused lynxfb_resume(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct fb_info *info;
+ struct sm750_dev *sm750_dev;
+
+ struct lynxfb_par *par;
+ struct lynxfb_crtc *crtc;
+ struct lynx_cursor *cursor;
+
+ sm750_dev = pci_get_drvdata(pdev);
+
+ console_lock();
+
+ hw_sm750_inithw(sm750_dev, pdev);
+
+ info = sm750_dev->fbinfo[0];
+
+ if (info) {
+ par = info->par;
+ crtc = &par->crtc;
+ cursor = &crtc->cursor;
+ memset_io(cursor->vstart, 0x0, cursor->size);
+ memset_io(crtc->v_screen, 0x0, crtc->vidmem_size);
+ lynxfb_ops_set_par(info);
+ fb_set_suspend(info, 0);
+ }
+
+ info = sm750_dev->fbinfo[1];
+
+ if (info) {
+ par = info->par;
+ crtc = &par->crtc;
+ cursor = &crtc->cursor;
+ memset_io(cursor->vstart, 0x0, cursor->size);
+ memset_io(crtc->v_screen, 0x0, crtc->vidmem_size);
+ lynxfb_ops_set_par(info);
+ fb_set_suspend(info, 0);
+ }
+
+ pdev->dev.power.power_state.event = PM_EVENT_RESUME;
+
+ console_unlock();
+ return 0;
+}
+
+static int lynxfb_ops_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ int ret;
+ struct lynxfb_par *par;
+ struct lynxfb_crtc *crtc;
+ resource_size_t request;
+
+ ret = 0;
+ par = info->par;
+ crtc = &par->crtc;
+
+ pr_debug("check var:%dx%d-%d\n",
+ var->xres,
+ var->yres,
+ var->bits_per_pixel);
+
+ ret = lynxfb_set_color_offsets(info);
+
+ if (ret) {
+ pr_err("bpp %d not supported\n", var->bits_per_pixel);
+ return ret;
+ }
+
+ var->height = -1;
+ var->width = -1;
+ var->accel_flags = 0;/* FB_ACCELF_TEXT; */
+
+ /* check if current fb's video memory big enough to hold the onscreen*/
+ request = var->xres_virtual * (var->bits_per_pixel >> 3);
+ /* defaulty crtc->channel go with par->index */
+
+ request = ALIGN(request, crtc->line_pad);
+ request = request * var->yres_virtual;
+ if (crtc->vidmem_size < request) {
+ pr_err("not enough video memory for mode\n");
+ return -ENOMEM;
+ }
+
+ return hw_sm750_crtc_checkMode(crtc, var);
+}
+
+static int lynxfb_ops_setcolreg(unsigned int regno,
+ unsigned int red,
+ unsigned int green,
+ unsigned int blue,
+ unsigned int 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;
+
+ if (regno > 256) {
+ pr_err("regno = %d\n", regno);
+ return -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 = hw_sm750_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;
+}
+
+static int lynxfb_ops_blank(int blank, struct fb_info *info)
+{
+ struct lynxfb_par *par;
+ struct lynxfb_output *output;
+
+ pr_debug("blank = %d.\n", blank);
+ par = info->par;
+ output = &par->output;
+ return output->proc_setBLANK(output, blank);
+}
+
+static int sm750fb_set_drv(struct lynxfb_par *par)
+{
+ int ret;
+ struct sm750_dev *sm750_dev;
+ struct lynxfb_output *output;
+ struct lynxfb_crtc *crtc;
+
+ ret = 0;
+
+ sm750_dev = par->dev;
+ output = &par->output;
+ crtc = &par->crtc;
+
+ crtc->vidmem_size = sm750_dev->vidmem_size;
+ if (sm750_dev->fb_count > 1)
+ crtc->vidmem_size >>= 1;
+
+ /* setup crtc and output member */
+ sm750_dev->hwCursor = g_hwcursor;
+
+ crtc->line_pad = 16;
+ crtc->xpanstep = 8;
+ crtc->ypanstep = 1;
+ crtc->ywrapstep = 0;
+
+ output->proc_setBLANK = (sm750_dev->revid == SM750LE_REVISION_ID) ?
+ hw_sm750le_setBLANK : hw_sm750_setBLANK;
+ /* chip specific phase */
+ sm750_dev->accel.de_wait = (sm750_dev->revid == SM750LE_REVISION_ID) ?
+ hw_sm750le_deWait : hw_sm750_deWait;
+ switch (sm750_dev->dataflow) {
+ case sm750_simul_pri:
+ output->paths = sm750_pnc;
+ crtc->channel = sm750_primary;
+ crtc->o_screen = 0;
+ crtc->v_screen = sm750_dev->pvMem;
+ pr_info("use simul primary mode\n");
+ break;
+ case sm750_simul_sec:
+ output->paths = sm750_pnc;
+ crtc->channel = sm750_secondary;
+ crtc->o_screen = 0;
+ crtc->v_screen = sm750_dev->pvMem;
+ break;
+ case sm750_dual_normal:
+ if (par->index == 0) {
+ output->paths = sm750_panel;
+ crtc->channel = sm750_primary;
+ crtc->o_screen = 0;
+ crtc->v_screen = sm750_dev->pvMem;
+ } else {
+ output->paths = sm750_crt;
+ crtc->channel = sm750_secondary;
+ /* not consider of padding stuffs for o_screen,need fix */
+ crtc->o_screen = sm750_dev->vidmem_size >> 1;
+ crtc->v_screen = sm750_dev->pvMem + crtc->o_screen;
+ }
+ break;
+ case sm750_dual_swap:
+ if (par->index == 0) {
+ output->paths = sm750_panel;
+ crtc->channel = sm750_secondary;
+ crtc->o_screen = 0;
+ crtc->v_screen = sm750_dev->pvMem;
+ } else {
+ output->paths = sm750_crt;
+ crtc->channel = sm750_primary;
+ /* not consider of padding stuffs for o_screen,
+ * need fix
+ */
+ crtc->o_screen = sm750_dev->vidmem_size >> 1;
+ crtc->v_screen = sm750_dev->pvMem + crtc->o_screen;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return 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,
+ .fb_fillrect = cfb_fillrect,
+ .fb_imageblit = cfb_imageblit,
+ .fb_copyarea = cfb_copyarea,
+ /* cursor */
+ .fb_cursor = lynxfb_ops_cursor,
+};
+
+static int lynxfb_set_fbinfo(struct fb_info *info, int index)
+{
+ int i;
+ struct lynxfb_par *par;
+ struct sm750_dev *sm750_dev;
+ struct lynxfb_crtc *crtc;
+ struct lynxfb_output *output;
+ struct fb_var_screeninfo *var;
+ struct fb_fix_screeninfo *fix;
+
+ const struct fb_videomode *pdb[] = {
+ lynx750_ext, NULL, vesa_modes,
+ };
+ int cdb[] = {ARRAY_SIZE(lynx750_ext), 0, VESA_MODEDB_SIZE};
+ static const char * const mdb_desc[] = {
+ "driver prepared modes",
+ "kernel prepared default modedb",
+ "kernel HELPERS prepared vesa_modes",
+ };
+
+ static const char *fixId[2] = {
+ "sm750_fb1", "sm750_fb2",
+ };
+
+ int ret, line_length;
+
+ ret = 0;
+ par = (struct lynxfb_par *)info->par;
+ sm750_dev = par->dev;
+ 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->o_screen + crtc->vidmem_size - 1024;
+ crtc->cursor.mmio = sm750_dev->pvReg +
+ 0x800f0 + (int)crtc->channel * 0x140;
+
+ pr_info("crtc->cursor.mmio = %p\n", crtc->cursor.mmio);
+ crtc->cursor.max_h = 64;
+ crtc->cursor.max_w = 64;
+ crtc->cursor.size = crtc->cursor.max_h * crtc->cursor.max_w * 2 / 8;
+ crtc->cursor.vstart = sm750_dev->pvMem + crtc->cursor.offset;
+
+ memset_io(crtc->cursor.vstart, 0, crtc->cursor.size);
+ if (!g_hwcursor) {
+ lynxfb_ops.fb_cursor = NULL;
+ sm750_hw_cursor_disable(&crtc->cursor);
+ }
+
+ /* set info->fbops, must be set before fb_find_mode */
+ if (!sm750_dev->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];
+ }
+
+ for (i = 0; i < 3; i++) {
+ ret = fb_find_mode(var, info, g_fbmode[index],
+ pdb[i], cdb[i], NULL, 8);
+
+ if (ret == 1) {
+ pr_info("success! use specified mode:%s in %s\n",
+ g_fbmode[index],
+ mdb_desc[i]);
+ break;
+ } else if (ret == 2) {
+ pr_warn("use specified mode:%s in %s,with an ignored refresh rate\n",
+ g_fbmode[index],
+ mdb_desc[i]);
+ break;
+ } else if (ret == 3) {
+ pr_warn("wanna use default mode\n");
+ /*break;*/
+ } else if (ret == 4) {
+ pr_warn("fall back to any valid mode\n");
+ } else {
+ pr_warn("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 */
+
+ pr_info("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 = ALIGN((var->xres_virtual * var->bits_per_pixel / 8),
+ crtc->line_pad);
+
+ info->pseudo_palette = &par->pseudo_palette[0];
+ info->screen_base = crtc->v_screen;
+ pr_debug("screen_base vaddr = %p\n", info->screen_base);
+ info->screen_size = line_length * var->yres_virtual;
+ 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_SMI;
+
+ strscpy(fix->id, fixId[index], sizeof(fix->id));
+
+ fix->smem_start = crtc->o_screen + sm750_dev->vidmem_start;
+ pr_info("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;
+ pr_info("fix->smem_len = %x\n", fix->smem_len);
+ info->screen_size = fix->smem_len;
+ fix->line_length = line_length;
+ fix->mmio_start = sm750_dev->vidreg_start;
+ pr_info("fix->mmio_start = %lx\n", fix->mmio_start);
+ fix->mmio_len = sm750_dev->vidreg_size;
+ pr_info("fix->mmio_len = %x\n", fix->mmio_len);
+
+ lynxfb_set_visual_mode(info);
+
+ /* set var */
+ var->activate = FB_ACTIVATE_NOW;
+ var->accel_flags = 0;
+ var->vmode = FB_VMODE_NONINTERLACED;
+
+ pr_debug("#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) {
+ pr_err("Could not allocate memory for cmap.\n");
+ goto exit;
+ }
+
+ pr_debug("#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);
+ return ret;
+}
+
+/* chip specific g_option configuration routine */
+static void sm750fb_setup(struct sm750_dev *sm750_dev, char *src)
+{
+ char *opt;
+ int swap;
+
+ swap = 0;
+
+ sm750_dev->initParm.chip_clk = 0;
+ sm750_dev->initParm.mem_clk = 0;
+ sm750_dev->initParm.master_clk = 0;
+ sm750_dev->initParm.powerMode = 0;
+ sm750_dev->initParm.setAllEngOff = 0;
+ sm750_dev->initParm.resetMemory = 1;
+
+ /* defaultly turn g_hwcursor on for both view */
+ g_hwcursor = 3;
+
+ if (!src || !*src) {
+ dev_warn(&sm750_dev->pdev->dev, "no specific g_option.\n");
+ goto NO_PARAM;
+ }
+
+ while ((opt = strsep(&src, ":")) != NULL && *opt != 0) {
+ dev_info(&sm750_dev->pdev->dev, "opt=%s\n", opt);
+ dev_info(&sm750_dev->pdev->dev, "src=%s\n", src);
+
+ if (!strncmp(opt, "swap", strlen("swap"))) {
+ swap = 1;
+ } else if (!strncmp(opt, "nocrt", strlen("nocrt"))) {
+ sm750_dev->nocrt = 1;
+ } else if (!strncmp(opt, "36bit", strlen("36bit"))) {
+ sm750_dev->pnltype = sm750_doubleTFT;
+ } else if (!strncmp(opt, "18bit", strlen("18bit"))) {
+ sm750_dev->pnltype = sm750_dualTFT;
+ } else if (!strncmp(opt, "24bit", strlen("24bit"))) {
+ sm750_dev->pnltype = sm750_24TFT;
+ } 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;
+ dev_info(&sm750_dev->pdev->dev,
+ "find fbmode0 : %s\n", g_fbmode[0]);
+ } else if (!g_fbmode[1]) {
+ g_fbmode[1] = opt;
+ dev_info(&sm750_dev->pdev->dev,
+ "find fbmode1 : %s\n", g_fbmode[1]);
+ } else {
+ dev_warn(&sm750_dev->pdev->dev, "How many view you wann set?\n");
+ }
+ }
+ }
+
+NO_PARAM:
+ if (sm750_dev->revid != SM750LE_REVISION_ID) {
+ if (sm750_dev->fb_count > 1) {
+ if (swap)
+ sm750_dev->dataflow = sm750_dual_swap;
+ else
+ sm750_dev->dataflow = sm750_dual_normal;
+ } else {
+ if (swap)
+ sm750_dev->dataflow = sm750_simul_sec;
+ else
+ sm750_dev->dataflow = sm750_simul_pri;
+ }
+ } else {
+ /* SM750LE only have one crt channel */
+ sm750_dev->dataflow = sm750_simul_sec;
+ /* sm750le do not have complex attributes */
+ sm750_dev->nocrt = 0;
+ }
+}
+
+static void sm750fb_framebuffer_release(struct sm750_dev *sm750_dev)
+{
+ struct fb_info *fb_info;
+
+ while (sm750_dev->fb_count) {
+ fb_info = sm750_dev->fbinfo[sm750_dev->fb_count - 1];
+ unregister_framebuffer(fb_info);
+ framebuffer_release(fb_info);
+ sm750_dev->fb_count--;
+ }
+}
+
+static int sm750fb_framebuffer_alloc(struct sm750_dev *sm750_dev, int fbidx)
+{
+ struct fb_info *fb_info;
+ struct lynxfb_par *par;
+ int err;
+
+ fb_info = framebuffer_alloc(sizeof(struct lynxfb_par),
+ &sm750_dev->pdev->dev);
+ if (!fb_info)
+ return -ENOMEM;
+
+ sm750_dev->fbinfo[fbidx] = fb_info;
+ par = fb_info->par;
+ par->dev = sm750_dev;
+
+ err = lynxfb_set_fbinfo(fb_info, fbidx);
+ if (err)
+ goto release_fb;
+
+ err = register_framebuffer(fb_info);
+ if (err < 0)
+ goto release_fb;
+
+ sm750_dev->fb_count++;
+
+ return 0;
+
+release_fb:
+ framebuffer_release(fb_info);
+ return err;
+}
+
+static int lynxfb_kick_out_firmware_fb(struct pci_dev *pdev)
+{
+ resource_size_t base = pci_resource_start(pdev, 0);
+ resource_size_t size = pci_resource_len(pdev, 0);
+ bool primary = false;
+
+#ifdef CONFIG_X86
+ primary = pdev->resource[PCI_ROM_RESOURCE].flags &
+ IORESOURCE_ROM_SHADOW;
+#endif
+
+ return aperture_remove_conflicting_devices(base, size, primary, "sm750_fb1");
+}
+
+static int lynxfb_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct sm750_dev *sm750_dev = NULL;
+ int max_fb;
+ int fbidx;
+ int err;
+
+ err = lynxfb_kick_out_firmware_fb(pdev);
+ if (err)
+ return err;
+
+ /* enable device */
+ err = pcim_enable_device(pdev);
+ if (err)
+ return err;
+
+ err = -ENOMEM;
+ sm750_dev = devm_kzalloc(&pdev->dev, sizeof(*sm750_dev), GFP_KERNEL);
+ if (!sm750_dev)
+ return err;
+
+ sm750_dev->fbinfo[0] = NULL;
+ sm750_dev->fbinfo[1] = NULL;
+ sm750_dev->devid = pdev->device;
+ sm750_dev->revid = pdev->revision;
+ sm750_dev->pdev = pdev;
+ sm750_dev->mtrr_off = g_nomtrr;
+ sm750_dev->mtrr.vram = 0;
+ sm750_dev->accel_off = g_noaccel;
+ spin_lock_init(&sm750_dev->slock);
+
+ if (!sm750_dev->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
+ */
+ sm750_dev->accel.de_init = sm750_hw_de_init;
+ sm750_dev->accel.de_fillrect = sm750_hw_fillrect;
+ sm750_dev->accel.de_copyarea = sm750_hw_copyarea;
+ sm750_dev->accel.de_imageblit = sm750_hw_imageblit;
+ }
+
+ /* call chip specific setup routine */
+ sm750fb_setup(sm750_dev, g_settings);
+
+ /* call chip specific mmap routine */
+ err = hw_sm750_map(sm750_dev, pdev);
+ if (err)
+ return err;
+
+ if (!sm750_dev->mtrr_off)
+ sm750_dev->mtrr.vram = arch_phys_wc_add(sm750_dev->vidmem_start,
+ sm750_dev->vidmem_size);
+
+ memset_io(sm750_dev->pvMem, 0, sm750_dev->vidmem_size);
+
+ pci_set_drvdata(pdev, sm750_dev);
+
+ /* call chipInit routine */
+ hw_sm750_inithw(sm750_dev, pdev);
+
+ /* allocate frame buffer info structures according to g_dualview */
+ max_fb = g_dualview ? 2 : 1;
+ for (fbidx = 0; fbidx < max_fb; fbidx++) {
+ err = sm750fb_framebuffer_alloc(sm750_dev, fbidx);
+ if (err)
+ goto release_fb;
+ }
+
+ return 0;
+
+release_fb:
+ sm750fb_framebuffer_release(sm750_dev);
+ return err;
+}
+
+static void lynxfb_pci_remove(struct pci_dev *pdev)
+{
+ struct sm750_dev *sm750_dev;
+
+ sm750_dev = pci_get_drvdata(pdev);
+
+ sm750fb_framebuffer_release(sm750_dev);
+ arch_phys_wc_del(sm750_dev->mtrr.vram);
+
+ iounmap(sm750_dev->pvReg);
+ iounmap(sm750_dev->pvMem);
+ kfree(g_settings);
+}
+
+static int __init lynxfb_setup(char *options)
+{
+ int len;
+ char *opt, *tmp;
+
+ if (!options || !*options) {
+ pr_warn("no options.\n");
+ return 0;
+ }
+
+ pr_info("options:%s\n", options);
+
+ len = strlen(options) + 1;
+ g_settings = kzalloc(len, GFP_KERNEL);
+ if (!g_settings)
+ return -ENOMEM;
+
+ 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;
+ } else if (!strncmp(opt, "nomtrr", strlen("nomtrr"))) {
+ g_nomtrr = 1;
+ } else if (!strncmp(opt, "dual", strlen("dual"))) {
+ g_dualview = 1;
+ } else {
+ strcat(tmp, opt);
+ tmp += strlen(opt);
+ if (options)
+ *tmp++ = ':';
+ else
+ *tmp++ = 0;
+ }
+ }
+
+ /* misc g_settings are transport to chip specific routines */
+ pr_info("parameter left for chip specific analysis:%s\n", g_settings);
+ return 0;
+}
+
+static const struct pci_device_id smi_pci_table[] = {
+ { PCI_DEVICE(0x126f, 0x0750), },
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, smi_pci_table);
+
+static SIMPLE_DEV_PM_OPS(lynxfb_pm_ops, lynxfb_suspend, lynxfb_resume);
+
+static struct pci_driver lynxfb_driver = {
+ .name = "sm750fb",
+ .id_table = smi_pci_table,
+ .probe = lynxfb_pci_probe,
+ .remove = lynxfb_pci_remove,
+ .driver.pm = &lynxfb_pm_ops,
+};
+
+static int __init lynxfb_init(void)
+{
+ char *option;
+
+#ifdef MODULE
+ option = g_option;
+#else
+ if (fb_get_options("sm750fb", &option))
+ return -ENODEV;
+#endif
+
+ lynxfb_setup(option);
+ return pci_register_driver(&lynxfb_driver);
+}
+module_init(lynxfb_init);
+
+static void __exit lynxfb_exit(void)
+{
+ pci_unregister_driver(&lynxfb_driver);
+}
+module_exit(lynxfb_exit);
+
+module_param(g_option, charp, 0444);
+
+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 ./sm750fb.ko g_option=\"noaccel,nohwc,1280x1024-8@60\"\n"
+ );
+
+MODULE_AUTHOR("monk liu <monk.liu@siliconmotion.com>");
+MODULE_AUTHOR("Sudip Mukherjee <sudip@vectorindia.org>");
+MODULE_DESCRIPTION("Frame buffer driver for SM750 chipset");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/staging/sm750fb/sm750.h b/drivers/staging/sm750fb/sm750.h
new file mode 100644
index 000000000..aff69661c
--- /dev/null
+++ b/drivers/staging/sm750fb/sm750.h
@@ -0,0 +1,220 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef LYNXDRV_H_
+#define LYNXDRV_H_
+
+#define FB_ACCEL_SMI 0xab
+
+#define MHZ(x) ((x) * 1000000)
+
+#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 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 pointers */
+ void (*de_init)(struct lynx_accel *accel);
+
+ int (*de_wait)(void);/* see if hardware ready to work */
+
+ int (*de_fillrect)(struct lynx_accel *accel,
+ u32 base, u32 pitch, u32 bpp,
+ u32 x, u32 y, u32 width, u32 height,
+ u32 color, u32 rop);
+
+ int (*de_copyarea)(struct lynx_accel *accel,
+ u32 s_base, u32 s_pitch,
+ u32 sx, u32 sy,
+ u32 d_base, u32 d_pitch,
+ u32 bpp, u32 dx, u32 dy,
+ u32 width, u32 height,
+ u32 rop2);
+
+ int (*de_imageblit)(struct lynx_accel *accel, const char *p_srcbuf,
+ u32 src_delta, u32 start_bit, u32 d_base, u32 d_pitch,
+ u32 byte_per_pixel, u32 dx, u32 dy, u32 width,
+ u32 height, u32 f_color, u32 b_color, u32 rop2);
+
+};
+
+struct sm750_dev {
+ /* common members */
+ u16 devid;
+ u8 revid;
+ struct pci_dev *pdev;
+ struct fb_info *fbinfo[2];
+ struct lynx_accel accel;
+ int accel_off;
+ int fb_count;
+ int mtrr_off;
+ struct{
+ int vram;
+ } mtrr;
+ /* all smi graphic adaptor got below attributes */
+ unsigned long vidmem_start;
+ unsigned long vidreg_start;
+ __u32 vidmem_size;
+ __u32 vidreg_size;
+ void __iomem *pvReg;
+ unsigned char __iomem *pvMem;
+ /* locks*/
+ spinlock_t slock;
+
+ struct init_status initParm;
+ enum sm750_pnltype pnltype;
+ enum sm750_dataflow dataflow;
+ int nocrt;
+
+ /*
+ * 0: no hardware cursor
+ * 1: primary crtc hw cursor enabled,
+ * 2: secondary crtc hw cursor enabled
+ * 3: both ctrc hw cursor enabled
+ */
+ int hwCursor;
+};
+
+struct lynx_cursor {
+ /* cursor width ,height and size */
+ int w;
+ int h;
+ int size;
+ /* hardware limitation */
+ int max_w;
+ int max_h;
+ /* base virtual address and offset of cursor image */
+ char __iomem *vstart;
+ int offset;
+ /* mmio addr of hw cursor */
+ volatile char __iomem *mmio;
+};
+
+struct lynxfb_crtc {
+ unsigned char __iomem *v_cursor; /* virtual address of cursor */
+ unsigned char __iomem *v_screen; /* virtual address of on_screen */
+ int o_cursor; /* cursor address offset in vidmem */
+ int o_screen; /* 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;
+
+ /* 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_setBLANK)(struct lynxfb_output *output, int blank);
+};
+
+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 sm750_dev *dev;
+};
+
+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;
+}
+
+int hw_sm750_map(struct sm750_dev *sm750_dev, struct pci_dev *pdev);
+int hw_sm750_inithw(struct sm750_dev *sm750_dev, struct pci_dev *pdev);
+void hw_sm750_initAccel(struct sm750_dev *sm750_dev);
+int hw_sm750_deWait(void);
+int hw_sm750le_deWait(void);
+
+int hw_sm750_output_setMode(struct lynxfb_output *output,
+ struct fb_var_screeninfo *var,
+ struct fb_fix_screeninfo *fix);
+
+int hw_sm750_crtc_checkMode(struct lynxfb_crtc *crtc,
+ struct fb_var_screeninfo *var);
+
+int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc,
+ struct fb_var_screeninfo *var,
+ struct fb_fix_screeninfo *fix);
+
+int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index,
+ ushort red, ushort green, ushort blue);
+
+int hw_sm750_setBLANK(struct lynxfb_output *output, int blank);
+int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank);
+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/staging/sm750fb/sm750_accel.c b/drivers/staging/sm750fb/sm750_accel.c
new file mode 100644
index 000000000..24b9077a6
--- /dev/null
+++ b/drivers/staging/sm750fb/sm750_accel.c
@@ -0,0 +1,414 @@
+// SPDX-License-Identifier: GPL-2.0
+#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>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+
+#include "sm750.h"
+#include "sm750_accel.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 sm750_hw_de_init(struct lynx_accel *accel)
+{
+ /* setup 2d engine registers */
+ u32 reg, clr;
+
+ write_dpr(accel, DE_MASKS, 0xFFFFFFFF);
+
+ /* dpr1c */
+ reg = 0x3;
+
+ clr = DE_STRETCH_FORMAT_PATTERN_XY |
+ DE_STRETCH_FORMAT_PATTERN_Y_MASK |
+ DE_STRETCH_FORMAT_PATTERN_X_MASK |
+ DE_STRETCH_FORMAT_ADDRESSING_MASK |
+ DE_STRETCH_FORMAT_SOURCE_HEIGHT_MASK;
+
+ /* DE_STRETCH bpp format need be initialized 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); /* dpr2c */
+ write_dpr(accel, DE_CLIP_BR, 0); /* dpr30 */
+
+ write_dpr(accel, DE_COLOR_COMPARE_MASK, 0); /* dpr24 */
+ write_dpr(accel, DE_COLOR_COMPARE, 0);
+
+ clr = DE_CONTROL_TRANSPARENCY | DE_CONTROL_TRANSPARENCY_MATCH |
+ DE_CONTROL_TRANSPARENCY_SELECT;
+
+ /* dpr0c */
+ write_dpr(accel, DE_CONTROL, read_dpr(accel, DE_CONTROL) & ~clr);
+}
+
+/*
+ * set2dformat only be called from setmode functions
+ * but if you need dual framebuffer driver,need call set2dformat
+ * every time you use 2d function
+ */
+
+void sm750_hw_set2dformat(struct lynx_accel *accel, int fmt)
+{
+ u32 reg;
+
+ /* fmt=0,1,2 for 8,16,32,bpp on sm718/750/502 */
+ reg = read_dpr(accel, DE_STRETCH_FORMAT);
+ reg &= ~DE_STRETCH_FORMAT_PIXEL_FORMAT_MASK;
+ reg |= ((fmt << DE_STRETCH_FORMAT_PIXEL_FORMAT_SHIFT) &
+ DE_STRETCH_FORMAT_PIXEL_FORMAT_MASK);
+ write_dpr(accel, DE_STRETCH_FORMAT, reg);
+}
+
+int sm750_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
+ */
+ pr_debug("De engine always busy\n");
+ return -1;
+ }
+
+ write_dpr(accel, DE_WINDOW_DESTINATION_BASE, base); /* dpr40 */
+ write_dpr(accel, DE_PITCH,
+ ((pitch / Bpp << DE_PITCH_DESTINATION_SHIFT) &
+ DE_PITCH_DESTINATION_MASK) |
+ (pitch / Bpp & DE_PITCH_SOURCE_MASK)); /* dpr10 */
+
+ write_dpr(accel, DE_WINDOW_WIDTH,
+ ((pitch / Bpp << DE_WINDOW_WIDTH_DST_SHIFT) &
+ DE_WINDOW_WIDTH_DST_MASK) |
+ (pitch / Bpp & DE_WINDOW_WIDTH_SRC_MASK)); /* dpr44 */
+
+ write_dpr(accel, DE_FOREGROUND, color); /* DPR14 */
+
+ write_dpr(accel, DE_DESTINATION,
+ ((x << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
+ (y & DE_DESTINATION_Y_MASK)); /* dpr4 */
+
+ write_dpr(accel, DE_DIMENSION,
+ ((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
+ (height & DE_DIMENSION_Y_ET_MASK)); /* dpr8 */
+
+ deCtrl = DE_CONTROL_STATUS | DE_CONTROL_LAST_PIXEL |
+ DE_CONTROL_COMMAND_RECTANGLE_FILL | DE_CONTROL_ROP_SELECT |
+ (rop & DE_CONTROL_ROP_MASK); /* dpr0xc */
+
+ write_dpr(accel, DE_CONTROL, deCtrl);
+ return 0;
+}
+
+/**
+ * sm750_hw_copyarea
+ * @accel: Acceleration device data
+ * @sBase: Address of source: offset in frame buffer
+ * @sPitch: Pitch value of source surface in BYTE
+ * @sx: Starting x coordinate of source surface
+ * @sy: Starting y coordinate of source surface
+ * @dBase: Address of destination: offset in frame buffer
+ * @dPitch: Pitch value of destination surface in BYTE
+ * @Bpp: Color depth of destination surface
+ * @dx: Starting x coordinate of destination surface
+ * @dy: Starting y coordinate of destination surface
+ * @width: width of rectangle in pixel value
+ * @height: height of rectangle in pixel value
+ * @rop2: ROP value
+ */
+int sm750_hw_copyarea(struct lynx_accel *accel,
+ unsigned int sBase, unsigned int sPitch,
+ unsigned int sx, unsigned int sy,
+ unsigned int dBase, unsigned int dPitch,
+ unsigned int Bpp, unsigned int dx, unsigned int dy,
+ unsigned int width, unsigned int height,
+ unsigned int rop2)
+{
+ unsigned int nDirection, de_ctrl;
+
+ nDirection = LEFT_TO_RIGHT;
+ /* Direction of ROP2 operation: 1 = Left to Right, (-1) = Right to Left */
+ 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;
+ }
+
+ /*
+ * Note:
+ * DE_FOREGROUND and 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); /* dpr40 */
+
+ /*
+ * 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); /* dpr44 */
+
+ /*
+ * Program pitch (distance between the 1st points of two adjacent lines).
+ * Note that input pitch is BYTE value, but the 2D Pitch register uses
+ * pixel values. Need Byte to pixel conversion.
+ */
+ write_dpr(accel, DE_PITCH,
+ ((dPitch / Bpp << DE_PITCH_DESTINATION_SHIFT) &
+ DE_PITCH_DESTINATION_MASK) |
+ (sPitch / Bpp & DE_PITCH_SOURCE_MASK)); /* dpr10 */
+
+ /*
+ * 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_DST_SHIFT) &
+ DE_WINDOW_WIDTH_DST_MASK) |
+ (sPitch / Bpp & DE_WINDOW_WIDTH_SRC_MASK)); /* dpr3c */
+
+ if (accel->de_wait() != 0)
+ return -1;
+
+ write_dpr(accel, DE_SOURCE,
+ ((sx << DE_SOURCE_X_K1_SHIFT) & DE_SOURCE_X_K1_MASK) |
+ (sy & DE_SOURCE_Y_K2_MASK)); /* dpr0 */
+ write_dpr(accel, DE_DESTINATION,
+ ((dx << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
+ (dy & DE_DESTINATION_Y_MASK)); /* dpr04 */
+ write_dpr(accel, DE_DIMENSION,
+ ((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
+ (height & DE_DIMENSION_Y_ET_MASK)); /* dpr08 */
+
+ de_ctrl = (rop2 & DE_CONTROL_ROP_MASK) | DE_CONTROL_ROP_SELECT |
+ ((nDirection == RIGHT_TO_LEFT) ? DE_CONTROL_DIRECTION : 0) |
+ DE_CONTROL_COMMAND_BITBLT | DE_CONTROL_STATUS;
+ write_dpr(accel, DE_CONTROL, de_ctrl); /* dpr0c */
+
+ return 0;
+}
+
+static unsigned int deGetTransparency(struct lynx_accel *accel)
+{
+ unsigned int de_ctrl;
+
+ de_ctrl = read_dpr(accel, DE_CONTROL);
+
+ de_ctrl &= (DE_CONTROL_TRANSPARENCY_MATCH |
+ DE_CONTROL_TRANSPARENCY_SELECT | DE_CONTROL_TRANSPARENCY);
+
+ return de_ctrl;
+}
+
+/**
+ * sm750_hw_imageblit
+ * @accel: Acceleration device data
+ * @pSrcbuf: pointer to start of source buffer in system memory
+ * @srcDelta: Pitch value (in bytes) of the source buffer, +ive means top down
+ * and -ive mean button up
+ * @startBit: Mono data can start at any bit in a byte, this value should be
+ * 0 to 7
+ * @dBase: Address of destination: offset in frame buffer
+ * @dPitch: Pitch value of destination surface in BYTE
+ * @bytePerPixel: Color depth of destination surface
+ * @dx: Starting x coordinate of destination surface
+ * @dy: Starting y coordinate of destination surface
+ * @width: width of rectangle in pixel value
+ * @height: height of rectangle in pixel value
+ * @fColor: Foreground color (corresponding to a 1 in the monochrome data
+ * @bColor: Background color (corresponding to a 0 in the monochrome data
+ * @rop2: ROP value
+ */
+int sm750_hw_imageblit(struct lynx_accel *accel, const char *pSrcbuf,
+ u32 srcDelta, u32 startBit, u32 dBase, u32 dPitch,
+ u32 bytePerPixel, u32 dx, u32 dy, u32 width,
+ u32 height, u32 fColor, u32 bColor, u32 rop2)
+{
+ 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)
+ 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);
+
+ /*
+ * Program pitch (distance between the 1st points of two adjacent
+ * lines). Note that input pitch is BYTE value, but the 2D Pitch
+ * register uses pixel values. Need Byte to pixel conversion.
+ */
+ write_dpr(accel, DE_PITCH,
+ ((dPitch / bytePerPixel << DE_PITCH_DESTINATION_SHIFT) &
+ DE_PITCH_DESTINATION_MASK) |
+ (dPitch / bytePerPixel & DE_PITCH_SOURCE_MASK)); /* dpr10 */
+
+ /*
+ * 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_DST_SHIFT) &
+ DE_WINDOW_WIDTH_DST_MASK) |
+ (dPitch / bytePerPixel & DE_WINDOW_WIDTH_SRC_MASK));
+
+ /*
+ * 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_SHIFT) &
+ DE_SOURCE_X_K1_MONO_MASK); /* dpr00 */
+
+ write_dpr(accel, DE_DESTINATION,
+ ((dx << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
+ (dy & DE_DESTINATION_Y_MASK)); /* dpr04 */
+
+ write_dpr(accel, DE_DIMENSION,
+ ((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
+ (height & DE_DIMENSION_Y_ET_MASK)); /* dpr08 */
+
+ write_dpr(accel, DE_FOREGROUND, fColor);
+ write_dpr(accel, DE_BACKGROUND, bColor);
+
+ de_ctrl = (rop2 & DE_CONTROL_ROP_MASK) |
+ DE_CONTROL_ROP_SELECT | DE_CONTROL_COMMAND_HOST_WRITE |
+ DE_CONTROL_HOST | DE_CONTROL_STATUS;
+
+ 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/staging/sm750fb/sm750_accel.h b/drivers/staging/sm750fb/sm750_accel.h
new file mode 100644
index 000000000..2c79cb730
--- /dev/null
+++ b/drivers/staging/sm750fb/sm750_accel.h
@@ -0,0 +1,243 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#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 0x0
+#define DE_SOURCE_WRAP BIT(31)
+#define DE_SOURCE_X_K1_SHIFT 16
+#define DE_SOURCE_X_K1_MASK (0x3fff << 16)
+#define DE_SOURCE_X_K1_MONO_MASK (0x1f << 16)
+#define DE_SOURCE_Y_K2_MASK 0xffff
+
+#define DE_DESTINATION 0x4
+#define DE_DESTINATION_WRAP BIT(31)
+#define DE_DESTINATION_X_SHIFT 16
+#define DE_DESTINATION_X_MASK (0x1fff << 16)
+#define DE_DESTINATION_Y_MASK 0xffff
+
+#define DE_DIMENSION 0x8
+#define DE_DIMENSION_X_SHIFT 16
+#define DE_DIMENSION_X_MASK (0x1fff << 16)
+#define DE_DIMENSION_Y_ET_MASK 0x1fff
+
+#define DE_CONTROL 0xC
+#define DE_CONTROL_STATUS BIT(31)
+#define DE_CONTROL_PATTERN BIT(30)
+#define DE_CONTROL_UPDATE_DESTINATION_X BIT(29)
+#define DE_CONTROL_QUICK_START BIT(28)
+#define DE_CONTROL_DIRECTION BIT(27)
+#define DE_CONTROL_MAJOR BIT(26)
+#define DE_CONTROL_STEP_X BIT(25)
+#define DE_CONTROL_STEP_Y BIT(24)
+#define DE_CONTROL_STRETCH BIT(23)
+#define DE_CONTROL_HOST BIT(22)
+#define DE_CONTROL_LAST_PIXEL BIT(21)
+#define DE_CONTROL_COMMAND_SHIFT 16
+#define DE_CONTROL_COMMAND_MASK (0x1f << 16)
+#define DE_CONTROL_COMMAND_BITBLT (0x0 << 16)
+#define DE_CONTROL_COMMAND_RECTANGLE_FILL (0x1 << 16)
+#define DE_CONTROL_COMMAND_DE_TILE (0x2 << 16)
+#define DE_CONTROL_COMMAND_TRAPEZOID_FILL (0x3 << 16)
+#define DE_CONTROL_COMMAND_ALPHA_BLEND (0x4 << 16)
+#define DE_CONTROL_COMMAND_RLE_STRIP (0x5 << 16)
+#define DE_CONTROL_COMMAND_SHORT_STROKE (0x6 << 16)
+#define DE_CONTROL_COMMAND_LINE_DRAW (0x7 << 16)
+#define DE_CONTROL_COMMAND_HOST_WRITE (0x8 << 16)
+#define DE_CONTROL_COMMAND_HOST_READ (0x9 << 16)
+#define DE_CONTROL_COMMAND_HOST_WRITE_BOTTOM_UP (0xa << 16)
+#define DE_CONTROL_COMMAND_ROTATE (0xb << 16)
+#define DE_CONTROL_COMMAND_FONT (0xc << 16)
+#define DE_CONTROL_COMMAND_TEXTURE_LOAD (0xe << 16)
+#define DE_CONTROL_ROP_SELECT BIT(15)
+#define DE_CONTROL_ROP2_SOURCE BIT(14)
+#define DE_CONTROL_MONO_DATA_SHIFT 12
+#define DE_CONTROL_MONO_DATA_MASK (0x3 << 12)
+#define DE_CONTROL_MONO_DATA_NOT_PACKED (0x0 << 12)
+#define DE_CONTROL_MONO_DATA_8_PACKED (0x1 << 12)
+#define DE_CONTROL_MONO_DATA_16_PACKED (0x2 << 12)
+#define DE_CONTROL_MONO_DATA_32_PACKED (0x3 << 12)
+#define DE_CONTROL_REPEAT_ROTATE BIT(11)
+#define DE_CONTROL_TRANSPARENCY_MATCH BIT(10)
+#define DE_CONTROL_TRANSPARENCY_SELECT BIT(9)
+#define DE_CONTROL_TRANSPARENCY BIT(8)
+#define DE_CONTROL_ROP_MASK 0xff
+
+/* Pseudo fields. */
+
+#define DE_CONTROL_SHORT_STROKE_DIR_MASK (0xf << 24)
+#define DE_CONTROL_SHORT_STROKE_DIR_225 (0x0 << 24)
+#define DE_CONTROL_SHORT_STROKE_DIR_135 (0x1 << 24)
+#define DE_CONTROL_SHORT_STROKE_DIR_315 (0x2 << 24)
+#define DE_CONTROL_SHORT_STROKE_DIR_45 (0x3 << 24)
+#define DE_CONTROL_SHORT_STROKE_DIR_270 (0x4 << 24)
+#define DE_CONTROL_SHORT_STROKE_DIR_90 (0x5 << 24)
+#define DE_CONTROL_SHORT_STROKE_DIR_180 (0x8 << 24)
+#define DE_CONTROL_SHORT_STROKE_DIR_0 (0xa << 24)
+#define DE_CONTROL_ROTATION_MASK (0x3 << 24)
+#define DE_CONTROL_ROTATION_0 (0x0 << 24)
+#define DE_CONTROL_ROTATION_270 (0x1 << 24)
+#define DE_CONTROL_ROTATION_90 (0x2 << 24)
+#define DE_CONTROL_ROTATION_180 (0x3 << 24)
+
+#define DE_PITCH 0x000010
+#define DE_PITCH_DESTINATION_SHIFT 16
+#define DE_PITCH_DESTINATION_MASK (0x1fff << 16)
+#define DE_PITCH_SOURCE_MASK 0x1fff
+
+#define DE_FOREGROUND 0x000014
+#define DE_FOREGROUND_COLOR_MASK 0xffffffff
+
+#define DE_BACKGROUND 0x000018
+#define DE_BACKGROUND_COLOR_MASK 0xffffffff
+
+#define DE_STRETCH_FORMAT 0x00001C
+#define DE_STRETCH_FORMAT_PATTERN_XY BIT(30)
+#define DE_STRETCH_FORMAT_PATTERN_Y_SHIFT 27
+#define DE_STRETCH_FORMAT_PATTERN_Y_MASK (0x7 << 27)
+#define DE_STRETCH_FORMAT_PATTERN_X_SHIFT 23
+#define DE_STRETCH_FORMAT_PATTERN_X_MASK (0x7 << 23)
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_SHIFT 20
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_MASK (0x3 << 20)
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_8 (0x0 << 20)
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_16 (0x1 << 20)
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_32 (0x2 << 20)
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_24 (0x3 << 20)
+#define DE_STRETCH_FORMAT_ADDRESSING_SHIFT 16
+#define DE_STRETCH_FORMAT_ADDRESSING_MASK (0xf << 16)
+#define DE_STRETCH_FORMAT_ADDRESSING_XY (0x0 << 16)
+#define DE_STRETCH_FORMAT_ADDRESSING_LINEAR (0xf << 16)
+#define DE_STRETCH_FORMAT_SOURCE_HEIGHT_MASK 0xfff
+
+#define DE_COLOR_COMPARE 0x000020
+#define DE_COLOR_COMPARE_COLOR_MASK 0xffffff
+
+#define DE_COLOR_COMPARE_MASK 0x000024
+#define DE_COLOR_COMPARE_MASK_MASK 0xffffff
+
+#define DE_MASKS 0x000028
+#define DE_MASKS_BYTE_MASK (0xffff << 16)
+#define DE_MASKS_BIT_MASK 0xffff
+
+#define DE_CLIP_TL 0x00002C
+#define DE_CLIP_TL_TOP_MASK (0xffff << 16)
+#define DE_CLIP_TL_STATUS BIT(13)
+#define DE_CLIP_TL_INHIBIT BIT(12)
+#define DE_CLIP_TL_LEFT_MASK 0xfff
+
+#define DE_CLIP_BR 0x000030
+#define DE_CLIP_BR_BOTTOM_MASK (0xffff << 16)
+#define DE_CLIP_BR_RIGHT_MASK 0x1fff
+
+#define DE_MONO_PATTERN_LOW 0x000034
+#define DE_MONO_PATTERN_LOW_PATTERN_MASK 0xffffffff
+
+#define DE_MONO_PATTERN_HIGH 0x000038
+#define DE_MONO_PATTERN_HIGH_PATTERN_MASK 0xffffffff
+
+#define DE_WINDOW_WIDTH 0x00003C
+#define DE_WINDOW_WIDTH_DST_SHIFT 16
+#define DE_WINDOW_WIDTH_DST_MASK (0x1fff << 16)
+#define DE_WINDOW_WIDTH_SRC_MASK 0x1fff
+
+#define DE_WINDOW_SOURCE_BASE 0x000040
+#define DE_WINDOW_SOURCE_BASE_EXT BIT(27)
+#define DE_WINDOW_SOURCE_BASE_CS BIT(26)
+#define DE_WINDOW_SOURCE_BASE_ADDRESS_MASK 0x3ffffff
+
+#define DE_WINDOW_DESTINATION_BASE 0x000044
+#define DE_WINDOW_DESTINATION_BASE_EXT BIT(27)
+#define DE_WINDOW_DESTINATION_BASE_CS BIT(26)
+#define DE_WINDOW_DESTINATION_BASE_ADDRESS_MASK 0x3ffffff
+
+#define DE_ALPHA 0x000048
+#define DE_ALPHA_VALUE_MASK 0xff
+
+#define DE_WRAP 0x00004C
+#define DE_WRAP_X_MASK (0xffff << 16)
+#define DE_WRAP_Y_MASK 0xffff
+
+#define DE_STATUS 0x000050
+#define DE_STATUS_CSC BIT(1)
+#define DE_STATUS_2D BIT(0)
+
+/* blt direction */
+#define TOP_TO_BOTTOM 0
+#define LEFT_TO_RIGHT 0
+#define BOTTOM_TO_TOP 1
+#define RIGHT_TO_LEFT 1
+
+void sm750_hw_set2dformat(struct lynx_accel *accel, int fmt);
+
+void sm750_hw_de_init(struct lynx_accel *accel);
+
+int sm750_hw_fillrect(struct lynx_accel *accel,
+ u32 base, u32 pitch, u32 Bpp,
+ u32 x, u32 y, u32 width, u32 height,
+ u32 color, u32 rop);
+
+/**
+ * sm750_hm_copyarea
+ * @sBase: Address of source: offset in frame buffer
+ * @sPitch: Pitch value of source surface in BYTE
+ * @sx: Starting x coordinate of source surface
+ * @sy: Starting y coordinate of source surface
+ * @dBase: Address of destination: offset in frame buffer
+ * @dPitch: Pitch value of destination surface in BYTE
+ * @Bpp: Color depth of destination surface
+ * @dx: Starting x coordinate of destination surface
+ * @dy: Starting y coordinate of destination surface
+ * @width: width of rectangle in pixel value
+ * @height: height of rectangle in pixel value
+ * @rop2: ROP value
+ */
+int sm750_hw_copyarea(struct lynx_accel *accel,
+ unsigned int sBase, unsigned int sPitch,
+ unsigned int sx, unsigned int sy,
+ unsigned int dBase, unsigned int dPitch,
+ unsigned int Bpp, unsigned int dx, unsigned int dy,
+ unsigned int width, unsigned int height,
+ unsigned int rop2);
+
+/**
+ * sm750_hw_imageblit
+ * @pSrcbuf: pointer to start of source buffer in system memory
+ * @srcDelta: Pitch value (in bytes) of the source buffer, +ive means top down
+ *>----- and -ive mean button up
+ * @startBit: Mono data can start at any bit in a byte, this value should be
+ *>----- 0 to 7
+ * @dBase: Address of destination: offset in frame buffer
+ * @dPitch: Pitch value of destination surface in BYTE
+ * @bytePerPixel: Color depth of destination surface
+ * @dx: Starting x coordinate of destination surface
+ * @dy: Starting y coordinate of destination surface
+ * @width: width of rectangle in pixel value
+ * @height: height of rectangle in pixel value
+ * @fColor: Foreground color (corresponding to a 1 in the monochrome data
+ * @bColor: Background color (corresponding to a 0 in the monochrome data
+ * @rop2: ROP value
+ */
+int sm750_hw_imageblit(struct lynx_accel *accel, const char *pSrcbuf,
+ u32 srcDelta, u32 startBit, u32 dBase, u32 dPitch,
+ u32 bytePerPixel, u32 dx, u32 dy, u32 width,
+ u32 height, u32 fColor, u32 bColor, u32 rop2);
+
+#endif
diff --git a/drivers/staging/sm750fb/sm750_cursor.c b/drivers/staging/sm750fb/sm750_cursor.c
new file mode 100644
index 000000000..43e6f52c2
--- /dev/null
+++ b/drivers/staging/sm750fb/sm750_cursor.c
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0
+#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>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+
+#include "sm750.h"
+#include "sm750_cursor.h"
+
+#define poke32(addr, data) \
+writel((data), cursor->mmio + (addr))
+
+/* cursor control for voyager and 718/750*/
+#define HWC_ADDRESS 0x0
+#define HWC_ADDRESS_ENABLE BIT(31)
+#define HWC_ADDRESS_EXT BIT(27)
+#define HWC_ADDRESS_CS BIT(26)
+#define HWC_ADDRESS_ADDRESS_MASK 0x3ffffff
+
+#define HWC_LOCATION 0x4
+#define HWC_LOCATION_TOP BIT(27)
+#define HWC_LOCATION_Y_SHIFT 16
+#define HWC_LOCATION_Y_MASK (0x7ff << 16)
+#define HWC_LOCATION_LEFT BIT(11)
+#define HWC_LOCATION_X_MASK 0x7ff
+
+#define HWC_COLOR_12 0x8
+#define HWC_COLOR_12_2_RGB565_SHIFT 16
+#define HWC_COLOR_12_2_RGB565_MASK (0xffff << 16)
+#define HWC_COLOR_12_1_RGB565_MASK 0xffff
+
+#define HWC_COLOR_3 0xC
+#define HWC_COLOR_3_RGB565_MASK 0xffff
+
+/* hw_cursor_xxx works for voyager,718 and 750 */
+void sm750_hw_cursor_enable(struct lynx_cursor *cursor)
+{
+ u32 reg;
+
+ reg = (cursor->offset & HWC_ADDRESS_ADDRESS_MASK) | HWC_ADDRESS_ENABLE;
+ poke32(HWC_ADDRESS, reg);
+}
+
+void sm750_hw_cursor_disable(struct lynx_cursor *cursor)
+{
+ poke32(HWC_ADDRESS, 0);
+}
+
+void sm750_hw_cursor_setSize(struct lynx_cursor *cursor, int w, int h)
+{
+ cursor->w = w;
+ cursor->h = h;
+}
+
+void sm750_hw_cursor_setPos(struct lynx_cursor *cursor, int x, int y)
+{
+ u32 reg;
+
+ reg = ((y << HWC_LOCATION_Y_SHIFT) & HWC_LOCATION_Y_MASK) |
+ (x & HWC_LOCATION_X_MASK);
+ poke32(HWC_LOCATION, reg);
+}
+
+void sm750_hw_cursor_setColor(struct lynx_cursor *cursor, u32 fg, u32 bg)
+{
+ u32 reg = (fg << HWC_COLOR_12_2_RGB565_SHIFT) &
+ HWC_COLOR_12_2_RGB565_MASK;
+
+ poke32(HWC_COLOR_12, reg | (bg & HWC_COLOR_12_1_RGB565_MASK));
+ poke32(HWC_COLOR_3, 0xffe0);
+}
+
+void sm750_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;
+ void __iomem *pbuffer, *pstart;
+
+ /* in byte*/
+ pitch = cursor->w >> 3;
+
+ /* in byte */
+ count = pitch * cursor->h;
+
+ /* in byte */
+ offset = cursor->max_w * 2 / 8;
+
+ data = 0;
+ pstart = cursor->vstart;
+ pbuffer = pstart;
+
+ for (i = 0; i < count; i++) {
+ color = *pcol++;
+ mask = *pmsk++;
+ data = 0;
+
+ 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);
+ }
+ }
+ iowrite16(data, pbuffer);
+
+ /* assume pitch is 1,2,4,8,...*/
+ if ((i + 1) % pitch == 0) {
+ /* need a return */
+ pstart += offset;
+ pbuffer = pstart;
+ } else {
+ pbuffer += sizeof(u16);
+ }
+ }
+}
+
+void sm750_hw_cursor_setData2(struct lynx_cursor *cursor, u16 rop,
+ const u8 *pcol, const u8 *pmsk)
+{
+ int i, j, count, pitch, offset;
+ u8 color, mask;
+ u16 data;
+ void __iomem *pbuffer, *pstart;
+
+ /* in byte*/
+ pitch = cursor->w >> 3;
+
+ /* in byte */
+ count = pitch * cursor->h;
+
+ /* in byte */
+ offset = cursor->max_w * 2 / 8;
+
+ data = 0;
+ pstart = cursor->vstart;
+ pbuffer = pstart;
+
+ for (i = 0; i < count; i++) {
+ color = *pcol++;
+ mask = *pmsk++;
+ data = 0;
+
+ for (j = 0; j < 8; j++) {
+ if (mask & (1 << j))
+ data |= ((color & (1 << j)) ? 1 : 2) << (j * 2);
+ }
+ iowrite16(data, pbuffer);
+
+ /* assume pitch is 1,2,4,8,...*/
+ if (!(i & (pitch - 1))) {
+ /* need a return */
+ pstart += offset;
+ pbuffer = pstart;
+ } else {
+ pbuffer += sizeof(u16);
+ }
+ }
+}
diff --git a/drivers/staging/sm750fb/sm750_cursor.h b/drivers/staging/sm750fb/sm750_cursor.h
new file mode 100644
index 000000000..b59643dd6
--- /dev/null
+++ b/drivers/staging/sm750fb/sm750_cursor.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef LYNX_CURSOR_H__
+#define LYNX_CURSOR_H__
+
+/* hw_cursor_xxx works for voyager,718 and 750 */
+void sm750_hw_cursor_enable(struct lynx_cursor *cursor);
+void sm750_hw_cursor_disable(struct lynx_cursor *cursor);
+void sm750_hw_cursor_setSize(struct lynx_cursor *cursor, int w, int h);
+void sm750_hw_cursor_setPos(struct lynx_cursor *cursor, int x, int y);
+void sm750_hw_cursor_setColor(struct lynx_cursor *cursor, u32 fg, u32 bg);
+void sm750_hw_cursor_setData(struct lynx_cursor *cursor, u16 rop,
+ const u8 *data, const u8 *mask);
+void sm750_hw_cursor_setData2(struct lynx_cursor *cursor, u16 rop,
+ const u8 *data, const u8 *mask);
+#endif
diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c
new file mode 100644
index 000000000..55cb00e8b
--- /dev/null
+++ b/drivers/staging/sm750fb/sm750_hw.c
@@ -0,0 +1,569 @@
+// SPDX-License-Identifier: GPL-2.0
+#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
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+#include <linux/sizes.h>
+
+#include "sm750.h"
+#include "ddk750.h"
+#include "sm750_accel.h"
+
+void __iomem *mmio750;
+
+int hw_sm750_map(struct sm750_dev *sm750_dev, struct pci_dev *pdev)
+{
+ int ret;
+
+ ret = 0;
+
+ sm750_dev->vidreg_start = pci_resource_start(pdev, 1);
+ sm750_dev->vidreg_size = SZ_2M;
+
+ pr_info("mmio phyAddr = %lx\n", sm750_dev->vidreg_start);
+
+ /*
+ * reserve the vidreg space of smi adaptor
+ * if you do this, you need to add release region code
+ * in lynxfb_remove, or memory will not be mapped again
+ * successfully
+ */
+ ret = pci_request_region(pdev, 1, "sm750fb");
+ if (ret) {
+ pr_err("Can not request PCI regions.\n");
+ goto exit;
+ }
+
+ /* now map mmio and vidmem */
+ sm750_dev->pvReg =
+ ioremap(sm750_dev->vidreg_start, sm750_dev->vidreg_size);
+ if (!sm750_dev->pvReg) {
+ pr_err("mmio failed\n");
+ ret = -EFAULT;
+ goto exit;
+ } else {
+ pr_info("mmio virtual addr = %p\n", sm750_dev->pvReg);
+ }
+
+ sm750_dev->accel.dprBase = sm750_dev->pvReg + DE_BASE_ADDR_TYPE1;
+ sm750_dev->accel.dpPortBase = sm750_dev->pvReg + DE_PORT_ADDR_TYPE1;
+
+ mmio750 = sm750_dev->pvReg;
+ sm750_set_chip_type(sm750_dev->devid, sm750_dev->revid);
+
+ sm750_dev->vidmem_start = pci_resource_start(pdev, 0);
+ /*
+ * don't use pdev_resource[x].end - resource[x].start to
+ * calculate the resource size, it's only the maximum available
+ * size but not the actual size, using
+ * @ddk750_get_vm_size function can be safe.
+ */
+ sm750_dev->vidmem_size = ddk750_get_vm_size();
+ pr_info("video memory phyAddr = %lx, size = %u bytes\n",
+ sm750_dev->vidmem_start, sm750_dev->vidmem_size);
+
+ /* reserve the vidmem space of smi adaptor */
+ sm750_dev->pvMem =
+ ioremap_wc(sm750_dev->vidmem_start, sm750_dev->vidmem_size);
+ if (!sm750_dev->pvMem) {
+ iounmap(sm750_dev->pvReg);
+ pr_err("Map video memory failed\n");
+ ret = -EFAULT;
+ goto exit;
+ } else {
+ pr_info("video memory vaddr = %p\n", sm750_dev->pvMem);
+ }
+exit:
+ return ret;
+}
+
+int hw_sm750_inithw(struct sm750_dev *sm750_dev, struct pci_dev *pdev)
+{
+ struct init_status *parm;
+
+ parm = &sm750_dev->initParm;
+ if (parm->chip_clk == 0)
+ parm->chip_clk = (sm750_get_chip_type() == 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_init_hw((struct initchip_param *)&sm750_dev->initParm);
+ /* for sm718, open pci burst */
+ if (sm750_dev->devid == 0x718) {
+ poke32(SYSTEM_CTRL,
+ peek32(SYSTEM_CTRL) | SYSTEM_CTRL_PCI_BURST);
+ }
+
+ if (sm750_get_chip_type() != SM750LE) {
+ unsigned int val;
+ /* does user need CRT? */
+ if (sm750_dev->nocrt) {
+ poke32(MISC_CTRL,
+ peek32(MISC_CTRL) | MISC_CTRL_DAC_POWER_OFF);
+ /* shut off dpms */
+ val = peek32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
+ val |= SYSTEM_CTRL_DPMS_VPHN;
+ poke32(SYSTEM_CTRL, val);
+ } else {
+ poke32(MISC_CTRL,
+ peek32(MISC_CTRL) & ~MISC_CTRL_DAC_POWER_OFF);
+ /* turn on dpms */
+ val = peek32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
+ val |= SYSTEM_CTRL_DPMS_VPHP;
+ poke32(SYSTEM_CTRL, val);
+ }
+
+ val = peek32(PANEL_DISPLAY_CTRL) &
+ ~(PANEL_DISPLAY_CTRL_DUAL_DISPLAY |
+ PANEL_DISPLAY_CTRL_DOUBLE_PIXEL);
+ switch (sm750_dev->pnltype) {
+ case sm750_24TFT:
+ break;
+ case sm750_doubleTFT:
+ val |= PANEL_DISPLAY_CTRL_DOUBLE_PIXEL;
+ break;
+ case sm750_dualTFT:
+ val |= PANEL_DISPLAY_CTRL_DUAL_DISPLAY;
+ break;
+ }
+ poke32(PANEL_DISPLAY_CTRL, val);
+ } else {
+ /*
+ * for 750LE, no DVI chip initialization
+ * 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.
+ */
+ sm750_sw_i2c_init(0, 1);
+
+ /*
+ * Customer may NOT use CH7301 DVI chip, which has to be
+ * initialized differently.
+ */
+ if (sm750_sw_i2c_read_reg(0xec, 0x4a) == 0x95) {
+ /*
+ * The following register values for CH7301 are from
+ * Chrontel app note and our experiment.
+ */
+ pr_info("yes,CH7301 DVI chip found\n");
+ sm750_sw_i2c_write_reg(0xec, 0x1d, 0x16);
+ sm750_sw_i2c_write_reg(0xec, 0x21, 0x9);
+ sm750_sw_i2c_write_reg(0xec, 0x49, 0xC0);
+ pr_info("okay,CH7301 DVI chip setup done\n");
+ }
+ }
+
+ /* init 2d engine */
+ if (!sm750_dev->accel_off)
+ hw_sm750_initAccel(sm750_dev);
+
+ return 0;
+}
+
+int hw_sm750_output_setMode(struct lynxfb_output *output,
+ struct fb_var_screeninfo *var,
+ struct fb_fix_screeninfo *fix)
+{
+ int ret;
+ enum disp_output disp_set;
+ int channel;
+
+ ret = 0;
+ disp_set = 0;
+ channel = *output->channel;
+
+ if (sm750_get_chip_type() != SM750LE) {
+ if (channel == sm750_primary) {
+ pr_info("primary channel\n");
+ if (output->paths & sm750_panel)
+ disp_set |= do_LCD1_PRI;
+ if (output->paths & sm750_crt)
+ disp_set |= do_CRT_PRI;
+
+ } else {
+ pr_info("secondary channel\n");
+ if (output->paths & sm750_panel)
+ disp_set |= do_LCD1_SEC;
+ if (output->paths & sm750_crt)
+ disp_set |= do_CRT_SEC;
+ }
+ ddk750_set_logical_disp_out(disp_set);
+ } else {
+ /* just open DISPLAY_CONTROL_750LE register bit 3:0 */
+ u32 reg;
+
+ reg = peek32(DISPLAY_CONTROL_750LE);
+ reg |= 0xf;
+ poke32(DISPLAY_CONTROL_750LE, reg);
+ }
+
+ pr_info("ddk setlogicdispout done\n");
+ return ret;
+}
+
+int hw_sm750_crtc_checkMode(struct lynxfb_crtc *crtc,
+ struct fb_var_screeninfo *var)
+{
+ struct sm750_dev *sm750_dev;
+ struct lynxfb_par *par = container_of(crtc, struct lynxfb_par, crtc);
+
+ sm750_dev = par->dev;
+
+ switch (var->bits_per_pixel) {
+ case 8:
+ case 16:
+ break;
+ case 32:
+ if (sm750_dev->revid == SM750LE_REVISION_ID) {
+ pr_debug("750le do not support 32bpp\n");
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 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;
+ struct mode_parameter modparm;
+ enum clock_type clock;
+ struct sm750_dev *sm750_dev;
+ struct lynxfb_par *par;
+
+ ret = 0;
+ par = container_of(crtc, struct lynxfb_par, crtc);
+ sm750_dev = par->dev;
+
+ if (!sm750_dev->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;
+ }
+ sm750_hw_set2dformat(&sm750_dev->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;
+
+ pr_debug("Request pixel clock = %lu\n", modparm.pixel_clock);
+ ret = ddk750_setModeTiming(&modparm, clock);
+ if (ret) {
+ pr_err("Set mode timing failed\n");
+ goto exit;
+ }
+
+ if (crtc->channel != sm750_secondary) {
+ /* set pitch, offset, width, start address, etc... */
+ poke32(PANEL_FB_ADDRESS,
+ crtc->o_screen & PANEL_FB_ADDRESS_ADDRESS_MASK);
+
+ reg = var->xres * (var->bits_per_pixel >> 3);
+ /*
+ * crtc->channel is not equal to par->index on numeric,
+ * be aware of that
+ */
+ reg = ALIGN(reg, crtc->line_pad);
+ reg = (reg << PANEL_FB_WIDTH_WIDTH_SHIFT) &
+ PANEL_FB_WIDTH_WIDTH_MASK;
+ reg |= (fix->line_length & PANEL_FB_WIDTH_OFFSET_MASK);
+ poke32(PANEL_FB_WIDTH, reg);
+
+ reg = ((var->xres - 1) << PANEL_WINDOW_WIDTH_WIDTH_SHIFT) &
+ PANEL_WINDOW_WIDTH_WIDTH_MASK;
+ reg |= (var->xoffset & PANEL_WINDOW_WIDTH_X_MASK);
+ poke32(PANEL_WINDOW_WIDTH, reg);
+
+ reg = (var->yres_virtual - 1)
+ << PANEL_WINDOW_HEIGHT_HEIGHT_SHIFT;
+ reg &= PANEL_WINDOW_HEIGHT_HEIGHT_MASK;
+ reg |= (var->yoffset & PANEL_WINDOW_HEIGHT_Y_MASK);
+ poke32(PANEL_WINDOW_HEIGHT, reg);
+
+ poke32(PANEL_PLANE_TL, 0);
+
+ reg = ((var->yres - 1) << PANEL_PLANE_BR_BOTTOM_SHIFT) &
+ PANEL_PLANE_BR_BOTTOM_MASK;
+ reg |= ((var->xres - 1) & PANEL_PLANE_BR_RIGHT_MASK);
+ poke32(PANEL_PLANE_BR, reg);
+
+ /* set pixel format */
+ reg = peek32(PANEL_DISPLAY_CTRL);
+ poke32(PANEL_DISPLAY_CTRL, reg | (var->bits_per_pixel >> 4));
+ } else {
+ /* not implemented now */
+ poke32(CRT_FB_ADDRESS, crtc->o_screen);
+ reg = var->xres * (var->bits_per_pixel >> 3);
+ /*
+ * crtc->channel is not equal to par->index on numeric,
+ * be aware of that
+ */
+ reg = ALIGN(reg, crtc->line_pad) << CRT_FB_WIDTH_WIDTH_SHIFT;
+ reg &= CRT_FB_WIDTH_WIDTH_MASK;
+ reg |= (fix->line_length & CRT_FB_WIDTH_OFFSET_MASK);
+ poke32(CRT_FB_WIDTH, reg);
+
+ /* SET PIXEL FORMAT */
+ reg = peek32(CRT_DISPLAY_CTRL);
+ reg |= ((var->bits_per_pixel >> 4) &
+ CRT_DISPLAY_CTRL_FORMAT_MASK);
+ poke32(CRT_DISPLAY_CTRL, reg);
+ }
+
+exit:
+ return ret;
+}
+
+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;
+
+ switch (blank) {
+ case FB_BLANK_UNBLANK:
+ dpms = CRT_DISPLAY_CTRL_DPMS_0;
+ crtdb = 0;
+ break;
+ case FB_BLANK_NORMAL:
+ dpms = CRT_DISPLAY_CTRL_DPMS_0;
+ crtdb = CRT_DISPLAY_CTRL_BLANK;
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ dpms = CRT_DISPLAY_CTRL_DPMS_2;
+ crtdb = CRT_DISPLAY_CTRL_BLANK;
+ break;
+ case FB_BLANK_HSYNC_SUSPEND:
+ dpms = CRT_DISPLAY_CTRL_DPMS_1;
+ crtdb = CRT_DISPLAY_CTRL_BLANK;
+ break;
+ case FB_BLANK_POWERDOWN:
+ dpms = CRT_DISPLAY_CTRL_DPMS_3;
+ crtdb = CRT_DISPLAY_CTRL_BLANK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (output->paths & sm750_crt) {
+ unsigned int val;
+
+ val = peek32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_DPMS_MASK;
+ poke32(CRT_DISPLAY_CTRL, val | dpms);
+
+ val = peek32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_BLANK;
+ poke32(CRT_DISPLAY_CTRL, val | crtdb);
+ }
+ return 0;
+}
+
+int hw_sm750_setBLANK(struct lynxfb_output *output, int blank)
+{
+ unsigned int dpms, pps, crtdb;
+
+ dpms = 0;
+ pps = 0;
+ crtdb = 0;
+
+ switch (blank) {
+ case FB_BLANK_UNBLANK:
+ pr_debug("flag = FB_BLANK_UNBLANK\n");
+ dpms = SYSTEM_CTRL_DPMS_VPHP;
+ pps = PANEL_DISPLAY_CTRL_DATA;
+ break;
+ case FB_BLANK_NORMAL:
+ pr_debug("flag = FB_BLANK_NORMAL\n");
+ dpms = SYSTEM_CTRL_DPMS_VPHP;
+ crtdb = CRT_DISPLAY_CTRL_BLANK;
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ dpms = SYSTEM_CTRL_DPMS_VNHP;
+ crtdb = CRT_DISPLAY_CTRL_BLANK;
+ break;
+ case FB_BLANK_HSYNC_SUSPEND:
+ dpms = SYSTEM_CTRL_DPMS_VPHN;
+ crtdb = CRT_DISPLAY_CTRL_BLANK;
+ break;
+ case FB_BLANK_POWERDOWN:
+ dpms = SYSTEM_CTRL_DPMS_VNHN;
+ crtdb = CRT_DISPLAY_CTRL_BLANK;
+ break;
+ }
+
+ if (output->paths & sm750_crt) {
+ unsigned int val = peek32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
+
+ poke32(SYSTEM_CTRL, val | dpms);
+
+ val = peek32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_BLANK;
+ poke32(CRT_DISPLAY_CTRL, val | crtdb);
+ }
+
+ if (output->paths & sm750_panel) {
+ unsigned int val = peek32(PANEL_DISPLAY_CTRL);
+
+ val &= ~PANEL_DISPLAY_CTRL_DATA;
+ val |= pps;
+ poke32(PANEL_DISPLAY_CTRL, val);
+ }
+
+ return 0;
+}
+
+void hw_sm750_initAccel(struct sm750_dev *sm750_dev)
+{
+ u32 reg;
+
+ sm750_enable_2d_engine(1);
+
+ if (sm750_get_chip_type() == SM750LE) {
+ reg = peek32(DE_STATE1);
+ reg |= DE_STATE1_DE_ABORT;
+ poke32(DE_STATE1, reg);
+
+ reg = peek32(DE_STATE1);
+ reg &= ~DE_STATE1_DE_ABORT;
+ poke32(DE_STATE1, reg);
+
+ } else {
+ /* engine reset */
+ reg = peek32(SYSTEM_CTRL);
+ reg |= SYSTEM_CTRL_DE_ABORT;
+ poke32(SYSTEM_CTRL, reg);
+
+ reg = peek32(SYSTEM_CTRL);
+ reg &= ~SYSTEM_CTRL_DE_ABORT;
+ poke32(SYSTEM_CTRL, reg);
+ }
+
+ /* call 2d init */
+ sm750_dev->accel.de_init(&sm750_dev->accel);
+}
+
+int hw_sm750le_deWait(void)
+{
+ int i = 0x10000000;
+ unsigned int mask = DE_STATE2_DE_STATUS_BUSY | DE_STATE2_DE_FIFO_EMPTY |
+ DE_STATE2_DE_MEM_FIFO_EMPTY;
+
+ while (i--) {
+ unsigned int val = peek32(DE_STATE2);
+
+ if ((val & mask) ==
+ (DE_STATE2_DE_FIFO_EMPTY | DE_STATE2_DE_MEM_FIFO_EMPTY))
+ return 0;
+ }
+ /* timeout error */
+ return -1;
+}
+
+int hw_sm750_deWait(void)
+{
+ int i = 0x10000000;
+ unsigned int mask = SYSTEM_CTRL_DE_STATUS_BUSY |
+ SYSTEM_CTRL_DE_FIFO_EMPTY |
+ SYSTEM_CTRL_DE_MEM_FIFO_EMPTY;
+
+ while (i--) {
+ unsigned int val = peek32(SYSTEM_CTRL);
+
+ if ((val & mask) ==
+ (SYSTEM_CTRL_DE_FIFO_EMPTY | 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)
+{
+ u32 total;
+ /* check params */
+ 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->o_screen;
+ if (crtc->channel == sm750_primary) {
+ poke32(PANEL_FB_ADDRESS,
+ peek32(PANEL_FB_ADDRESS) |
+ (total & PANEL_FB_ADDRESS_ADDRESS_MASK));
+ } else {
+ poke32(CRT_FB_ADDRESS,
+ peek32(CRT_FB_ADDRESS) |
+ (total & CRT_FB_ADDRESS_ADDRESS_MASK));
+ }
+ return 0;
+}