mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-01 08:04:22 +08:00
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. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEuXvWqAysSYEJGuVH/lWMcqZwE8MFAmAlT9AACgkQ/lWMcqZw E8OJWg//S98XkPuGyjuvGuBdjc5RU8mU76Zu849y7PYb0IW0Ep4QSss3Ustw1gu1 9b7TaLzn9trU9L2p7DIKxPM1PypnkFtg+dY4EFeQk5mgSMwoybhe6vqaKV3M6d/v XjvDWHKuawLeMmoxg+l8X/YehLMzIIfd+EHWIH6NmqYClf4onzxntmsnH4oWy78c boVe1wkjyQIbgB8rp24QJlFpy2Eo/HofWjRHMgSIYm5hm985B3S9/xFlYf1WTXMw nTtbhzAyolYtYiw2obGKJvikrpaDPP1gz5ylWF+o5O4dtg1DH+OcDQ/g/sQhOcf1 e6UD4NlwvIgOyn9OByPlxwjCJMMxiFJS0Nccp3kpGk35TnNK5t/i/jByadk92P+W if38lAHoVGkVEEfSYKhsSvgLJr43cV4O6/Nz0ZcNfi9XZLIsF7jXM6iVYrIK+Dns UQ6QIKSgag4RWeiqZFYmNx1oE2B/UEE2crwziAP1WymuK33idtAAJ5vazLTVLsNc exIxbVmw5/obUdblZNpFgRSM6KzucAeOlvdb6hPASJ9/Z2D3Uecp7L8fiQypSPAK vpXbQrrfDu0fFemwIyfMeCwfW0RkZmlaHXDAFh6fl9SUREeG6cNedYme62MDfr3h 3tnoQkfiP/+hi1EiK42I7UGUAp+SZMZ5sGW9ENY/p0WKWSQTkGI= =YN2m -----END PGP SIGNATURE----- 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: Dave 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
This commit is contained in:
commit
ef23d5008b
@ -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);
|
||||
|
@ -1,9 +1,8 @@
|
||||
# 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;
|
||||
};
|
||||
|
@ -1,564 +0,0 @@
|
||||
// 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 = ®s->saveMIPI;
|
||||
break;
|
||||
case 1:
|
||||
mipi_val = ®s->saveMIPI;
|
||||
break;
|
||||
case 2:
|
||||
/* register */
|
||||
mipi_reg = MIPI_C;
|
||||
/* pointer to values */
|
||||
mipi_val = ®s->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,
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -1,79 +0,0 @@
|
||||
/*
|
||||
* 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__*/
|
@ -1,603 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
@ -1,377 +0,0 @@
|
||||
/*
|
||||
* 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__*/
|
@ -1,679 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
@ -1,80 +0,0 @@
|
||||
/*
|
||||
* 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
|
@ -1,966 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright © 2006-2007 Intel Corporation
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
|
||||
#include "framebuffer.h"
|
||||
#include "gma_display.h"
|
||||
#include "mdfld_dsi_output.h"
|
||||
#include "mdfld_output.h"
|
||||
#include "psb_intel_reg.h"
|
||||
|
||||
/* Hardcoded currently */
|
||||
static int ksel = KSEL_CRYSTAL_19;
|
||||
|
||||
struct psb_intel_range_t {
|
||||
int min, max;
|
||||
};
|
||||
|
||||
struct mrst_limit_t {
|
||||
struct psb_intel_range_t dot, m, p1;
|
||||
};
|
||||
|
||||
struct mrst_clock_t {
|
||||
/* derived values */
|
||||
int dot;
|
||||
int m;
|
||||
int p1;
|
||||
};
|
||||
|
||||
#define COUNT_MAX 0x10000000
|
||||
|
||||
void mdfldWaitForPipeDisable(struct drm_device *dev, int pipe)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
const struct psb_offset *map = &dev_priv->regmap[pipe];
|
||||
int count, temp;
|
||||
|
||||
switch (pipe) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Illegal Pipe Number.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* FIXME JLIU7_PO */
|
||||
gma_wait_for_vblank(dev);
|
||||
return;
|
||||
|
||||
/* Wait for for the pipe disable to take effect. */
|
||||
for (count = 0; count < COUNT_MAX; count++) {
|
||||
temp = REG_READ(map->conf);
|
||||
if ((temp & PIPEACONF_PIPE_STATE) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void mdfldWaitForPipeEnable(struct drm_device *dev, int pipe)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
const struct psb_offset *map = &dev_priv->regmap[pipe];
|
||||
int count, temp;
|
||||
|
||||
switch (pipe) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Illegal Pipe Number.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* FIXME JLIU7_PO */
|
||||
gma_wait_for_vblank(dev);
|
||||
return;
|
||||
|
||||
/* Wait for for the pipe enable to take effect. */
|
||||
for (count = 0; count < COUNT_MAX; count++) {
|
||||
temp = REG_READ(map->conf);
|
||||
if (temp & PIPEACONF_PIPE_STATE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the pipe currently connected to the panel fitter,
|
||||
* or -1 if the panel fitter is not present or not in use
|
||||
*/
|
||||
static int psb_intel_panel_fitter_pipe(struct drm_device *dev)
|
||||
{
|
||||
u32 pfit_control;
|
||||
|
||||
pfit_control = REG_READ(PFIT_CONTROL);
|
||||
|
||||
/* See if the panel fitter is in use */
|
||||
if ((pfit_control & PFIT_ENABLE) == 0)
|
||||
return -1;
|
||||
|
||||
/* 965 can place panel fitter on either pipe */
|
||||
return (pfit_control >> 29) & 0x3;
|
||||
}
|
||||
|
||||
static int check_fb(struct drm_framebuffer *fb)
|
||||
{
|
||||
if (!fb)
|
||||
return 0;
|
||||
|
||||
switch (fb->format->cpp[0] * 8) {
|
||||
case 8:
|
||||
case 16:
|
||||
case 24:
|
||||
case 32:
|
||||
return 0;
|
||||
default:
|
||||
DRM_ERROR("Unknown color depth\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
||||
struct drm_framebuffer *old_fb)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct drm_framebuffer *fb = crtc->primary->fb;
|
||||
struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
|
||||
int pipe = gma_crtc->pipe;
|
||||
const struct psb_offset *map = &dev_priv->regmap[pipe];
|
||||
unsigned long start, offset;
|
||||
u32 dspcntr;
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev->dev, "pipe = 0x%x.\n", pipe);
|
||||
|
||||
/* no fb bound */
|
||||
if (!fb) {
|
||||
dev_dbg(dev->dev, "No FB bound\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = check_fb(fb);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (pipe > 2) {
|
||||
DRM_ERROR("Illegal Pipe Number.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!gma_power_begin(dev, true))
|
||||
return 0;
|
||||
|
||||
start = to_gtt_range(fb->obj[0])->offset;
|
||||
offset = y * fb->pitches[0] + x * fb->format->cpp[0];
|
||||
|
||||
REG_WRITE(map->stride, fb->pitches[0]);
|
||||
dspcntr = REG_READ(map->cntr);
|
||||
dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
|
||||
|
||||
switch (fb->format->cpp[0] * 8) {
|
||||
case 8:
|
||||
dspcntr |= DISPPLANE_8BPP;
|
||||
break;
|
||||
case 16:
|
||||
if (fb->format->depth == 15)
|
||||
dspcntr |= DISPPLANE_15_16BPP;
|
||||
else
|
||||
dspcntr |= DISPPLANE_16BPP;
|
||||
break;
|
||||
case 24:
|
||||
case 32:
|
||||
dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
|
||||
break;
|
||||
}
|
||||
REG_WRITE(map->cntr, dspcntr);
|
||||
|
||||
dev_dbg(dev->dev, "Writing base %08lX %08lX %d %d\n",
|
||||
start, offset, x, y);
|
||||
REG_WRITE(map->linoff, offset);
|
||||
REG_READ(map->linoff);
|
||||
REG_WRITE(map->surf, start);
|
||||
REG_READ(map->surf);
|
||||
|
||||
gma_power_end(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable the pipe, plane and pll.
|
||||
*
|
||||
*/
|
||||
void mdfld_disable_crtc(struct drm_device *dev, int pipe)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
const struct psb_offset *map = &dev_priv->regmap[pipe];
|
||||
u32 temp;
|
||||
|
||||
dev_dbg(dev->dev, "pipe = %d\n", pipe);
|
||||
|
||||
|
||||
if (pipe != 1)
|
||||
mdfld_dsi_gen_fifo_ready(dev, MIPI_GEN_FIFO_STAT_REG(pipe),
|
||||
HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY);
|
||||
|
||||
/* Disable display plane */
|
||||
temp = REG_READ(map->cntr);
|
||||
if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
|
||||
REG_WRITE(map->cntr,
|
||||
temp & ~DISPLAY_PLANE_ENABLE);
|
||||
/* Flush the plane changes */
|
||||
REG_WRITE(map->base, REG_READ(map->base));
|
||||
REG_READ(map->base);
|
||||
}
|
||||
|
||||
/* FIXME_JLIU7 MDFLD_PO revisit */
|
||||
|
||||
/* Next, disable display pipes */
|
||||
temp = REG_READ(map->conf);
|
||||
if ((temp & PIPEACONF_ENABLE) != 0) {
|
||||
temp &= ~PIPEACONF_ENABLE;
|
||||
temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF;
|
||||
REG_WRITE(map->conf, temp);
|
||||
REG_READ(map->conf);
|
||||
|
||||
/* Wait for for the pipe disable to take effect. */
|
||||
mdfldWaitForPipeDisable(dev, pipe);
|
||||
}
|
||||
|
||||
temp = REG_READ(map->dpll);
|
||||
if (temp & DPLL_VCO_ENABLE) {
|
||||
if ((pipe != 1 &&
|
||||
!((REG_READ(PIPEACONF) | REG_READ(PIPECCONF))
|
||||
& PIPEACONF_ENABLE)) || pipe == 1) {
|
||||
temp &= ~(DPLL_VCO_ENABLE);
|
||||
REG_WRITE(map->dpll, temp);
|
||||
REG_READ(map->dpll);
|
||||
/* Wait for the clocks to turn off. */
|
||||
/* FIXME_MDFLD PO may need more delay */
|
||||
udelay(500);
|
||||
|
||||
if (!(temp & MDFLD_PWR_GATE_EN)) {
|
||||
/* gating power of DPLL */
|
||||
REG_WRITE(map->dpll, temp | MDFLD_PWR_GATE_EN);
|
||||
/* FIXME_MDFLD PO - change 500 to 1 after PO */
|
||||
udelay(5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the power management mode of the pipe and plane.
|
||||
*
|
||||
* This code should probably grow support for turning the cursor off and back
|
||||
* on appropriately at the same time as we're turning the pipe off/on.
|
||||
*/
|
||||
static void mdfld_crtc_dpms(struct drm_crtc *crtc, int mode)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
|
||||
int pipe = gma_crtc->pipe;
|
||||
const struct psb_offset *map = &dev_priv->regmap[pipe];
|
||||
u32 pipeconf = dev_priv->pipeconf[pipe];
|
||||
u32 temp;
|
||||
int timeout = 0;
|
||||
|
||||
dev_dbg(dev->dev, "mode = %d, pipe = %d\n", mode, pipe);
|
||||
|
||||
/* Note: Old code uses pipe a stat for pipe b but that appears
|
||||
to be a bug */
|
||||
|
||||
if (!gma_power_begin(dev, true))
|
||||
return;
|
||||
|
||||
/* XXX: When our outputs are all unaware of DPMS modes other than off
|
||||
* and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
|
||||
*/
|
||||
switch (mode) {
|
||||
case DRM_MODE_DPMS_ON:
|
||||
case DRM_MODE_DPMS_STANDBY:
|
||||
case DRM_MODE_DPMS_SUSPEND:
|
||||
/* Enable the DPLL */
|
||||
temp = REG_READ(map->dpll);
|
||||
|
||||
if ((temp & DPLL_VCO_ENABLE) == 0) {
|
||||
/* When ungating power of DPLL, needs to wait 0.5us
|
||||
before enable the VCO */
|
||||
if (temp & MDFLD_PWR_GATE_EN) {
|
||||
temp &= ~MDFLD_PWR_GATE_EN;
|
||||
REG_WRITE(map->dpll, temp);
|
||||
/* FIXME_MDFLD PO - change 500 to 1 after PO */
|
||||
udelay(500);
|
||||
}
|
||||
|
||||
REG_WRITE(map->dpll, temp);
|
||||
REG_READ(map->dpll);
|
||||
/* FIXME_MDFLD PO - change 500 to 1 after PO */
|
||||
udelay(500);
|
||||
|
||||
REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE);
|
||||
REG_READ(map->dpll);
|
||||
|
||||
/**
|
||||
* wait for DSI PLL to lock
|
||||
* NOTE: only need to poll status of pipe 0 and pipe 1,
|
||||
* since both MIPI pipes share the same PLL.
|
||||
*/
|
||||
while ((pipe != 2) && (timeout < 20000) &&
|
||||
!(REG_READ(map->conf) & PIPECONF_DSIPLL_LOCK)) {
|
||||
udelay(150);
|
||||
timeout++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable the plane */
|
||||
temp = REG_READ(map->cntr);
|
||||
if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
|
||||
REG_WRITE(map->cntr,
|
||||
temp | DISPLAY_PLANE_ENABLE);
|
||||
/* Flush the plane changes */
|
||||
REG_WRITE(map->base, REG_READ(map->base));
|
||||
}
|
||||
|
||||
/* Enable the pipe */
|
||||
temp = REG_READ(map->conf);
|
||||
if ((temp & PIPEACONF_ENABLE) == 0) {
|
||||
REG_WRITE(map->conf, pipeconf);
|
||||
|
||||
/* Wait for for the pipe enable to take effect. */
|
||||
mdfldWaitForPipeEnable(dev, pipe);
|
||||
}
|
||||
|
||||
/*workaround for sighting 3741701 Random X blank display*/
|
||||
/*perform w/a in video mode only on pipe A or C*/
|
||||
if (pipe == 0 || pipe == 2) {
|
||||
REG_WRITE(map->status, REG_READ(map->status));
|
||||
msleep(100);
|
||||
if (PIPE_VBLANK_STATUS & REG_READ(map->status))
|
||||
dev_dbg(dev->dev, "OK");
|
||||
else {
|
||||
dev_dbg(dev->dev, "STUCK!!!!");
|
||||
/*shutdown controller*/
|
||||
temp = REG_READ(map->cntr);
|
||||
REG_WRITE(map->cntr,
|
||||
temp & ~DISPLAY_PLANE_ENABLE);
|
||||
REG_WRITE(map->base, REG_READ(map->base));
|
||||
/*mdfld_dsi_dpi_shut_down(dev, pipe);*/
|
||||
REG_WRITE(0xb048, 1);
|
||||
msleep(100);
|
||||
temp = REG_READ(map->conf);
|
||||
temp &= ~PIPEACONF_ENABLE;
|
||||
REG_WRITE(map->conf, temp);
|
||||
msleep(100); /*wait for pipe disable*/
|
||||
REG_WRITE(MIPI_DEVICE_READY_REG(pipe), 0);
|
||||
msleep(100);
|
||||
REG_WRITE(0xb004, REG_READ(0xb004));
|
||||
/* try to bring the controller back up again*/
|
||||
REG_WRITE(MIPI_DEVICE_READY_REG(pipe), 1);
|
||||
temp = REG_READ(map->cntr);
|
||||
REG_WRITE(map->cntr,
|
||||
temp | DISPLAY_PLANE_ENABLE);
|
||||
REG_WRITE(map->base, REG_READ(map->base));
|
||||
/*mdfld_dsi_dpi_turn_on(dev, pipe);*/
|
||||
REG_WRITE(0xb048, 2);
|
||||
msleep(100);
|
||||
temp = REG_READ(map->conf);
|
||||
temp |= PIPEACONF_ENABLE;
|
||||
REG_WRITE(map->conf, temp);
|
||||
}
|
||||
}
|
||||
|
||||
gma_crtc_load_lut(crtc);
|
||||
|
||||
/* Give the overlay scaler a chance to enable
|
||||
if it's on this pipe */
|
||||
/* psb_intel_crtc_dpms_video(crtc, true); TODO */
|
||||
|
||||
break;
|
||||
case DRM_MODE_DPMS_OFF:
|
||||
/* Give the overlay scaler a chance to disable
|
||||
* if it's on this pipe */
|
||||
/* psb_intel_crtc_dpms_video(crtc, FALSE); TODO */
|
||||
if (pipe != 1)
|
||||
mdfld_dsi_gen_fifo_ready(dev,
|
||||
MIPI_GEN_FIFO_STAT_REG(pipe),
|
||||
HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY);
|
||||
|
||||
/* Disable the VGA plane that we never use */
|
||||
REG_WRITE(VGACNTRL, VGA_DISP_DISABLE);
|
||||
|
||||
/* Disable display plane */
|
||||
temp = REG_READ(map->cntr);
|
||||
if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
|
||||
REG_WRITE(map->cntr,
|
||||
temp & ~DISPLAY_PLANE_ENABLE);
|
||||
/* Flush the plane changes */
|
||||
REG_WRITE(map->base, REG_READ(map->base));
|
||||
REG_READ(map->base);
|
||||
}
|
||||
|
||||
/* Next, disable display pipes */
|
||||
temp = REG_READ(map->conf);
|
||||
if ((temp & PIPEACONF_ENABLE) != 0) {
|
||||
temp &= ~PIPEACONF_ENABLE;
|
||||
temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF;
|
||||
REG_WRITE(map->conf, temp);
|
||||
REG_READ(map->conf);
|
||||
|
||||
/* Wait for for the pipe disable to take effect. */
|
||||
mdfldWaitForPipeDisable(dev, pipe);
|
||||
}
|
||||
|
||||
temp = REG_READ(map->dpll);
|
||||
if (temp & DPLL_VCO_ENABLE) {
|
||||
if ((pipe != 1 && !((REG_READ(PIPEACONF)
|
||||
| REG_READ(PIPECCONF)) & PIPEACONF_ENABLE))
|
||||
|| pipe == 1) {
|
||||
temp &= ~(DPLL_VCO_ENABLE);
|
||||
REG_WRITE(map->dpll, temp);
|
||||
REG_READ(map->dpll);
|
||||
/* Wait for the clocks to turn off. */
|
||||
/* FIXME_MDFLD PO may need more delay */
|
||||
udelay(500);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
gma_power_end(dev);
|
||||
}
|
||||
|
||||
|
||||
#define MDFLD_LIMT_DPLL_19 0
|
||||
#define MDFLD_LIMT_DPLL_25 1
|
||||
#define MDFLD_LIMT_DPLL_83 2
|
||||
#define MDFLD_LIMT_DPLL_100 3
|
||||
#define MDFLD_LIMT_DSIPLL_19 4
|
||||
#define MDFLD_LIMT_DSIPLL_25 5
|
||||
#define MDFLD_LIMT_DSIPLL_83 6
|
||||
#define MDFLD_LIMT_DSIPLL_100 7
|
||||
|
||||
#define MDFLD_DOT_MIN 19750
|
||||
#define MDFLD_DOT_MAX 120000
|
||||
#define MDFLD_DPLL_M_MIN_19 113
|
||||
#define MDFLD_DPLL_M_MAX_19 155
|
||||
#define MDFLD_DPLL_P1_MIN_19 2
|
||||
#define MDFLD_DPLL_P1_MAX_19 10
|
||||
#define MDFLD_DPLL_M_MIN_25 101
|
||||
#define MDFLD_DPLL_M_MAX_25 130
|
||||
#define MDFLD_DPLL_P1_MIN_25 2
|
||||
#define MDFLD_DPLL_P1_MAX_25 10
|
||||
#define MDFLD_DPLL_M_MIN_83 64
|
||||
#define MDFLD_DPLL_M_MAX_83 64
|
||||
#define MDFLD_DPLL_P1_MIN_83 2
|
||||
#define MDFLD_DPLL_P1_MAX_83 2
|
||||
#define MDFLD_DPLL_M_MIN_100 64
|
||||
#define MDFLD_DPLL_M_MAX_100 64
|
||||
#define MDFLD_DPLL_P1_MIN_100 2
|
||||
#define MDFLD_DPLL_P1_MAX_100 2
|
||||
#define MDFLD_DSIPLL_M_MIN_19 131
|
||||
#define MDFLD_DSIPLL_M_MAX_19 175
|
||||
#define MDFLD_DSIPLL_P1_MIN_19 3
|
||||
#define MDFLD_DSIPLL_P1_MAX_19 8
|
||||
#define MDFLD_DSIPLL_M_MIN_25 97
|
||||
#define MDFLD_DSIPLL_M_MAX_25 140
|
||||
#define MDFLD_DSIPLL_P1_MIN_25 3
|
||||
#define MDFLD_DSIPLL_P1_MAX_25 9
|
||||
#define MDFLD_DSIPLL_M_MIN_83 33
|
||||
#define MDFLD_DSIPLL_M_MAX_83 92
|
||||
#define MDFLD_DSIPLL_P1_MIN_83 2
|
||||
#define MDFLD_DSIPLL_P1_MAX_83 3
|
||||
#define MDFLD_DSIPLL_M_MIN_100 97
|
||||
#define MDFLD_DSIPLL_M_MAX_100 140
|
||||
#define MDFLD_DSIPLL_P1_MIN_100 3
|
||||
#define MDFLD_DSIPLL_P1_MAX_100 9
|
||||
|
||||
static const struct mrst_limit_t mdfld_limits[] = {
|
||||
{ /* MDFLD_LIMT_DPLL_19 */
|
||||
.dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
|
||||
.m = {.min = MDFLD_DPLL_M_MIN_19, .max = MDFLD_DPLL_M_MAX_19},
|
||||
.p1 = {.min = MDFLD_DPLL_P1_MIN_19, .max = MDFLD_DPLL_P1_MAX_19},
|
||||
},
|
||||
{ /* MDFLD_LIMT_DPLL_25 */
|
||||
.dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
|
||||
.m = {.min = MDFLD_DPLL_M_MIN_25, .max = MDFLD_DPLL_M_MAX_25},
|
||||
.p1 = {.min = MDFLD_DPLL_P1_MIN_25, .max = MDFLD_DPLL_P1_MAX_25},
|
||||
},
|
||||
{ /* MDFLD_LIMT_DPLL_83 */
|
||||
.dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
|
||||
.m = {.min = MDFLD_DPLL_M_MIN_83, .max = MDFLD_DPLL_M_MAX_83},
|
||||
.p1 = {.min = MDFLD_DPLL_P1_MIN_83, .max = MDFLD_DPLL_P1_MAX_83},
|
||||
},
|
||||
{ /* MDFLD_LIMT_DPLL_100 */
|
||||
.dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
|
||||
.m = {.min = MDFLD_DPLL_M_MIN_100, .max = MDFLD_DPLL_M_MAX_100},
|
||||
.p1 = {.min = MDFLD_DPLL_P1_MIN_100, .max = MDFLD_DPLL_P1_MAX_100},
|
||||
},
|
||||
{ /* MDFLD_LIMT_DSIPLL_19 */
|
||||
.dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
|
||||
.m = {.min = MDFLD_DSIPLL_M_MIN_19, .max = MDFLD_DSIPLL_M_MAX_19},
|
||||
.p1 = {.min = MDFLD_DSIPLL_P1_MIN_19, .max = MDFLD_DSIPLL_P1_MAX_19},
|
||||
},
|
||||
{ /* MDFLD_LIMT_DSIPLL_25 */
|
||||
.dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
|
||||
.m = {.min = MDFLD_DSIPLL_M_MIN_25, .max = MDFLD_DSIPLL_M_MAX_25},
|
||||
.p1 = {.min = MDFLD_DSIPLL_P1_MIN_25, .max = MDFLD_DSIPLL_P1_MAX_25},
|
||||
},
|
||||
{ /* MDFLD_LIMT_DSIPLL_83 */
|
||||
.dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
|
||||
.m = {.min = MDFLD_DSIPLL_M_MIN_83, .max = MDFLD_DSIPLL_M_MAX_83},
|
||||
.p1 = {.min = MDFLD_DSIPLL_P1_MIN_83, .max = MDFLD_DSIPLL_P1_MAX_83},
|
||||
},
|
||||
{ /* MDFLD_LIMT_DSIPLL_100 */
|
||||
.dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX},
|
||||
.m = {.min = MDFLD_DSIPLL_M_MIN_100, .max = MDFLD_DSIPLL_M_MAX_100},
|
||||
.p1 = {.min = MDFLD_DSIPLL_P1_MIN_100, .max = MDFLD_DSIPLL_P1_MAX_100},
|
||||
},
|
||||
};
|
||||
|
||||
#define MDFLD_M_MIN 21
|
||||
#define MDFLD_M_MAX 180
|
||||
static const u32 mdfld_m_converts[] = {
|
||||
/* M configuration table from 9-bit LFSR table */
|
||||
224, 368, 440, 220, 366, 439, 219, 365, 182, 347, /* 21 - 30 */
|
||||
173, 342, 171, 85, 298, 149, 74, 37, 18, 265, /* 31 - 40 */
|
||||
388, 194, 353, 432, 216, 108, 310, 155, 333, 166, /* 41 - 50 */
|
||||
83, 41, 276, 138, 325, 162, 337, 168, 340, 170, /* 51 - 60 */
|
||||
341, 426, 469, 234, 373, 442, 221, 110, 311, 411, /* 61 - 70 */
|
||||
461, 486, 243, 377, 188, 350, 175, 343, 427, 213, /* 71 - 80 */
|
||||
106, 53, 282, 397, 354, 227, 113, 56, 284, 142, /* 81 - 90 */
|
||||
71, 35, 273, 136, 324, 418, 465, 488, 500, 506, /* 91 - 100 */
|
||||
253, 126, 63, 287, 399, 455, 483, 241, 376, 444, /* 101 - 110 */
|
||||
478, 495, 503, 251, 381, 446, 479, 239, 375, 443, /* 111 - 120 */
|
||||
477, 238, 119, 315, 157, 78, 295, 147, 329, 420, /* 121 - 130 */
|
||||
210, 105, 308, 154, 77, 38, 275, 137, 68, 290, /* 131 - 140 */
|
||||
145, 328, 164, 82, 297, 404, 458, 485, 498, 249, /* 141 - 150 */
|
||||
380, 190, 351, 431, 471, 235, 117, 314, 413, 206, /* 151 - 160 */
|
||||
103, 51, 25, 12, 262, 387, 193, 96, 48, 280, /* 161 - 170 */
|
||||
396, 198, 99, 305, 152, 76, 294, 403, 457, 228, /* 171 - 180 */
|
||||
};
|
||||
|
||||
static const struct mrst_limit_t *mdfld_limit(struct drm_crtc *crtc)
|
||||
{
|
||||
const struct mrst_limit_t *limit = NULL;
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (gma_pipe_has_type(crtc, INTEL_OUTPUT_MIPI)
|
||||
|| gma_pipe_has_type(crtc, INTEL_OUTPUT_MIPI2)) {
|
||||
if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19))
|
||||
limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_19];
|
||||
else if (ksel == KSEL_BYPASS_25)
|
||||
limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_25];
|
||||
else if ((ksel == KSEL_BYPASS_83_100) &&
|
||||
(dev_priv->core_freq == 166))
|
||||
limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_83];
|
||||
else if ((ksel == KSEL_BYPASS_83_100) &&
|
||||
(dev_priv->core_freq == 100 ||
|
||||
dev_priv->core_freq == 200))
|
||||
limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_100];
|
||||
} else if (gma_pipe_has_type(crtc, INTEL_OUTPUT_HDMI)) {
|
||||
if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19))
|
||||
limit = &mdfld_limits[MDFLD_LIMT_DPLL_19];
|
||||
else if (ksel == KSEL_BYPASS_25)
|
||||
limit = &mdfld_limits[MDFLD_LIMT_DPLL_25];
|
||||
else if ((ksel == KSEL_BYPASS_83_100) &&
|
||||
(dev_priv->core_freq == 166))
|
||||
limit = &mdfld_limits[MDFLD_LIMT_DPLL_83];
|
||||
else if ((ksel == KSEL_BYPASS_83_100) &&
|
||||
(dev_priv->core_freq == 100 ||
|
||||
dev_priv->core_freq == 200))
|
||||
limit = &mdfld_limits[MDFLD_LIMT_DPLL_100];
|
||||
} else {
|
||||
limit = NULL;
|
||||
dev_dbg(dev->dev, "mdfld_limit Wrong display type.\n");
|
||||
}
|
||||
|
||||
return limit;
|
||||
}
|
||||
|
||||
/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */
|
||||
static void mdfld_clock(int refclk, struct mrst_clock_t *clock)
|
||||
{
|
||||
clock->dot = (refclk * clock->m) / clock->p1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a set of divisors for the desired target clock with the given refclk,
|
||||
* or FALSE. Divisor values are the actual divisors for
|
||||
*/
|
||||
static bool
|
||||
mdfldFindBestPLL(struct drm_crtc *crtc, int target, int refclk,
|
||||
struct mrst_clock_t *best_clock)
|
||||
{
|
||||
struct mrst_clock_t clock;
|
||||
const struct mrst_limit_t *limit = mdfld_limit(crtc);
|
||||
int err = target;
|
||||
|
||||
memset(best_clock, 0, sizeof(*best_clock));
|
||||
|
||||
for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) {
|
||||
for (clock.p1 = limit->p1.min; clock.p1 <= limit->p1.max;
|
||||
clock.p1++) {
|
||||
int this_err;
|
||||
|
||||
mdfld_clock(refclk, &clock);
|
||||
|
||||
this_err = abs(clock.dot - target);
|
||||
if (this_err < err) {
|
||||
*best_clock = clock;
|
||||
err = this_err;
|
||||
}
|
||||
}
|
||||
}
|
||||
return err != target;
|
||||
}
|
||||
|
||||
static int mdfld_crtc_mode_set(struct drm_crtc *crtc,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode,
|
||||
int x, int y,
|
||||
struct drm_framebuffer *old_fb)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
int pipe = gma_crtc->pipe;
|
||||
const struct psb_offset *map = &dev_priv->regmap[pipe];
|
||||
int refclk = 0;
|
||||
int clk_n = 0, clk_p2 = 0, clk_byte = 1, clk = 0, m_conv = 0,
|
||||
clk_tmp = 0;
|
||||
struct mrst_clock_t clock;
|
||||
bool ok;
|
||||
u32 dpll = 0, fp = 0;
|
||||
bool is_mipi = false, is_mipi2 = false, is_hdmi = false;
|
||||
struct drm_mode_config *mode_config = &dev->mode_config;
|
||||
struct gma_encoder *gma_encoder = NULL;
|
||||
uint64_t scalingType = DRM_MODE_SCALE_FULLSCREEN;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_connector *connector;
|
||||
int timeout = 0;
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev->dev, "pipe = 0x%x\n", pipe);
|
||||
|
||||
ret = check_fb(crtc->primary->fb);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_dbg(dev->dev, "adjusted_hdisplay = %d\n",
|
||||
adjusted_mode->hdisplay);
|
||||
dev_dbg(dev->dev, "adjusted_vdisplay = %d\n",
|
||||
adjusted_mode->vdisplay);
|
||||
dev_dbg(dev->dev, "adjusted_hsync_start = %d\n",
|
||||
adjusted_mode->hsync_start);
|
||||
dev_dbg(dev->dev, "adjusted_hsync_end = %d\n",
|
||||
adjusted_mode->hsync_end);
|
||||
dev_dbg(dev->dev, "adjusted_htotal = %d\n",
|
||||
adjusted_mode->htotal);
|
||||
dev_dbg(dev->dev, "adjusted_vsync_start = %d\n",
|
||||
adjusted_mode->vsync_start);
|
||||
dev_dbg(dev->dev, "adjusted_vsync_end = %d\n",
|
||||
adjusted_mode->vsync_end);
|
||||
dev_dbg(dev->dev, "adjusted_vtotal = %d\n",
|
||||
adjusted_mode->vtotal);
|
||||
dev_dbg(dev->dev, "adjusted_clock = %d\n",
|
||||
adjusted_mode->clock);
|
||||
dev_dbg(dev->dev, "hdisplay = %d\n",
|
||||
mode->hdisplay);
|
||||
dev_dbg(dev->dev, "vdisplay = %d\n",
|
||||
mode->vdisplay);
|
||||
|
||||
if (!gma_power_begin(dev, true))
|
||||
return 0;
|
||||
|
||||
memcpy(&gma_crtc->saved_mode, mode,
|
||||
sizeof(struct drm_display_mode));
|
||||
memcpy(&gma_crtc->saved_adjusted_mode, adjusted_mode,
|
||||
sizeof(struct drm_display_mode));
|
||||
|
||||
list_for_each_entry(connector, &mode_config->connector_list, head) {
|
||||
encoder = connector->encoder;
|
||||
if (!encoder)
|
||||
continue;
|
||||
|
||||
if (encoder->crtc != crtc)
|
||||
continue;
|
||||
|
||||
gma_encoder = gma_attached_encoder(connector);
|
||||
|
||||
switch (gma_encoder->type) {
|
||||
case INTEL_OUTPUT_MIPI:
|
||||
is_mipi = true;
|
||||
break;
|
||||
case INTEL_OUTPUT_MIPI2:
|
||||
is_mipi2 = true;
|
||||
break;
|
||||
case INTEL_OUTPUT_HDMI:
|
||||
is_hdmi = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable the VGA plane that we never use */
|
||||
REG_WRITE(VGACNTRL, VGA_DISP_DISABLE);
|
||||
|
||||
/* Disable the panel fitter if it was on our pipe */
|
||||
if (psb_intel_panel_fitter_pipe(dev) == pipe)
|
||||
REG_WRITE(PFIT_CONTROL, 0);
|
||||
|
||||
/* pipesrc and dspsize control the size that is scaled from,
|
||||
* which should always be the user's requested size.
|
||||
*/
|
||||
if (pipe == 1) {
|
||||
/* FIXME: To make HDMI display with 864x480 (TPO), 480x864
|
||||
* (PYR) or 480x854 (TMD), set the sprite width/height and
|
||||
* souce image size registers with the adjusted mode for
|
||||
* pipe B.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The defined sprite rectangle must always be completely
|
||||
* contained within the displayable area of the screen image
|
||||
* (frame buffer).
|
||||
*/
|
||||
REG_WRITE(map->size, ((min(mode->crtc_vdisplay, adjusted_mode->crtc_vdisplay) - 1) << 16)
|
||||
| (min(mode->crtc_hdisplay, adjusted_mode->crtc_hdisplay) - 1));
|
||||
/* Set the CRTC with encoder mode. */
|
||||
REG_WRITE(map->src, ((mode->crtc_hdisplay - 1) << 16)
|
||||
| (mode->crtc_vdisplay - 1));
|
||||
} else {
|
||||
REG_WRITE(map->size,
|
||||
((mode->crtc_vdisplay - 1) << 16) |
|
||||
(mode->crtc_hdisplay - 1));
|
||||
REG_WRITE(map->src,
|
||||
((mode->crtc_hdisplay - 1) << 16) |
|
||||
(mode->crtc_vdisplay - 1));
|
||||
}
|
||||
|
||||
REG_WRITE(map->pos, 0);
|
||||
|
||||
if (gma_encoder)
|
||||
drm_object_property_get_value(&connector->base,
|
||||
dev->mode_config.scaling_mode_property, &scalingType);
|
||||
|
||||
if (scalingType == DRM_MODE_SCALE_NO_SCALE) {
|
||||
/* Medfield doesn't have register support for centering so we
|
||||
* need to mess with the h/vblank and h/vsync start and ends
|
||||
* to get centering
|
||||
*/
|
||||
int offsetX = 0, offsetY = 0;
|
||||
|
||||
offsetX = (adjusted_mode->crtc_hdisplay -
|
||||
mode->crtc_hdisplay) / 2;
|
||||
offsetY = (adjusted_mode->crtc_vdisplay -
|
||||
mode->crtc_vdisplay) / 2;
|
||||
|
||||
REG_WRITE(map->htotal, (mode->crtc_hdisplay - 1) |
|
||||
((adjusted_mode->crtc_htotal - 1) << 16));
|
||||
REG_WRITE(map->vtotal, (mode->crtc_vdisplay - 1) |
|
||||
((adjusted_mode->crtc_vtotal - 1) << 16));
|
||||
REG_WRITE(map->hblank, (adjusted_mode->crtc_hblank_start -
|
||||
offsetX - 1) |
|
||||
((adjusted_mode->crtc_hblank_end - offsetX - 1) << 16));
|
||||
REG_WRITE(map->hsync, (adjusted_mode->crtc_hsync_start -
|
||||
offsetX - 1) |
|
||||
((adjusted_mode->crtc_hsync_end - offsetX - 1) << 16));
|
||||
REG_WRITE(map->vblank, (adjusted_mode->crtc_vblank_start -
|
||||
offsetY - 1) |
|
||||
((adjusted_mode->crtc_vblank_end - offsetY - 1) << 16));
|
||||
REG_WRITE(map->vsync, (adjusted_mode->crtc_vsync_start -
|
||||
offsetY - 1) |
|
||||
((adjusted_mode->crtc_vsync_end - offsetY - 1) << 16));
|
||||
} else {
|
||||
REG_WRITE(map->htotal, (adjusted_mode->crtc_hdisplay - 1) |
|
||||
((adjusted_mode->crtc_htotal - 1) << 16));
|
||||
REG_WRITE(map->vtotal, (adjusted_mode->crtc_vdisplay - 1) |
|
||||
((adjusted_mode->crtc_vtotal - 1) << 16));
|
||||
REG_WRITE(map->hblank, (adjusted_mode->crtc_hblank_start - 1) |
|
||||
((adjusted_mode->crtc_hblank_end - 1) << 16));
|
||||
REG_WRITE(map->hsync, (adjusted_mode->crtc_hsync_start - 1) |
|
||||
((adjusted_mode->crtc_hsync_end - 1) << 16));
|
||||
REG_WRITE(map->vblank, (adjusted_mode->crtc_vblank_start - 1) |
|
||||
((adjusted_mode->crtc_vblank_end - 1) << 16));
|
||||
REG_WRITE(map->vsync, (adjusted_mode->crtc_vsync_start - 1) |
|
||||
((adjusted_mode->crtc_vsync_end - 1) << 16));
|
||||
}
|
||||
|
||||
/* Flush the plane changes */
|
||||
{
|
||||
const struct drm_crtc_helper_funcs *crtc_funcs =
|
||||
crtc->helper_private;
|
||||
crtc_funcs->mode_set_base(crtc, x, y, old_fb);
|
||||
}
|
||||
|
||||
/* setup pipeconf */
|
||||
dev_priv->pipeconf[pipe] = PIPEACONF_ENABLE; /* FIXME_JLIU7 REG_READ(pipeconf_reg); */
|
||||
|
||||
/* Set up the display plane register */
|
||||
dev_priv->dspcntr[pipe] = REG_READ(map->cntr);
|
||||
dev_priv->dspcntr[pipe] |= pipe << DISPPLANE_SEL_PIPE_POS;
|
||||
dev_priv->dspcntr[pipe] |= DISPLAY_PLANE_ENABLE;
|
||||
|
||||
if (is_mipi2)
|
||||
goto mrst_crtc_mode_set_exit;
|
||||
clk = adjusted_mode->clock;
|
||||
|
||||
if (is_hdmi) {
|
||||
if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19)) {
|
||||
refclk = 19200;
|
||||
|
||||
if (is_mipi || is_mipi2)
|
||||
clk_n = 1, clk_p2 = 8;
|
||||
else if (is_hdmi)
|
||||
clk_n = 1, clk_p2 = 10;
|
||||
} else if (ksel == KSEL_BYPASS_25) {
|
||||
refclk = 25000;
|
||||
|
||||
if (is_mipi || is_mipi2)
|
||||
clk_n = 1, clk_p2 = 8;
|
||||
else if (is_hdmi)
|
||||
clk_n = 1, clk_p2 = 10;
|
||||
} else if ((ksel == KSEL_BYPASS_83_100) &&
|
||||
dev_priv->core_freq == 166) {
|
||||
refclk = 83000;
|
||||
|
||||
if (is_mipi || is_mipi2)
|
||||
clk_n = 4, clk_p2 = 8;
|
||||
else if (is_hdmi)
|
||||
clk_n = 4, clk_p2 = 10;
|
||||
} else if ((ksel == KSEL_BYPASS_83_100) &&
|
||||
(dev_priv->core_freq == 100 ||
|
||||
dev_priv->core_freq == 200)) {
|
||||
refclk = 100000;
|
||||
if (is_mipi || is_mipi2)
|
||||
clk_n = 4, clk_p2 = 8;
|
||||
else if (is_hdmi)
|
||||
clk_n = 4, clk_p2 = 10;
|
||||
}
|
||||
|
||||
if (is_mipi)
|
||||
clk_byte = dev_priv->bpp / 8;
|
||||
else if (is_mipi2)
|
||||
clk_byte = dev_priv->bpp2 / 8;
|
||||
|
||||
clk_tmp = clk * clk_n * clk_p2 * clk_byte;
|
||||
|
||||
dev_dbg(dev->dev, "clk = %d, clk_n = %d, clk_p2 = %d.\n",
|
||||
clk, clk_n, clk_p2);
|
||||
dev_dbg(dev->dev, "adjusted_mode->clock = %d, clk_tmp = %d.\n",
|
||||
adjusted_mode->clock, clk_tmp);
|
||||
|
||||
ok = mdfldFindBestPLL(crtc, clk_tmp, refclk, &clock);
|
||||
|
||||
if (!ok) {
|
||||
DRM_ERROR
|
||||
("mdfldFindBestPLL fail in mdfld_crtc_mode_set.\n");
|
||||
} else {
|
||||
m_conv = mdfld_m_converts[(clock.m - MDFLD_M_MIN)];
|
||||
|
||||
dev_dbg(dev->dev, "dot clock = %d,"
|
||||
"m = %d, p1 = %d, m_conv = %d.\n",
|
||||
clock.dot, clock.m,
|
||||
clock.p1, m_conv);
|
||||
}
|
||||
|
||||
dpll = REG_READ(map->dpll);
|
||||
|
||||
if (dpll & DPLL_VCO_ENABLE) {
|
||||
dpll &= ~DPLL_VCO_ENABLE;
|
||||
REG_WRITE(map->dpll, dpll);
|
||||
REG_READ(map->dpll);
|
||||
|
||||
/* FIXME jliu7 check the DPLL lock bit PIPEACONF[29] */
|
||||
/* FIXME_MDFLD PO - change 500 to 1 after PO */
|
||||
udelay(500);
|
||||
|
||||
/* reset M1, N1 & P1 */
|
||||
REG_WRITE(map->fp0, 0);
|
||||
dpll &= ~MDFLD_P1_MASK;
|
||||
REG_WRITE(map->dpll, dpll);
|
||||
/* FIXME_MDFLD PO - change 500 to 1 after PO */
|
||||
udelay(500);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
REG_WRITE(map->dpll, dpll);
|
||||
/* FIXME_MDFLD PO - change 500 to 1 after PO */
|
||||
udelay(500);
|
||||
}
|
||||
dpll = 0;
|
||||
|
||||
if (is_hdmi)
|
||||
dpll |= MDFLD_VCO_SEL;
|
||||
|
||||
fp = (clk_n / 2) << 16;
|
||||
fp |= m_conv;
|
||||
|
||||
/* compute bitmask from p1 value */
|
||||
dpll |= (1 << (clock.p1 - 2)) << 17;
|
||||
|
||||
} else {
|
||||
dpll = 0x00800000;
|
||||
fp = 0x000000c1;
|
||||
}
|
||||
|
||||
REG_WRITE(map->fp0, fp);
|
||||
REG_WRITE(map->dpll, dpll);
|
||||
/* FIXME_MDFLD PO - change 500 to 1 after PO */
|
||||
udelay(500);
|
||||
|
||||
dpll |= DPLL_VCO_ENABLE;
|
||||
REG_WRITE(map->dpll, dpll);
|
||||
REG_READ(map->dpll);
|
||||
|
||||
/* wait for DSI PLL to lock */
|
||||
while (timeout < 20000 &&
|
||||
!(REG_READ(map->conf) & PIPECONF_DSIPLL_LOCK)) {
|
||||
udelay(150);
|
||||
timeout++;
|
||||
}
|
||||
|
||||
if (is_mipi)
|
||||
goto mrst_crtc_mode_set_exit;
|
||||
|
||||
dev_dbg(dev->dev, "is_mipi = 0x%x\n", is_mipi);
|
||||
|
||||
REG_WRITE(map->conf, dev_priv->pipeconf[pipe]);
|
||||
REG_READ(map->conf);
|
||||
|
||||
/* Wait for for the pipe enable to take effect. */
|
||||
REG_WRITE(map->cntr, dev_priv->dspcntr[pipe]);
|
||||
gma_wait_for_vblank(dev);
|
||||
|
||||
mrst_crtc_mode_set_exit:
|
||||
|
||||
gma_power_end(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct drm_crtc_helper_funcs mdfld_helper_funcs = {
|
||||
.dpms = mdfld_crtc_dpms,
|
||||
.mode_set = mdfld_crtc_mode_set,
|
||||
.mode_set_base = mdfld__intel_pipe_set_base,
|
||||
.prepare = gma_crtc_prepare,
|
||||
.commit = gma_crtc_commit,
|
||||
};
|
@ -1,74 +0,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>
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
|
@ -1,76 +0,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
|
@ -1,197 +0,0 @@
|
||||
/*
|
||||
* 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,
|
||||
};
|
@ -1,83 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
mode = kzalloc(sizeof(*mode), GFP_KERNEL);
|
||||
if (!mode)
|
||||
return NULL;
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
const struct panel_funcs mdfld_tpo_vid_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,
|
||||
};
|
@ -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 @@ out_err1:
|
||||
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)
|
||||
|
@ -46,13 +46,12 @@ static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
|
||||
* PowerVR SGX535 - Poulsbo - Intel GMA 500, Intel Atom Z5xx
|
||||
* PowerVR SGX535 - Moorestown - Intel GMA 600
|
||||
* PowerVR SGX535 - Oaktrail - Intel GMA 600, Intel Atom Z6xx, E6xx
|
||||
* PowerVR SGX540 - Medfield - Intel Atom Z2460
|
||||
* PowerVR SGX544MP2 - Medfield -
|
||||
* PowerVR SGX545 - Cedartrail - Intel GMA 3600, Intel Atom D2500, N2600
|
||||
* PowerVR SGX545 - Cedartrail - Intel GMA 3650, Intel Atom D2550, D2700,
|
||||
* N2800
|
||||
*/
|
||||
static const struct pci_device_id pciidlist[] = {
|
||||
/* Poulsbo */
|
||||
{ 0x8086, 0x8108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &psb_chip_ops },
|
||||
{ 0x8086, 0x8109, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &psb_chip_ops },
|
||||
#if defined(CONFIG_DRM_GMA600)
|
||||
@ -66,17 +65,7 @@ static const struct pci_device_id pciidlist[] = {
|
||||
{ 0x8086, 0x4107, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops },
|
||||
{ 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)
|
||||
/* Cedartrail */
|
||||
{ 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 },
|
||||
{ 0x8086, 0x0be2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
|
||||
@ -93,7 +82,6 @@ static const struct pci_device_id pciidlist[] = {
|
||||
{ 0x8086, 0x0bed, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
|
||||
{ 0x8086, 0x0bee, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
|
||||
{ 0x8086, 0x0bef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
|
||||
#endif
|
||||
{ 0, }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pciidlist);
|
||||
|
@ -40,19 +40,16 @@ enum {
|
||||
CHIP_PSB_8108 = 0, /* Poulsbo */
|
||||
CHIP_PSB_8109 = 1, /* Poulsbo */
|
||||
CHIP_MRST_4100 = 2, /* Moorestown/Oaktrail */
|
||||
CHIP_MFLD_0130 = 3, /* Medfield */
|
||||
};
|
||||
|
||||
#define IS_PSB(drm) ((to_pci_dev((drm)->dev)->device & 0xfffe) == 0x8108)
|
||||
#define IS_MRST(drm) ((to_pci_dev((drm)->dev)->device & 0xfff0) == 0x4100)
|
||||
#define IS_MFLD(drm) ((to_pci_dev((drm)->dev)->device & 0xfff8) == 0x0130)
|
||||
#define IS_CDV(drm) ((to_pci_dev((drm)->dev)->device & 0xfff0) == 0x0be0)
|
||||
|
||||
/* Hardware offsets */
|
||||
#define PSB_VDC_OFFSET 0x00000000
|
||||
#define PSB_VDC_SIZE 0x000080000
|
||||
#define MRST_MMIO_SIZE 0x0000C0000
|
||||
#define MDFLD_MMIO_SIZE 0x000100000
|
||||
#define PSB_SGX_SIZE 0x8000
|
||||
#define PSB_SGX_OFFSET 0x00040000
|
||||
#define MRST_SGX_OFFSET 0x00080000
|
||||
@ -109,8 +106,6 @@ enum {
|
||||
#define _PSB_DPST_PIPEA_FLAG (1<<6)
|
||||
#define _PSB_PIPEA_EVENT_FLAG (1<<6)
|
||||
#define _PSB_VSYNC_PIPEA_FLAG (1<<7)
|
||||
#define _MDFLD_MIPIA_FLAG (1<<16)
|
||||
#define _MDFLD_MIPIC_FLAG (1<<17)
|
||||
#define _PSB_IRQ_DISP_HOTSYNC (1<<17)
|
||||
#define _PSB_IRQ_SGX_FLAG (1<<18)
|
||||
#define _PSB_IRQ_MSVDX_FLAG (1<<19)
|
||||
@ -119,13 +114,6 @@ enum {
|
||||
#define _PSB_PIPE_EVENT_FLAG (_PSB_VSYNC_PIPEA_FLAG | \
|
||||
_PSB_VSYNC_PIPEB_FLAG)
|
||||
|
||||
/* This flag includes all the display IRQ bits excepts the vblank irqs. */
|
||||
#define _MDFLD_DISP_ALL_IRQ_FLAG (_MDFLD_PIPEC_EVENT_FLAG | \
|
||||
_MDFLD_PIPEB_EVENT_FLAG | \
|
||||
_PSB_PIPEA_EVENT_FLAG | \
|
||||
_PSB_VSYNC_PIPEA_FLAG | \
|
||||
_MDFLD_MIPIA_FLAG | \
|
||||
_MDFLD_MIPIC_FLAG)
|
||||
#define PSB_INT_IDENTITY_R 0x20A4
|
||||
#define PSB_INT_MASK_R 0x20A8
|
||||
#define PSB_INT_ENABLE_R 0x20A0
|
||||
@ -191,25 +179,6 @@ enum {
|
||||
#define PSB_WATCHDOG_DELAY (HZ * 2)
|
||||
#define PSB_LID_DELAY (HZ / 10)
|
||||
|
||||
#define MDFLD_PNW_B0 0x04
|
||||
#define MDFLD_PNW_C0 0x08
|
||||
|
||||
#define MDFLD_DSR_2D_3D_0 (1 << 0)
|
||||
#define MDFLD_DSR_2D_3D_2 (1 << 1)
|
||||
#define MDFLD_DSR_CURSOR_0 (1 << 2)
|
||||
#define MDFLD_DSR_CURSOR_2 (1 << 3)
|
||||
#define MDFLD_DSR_OVERLAY_0 (1 << 4)
|
||||
#define MDFLD_DSR_OVERLAY_2 (1 << 5)
|
||||
#define MDFLD_DSR_MIPI_CONTROL (1 << 6)
|
||||
#define MDFLD_DSR_DAMAGE_MASK_0 ((1 << 0) | (1 << 2) | (1 << 4))
|
||||
#define MDFLD_DSR_DAMAGE_MASK_2 ((1 << 1) | (1 << 3) | (1 << 5))
|
||||
#define MDFLD_DSR_2D_3D (MDFLD_DSR_2D_3D_0 | MDFLD_DSR_2D_3D_2)
|
||||
|
||||
#define MDFLD_DSR_RR 45
|
||||
#define MDFLD_DPU_ENABLE (1 << 31)
|
||||
#define MDFLD_DSR_FULLSCREEN (1 << 30)
|
||||
#define MDFLD_DSR_DELAY (HZ / MDFLD_DSR_RR)
|
||||
|
||||
#define PSB_PWR_STATE_ON 1
|
||||
#define PSB_PWR_STATE_OFF 2
|
||||
|
||||
@ -382,16 +351,6 @@ struct psb_state {
|
||||
uint32_t savePWM_CONTROL_LOGIC;
|
||||
};
|
||||
|
||||
struct medfield_state {
|
||||
uint32_t saveMIPI;
|
||||
uint32_t saveMIPI_C;
|
||||
|
||||
uint32_t savePFIT_CONTROL;
|
||||
uint32_t savePFIT_PGM_RATIOS;
|
||||
uint32_t saveHDMIPHYMISCCTL;
|
||||
uint32_t saveHDMIB_CONTROL;
|
||||
};
|
||||
|
||||
struct cdv_state {
|
||||
uint32_t saveDSPCLK_GATE_D;
|
||||
uint32_t saveRAMCLK_GATE_D;
|
||||
@ -417,7 +376,6 @@ struct psb_save_area {
|
||||
uint32_t saveVBT;
|
||||
union {
|
||||
struct psb_state psb;
|
||||
struct medfield_state mdfld;
|
||||
struct cdv_state cdv;
|
||||
};
|
||||
uint32_t saveBLC_PWM_CTL2;
|
||||
@ -590,8 +548,6 @@ struct drm_psb_private {
|
||||
u32 pipeconf[3];
|
||||
u32 dspcntr[3];
|
||||
|
||||
int mdfld_panel_id;
|
||||
|
||||
bool dplla_96mhz; /* DPLL data from the VBT */
|
||||
|
||||
struct {
|
||||
@ -737,9 +693,6 @@ 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;
|
||||
|
||||
@ -779,25 +732,6 @@ static inline void MRST_MSG_WRITE32(int domain, uint port, uint offset,
|
||||
pci_write_config_dword(pci_root, 0xD0, mcr);
|
||||
pci_dev_put(pci_root);
|
||||
}
|
||||
static inline u32 MDFLD_MSG_READ32(int domain, uint port, uint offset)
|
||||
{
|
||||
int mcr = (0x10<<24) | (port << 16) | (offset << 8);
|
||||
uint32_t ret_val = 0;
|
||||
struct pci_dev *pci_root = pci_get_domain_bus_and_slot(domain, 0, 0);
|
||||
pci_write_config_dword(pci_root, 0xD0, mcr);
|
||||
pci_read_config_dword(pci_root, 0xD4, &ret_val);
|
||||
pci_dev_put(pci_root);
|
||||
return ret_val;
|
||||
}
|
||||
static inline void MDFLD_MSG_WRITE32(int domain, uint port, uint offset,
|
||||
u32 value)
|
||||
{
|
||||
int mcr = (0x11<<24) | (port << 16) | (offset << 8) | 0xF0;
|
||||
struct pci_dev *pci_root = pci_get_domain_bus_and_slot(domain, 0, 0);
|
||||
pci_write_config_dword(pci_root, 0xD4, value);
|
||||
pci_write_config_dword(pci_root, 0xD0, mcr);
|
||||
pci_dev_put(pci_root);
|
||||
}
|
||||
|
||||
static inline uint32_t REGISTER_READ(struct drm_device *dev, uint32_t reg)
|
||||
{
|
||||
|
@ -595,7 +595,7 @@ struct dpst_guardband {
|
||||
#define PIPE_PIXEL_MASK 0x00ffffff
|
||||
#define PIPE_PIXEL_SHIFT 0
|
||||
|
||||
#define FW_BLC_SELF 0x20e0
|
||||
#define FW_BLC_SELF 0x20e0
|
||||
#define FW_BLC_SELF_EN (1<<15)
|
||||
|
||||
#define DSPARB 0x70030
|
||||
@ -789,17 +789,9 @@ struct dpst_guardband {
|
||||
* MOORESTOWN delta registers
|
||||
*/
|
||||
#define MRST_DPLL_A 0x0f014
|
||||
#define MDFLD_DPLL_B 0x0f018
|
||||
#define MDFLD_INPUT_REF_SEL (1 << 14)
|
||||
#define MDFLD_VCO_SEL (1 << 16)
|
||||
#define DPLLA_MODE_LVDS (2 << 26) /* mrst */
|
||||
#define MDFLD_PLL_LATCHEN (1 << 28)
|
||||
#define MDFLD_PWR_GATE_EN (1 << 30)
|
||||
#define MDFLD_P1_MASK (0x1FF << 17)
|
||||
#define MRST_FPA0 0x0f040
|
||||
#define MRST_FPA1 0x0f044
|
||||
#define MDFLD_DPLL_DIV0 0x0f048
|
||||
#define MDFLD_DPLL_DIV1 0x0f04c
|
||||
#define MRST_PERF_MODE 0x020f4
|
||||
|
||||
/*
|
||||
@ -848,7 +840,6 @@ struct dpst_guardband {
|
||||
|
||||
#define MRST_DSPABASE 0x7019c
|
||||
#define MRST_DSPBBASE 0x7119c
|
||||
#define MDFLD_DSPCBASE 0x7219c
|
||||
|
||||
/*
|
||||
* Moorestown registers.
|
||||
@ -930,7 +921,6 @@ struct dpst_guardband {
|
||||
#define DEVICE_RESET_REG 0xb01C
|
||||
#define DPI_RESOLUTION_REG 0xb020
|
||||
#define RES_V_POS 0x10
|
||||
#define DBI_RESOLUTION_REG 0xb024 /* Reserved for MDFLD */
|
||||
#define HORIZ_SYNC_PAD_COUNT_REG 0xb028
|
||||
#define HORIZ_BACK_PORCH_COUNT_REG 0xb02C
|
||||
#define HORIZ_FRONT_PORCH_COUNT_REG 0xb030
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
#include <drm/drm_vblank.h>
|
||||
|
||||
#include "mdfld_output.h"
|
||||
#include "power.h"
|
||||
#include "psb_drv.h"
|
||||
#include "psb_intel_reg.h"
|
||||
@ -164,8 +163,7 @@ static void mid_pipe_event_handler(struct drm_device *dev, int pipe)
|
||||
"%s, can't clear status bits for pipe %d, its value = 0x%x.\n",
|
||||
__func__, pipe, PSB_RVDC32(pipe_stat_reg));
|
||||
|
||||
if (pipe_stat_val & PIPE_VBLANK_STATUS ||
|
||||
(IS_MFLD(dev) && pipe_stat_val & PIPE_TE_STATUS)) {
|
||||
if (pipe_stat_val & PIPE_VBLANK_STATUS) {
|
||||
struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
|
||||
struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
|
||||
unsigned long flags;
|
||||
@ -263,11 +261,6 @@ irqreturn_t psb_irq_handler(int irq, void *arg)
|
||||
if (vdc_stat & (_PSB_PIPE_EVENT_FLAG|_PSB_IRQ_ASLE))
|
||||
dsp_int = 1;
|
||||
|
||||
/* FIXME: Handle Medfield
|
||||
if (vdc_stat & _MDFLD_DISP_ALL_IRQ_FLAG)
|
||||
dsp_int = 1;
|
||||
*/
|
||||
|
||||
if (vdc_stat & _PSB_IRQ_SGX_FLAG)
|
||||
sgx_int = 1;
|
||||
if (vdc_stat & _PSB_IRQ_DISP_HOTSYNC)
|
||||
@ -325,13 +318,6 @@ void psb_irq_preinstall(struct drm_device *dev)
|
||||
if (dev->vblank[1].enabled)
|
||||
dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEB_FLAG;
|
||||
|
||||
/* FIXME: Handle Medfield irq mask
|
||||
if (dev->vblank[1].enabled)
|
||||
dev_priv->vdc_irq_mask |= _MDFLD_PIPEB_EVENT_FLAG;
|
||||
if (dev->vblank[2].enabled)
|
||||
dev_priv->vdc_irq_mask |= _MDFLD_PIPEC_EVENT_FLAG;
|
||||
*/
|
||||
|
||||
/* Revisit this area - want per device masks ? */
|
||||
if (dev_priv->ops->hotplug)
|
||||
dev_priv->vdc_irq_mask |= _PSB_IRQ_DISP_HOTSYNC;
|
||||
@ -504,11 +490,6 @@ int psb_enable_vblank(struct drm_crtc *crtc)
|
||||
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);
|
||||
@ -543,8 +524,6 @@ void psb_disable_vblank(struct drm_crtc *crtc)
|
||||
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)
|
||||
@ -559,55 +538,6 @@ void psb_disable_vblank(struct drm_crtc *crtc)
|
||||
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
|
||||
*/
|
||||
|
@ -31,6 +31,4 @@ int psb_enable_vblank(struct drm_crtc *crtc);
|
||||
void psb_disable_vblank(struct drm_crtc *crtc);
|
||||
u32 psb_get_vblank_counter(struct drm_crtc *crtc);
|
||||
|
||||
int mdfld_enable_te(struct drm_device *dev, int pipe);
|
||||
void mdfld_disable_te(struct drm_device *dev, int pipe);
|
||||
#endif /* _PSB_IRQ_H_ */
|
||||
|
@ -550,21 +550,7 @@
|
||||
#define PSB_PM_SSC 0x20
|
||||
#define PSB_PM_SSS 0x30
|
||||
#define PSB_PWRGT_DISPLAY_MASK 0xc /*on a different BA than video/gfx*/
|
||||
#define MDFLD_PWRGT_DISPLAY_A_CNTR 0x0000000c
|
||||
#define MDFLD_PWRGT_DISPLAY_B_CNTR 0x0000c000
|
||||
#define MDFLD_PWRGT_DISPLAY_C_CNTR 0x00030000
|
||||
#define MDFLD_PWRGT_DISP_MIPI_CNTR 0x000c0000
|
||||
#define MDFLD_PWRGT_DISPLAY_CNTR (MDFLD_PWRGT_DISPLAY_A_CNTR | MDFLD_PWRGT_DISPLAY_B_CNTR | MDFLD_PWRGT_DISPLAY_C_CNTR | MDFLD_PWRGT_DISP_MIPI_CNTR) /* 0x000fc00c */
|
||||
/* Display SSS register bits are different in A0 vs. B0 */
|
||||
#define PSB_PWRGT_GFX_MASK 0x3
|
||||
#define MDFLD_PWRGT_DISPLAY_A_STS 0x000000c0
|
||||
#define MDFLD_PWRGT_DISPLAY_B_STS 0x00000300
|
||||
#define MDFLD_PWRGT_DISPLAY_C_STS 0x00000c00
|
||||
#define PSB_PWRGT_GFX_MASK_B0 0xc3
|
||||
#define MDFLD_PWRGT_DISPLAY_A_STS_B0 0x0000000c
|
||||
#define MDFLD_PWRGT_DISPLAY_B_STS_B0 0x0000c000
|
||||
#define MDFLD_PWRGT_DISPLAY_C_STS_B0 0x00030000
|
||||
#define MDFLD_PWRGT_DISP_MIPI_STS 0x000c0000
|
||||
#define MDFLD_PWRGT_DISPLAY_STS_A0 (MDFLD_PWRGT_DISPLAY_A_STS | MDFLD_PWRGT_DISPLAY_B_STS | MDFLD_PWRGT_DISPLAY_C_STS | MDFLD_PWRGT_DISP_MIPI_STS) /* 0x000fc00c */
|
||||
#define MDFLD_PWRGT_DISPLAY_STS_B0 (MDFLD_PWRGT_DISPLAY_A_STS_B0 | MDFLD_PWRGT_DISPLAY_B_STS_B0 | MDFLD_PWRGT_DISPLAY_C_STS_B0 | MDFLD_PWRGT_DISP_MIPI_STS) /* 0x000fc00c */
|
||||
#endif
|
||||
|
@ -1,805 +0,0 @@
|
||||
/*
|
||||
* 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 <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
#include <asm/intel_scu_ipc.h>
|
||||
|
||||
#include "mdfld_dsi_dpi.h"
|
||||
#include "mdfld_dsi_pkg_sender.h"
|
||||
#include "mdfld_output.h"
|
||||
#include "tc35876x-dsi-lvds.h"
|
||||
|
||||
static struct i2c_client *tc35876x_client;
|
||||
static struct i2c_client *cmi_lcd_i2c_client;
|
||||
/* Panel GPIOs */
|
||||
static struct gpio_desc *bridge_reset;
|
||||
static struct gpio_desc *bridge_bl_enable;
|
||||
static struct gpio_desc *backlight_voltage;
|
||||
|
||||
|
||||
#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)
|
||||
{
|
||||
if (WARN(!tc35876x_client, "%s called before probe", __func__))
|
||||
return;
|
||||
|
||||
dev_dbg(&tc35876x_client->dev, "%s: state %d\n", __func__, state);
|
||||
|
||||
if (!bridge_reset)
|
||||
return;
|
||||
|
||||
if (state) {
|
||||
gpiod_set_value_cansleep(bridge_reset, 0);
|
||||
mdelay(10);
|
||||
} else {
|
||||
/* Pull MIPI Bridge reset pin to Low */
|
||||
gpiod_set_value_cansleep(bridge_reset, 0);
|
||||
mdelay(20);
|
||||
/* Pull MIPI Bridge reset pin to High */
|
||||
gpiod_set_value_cansleep(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->dev, "GPIOPWMCTRL read failed\n");
|
||||
else
|
||||
dev_warn(dev->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->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->dev, "PWM0CLKDIV set failed\n");
|
||||
else
|
||||
dev_dbg(dev->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)
|
||||
{
|
||||
if (WARN(!tc35876x_client, "%s called before probe", __func__))
|
||||
return;
|
||||
|
||||
dev_dbg(&tc35876x_client->dev, "%s\n", __func__);
|
||||
|
||||
if (bridge_bl_enable)
|
||||
gpiod_set_value_cansleep(bridge_bl_enable, 0);
|
||||
|
||||
if (backlight_voltage)
|
||||
gpiod_set_value_cansleep(backlight_voltage, 0);
|
||||
}
|
||||
|
||||
void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev)
|
||||
{
|
||||
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__);
|
||||
|
||||
if (backlight_voltage) {
|
||||
gpiod_set_value_cansleep(backlight_voltage, 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 (bridge_bl_enable)
|
||||
gpiod_set_value_cansleep(bridge_bl_enable, 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->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->dev, "hdisplay(w) = %d\n", mode->hdisplay);
|
||||
dev_info(dev->dev, "vdisplay(h) = %d\n", mode->vdisplay);
|
||||
dev_info(dev->dev, "HSS = %d\n", mode->hsync_start);
|
||||
dev_info(dev->dev, "HSE = %d\n", mode->hsync_end);
|
||||
dev_info(dev->dev, "htotal = %d\n", mode->htotal);
|
||||
dev_info(dev->dev, "VSS = %d\n", mode->vsync_start);
|
||||
dev_info(dev->dev, "VSE = %d\n", mode->vsync_end);
|
||||
dev_info(dev->dev, "vtotal = %d\n", mode->vtotal);
|
||||
dev_info(dev->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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
bridge_reset = devm_gpiod_get_optional(&client->dev, "bridge-reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(bridge_reset))
|
||||
return PTR_ERR(bridge_reset);
|
||||
if (bridge_reset)
|
||||
gpiod_set_consumer_name(bridge_reset, "tc35876x bridge reset");
|
||||
|
||||
bridge_bl_enable = devm_gpiod_get_optional(&client->dev, "bl-en", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(bridge_bl_enable))
|
||||
return PTR_ERR(bridge_bl_enable);
|
||||
if (bridge_bl_enable)
|
||||
gpiod_set_consumer_name(bridge_bl_enable, "tc35876x panel bl en");
|
||||
|
||||
backlight_voltage = devm_gpiod_get_optional(&client->dev, "vadd", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(backlight_voltage))
|
||||
return PTR_ERR(backlight_voltage);
|
||||
if (backlight_voltage)
|
||||
gpiod_set_consumer_name(backlight_voltage, "tc35876x panel vadd");
|
||||
|
||||
tc35876x_client = client;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tc35876x_bridge_remove(struct i2c_client *client)
|
||||
{
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
|
||||
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 = 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 = 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_client_device(adapter, &info);
|
||||
if (IS_ERR(client)) {
|
||||
pr_err("%s: creating I2C device failed\n", __func__);
|
||||
i2c_put_adapter(adapter);
|
||||
return PTR_ERR(client);
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
const struct panel_funcs mdfld_tc35876x_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->dev, "%s\n", __func__);
|
||||
|
||||
cmi_lcd_hack_create_device();
|
||||
|
||||
r = i2c_add_driver(&cmi_lcd_i2c_driver);
|
||||
if (r < 0)
|
||||
dev_err(dev->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->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);
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* 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__*/
|
@ -201,7 +201,7 @@ static int lima_pm_busy(struct lima_device *ldev)
|
||||
int ret;
|
||||
|
||||
/* resume GPU if it has been suspended by runtime PM */
|
||||
ret = pm_runtime_get_sync(ldev->dev);
|
||||
ret = pm_runtime_resume_and_get(ldev->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -2083,13 +2083,11 @@ nouveau_bios_init(struct drm_device *dev)
|
||||
{
|
||||
struct nouveau_drm *drm = nouveau_drm(dev);
|
||||
struct nvbios *bios = &drm->vbios;
|
||||
struct pci_dev *pdev;
|
||||
int ret;
|
||||
|
||||
/* only relevant for PCI devices */
|
||||
if (!dev_is_pci(dev->dev))
|
||||
return 0;
|
||||
pdev = to_pci_dev(dev->dev);
|
||||
|
||||
if (!NVInitVBIOS(dev))
|
||||
return -ENODEV;
|
||||
|
@ -1026,7 +1026,6 @@ int vc4_queue_seqno_cb(struct drm_device *dev,
|
||||
void (*func)(struct vc4_seqno_cb *cb))
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
int ret = 0;
|
||||
unsigned long irqflags;
|
||||
|
||||
cb->func = func;
|
||||
@ -1041,7 +1040,7 @@ int vc4_queue_seqno_cb(struct drm_device *dev,
|
||||
}
|
||||
spin_unlock_irqrestore(&vc4->job_lock, irqflags);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Scheduled when any job has been completed, this walks the list of
|
||||
|
@ -132,24 +132,57 @@ static void vc5_hdmi_reset(struct vc4_hdmi *vc4_hdmi)
|
||||
HDMI_READ(HDMI_CLOCK_STOP) | VC4_DVP_HT_CLOCK_STOP_PIXEL);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DRM_VC4_HDMI_CEC
|
||||
static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
u16 clk_cnt;
|
||||
u32 value;
|
||||
|
||||
value = HDMI_READ(HDMI_CEC_CNTRL_1);
|
||||
value &= ~VC4_HDMI_CEC_DIV_CLK_CNT_MASK;
|
||||
|
||||
/*
|
||||
* Set the clock divider: the hsm_clock rate and this divider
|
||||
* setting will give a 40 kHz CEC clock.
|
||||
*/
|
||||
clk_cnt = clk_get_rate(vc4_hdmi->cec_clock) / CEC_CLOCK_FREQ;
|
||||
value |= clk_cnt << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT;
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_1, value);
|
||||
}
|
||||
#else
|
||||
static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {}
|
||||
#endif
|
||||
|
||||
static enum drm_connector_status
|
||||
vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
|
||||
bool connected = false;
|
||||
|
||||
if (vc4_hdmi->hpd_gpio) {
|
||||
if (gpio_get_value_cansleep(vc4_hdmi->hpd_gpio) ^
|
||||
vc4_hdmi->hpd_active_low)
|
||||
return connector_status_connected;
|
||||
cec_phys_addr_invalidate(vc4_hdmi->cec_adap);
|
||||
return connector_status_disconnected;
|
||||
connected = true;
|
||||
} else if (drm_probe_ddc(vc4_hdmi->ddc)) {
|
||||
connected = true;
|
||||
} else if (HDMI_READ(HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) {
|
||||
connected = true;
|
||||
}
|
||||
|
||||
if (drm_probe_ddc(vc4_hdmi->ddc))
|
||||
return connector_status_connected;
|
||||
if (connected) {
|
||||
if (connector->status != connector_status_connected) {
|
||||
struct edid *edid = drm_get_edid(connector, vc4_hdmi->ddc);
|
||||
|
||||
if (edid) {
|
||||
cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid);
|
||||
vc4_hdmi->encoder.hdmi_monitor = drm_detect_hdmi_monitor(edid);
|
||||
kfree(edid);
|
||||
}
|
||||
}
|
||||
|
||||
if (HDMI_READ(HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED)
|
||||
return connector_status_connected;
|
||||
}
|
||||
|
||||
cec_phys_addr_invalidate(vc4_hdmi->cec_adap);
|
||||
return connector_status_disconnected;
|
||||
}
|
||||
@ -758,6 +791,8 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
return;
|
||||
}
|
||||
|
||||
vc4_hdmi_cec_update_clk_div(vc4_hdmi);
|
||||
|
||||
/*
|
||||
* FIXME: When the pixel freq is 594MHz (4k60), this needs to be setup
|
||||
* at 300MHz.
|
||||
@ -779,9 +814,6 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
return;
|
||||
}
|
||||
|
||||
if (vc4_hdmi->variant->reset)
|
||||
vc4_hdmi->variant->reset(vc4_hdmi);
|
||||
|
||||
if (vc4_hdmi->variant->phy_init)
|
||||
vc4_hdmi->variant->phy_init(vc4_hdmi, vc4_conn_state);
|
||||
|
||||
@ -1423,15 +1455,22 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DRM_VC4_HDMI_CEC
|
||||
static irqreturn_t vc4_cec_irq_handler_thread(int irq, void *priv)
|
||||
static irqreturn_t vc4_cec_irq_handler_rx_thread(int irq, void *priv)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = priv;
|
||||
|
||||
if (vc4_hdmi->cec_irq_was_rx) {
|
||||
if (vc4_hdmi->cec_rx_msg.len)
|
||||
cec_received_msg(vc4_hdmi->cec_adap,
|
||||
&vc4_hdmi->cec_rx_msg);
|
||||
} else if (vc4_hdmi->cec_tx_ok) {
|
||||
if (vc4_hdmi->cec_rx_msg.len)
|
||||
cec_received_msg(vc4_hdmi->cec_adap,
|
||||
&vc4_hdmi->cec_rx_msg);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t vc4_cec_irq_handler_tx_thread(int irq, void *priv)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = priv;
|
||||
|
||||
if (vc4_hdmi->cec_tx_ok) {
|
||||
cec_transmit_done(vc4_hdmi->cec_adap, CEC_TX_STATUS_OK,
|
||||
0, 0, 0, 0);
|
||||
} else {
|
||||
@ -1445,15 +1484,35 @@ static irqreturn_t vc4_cec_irq_handler_thread(int irq, void *priv)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t vc4_cec_irq_handler_thread(int irq, void *priv)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = priv;
|
||||
irqreturn_t ret;
|
||||
|
||||
if (vc4_hdmi->cec_irq_was_rx)
|
||||
ret = vc4_cec_irq_handler_rx_thread(irq, priv);
|
||||
else
|
||||
ret = vc4_cec_irq_handler_tx_thread(irq, priv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void vc4_cec_read_msg(struct vc4_hdmi *vc4_hdmi, u32 cntrl1)
|
||||
{
|
||||
struct drm_device *dev = vc4_hdmi->connector.dev;
|
||||
struct cec_msg *msg = &vc4_hdmi->cec_rx_msg;
|
||||
unsigned int i;
|
||||
|
||||
msg->len = 1 + ((cntrl1 & VC4_HDMI_CEC_REC_WRD_CNT_MASK) >>
|
||||
VC4_HDMI_CEC_REC_WRD_CNT_SHIFT);
|
||||
|
||||
if (msg->len > 16) {
|
||||
drm_err(dev, "Attempting to read too much data (%d)\n", msg->len);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < msg->len; i += 4) {
|
||||
u32 val = HDMI_READ(HDMI_CEC_RX_DATA_1 + i);
|
||||
u32 val = HDMI_READ(HDMI_CEC_RX_DATA_1 + (i >> 2));
|
||||
|
||||
msg->msg[i] = val & 0xff;
|
||||
msg->msg[i + 1] = (val >> 8) & 0xff;
|
||||
@ -1462,31 +1521,55 @@ static void vc4_cec_read_msg(struct vc4_hdmi *vc4_hdmi, u32 cntrl1)
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t vc4_cec_irq_handler_tx_bare(int irq, void *priv)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = priv;
|
||||
u32 cntrl1;
|
||||
|
||||
cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1);
|
||||
vc4_hdmi->cec_tx_ok = cntrl1 & VC4_HDMI_CEC_TX_STATUS_GOOD;
|
||||
cntrl1 &= ~VC4_HDMI_CEC_START_XMIT_BEGIN;
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static irqreturn_t vc4_cec_irq_handler_rx_bare(int irq, void *priv)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = priv;
|
||||
u32 cntrl1;
|
||||
|
||||
vc4_hdmi->cec_rx_msg.len = 0;
|
||||
cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1);
|
||||
vc4_cec_read_msg(vc4_hdmi, cntrl1);
|
||||
cntrl1 |= VC4_HDMI_CEC_CLEAR_RECEIVE_OFF;
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
|
||||
cntrl1 &= ~VC4_HDMI_CEC_CLEAR_RECEIVE_OFF;
|
||||
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static irqreturn_t vc4_cec_irq_handler(int irq, void *priv)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = priv;
|
||||
u32 stat = HDMI_READ(HDMI_CEC_CPU_STATUS);
|
||||
u32 cntrl1, cntrl5;
|
||||
irqreturn_t ret;
|
||||
u32 cntrl5;
|
||||
|
||||
if (!(stat & VC4_HDMI_CPU_CEC))
|
||||
return IRQ_NONE;
|
||||
vc4_hdmi->cec_rx_msg.len = 0;
|
||||
cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1);
|
||||
|
||||
cntrl5 = HDMI_READ(HDMI_CEC_CNTRL_5);
|
||||
vc4_hdmi->cec_irq_was_rx = cntrl5 & VC4_HDMI_CEC_RX_CEC_INT;
|
||||
if (vc4_hdmi->cec_irq_was_rx) {
|
||||
vc4_cec_read_msg(vc4_hdmi, cntrl1);
|
||||
cntrl1 |= VC4_HDMI_CEC_CLEAR_RECEIVE_OFF;
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
|
||||
cntrl1 &= ~VC4_HDMI_CEC_CLEAR_RECEIVE_OFF;
|
||||
} else {
|
||||
vc4_hdmi->cec_tx_ok = cntrl1 & VC4_HDMI_CEC_TX_STATUS_GOOD;
|
||||
cntrl1 &= ~VC4_HDMI_CEC_START_XMIT_BEGIN;
|
||||
}
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
|
||||
HDMI_WRITE(HDMI_CEC_CPU_CLEAR, VC4_HDMI_CPU_CEC);
|
||||
if (vc4_hdmi->cec_irq_was_rx)
|
||||
ret = vc4_cec_irq_handler_rx_bare(irq, priv);
|
||||
else
|
||||
ret = vc4_cec_irq_handler_tx_bare(irq, priv);
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
HDMI_WRITE(HDMI_CEC_CPU_CLEAR, VC4_HDMI_CPU_CEC);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
||||
@ -1523,9 +1606,11 @@ static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
||||
((3600 / usecs) << VC4_HDMI_CEC_CNT_TO_3600_US_SHIFT) |
|
||||
((3500 / usecs) << VC4_HDMI_CEC_CNT_TO_3500_US_SHIFT));
|
||||
|
||||
HDMI_WRITE(HDMI_CEC_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC);
|
||||
if (!vc4_hdmi->variant->external_irq_controller)
|
||||
HDMI_WRITE(HDMI_CEC_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC);
|
||||
} else {
|
||||
HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, VC4_HDMI_CPU_CEC);
|
||||
if (!vc4_hdmi->variant->external_irq_controller)
|
||||
HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, VC4_HDMI_CPU_CEC);
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_5, val |
|
||||
VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
|
||||
}
|
||||
@ -1546,11 +1631,17 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
|
||||
u32 signal_free_time, struct cec_msg *msg)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
struct drm_device *dev = vc4_hdmi->connector.dev;
|
||||
u32 val;
|
||||
unsigned int i;
|
||||
|
||||
if (msg->len > 16) {
|
||||
drm_err(dev, "Attempting to transmit too much data (%d)\n", msg->len);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < msg->len; i += 4)
|
||||
HDMI_WRITE(HDMI_CEC_TX_DATA_1 + i,
|
||||
HDMI_WRITE(HDMI_CEC_TX_DATA_1 + (i >> 2),
|
||||
(msg->msg[i]) |
|
||||
(msg->msg[i + 1] << 8) |
|
||||
(msg->msg[i + 2] << 16) |
|
||||
@ -1577,11 +1668,14 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
struct cec_connector_info conn_info;
|
||||
struct platform_device *pdev = vc4_hdmi->pdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
u32 value;
|
||||
int ret;
|
||||
|
||||
if (!vc4_hdmi->variant->cec_available)
|
||||
if (!of_find_property(dev->of_node, "interrupts", NULL)) {
|
||||
dev_warn(dev, "'interrupts' DT property is missing, no CEC\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
vc4_hdmi->cec_adap = cec_allocate_adapter(&vc4_hdmi_cec_adap_ops,
|
||||
vc4_hdmi, "vc4",
|
||||
@ -1594,23 +1688,39 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)
|
||||
cec_fill_conn_info_from_drm(&conn_info, &vc4_hdmi->connector);
|
||||
cec_s_conn_info(vc4_hdmi->cec_adap, &conn_info);
|
||||
|
||||
HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff);
|
||||
value = HDMI_READ(HDMI_CEC_CNTRL_1);
|
||||
value &= ~VC4_HDMI_CEC_DIV_CLK_CNT_MASK;
|
||||
/*
|
||||
* Set the logical address to Unregistered and set the clock
|
||||
* divider: the hsm_clock rate and this divider setting will
|
||||
* give a 40 kHz CEC clock.
|
||||
*/
|
||||
value |= VC4_HDMI_CEC_ADDR_MASK |
|
||||
(4091 << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT);
|
||||
/* Set the logical address to Unregistered */
|
||||
value |= VC4_HDMI_CEC_ADDR_MASK;
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_1, value);
|
||||
ret = devm_request_threaded_irq(&pdev->dev, platform_get_irq(pdev, 0),
|
||||
vc4_cec_irq_handler,
|
||||
vc4_cec_irq_handler_thread, 0,
|
||||
"vc4 hdmi cec", vc4_hdmi);
|
||||
if (ret)
|
||||
goto err_delete_cec_adap;
|
||||
|
||||
vc4_hdmi_cec_update_clk_div(vc4_hdmi);
|
||||
|
||||
if (vc4_hdmi->variant->external_irq_controller) {
|
||||
ret = devm_request_threaded_irq(&pdev->dev,
|
||||
platform_get_irq_byname(pdev, "cec-rx"),
|
||||
vc4_cec_irq_handler_rx_bare,
|
||||
vc4_cec_irq_handler_rx_thread, 0,
|
||||
"vc4 hdmi cec rx", vc4_hdmi);
|
||||
if (ret)
|
||||
goto err_delete_cec_adap;
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev,
|
||||
platform_get_irq_byname(pdev, "cec-tx"),
|
||||
vc4_cec_irq_handler_tx_bare,
|
||||
vc4_cec_irq_handler_tx_thread, 0,
|
||||
"vc4 hdmi cec tx", vc4_hdmi);
|
||||
if (ret)
|
||||
goto err_delete_cec_adap;
|
||||
} else {
|
||||
HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff);
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, platform_get_irq(pdev, 0),
|
||||
vc4_cec_irq_handler,
|
||||
vc4_cec_irq_handler_thread, 0,
|
||||
"vc4 hdmi cec", vc4_hdmi);
|
||||
if (ret)
|
||||
goto err_delete_cec_adap;
|
||||
}
|
||||
|
||||
ret = cec_register_adapter(vc4_hdmi->cec_adap, &pdev->dev);
|
||||
if (ret < 0)
|
||||
@ -1710,6 +1820,7 @@ static int vc4_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi)
|
||||
return PTR_ERR(vc4_hdmi->hsm_clock);
|
||||
}
|
||||
vc4_hdmi->audio_clock = vc4_hdmi->hsm_clock;
|
||||
vc4_hdmi->cec_clock = vc4_hdmi->hsm_clock;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1803,6 +1914,12 @@ static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi)
|
||||
return PTR_ERR(vc4_hdmi->audio_clock);
|
||||
}
|
||||
|
||||
vc4_hdmi->cec_clock = devm_clk_get(dev, "cec");
|
||||
if (IS_ERR(vc4_hdmi->cec_clock)) {
|
||||
DRM_ERROR("Failed to get CEC clock\n");
|
||||
return PTR_ERR(vc4_hdmi->cec_clock);
|
||||
}
|
||||
|
||||
vc4_hdmi->reset = devm_reset_control_get(dev, NULL);
|
||||
if (IS_ERR(vc4_hdmi->reset)) {
|
||||
DRM_ERROR("Failed to get HDMI reset line\n");
|
||||
@ -1875,6 +1992,9 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
vc4_hdmi->disable_wifi_frequencies =
|
||||
of_property_read_bool(dev->of_node, "wifi-2.4ghz-coexistence");
|
||||
|
||||
if (vc4_hdmi->variant->reset)
|
||||
vc4_hdmi->variant->reset(vc4_hdmi);
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
|
||||
@ -1970,7 +2090,6 @@ static const struct vc4_hdmi_variant bcm2835_variant = {
|
||||
.debugfs_name = "hdmi_regs",
|
||||
.card_name = "vc4-hdmi",
|
||||
.max_pixel_clock = 162000000,
|
||||
.cec_available = true,
|
||||
.registers = vc4_hdmi_fields,
|
||||
.num_registers = ARRAY_SIZE(vc4_hdmi_fields),
|
||||
|
||||
@ -1999,6 +2118,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
|
||||
PHY_LANE_CK,
|
||||
},
|
||||
.unsupported_odd_h_timings = true,
|
||||
.external_irq_controller = true,
|
||||
|
||||
.init_resources = vc5_hdmi_init_resources,
|
||||
.csc_setup = vc5_hdmi_csc_setup,
|
||||
@ -2025,6 +2145,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
|
||||
PHY_LANE_2,
|
||||
},
|
||||
.unsupported_odd_h_timings = true,
|
||||
.external_irq_controller = true,
|
||||
|
||||
.init_resources = vc5_hdmi_init_resources,
|
||||
.csc_setup = vc5_hdmi_csc_setup,
|
||||
|
@ -42,9 +42,6 @@ struct vc4_hdmi_variant {
|
||||
/* Filename to expose the registers in debugfs */
|
||||
const char *debugfs_name;
|
||||
|
||||
/* Set to true when the CEC support is available */
|
||||
bool cec_available;
|
||||
|
||||
/* Maximum pixel clock supported by the controller (in Hz) */
|
||||
unsigned long long max_pixel_clock;
|
||||
|
||||
@ -64,6 +61,13 @@ struct vc4_hdmi_variant {
|
||||
/* The BCM2711 cannot deal with odd horizontal pixel timings */
|
||||
bool unsupported_odd_h_timings;
|
||||
|
||||
/*
|
||||
* The BCM2711 CEC/hotplug IRQ controller is shared between the
|
||||
* two HDMI controllers, and we have a proper irqchip driver for
|
||||
* it.
|
||||
*/
|
||||
bool external_irq_controller;
|
||||
|
||||
/* Callback to get the resources (memory region, interrupts,
|
||||
* clocks, etc) for that variant.
|
||||
*/
|
||||
@ -155,6 +159,7 @@ struct vc4_hdmi {
|
||||
bool cec_tx_ok;
|
||||
bool cec_irq_was_rx;
|
||||
|
||||
struct clk *cec_clock;
|
||||
struct clk *pixel_clock;
|
||||
struct clk *hsm_clock;
|
||||
struct clk *audio_clock;
|
||||
|
@ -29,6 +29,7 @@ enum vc4_hdmi_field {
|
||||
HDMI_CEC_CPU_MASK_SET,
|
||||
HDMI_CEC_CPU_MASK_STATUS,
|
||||
HDMI_CEC_CPU_STATUS,
|
||||
HDMI_CEC_CPU_SET,
|
||||
|
||||
/*
|
||||
* Transmit data, first byte is low byte of the 32-bit reg.
|
||||
@ -199,9 +200,10 @@ static const struct vc4_hdmi_register __maybe_unused vc4_hdmi_fields[] = {
|
||||
VC4_HDMI_REG(HDMI_TX_PHY_RESET_CTL, 0x02c0),
|
||||
VC4_HDMI_REG(HDMI_TX_PHY_CTL_0, 0x02c4),
|
||||
VC4_HDMI_REG(HDMI_CEC_CPU_STATUS, 0x0340),
|
||||
VC4_HDMI_REG(HDMI_CEC_CPU_SET, 0x0344),
|
||||
VC4_HDMI_REG(HDMI_CEC_CPU_CLEAR, 0x0348),
|
||||
VC4_HDMI_REG(HDMI_CEC_CPU_MASK_STATUS, 0x034c),
|
||||
VC4_HDMI_REG(HDMI_CEC_CPU_MASK_SET, 0x034c),
|
||||
VC4_HDMI_REG(HDMI_CEC_CPU_MASK_SET, 0x0350),
|
||||
VC4_HDMI_REG(HDMI_CEC_CPU_MASK_CLEAR, 0x0354),
|
||||
VC4_HDMI_REG(HDMI_RAM_PACKET_START, 0x0400),
|
||||
};
|
||||
|
@ -163,6 +163,7 @@ int virtio_gpu_init(struct drm_device *dev)
|
||||
vgdev->host_visible_region.len,
|
||||
dev_name(&vgdev->vdev->dev))) {
|
||||
DRM_ERROR("Could not reserve host visible region\n");
|
||||
ret = -EBUSY;
|
||||
goto err_vqs;
|
||||
}
|
||||
|
||||
|
@ -668,9 +668,10 @@ static int vmw_setup_pci_resources(struct vmw_private *dev,
|
||||
fifo_size,
|
||||
MEMREMAP_WB);
|
||||
|
||||
if (unlikely(dev->fifo_mem == NULL)) {
|
||||
if (IS_ERR(dev->fifo_mem)) {
|
||||
DRM_ERROR("Failed mapping FIFO memory.\n");
|
||||
return -ENOMEM;
|
||||
pci_release_regions(pdev);
|
||||
return PTR_ERR(dev->fifo_mem);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -716,7 +717,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
|
||||
return ret;
|
||||
ret = vmw_detect_version(dev_priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out_no_pci_or_version;
|
||||
|
||||
mutex_init(&dev_priv->cmdbuf_mutex);
|
||||
mutex_init(&dev_priv->release_mutex);
|
||||
@ -1013,7 +1014,6 @@ out_no_fman:
|
||||
if (dev_priv->capabilities & SVGA_CAP_IRQMASK)
|
||||
vmw_irq_uninstall(&dev_priv->drm);
|
||||
out_no_irq:
|
||||
pci_release_regions(pdev);
|
||||
ttm_object_device_release(&dev_priv->tdev);
|
||||
out_err0:
|
||||
for (i = vmw_res_context; i < vmw_res_max; ++i)
|
||||
@ -1021,7 +1021,8 @@ out_err0:
|
||||
|
||||
if (dev_priv->ctx.staged_bindings)
|
||||
vmw_binding_state_free(dev_priv->ctx.staged_bindings);
|
||||
kfree(dev_priv);
|
||||
out_no_pci_or_version:
|
||||
pci_release_regions(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1059,7 +1060,6 @@ static void vmw_driver_unload(struct drm_device *dev)
|
||||
vmw_fence_manager_takedown(dev_priv->fman);
|
||||
if (dev_priv->capabilities & SVGA_CAP_IRQMASK)
|
||||
vmw_irq_uninstall(&dev_priv->drm);
|
||||
pci_release_regions(pdev);
|
||||
|
||||
ttm_object_device_release(&dev_priv->tdev);
|
||||
if (dev_priv->ctx.staged_bindings)
|
||||
@ -1068,7 +1068,7 @@ static void vmw_driver_unload(struct drm_device *dev)
|
||||
for (i = vmw_res_context; i < vmw_res_max; ++i)
|
||||
idr_destroy(&dev_priv->res_idr[i]);
|
||||
|
||||
kfree(dev_priv);
|
||||
pci_release_regions(pdev);
|
||||
}
|
||||
|
||||
static void vmw_postclose(struct drm_device *dev,
|
||||
|
Loading…
Reference in New Issue
Block a user