diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:49:45 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:49:45 +0000 |
commit | 2c3c1048746a4622d8c89a29670120dc8fab93c4 (patch) | |
tree | 848558de17fb3008cdf4d861b01ac7781903ce39 /drivers/staging/sm750fb | |
parent | Initial commit. (diff) | |
download | linux-2c3c1048746a4622d8c89a29670120dc8fab93c4.tar.xz linux-2c3c1048746a4622d8c89a29670120dc8fab93c4.zip |
Adding upstream version 6.1.76.upstream/6.1.76
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/staging/sm750fb')
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, ®) == 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; +} |