提交 ef23d500 编写于 作者: D Dave Airlie

Merge tag 'drm-misc-next-fixes-2021-02-11' of...

Merge tag 'drm-misc-next-fixes-2021-02-11' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

drm-misc-next-fixes cherry picked from drm-misc-next for v5.12:
- Assorted small fixes.
- Disable and remove gma3600 support.
- Fix CEC for vc4/hdmi.
Signed-off-by: NDave Airlie <airlied@redhat.com>

From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/dac2ae30-c5d9-4222-39e2-f64067310491@linux.intel.com
......@@ -53,6 +53,24 @@ properties:
- const: audio
- const: cec
interrupts:
items:
- description: CEC TX interrupt
- description: CEC RX interrupt
- description: CEC stuck at low interrupt
- description: Wake-up interrupt
- description: Hotplug connected interrupt
- description: Hotplug removed interrupt
interrupt-names:
items:
- const: cec-tx
- const: cec-rx
- const: cec-low
- const: wakeup
- const: hpd-connected
- const: hpd-removed
ddc:
allOf:
- $ref: /schemas/types.yaml#/definitions/phandle
......@@ -90,7 +108,7 @@ required:
- resets
- ddc
additionalProperties: false
unevaluatedProperties: false
examples:
- |
......
......@@ -23,6 +23,9 @@ Advanced: Tricky tasks that need fairly good understanding of the DRM subsystem
and graphics topics. Generally need the relevant hardware for development and
testing.
Expert: Only attempt these if you've successfully completed some tricky
refactorings already and are an expert in the specific area
Subsystem-wide refactorings
===========================
......@@ -168,6 +171,22 @@ Contact: Daniel Vetter, respective driver maintainers
Level: Advanced
Move Buffer Object Locking to dma_resv_lock()
---------------------------------------------
Many drivers have their own per-object locking scheme, usually using
mutex_lock(). This causes all kinds of trouble for buffer sharing, since
depending which driver is the exporter and importer, the locking hierarchy is
reversed.
To solve this we need one standard per-object locking mechanism, which is
dma_resv_lock(). This lock needs to be called as the outermost lock, with all
other driver specific per-object locks removed. The problem is tha rolling out
the actual change to the locking contract is a flag day, due to struct dma_buf
buffer sharing.
Level: Expert
Convert logging to drm_* functions with drm_device paramater
------------------------------------------------------------
......
......@@ -471,8 +471,11 @@ static int thread_signal_callback(void *arg)
dma_fence_signal(f1);
smp_store_mb(cb.seen, false);
if (!f2 || dma_fence_add_callback(f2, &cb.cb, simple_callback))
miss++, cb.seen = true;
if (!f2 ||
dma_fence_add_callback(f2, &cb.cb, simple_callback)) {
miss++;
cb.seen = true;
}
if (!t->before)
dma_fence_signal(f1);
......
......@@ -7,6 +7,7 @@
* Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
*/
#include "drm/drm_modeset_lock.h"
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
......@@ -1181,9 +1182,11 @@ static void drm_client_modeset_dpms_legacy(struct drm_client_dev *client, int dp
struct drm_device *dev = client->dev;
struct drm_connector *connector;
struct drm_mode_set *modeset;
struct drm_modeset_acquire_ctx ctx;
int j;
int ret;
drm_modeset_lock_all(dev);
DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret);
drm_client_for_each_modeset(modeset, client) {
if (!modeset->crtc->enabled)
continue;
......@@ -1195,7 +1198,7 @@ static void drm_client_modeset_dpms_legacy(struct drm_client_dev *client, int dp
dev->mode_config.dpms_property, dpms_mode);
}
}
drm_modeset_unlock_all(dev);
DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
}
/**
......
......@@ -2302,7 +2302,8 @@ drm_dp_mst_port_add_connector(struct drm_dp_mst_branch *mstb,
}
if (port->pdt != DP_PEER_DEVICE_NONE &&
drm_dp_mst_is_end_device(port->pdt, port->mcs)) {
drm_dp_mst_is_end_device(port->pdt, port->mcs) &&
port->port_num >= DP_MST_LOGICAL_PORT_0) {
port->cached_edid = drm_get_edid(port->connector,
&port->aux.ddc);
drm_connector_set_tile_property(port->connector);
......
# SPDX-License-Identifier: GPL-2.0-only
config DRM_GMA500
tristate "Intel GMA5/600 KMS Framebuffer"
tristate "Intel GMA500/600/3600/3650 KMS Framebuffer"
depends on DRM && PCI && X86 && MMU
select DRM_KMS_HELPER
select DRM_TTM
# GMA500 depends on ACPI_VIDEO when ACPI is enabled, just like i915
select ACPI_VIDEO if ACPI
select BACKLIGHT_CLASS_DEVICE if ACPI
......@@ -19,17 +18,3 @@ config DRM_GMA600
help
Say yes to include support for GMA600 (Intel Moorestown/Oaktrail)
platforms with LVDS ports. MIPI is not currently supported.
config DRM_GMA3600
bool "Intel GMA3600/3650 support (Experimental)"
depends on DRM_GMA500
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.
......@@ -6,36 +6,35 @@
gma500_gfx-y += \
accel_2d.o \
backlight.o \
blitter.o \
cdv_device.o \
cdv_intel_crt.o \
cdv_intel_display.o \
cdv_intel_dp.o \
cdv_intel_hdmi.o \
cdv_intel_lvds.o \
framebuffer.o \
gem.o \
gma_device.o \
gma_display.o \
gtt.o \
intel_bios.o \
intel_i2c.o \
intel_gmbus.o \
intel_i2c.o \
mid_bios.o \
mmu.o \
blitter.o \
power.o \
psb_device.o \
psb_drv.o \
gma_display.o \
gma_device.o \
psb_intel_display.o \
psb_intel_lvds.o \
psb_intel_modes.o \
psb_intel_sdvo.o \
psb_lid.o \
psb_irq.o \
psb_device.o \
mid_bios.o
psb_irq.o
gma500_gfx-$(CONFIG_ACPI) += opregion.o \
gma500_gfx-$(CONFIG_DRM_GMA3600) += cdv_device.o \
cdv_intel_crt.o \
cdv_intel_display.o \
cdv_intel_hdmi.o \
cdv_intel_lvds.o \
cdv_intel_dp.o
gma500_gfx-$(CONFIG_DRM_GMA600) += oaktrail_device.o \
oaktrail_crtc.o \
oaktrail_lvds.o \
......@@ -43,14 +42,4 @@ 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
......@@ -22,9 +22,6 @@
*
* Authors:
* jim liu <jim.liu@intel.com>
*
* FIXME:
* We should probably make this generic and share it with Medfield
*/
#include <linux/pm_runtime.h>
......@@ -56,7 +53,6 @@ struct mid_intel_hdmi_priv {
bool has_hdmi_audio;
/* Should set this when detect hotplug */
bool hdmi_device_connected;
struct mdfld_hdmi_i2c *i2c_bus;
struct i2c_adapter *hdmi_i2c_adapter; /* for control functions */
struct drm_device *dev;
};
......
// SPDX-License-Identifier: GPL-2.0-only
/**************************************************************************
* Copyright (c) 2011, Intel Corporation.
* All Rights Reserved.
*
**************************************************************************/
#include <linux/delay.h>
#include <linux/gpio/machine.h>
#include <asm/intel_scu_ipc.h>
#include "mdfld_dsi_output.h"
#include "mdfld_output.h"
#include "mid_bios.h"
#include "psb_drv.h"
#include "tc35876x-dsi-lvds.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;
}
static 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;
}
static 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 pipenum)
{
struct drm_psb_private *dev_priv = dev->dev_private;
struct medfield_state *regs = &dev_priv->regs.mdfld;
struct psb_pipe *pipe = &dev_priv->regs.pipe[pipenum];
const struct psb_offset *map = &dev_priv->regmap[pipenum];
int i;
u32 *mipi_val;
/* register */
u32 mipi_reg = MIPI;
switch (pipenum) {
case 0:
mipi_val = &regs->saveMIPI;
break;
case 1:
mipi_val = &regs->saveMIPI;
break;
case 2:
/* register */
mipi_reg = MIPI_C;
/* pointer to values */
mipi_val = &regs->saveMIPI_C;
break;
default:
DRM_ERROR("%s, invalid pipe number.\n", __func__);
return -EINVAL;
}
/* Pipe & plane A info */
pipe->dpll = PSB_RVDC32(map->dpll);
pipe->fp0 = PSB_RVDC32(map->fp0);
pipe->conf = PSB_RVDC32(map->conf);
pipe->htotal = PSB_RVDC32(map->htotal);
pipe->hblank = PSB_RVDC32(map->hblank);
pipe->hsync = PSB_RVDC32(map->hsync);
pipe->vtotal = PSB_RVDC32(map->vtotal);
pipe->vblank = PSB_RVDC32(map->vblank);
pipe->vsync = PSB_RVDC32(map->vsync);
pipe->src = PSB_RVDC32(map->src);
pipe->stride = PSB_RVDC32(map->stride);
pipe->linoff = PSB_RVDC32(map->linoff);
pipe->tileoff = PSB_RVDC32(map->tileoff);
pipe->size = PSB_RVDC32(map->size);
pipe->pos = PSB_RVDC32(map->pos);
pipe->surf = PSB_RVDC32(map->surf);
pipe->cntr = PSB_RVDC32(map->cntr);
pipe->status = PSB_RVDC32(map->status);
/*save palette (gamma) */
for (i = 0; i < 256; i++)
pipe->palette[i] = PSB_RVDC32(map->palette + (i << 2));
if (pipenum == 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 pipenum)
{
/* 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;
struct psb_pipe *pipe = &dev_priv->regs.pipe[pipenum];
const struct psb_offset *map = &dev_priv->regmap[pipenum];
u32 i;
u32 dpll;
u32 timeout = 0;
/* register */
u32 mipi_reg = MIPI;
/* values */
u32 dpll_val = pipe->dpll;
u32 mipi_val = regs->saveMIPI;
switch (pipenum) {
case 0:
dpll_val &= ~DPLL_VCO_ENABLE;
dsi_config = dev_priv->dsi_configs[0];
break;
case 1:
dpll_val &= ~DPLL_VCO_ENABLE;
break;
case 2:
mipi_reg = MIPI_C;
mipi_val = regs->saveMIPI_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 (pipenum == 1) {
PSB_WVDC32(dpll_val & ~DPLL_VCO_ENABLE, map->dpll);
PSB_RVDC32(map->dpll);
PSB_WVDC32(pipe->fp0, map->fp0);
} else {
dpll = PSB_RVDC32(map->dpll);
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, map->dpll);
/* FIXME_MDFLD PO - change 500 to 1 after PO */
udelay(500);
}
PSB_WVDC32(pipe->fp0, map->fp0);
PSB_WVDC32(dpll_val, map->dpll);
/* FIXME_MDFLD PO - change 500 to 1 after PO */
udelay(500);
dpll_val |= DPLL_VCO_ENABLE;
PSB_WVDC32(dpll_val, map->dpll);
PSB_RVDC32(map->dpll);
/* wait for DSI PLL to lock */
while (timeout < 20000 &&
!(PSB_RVDC32(map->conf) & PIPECONF_DSIPLL_LOCK)) {
udelay(150);
timeout++;
}
if (timeout == 20000) {
DRM_ERROR("%s, can't lock DSIPLL.\n",
__func__);
return -EINVAL;
}
}
}
/* Restore mode */
PSB_WVDC32(pipe->htotal, map->htotal);
PSB_WVDC32(pipe->hblank, map->hblank);
PSB_WVDC32(pipe->hsync, map->hsync);
PSB_WVDC32(pipe->vtotal, map->vtotal);
PSB_WVDC32(pipe->vblank, map->vblank);
PSB_WVDC32(pipe->vsync, map->vsync);
PSB_WVDC32(pipe->src, map->src);
PSB_WVDC32(pipe->status, map->status);
/*set up the plane*/
PSB_WVDC32(pipe->stride, map->stride);
PSB_WVDC32(pipe->linoff, map->linoff);
PSB_WVDC32(pipe->tileoff, map->tileoff);
PSB_WVDC32(pipe->size, map->size);
PSB_WVDC32(pipe->pos, map->pos);
PSB_WVDC32(pipe->surf, map->surf);
if (pipenum == 1) {
/* restore palette (gamma) */
/* udelay(50000); */
for (i = 0; i < 256; i++)
PSB_WVDC32(pipe->palette[i], map->palette + (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(pipe->cntr & ~DISPLAY_PLANE_ENABLE, map->cntr);
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, pipenum);
if (in_atomic() || in_interrupt())
mdelay(20);
else
msleep(20);
/*enable the plane*/
PSB_WVDC32(pipe->cntr, map->cntr);
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(pipe->conf, map->conf);
/* restore palette (gamma) */
/* udelay(50000); */
for (i = 0; i < 256; i++)
PSB_WVDC32(pipe->palette[i], map->palette + (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;
}
/* Medfield */
static const struct psb_offset mdfld_regmap[3] = {
{
.fp0 = MRST_FPA0,
.fp1 = MRST_FPA1,
.cntr = DSPACNTR,
.conf = PIPEACONF,
.src = PIPEASRC,
.dpll = MRST_DPLL_A,
.htotal = HTOTAL_A,
.hblank = HBLANK_A,
.hsync = HSYNC_A,
.vtotal = VTOTAL_A,
.vblank = VBLANK_A,
.vsync = VSYNC_A,
.stride = DSPASTRIDE,
.size = DSPASIZE,
.pos = DSPAPOS,
.surf = DSPASURF,
.addr = MRST_DSPABASE,
.status = PIPEASTAT,
.linoff = DSPALINOFF,
.tileoff = DSPATILEOFF,
.palette = PALETTE_A,
},
{
.fp0 = MDFLD_DPLL_DIV0,
.cntr = DSPBCNTR,
.conf = PIPEBCONF,
.src = PIPEBSRC,
.dpll = MDFLD_DPLL_B,
.htotal = HTOTAL_B,
.hblank = HBLANK_B,
.hsync = HSYNC_B,
.vtotal = VTOTAL_B,
.vblank = VBLANK_B,
.vsync = VSYNC_B,
.stride = DSPBSTRIDE,
.size = DSPBSIZE,
.pos = DSPBPOS,
.surf = DSPBSURF,
.addr = MRST_DSPBBASE,
.status = PIPEBSTAT,
.linoff = DSPBLINOFF,
.tileoff = DSPBTILEOFF,
.palette = PALETTE_B,
},
{
.fp0 = MRST_FPA0, /* This is what the old code did ?? */
.cntr = DSPCCNTR,
.conf = PIPECCONF,
.src = PIPECSRC,
/* No DPLL_C */
.dpll = MRST_DPLL_A,
.htotal = HTOTAL_C,
.hblank = HBLANK_C,
.hsync = HSYNC_C,
.vtotal = VTOTAL_C,
.vblank = VBLANK_C,
.vsync = VSYNC_C,
.stride = DSPCSTRIDE,
.size = DSPBSIZE,
.pos = DSPCPOS,
.surf = DSPCSURF,
.addr = MDFLD_DSPCBASE,
.status = PIPECSTAT,
.linoff = DSPCLINOFF,
.tileoff = DSPCTILEOFF,
.palette = PALETTE_C,
},
};
/*
* The GPIO lines for resetting DSI pipe 0 and 2 are available in the
* PCI device 0000:00:0c.0 on the Medfield.
*/
static struct gpiod_lookup_table mdfld_dsi_pipe_gpio_table = {
.table = {
GPIO_LOOKUP("0000:00:0c.0", 128, "dsi-pipe0-reset",
GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("0000:00:0c.0", 34, "dsi-pipe2-reset",
GPIO_ACTIVE_HIGH),
{ },
},
};
static int mdfld_chip_setup(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
struct pci_dev *pdev = to_pci_dev(dev->dev);
if (pci_enable_msi(pdev))
dev_warn(dev->dev, "Enabling MSI failed!\n");
dev_priv->regmap = mdfld_regmap;
/* Associate the GPIO lines with the DRM device */
mdfld_dsi_pipe_gpio_table.dev_id = dev_name(dev->dev);
gpiod_add_lookup_table(&mdfld_dsi_pipe_gpio_table);
return mid_chip_setup(dev);
}
const struct psb_ops mdfld_chip_ops = {
.name = "mdfld",
.pipes = 3,
.crtcs = 3,
.lvds_mask = (1 << 1),
.hdmi_mask = (1 << 1),
.cursor_needs_phys = 0,
.sgx_offset = MRST_SGX_OFFSET,
.chip_setup = mdfld_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,
.save_crtc = gma_crtc_save,
.restore_crtc = gma_crtc_restore,
.power_down = mdfld_power_down,
.power_up = mdfld_power_up,
};
此差异已折叠。
/*
* 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,
const 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__*/
/*
* 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/delay.h>
#include <linux/moduleparam.h>
#include <linux/pm_runtime.h>
#include <linux/gpio/consumer.h>
#include <asm/intel_scu_ipc.h>
#include "mdfld_dsi_dpi.h"
#include "mdfld_dsi_output.h"
#include "mdfld_dsi_pkg_sender.h"
#include "mdfld_output.h"
#include "tc35876x-dsi-lvds.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;
struct drm_psb_private *dev_priv;
u32 gen_ctrl_val;
if (!sender) {
DRM_ERROR("No sender found\n");
return;
}
dev = sender->dev;
dev_priv = dev->dev_private;
/* 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);
}
/*
* 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;
if (!strcmp(property->name, "scaling mode") && encoder) {
struct gma_crtc *gma_crtc = to_gma_crtc(encoder->crtc);
bool centerechange;
uint64_t val;
if (!gma_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_object_property_get_value(&connector->base, property, &val))
goto set_prop_error;
if (val == value)
goto set_prop_done;
if (drm_object_property_set_value(&connector->base,
property, value))
goto set_prop_error;
centerechange = (val == DRM_MODE_SCALE_NO_SCALE) ||
(value == DRM_MODE_SCALE_NO_SCALE);
if (gma_crtc->saved_mode.hdisplay != 0 &&
gma_crtc->saved_mode.vdisplay != 0) {
if (centerechange) {
if (!drm_crtc_helper_set_mode(encoder->crtc,
&gma_crtc->saved_mode,
encoder->crtc->x,
encoder->crtc->y,
encoder->crtc->primary->fb))
goto set_prop_error;
} else {
const struct drm_encoder_helper_funcs *funcs =
encoder->helper_private;
funcs->mode_set(encoder,
&gma_crtc->saved_mode,
&gma_crtc->saved_adjusted_mode);
}
}
} else if (!strcmp(property->name, "backlight") && encoder) {
if (drm_object_property_set_value(&connector->base, property,
value))
goto set_prop_error;
else
gma_backlight_set(encoder->dev, value);
}
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_connector_unregister(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;
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 enum drm_mode_status 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(panel 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 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,
.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(struct drm_device *ddev, int pipe)
{
struct device *dev = ddev->dev;
struct gpio_desc *gpiod;
/*
* Raise the GPIO reset line for the corresponding pipe to HIGH,
* this is probably because it is active low so this takes the
* respective pipe out of reset. (We have no code to put it back
* into reset in this driver.)
*/
switch (pipe) {
case 0:
gpiod = gpiod_get(dev, "dsi-pipe0-reset", GPIOD_OUT_HIGH);
if (IS_ERR(gpiod))
return PTR_ERR(gpiod);
break;
case 2:
gpiod = gpiod_get(dev, "dsi-pipe2-reset", GPIOD_OUT_HIGH);
if (IS_ERR(gpiod))
return PTR_ERR(gpiod);
break;
default:
DRM_DEV_ERROR(dev, "Invalid output pipe\n");
return -EINVAL;
}
gpiod_put(gpiod);
/* Flush posted writes on the device */
gpiod = gpiod_get(dev, "dsi-pipe0-reset", GPIOD_ASIS);
if (IS_ERR(gpiod))
return PTR_ERR(gpiod);
gpiod_get_value(gpiod);
gpiod_put(gpiod);
return 0;
}
/*
* 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,
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 (pipe != 0 && pipe != 2) {
DRM_ERROR("Invalid parameter\n");
return;
}
/*create a new connector*/
dsi_connector = kzalloc(sizeof(struct mdfld_dsi_connector), GFP_KERNEL);
if (!dsi_connector) {
DRM_ERROR("No memory");
return;
}
dsi_connector->pipe = pipe;
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 panel 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;
dsi_connector->base.save = mdfld_dsi_connector_save;
dsi_connector->base.restore = mdfld_dsi_connector_restore;
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_object_attach_property(&connector->base,
dev->mode_config.scaling_mode_property,
DRM_MODE_SCALE_FULLSCREEN);
drm_object_attach_property(&connector->base,
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_connector_register(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);
}
/*
* 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 <asm/intel-mid.h>
#include <drm/drm.h>
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include "mdfld_output.h"
#include "psb_drv.h"
#include "psb_intel_drv.h"
#include "psb_intel_reg.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 {
struct gma_connector base;
int pipe;
void *private;
void *pkg_sender;
/* Connection status */
enum drm_connector_status status;
};
struct mdfld_dsi_encoder {
struct gma_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 gma_connector *gma_connector;
gma_connector = to_gma_connector(connector);
return container_of(gma_connector, struct mdfld_dsi_connector, base);
}
static inline struct mdfld_dsi_encoder *mdfld_dsi_encoder(
struct drm_encoder *encoder)
{
struct gma_encoder *gma_encoder;
gma_encoder = to_gma_encoder(encoder);
return container_of(gma_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,
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_panel_reset(struct drm_device *dev, int pipe);
#endif /*__MDFLD_DSI_OUTPUT_H__*/
/*
* 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/delay.h>
#include <linux/freezer.h>
#include <video/mipi_display.h>
#include "mdfld_dsi_dpi.h"
#include "mdfld_dsi_output.h"
#include "mdfld_dsi_pkg_sender.h"
#define MDFLD_DSI_READ_MAX_COUNT 5000
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 MIPI_DSI_DCS_SHORT_WRITE:
case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
case MIPI_DSI_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 == MIPI_DCS_ENTER_SLEEP_MODE)) {
/*TODO: replace it with msleep later*/
mdelay(120);
}
if (unlikely(cmd == MIPI_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 MIPI_DSI_DCS_SHORT_WRITE:
case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
case MIPI_DSI_DCS_LONG_WRITE:
cmd = *data;
break;
default:
return 0;
}
/*update panel status*/
if (unlikely(cmd == MIPI_DCS_ENTER_SLEEP_MODE)) {
sender->panel_mode |= MDFLD_DSI_PANEL_MODE_SLEEP;
/*TODO: replace it with msleep later*/
mdelay(120);
} else if (unlikely(cmd == MIPI_DCS_EXIT_SLEEP_MODE)) {
sender->panel_mode &= ~MDFLD_DSI_PANEL_MODE_SLEEP;
/*TODO: replace it with msleep later*/
mdelay(120);
} else if (unlikely(cmd == MIPI_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 MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
case MIPI_DSI_DCS_SHORT_WRITE:
case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
case MIPI_DSI_DCS_READ:
ret = send_short_pkg(sender, data_type, data[0], data[1], hs);
break;
case MIPI_DSI_GENERIC_LONG_WRITE:
case MIPI_DSI_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, MIPI_DSI_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 = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
data[1] = param;
} else {
data_type = MIPI_DSI_DCS_SHORT_WRITE;
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 > 2) {
DRM_ERROR("Invalid parameter\n");
return -EINVAL;
}
switch (param_num) {
case 0:
data_type = MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM;
data[0] = 0;
data[1] = 0;
break;
case 1:
data_type = MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM;
data[0] = param0;
data[1] = 0;
break;
case 2:
data_type = MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM;
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, MIPI_DSI_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;
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;
}
dev = sender->dev;
/**
* 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, MIPI_DSI_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;
struct drm_psb_private *dev_priv = dev->dev_private;
const struct psb_offset *map = &dev_priv->regmap[pipe];
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*/
/* FIXME: should just copy the regmap ptr ? */
pkg_sender->dpll_reg = map->dpll;
pkg_sender->dspcntr_reg = map->cntr;
pkg_sender->pipeconf_reg = map->conf;
pkg_sender->dsplinoff_reg = map->linoff;
pkg_sender->dspsurf_reg = map->surf;
pkg_sender->pipestat_reg = map->status;
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);
}
/*
* 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;
};
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
此差异已折叠。
/*
* 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, &mdfld_tpo_vid_funcs);
break;
case TC35876X:
tc35876x_init(dev);
mdfld_dsi_output_init(dev, mipi_pipe, &mdfld_tc35876x_funcs);
break;
case TMD_VID:
mdfld_dsi_output_init(dev, mipi_pipe, &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;
}
/*
* 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_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)(struct drm_device *, int);
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
/*
* 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 <linux/delay.h>
#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,
};
const struct panel_funcs mdfld_tmd_vid_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,
};
此差异已折叠。
......@@ -48,7 +48,6 @@ static inline uint32_t psb_mmu_pd_index(uint32_t offset)
return offset >> PSB_PDE_SHIFT;
}
#if defined(CONFIG_X86)
static inline void psb_clflush(void *addr)
{
__asm__ __volatile__("clflush (%0)\n" : : "r"(addr) : "memory");
......@@ -63,13 +62,6 @@ static inline void psb_mmu_clflush(struct psb_mmu_driver *driver, void *addr)
psb_clflush(addr);
mb();
}
#else
static inline void psb_mmu_clflush(struct psb_mmu_driver *driver, void *addr)
{;
}
#endif
static void psb_mmu_flush_pd_locked(struct psb_mmu_driver *driver, int force)
{
......@@ -293,7 +285,6 @@ static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd)
for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i)
*ptes++ = pd->invalid_pte;
#if defined(CONFIG_X86)
if (pd->driver->has_clflush && pd->hw_context != -1) {
mb();
for (i = 0; i < clflush_count; ++i) {
......@@ -302,7 +293,6 @@ static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd)
}
mb();
}
#endif
kunmap_atomic(v);
spin_unlock(lock);
......@@ -459,7 +449,6 @@ struct psb_mmu_driver *psb_mmu_driver_init(struct drm_device *dev,
driver->has_clflush = 0;
#if defined(CONFIG_X86)
if (boot_cpu_has(X86_FEATURE_CLFLUSH)) {
uint32_t tfms, misc, cap0, cap4, clflush_size;
......@@ -476,7 +465,6 @@ struct psb_mmu_driver *psb_mmu_driver_init(struct drm_device *dev,
driver->clflush_mask = driver->clflush_add - 1;
driver->clflush_mask = ~driver->clflush_mask;
}
#endif
up_write(&driver->sem);
return driver;
......@@ -486,7 +474,6 @@ struct psb_mmu_driver *psb_mmu_driver_init(struct drm_device *dev,
return NULL;
}
#if defined(CONFIG_X86)
static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, unsigned long address,
uint32_t num_pages, uint32_t desired_tile_stride,
uint32_t hw_tile_stride)
......@@ -534,14 +521,6 @@ static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, unsigned long address,
}
mb();
}
#else
static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, unsigned long address,
uint32_t num_pages, uint32_t desired_tile_stride,
uint32_t hw_tile_stride)
{
drm_ttm_cache_flush();
}
#endif
void psb_mmu_remove_pfn_sequence(struct psb_mmu_pd *pd,
unsigned long address, uint32_t num_pages)
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册