gma500: initial medfield merge
We need to merge this ahead of some of the cleanup because a lot of needed cleanup spans both new and old chips. If we try and clean up and the merge we end up fighting ourselves. Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> [With a load of the cleanup stuff folded in, register stuff reworked sanely] Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
parent
c6265ff593
commit
026abc3332
|
@ -28,6 +28,8 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/mfd/intel_msic.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c/tc35876x.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <asm/mpspec_def.h>
|
||||
|
@ -686,6 +688,19 @@ static void *msic_ocd_platform_data(void *info)
|
|||
return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_OCD);
|
||||
}
|
||||
|
||||
/* tc35876x DSI-LVDS bridge chip and panel platform data */
|
||||
static void *tc35876x_platform_data(void *data)
|
||||
{
|
||||
static struct tc35876x_platform_data pdata;
|
||||
|
||||
/* gpio pins set to -1 will not be used by the driver */
|
||||
pdata.gpio_bridge_reset = get_gpio_by_name("LCMB_RXEN");
|
||||
pdata.gpio_panel_bl_en = get_gpio_by_name("6S6P_BL_EN");
|
||||
pdata.gpio_panel_vadd = get_gpio_by_name("EN_VREG_LCD_V3P3");
|
||||
|
||||
return &pdata;
|
||||
}
|
||||
|
||||
static const struct devs_id __initconst device_ids[] = {
|
||||
{"bma023", SFI_DEV_TYPE_I2C, 1, &no_platform_data},
|
||||
{"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data},
|
||||
|
@ -698,6 +713,7 @@ static const struct devs_id __initconst device_ids[] = {
|
|||
{"i2c_accel", SFI_DEV_TYPE_I2C, 0, &lis331dl_platform_data},
|
||||
{"pmic_audio", SFI_DEV_TYPE_IPC, 1, &no_platform_data},
|
||||
{"mpu3050", SFI_DEV_TYPE_I2C, 1, &mpu3050_platform_data},
|
||||
{"i2c_disp_brig", SFI_DEV_TYPE_I2C, 0, &tc35876x_platform_data},
|
||||
|
||||
/* MSIC subdevices */
|
||||
{"msic_battery", SFI_DEV_TYPE_IPC, 1, &msic_battery_platform_data},
|
||||
|
|
|
@ -24,3 +24,10 @@ config DRM_GMA3600
|
|||
help
|
||||
Say yes to include basic support for Intel GMA3600/3650 (Intel
|
||||
Cedar Trail) platforms.
|
||||
|
||||
config DRM_MEDFIELD
|
||||
bool "Intel Medfield support (Experimental)"
|
||||
depends on DRM_GMA500 && X86_INTEL_MID
|
||||
help
|
||||
Say yes to include support for the Intel Medfield platform.
|
||||
|
||||
|
|
|
@ -37,4 +37,14 @@ gma500_gfx-$(CONFIG_DRM_GMA600) += oaktrail_device.o \
|
|||
oaktrail_hdmi.o \
|
||||
oaktrail_hdmi_i2c.o
|
||||
|
||||
gma500_gfx-$(CONFIG_DRM_MEDFIELD) += mdfld_device.o \
|
||||
mdfld_output.o \
|
||||
mdfld_intel_display.o \
|
||||
mdfld_dsi_output.o \
|
||||
mdfld_dsi_dpi.o \
|
||||
mdfld_dsi_pkg_sender.o \
|
||||
mdfld_tpo_vid.o \
|
||||
mdfld_tmd_vid.o \
|
||||
tc35876x-dsi-lvds.o
|
||||
|
||||
obj-$(CONFIG_DRM_GMA500) += gma500_gfx.o
|
||||
|
|
|
@ -0,0 +1,691 @@
|
|||
/**************************************************************************
|
||||
* Copyright (c) 2011, Intel Corporation.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#include "psb_drv.h"
|
||||
#include "mid_bios.h"
|
||||
#include "mdfld_output.h"
|
||||
#include "mdfld_dsi_output.h"
|
||||
#include "tc35876x-dsi-lvds.h"
|
||||
|
||||
#include <asm/intel_scu_ipc.h>
|
||||
|
||||
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
|
||||
|
||||
#define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF
|
||||
#define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */
|
||||
#define BLC_PWM_FREQ_CALC_CONSTANT 32
|
||||
#define MHz 1000000
|
||||
#define BRIGHTNESS_MIN_LEVEL 1
|
||||
#define BRIGHTNESS_MAX_LEVEL 100
|
||||
#define BRIGHTNESS_MASK 0xFF
|
||||
#define BLC_POLARITY_NORMAL 0
|
||||
#define BLC_POLARITY_INVERSE 1
|
||||
#define BLC_ADJUSTMENT_MAX 100
|
||||
|
||||
#define MDFLD_BLC_PWM_PRECISION_FACTOR 10
|
||||
#define MDFLD_BLC_MAX_PWM_REG_FREQ 0xFFFE
|
||||
#define MDFLD_BLC_MIN_PWM_REG_FREQ 0x2
|
||||
|
||||
#define MDFLD_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE)
|
||||
#define MDFLD_BACKLIGHT_PWM_CTL_SHIFT (16)
|
||||
|
||||
static struct backlight_device *mdfld_backlight_device;
|
||||
|
||||
int mdfld_set_brightness(struct backlight_device *bd)
|
||||
{
|
||||
struct drm_device *dev =
|
||||
(struct drm_device *)bl_get_data(mdfld_backlight_device);
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
int level = bd->props.brightness;
|
||||
|
||||
DRM_DEBUG_DRIVER("backlight level set to %d\n", level);
|
||||
|
||||
/* Perform value bounds checking */
|
||||
if (level < BRIGHTNESS_MIN_LEVEL)
|
||||
level = BRIGHTNESS_MIN_LEVEL;
|
||||
|
||||
if (gma_power_begin(dev, false)) {
|
||||
u32 adjusted_level = 0;
|
||||
|
||||
/*
|
||||
* Adjust the backlight level with the percent in
|
||||
* dev_priv->blc_adj2
|
||||
*/
|
||||
adjusted_level = level * dev_priv->blc_adj2;
|
||||
adjusted_level = adjusted_level / BLC_ADJUSTMENT_MAX;
|
||||
dev_priv->brightness_adjusted = adjusted_level;
|
||||
|
||||
if (mdfld_get_panel_type(dev, 0) == TC35876X) {
|
||||
if (dev_priv->dpi_panel_on[0] ||
|
||||
dev_priv->dpi_panel_on[2])
|
||||
tc35876x_brightness_control(dev,
|
||||
dev_priv->brightness_adjusted);
|
||||
} else {
|
||||
if (dev_priv->dpi_panel_on[0])
|
||||
mdfld_dsi_brightness_control(dev, 0,
|
||||
dev_priv->brightness_adjusted);
|
||||
}
|
||||
|
||||
if (dev_priv->dpi_panel_on[2])
|
||||
mdfld_dsi_brightness_control(dev, 2,
|
||||
dev_priv->brightness_adjusted);
|
||||
gma_power_end(dev);
|
||||
}
|
||||
|
||||
/* cache the brightness for later use */
|
||||
dev_priv->brightness = level;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdfld_get_brightness(struct backlight_device *bd)
|
||||
{
|
||||
struct drm_device *dev =
|
||||
(struct drm_device *)bl_get_data(mdfld_backlight_device);
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
|
||||
DRM_DEBUG_DRIVER("brightness = 0x%x \n", dev_priv->brightness);
|
||||
|
||||
/* return locally cached var instead of HW read (due to DPST etc.) */
|
||||
return dev_priv->brightness;
|
||||
}
|
||||
|
||||
static const struct backlight_ops mdfld_ops = {
|
||||
.get_brightness = mdfld_get_brightness,
|
||||
.update_status = mdfld_set_brightness,
|
||||
};
|
||||
|
||||
static int device_backlight_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = (struct drm_psb_private *)
|
||||
dev->dev_private;
|
||||
|
||||
dev_priv->blc_adj1 = BLC_ADJUSTMENT_MAX;
|
||||
dev_priv->blc_adj2 = BLC_ADJUSTMENT_MAX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdfld_backlight_init(struct drm_device *dev)
|
||||
{
|
||||
struct backlight_properties props;
|
||||
int ret = 0;
|
||||
|
||||
memset(&props, 0, sizeof(struct backlight_properties));
|
||||
props.max_brightness = BRIGHTNESS_MAX_LEVEL;
|
||||
props.type = BACKLIGHT_PLATFORM;
|
||||
mdfld_backlight_device = backlight_device_register("mdfld-bl",
|
||||
NULL, (void *)dev, &mdfld_ops, &props);
|
||||
|
||||
if (IS_ERR(mdfld_backlight_device))
|
||||
return PTR_ERR(mdfld_backlight_device);
|
||||
|
||||
ret = device_backlight_init(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mdfld_backlight_device->props.brightness = BRIGHTNESS_MAX_LEVEL;
|
||||
mdfld_backlight_device->props.max_brightness = BRIGHTNESS_MAX_LEVEL;
|
||||
backlight_update_status(mdfld_backlight_device);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct backlight_device *mdfld_get_backlight_device(void)
|
||||
{
|
||||
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
|
||||
return mdfld_backlight_device;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* mdfld_save_display_registers
|
||||
*
|
||||
* Description: We are going to suspend so save current display
|
||||
* register state.
|
||||
*
|
||||
* Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
|
||||
*/
|
||||
static int mdfld_save_display_registers(struct drm_device *dev, int pipe)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct medfield_state *regs = &dev_priv->regs.mdfld;
|
||||
int i;
|
||||
|
||||
/* register */
|
||||
u32 dpll_reg = MRST_DPLL_A;
|
||||
u32 fp_reg = MRST_FPA0;
|
||||
u32 pipeconf_reg = PIPEACONF;
|
||||
u32 htot_reg = HTOTAL_A;
|
||||
u32 hblank_reg = HBLANK_A;
|
||||
u32 hsync_reg = HSYNC_A;
|
||||
u32 vtot_reg = VTOTAL_A;
|
||||
u32 vblank_reg = VBLANK_A;
|
||||
u32 vsync_reg = VSYNC_A;
|
||||
u32 pipesrc_reg = PIPEASRC;
|
||||
u32 dspstride_reg = DSPASTRIDE;
|
||||
u32 dsplinoff_reg = DSPALINOFF;
|
||||
u32 dsptileoff_reg = DSPATILEOFF;
|
||||
u32 dspsize_reg = DSPASIZE;
|
||||
u32 dsppos_reg = DSPAPOS;
|
||||
u32 dspsurf_reg = DSPASURF;
|
||||
u32 mipi_reg = MIPI;
|
||||
u32 dspcntr_reg = DSPACNTR;
|
||||
u32 dspstatus_reg = PIPEASTAT;
|
||||
u32 palette_reg = PALETTE_A;
|
||||
|
||||
/* pointer to values */
|
||||
u32 *dpll_val = ®s->saveDPLL_A;
|
||||
u32 *fp_val = ®s->saveFPA0;
|
||||
u32 *pipeconf_val = ®s->savePIPEACONF;
|
||||
u32 *htot_val = ®s->saveHTOTAL_A;
|
||||
u32 *hblank_val = ®s->saveHBLANK_A;
|
||||
u32 *hsync_val = ®s->saveHSYNC_A;
|
||||
u32 *vtot_val = ®s->saveVTOTAL_A;
|
||||
u32 *vblank_val = ®s->saveVBLANK_A;
|
||||
u32 *vsync_val = ®s->saveVSYNC_A;
|
||||
u32 *pipesrc_val = ®s->savePIPEASRC;
|
||||
u32 *dspstride_val = ®s->saveDSPASTRIDE;
|
||||
u32 *dsplinoff_val = ®s->saveDSPALINOFF;
|
||||
u32 *dsptileoff_val = ®s->saveDSPATILEOFF;
|
||||
u32 *dspsize_val = ®s->saveDSPASIZE;
|
||||
u32 *dsppos_val = ®s->saveDSPAPOS;
|
||||
u32 *dspsurf_val = ®s->saveDSPASURF;
|
||||
u32 *mipi_val = ®s->saveMIPI;
|
||||
u32 *dspcntr_val = ®s->saveDSPACNTR;
|
||||
u32 *dspstatus_val = ®s->saveDSPASTATUS;
|
||||
u32 *palette_val = regs->save_palette_a;
|
||||
|
||||
switch (pipe) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
/* regester */
|
||||
dpll_reg = MDFLD_DPLL_B;
|
||||
fp_reg = MDFLD_DPLL_DIV0;
|
||||
pipeconf_reg = PIPEBCONF;
|
||||
htot_reg = HTOTAL_B;
|
||||
hblank_reg = HBLANK_B;
|
||||
hsync_reg = HSYNC_B;
|
||||
vtot_reg = VTOTAL_B;
|
||||
vblank_reg = VBLANK_B;
|
||||
vsync_reg = VSYNC_B;
|
||||
pipesrc_reg = PIPEBSRC;
|
||||
dspstride_reg = DSPBSTRIDE;
|
||||
dsplinoff_reg = DSPBLINOFF;
|
||||
dsptileoff_reg = DSPBTILEOFF;
|
||||
dspsize_reg = DSPBSIZE;
|
||||
dsppos_reg = DSPBPOS;
|
||||
dspsurf_reg = DSPBSURF;
|
||||
dspcntr_reg = DSPBCNTR;
|
||||
dspstatus_reg = PIPEBSTAT;
|
||||
palette_reg = PALETTE_B;
|
||||
|
||||
/* values */
|
||||
dpll_val = ®s->saveDPLL_B;
|
||||
fp_val = ®s->saveFPB0;
|
||||
pipeconf_val = ®s->savePIPEBCONF;
|
||||
htot_val = ®s->saveHTOTAL_B;
|
||||
hblank_val = ®s->saveHBLANK_B;
|
||||
hsync_val = ®s->saveHSYNC_B;
|
||||
vtot_val = ®s->saveVTOTAL_B;
|
||||
vblank_val = ®s->saveVBLANK_B;
|
||||
vsync_val = ®s->saveVSYNC_B;
|
||||
pipesrc_val = ®s->savePIPEBSRC;
|
||||
dspstride_val = ®s->saveDSPBSTRIDE;
|
||||
dsplinoff_val = ®s->saveDSPBLINOFF;
|
||||
dsptileoff_val = ®s->saveDSPBTILEOFF;
|
||||
dspsize_val = ®s->saveDSPBSIZE;
|
||||
dsppos_val = ®s->saveDSPBPOS;
|
||||
dspsurf_val = ®s->saveDSPBSURF;
|
||||
dspcntr_val = ®s->saveDSPBCNTR;
|
||||
dspstatus_val = ®s->saveDSPBSTATUS;
|
||||
palette_val = regs->save_palette_b;
|
||||
break;
|
||||
case 2:
|
||||
/* register */
|
||||
pipeconf_reg = PIPECCONF;
|
||||
htot_reg = HTOTAL_C;
|
||||
hblank_reg = HBLANK_C;
|
||||
hsync_reg = HSYNC_C;
|
||||
vtot_reg = VTOTAL_C;
|
||||
vblank_reg = VBLANK_C;
|
||||
vsync_reg = VSYNC_C;
|
||||
pipesrc_reg = PIPECSRC;
|
||||
dspstride_reg = DSPCSTRIDE;
|
||||
dsplinoff_reg = DSPCLINOFF;
|
||||
dsptileoff_reg = DSPCTILEOFF;
|
||||
dspsize_reg = DSPCSIZE;
|
||||
dsppos_reg = DSPCPOS;
|
||||
dspsurf_reg = DSPCSURF;
|
||||
mipi_reg = MIPI_C;
|
||||
dspcntr_reg = DSPCCNTR;
|
||||
dspstatus_reg = PIPECSTAT;
|
||||
palette_reg = PALETTE_C;
|
||||
|
||||
/* pointer to values */
|
||||
pipeconf_val = ®s->savePIPECCONF;
|
||||
htot_val = ®s->saveHTOTAL_C;
|
||||
hblank_val = ®s->saveHBLANK_C;
|
||||
hsync_val = ®s->saveHSYNC_C;
|
||||
vtot_val = ®s->saveVTOTAL_C;
|
||||
vblank_val = ®s->saveVBLANK_C;
|
||||
vsync_val = ®s->saveVSYNC_C;
|
||||
pipesrc_val = ®s->savePIPECSRC;
|
||||
dspstride_val = ®s->saveDSPCSTRIDE;
|
||||
dsplinoff_val = ®s->saveDSPCLINOFF;
|
||||
dsptileoff_val = ®s->saveDSPCTILEOFF;
|
||||
dspsize_val = ®s->saveDSPCSIZE;
|
||||
dsppos_val = ®s->saveDSPCPOS;
|
||||
dspsurf_val = ®s->saveDSPCSURF;
|
||||
mipi_val = ®s->saveMIPI_C;
|
||||
dspcntr_val = ®s->saveDSPCCNTR;
|
||||
dspstatus_val = ®s->saveDSPCSTATUS;
|
||||
palette_val = regs->save_palette_c;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("%s, invalid pipe number.\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Pipe & plane A info */
|
||||
*dpll_val = PSB_RVDC32(dpll_reg);
|
||||
*fp_val = PSB_RVDC32(fp_reg);
|
||||
*pipeconf_val = PSB_RVDC32(pipeconf_reg);
|
||||
*htot_val = PSB_RVDC32(htot_reg);
|
||||
*hblank_val = PSB_RVDC32(hblank_reg);
|
||||
*hsync_val = PSB_RVDC32(hsync_reg);
|
||||
*vtot_val = PSB_RVDC32(vtot_reg);
|
||||
*vblank_val = PSB_RVDC32(vblank_reg);
|
||||
*vsync_val = PSB_RVDC32(vsync_reg);
|
||||
*pipesrc_val = PSB_RVDC32(pipesrc_reg);
|
||||
*dspstride_val = PSB_RVDC32(dspstride_reg);
|
||||
*dsplinoff_val = PSB_RVDC32(dsplinoff_reg);
|
||||
*dsptileoff_val = PSB_RVDC32(dsptileoff_reg);
|
||||
*dspsize_val = PSB_RVDC32(dspsize_reg);
|
||||
*dsppos_val = PSB_RVDC32(dsppos_reg);
|
||||
*dspsurf_val = PSB_RVDC32(dspsurf_reg);
|
||||
*dspcntr_val = PSB_RVDC32(dspcntr_reg);
|
||||
*dspstatus_val = PSB_RVDC32(dspstatus_reg);
|
||||
|
||||
/*save palette (gamma) */
|
||||
for (i = 0; i < 256; i++)
|
||||
palette_val[i] = PSB_RVDC32(palette_reg + (i << 2));
|
||||
|
||||
if (pipe == 1) {
|
||||
regs->savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL);
|
||||
regs->savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS);
|
||||
|
||||
regs->saveHDMIPHYMISCCTL = PSB_RVDC32(HDMIPHYMISCCTL);
|
||||
regs->saveHDMIB_CONTROL = PSB_RVDC32(HDMIB_CONTROL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*mipi_val = PSB_RVDC32(mipi_reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* mdfld_restore_display_registers
|
||||
*
|
||||
* Description: We are going to resume so restore display register state.
|
||||
*
|
||||
* Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
|
||||
*/
|
||||
static int mdfld_restore_display_registers(struct drm_device *dev, int pipe)
|
||||
{
|
||||
/* To get panel out of ULPS mode. */
|
||||
u32 temp = 0;
|
||||
u32 device_ready_reg = DEVICE_READY_REG;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct mdfld_dsi_config *dsi_config = NULL;
|
||||
struct medfield_state *regs = &dev_priv->regs.mdfld;
|
||||
u32 i = 0;
|
||||
u32 dpll = 0;
|
||||
u32 timeout = 0;
|
||||
|
||||
/* regester */
|
||||
u32 dpll_reg = MRST_DPLL_A;
|
||||
u32 fp_reg = MRST_FPA0;
|
||||
u32 pipeconf_reg = PIPEACONF;
|
||||
u32 htot_reg = HTOTAL_A;
|
||||
u32 hblank_reg = HBLANK_A;
|
||||
u32 hsync_reg = HSYNC_A;
|
||||
u32 vtot_reg = VTOTAL_A;
|
||||
u32 vblank_reg = VBLANK_A;
|
||||
u32 vsync_reg = VSYNC_A;
|
||||
u32 pipesrc_reg = PIPEASRC;
|
||||
u32 dspstride_reg = DSPASTRIDE;
|
||||
u32 dsplinoff_reg = DSPALINOFF;
|
||||
u32 dsptileoff_reg = DSPATILEOFF;
|
||||
u32 dspsize_reg = DSPASIZE;
|
||||
u32 dsppos_reg = DSPAPOS;
|
||||
u32 dspsurf_reg = DSPASURF;
|
||||
u32 dspstatus_reg = PIPEASTAT;
|
||||
u32 mipi_reg = MIPI;
|
||||
u32 dspcntr_reg = DSPACNTR;
|
||||
u32 palette_reg = PALETTE_A;
|
||||
|
||||
/* values */
|
||||
u32 dpll_val = regs->saveDPLL_A & ~DPLL_VCO_ENABLE;
|
||||
u32 fp_val = regs->saveFPA0;
|
||||
u32 pipeconf_val = regs->savePIPEACONF;
|
||||
u32 htot_val = regs->saveHTOTAL_A;
|
||||
u32 hblank_val = regs->saveHBLANK_A;
|
||||
u32 hsync_val = regs->saveHSYNC_A;
|
||||
u32 vtot_val = regs->saveVTOTAL_A;
|
||||
u32 vblank_val = regs->saveVBLANK_A;
|
||||
u32 vsync_val = regs->saveVSYNC_A;
|
||||
u32 pipesrc_val = regs->savePIPEASRC;
|
||||
u32 dspstride_val = regs->saveDSPASTRIDE;
|
||||
u32 dsplinoff_val = regs->saveDSPALINOFF;
|
||||
u32 dsptileoff_val = regs->saveDSPATILEOFF;
|
||||
u32 dspsize_val = regs->saveDSPASIZE;
|
||||
u32 dsppos_val = regs->saveDSPAPOS;
|
||||
u32 dspsurf_val = regs->saveDSPASURF;
|
||||
u32 dspstatus_val = regs->saveDSPASTATUS;
|
||||
u32 mipi_val = regs->saveMIPI;
|
||||
u32 dspcntr_val = regs->saveDSPACNTR;
|
||||
u32 *palette_val = regs->save_palette_a;
|
||||
|
||||
switch (pipe) {
|
||||
case 0:
|
||||
dsi_config = dev_priv->dsi_configs[0];
|
||||
break;
|
||||
case 1:
|
||||
/* regester */
|
||||
dpll_reg = MDFLD_DPLL_B;
|
||||
fp_reg = MDFLD_DPLL_DIV0;
|
||||
pipeconf_reg = PIPEBCONF;
|
||||
htot_reg = HTOTAL_B;
|
||||
hblank_reg = HBLANK_B;
|
||||
hsync_reg = HSYNC_B;
|
||||
vtot_reg = VTOTAL_B;
|
||||
vblank_reg = VBLANK_B;
|
||||
vsync_reg = VSYNC_B;
|
||||
pipesrc_reg = PIPEBSRC;
|
||||
dspstride_reg = DSPBSTRIDE;
|
||||
dsplinoff_reg = DSPBLINOFF;
|
||||
dsptileoff_reg = DSPBTILEOFF;
|
||||
dspsize_reg = DSPBSIZE;
|
||||
dsppos_reg = DSPBPOS;
|
||||
dspsurf_reg = DSPBSURF;
|
||||
dspcntr_reg = DSPBCNTR;
|
||||
dspstatus_reg = PIPEBSTAT;
|
||||
palette_reg = PALETTE_B;
|
||||
|
||||
/* values */
|
||||
dpll_val = regs->saveDPLL_B & ~DPLL_VCO_ENABLE;
|
||||
fp_val = regs->saveFPB0;
|
||||
pipeconf_val = regs->savePIPEBCONF;
|
||||
htot_val = regs->saveHTOTAL_B;
|
||||
hblank_val = regs->saveHBLANK_B;
|
||||
hsync_val = regs->saveHSYNC_B;
|
||||
vtot_val = regs->saveVTOTAL_B;
|
||||
vblank_val = regs->saveVBLANK_B;
|
||||
vsync_val = regs->saveVSYNC_B;
|
||||
pipesrc_val = regs->savePIPEBSRC;
|
||||
dspstride_val = regs->saveDSPBSTRIDE;
|
||||
dsplinoff_val = regs->saveDSPBLINOFF;
|
||||
dsptileoff_val = regs->saveDSPBTILEOFF;
|
||||
dspsize_val = regs->saveDSPBSIZE;
|
||||
dsppos_val = regs->saveDSPBPOS;
|
||||
dspsurf_val = regs->saveDSPBSURF;
|
||||
dspcntr_val = regs->saveDSPBCNTR;
|
||||
dspstatus_val = regs->saveDSPBSTATUS;
|
||||
palette_val = regs->save_palette_b;
|
||||
break;
|
||||
case 2:
|
||||
/* regester */
|
||||
pipeconf_reg = PIPECCONF;
|
||||
htot_reg = HTOTAL_C;
|
||||
hblank_reg = HBLANK_C;
|
||||
hsync_reg = HSYNC_C;
|
||||
vtot_reg = VTOTAL_C;
|
||||
vblank_reg = VBLANK_C;
|
||||
vsync_reg = VSYNC_C;
|
||||
pipesrc_reg = PIPECSRC;
|
||||
dspstride_reg = DSPCSTRIDE;
|
||||
dsplinoff_reg = DSPCLINOFF;
|
||||
dsptileoff_reg = DSPCTILEOFF;
|
||||
dspsize_reg = DSPCSIZE;
|
||||
dsppos_reg = DSPCPOS;
|
||||
dspsurf_reg = DSPCSURF;
|
||||
mipi_reg = MIPI_C;
|
||||
dspcntr_reg = DSPCCNTR;
|
||||
dspstatus_reg = PIPECSTAT;
|
||||
palette_reg = PALETTE_C;
|
||||
|
||||
/* values */
|
||||
pipeconf_val = regs->savePIPECCONF;
|
||||
htot_val = regs->saveHTOTAL_C;
|
||||
hblank_val = regs->saveHBLANK_C;
|
||||
hsync_val = regs->saveHSYNC_C;
|
||||
vtot_val = regs->saveVTOTAL_C;
|
||||
vblank_val = regs->saveVBLANK_C;
|
||||
vsync_val = regs->saveVSYNC_C;
|
||||
pipesrc_val = regs->savePIPECSRC;
|
||||
dspstride_val = regs->saveDSPCSTRIDE;
|
||||
dsplinoff_val = regs->saveDSPCLINOFF;
|
||||
dsptileoff_val = regs->saveDSPCTILEOFF;
|
||||
dspsize_val = regs->saveDSPCSIZE;
|
||||
dsppos_val = regs->saveDSPCPOS;
|
||||
dspsurf_val = regs->saveDSPCSURF;
|
||||
mipi_val = regs->saveMIPI_C;
|
||||
dspcntr_val = regs->saveDSPCCNTR;
|
||||
dspstatus_val = regs->saveDSPCSTATUS;
|
||||
palette_val = regs->save_palette_c;
|
||||
|
||||
dsi_config = dev_priv->dsi_configs[1];
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("%s, invalid pipe number.\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*make sure VGA plane is off. it initializes to on after reset!*/
|
||||
PSB_WVDC32(0x80000000, VGACNTRL);
|
||||
|
||||
if (pipe == 1) {
|
||||
PSB_WVDC32(dpll_val & ~DPLL_VCO_ENABLE, dpll_reg);
|
||||
PSB_RVDC32(dpll_reg);
|
||||
|
||||
PSB_WVDC32(fp_val, fp_reg);
|
||||
} else {
|
||||
|
||||
dpll = PSB_RVDC32(dpll_reg);
|
||||
|
||||
if (!(dpll & DPLL_VCO_ENABLE)) {
|
||||
|
||||
/* When ungating power of DPLL, needs to wait 0.5us
|
||||
before enable the VCO */
|
||||
if (dpll & MDFLD_PWR_GATE_EN) {
|
||||
dpll &= ~MDFLD_PWR_GATE_EN;
|
||||
PSB_WVDC32(dpll, dpll_reg);
|
||||
/* FIXME_MDFLD PO - change 500 to 1 after PO */
|
||||
udelay(500);
|
||||
}
|
||||
|
||||
PSB_WVDC32(fp_val, fp_reg);
|
||||
PSB_WVDC32(dpll_val, dpll_reg);
|
||||
/* FIXME_MDFLD PO - change 500 to 1 after PO */
|
||||
udelay(500);
|
||||
|
||||
dpll_val |= DPLL_VCO_ENABLE;
|
||||
PSB_WVDC32(dpll_val, dpll_reg);
|
||||
PSB_RVDC32(dpll_reg);
|
||||
|
||||
/* wait for DSI PLL to lock */
|
||||
while (timeout < 20000 &&
|
||||
!(PSB_RVDC32(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) {
|
||||
udelay(150);
|
||||
timeout++;
|
||||
}
|
||||
|
||||
if (timeout == 20000) {
|
||||
DRM_ERROR("%s, can't lock DSIPLL.\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Restore mode */
|
||||
PSB_WVDC32(htot_val, htot_reg);
|
||||
PSB_WVDC32(hblank_val, hblank_reg);
|
||||
PSB_WVDC32(hsync_val, hsync_reg);
|
||||
PSB_WVDC32(vtot_val, vtot_reg);
|
||||
PSB_WVDC32(vblank_val, vblank_reg);
|
||||
PSB_WVDC32(vsync_val, vsync_reg);
|
||||
PSB_WVDC32(pipesrc_val, pipesrc_reg);
|
||||
PSB_WVDC32(dspstatus_val, dspstatus_reg);
|
||||
|
||||
/*set up the plane*/
|
||||
PSB_WVDC32(dspstride_val, dspstride_reg);
|
||||
PSB_WVDC32(dsplinoff_val, dsplinoff_reg);
|
||||
PSB_WVDC32(dsptileoff_val, dsptileoff_reg);
|
||||
PSB_WVDC32(dspsize_val, dspsize_reg);
|
||||
PSB_WVDC32(dsppos_val, dsppos_reg);
|
||||
PSB_WVDC32(dspsurf_val, dspsurf_reg);
|
||||
|
||||
if (pipe == 1) {
|
||||
/* restore palette (gamma) */
|
||||
/*DRM_UDELAY(50000); */
|
||||
for (i = 0; i < 256; i++)
|
||||
PSB_WVDC32(palette_val[i], palette_reg + (i << 2));
|
||||
|
||||
PSB_WVDC32(regs->savePFIT_CONTROL, PFIT_CONTROL);
|
||||
PSB_WVDC32(regs->savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS);
|
||||
|
||||
/*TODO: resume HDMI port */
|
||||
|
||||
/*TODO: resume pipe*/
|
||||
|
||||
/*enable the plane*/
|
||||
PSB_WVDC32(dspcntr_val & ~DISPLAY_PLANE_ENABLE, dspcntr_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*set up pipe related registers*/
|
||||
PSB_WVDC32(mipi_val, mipi_reg);
|
||||
|
||||
/*setup MIPI adapter + MIPI IP registers*/
|
||||
if (dsi_config)
|
||||
mdfld_dsi_controller_init(dsi_config, pipe);
|
||||
|
||||
if (in_atomic() || in_interrupt())
|
||||
mdelay(20);
|
||||
else
|
||||
msleep(20);
|
||||
|
||||
/*enable the plane*/
|
||||
PSB_WVDC32(dspcntr_val, dspcntr_reg);
|
||||
|
||||
if (in_atomic() || in_interrupt())
|
||||
mdelay(20);
|
||||
else
|
||||
msleep(20);
|
||||
|
||||
/* LP Hold Release */
|
||||
temp = REG_READ(mipi_reg);
|
||||
temp |= LP_OUTPUT_HOLD_RELEASE;
|
||||
REG_WRITE(mipi_reg, temp);
|
||||
mdelay(1);
|
||||
|
||||
|
||||
/* Set DSI host to exit from Utra Low Power State */
|
||||
temp = REG_READ(device_ready_reg);
|
||||
temp &= ~ULPS_MASK;
|
||||
temp |= 0x3;
|
||||
temp |= EXIT_ULPS_DEV_READY;
|
||||
REG_WRITE(device_ready_reg, temp);
|
||||
mdelay(1);
|
||||
|
||||
temp = REG_READ(device_ready_reg);
|
||||
temp &= ~ULPS_MASK;
|
||||
temp |= EXITING_ULPS;
|
||||
REG_WRITE(device_ready_reg, temp);
|
||||
mdelay(1);
|
||||
|
||||
/*enable the pipe*/
|
||||
PSB_WVDC32(pipeconf_val, pipeconf_reg);
|
||||
|
||||
/* restore palette (gamma) */
|
||||
/*DRM_UDELAY(50000); */
|
||||
for (i = 0; i < 256; i++)
|
||||
PSB_WVDC32(palette_val[i], palette_reg + (i << 2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdfld_save_registers(struct drm_device *dev)
|
||||
{
|
||||
/* mdfld_save_cursor_overlay_registers(dev); */
|
||||
mdfld_save_display_registers(dev, 0);
|
||||
mdfld_save_display_registers(dev, 2);
|
||||
mdfld_disable_crtc(dev, 0);
|
||||
mdfld_disable_crtc(dev, 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdfld_restore_registers(struct drm_device *dev)
|
||||
{
|
||||
mdfld_restore_display_registers(dev, 2);
|
||||
mdfld_restore_display_registers(dev, 0);
|
||||
/* mdfld_restore_cursor_overlay_registers(dev); */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdfld_power_down(struct drm_device *dev)
|
||||
{
|
||||
/* FIXME */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdfld_power_up(struct drm_device *dev)
|
||||
{
|
||||
/* FIXME */
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct psb_ops mdfld_chip_ops = {
|
||||
.name = "mdfld",
|
||||
.accel_2d = 0,
|
||||
.pipes = 3,
|
||||
.crtcs = 3,
|
||||
.sgx_offset = MRST_SGX_OFFSET,
|
||||
|
||||
.chip_setup = mid_chip_setup,
|
||||
.crtc_helper = &mdfld_helper_funcs,
|
||||
.crtc_funcs = &psb_intel_crtc_funcs,
|
||||
|
||||
.output_init = mdfld_output_init,
|
||||
|
||||
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
|
||||
.backlight_init = mdfld_backlight_init,
|
||||
#endif
|
||||
|
||||
.save_regs = mdfld_save_registers,
|
||||
.restore_regs = mdfld_restore_registers,
|
||||
.power_down = mdfld_power_down,
|
||||
.power_up = mdfld_power_up,
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright © 2010 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* jim liu <jim.liu@intel.com>
|
||||
* Jackie Li<yaodong.li@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef __MDFLD_DSI_DPI_H__
|
||||
#define __MDFLD_DSI_DPI_H__
|
||||
|
||||
#include "mdfld_dsi_output.h"
|
||||
#include "mdfld_output.h"
|
||||
|
||||
struct mdfld_dsi_dpi_timing {
|
||||
u16 hsync_count;
|
||||
u16 hbp_count;
|
||||
u16 hfp_count;
|
||||
u16 hactive_count;
|
||||
u16 vsync_count;
|
||||
u16 vbp_count;
|
||||
u16 vfp_count;
|
||||
};
|
||||
|
||||
struct mdfld_dsi_dpi_output {
|
||||
struct mdfld_dsi_encoder base;
|
||||
struct drm_device *dev;
|
||||
|
||||
int panel_on;
|
||||
int first_boot;
|
||||
|
||||
const struct panel_funcs *p_funcs;
|
||||
};
|
||||
|
||||
#define MDFLD_DSI_DPI_OUTPUT(dsi_encoder)\
|
||||
container_of(dsi_encoder, struct mdfld_dsi_dpi_output, base)
|
||||
|
||||
/* Export functions */
|
||||
extern int mdfld_dsi_dpi_timing_calculation(struct drm_display_mode *mode,
|
||||
struct mdfld_dsi_dpi_timing *dpi_timing,
|
||||
int num_lane, int bpp);
|
||||
extern struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev,
|
||||
struct mdfld_dsi_connector *dsi_connector,
|
||||
const struct panel_funcs *p_funcs);
|
||||
|
||||
/* MDFLD DPI helper functions */
|
||||
extern void mdfld_dsi_dpi_dpms(struct drm_encoder *encoder, int mode);
|
||||
extern bool mdfld_dsi_dpi_mode_fixup(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
extern void mdfld_dsi_dpi_prepare(struct drm_encoder *encoder);
|
||||
extern void mdfld_dsi_dpi_commit(struct drm_encoder *encoder);
|
||||
extern void mdfld_dsi_dpi_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
extern void mdfld_dsi_dpi_turn_on(struct mdfld_dsi_dpi_output *output,
|
||||
int pipe);
|
||||
extern void mdfld_dsi_dpi_controller_init(struct mdfld_dsi_config *dsi_config,
|
||||
int pipe);
|
||||
#endif /*__MDFLD_DSI_DPI_H__*/
|
|
@ -0,0 +1,635 @@
|
|||
/*
|
||||
* Copyright © 2010 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* jim liu <jim.liu@intel.com>
|
||||
* Jackie Li<yaodong.li@intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "mdfld_dsi_output.h"
|
||||
#include "mdfld_dsi_dpi.h"
|
||||
#include "mdfld_output.h"
|
||||
#include "mdfld_dsi_pkg_sender.h"
|
||||
#include "tc35876x-dsi-lvds.h"
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <asm/intel_scu_ipc.h>
|
||||
|
||||
/* get the LABC from command line. */
|
||||
static int LABC_control = 1;
|
||||
|
||||
#ifdef MODULE
|
||||
module_param(LABC_control, int, 0644);
|
||||
#else
|
||||
|
||||
static int __init parse_LABC_control(char *arg)
|
||||
{
|
||||
/* LABC control can be passed in as a cmdline parameter */
|
||||
/* to enable this feature add LABC=1 to cmdline */
|
||||
/* to disable this feature add LABC=0 to cmdline */
|
||||
if (!arg)
|
||||
return -EINVAL;
|
||||
|
||||
if (!strcasecmp(arg, "0"))
|
||||
LABC_control = 0;
|
||||
else if (!strcasecmp(arg, "1"))
|
||||
LABC_control = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
early_param("LABC", parse_LABC_control);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Check and see if the generic control or data buffer is empty and ready.
|
||||
*/
|
||||
void mdfld_dsi_gen_fifo_ready(struct drm_device *dev, u32 gen_fifo_stat_reg,
|
||||
u32 fifo_stat)
|
||||
{
|
||||
u32 GEN_BF_time_out_count;
|
||||
|
||||
/* Check MIPI Adatper command registers */
|
||||
for (GEN_BF_time_out_count = 0;
|
||||
GEN_BF_time_out_count < GEN_FB_TIME_OUT;
|
||||
GEN_BF_time_out_count++) {
|
||||
if ((REG_READ(gen_fifo_stat_reg) & fifo_stat) == fifo_stat)
|
||||
break;
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
if (GEN_BF_time_out_count == GEN_FB_TIME_OUT)
|
||||
DRM_ERROR("mdfld_dsi_gen_fifo_ready, Timeout. gen_fifo_stat_reg = 0x%x.\n",
|
||||
gen_fifo_stat_reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage the DSI MIPI keyboard and display brightness.
|
||||
* FIXME: this is exported to OSPM code. should work out an specific
|
||||
* display interface to OSPM.
|
||||
*/
|
||||
|
||||
void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config, int pipe)
|
||||
{
|
||||
struct mdfld_dsi_pkg_sender *sender =
|
||||
mdfld_dsi_get_pkg_sender(dsi_config);
|
||||
struct drm_device *dev = sender->dev;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
u32 gen_ctrl_val;
|
||||
|
||||
if (!sender) {
|
||||
DRM_ERROR("No sender found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set default display backlight value to 85% (0xd8)*/
|
||||
mdfld_dsi_send_mcs_short(sender, write_display_brightness, 0xd8, 1,
|
||||
true);
|
||||
|
||||
/* Set minimum brightness setting of CABC function to 20% (0x33)*/
|
||||
mdfld_dsi_send_mcs_short(sender, write_cabc_min_bright, 0x33, 1, true);
|
||||
|
||||
/* Enable backlight or/and LABC */
|
||||
gen_ctrl_val = BRIGHT_CNTL_BLOCK_ON | DISPLAY_DIMMING_ON |
|
||||
BACKLIGHT_ON;
|
||||
if (LABC_control == 1)
|
||||
gen_ctrl_val |= DISPLAY_DIMMING_ON | DISPLAY_BRIGHTNESS_AUTO
|
||||
| GAMMA_AUTO;
|
||||
|
||||
if (LABC_control == 1)
|
||||
gen_ctrl_val |= AMBIENT_LIGHT_SENSE_ON;
|
||||
|
||||
dev_priv->mipi_ctrl_display = gen_ctrl_val;
|
||||
|
||||
mdfld_dsi_send_mcs_short(sender, write_ctrl_display, (u8)gen_ctrl_val,
|
||||
1, true);
|
||||
|
||||
mdfld_dsi_send_mcs_short(sender, write_ctrl_cabc, UI_IMAGE, 1, true);
|
||||
}
|
||||
|
||||
void mdfld_dsi_brightness_control(struct drm_device *dev, int pipe, int level)
|
||||
{
|
||||
struct mdfld_dsi_pkg_sender *sender;
|
||||
struct drm_psb_private *dev_priv;
|
||||
struct mdfld_dsi_config *dsi_config;
|
||||
u32 gen_ctrl_val = 0;
|
||||
int p_type = TMD_VID;
|
||||
|
||||
if (!dev || (pipe != 0 && pipe != 2)) {
|
||||
DRM_ERROR("Invalid parameter\n");
|
||||
return;
|
||||
}
|
||||
|
||||
p_type = mdfld_get_panel_type(dev, 0);
|
||||
|
||||
dev_priv = dev->dev_private;
|
||||
|
||||
if (pipe)
|
||||
dsi_config = dev_priv->dsi_configs[1];
|
||||
else
|
||||
dsi_config = dev_priv->dsi_configs[0];
|
||||
|
||||
sender = mdfld_dsi_get_pkg_sender(dsi_config);
|
||||
|
||||
if (!sender) {
|
||||
DRM_ERROR("No sender found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
gen_ctrl_val = (level * 0xff / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL) & 0xff;
|
||||
|
||||
dev_dbg(sender->dev->dev, "pipe = %d, gen_ctrl_val = %d.\n",
|
||||
pipe, gen_ctrl_val);
|
||||
|
||||
if (p_type == TMD_VID) {
|
||||
/* Set display backlight value */
|
||||
mdfld_dsi_send_mcs_short(sender, tmd_write_display_brightness,
|
||||
(u8)gen_ctrl_val, 1, true);
|
||||
} else {
|
||||
/* Set display backlight value */
|
||||
mdfld_dsi_send_mcs_short(sender, write_display_brightness,
|
||||
(u8)gen_ctrl_val, 1, true);
|
||||
|
||||
/* Enable backlight control */
|
||||
if (level == 0)
|
||||
gen_ctrl_val = 0;
|
||||
else
|
||||
gen_ctrl_val = dev_priv->mipi_ctrl_display;
|
||||
|
||||
mdfld_dsi_send_mcs_short(sender, write_ctrl_display,
|
||||
(u8)gen_ctrl_val, 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
static int mdfld_dsi_get_panel_status(struct mdfld_dsi_config *dsi_config,
|
||||
u8 dcs, u32 *data, bool hs)
|
||||
{
|
||||
struct mdfld_dsi_pkg_sender *sender
|
||||
= mdfld_dsi_get_pkg_sender(dsi_config);
|
||||
|
||||
if (!sender || !data) {
|
||||
DRM_ERROR("Invalid parameter\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return mdfld_dsi_read_mcs(sender, dcs, data, 1, hs);
|
||||
}
|
||||
|
||||
int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config, u32 *mode,
|
||||
bool hs)
|
||||
{
|
||||
if (!dsi_config || !mode) {
|
||||
DRM_ERROR("Invalid parameter\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return mdfld_dsi_get_panel_status(dsi_config, 0x0a, mode, hs);
|
||||
}
|
||||
|
||||
int mdfld_dsi_get_diagnostic_result(struct mdfld_dsi_config *dsi_config,
|
||||
u32 *result, bool hs)
|
||||
{
|
||||
if (!dsi_config || !result) {
|
||||
DRM_ERROR("Invalid parameter\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return mdfld_dsi_get_panel_status(dsi_config, 0x0f, result, hs);
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: this function was used by OSPM.
|
||||
* TODO: will be removed later, should work out display interfaces for OSPM
|
||||
*/
|
||||
void mdfld_dsi_controller_init(struct mdfld_dsi_config *dsi_config, int pipe)
|
||||
{
|
||||
if (!dsi_config || ((pipe != 0) && (pipe != 2))) {
|
||||
DRM_ERROR("Invalid parameters\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mdfld_dsi_dpi_controller_init(dsi_config, pipe);
|
||||
}
|
||||
|
||||
static void mdfld_dsi_connector_save(struct drm_connector *connector)
|
||||
{
|
||||
}
|
||||
|
||||
static void mdfld_dsi_connector_restore(struct drm_connector *connector)
|
||||
{
|
||||
}
|
||||
|
||||
/* FIXME: start using the force parameter */
|
||||
static enum drm_connector_status
|
||||
mdfld_dsi_connector_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct mdfld_dsi_connector *dsi_connector
|
||||
= mdfld_dsi_connector(connector);
|
||||
|
||||
dsi_connector->status = connector_status_connected;
|
||||
|
||||
return dsi_connector->status;
|
||||
}
|
||||
|
||||
static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
|
||||
struct drm_property *property,
|
||||
uint64_t value)
|
||||
{
|
||||
struct drm_encoder *encoder = connector->encoder;
|
||||
struct backlight_device *psb_bd;
|
||||
|
||||
if (!strcmp(property->name, "scaling mode") && encoder) {
|
||||
struct psb_intel_crtc *psb_crtc =
|
||||
to_psb_intel_crtc(encoder->crtc);
|
||||
bool centerechange;
|
||||
uint64_t val;
|
||||
|
||||
if (!psb_crtc)
|
||||
goto set_prop_error;
|
||||
|
||||
switch (value) {
|
||||
case DRM_MODE_SCALE_FULLSCREEN:
|
||||
break;
|
||||
case DRM_MODE_SCALE_NO_SCALE:
|
||||
break;
|
||||
case DRM_MODE_SCALE_ASPECT:
|
||||
break;
|
||||
default:
|
||||
goto set_prop_error;
|
||||
}
|
||||
|
||||
if (drm_connector_property_get_value(connector, property, &val))
|
||||
goto set_prop_error;
|
||||
|
||||
if (val == value)
|
||||
goto set_prop_done;
|
||||
|
||||
if (drm_connector_property_set_value(connector,
|
||||
property, value))
|
||||
goto set_prop_error;
|
||||
|
||||
centerechange = (val == DRM_MODE_SCALE_NO_SCALE) ||
|
||||
(value == DRM_MODE_SCALE_NO_SCALE);
|
||||
|
||||
if (psb_crtc->saved_mode.hdisplay != 0 &&
|
||||
psb_crtc->saved_mode.vdisplay != 0) {
|
||||
if (centerechange) {
|
||||
if (!drm_crtc_helper_set_mode(encoder->crtc,
|
||||
&psb_crtc->saved_mode,
|
||||
encoder->crtc->x,
|
||||
encoder->crtc->y,
|
||||
encoder->crtc->fb))
|
||||
goto set_prop_error;
|
||||
} else {
|
||||
struct drm_encoder_helper_funcs *funcs =
|
||||
encoder->helper_private;
|
||||
funcs->mode_set(encoder,
|
||||
&psb_crtc->saved_mode,
|
||||
&psb_crtc->saved_adjusted_mode);
|
||||
}
|
||||
}
|
||||
} else if (!strcmp(property->name, "backlight") && encoder) {
|
||||
if (drm_connector_property_set_value(connector, property,
|
||||
value))
|
||||
goto set_prop_error;
|
||||
else {
|
||||
psb_bd = mdfld_get_backlight_device();
|
||||
if (psb_bd) {
|
||||
psb_bd->props.brightness = value;
|
||||
mdfld_set_brightness(psb_bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
set_prop_done:
|
||||
return 0;
|
||||
set_prop_error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void mdfld_dsi_connector_destroy(struct drm_connector *connector)
|
||||
{
|
||||
struct mdfld_dsi_connector *dsi_connector =
|
||||
mdfld_dsi_connector(connector);
|
||||
struct mdfld_dsi_pkg_sender *sender;
|
||||
|
||||
if (!dsi_connector)
|
||||
return;
|
||||
drm_sysfs_connector_remove(connector);
|
||||
drm_connector_cleanup(connector);
|
||||
sender = dsi_connector->pkg_sender;
|
||||
mdfld_dsi_pkg_sender_destroy(sender);
|
||||
kfree(dsi_connector);
|
||||
}
|
||||
|
||||
static int mdfld_dsi_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct mdfld_dsi_connector *dsi_connector =
|
||||
mdfld_dsi_connector(connector);
|
||||
struct mdfld_dsi_config *dsi_config =
|
||||
mdfld_dsi_get_config(dsi_connector);
|
||||
struct drm_display_mode *fixed_mode = dsi_config->fixed_mode;
|
||||
struct drm_display_mode *dup_mode = NULL;
|
||||
struct drm_device *dev = connector->dev;
|
||||
|
||||
connector->display_info.min_vfreq = 0;
|
||||
connector->display_info.max_vfreq = 200;
|
||||
connector->display_info.min_hfreq = 0;
|
||||
connector->display_info.max_hfreq = 200;
|
||||
|
||||
if (fixed_mode) {
|
||||
dev_dbg(dev->dev, "fixed_mode %dx%d\n",
|
||||
fixed_mode->hdisplay, fixed_mode->vdisplay);
|
||||
dup_mode = drm_mode_duplicate(dev, fixed_mode);
|
||||
drm_mode_probed_add(connector, dup_mode);
|
||||
return 1;
|
||||
}
|
||||
DRM_ERROR("Didn't get any modes!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdfld_dsi_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct mdfld_dsi_connector *dsi_connector =
|
||||
mdfld_dsi_connector(connector);
|
||||
struct mdfld_dsi_config *dsi_config =
|
||||
mdfld_dsi_get_config(dsi_connector);
|
||||
struct drm_display_mode *fixed_mode = dsi_config->fixed_mode;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return MODE_NO_DBLESCAN;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
return MODE_NO_INTERLACE;
|
||||
|
||||
/**
|
||||
* FIXME: current DC has no fitting unit, reject any mode setting
|
||||
* request
|
||||
* Will figure out a way to do up-scaling(pannel fitting) later.
|
||||
**/
|
||||
if (fixed_mode) {
|
||||
if (mode->hdisplay != fixed_mode->hdisplay)
|
||||
return MODE_PANEL;
|
||||
|
||||
if (mode->vdisplay != fixed_mode->vdisplay)
|
||||
return MODE_PANEL;
|
||||
}
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static void mdfld_dsi_connector_dpms(struct drm_connector *connector, int mode)
|
||||
{
|
||||
if (mode == connector->dpms)
|
||||
return;
|
||||
|
||||
/*first, execute dpms*/
|
||||
|
||||
drm_helper_connector_dpms(connector, mode);
|
||||
}
|
||||
|
||||
static struct drm_encoder *mdfld_dsi_connector_best_encoder(
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct mdfld_dsi_connector *dsi_connector =
|
||||
mdfld_dsi_connector(connector);
|
||||
struct mdfld_dsi_config *dsi_config =
|
||||
mdfld_dsi_get_config(dsi_connector);
|
||||
return &dsi_config->encoder->base.base;
|
||||
}
|
||||
|
||||
/*DSI connector funcs*/
|
||||
static const struct drm_connector_funcs mdfld_dsi_connector_funcs = {
|
||||
.dpms = /*drm_helper_connector_dpms*/mdfld_dsi_connector_dpms,
|
||||
.save = mdfld_dsi_connector_save,
|
||||
.restore = mdfld_dsi_connector_restore,
|
||||
.detect = mdfld_dsi_connector_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.set_property = mdfld_dsi_connector_set_property,
|
||||
.destroy = mdfld_dsi_connector_destroy,
|
||||
};
|
||||
|
||||
/*DSI connector helper funcs*/
|
||||
static const struct drm_connector_helper_funcs
|
||||
mdfld_dsi_connector_helper_funcs = {
|
||||
.get_modes = mdfld_dsi_connector_get_modes,
|
||||
.mode_valid = mdfld_dsi_connector_mode_valid,
|
||||
.best_encoder = mdfld_dsi_connector_best_encoder,
|
||||
};
|
||||
|
||||
static int mdfld_dsi_get_default_config(struct drm_device *dev,
|
||||
struct mdfld_dsi_config *config, int pipe)
|
||||
{
|
||||
if (!dev || !config) {
|
||||
DRM_ERROR("Invalid parameters");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
config->bpp = 24;
|
||||
if (mdfld_get_panel_type(dev, pipe) == TC35876X)
|
||||
config->lane_count = 4;
|
||||
else
|
||||
config->lane_count = 2;
|
||||
config->channel_num = 0;
|
||||
|
||||
if (mdfld_get_panel_type(dev, pipe) == TMD_VID)
|
||||
config->video_mode = MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE;
|
||||
else if (mdfld_get_panel_type(dev, pipe) == TC35876X)
|
||||
config->video_mode =
|
||||
MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS;
|
||||
else
|
||||
config->video_mode = MDFLD_DSI_VIDEO_BURST_MODE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdfld_dsi_panel_reset(int pipe)
|
||||
{
|
||||
unsigned gpio;
|
||||
int ret = 0;
|
||||
|
||||
switch (pipe) {
|
||||
case 0:
|
||||
gpio = 128;
|
||||
break;
|
||||
case 2:
|
||||
gpio = 34;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Invalid output\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = gpio_request(gpio, "gfx");
|
||||
if (ret) {
|
||||
DRM_ERROR("gpio_rqueset failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = gpio_direction_output(gpio, 1);
|
||||
if (ret) {
|
||||
DRM_ERROR("gpio_direction_output failed\n");
|
||||
goto gpio_error;
|
||||
}
|
||||
|
||||
gpio_get_value(128);
|
||||
|
||||
gpio_error:
|
||||
if (gpio_is_valid(gpio))
|
||||
gpio_free(gpio);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* MIPI output init
|
||||
* @dev drm device
|
||||
* @pipe pipe number. 0 or 2
|
||||
* @config
|
||||
*
|
||||
* Do the initialization of a MIPI output, including create DRM mode objects
|
||||
* initialization of DSI output on @pipe
|
||||
*/
|
||||
void mdfld_dsi_output_init(struct drm_device *dev,
|
||||
int pipe,
|
||||
struct mdfld_dsi_config *config,
|
||||
const struct panel_funcs *p_vid_funcs)
|
||||
{
|
||||
struct mdfld_dsi_config *dsi_config;
|
||||
struct mdfld_dsi_connector *dsi_connector;
|
||||
struct drm_connector *connector;
|
||||
struct mdfld_dsi_encoder *encoder;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct panel_info dsi_panel_info;
|
||||
u32 width_mm, height_mm;
|
||||
|
||||
dev_dbg(dev->dev, "init DSI output on pipe %d\n", pipe);
|
||||
|
||||
if (!dev || ((pipe != 0) && (pipe != 2))) {
|
||||
DRM_ERROR("Invalid parameter\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*create a new connetor*/
|
||||
dsi_connector = kzalloc(sizeof(struct mdfld_dsi_connector), GFP_KERNEL);
|
||||
if (!dsi_connector) {
|
||||
DRM_ERROR("No memory");
|
||||
return;
|
||||
}
|
||||
|
||||
dsi_connector->pipe = pipe;
|
||||
|
||||
/*set DSI config*/
|
||||
if (config)
|
||||
dsi_config = config;
|
||||
else {
|
||||
dsi_config = kzalloc(sizeof(struct mdfld_dsi_config),
|
||||
GFP_KERNEL);
|
||||
if (!dsi_config) {
|
||||
DRM_ERROR("cannot allocate memory for DSI config\n");
|
||||
goto dsi_init_err0;
|
||||
}
|
||||
mdfld_dsi_get_default_config(dev, dsi_config, pipe);
|
||||
}
|
||||
|
||||
dsi_connector->private = dsi_config;
|
||||
|
||||
dsi_config->changed = 1;
|
||||
dsi_config->dev = dev;
|
||||
|
||||
dsi_config->fixed_mode = p_vid_funcs->get_config_mode(dev);
|
||||
if (p_vid_funcs->get_panel_info(dev, pipe, &dsi_panel_info))
|
||||
goto dsi_init_err0;
|
||||
|
||||
width_mm = dsi_panel_info.width_mm;
|
||||
height_mm = dsi_panel_info.height_mm;
|
||||
|
||||
dsi_config->mode = dsi_config->fixed_mode;
|
||||
dsi_config->connector = dsi_connector;
|
||||
|
||||
if (!dsi_config->fixed_mode) {
|
||||
DRM_ERROR("No pannel fixed mode was found\n");
|
||||
goto dsi_init_err0;
|
||||
}
|
||||
|
||||
if (pipe && dev_priv->dsi_configs[0]) {
|
||||
dsi_config->dvr_ic_inited = 0;
|
||||
dev_priv->dsi_configs[1] = dsi_config;
|
||||
} else if (pipe == 0) {
|
||||
dsi_config->dvr_ic_inited = 1;
|
||||
dev_priv->dsi_configs[0] = dsi_config;
|
||||
} else {
|
||||
DRM_ERROR("Trying to init MIPI1 before MIPI0\n");
|
||||
goto dsi_init_err0;
|
||||
}
|
||||
|
||||
|
||||
connector = &dsi_connector->base.base;
|
||||
drm_connector_init(dev, connector, &mdfld_dsi_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_LVDS);
|
||||
drm_connector_helper_add(connector, &mdfld_dsi_connector_helper_funcs);
|
||||
|
||||
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
|
||||
connector->display_info.width_mm = width_mm;
|
||||
connector->display_info.height_mm = height_mm;
|
||||
connector->interlace_allowed = false;
|
||||
connector->doublescan_allowed = false;
|
||||
|
||||
/*attach properties*/
|
||||
drm_connector_attach_property(connector,
|
||||
dev->mode_config.scaling_mode_property,
|
||||
DRM_MODE_SCALE_FULLSCREEN);
|
||||
drm_connector_attach_property(connector,
|
||||
dev_priv->backlight_property,
|
||||
MDFLD_DSI_BRIGHTNESS_MAX_LEVEL);
|
||||
|
||||
/*init DSI package sender on this output*/
|
||||
if (mdfld_dsi_pkg_sender_init(dsi_connector, pipe)) {
|
||||
DRM_ERROR("Package Sender initialization failed on pipe %d\n",
|
||||
pipe);
|
||||
goto dsi_init_err0;
|
||||
}
|
||||
|
||||
encoder = mdfld_dsi_dpi_init(dev, dsi_connector, p_vid_funcs);
|
||||
if (!encoder) {
|
||||
DRM_ERROR("Create DPI encoder failed\n");
|
||||
goto dsi_init_err1;
|
||||
}
|
||||
encoder->private = dsi_config;
|
||||
dsi_config->encoder = encoder;
|
||||
encoder->base.type = (pipe == 0) ? INTEL_OUTPUT_MIPI :
|
||||
INTEL_OUTPUT_MIPI2;
|
||||
drm_sysfs_connector_add(connector);
|
||||
return;
|
||||
|
||||
/*TODO: add code to destroy outputs on error*/
|
||||
dsi_init_err1:
|
||||
/*destroy sender*/
|
||||
mdfld_dsi_pkg_sender_destroy(dsi_connector->pkg_sender);
|
||||
|
||||
drm_connector_cleanup(connector);
|
||||
|
||||
kfree(dsi_config->fixed_mode);
|
||||
kfree(dsi_config);
|
||||
dsi_init_err0:
|
||||
kfree(dsi_connector);
|
||||
}
|
|
@ -0,0 +1,389 @@
|
|||
/*
|
||||
* Copyright © 2010 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* jim liu <jim.liu@intel.com>
|
||||
* Jackie Li<yaodong.li@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef __MDFLD_DSI_OUTPUT_H__
|
||||
#define __MDFLD_DSI_OUTPUT_H__
|
||||
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/version.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_edid.h>
|
||||
|
||||
#include "psb_drv.h"
|
||||
#include "psb_intel_drv.h"
|
||||
#include "psb_intel_reg.h"
|
||||
#include "mdfld_output.h"
|
||||
|
||||
#include <asm/mrst.h>
|
||||
|
||||
#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
|
||||
#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
|
||||
#define FLD_GET(val, start, end) (((val) & FLD_MASK(start, end)) >> (end))
|
||||
#define FLD_MOD(orig, val, start, end) \
|
||||
(((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
|
||||
|
||||
#define REG_FLD_MOD(reg, val, start, end) \
|
||||
REG_WRITE(reg, FLD_MOD(REG_READ(reg), val, start, end))
|
||||
|
||||
static inline int REGISTER_FLD_WAIT(struct drm_device *dev, u32 reg,
|
||||
u32 val, int start, int end)
|
||||
{
|
||||
int t = 100000;
|
||||
|
||||
while (FLD_GET(REG_READ(reg), start, end) != val) {
|
||||
if (--t == 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define REG_FLD_WAIT(reg, val, start, end) \
|
||||
REGISTER_FLD_WAIT(dev, reg, val, start, end)
|
||||
|
||||
#define REG_BIT_WAIT(reg, val, bitnum) \
|
||||
REGISTER_FLD_WAIT(dev, reg, val, bitnum, bitnum)
|
||||
|
||||
#define MDFLD_DSI_BRIGHTNESS_MAX_LEVEL 100
|
||||
|
||||
#ifdef DEBUG
|
||||
#define CHECK_PIPE(pipe) ({ \
|
||||
const typeof(pipe) __pipe = (pipe); \
|
||||
BUG_ON(__pipe != 0 && __pipe != 2); \
|
||||
__pipe; })
|
||||
#else
|
||||
#define CHECK_PIPE(pipe) (pipe)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Actual MIPIA->MIPIC reg offset is 0x800, value 0x400 is valid for 0 and 2
|
||||
*/
|
||||
#define REG_OFFSET(pipe) (CHECK_PIPE(pipe) * 0x400)
|
||||
|
||||
/* mdfld DSI controller registers */
|
||||
#define MIPI_DEVICE_READY_REG(pipe) (0xb000 + REG_OFFSET(pipe))
|
||||
#define MIPI_INTR_STAT_REG(pipe) (0xb004 + REG_OFFSET(pipe))
|
||||
#define MIPI_INTR_EN_REG(pipe) (0xb008 + REG_OFFSET(pipe))
|
||||
#define MIPI_DSI_FUNC_PRG_REG(pipe) (0xb00c + REG_OFFSET(pipe))
|
||||
#define MIPI_HS_TX_TIMEOUT_REG(pipe) (0xb010 + REG_OFFSET(pipe))
|
||||
#define MIPI_LP_RX_TIMEOUT_REG(pipe) (0xb014 + REG_OFFSET(pipe))
|
||||
#define MIPI_TURN_AROUND_TIMEOUT_REG(pipe) (0xb018 + REG_OFFSET(pipe))
|
||||
#define MIPI_DEVICE_RESET_TIMER_REG(pipe) (0xb01c + REG_OFFSET(pipe))
|
||||
#define MIPI_DPI_RESOLUTION_REG(pipe) (0xb020 + REG_OFFSET(pipe))
|
||||
#define MIPI_DBI_FIFO_THROTTLE_REG(pipe) (0xb024 + REG_OFFSET(pipe))
|
||||
#define MIPI_HSYNC_COUNT_REG(pipe) (0xb028 + REG_OFFSET(pipe))
|
||||
#define MIPI_HBP_COUNT_REG(pipe) (0xb02c + REG_OFFSET(pipe))
|
||||
#define MIPI_HFP_COUNT_REG(pipe) (0xb030 + REG_OFFSET(pipe))
|
||||
#define MIPI_HACTIVE_COUNT_REG(pipe) (0xb034 + REG_OFFSET(pipe))
|
||||
#define MIPI_VSYNC_COUNT_REG(pipe) (0xb038 + REG_OFFSET(pipe))
|
||||
#define MIPI_VBP_COUNT_REG(pipe) (0xb03c + REG_OFFSET(pipe))
|
||||
#define MIPI_VFP_COUNT_REG(pipe) (0xb040 + REG_OFFSET(pipe))
|
||||
#define MIPI_HIGH_LOW_SWITCH_COUNT_REG(pipe) (0xb044 + REG_OFFSET(pipe))
|
||||
#define MIPI_DPI_CONTROL_REG(pipe) (0xb048 + REG_OFFSET(pipe))
|
||||
#define MIPI_DPI_DATA_REG(pipe) (0xb04c + REG_OFFSET(pipe))
|
||||
#define MIPI_INIT_COUNT_REG(pipe) (0xb050 + REG_OFFSET(pipe))
|
||||
#define MIPI_MAX_RETURN_PACK_SIZE_REG(pipe) (0xb054 + REG_OFFSET(pipe))
|
||||
#define MIPI_VIDEO_MODE_FORMAT_REG(pipe) (0xb058 + REG_OFFSET(pipe))
|
||||
#define MIPI_EOT_DISABLE_REG(pipe) (0xb05c + REG_OFFSET(pipe))
|
||||
#define MIPI_LP_BYTECLK_REG(pipe) (0xb060 + REG_OFFSET(pipe))
|
||||
#define MIPI_LP_GEN_DATA_REG(pipe) (0xb064 + REG_OFFSET(pipe))
|
||||
#define MIPI_HS_GEN_DATA_REG(pipe) (0xb068 + REG_OFFSET(pipe))
|
||||
#define MIPI_LP_GEN_CTRL_REG(pipe) (0xb06c + REG_OFFSET(pipe))
|
||||
#define MIPI_HS_GEN_CTRL_REG(pipe) (0xb070 + REG_OFFSET(pipe))
|
||||
#define MIPI_GEN_FIFO_STAT_REG(pipe) (0xb074 + REG_OFFSET(pipe))
|
||||
#define MIPI_HS_LS_DBI_ENABLE_REG(pipe) (0xb078 + REG_OFFSET(pipe))
|
||||
#define MIPI_DPHY_PARAM_REG(pipe) (0xb080 + REG_OFFSET(pipe))
|
||||
#define MIPI_DBI_BW_CTRL_REG(pipe) (0xb084 + REG_OFFSET(pipe))
|
||||
#define MIPI_CLK_LANE_SWITCH_TIME_CNT_REG(pipe) (0xb088 + REG_OFFSET(pipe))
|
||||
|
||||
#define MIPI_CTRL_REG(pipe) (0xb104 + REG_OFFSET(pipe))
|
||||
#define MIPI_DATA_ADD_REG(pipe) (0xb108 + REG_OFFSET(pipe))
|
||||
#define MIPI_DATA_LEN_REG(pipe) (0xb10c + REG_OFFSET(pipe))
|
||||
#define MIPI_CMD_ADD_REG(pipe) (0xb110 + REG_OFFSET(pipe))
|
||||
#define MIPI_CMD_LEN_REG(pipe) (0xb114 + REG_OFFSET(pipe))
|
||||
|
||||
/* non-uniform reg offset */
|
||||
#define MIPI_PORT_CONTROL(pipe) (CHECK_PIPE(pipe) ? MIPI_C : MIPI)
|
||||
|
||||
#define DSI_DEVICE_READY (0x1)
|
||||
#define DSI_POWER_STATE_ULPS_ENTER (0x2 << 1)
|
||||
#define DSI_POWER_STATE_ULPS_EXIT (0x1 << 1)
|
||||
#define DSI_POWER_STATE_ULPS_OFFSET (0x1)
|
||||
|
||||
|
||||
#define DSI_ONE_DATA_LANE (0x1)
|
||||
#define DSI_TWO_DATA_LANE (0x2)
|
||||
#define DSI_THREE_DATA_LANE (0X3)
|
||||
#define DSI_FOUR_DATA_LANE (0x4)
|
||||
#define DSI_DPI_VIRT_CHANNEL_OFFSET (0x3)
|
||||
#define DSI_DBI_VIRT_CHANNEL_OFFSET (0x5)
|
||||
#define DSI_DPI_COLOR_FORMAT_RGB565 (0x01 << 7)
|
||||
#define DSI_DPI_COLOR_FORMAT_RGB666 (0x02 << 7)
|
||||
#define DSI_DPI_COLOR_FORMAT_RGB666_UNPACK (0x03 << 7)
|
||||
#define DSI_DPI_COLOR_FORMAT_RGB888 (0x04 << 7)
|
||||
#define DSI_DBI_COLOR_FORMAT_OPTION2 (0x05 << 13)
|
||||
|
||||
#define DSI_INTR_STATE_RXSOTERROR BIT(0)
|
||||
|
||||
#define DSI_INTR_STATE_SPL_PKG_SENT BIT(30)
|
||||
#define DSI_INTR_STATE_TE BIT(31)
|
||||
|
||||
#define DSI_HS_TX_TIMEOUT_MASK (0xffffff)
|
||||
|
||||
#define DSI_LP_RX_TIMEOUT_MASK (0xffffff)
|
||||
|
||||
#define DSI_TURN_AROUND_TIMEOUT_MASK (0x3f)
|
||||
|
||||
#define DSI_RESET_TIMER_MASK (0xffff)
|
||||
|
||||
#define DSI_DBI_FIFO_WM_HALF (0x0)
|
||||
#define DSI_DBI_FIFO_WM_QUARTER (0x1)
|
||||
#define DSI_DBI_FIFO_WM_LOW (0x2)
|
||||
|
||||
#define DSI_DPI_TIMING_MASK (0xffff)
|
||||
|
||||
#define DSI_INIT_TIMER_MASK (0xffff)
|
||||
|
||||
#define DSI_DBI_RETURN_PACK_SIZE_MASK (0x3ff)
|
||||
|
||||
#define DSI_LP_BYTECLK_MASK (0x0ffff)
|
||||
|
||||
#define DSI_HS_CTRL_GEN_SHORT_W0 (0x03)
|
||||
#define DSI_HS_CTRL_GEN_SHORT_W1 (0x13)
|
||||
#define DSI_HS_CTRL_GEN_SHORT_W2 (0x23)
|
||||
#define DSI_HS_CTRL_GEN_R0 (0x04)
|
||||
#define DSI_HS_CTRL_GEN_R1 (0x14)
|
||||
#define DSI_HS_CTRL_GEN_R2 (0x24)
|
||||
#define DSI_HS_CTRL_GEN_LONG_W (0x29)
|
||||
#define DSI_HS_CTRL_MCS_SHORT_W0 (0x05)
|
||||
#define DSI_HS_CTRL_MCS_SHORT_W1 (0x15)
|
||||
#define DSI_HS_CTRL_MCS_R0 (0x06)
|
||||
#define DSI_HS_CTRL_MCS_LONG_W (0x39)
|
||||
#define DSI_HS_CTRL_VC_OFFSET (0x06)
|
||||
#define DSI_HS_CTRL_WC_OFFSET (0x08)
|
||||
|
||||
#define DSI_FIFO_GEN_HS_DATA_FULL BIT(0)
|
||||
#define DSI_FIFO_GEN_HS_DATA_HALF_EMPTY BIT(1)
|
||||
#define DSI_FIFO_GEN_HS_DATA_EMPTY BIT(2)
|
||||
#define DSI_FIFO_GEN_LP_DATA_FULL BIT(8)
|
||||
#define DSI_FIFO_GEN_LP_DATA_HALF_EMPTY BIT(9)
|
||||
#define DSI_FIFO_GEN_LP_DATA_EMPTY BIT(10)
|
||||
#define DSI_FIFO_GEN_HS_CTRL_FULL BIT(16)
|
||||
#define DSI_FIFO_GEN_HS_CTRL_HALF_EMPTY BIT(17)
|
||||
#define DSI_FIFO_GEN_HS_CTRL_EMPTY BIT(18)
|
||||
#define DSI_FIFO_GEN_LP_CTRL_FULL BIT(24)
|
||||
#define DSI_FIFO_GEN_LP_CTRL_HALF_EMPTY BIT(25)
|
||||
#define DSI_FIFO_GEN_LP_CTRL_EMPTY BIT(26)
|
||||
#define DSI_FIFO_DBI_EMPTY BIT(27)
|
||||
#define DSI_FIFO_DPI_EMPTY BIT(28)
|
||||
|
||||
#define DSI_DBI_HS_LP_SWITCH_MASK (0x1)
|
||||
|
||||
#define DSI_HS_LP_SWITCH_COUNTER_OFFSET (0x0)
|
||||
#define DSI_LP_HS_SWITCH_COUNTER_OFFSET (0x16)
|
||||
|
||||
#define DSI_DPI_CTRL_HS_SHUTDOWN (0x00000001)
|
||||
#define DSI_DPI_CTRL_HS_TURN_ON (0x00000002)
|
||||
|
||||
/*dsi power modes*/
|
||||
#define DSI_POWER_MODE_DISPLAY_ON BIT(2)
|
||||
#define DSI_POWER_MODE_NORMAL_ON BIT(3)
|
||||
#define DSI_POWER_MODE_SLEEP_OUT BIT(4)
|
||||
#define DSI_POWER_MODE_PARTIAL_ON BIT(5)
|
||||
#define DSI_POWER_MODE_IDLE_ON BIT(6)
|
||||
|
||||
enum {
|
||||
MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE = 1,
|
||||
MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS = 2,
|
||||
MDFLD_DSI_VIDEO_BURST_MODE = 3,
|
||||
};
|
||||
|
||||
#define DSI_DPI_COMPLETE_LAST_LINE BIT(2)
|
||||
#define DSI_DPI_DISABLE_BTA BIT(3)
|
||||
|
||||
struct mdfld_dsi_connector_state {
|
||||
u32 mipi_ctrl_reg;
|
||||
};
|
||||
|
||||
struct mdfld_dsi_encoder_state {
|
||||
|
||||
};
|
||||
|
||||
struct mdfld_dsi_connector {
|
||||
struct psb_intel_connector base;
|
||||
|
||||
int pipe;
|
||||
void *private;
|
||||
void *pkg_sender;
|
||||
|
||||
/* Connection status */
|
||||
enum drm_connector_status status;
|
||||
};
|
||||
|
||||
struct mdfld_dsi_encoder {
|
||||
struct psb_intel_encoder base;
|
||||
void *private;
|
||||
};
|
||||
|
||||
/*
|
||||
* DSI config, consists of one DSI connector, two DSI encoders.
|
||||
* DRM will pick up on DSI encoder basing on differents configs.
|
||||
*/
|
||||
struct mdfld_dsi_config {
|
||||
struct drm_device *dev;
|
||||
struct drm_display_mode *fixed_mode;
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
struct mdfld_dsi_connector *connector;
|
||||
struct mdfld_dsi_encoder *encoder;
|
||||
|
||||
int changed;
|
||||
|
||||
int bpp;
|
||||
int lane_count;
|
||||
/*Virtual channel number for this encoder*/
|
||||
int channel_num;
|
||||
/*video mode configure*/
|
||||
int video_mode;
|
||||
|
||||
int dvr_ic_inited;
|
||||
};
|
||||
|
||||
static inline struct mdfld_dsi_connector *mdfld_dsi_connector(
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct psb_intel_connector *psb_connector;
|
||||
|
||||
psb_connector = to_psb_intel_connector(connector);
|
||||
|
||||
return container_of(psb_connector, struct mdfld_dsi_connector, base);
|
||||
}
|
||||
|
||||
static inline struct mdfld_dsi_encoder *mdfld_dsi_encoder(
|
||||
struct drm_encoder *encoder)
|
||||
{
|
||||
struct psb_intel_encoder *psb_encoder;
|
||||
|
||||
psb_encoder = to_psb_intel_encoder(encoder);
|
||||
|
||||
return container_of(psb_encoder, struct mdfld_dsi_encoder, base);
|
||||
}
|
||||
|
||||
static inline struct mdfld_dsi_config *
|
||||
mdfld_dsi_get_config(struct mdfld_dsi_connector *connector)
|
||||
{
|
||||
if (!connector)
|
||||
return NULL;
|
||||
return (struct mdfld_dsi_config *)connector->private;
|
||||
}
|
||||
|
||||
static inline void *mdfld_dsi_get_pkg_sender(struct mdfld_dsi_config *config)
|
||||
{
|
||||
struct mdfld_dsi_connector *dsi_connector;
|
||||
|
||||
if (!config)
|
||||
return NULL;
|
||||
|
||||
dsi_connector = config->connector;
|
||||
|
||||
if (!dsi_connector)
|
||||
return NULL;
|
||||
|
||||
return dsi_connector->pkg_sender;
|
||||
}
|
||||
|
||||
static inline struct mdfld_dsi_config *
|
||||
mdfld_dsi_encoder_get_config(struct mdfld_dsi_encoder *encoder)
|
||||
{
|
||||
if (!encoder)
|
||||
return NULL;
|
||||
return (struct mdfld_dsi_config *)encoder->private;
|
||||
}
|
||||
|
||||
static inline struct mdfld_dsi_connector *
|
||||
mdfld_dsi_encoder_get_connector(struct mdfld_dsi_encoder *encoder)
|
||||
{
|
||||
struct mdfld_dsi_config *config;
|
||||
|
||||
if (!encoder)
|
||||
return NULL;
|
||||
|
||||
config = mdfld_dsi_encoder_get_config(encoder);
|
||||
if (!config)
|
||||
return NULL;
|
||||
|
||||
return config->connector;
|
||||
}
|
||||
|
||||
static inline void *mdfld_dsi_encoder_get_pkg_sender(
|
||||
struct mdfld_dsi_encoder *encoder)
|
||||
{
|
||||
struct mdfld_dsi_config *dsi_config;
|
||||
|
||||
dsi_config = mdfld_dsi_encoder_get_config(encoder);
|
||||
if (!dsi_config)
|
||||
return NULL;
|
||||
|
||||
return mdfld_dsi_get_pkg_sender(dsi_config);
|
||||
}
|
||||
|
||||
static inline int mdfld_dsi_encoder_get_pipe(struct mdfld_dsi_encoder *encoder)
|
||||
{
|
||||
struct mdfld_dsi_connector *connector;
|
||||
|
||||
if (!encoder)
|
||||
return -1;
|
||||
|
||||
connector = mdfld_dsi_encoder_get_connector(encoder);
|
||||
if (!connector)
|
||||
return -1;
|
||||
return connector->pipe;
|
||||
}
|
||||
|
||||
/* Export functions */
|
||||
extern void mdfld_dsi_gen_fifo_ready(struct drm_device *dev,
|
||||
u32 gen_fifo_stat_reg, u32 fifo_stat);
|
||||
extern void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config,
|
||||
int pipe);
|
||||
extern void mdfld_dsi_brightness_control(struct drm_device *dev, int pipe,
|
||||
int level);
|
||||
extern void mdfld_dsi_output_init(struct drm_device *dev,
|
||||
int pipe,
|
||||
struct mdfld_dsi_config *config,
|
||||
const struct panel_funcs *p_vid_funcs);
|
||||
extern void mdfld_dsi_controller_init(struct mdfld_dsi_config *dsi_config,
|
||||
int pipe);
|
||||
|
||||
extern int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config,
|
||||
u32 *mode, bool hs);
|
||||
extern int mdfld_dsi_get_diagnostic_result(struct mdfld_dsi_config *dsi_config,
|
||||
u32 *result, bool hs);
|
||||
extern int mdfld_dsi_panel_reset(int pipe);
|
||||
|
||||
#endif /*__MDFLD_DSI_OUTPUT_H__*/
|
|
@ -0,0 +1,694 @@
|
|||
/*
|
||||
* Copyright © 2010 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Jackie Li<yaodong.li@intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/freezer.h>
|
||||
|
||||
#include "mdfld_dsi_output.h"
|
||||
#include "mdfld_dsi_pkg_sender.h"
|
||||
#include "mdfld_dsi_dpi.h"
|
||||
|
||||
#define MDFLD_DSI_READ_MAX_COUNT 5000
|
||||
|
||||
enum data_type {
|
||||
DSI_DT_GENERIC_SHORT_WRITE_0 = 0x03,
|
||||
DSI_DT_GENERIC_SHORT_WRITE_1 = 0x13,
|
||||
DSI_DT_GENERIC_SHORT_WRITE_2 = 0x23,
|
||||
DSI_DT_GENERIC_READ_0 = 0x04,
|
||||
DSI_DT_GENERIC_READ_1 = 0x14,
|
||||
DSI_DT_GENERIC_READ_2 = 0x24,
|
||||
DSI_DT_GENERIC_LONG_WRITE = 0x29,
|
||||
DSI_DT_DCS_SHORT_WRITE_0 = 0x05,
|
||||
DSI_DT_DCS_SHORT_WRITE_1 = 0x15,
|
||||
DSI_DT_DCS_READ = 0x06,
|
||||
DSI_DT_DCS_LONG_WRITE = 0x39,
|
||||
};
|
||||
|
||||
enum {
|
||||
MDFLD_DSI_PANEL_MODE_SLEEP = 0x1,
|
||||
};
|
||||
|
||||
enum {
|
||||
MDFLD_DSI_PKG_SENDER_FREE = 0x0,
|
||||
MDFLD_DSI_PKG_SENDER_BUSY = 0x1,
|
||||
};
|
||||
|
||||
static const char *const dsi_errors[] = {
|
||||
"RX SOT Error",
|
||||
"RX SOT Sync Error",
|
||||
"RX EOT Sync Error",
|
||||
"RX Escape Mode Entry Error",
|
||||
"RX LP TX Sync Error",
|
||||
"RX HS Receive Timeout Error",
|
||||
"RX False Control Error",
|
||||
"RX ECC Single Bit Error",
|
||||
"RX ECC Multibit Error",
|
||||
"RX Checksum Error",
|
||||
"RX DSI Data Type Not Recognised",
|
||||
"RX DSI VC ID Invalid",
|
||||
"TX False Control Error",
|
||||
"TX ECC Single Bit Error",
|
||||
"TX ECC Multibit Error",
|
||||
"TX Checksum Error",
|
||||
"TX DSI Data Type Not Recognised",
|
||||
"TX DSI VC ID invalid",
|
||||
"High Contention",
|
||||
"Low contention",
|
||||
"DPI FIFO Under run",
|
||||
"HS TX Timeout",
|
||||
"LP RX Timeout",
|
||||
"Turn Around ACK Timeout",
|
||||
"ACK With No Error",
|
||||
"RX Invalid TX Length",
|
||||
"RX Prot Violation",
|
||||
"HS Generic Write FIFO Full",
|
||||
"LP Generic Write FIFO Full",
|
||||
"Generic Read Data Avail"
|
||||
"Special Packet Sent",
|
||||
"Tearing Effect",
|
||||
};
|
||||
|
||||
static inline int wait_for_gen_fifo_empty(struct mdfld_dsi_pkg_sender *sender,
|
||||
u32 mask)
|
||||
{
|
||||
struct drm_device *dev = sender->dev;
|
||||
u32 gen_fifo_stat_reg = sender->mipi_gen_fifo_stat_reg;
|
||||
int retry = 0xffff;
|
||||
|
||||
while (retry--) {
|
||||
if ((mask & REG_READ(gen_fifo_stat_reg)) == mask)
|
||||
return 0;
|
||||
udelay(100);
|
||||
}
|
||||
DRM_ERROR("fifo is NOT empty 0x%08x\n", REG_READ(gen_fifo_stat_reg));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int wait_for_all_fifos_empty(struct mdfld_dsi_pkg_sender *sender)
|
||||
{
|
||||
return wait_for_gen_fifo_empty(sender, (BIT(2) | BIT(10) | BIT(18) |
|
||||
BIT(26) | BIT(27) | BIT(28)));
|
||||
}
|
||||
|
||||
static int wait_for_lp_fifos_empty(struct mdfld_dsi_pkg_sender *sender)
|
||||
{
|
||||
return wait_for_gen_fifo_empty(sender, (BIT(10) | BIT(26)));
|
||||
}
|
||||
|
||||
static int wait_for_hs_fifos_empty(struct mdfld_dsi_pkg_sender *sender)
|
||||
{
|
||||
return wait_for_gen_fifo_empty(sender, (BIT(2) | BIT(18)));
|
||||
}
|
||||
|
||||
static int handle_dsi_error(struct mdfld_dsi_pkg_sender *sender, u32 mask)
|
||||
{
|
||||
u32 intr_stat_reg = sender->mipi_intr_stat_reg;
|
||||
struct drm_device *dev = sender->dev;
|
||||
|
||||
dev_dbg(sender->dev->dev, "Handling error 0x%08x\n", mask);
|
||||
|
||||
switch (mask) {
|
||||
case BIT(0):
|
||||
case BIT(1):
|
||||
case BIT(2):
|
||||
case BIT(3):
|
||||
case BIT(4):
|
||||
case BIT(5):
|
||||
case BIT(6):
|
||||
case BIT(7):
|
||||
case BIT(8):
|
||||
case BIT(9):
|
||||
case BIT(10):
|
||||
case BIT(11):
|
||||
case BIT(12):
|
||||
case BIT(13):
|
||||
dev_dbg(sender->dev->dev, "No Action required\n");
|
||||
break;
|
||||
case BIT(14):
|
||||
/*wait for all fifo empty*/
|
||||
/*wait_for_all_fifos_empty(sender)*/;
|
||||
break;
|
||||
case BIT(15):
|
||||
dev_dbg(sender->dev->dev, "No Action required\n");
|
||||
break;
|
||||
case BIT(16):
|
||||
break;
|
||||
case BIT(17):
|
||||
break;
|
||||
case BIT(18):
|
||||
case BIT(19):
|
||||
dev_dbg(sender->dev->dev, "High/Low contention detected\n");
|
||||
/*wait for contention recovery time*/
|
||||
/*mdelay(10);*/
|
||||
/*wait for all fifo empty*/
|
||||
if (0)
|
||||
wait_for_all_fifos_empty(sender);
|
||||
break;
|
||||
case BIT(20):
|
||||
dev_dbg(sender->dev->dev, "No Action required\n");
|
||||
break;
|
||||
case BIT(21):
|
||||
/*wait for all fifo empty*/
|
||||
/*wait_for_all_fifos_empty(sender);*/
|
||||
break;
|
||||
case BIT(22):
|
||||
break;
|
||||
case BIT(23):
|
||||
case BIT(24):
|
||||
case BIT(25):
|
||||
case BIT(26):
|
||||
case BIT(27):
|
||||
dev_dbg(sender->dev->dev, "HS Gen fifo full\n");
|
||||
REG_WRITE(intr_stat_reg, mask);
|
||||
wait_for_hs_fifos_empty(sender);
|
||||
break;
|
||||
case BIT(28):
|
||||
dev_dbg(sender->dev->dev, "LP Gen fifo full\n");
|
||||
REG_WRITE(intr_stat_reg, mask);
|
||||
wait_for_lp_fifos_empty(sender);
|
||||
break;
|
||||
case BIT(29):
|
||||
case BIT(30):
|
||||
case BIT(31):
|
||||
dev_dbg(sender->dev->dev, "No Action required\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (mask & REG_READ(intr_stat_reg))
|
||||
dev_dbg(sender->dev->dev,
|
||||
"Cannot clean interrupt 0x%08x\n", mask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsi_error_handler(struct mdfld_dsi_pkg_sender *sender)
|
||||
{
|
||||
struct drm_device *dev = sender->dev;
|
||||
u32 intr_stat_reg = sender->mipi_intr_stat_reg;
|
||||
u32 mask;
|
||||
u32 intr_stat;
|
||||
int i;
|
||||
int err = 0;
|
||||
|
||||
intr_stat = REG_READ(intr_stat_reg);
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
mask = (0x00000001UL) << i;
|
||||
if (intr_stat & mask) {
|
||||
dev_dbg(sender->dev->dev, "[DSI]: %s\n", dsi_errors[i]);
|
||||
err = handle_dsi_error(sender, mask);
|
||||
if (err)
|
||||
DRM_ERROR("Cannot handle error\n");
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int send_short_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
|
||||
u8 cmd, u8 param, bool hs)
|
||||
{
|
||||
struct drm_device *dev = sender->dev;
|
||||
u32 ctrl_reg;
|
||||
u32 val;
|
||||
u8 virtual_channel = 0;
|
||||
|
||||
if (hs) {
|
||||
ctrl_reg = sender->mipi_hs_gen_ctrl_reg;
|
||||
|
||||
/* FIXME: wait_for_hs_fifos_empty(sender); */
|
||||
} else {
|
||||
ctrl_reg = sender->mipi_lp_gen_ctrl_reg;
|
||||
|
||||
/* FIXME: wait_for_lp_fifos_empty(sender); */
|
||||
}
|
||||
|
||||
val = FLD_VAL(param, 23, 16) | FLD_VAL(cmd, 15, 8) |
|
||||
FLD_VAL(virtual_channel, 7, 6) | FLD_VAL(data_type, 5, 0);
|
||||
|
||||
REG_WRITE(ctrl_reg, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_long_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
|
||||
u8 *data, int len, bool hs)
|
||||
{
|
||||
struct drm_device *dev = sender->dev;
|
||||
u32 ctrl_reg;
|
||||
u32 data_reg;
|
||||
u32 val;
|
||||
u8 *p;
|
||||
u8 b1, b2, b3, b4;
|
||||
u8 virtual_channel = 0;
|
||||
int i;
|
||||
|
||||
if (hs) {
|
||||
ctrl_reg = sender->mipi_hs_gen_ctrl_reg;
|
||||
data_reg = sender->mipi_hs_gen_data_reg;
|
||||
|
||||
/* FIXME: wait_for_hs_fifos_empty(sender); */
|
||||
} else {
|
||||
ctrl_reg = sender->mipi_lp_gen_ctrl_reg;
|
||||
data_reg = sender->mipi_lp_gen_data_reg;
|
||||
|
||||
/* FIXME: wait_for_lp_fifos_empty(sender); */
|
||||
}
|
||||
|
||||
p = data;
|
||||
for (i = 0; i < len / 4; i++) {
|
||||
b1 = *p++;
|
||||
b2 = *p++;
|
||||
b3 = *p++;
|
||||
b4 = *p++;
|
||||
|
||||
REG_WRITE(data_reg, b4 << 24 | b3 << 16 | b2 << 8 | b1);
|
||||
}
|
||||
|
||||
i = len % 4;
|
||||
if (i) {
|
||||
b1 = 0; b2 = 0; b3 = 0;
|
||||
|
||||
switch (i) {
|
||||
case 3:
|
||||
b1 = *p++;
|
||||
b2 = *p++;
|
||||
b3 = *p++;
|
||||
break;
|
||||
case 2:
|
||||
b1 = *p++;
|
||||
b2 = *p++;
|
||||
break;
|
||||
case 1:
|
||||
b1 = *p++;
|
||||
break;
|
||||
}
|
||||
|
||||
REG_WRITE(data_reg, b3 << 16 | b2 << 8 | b1);
|
||||
}
|
||||
|
||||
val = FLD_VAL(len, 23, 8) | FLD_VAL(virtual_channel, 7, 6) |
|
||||
FLD_VAL(data_type, 5, 0);
|
||||
|
||||
REG_WRITE(ctrl_reg, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_pkg_prepare(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
|
||||
u8 *data, u16 len)
|
||||
{
|
||||
u8 cmd;
|
||||
|
||||
switch (data_type) {
|
||||
case DSI_DT_DCS_SHORT_WRITE_0:
|
||||
case DSI_DT_DCS_SHORT_WRITE_1:
|
||||
case DSI_DT_DCS_LONG_WRITE:
|
||||
cmd = *data;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*this prevents other package sending while doing msleep*/
|
||||
sender->status = MDFLD_DSI_PKG_SENDER_BUSY;
|
||||
|
||||
/*wait for 120 milliseconds in case exit_sleep_mode just be sent*/
|
||||
if (unlikely(cmd == DCS_ENTER_SLEEP_MODE)) {
|
||||
/*TODO: replace it with msleep later*/
|
||||
mdelay(120);
|
||||
}
|
||||
|
||||
if (unlikely(cmd == DCS_EXIT_SLEEP_MODE)) {
|
||||
/*TODO: replace it with msleep later*/
|
||||
mdelay(120);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_pkg_done(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
|
||||
u8 *data, u16 len)
|
||||
{
|
||||
u8 cmd;
|
||||
|
||||
switch (data_type) {
|
||||
case DSI_DT_DCS_SHORT_WRITE_0:
|
||||
case DSI_DT_DCS_SHORT_WRITE_1:
|
||||
case DSI_DT_DCS_LONG_WRITE:
|
||||
cmd = *data;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*update panel status*/
|
||||
if (unlikely(cmd == DCS_ENTER_SLEEP_MODE)) {
|
||||
sender->panel_mode |= MDFLD_DSI_PANEL_MODE_SLEEP;
|
||||
/*TODO: replace it with msleep later*/
|
||||
mdelay(120);
|
||||
} else if (unlikely(cmd == DCS_EXIT_SLEEP_MODE)) {
|
||||
sender->panel_mode &= ~MDFLD_DSI_PANEL_MODE_SLEEP;
|
||||
/*TODO: replace it with msleep later*/
|
||||
mdelay(120);
|
||||
} else if (unlikely(cmd == DCS_SOFT_RESET)) {
|
||||
/*TODO: replace it with msleep later*/
|
||||
mdelay(5);
|
||||
}
|
||||
|
||||
sender->status = MDFLD_DSI_PKG_SENDER_FREE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
|
||||
u8 *data, u16 len, bool hs)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*handle DSI error*/
|
||||
ret = dsi_error_handler(sender);
|
||||
if (ret) {
|
||||
DRM_ERROR("Error handling failed\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/* send pkg */
|
||||
if (sender->status == MDFLD_DSI_PKG_SENDER_BUSY) {
|
||||
DRM_ERROR("sender is busy\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
ret = send_pkg_prepare(sender, data_type, data, len);
|
||||
if (ret) {
|
||||
DRM_ERROR("send_pkg_prepare error\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (data_type) {
|
||||
case DSI_DT_GENERIC_SHORT_WRITE_0:
|
||||
case DSI_DT_GENERIC_SHORT_WRITE_1:
|
||||
case DSI_DT_GENERIC_SHORT_WRITE_2:
|
||||
case DSI_DT_GENERIC_READ_0:
|
||||
case DSI_DT_GENERIC_READ_1:
|
||||
case DSI_DT_GENERIC_READ_2:
|
||||
case DSI_DT_DCS_SHORT_WRITE_0:
|
||||
case DSI_DT_DCS_SHORT_WRITE_1:
|
||||
case DSI_DT_DCS_READ:
|
||||
ret = send_short_pkg(sender, data_type, data[0], data[1], hs);
|
||||
break;
|
||||
case DSI_DT_GENERIC_LONG_WRITE:
|
||||
case DSI_DT_DCS_LONG_WRITE:
|
||||
ret = send_long_pkg(sender, data_type, data, len, hs);
|
||||
break;
|
||||
}
|
||||
|
||||
send_pkg_done(sender, data_type, data, len);
|
||||
|
||||
/*FIXME: should I query complete and fifo empty here?*/
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mdfld_dsi_send_mcs_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
|
||||
u32 len, bool hs)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!sender || !data || !len) {
|
||||
DRM_ERROR("Invalid parameters\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sender->lock, flags);
|
||||
send_pkg(sender, DSI_DT_DCS_LONG_WRITE, data, len, hs);
|
||||
spin_unlock_irqrestore(&sender->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdfld_dsi_send_mcs_short(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
|
||||
u8 param, u8 param_num, bool hs)
|
||||
{
|
||||
u8 data[2];
|
||||
unsigned long flags;
|
||||
u8 data_type;
|
||||
|
||||
if (!sender) {
|
||||
DRM_ERROR("Invalid parameter\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
data[0] = cmd;
|
||||
|
||||
if (param_num) {
|
||||
data_type = DSI_DT_DCS_SHORT_WRITE_1;
|
||||
data[1] = param;
|
||||
} else {
|
||||
data_type = DSI_DT_DCS_SHORT_WRITE_0;
|
||||
data[1] = 0;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sender->lock, flags);
|
||||
send_pkg(sender, data_type, data, sizeof(data), hs);
|
||||
spin_unlock_irqrestore(&sender->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdfld_dsi_send_gen_short(struct mdfld_dsi_pkg_sender *sender, u8 param0,
|
||||
u8 param1, u8 param_num, bool hs)
|
||||
{
|
||||
u8 data[2];
|
||||
unsigned long flags;
|
||||
u8 data_type;
|
||||
|
||||
if (!sender || param_num < 0 || param_num > 2) {
|
||||
DRM_ERROR("Invalid parameter\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (param_num) {
|
||||
case 0:
|
||||
data_type = DSI_DT_GENERIC_SHORT_WRITE_0;
|
||||
data[0] = 0;
|
||||
data[1] = 0;
|
||||
break;
|
||||
case 1:
|
||||
data_type = DSI_DT_GENERIC_SHORT_WRITE_1;
|
||||
data[0] = param0;
|
||||
data[1] = 0;
|
||||
break;
|
||||
case 2:
|
||||
data_type = DSI_DT_GENERIC_SHORT_WRITE_2;
|
||||
data[0] = param0;
|
||||
data[1] = param1;
|
||||
break;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sender->lock, flags);
|
||||
send_pkg(sender, data_type, data, sizeof(data), hs);
|
||||
spin_unlock_irqrestore(&sender->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdfld_dsi_send_gen_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
|
||||
u32 len, bool hs)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!sender || !data || !len) {
|
||||
DRM_ERROR("Invalid parameters\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sender->lock, flags);
|
||||
send_pkg(sender, DSI_DT_GENERIC_LONG_WRITE, data, len, hs);
|
||||
spin_unlock_irqrestore(&sender->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __read_panel_data(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
|
||||
u8 *data, u16 len, u32 *data_out, u16 len_out, bool hs)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct drm_device *dev = sender->dev;
|
||||
int i;
|
||||
u32 gen_data_reg;
|
||||
int retry = MDFLD_DSI_READ_MAX_COUNT;
|
||||
|
||||
if (!sender || !data_out || !len_out) {
|
||||
DRM_ERROR("Invalid parameters\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* do reading.
|
||||
* 0) send out generic read request
|
||||
* 1) polling read data avail interrupt
|
||||
* 2) read data
|
||||
*/
|
||||
spin_lock_irqsave(&sender->lock, flags);
|
||||
|
||||
REG_WRITE(sender->mipi_intr_stat_reg, BIT(29));
|
||||
|
||||
if ((REG_READ(sender->mipi_intr_stat_reg) & BIT(29)))
|
||||
DRM_ERROR("Can NOT clean read data valid interrupt\n");
|
||||
|
||||
/*send out read request*/
|
||||
send_pkg(sender, data_type, data, len, hs);
|
||||
|
||||
/*polling read data avail interrupt*/
|
||||
while (retry && !(REG_READ(sender->mipi_intr_stat_reg) & BIT(29))) {
|
||||
udelay(100);
|
||||
retry--;
|
||||
}
|
||||
|
||||
if (!retry) {
|
||||
spin_unlock_irqrestore(&sender->lock, flags);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
REG_WRITE(sender->mipi_intr_stat_reg, BIT(29));
|
||||
|
||||
/*read data*/
|
||||
if (hs)
|
||||
gen_data_reg = sender->mipi_hs_gen_data_reg;
|
||||
else
|
||||
gen_data_reg = sender->mipi_lp_gen_data_reg;
|
||||
|
||||
for (i = 0; i < len_out; i++)
|
||||
*(data_out + i) = REG_READ(gen_data_reg);
|
||||
|
||||
spin_unlock_irqrestore(&sender->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdfld_dsi_read_mcs(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
|
||||
u32 *data, u16 len, bool hs)
|
||||
{
|
||||
if (!sender || !data || !len) {
|
||||
DRM_ERROR("Invalid parameters\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return __read_panel_data(sender, DSI_DT_DCS_READ, &cmd, 1,
|
||||
data, len, hs);
|
||||
}
|
||||
|
||||
int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector,
|
||||
int pipe)
|
||||
{
|
||||
struct mdfld_dsi_pkg_sender *pkg_sender;
|
||||
struct mdfld_dsi_config *dsi_config =
|
||||
mdfld_dsi_get_config(dsi_connector);
|
||||
struct drm_device *dev = dsi_config->dev;
|
||||
u32 mipi_val = 0;
|
||||
|
||||
if (!dsi_connector) {
|
||||
DRM_ERROR("Invalid parameter\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pkg_sender = dsi_connector->pkg_sender;
|
||||
|
||||
if (!pkg_sender || IS_ERR(pkg_sender)) {
|
||||
pkg_sender = kzalloc(sizeof(struct mdfld_dsi_pkg_sender),
|
||||
GFP_KERNEL);
|
||||
if (!pkg_sender) {
|
||||
DRM_ERROR("Create DSI pkg sender failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
dsi_connector->pkg_sender = (void *)pkg_sender;
|
||||
}
|
||||
|
||||
pkg_sender->dev = dev;
|
||||
pkg_sender->dsi_connector = dsi_connector;
|
||||
pkg_sender->pipe = pipe;
|
||||
pkg_sender->pkg_num = 0;
|
||||
pkg_sender->panel_mode = 0;
|
||||
pkg_sender->status = MDFLD_DSI_PKG_SENDER_FREE;
|
||||
|
||||
/*init regs*/
|
||||
if (pipe == 0) {
|
||||
pkg_sender->dpll_reg = MRST_DPLL_A;
|
||||
pkg_sender->dspcntr_reg = DSPACNTR;
|
||||
pkg_sender->pipeconf_reg = PIPEACONF;
|
||||
pkg_sender->dsplinoff_reg = DSPALINOFF;
|
||||
pkg_sender->dspsurf_reg = DSPASURF;
|
||||
pkg_sender->pipestat_reg = PIPEASTAT;
|
||||
} else if (pipe == 2) {
|
||||
pkg_sender->dpll_reg = MRST_DPLL_A;
|
||||
pkg_sender->dspcntr_reg = DSPCCNTR;
|
||||
pkg_sender->pipeconf_reg = PIPECCONF;
|
||||
pkg_sender->dsplinoff_reg = DSPCLINOFF;
|
||||
pkg_sender->dspsurf_reg = DSPCSURF;
|
||||
pkg_sender->pipestat_reg = PIPECSTAT;
|
||||
}
|
||||
|
||||
pkg_sender->mipi_intr_stat_reg = MIPI_INTR_STAT_REG(pipe);
|
||||
pkg_sender->mipi_lp_gen_data_reg = MIPI_LP_GEN_DATA_REG(pipe);
|
||||
pkg_sender->mipi_hs_gen_data_reg = MIPI_HS_GEN_DATA_REG(pipe);
|
||||
pkg_sender->mipi_lp_gen_ctrl_reg = MIPI_LP_GEN_CTRL_REG(pipe);
|
||||
pkg_sender->mipi_hs_gen_ctrl_reg = MIPI_HS_GEN_CTRL_REG(pipe);
|
||||
pkg_sender->mipi_gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe);
|
||||
pkg_sender->mipi_data_addr_reg = MIPI_DATA_ADD_REG(pipe);
|
||||
pkg_sender->mipi_data_len_reg = MIPI_DATA_LEN_REG(pipe);
|
||||
pkg_sender->mipi_cmd_addr_reg = MIPI_CMD_ADD_REG(pipe);
|
||||
pkg_sender->mipi_cmd_len_reg = MIPI_CMD_LEN_REG(pipe);
|
||||
|
||||
/*init lock*/
|
||||
spin_lock_init(&pkg_sender->lock);
|
||||
|
||||
if (mdfld_get_panel_type(dev, pipe) != TC35876X) {
|
||||
/**
|
||||
* For video mode, don't enable DPI timing output here,
|
||||
* will init the DPI timing output during mode setting.
|
||||
*/
|
||||
mipi_val = PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX;
|
||||
|
||||
if (pipe == 0)
|
||||
mipi_val |= 0x2;
|
||||
|
||||
REG_WRITE(MIPI_PORT_CONTROL(pipe), mipi_val);
|
||||
REG_READ(MIPI_PORT_CONTROL(pipe));
|
||||
|
||||
/* do dsi controller init */
|
||||
mdfld_dsi_controller_init(dsi_config, pipe);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender)
|
||||
{
|
||||
if (!sender || IS_ERR(sender))
|
||||
return;
|
||||
|
||||
/*free*/
|
||||
kfree(sender);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright © 2010 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Jackie Li<yaodong.li@intel.com>
|
||||
*/
|
||||
#ifndef __MDFLD_DSI_PKG_SENDER_H__
|
||||
#define __MDFLD_DSI_PKG_SENDER_H__
|
||||
|
||||
#include <linux/kthread.h>
|
||||
|
||||
#define MDFLD_MAX_DCS_PARAM 8
|
||||
|
||||
struct mdfld_dsi_pkg_sender {
|
||||
struct drm_device *dev;
|
||||
struct mdfld_dsi_connector *dsi_connector;
|
||||
u32 status;
|
||||
u32 panel_mode;
|
||||
|
||||
int pipe;
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
u32 pkg_num;
|
||||
|
||||
/* Registers */
|
||||
u32 dpll_reg;
|
||||
u32 dspcntr_reg;
|
||||
u32 pipeconf_reg;
|
||||
u32 pipestat_reg;
|
||||
u32 dsplinoff_reg;
|
||||
u32 dspsurf_reg;
|
||||
|
||||
u32 mipi_intr_stat_reg;
|
||||
u32 mipi_lp_gen_data_reg;
|
||||
u32 mipi_hs_gen_data_reg;
|
||||
u32 mipi_lp_gen_ctrl_reg;
|
||||
u32 mipi_hs_gen_ctrl_reg;
|
||||
u32 mipi_gen_fifo_stat_reg;
|
||||
u32 mipi_data_addr_reg;
|
||||
u32 mipi_data_len_reg;
|
||||
u32 mipi_cmd_addr_reg;
|
||||
u32 mipi_cmd_len_reg;
|
||||
};
|
||||
|
||||
/* DCS definitions */
|
||||
#define DCS_SOFT_RESET 0x01
|
||||
#define DCS_ENTER_SLEEP_MODE 0x10
|
||||
#define DCS_EXIT_SLEEP_MODE 0x11
|
||||
#define DCS_SET_DISPLAY_OFF 0x28
|
||||
#define DCS_SET_DISPLAY_ON 0x29
|
||||
#define DCS_SET_COLUMN_ADDRESS 0x2a
|
||||
#define DCS_SET_PAGE_ADDRESS 0x2b
|
||||
#define DCS_WRITE_MEM_START 0x2c
|
||||
#define DCS_SET_TEAR_OFF 0x34
|
||||
#define DCS_SET_TEAR_ON 0x35
|
||||
|
||||
extern int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector,
|
||||
int pipe);
|
||||
extern void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender);
|
||||
int mdfld_dsi_send_mcs_short(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
|
||||
u8 param, u8 param_num, bool hs);
|
||||
int mdfld_dsi_send_mcs_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
|
||||
u32 len, bool hs);
|
||||
int mdfld_dsi_send_gen_short(struct mdfld_dsi_pkg_sender *sender, u8 param0,
|
||||
u8 param1, u8 param_num, bool hs);
|
||||
int mdfld_dsi_send_gen_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
|
||||
u32 len, bool hs);
|
||||
/* Read interfaces */
|
||||
int mdfld_dsi_read_mcs(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
|
||||
u32 *data, u16 len, bool hs);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2010 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicensen
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Thomas Eaton <thomas.g.eaton@intel.com>
|
||||
* Scott Rowe <scott.m.rowe@intel.com>
|
||||
*/
|
||||
|
||||
#include "mdfld_output.h"
|
||||
#include "mdfld_dsi_dpi.h"
|
||||
#include "mdfld_dsi_output.h"
|
||||
|
||||
#include "tc35876x-dsi-lvds.h"
|
||||
|
||||
int mdfld_get_panel_type(struct drm_device *dev, int pipe)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
return dev_priv->mdfld_panel_id;
|
||||
}
|
||||
|
||||
static void mdfld_init_panel(struct drm_device *dev, int mipi_pipe,
|
||||
int p_type)
|
||||
{
|
||||
switch (p_type) {
|
||||
case TPO_VID:
|
||||
mdfld_dsi_output_init(dev, mipi_pipe, NULL,
|
||||
&mdfld_tpo_vid_funcs);
|
||||
break;
|
||||
case TC35876X:
|
||||
tc35876x_init(dev);
|
||||
mdfld_dsi_output_init(dev, mipi_pipe, NULL,
|
||||
&mdfld_tc35876x_funcs);
|
||||
break;
|
||||
case TMD_VID:
|
||||
mdfld_dsi_output_init(dev, mipi_pipe, NULL,
|
||||
&mdfld_tmd_vid_funcs);
|
||||
break;
|
||||
case HDMI:
|
||||
/* if (dev_priv->mdfld_hdmi_present)
|
||||
mdfld_hdmi_init(dev, &dev_priv->mode_dev); */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int mdfld_output_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
|
||||
/* FIXME: hardcoded for now */
|
||||
dev_priv->mdfld_panel_id = TC35876X;
|
||||
/* MIPI panel 1 */
|
||||
mdfld_init_panel(dev, 0, dev_priv->mdfld_panel_id);
|
||||
/* HDMI panel */
|
||||
mdfld_init_panel(dev, 1, HDMI);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2010 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicensen
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Thomas Eaton <thomas.g.eaton@intel.com>
|
||||
* Scott Rowe <scott.m.rowe@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef MDFLD_OUTPUT_H
|
||||
#define MDFLD_OUTPUT_H
|
||||
|
||||
#include "psb_drv.h"
|
||||
|
||||
#define TPO_PANEL_WIDTH 84
|
||||
#define TPO_PANEL_HEIGHT 46
|
||||
#define TMD_PANEL_WIDTH 39
|
||||
#define TMD_PANEL_HEIGHT 71
|
||||
|
||||
struct mdfld_dsi_config;
|
||||
|
||||
enum panel_type {
|
||||
TPO_VID,
|
||||
TMD_VID,
|
||||
HDMI,
|
||||
TC35876X,
|
||||
};
|
||||
|
||||
struct panel_info {
|
||||
u32 width_mm;
|
||||
u32 height_mm;
|
||||
/* Other info */
|
||||
};
|
||||
|
||||
struct panel_funcs {
|
||||
const struct drm_encoder_funcs *encoder_funcs;
|
||||
const struct drm_encoder_helper_funcs *encoder_helper_funcs;
|
||||
struct drm_display_mode * (*get_config_mode)(struct drm_device *);
|
||||
int (*get_panel_info)(struct drm_device *, int, struct panel_info *);
|
||||
int (*reset)(int pipe);
|
||||
void (*drv_ic_init)(struct mdfld_dsi_config *dsi_config, int pipe);
|
||||
};
|
||||
|
||||
int mdfld_output_init(struct drm_device *dev);
|
||||
|
||||
struct backlight_device *mdfld_get_backlight_device(void);
|
||||
int mdfld_set_brightness(struct backlight_device *bd);
|
||||
|
||||
int mdfld_get_panel_type(struct drm_device *dev, int pipe);
|
||||
|
||||
extern const struct drm_crtc_helper_funcs mdfld_helper_funcs;
|
||||
|
||||
extern const struct panel_funcs mdfld_tmd_vid_funcs;
|
||||
extern const struct panel_funcs mdfld_tpo_vid_funcs;
|
||||
|
||||
extern void mdfld_disable_crtc(struct drm_device *dev, int pipe);
|
||||
extern void mdfldWaitForPipeEnable(struct drm_device *dev, int pipe);
|
||||
extern void mdfldWaitForPipeDisable(struct drm_device *dev, int pipe);
|
||||
#endif
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Copyright © 2010 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Jim Liu <jim.liu@intel.com>
|
||||
* Jackie Li<yaodong.li@intel.com>
|
||||
* Gideon Eaton <eaton.
|
||||
* Scott Rowe <scott.m.rowe@intel.com>
|
||||
*/
|
||||
|
||||
#include "mdfld_dsi_dpi.h"
|
||||
#include "mdfld_dsi_pkg_sender.h"
|
||||
|
||||
static struct drm_display_mode *tmd_vid_get_config_mode(struct drm_device *dev)
|
||||
{
|
||||
struct drm_display_mode *mode;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD;
|
||||
bool use_gct = false; /*Disable GCT for now*/
|
||||
|
||||
mode = kzalloc(sizeof(*mode), GFP_KERNEL);
|
||||
if (!mode)
|
||||
return NULL;
|
||||
|
||||
if (use_gct) {
|
||||
mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo;
|
||||
mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo;
|
||||
mode->hsync_start = mode->hdisplay + \
|
||||
((ti->hsync_offset_hi << 8) | \
|
||||
ti->hsync_offset_lo);
|
||||
mode->hsync_end = mode->hsync_start + \
|
||||
((ti->hsync_pulse_width_hi << 8) | \
|
||||
ti->hsync_pulse_width_lo);
|
||||
mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) | \
|
||||
ti->hblank_lo);
|
||||
mode->vsync_start = \
|
||||
mode->vdisplay + ((ti->vsync_offset_hi << 8) | \
|
||||
ti->vsync_offset_lo);
|
||||
mode->vsync_end = \
|
||||
mode->vsync_start + ((ti->vsync_pulse_width_hi << 8) | \
|
||||
ti->vsync_pulse_width_lo);
|
||||
mode->vtotal = mode->vdisplay + \
|
||||
((ti->vblank_hi << 8) | ti->vblank_lo);
|
||||
mode->clock = ti->pixel_clock * 10;
|
||||
|
||||
dev_dbg(dev->dev, "hdisplay is %d\n", mode->hdisplay);
|
||||
dev_dbg(dev->dev, "vdisplay is %d\n", mode->vdisplay);
|
||||
dev_dbg(dev->dev, "HSS is %d\n", mode->hsync_start);
|
||||
dev_dbg(dev->dev, "HSE is %d\n", mode->hsync_end);
|
||||
dev_dbg(dev->dev, "htotal is %d\n", mode->htotal);
|
||||
dev_dbg(dev->dev, "VSS is %d\n", mode->vsync_start);
|
||||
dev_dbg(dev->dev, "VSE is %d\n", mode->vsync_end);
|
||||
dev_dbg(dev->dev, "vtotal is %d\n", mode->vtotal);
|
||||
dev_dbg(dev->dev, "clock is %d\n", mode->clock);
|
||||
} else {
|
||||
mode->hdisplay = 480;
|
||||
mode->vdisplay = 854;
|
||||
mode->hsync_start = 487;
|
||||
mode->hsync_end = 490;
|
||||
mode->htotal = 499;
|
||||
mode->vsync_start = 861;
|
||||
mode->vsync_end = 865;
|
||||
mode->vtotal = 873;
|
||||
mode->clock = 33264;
|
||||
}
|
||||
|
||||
drm_mode_set_name(mode);
|
||||
drm_mode_set_crtcinfo(mode, 0);
|
||||
|
||||
mode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
static int tmd_vid_get_panel_info(struct drm_device *dev,
|
||||
int pipe,
|
||||
struct panel_info *pi)
|
||||
{
|
||||
if (!dev || !pi)
|
||||
return -EINVAL;
|
||||
|
||||
pi->width_mm = TMD_PANEL_WIDTH;
|
||||
pi->height_mm = TMD_PANEL_HEIGHT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ************************************************************************* *\
|
||||
* FUNCTION: mdfld_init_TMD_MIPI
|
||||
*
|
||||
* DESCRIPTION: This function is called only by mrst_dsi_mode_set and
|
||||
* restore_display_registers. since this function does not
|
||||
* acquire the mutex, it is important that the calling function
|
||||
* does!
|
||||
\* ************************************************************************* */
|
||||
|
||||
/* FIXME: make the below data u8 instead of u32; note byte order! */
|
||||
static u32 tmd_cmd_mcap_off[] = {0x000000b2};
|
||||
static u32 tmd_cmd_enable_lane_switch[] = {0x000101ef};
|
||||
static u32 tmd_cmd_set_lane_num[] = {0x006360ef};
|
||||
static u32 tmd_cmd_pushing_clock0[] = {0x00cc2fef};
|
||||
static u32 tmd_cmd_pushing_clock1[] = {0x00dd6eef};
|
||||
static u32 tmd_cmd_set_mode[] = {0x000000b3};
|
||||
static u32 tmd_cmd_set_sync_pulse_mode[] = {0x000961ef};
|
||||
static u32 tmd_cmd_set_column[] = {0x0100002a, 0x000000df};
|
||||
static u32 tmd_cmd_set_page[] = {0x0300002b, 0x00000055};
|
||||
static u32 tmd_cmd_set_video_mode[] = {0x00000153};
|
||||
/*no auto_bl,need add in furture*/
|
||||
static u32 tmd_cmd_enable_backlight[] = {0x00005ab4};
|
||||
static u32 tmd_cmd_set_backlight_dimming[] = {0x00000ebd};
|
||||
|
||||
static void mdfld_dsi_tmd_drv_ic_init(struct mdfld_dsi_config *dsi_config,
|
||||
int pipe)
|
||||
{
|
||||
struct mdfld_dsi_pkg_sender *sender
|
||||
= mdfld_dsi_get_pkg_sender(dsi_config);
|
||||
|
||||
DRM_INFO("Enter mdfld init TMD MIPI display.\n");
|
||||
|
||||
if (!sender) {
|
||||
DRM_ERROR("Cannot get sender\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dsi_config->dvr_ic_inited)
|
||||
return;
|
||||
|
||||
msleep(3);
|
||||
|
||||
/* FIXME: make the below data u8 instead of u32; note byte order! */
|
||||
|
||||
mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_mcap_off,
|
||||
sizeof(tmd_cmd_mcap_off), false);
|
||||
mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_enable_lane_switch,
|
||||
sizeof(tmd_cmd_enable_lane_switch), false);
|
||||
mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_lane_num,
|
||||
sizeof(tmd_cmd_set_lane_num), false);
|
||||
mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_pushing_clock0,
|
||||
sizeof(tmd_cmd_pushing_clock0), false);
|
||||
mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_pushing_clock1,
|
||||
sizeof(tmd_cmd_pushing_clock1), false);
|
||||
mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_mode,
|
||||
sizeof(tmd_cmd_set_mode), false);
|
||||
mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_sync_pulse_mode,
|
||||
sizeof(tmd_cmd_set_sync_pulse_mode), false);
|
||||
mdfld_dsi_send_mcs_long(sender, (u8 *) tmd_cmd_set_column,
|
||||
sizeof(tmd_cmd_set_column), false);
|
||||
mdfld_dsi_send_mcs_long(sender, (u8 *) tmd_cmd_set_page,
|
||||
sizeof(tmd_cmd_set_page), false);
|
||||
mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_video_mode,
|
||||
sizeof(tmd_cmd_set_video_mode), false);
|
||||
mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_enable_backlight,
|
||||
sizeof(tmd_cmd_enable_backlight), false);
|
||||
mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_backlight_dimming,
|
||||
sizeof(tmd_cmd_set_backlight_dimming), false);
|
||||
|
||||
dsi_config->dvr_ic_inited = 1;
|
||||
}
|
||||
|
||||
/*TPO DPI encoder helper funcs*/
|
||||
static const struct drm_encoder_helper_funcs
|
||||
mdfld_tpo_dpi_encoder_helper_funcs = {
|
||||
.dpms = mdfld_dsi_dpi_dpms,
|
||||
.mode_fixup = mdfld_dsi_dpi_mode_fixup,
|
||||
.prepare = mdfld_dsi_dpi_prepare,
|
||||
.mode_set = mdfld_dsi_dpi_mode_set,
|
||||
.commit = mdfld_dsi_dpi_commit,
|
||||
};
|
||||
|
||||
/*TPO DPI encoder funcs*/
|
||||
static const struct drm_encoder_funcs mdfld_tpo_dpi_encoder_funcs = {
|
||||
.destroy = drm_encoder_cleanup,
|
||||
};
|
||||
|
||||
const struct panel_funcs mdfld_tmd_vid_funcs = {
|
||||
.encoder_funcs = &mdfld_tpo_dpi_encoder_funcs,
|
||||
.encoder_helper_funcs = &mdfld_tpo_dpi_encoder_helper_funcs,
|
||||
.get_config_mode = &tmd_vid_get_config_mode,
|
||||
.get_panel_info = tmd_vid_get_panel_info,
|
||||
.reset = mdfld_dsi_panel_reset,
|
||||
.drv_ic_init = mdfld_dsi_tmd_drv_ic_init,
|
||||
};
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright © 2010 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* jim liu <jim.liu@intel.com>
|
||||
* Jackie Li<yaodong.li@intel.com>
|
||||
*/
|
||||
|
||||
#include "mdfld_dsi_dpi.h"
|
||||
|
||||
static struct drm_display_mode *tpo_vid_get_config_mode(struct drm_device *dev)
|
||||
{
|
||||
struct drm_display_mode *mode;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD;
|
||||
bool use_gct = false;
|
||||
|
||||
mode = kzalloc(sizeof(*mode), GFP_KERNEL);
|
||||
if (!mode)
|
||||
return NULL;
|
||||
|
||||
if (use_gct) {
|
||||
mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo;
|
||||
mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo;
|
||||
mode->hsync_start = mode->hdisplay +
|
||||
((ti->hsync_offset_hi << 8) |
|
||||
ti->hsync_offset_lo);
|
||||
mode->hsync_end = mode->hsync_start +
|
||||
((ti->hsync_pulse_width_hi << 8) |
|
||||
ti->hsync_pulse_width_lo);
|
||||
mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) |
|
||||
ti->hblank_lo);
|
||||
mode->vsync_start =
|
||||
mode->vdisplay + ((ti->vsync_offset_hi << 8) |
|
||||
ti->vsync_offset_lo);
|
||||
mode->vsync_end =
|
||||
mode->vsync_start + ((ti->vsync_pulse_width_hi << 8) |
|
||||
ti->vsync_pulse_width_lo);
|
||||
mode->vtotal = mode->vdisplay +
|
||||
((ti->vblank_hi << 8) | ti->vblank_lo);
|
||||
mode->clock = ti->pixel_clock * 10;
|
||||
|
||||
dev_dbg(dev->dev, "hdisplay is %d\n", mode->hdisplay);
|
||||
dev_dbg(dev->dev, "vdisplay is %d\n", mode->vdisplay);
|
||||
dev_dbg(dev->dev, "HSS is %d\n", mode->hsync_start);
|
||||
dev_dbg(dev->dev, "HSE is %d\n", mode->hsync_end);
|
||||
dev_dbg(dev->dev, "htotal is %d\n", mode->htotal);
|
||||
dev_dbg(dev->dev, "VSS is %d\n", mode->vsync_start);
|
||||
dev_dbg(dev->dev, "VSE is %d\n", mode->vsync_end);
|
||||
dev_dbg(dev->dev, "vtotal is %d\n", mode->vtotal);
|
||||
dev_dbg(dev->dev, "clock is %d\n", mode->clock);
|
||||
} else {
|
||||
mode->hdisplay = 864;
|
||||
mode->vdisplay = 480;
|
||||
mode->hsync_start = 873;
|
||||
mode->hsync_end = 876;
|
||||
mode->htotal = 887;
|
||||
mode->vsync_start = 487;
|
||||
mode->vsync_end = 490;
|
||||
mode->vtotal = 499;
|
||||
mode->clock = 33264;
|
||||
}
|
||||
|
||||
drm_mode_set_name(mode);
|
||||
drm_mode_set_crtcinfo(mode, 0);
|
||||
|
||||
mode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
static int tpo_vid_get_panel_info(struct drm_device *dev,
|
||||
int pipe,
|
||||
struct panel_info *pi)
|
||||
{
|
||||
if (!dev || !pi)
|
||||
return -EINVAL;
|
||||
|
||||
pi->width_mm = TPO_PANEL_WIDTH;
|
||||
pi->height_mm = TPO_PANEL_HEIGHT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*TPO DPI encoder helper funcs*/
|
||||
static const struct drm_encoder_helper_funcs
|
||||
mdfld_tpo_dpi_encoder_helper_funcs = {
|
||||
.dpms = mdfld_dsi_dpi_dpms,
|
||||
.mode_fixup = mdfld_dsi_dpi_mode_fixup,
|
||||
.prepare = mdfld_dsi_dpi_prepare,
|
||||
.mode_set = mdfld_dsi_dpi_mode_set,
|
||||
.commit = mdfld_dsi_dpi_commit,
|
||||
};
|
||||
|
||||
/*TPO DPI encoder funcs*/
|
||||
static const struct drm_encoder_funcs mdfld_tpo_dpi_encoder_funcs = {
|
||||
.destroy = drm_encoder_cleanup,
|
||||
};
|
||||
|
||||
const struct panel_funcs mdfld_tpo_vid_funcs = {
|
||||
.encoder_funcs = &mdfld_tpo_dpi_encoder_funcs,
|
||||
.encoder_helper_funcs = &mdfld_tpo_dpi_encoder_helper_funcs,
|
||||
.get_config_mode = &tpo_vid_get_config_mode,
|
||||
.get_panel_info = tpo_vid_get_panel_info,
|
||||
};
|
|
@ -60,6 +60,16 @@ static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
|
|||
/* Atom E620 */
|
||||
{ 0x8086, 0x4108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops},
|
||||
#endif
|
||||
#if defined(CONFIG_DRM_MEDFIELD)
|
||||
{0x8086, 0x0130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
|
||||
{0x8086, 0x0131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
|
||||
{0x8086, 0x0132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
|
||||
{0x8086, 0x0133, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
|
||||
{0x8086, 0x0134, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
|
||||
{0x8086, 0x0135, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
|
||||
{0x8086, 0x0136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
|
||||
{0x8086, 0x0137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
|
||||
#endif
|
||||
#if defined(CONFIG_DRM_GMA3600)
|
||||
{ 0x8086, 0x0be0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
|
||||
{ 0x8086, 0x0be1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
|
||||
|
|
|
@ -389,11 +389,79 @@ struct psb_state {
|
|||
uint32_t savePWM_CONTROL_LOGIC;
|
||||
};
|
||||
|
||||
struct medfield_state {
|
||||
uint32_t saveDPLL_A;
|
||||
uint32_t saveFPA0;
|
||||
uint32_t savePIPEACONF;
|
||||
uint32_t saveHTOTAL_A;
|
||||
uint32_t saveHBLANK_A;
|
||||
uint32_t saveHSYNC_A;
|
||||
uint32_t saveVTOTAL_A;
|
||||
uint32_t saveVBLANK_A;
|
||||
uint32_t saveVSYNC_A;
|
||||
uint32_t savePIPEASRC;
|
||||
uint32_t saveDSPASTRIDE;
|
||||
uint32_t saveDSPALINOFF;
|
||||
uint32_t saveDSPATILEOFF;
|
||||
uint32_t saveDSPASIZE;
|
||||
uint32_t saveDSPAPOS;
|
||||
uint32_t saveDSPASURF;
|
||||
uint32_t saveDSPACNTR;
|
||||
uint32_t saveDSPASTATUS;
|
||||
uint32_t save_palette_a[256];
|
||||
uint32_t saveMIPI;
|
||||
|
||||
uint32_t saveDPLL_B;
|
||||
uint32_t saveFPB0;
|
||||
uint32_t savePIPEBCONF;
|
||||
uint32_t saveHTOTAL_B;
|
||||
uint32_t saveHBLANK_B;
|
||||
uint32_t saveHSYNC_B;
|
||||
uint32_t saveVTOTAL_B;
|
||||
uint32_t saveVBLANK_B;
|
||||
uint32_t saveVSYNC_B;
|
||||
uint32_t savePIPEBSRC;
|
||||
uint32_t saveDSPBSTRIDE;
|
||||
uint32_t saveDSPBLINOFF;
|
||||
uint32_t saveDSPBTILEOFF;
|
||||
uint32_t saveDSPBSIZE;
|
||||
uint32_t saveDSPBPOS;
|
||||
uint32_t saveDSPBSURF;
|
||||
uint32_t saveDSPBCNTR;
|
||||
uint32_t saveDSPBSTATUS;
|
||||
uint32_t save_palette_b[256];
|
||||
|
||||
uint32_t savePIPECCONF;
|
||||
uint32_t saveHTOTAL_C;
|
||||
uint32_t saveHBLANK_C;
|
||||
uint32_t saveHSYNC_C;
|
||||
uint32_t saveVTOTAL_C;
|
||||
uint32_t saveVBLANK_C;
|
||||
uint32_t saveVSYNC_C;
|
||||
uint32_t savePIPECSRC;
|
||||
uint32_t saveDSPCSTRIDE;
|
||||
uint32_t saveDSPCLINOFF;
|
||||
uint32_t saveDSPCTILEOFF;
|
||||
uint32_t saveDSPCSIZE;
|
||||
uint32_t saveDSPCPOS;
|
||||
uint32_t saveDSPCSURF;
|
||||
uint32_t saveDSPCCNTR;
|
||||
uint32_t saveDSPCSTATUS;
|
||||
uint32_t save_palette_c[256];
|
||||
uint32_t saveMIPI_C;
|
||||
|
||||
uint32_t savePFIT_CONTROL;
|
||||
uint32_t savePFIT_PGM_RATIOS;
|
||||
uint32_t saveHDMIPHYMISCCTL;
|
||||
uint32_t saveHDMIB_CONTROL;
|
||||
};
|
||||
|
||||
struct psb_save_area {
|
||||
uint32_t saveBSM;
|
||||
uint32_t saveVBT;
|
||||
union {
|
||||
struct psb_state psb;
|
||||
struct medfield_state mdfld;
|
||||
};
|
||||
uint32_t saveBLC_PWM_CTL2;
|
||||
uint32_t saveBLC_PWM_CTL;
|
||||
|
@ -563,6 +631,24 @@ struct drm_psb_private {
|
|||
|
||||
/* 2D acceleration */
|
||||
spinlock_t lock_2d;
|
||||
|
||||
/*
|
||||
* Panel brightness
|
||||
*/
|
||||
int brightness;
|
||||
int brightness_adjusted;
|
||||
|
||||
bool dsr_enable;
|
||||
u32 dsr_fb_update;
|
||||
bool dpi_panel_on[3];
|
||||
void *dsi_configs[2];
|
||||
u32 bpp;
|
||||
u32 bpp2;
|
||||
|
||||
u32 pipeconf[3];
|
||||
u32 dspcntr[3];
|
||||
|
||||
int mdfld_panel_id;
|
||||
};
|
||||
|
||||
|
||||
|
@ -758,6 +844,9 @@ extern const struct psb_ops psb_chip_ops;
|
|||
/* oaktrail_device.c */
|
||||
extern const struct psb_ops oaktrail_chip_ops;
|
||||
|
||||
/* mdlfd_device.c */
|
||||
extern const struct psb_ops mdfld_chip_ops;
|
||||
|
||||
/* cdv_device.c */
|
||||
extern const struct psb_ops cdv_chip_ops;
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include "psb_reg.h"
|
||||
#include "psb_intel_reg.h"
|
||||
#include "power.h"
|
||||
#include "psb_irq.h"
|
||||
#include "mdfld_output.h"
|
||||
|
||||
/*
|
||||
* inline functions
|
||||
|
@ -453,6 +455,11 @@ int psb_enable_vblank(struct drm_device *dev, int pipe)
|
|||
uint32_t reg_val = 0;
|
||||
uint32_t pipeconf_reg = mid_pipeconf(pipe);
|
||||
|
||||
/* Medfield is different - we should perhaps extract out vblank
|
||||
and blacklight etc ops */
|
||||
if (IS_MFLD(dev))
|
||||
return mdfld_enable_te(dev, pipe);
|
||||
|
||||
if (gma_power_begin(dev, false)) {
|
||||
reg_val = REG_READ(pipeconf_reg);
|
||||
gma_power_end(dev);
|
||||
|
@ -485,6 +492,8 @@ void psb_disable_vblank(struct drm_device *dev, int pipe)
|
|||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
unsigned long irqflags;
|
||||
|
||||
if (IS_MFLD(dev))
|
||||
mdfld_disable_te(dev, pipe);
|
||||
spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
|
||||
|
||||
if (pipe == 0)
|
||||
|
@ -499,6 +508,55 @@ void psb_disable_vblank(struct drm_device *dev, int pipe)
|
|||
spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
|
||||
}
|
||||
|
||||
/*
|
||||
* It is used to enable TE interrupt
|
||||
*/
|
||||
int mdfld_enable_te(struct drm_device *dev, int pipe)
|
||||
{
|
||||
struct drm_psb_private *dev_priv =
|
||||
(struct drm_psb_private *) dev->dev_private;
|
||||
unsigned long irqflags;
|
||||
uint32_t reg_val = 0;
|
||||
uint32_t pipeconf_reg = mid_pipeconf(pipe);
|
||||
|
||||
if (gma_power_begin(dev, false)) {
|
||||
reg_val = REG_READ(pipeconf_reg);
|
||||
gma_power_end(dev);
|
||||
}
|
||||
|
||||
if (!(reg_val & PIPEACONF_ENABLE))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
|
||||
|
||||
mid_enable_pipe_event(dev_priv, pipe);
|
||||
psb_enable_pipestat(dev_priv, pipe, PIPE_TE_ENABLE);
|
||||
|
||||
spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* It is used to disable TE interrupt
|
||||
*/
|
||||
void mdfld_disable_te(struct drm_device *dev, int pipe)
|
||||
{
|
||||
struct drm_psb_private *dev_priv =
|
||||
(struct drm_psb_private *) dev->dev_private;
|
||||
unsigned long irqflags;
|
||||
|
||||
if (!dev_priv->dsr_enable)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
|
||||
|
||||
mid_disable_pipe_event(dev_priv, pipe);
|
||||
psb_disable_pipestat(dev_priv, pipe, PIPE_TE_ENABLE);
|
||||
|
||||
spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
|
||||
}
|
||||
|
||||
/* Called from drm generic code, passed a 'crtc', which
|
||||
* we use as a pipe index
|
||||
*/
|
||||
|
|
|
@ -42,4 +42,6 @@ int psb_enable_vblank(struct drm_device *dev, int pipe);
|
|||
void psb_disable_vblank(struct drm_device *dev, int pipe);
|
||||
u32 psb_get_vblank_counter(struct drm_device *dev, int pipe);
|
||||
|
||||
int mdfld_enable_te(struct drm_device *dev, int pipe);
|
||||
void mdfld_disable_te(struct drm_device *dev, int pipe);
|
||||
#endif /* _SYSIRQ_H_ */
|
||||
|
|
|
@ -0,0 +1,829 @@
|
|||
/*
|
||||
* Copyright © 2011 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mdfld_dsi_dpi.h"
|
||||
#include "mdfld_output.h"
|
||||
#include "mdfld_dsi_pkg_sender.h"
|
||||
#include "tc35876x-dsi-lvds.h"
|
||||
#include <linux/i2c/tc35876x.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/intel_scu_ipc.h>
|
||||
|
||||
static struct i2c_client *tc35876x_client;
|
||||
static struct i2c_client *cmi_lcd_i2c_client;
|
||||
|
||||
#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
|
||||
#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
|
||||
|
||||
/* DSI D-PHY Layer Registers */
|
||||
#define D0W_DPHYCONTTX 0x0004
|
||||
#define CLW_DPHYCONTRX 0x0020
|
||||
#define D0W_DPHYCONTRX 0x0024
|
||||
#define D1W_DPHYCONTRX 0x0028
|
||||
#define D2W_DPHYCONTRX 0x002C
|
||||
#define D3W_DPHYCONTRX 0x0030
|
||||
#define COM_DPHYCONTRX 0x0038
|
||||
#define CLW_CNTRL 0x0040
|
||||
#define D0W_CNTRL 0x0044
|
||||
#define D1W_CNTRL 0x0048
|
||||
#define D2W_CNTRL 0x004C
|
||||
#define D3W_CNTRL 0x0050
|
||||
#define DFTMODE_CNTRL 0x0054
|
||||
|
||||
/* DSI PPI Layer Registers */
|
||||
#define PPI_STARTPPI 0x0104
|
||||
#define PPI_BUSYPPI 0x0108
|
||||
#define PPI_LINEINITCNT 0x0110
|
||||
#define PPI_LPTXTIMECNT 0x0114
|
||||
#define PPI_LANEENABLE 0x0134
|
||||
#define PPI_TX_RX_TA 0x013C
|
||||
#define PPI_CLS_ATMR 0x0140
|
||||
#define PPI_D0S_ATMR 0x0144
|
||||
#define PPI_D1S_ATMR 0x0148
|
||||
#define PPI_D2S_ATMR 0x014C
|
||||
#define PPI_D3S_ATMR 0x0150
|
||||
#define PPI_D0S_CLRSIPOCOUNT 0x0164
|
||||
#define PPI_D1S_CLRSIPOCOUNT 0x0168
|
||||
#define PPI_D2S_CLRSIPOCOUNT 0x016C
|
||||
#define PPI_D3S_CLRSIPOCOUNT 0x0170
|
||||
#define CLS_PRE 0x0180
|
||||
#define D0S_PRE 0x0184
|
||||
#define D1S_PRE 0x0188
|
||||
#define D2S_PRE 0x018C
|
||||
#define D3S_PRE 0x0190
|
||||
#define CLS_PREP 0x01A0
|
||||
#define D0S_PREP 0x01A4
|
||||
#define D1S_PREP 0x01A8
|
||||
#define D2S_PREP 0x01AC
|
||||
#define D3S_PREP 0x01B0
|
||||
#define CLS_ZERO 0x01C0
|
||||
#define D0S_ZERO 0x01C4
|
||||
#define D1S_ZERO 0x01C8
|
||||
#define D2S_ZERO 0x01CC
|
||||
#define D3S_ZERO 0x01D0
|
||||
#define PPI_CLRFLG 0x01E0
|
||||
#define PPI_CLRSIPO 0x01E4
|
||||
#define HSTIMEOUT 0x01F0
|
||||
#define HSTIMEOUTENABLE 0x01F4
|
||||
|
||||
/* DSI Protocol Layer Registers */
|
||||
#define DSI_STARTDSI 0x0204
|
||||
#define DSI_BUSYDSI 0x0208
|
||||
#define DSI_LANEENABLE 0x0210
|
||||
#define DSI_LANESTATUS0 0x0214
|
||||
#define DSI_LANESTATUS1 0x0218
|
||||
#define DSI_INTSTATUS 0x0220
|
||||
#define DSI_INTMASK 0x0224
|
||||
#define DSI_INTCLR 0x0228
|
||||
#define DSI_LPTXTO 0x0230
|
||||
|
||||
/* DSI General Registers */
|
||||
#define DSIERRCNT 0x0300
|
||||
|
||||
/* DSI Application Layer Registers */
|
||||
#define APLCTRL 0x0400
|
||||
#define RDPKTLN 0x0404
|
||||
|
||||
/* Video Path Registers */
|
||||
#define VPCTRL 0x0450
|
||||
#define HTIM1 0x0454
|
||||
#define HTIM2 0x0458
|
||||
#define VTIM1 0x045C
|
||||
#define VTIM2 0x0460
|
||||
#define VFUEN 0x0464
|
||||
|
||||
/* LVDS Registers */
|
||||
#define LVMX0003 0x0480
|
||||
#define LVMX0407 0x0484
|
||||
#define LVMX0811 0x0488
|
||||
#define LVMX1215 0x048C
|
||||
#define LVMX1619 0x0490
|
||||
#define LVMX2023 0x0494
|
||||
#define LVMX2427 0x0498
|
||||
#define LVCFG 0x049C
|
||||
#define LVPHY0 0x04A0
|
||||
#define LVPHY1 0x04A4
|
||||
|
||||
/* System Registers */
|
||||
#define SYSSTAT 0x0500
|
||||
#define SYSRST 0x0504
|
||||
|
||||
/* GPIO Registers */
|
||||
/*#define GPIOC 0x0520*/
|
||||
#define GPIOO 0x0524
|
||||
#define GPIOI 0x0528
|
||||
|
||||
/* I2C Registers */
|
||||
#define I2CTIMCTRL 0x0540
|
||||
#define I2CMADDR 0x0544
|
||||
#define WDATAQ 0x0548
|
||||
#define RDATAQ 0x054C
|
||||
|
||||
/* Chip/Rev Registers */
|
||||
#define IDREG 0x0580
|
||||
|
||||
/* Debug Registers */
|
||||
#define DEBUG00 0x05A0
|
||||
#define DEBUG01 0x05A4
|
||||
|
||||
/* Panel CABC registers */
|
||||
#define PANEL_PWM_CONTROL 0x90
|
||||
#define PANEL_FREQ_DIVIDER_HI 0x91
|
||||
#define PANEL_FREQ_DIVIDER_LO 0x92
|
||||
#define PANEL_DUTY_CONTROL 0x93
|
||||
#define PANEL_MODIFY_RGB 0x94
|
||||
#define PANEL_FRAMERATE_CONTROL 0x96
|
||||
#define PANEL_PWM_MIN 0x97
|
||||
#define PANEL_PWM_REF 0x98
|
||||
#define PANEL_PWM_MAX 0x99
|
||||
#define PANEL_ALLOW_DISTORT 0x9A
|
||||
#define PANEL_BYPASS_PWMI 0x9B
|
||||
|
||||
/* Panel color management registers */
|
||||
#define PANEL_CM_ENABLE 0x700
|
||||
#define PANEL_CM_HUE 0x701
|
||||
#define PANEL_CM_SATURATION 0x702
|
||||
#define PANEL_CM_INTENSITY 0x703
|
||||
#define PANEL_CM_BRIGHTNESS 0x704
|
||||
#define PANEL_CM_CE_ENABLE 0x705
|
||||
#define PANEL_CM_PEAK_EN 0x710
|
||||
#define PANEL_CM_GAIN 0x711
|
||||
#define PANEL_CM_HUETABLE_START 0x730
|
||||
#define PANEL_CM_HUETABLE_END 0x747 /* inclusive */
|
||||
|
||||
/* Input muxing for registers LVMX0003...LVMX2427 */
|
||||
enum {
|
||||
INPUT_R0, /* 0 */
|
||||
INPUT_R1,
|
||||
INPUT_R2,
|
||||
INPUT_R3,
|
||||
INPUT_R4,
|
||||
INPUT_R5,
|
||||
INPUT_R6,
|
||||
INPUT_R7,
|
||||
INPUT_G0, /* 8 */
|
||||
INPUT_G1,
|
||||
INPUT_G2,
|
||||
INPUT_G3,
|
||||
INPUT_G4,
|
||||
INPUT_G5,
|
||||
INPUT_G6,
|
||||
INPUT_G7,
|
||||
INPUT_B0, /* 16 */
|
||||
INPUT_B1,
|
||||
INPUT_B2,
|
||||
INPUT_B3,
|
||||
INPUT_B4,
|
||||
INPUT_B5,
|
||||
INPUT_B6,
|
||||
INPUT_B7,
|
||||
INPUT_HSYNC, /* 24 */
|
||||
INPUT_VSYNC,
|
||||
INPUT_DE,
|
||||
LOGIC_0,
|
||||
/* 28...31 undefined */
|
||||
};
|
||||
|
||||
#define INPUT_MUX(lvmx03, lvmx02, lvmx01, lvmx00) \
|
||||
(FLD_VAL(lvmx03, 29, 24) | FLD_VAL(lvmx02, 20, 16) | \
|
||||
FLD_VAL(lvmx01, 12, 8) | FLD_VAL(lvmx00, 4, 0))
|
||||
|
||||
/**
|
||||
* tc35876x_regw - Write DSI-LVDS bridge register using I2C
|
||||
* @client: struct i2c_client to use
|
||||
* @reg: register address
|
||||
* @value: value to write
|
||||
*
|
||||
* Returns 0 on success, or a negative error value.
|
||||
*/
|
||||
static int tc35876x_regw(struct i2c_client *client, u16 reg, u32 value)
|
||||
{
|
||||
int r;
|
||||
u8 tx_data[] = {
|
||||
/* NOTE: Register address big-endian, data little-endian. */
|
||||
(reg >> 8) & 0xff,
|
||||
reg & 0xff,
|
||||
value & 0xff,
|
||||
(value >> 8) & 0xff,
|
||||
(value >> 16) & 0xff,
|
||||
(value >> 24) & 0xff,
|
||||
};
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.buf = tx_data,
|
||||
.len = ARRAY_SIZE(tx_data),
|
||||
},
|
||||
};
|
||||
|
||||
r = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (r < 0) {
|
||||
dev_err(&client->dev, "%s: reg 0x%04x val 0x%08x error %d\n",
|
||||
__func__, reg, value, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (r < ARRAY_SIZE(msgs)) {
|
||||
dev_err(&client->dev, "%s: reg 0x%04x val 0x%08x msgs %d\n",
|
||||
__func__, reg, value, r);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
dev_dbg(&client->dev, "%s: reg 0x%04x val 0x%08x\n",
|
||||
__func__, reg, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tc35876x_regr - Read DSI-LVDS bridge register using I2C
|
||||
* @client: struct i2c_client to use
|
||||
* @reg: register address
|
||||
* @value: pointer for storing the value
|
||||
*
|
||||
* Returns 0 on success, or a negative error value.
|
||||
*/
|
||||
static int tc35876x_regr(struct i2c_client *client, u16 reg, u32 *value)
|
||||
{
|
||||
int r;
|
||||
u8 tx_data[] = {
|
||||
(reg >> 8) & 0xff,
|
||||
reg & 0xff,
|
||||
};
|
||||
u8 rx_data[4];
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.buf = tx_data,
|
||||
.len = ARRAY_SIZE(tx_data),
|
||||
},
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.buf = rx_data,
|
||||
.len = ARRAY_SIZE(rx_data),
|
||||
},
|
||||
};
|
||||
|
||||
r = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (r < 0) {
|
||||
dev_err(&client->dev, "%s: reg 0x%04x error %d\n", __func__,
|
||||
reg, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (r < ARRAY_SIZE(msgs)) {
|
||||
dev_err(&client->dev, "%s: reg 0x%04x msgs %d\n", __func__,
|
||||
reg, r);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
*value = rx_data[0] << 24 | rx_data[1] << 16 |
|
||||
rx_data[2] << 8 | rx_data[3];
|
||||
|
||||
dev_dbg(&client->dev, "%s: reg 0x%04x value 0x%08x\n", __func__,
|
||||
reg, *value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tc35876x_set_bridge_reset_state(struct drm_device *dev, int state)
|
||||
{
|
||||
struct tc35876x_platform_data *pdata;
|
||||
|
||||
if (WARN(!tc35876x_client, "%s called before probe", __func__))
|
||||
return;
|
||||
|
||||
dev_dbg(&tc35876x_client->dev, "%s: state %d\n", __func__, state);
|
||||
|
||||
pdata = dev_get_platdata(&tc35876x_client->dev);
|
||||
|
||||
if (pdata->gpio_bridge_reset == -1)
|
||||
return;
|
||||
|
||||
if (state) {
|
||||
gpio_set_value_cansleep(pdata->gpio_bridge_reset, 0);
|
||||
mdelay(10);
|
||||
} else {
|
||||
/* Pull MIPI Bridge reset pin to Low */
|
||||
gpio_set_value_cansleep(pdata->gpio_bridge_reset, 0);
|
||||
mdelay(20);
|
||||
/* Pull MIPI Bridge reset pin to High */
|
||||
gpio_set_value_cansleep(pdata->gpio_bridge_reset, 1);
|
||||
mdelay(40);
|
||||
}
|
||||
}
|
||||
|
||||
void tc35876x_configure_lvds_bridge(struct drm_device *dev)
|
||||
{
|
||||
struct i2c_client *i2c = tc35876x_client;
|
||||
u32 ppi_lptxtimecnt;
|
||||
u32 txtagocnt;
|
||||
u32 txtasurecnt;
|
||||
u32 id;
|
||||
|
||||
if (WARN(!tc35876x_client, "%s called before probe", __func__))
|
||||
return;
|
||||
|
||||
dev_dbg(&tc35876x_client->dev, "%s\n", __func__);
|
||||
|
||||
if (!tc35876x_regr(i2c, IDREG, &id))
|
||||
dev_info(&tc35876x_client->dev, "tc35876x ID 0x%08x\n", id);
|
||||
else
|
||||
dev_err(&tc35876x_client->dev, "Cannot read ID\n");
|
||||
|
||||
ppi_lptxtimecnt = 4;
|
||||
txtagocnt = (5 * ppi_lptxtimecnt - 3) / 4;
|
||||
txtasurecnt = 3 * ppi_lptxtimecnt / 2;
|
||||
tc35876x_regw(i2c, PPI_TX_RX_TA, FLD_VAL(txtagocnt, 26, 16) |
|
||||
FLD_VAL(txtasurecnt, 10, 0));
|
||||
tc35876x_regw(i2c, PPI_LPTXTIMECNT, FLD_VAL(ppi_lptxtimecnt, 10, 0));
|
||||
|
||||
tc35876x_regw(i2c, PPI_D0S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0));
|
||||
tc35876x_regw(i2c, PPI_D1S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0));
|
||||
tc35876x_regw(i2c, PPI_D2S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0));
|
||||
tc35876x_regw(i2c, PPI_D3S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0));
|
||||
|
||||
/* Enabling MIPI & PPI lanes, Enable 4 lanes */
|
||||
tc35876x_regw(i2c, PPI_LANEENABLE,
|
||||
BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0));
|
||||
tc35876x_regw(i2c, DSI_LANEENABLE,
|
||||
BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0));
|
||||
tc35876x_regw(i2c, PPI_STARTPPI, BIT(0));
|
||||
tc35876x_regw(i2c, DSI_STARTDSI, BIT(0));
|
||||
|
||||
/* Setting LVDS output frequency */
|
||||
tc35876x_regw(i2c, LVPHY0, FLD_VAL(1, 20, 16) |
|
||||
FLD_VAL(2, 15, 14) | FLD_VAL(6, 4, 0)); /* 0x00048006 */
|
||||
|
||||
/* Setting video panel control register,0x00000120 VTGen=ON ?!?!? */
|
||||
tc35876x_regw(i2c, VPCTRL, BIT(8) | BIT(5));
|
||||
|
||||
/* Horizontal back porch and horizontal pulse width. 0x00280028 */
|
||||
tc35876x_regw(i2c, HTIM1, FLD_VAL(40, 24, 16) | FLD_VAL(40, 8, 0));
|
||||
|
||||
/* Horizontal front porch and horizontal active video size. 0x00500500*/
|
||||
tc35876x_regw(i2c, HTIM2, FLD_VAL(80, 24, 16) | FLD_VAL(1280, 10, 0));
|
||||
|
||||
/* Vertical back porch and vertical sync pulse width. 0x000e000a */
|
||||
tc35876x_regw(i2c, VTIM1, FLD_VAL(14, 23, 16) | FLD_VAL(10, 7, 0));
|
||||
|
||||
/* Vertical front porch and vertical display size. 0x000e0320 */
|
||||
tc35876x_regw(i2c, VTIM2, FLD_VAL(14, 23, 16) | FLD_VAL(800, 10, 0));
|
||||
|
||||
/* Set above HTIM1, HTIM2, VTIM1, and VTIM2 at next VSYNC. */
|
||||
tc35876x_regw(i2c, VFUEN, BIT(0));
|
||||
|
||||
/* Soft reset LCD controller. */
|
||||
tc35876x_regw(i2c, SYSRST, BIT(2));
|
||||
|
||||
/* LVDS-TX input muxing */
|
||||
tc35876x_regw(i2c, LVMX0003,
|
||||
INPUT_MUX(INPUT_R5, INPUT_R4, INPUT_R3, INPUT_R2));
|
||||
tc35876x_regw(i2c, LVMX0407,
|
||||
INPUT_MUX(INPUT_G2, INPUT_R7, INPUT_R1, INPUT_R6));
|
||||
tc35876x_regw(i2c, LVMX0811,
|
||||
INPUT_MUX(INPUT_G1, INPUT_G0, INPUT_G4, INPUT_G3));
|
||||
tc35876x_regw(i2c, LVMX1215,
|
||||
INPUT_MUX(INPUT_B2, INPUT_G7, INPUT_G6, INPUT_G5));
|
||||
tc35876x_regw(i2c, LVMX1619,
|
||||
INPUT_MUX(INPUT_B4, INPUT_B3, INPUT_B1, INPUT_B0));
|
||||
tc35876x_regw(i2c, LVMX2023,
|
||||
INPUT_MUX(LOGIC_0, INPUT_B7, INPUT_B6, INPUT_B5));
|
||||
tc35876x_regw(i2c, LVMX2427,
|
||||
INPUT_MUX(INPUT_R0, INPUT_DE, INPUT_VSYNC, INPUT_HSYNC));
|
||||
|
||||
/* Enable LVDS transmitter. */
|
||||
tc35876x_regw(i2c, LVCFG, BIT(0));
|
||||
|
||||
/* Clear notifications. Don't write reserved bits. Was write 0xffffffff
|
||||
* to 0x0288, must be in error?! */
|
||||
tc35876x_regw(i2c, DSI_INTCLR, FLD_MASK(31, 30) | FLD_MASK(22, 0));
|
||||
}
|
||||
|
||||
#define GPIOPWMCTRL 0x38F
|
||||
#define PWM0CLKDIV0 0x62 /* low byte */
|
||||
#define PWM0CLKDIV1 0x61 /* high byte */
|
||||
|
||||
#define SYSTEMCLK 19200000UL /* 19.2 MHz */
|
||||
#define PWM_FREQUENCY 9600 /* Hz */
|
||||
|
||||
/* f = baseclk / (clkdiv + 1) => clkdiv = (baseclk - f) / f */
|
||||
static inline u16 calc_clkdiv(unsigned long baseclk, unsigned int f)
|
||||
{
|
||||
return (baseclk - f) / f;
|
||||
}
|
||||
|
||||
static void tc35876x_brightness_init(struct drm_device *dev)
|
||||
{
|
||||
int ret;
|
||||
u8 pwmctrl;
|
||||
u16 clkdiv;
|
||||
|
||||
/* Make sure the PWM reference is the 19.2 MHz system clock. Read first
|
||||
* instead of setting directly to catch potential conflicts between PWM
|
||||
* users. */
|
||||
ret = intel_scu_ipc_ioread8(GPIOPWMCTRL, &pwmctrl);
|
||||
if (ret || pwmctrl != 0x01) {
|
||||
if (ret)
|
||||
dev_err(&dev->pdev->dev, "GPIOPWMCTRL read failed\n");
|
||||
else
|
||||
dev_warn(&dev->pdev->dev, "GPIOPWMCTRL was not set to system clock (pwmctrl = 0x%02x)\n", pwmctrl);
|
||||
|
||||
ret = intel_scu_ipc_iowrite8(GPIOPWMCTRL, 0x01);
|
||||
if (ret)
|
||||
dev_err(&dev->pdev->dev, "GPIOPWMCTRL set failed\n");
|
||||
}
|
||||
|
||||
clkdiv = calc_clkdiv(SYSTEMCLK, PWM_FREQUENCY);
|
||||
|
||||
ret = intel_scu_ipc_iowrite8(PWM0CLKDIV1, (clkdiv >> 8) & 0xff);
|
||||
if (!ret)
|
||||
ret = intel_scu_ipc_iowrite8(PWM0CLKDIV0, clkdiv & 0xff);
|
||||
|
||||
if (ret)
|
||||
dev_err(&dev->pdev->dev, "PWM0CLKDIV set failed\n");
|
||||
else
|
||||
dev_dbg(&dev->pdev->dev, "PWM0CLKDIV set to 0x%04x (%d Hz)\n",
|
||||
clkdiv, PWM_FREQUENCY);
|
||||
}
|
||||
|
||||
#define PWM0DUTYCYCLE 0x67
|
||||
|
||||
void tc35876x_brightness_control(struct drm_device *dev, int level)
|
||||
{
|
||||
int ret;
|
||||
u8 duty_val;
|
||||
u8 panel_duty_val;
|
||||
|
||||
level = clamp(level, 0, MDFLD_DSI_BRIGHTNESS_MAX_LEVEL);
|
||||
|
||||
/* PWM duty cycle 0x00...0x63 corresponds to 0...99% */
|
||||
duty_val = level * 0x63 / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL;
|
||||
|
||||
/* I won't pretend to understand this formula. The panel spec is quite
|
||||
* bad engrish.
|
||||
*/
|
||||
panel_duty_val = (2 * level - 100) * 0xA9 /
|
||||
MDFLD_DSI_BRIGHTNESS_MAX_LEVEL + 0x56;
|
||||
|
||||
ret = intel_scu_ipc_iowrite8(PWM0DUTYCYCLE, duty_val);
|
||||
if (ret)
|
||||
dev_err(&tc35876x_client->dev, "%s: ipc write fail\n",
|
||||
__func__);
|
||||
|
||||
if (cmi_lcd_i2c_client) {
|
||||
ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client,
|
||||
PANEL_PWM_MAX, panel_duty_val);
|
||||
if (ret < 0)
|
||||
dev_err(&cmi_lcd_i2c_client->dev, "%s: i2c write failed\n",
|
||||
__func__);
|
||||
}
|
||||
}
|
||||
|
||||
void tc35876x_toshiba_bridge_panel_off(struct drm_device *dev)
|
||||
{
|
||||
struct tc35876x_platform_data *pdata;
|
||||
|
||||
if (WARN(!tc35876x_client, "%s called before probe", __func__))
|
||||
return;
|
||||
|
||||
dev_dbg(&tc35876x_client->dev, "%s\n", __func__);
|
||||
|
||||
pdata = dev_get_platdata(&tc35876x_client->dev);
|
||||
|
||||
if (pdata->gpio_panel_bl_en != -1)
|
||||
gpio_set_value_cansleep(pdata->gpio_panel_bl_en, 0);
|
||||
|
||||
if (pdata->gpio_panel_vadd != -1)
|
||||
gpio_set_value_cansleep(pdata->gpio_panel_vadd, 0);
|
||||
}
|
||||
|
||||
void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev)
|
||||
{
|
||||
struct tc35876x_platform_data *pdata;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (WARN(!tc35876x_client, "%s called before probe", __func__))
|
||||
return;
|
||||
|
||||
dev_dbg(&tc35876x_client->dev, "%s\n", __func__);
|
||||
|
||||
pdata = dev_get_platdata(&tc35876x_client->dev);
|
||||
|
||||
if (pdata->gpio_panel_vadd != -1) {
|
||||
gpio_set_value_cansleep(pdata->gpio_panel_vadd, 1);
|
||||
msleep(260);
|
||||
}
|
||||
|
||||
if (cmi_lcd_i2c_client) {
|
||||
int ret;
|
||||
dev_dbg(&cmi_lcd_i2c_client->dev, "setting TCON\n");
|
||||
/* Bit 4 is average_saving. Setting it to 1, the brightness is
|
||||
* referenced to the average of the frame content. 0 means
|
||||
* reference to the maximum of frame contents. Bits 3:0 are
|
||||
* allow_distort. When set to a nonzero value, all color values
|
||||
* between 255-allow_distort*2 and 255 are mapped to the
|
||||
* 255-allow_distort*2 value.
|
||||
*/
|
||||
ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client,
|
||||
PANEL_ALLOW_DISTORT, 0x10);
|
||||
if (ret < 0)
|
||||
dev_err(&cmi_lcd_i2c_client->dev,
|
||||
"i2c write failed (%d)\n", ret);
|
||||
ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client,
|
||||
PANEL_BYPASS_PWMI, 0);
|
||||
if (ret < 0)
|
||||
dev_err(&cmi_lcd_i2c_client->dev,
|
||||
"i2c write failed (%d)\n", ret);
|
||||
/* Set minimum brightness value - this is tunable */
|
||||
ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client,
|
||||
PANEL_PWM_MIN, 0x35);
|
||||
if (ret < 0)
|
||||
dev_err(&cmi_lcd_i2c_client->dev,
|
||||
"i2c write failed (%d)\n", ret);
|
||||
}
|
||||
|
||||
if (pdata->gpio_panel_bl_en != -1)
|
||||
gpio_set_value_cansleep(pdata->gpio_panel_bl_en, 1);
|
||||
|
||||
tc35876x_brightness_control(dev, dev_priv->brightness_adjusted);
|
||||
}
|
||||
|
||||
static struct drm_display_mode *tc35876x_get_config_mode(struct drm_device *dev)
|
||||
{
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
dev_dbg(&dev->pdev->dev, "%s\n", __func__);
|
||||
|
||||
mode = kzalloc(sizeof(*mode), GFP_KERNEL);
|
||||
if (!mode)
|
||||
return NULL;
|
||||
|
||||
/* FIXME: do this properly. */
|
||||
mode->hdisplay = 1280;
|
||||
mode->vdisplay = 800;
|
||||
mode->hsync_start = 1360;
|
||||
mode->hsync_end = 1400;
|
||||
mode->htotal = 1440;
|
||||
mode->vsync_start = 814;
|
||||
mode->vsync_end = 824;
|
||||
mode->vtotal = 838;
|
||||
mode->clock = 33324 << 1;
|
||||
|
||||
dev_info(&dev->pdev->dev, "hdisplay(w) = %d\n", mode->hdisplay);
|
||||
dev_info(&dev->pdev->dev, "vdisplay(h) = %d\n", mode->vdisplay);
|
||||
dev_info(&dev->pdev->dev, "HSS = %d\n", mode->hsync_start);
|
||||
dev_info(&dev->pdev->dev, "HSE = %d\n", mode->hsync_end);
|
||||
dev_info(&dev->pdev->dev, "htotal = %d\n", mode->htotal);
|
||||
dev_info(&dev->pdev->dev, "VSS = %d\n", mode->vsync_start);
|
||||
dev_info(&dev->pdev->dev, "VSE = %d\n", mode->vsync_end);
|
||||
dev_info(&dev->pdev->dev, "vtotal = %d\n", mode->vtotal);
|
||||
dev_info(&dev->pdev->dev, "clock = %d\n", mode->clock);
|
||||
|
||||
drm_mode_set_name(mode);
|
||||
drm_mode_set_crtcinfo(mode, 0);
|
||||
|
||||
mode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
/* DV1 Active area 216.96 x 135.6 mm */
|
||||
#define DV1_PANEL_WIDTH 217
|
||||
#define DV1_PANEL_HEIGHT 136
|
||||
|
||||
static int tc35876x_get_panel_info(struct drm_device *dev, int pipe,
|
||||
struct panel_info *pi)
|
||||
{
|
||||
if (!dev || !pi)
|
||||
return -EINVAL;
|
||||
|
||||
pi->width_mm = DV1_PANEL_WIDTH;
|
||||
pi->height_mm = DV1_PANEL_HEIGHT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tc35876x_bridge_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct tc35876x_platform_data *pdata;
|
||||
|
||||
dev_info(&client->dev, "%s\n", __func__);
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
dev_err(&client->dev, "%s: i2c_check_functionality() failed\n",
|
||||
__func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pdata = dev_get_platdata(&client->dev);
|
||||
if (!pdata) {
|
||||
dev_err(&client->dev, "%s: no platform data\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (pdata->gpio_bridge_reset != -1) {
|
||||
gpio_request(pdata->gpio_bridge_reset, "tc35876x bridge reset");
|
||||
gpio_direction_output(pdata->gpio_bridge_reset, 0);
|
||||
}
|
||||
|
||||
if (pdata->gpio_panel_bl_en != -1) {
|
||||
gpio_request(pdata->gpio_panel_bl_en, "tc35876x panel bl en");
|
||||
gpio_direction_output(pdata->gpio_panel_bl_en, 0);
|
||||
}
|
||||
|
||||
if (pdata->gpio_panel_vadd != -1) {
|
||||
gpio_request(pdata->gpio_panel_vadd, "tc35876x panel vadd");
|
||||
gpio_direction_output(pdata->gpio_panel_vadd, 0);
|
||||
}
|
||||
|
||||
tc35876x_client = client;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tc35876x_bridge_remove(struct i2c_client *client)
|
||||
{
|
||||
struct tc35876x_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
|
||||
if (pdata->gpio_bridge_reset != -1)
|
||||
gpio_free(pdata->gpio_bridge_reset);
|
||||
|
||||
if (pdata->gpio_panel_bl_en != -1)
|
||||
gpio_free(pdata->gpio_panel_bl_en);
|
||||
|
||||
if (pdata->gpio_panel_vadd != -1)
|
||||
gpio_free(pdata->gpio_panel_vadd);
|
||||
|
||||
tc35876x_client = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id tc35876x_bridge_id[] = {
|
||||
{ "i2c_disp_brig", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tc35876x_bridge_id);
|
||||
|
||||
static struct i2c_driver tc35876x_bridge_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "i2c_disp_brig",
|
||||
},
|
||||
.id_table = tc35876x_bridge_id,
|
||||
.probe = tc35876x_bridge_probe,
|
||||
.remove = __devexit_p(tc35876x_bridge_remove),
|
||||
};
|
||||
|
||||
/* LCD panel I2C */
|
||||
static int cmi_lcd_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
dev_info(&client->dev, "%s\n", __func__);
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
dev_err(&client->dev, "%s: i2c_check_functionality() failed\n",
|
||||
__func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
cmi_lcd_i2c_client = client;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmi_lcd_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
|
||||
cmi_lcd_i2c_client = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id cmi_lcd_i2c_id[] = {
|
||||
{ "cmi-lcd", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cmi_lcd_i2c_id);
|
||||
|
||||
static struct i2c_driver cmi_lcd_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "cmi-lcd",
|
||||
},
|
||||
.id_table = cmi_lcd_i2c_id,
|
||||
.probe = cmi_lcd_i2c_probe,
|
||||
.remove = __devexit_p(cmi_lcd_i2c_remove),
|
||||
};
|
||||
|
||||
/* HACK to create I2C device while it's not created by platform code */
|
||||
#define CMI_LCD_I2C_ADAPTER 2
|
||||
#define CMI_LCD_I2C_ADDR 0x60
|
||||
|
||||
static int cmi_lcd_hack_create_device(void)
|
||||
{
|
||||
struct i2c_adapter *adapter;
|
||||
struct i2c_client *client;
|
||||
struct i2c_board_info info = {
|
||||
.type = "cmi-lcd",
|
||||
.addr = CMI_LCD_I2C_ADDR,
|
||||
};
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
adapter = i2c_get_adapter(CMI_LCD_I2C_ADAPTER);
|
||||
if (!adapter) {
|
||||
pr_err("%s: i2c_get_adapter(%d) failed\n", __func__,
|
||||
CMI_LCD_I2C_ADAPTER);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
client = i2c_new_device(adapter, &info);
|
||||
if (!client) {
|
||||
pr_err("%s: i2c_new_device() failed\n", __func__);
|
||||
i2c_put_adapter(adapter);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs tc35876x_encoder_helper_funcs = {
|
||||
.dpms = mdfld_dsi_dpi_dpms,
|
||||
.mode_fixup = mdfld_dsi_dpi_mode_fixup,
|
||||
.prepare = mdfld_dsi_dpi_prepare,
|
||||
.mode_set = mdfld_dsi_dpi_mode_set,
|
||||
.commit = mdfld_dsi_dpi_commit,
|
||||
};
|
||||
|
||||
static const struct drm_encoder_funcs tc35876x_encoder_funcs = {
|
||||
.destroy = drm_encoder_cleanup,
|
||||
};
|
||||
|
||||
const struct panel_funcs mdfld_tc35876x_funcs = {
|
||||
.encoder_funcs = &tc35876x_encoder_funcs,
|
||||
.encoder_helper_funcs = &tc35876x_encoder_helper_funcs,
|
||||
.get_config_mode = tc35876x_get_config_mode,
|
||||
.get_panel_info = tc35876x_get_panel_info,
|
||||
};
|
||||
|
||||
void tc35876x_init(struct drm_device *dev)
|
||||
{
|
||||
int r;
|
||||
|
||||
dev_dbg(&dev->pdev->dev, "%s\n", __func__);
|
||||
|
||||
cmi_lcd_hack_create_device();
|
||||
|
||||
r = i2c_add_driver(&cmi_lcd_i2c_driver);
|
||||
if (r < 0)
|
||||
dev_err(&dev->pdev->dev,
|
||||
"%s: i2c_add_driver() for %s failed (%d)\n",
|
||||
__func__, cmi_lcd_i2c_driver.driver.name, r);
|
||||
|
||||
r = i2c_add_driver(&tc35876x_bridge_i2c_driver);
|
||||
if (r < 0)
|
||||
dev_err(&dev->pdev->dev,
|
||||
"%s: i2c_add_driver() for %s failed (%d)\n",
|
||||
__func__, tc35876x_bridge_i2c_driver.driver.name, r);
|
||||
|
||||
tc35876x_brightness_init(dev);
|
||||
}
|
||||
|
||||
void tc35876x_exit(void)
|
||||
{
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
i2c_del_driver(&tc35876x_bridge_i2c_driver);
|
||||
|
||||
if (cmi_lcd_i2c_client)
|
||||
i2c_del_driver(&cmi_lcd_i2c_driver);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright © 2011 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MDFLD_DSI_LVDS_BRIDGE_H__
|
||||
#define __MDFLD_DSI_LVDS_BRIDGE_H__
|
||||
|
||||
void tc35876x_set_bridge_reset_state(struct drm_device *dev, int state);
|
||||
void tc35876x_configure_lvds_bridge(struct drm_device *dev);
|
||||
void tc35876x_brightness_control(struct drm_device *dev, int level);
|
||||
void tc35876x_toshiba_bridge_panel_off(struct drm_device *dev);
|
||||
void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev);
|
||||
void tc35876x_init(struct drm_device *dev);
|
||||
void tc35876x_exit(void);
|
||||
|
||||
extern const struct panel_funcs mdfld_tc35876x_funcs;
|
||||
|
||||
#endif /*__MDFLD_DSI_LVDS_BRIDGE_H__*/
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
#ifndef _TC35876X_H
|
||||
#define _TC35876X_H
|
||||
|
||||
struct tc35876x_platform_data {
|
||||
int gpio_bridge_reset;
|
||||
int gpio_panel_bl_en;
|
||||
int gpio_panel_vadd;
|
||||
};
|
||||
|
||||
#endif /* _TC35876X_H */
|
Loading…
Reference in New Issue