Commit 93b68b67 authored by Alan Cox's avatar Alan Cox Committed by Greg Kroah-Hartman

gma500: begin adding CDV specific code

A lot of the intel_display stuff is duplicated, but we will add it first,
clean it up and then investigate the best way to merge stuff.

This first block integrates the various basic chunks of the CDV display setup.
Signed-off-by: default avatarAlan Cox <alan@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 4bc59253
......@@ -24,7 +24,10 @@ psb_gfx-y += gem_glue.o \
psb_device.o \
mid_bios.o
psb_gfx-$(CONFIG_DRM_PSB_CDV) += cdv_device.o
psb_gfx-$(CONFIG_DRM_PSB_CDV) += cdv_device.o \
cdv_intel_display.o \
cdv_intel_crt.o \
cdv_intel_lvds.o
psb_gfx-$(CONFIG_DRM_PSB_MRST) += mrst_device.o \
mrst_crtc.o \
......
......@@ -25,13 +25,42 @@
#include "psb_reg.h"
#include "psb_intel_reg.h"
#include "intel_bios.h"
#include "cdv_device.h"
#define VGA_SR_INDEX 0x3c4
#define VGA_SR_DATA 0x3c5
/* FIXME: should check if we are the active VGA device ?? */
static void cdv_disable_vga(struct drm_device *dev)
{
u8 sr1;
u32 vga_reg;
vga_reg = VGACNTRL;
outb(1, VGA_SR_INDEX);
sr1 = inb(VGA_SR_DATA);
outb(sr1 | 1<<5, VGA_SR_DATA);
udelay(300);
REG_WRITE(vga_reg, VGA_DISP_DISABLE);
REG_READ(vga_reg);
}
static int cdv_output_init(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
psb_intel_lvds_init(dev, &dev_priv->mode_dev);
psb_intel_sdvo_init(dev, SDVOB);
cdv_disable_vga(dev);
cdv_intel_crt_init(dev, &dev_priv->mode_dev);
cdv_intel_lvds_init(dev, &dev_priv->mode_dev);
/* These bits indicate HDMI not SDVO on CDV, but we don't yet support
the HDMI interface */
if (REG_READ(SDVOB) & SDVO_DETECTED)
DRM_ERROR("HDMI not supported yet\n");
if (REG_READ(SDVOC) & SDVO_DETECTED)
DRM_ERROR("HDMI not supported yet\n");
return 0;
}
......@@ -148,19 +177,70 @@ static int cdv_backlight_init(struct drm_device *dev)
#endif
/*
* Provide the Poulsbo specific chip logic and low level methods
* Provide the Cedarview specific chip logic and low level methods
* for power management
*
* FIXME: we need to implement the apm/ospm base management bits
* for this and the MID devices.
*/
static inline u32 CDV_MSG_READ32(uint port, uint offset)
{
int mcr = (0x10<<24) | (port << 16) | (offset << 8);
uint32_t ret_val = 0;
struct pci_dev *pci_root = pci_get_bus_and_slot (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 CDV_MSG_WRITE32(uint port, uint offset, u32 value)
{
int mcr = (0x11<<24) | (port << 16) | (offset << 8) | 0xF0;
struct pci_dev *pci_root = pci_get_bus_and_slot (0, 0);
pci_write_config_dword (pci_root, 0xD4, value);
pci_write_config_dword (pci_root, 0xD0, mcr);
pci_dev_put(pci_root);
}
#define PSB_APM_CMD 0x0
#define PSB_APM_STS 0x04
#define PSB_PM_SSC 0x20
#define PSB_PM_SSS 0x30
#define PSB_PWRGT_GFX_MASK 0x3
#define CDV_PWRGT_DISPLAY_CNTR 0x000fc00c
#define CDV_PWRGT_DISPLAY_STS 0x000fc00c
static void cdv_init_pm(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
u32 gating = PSB_RSGX32(PSB_CR_CLKGATECTL);
gating &= ~3; /* Disable 2D clock gating */
gating |= 1;
PSB_WSGX32(gating, PSB_CR_CLKGATECTL);
PSB_RSGX32(PSB_CR_CLKGATECTL);
u32 pwr_cnt;
int i;
dev_priv->apm_base = CDV_MSG_READ32(PSB_PUNIT_PORT, PSB_APMBA) & 0xFFFF;
dev_priv->ospm_base = CDV_MSG_READ32(PSB_PUNIT_PORT, PSB_OSPMBA) & 0xFFFF;
/* Force power on for now */
pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD);
pwr_cnt &= ~PSB_PWRGT_GFX_MASK;
outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD);
for (i = 0; i < 5; i++) {
u32 pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS);
if ((pwr_sts & PSB_PWRGT_GFX_MASK) == 0)
break;
udelay(10);
}
pwr_cnt = inl(dev_priv->ospm_base + PSB_PM_SSC);
pwr_cnt &= ~CDV_PWRGT_DISPLAY_CNTR;
outl(pwr_cnt, dev_priv->ospm_base + PSB_PM_SSC);
for (i = 0; i < 5; i++) {
u32 pwr_sts = inl(dev_priv->ospm_base + PSB_PM_SSS);
if ((pwr_sts & CDV_PWRGT_DISPLAY_STS) == 0)
break;
udelay(10);
}
}
/**
......@@ -169,34 +249,11 @@ static void cdv_init_pm(struct drm_device *dev)
*
* Save the state we need in order to be able to restore the interface
* upon resume from suspend
*
* FIXME: review
*/
static int cdv_save_display_registers(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc;
struct drm_connector *connector;
/* Display arbitration control + watermarks */
dev_priv->saveDSPARB = PSB_RVDC32(DSPARB);
dev_priv->saveDSPFW1 = PSB_RVDC32(DSPFW1);
dev_priv->saveDSPFW2 = PSB_RVDC32(DSPFW2);
dev_priv->saveDSPFW3 = PSB_RVDC32(DSPFW3);
dev_priv->saveDSPFW4 = PSB_RVDC32(DSPFW4);
dev_priv->saveDSPFW5 = PSB_RVDC32(DSPFW5);
dev_priv->saveDSPFW6 = PSB_RVDC32(DSPFW6);
dev_priv->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);
/* Save crtc and output state */
mutex_lock(&dev->mode_config.mutex);
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
if (drm_helper_crtc_in_use(crtc))
crtc->funcs->save(crtc);
}
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
connector->funcs->save(connector);
mutex_unlock(&dev->mode_config.mutex);
return 0;
}
......@@ -205,67 +262,11 @@ static int cdv_save_display_registers(struct drm_device *dev)
* @dev: our DRM device
*
* Restore register state that was lost during suspend and resume.
*
* FIXME: review
*/
static int cdv_restore_display_registers(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc;
struct drm_connector *connector;
int pp_stat;
/* Display arbitration + watermarks */
PSB_WVDC32(dev_priv->saveDSPARB, DSPARB);
PSB_WVDC32(dev_priv->saveDSPFW1, DSPFW1);
PSB_WVDC32(dev_priv->saveDSPFW2, DSPFW2);
PSB_WVDC32(dev_priv->saveDSPFW3, DSPFW3);
PSB_WVDC32(dev_priv->saveDSPFW4, DSPFW4);
PSB_WVDC32(dev_priv->saveDSPFW5, DSPFW5);
PSB_WVDC32(dev_priv->saveDSPFW6, DSPFW6);
PSB_WVDC32(dev_priv->saveCHICKENBIT, DSPCHICKENBIT);
/*make sure VGA plane is off. it initializes to on after reset!*/
PSB_WVDC32(0x80000000, VGACNTRL);
mutex_lock(&dev->mode_config.mutex);
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
if (drm_helper_crtc_in_use(crtc))
crtc->funcs->restore(crtc);
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
connector->funcs->restore(connector);
mutex_unlock(&dev->mode_config.mutex);
if (dev_priv->iLVDS_enable) {
/*shutdown the panel*/
PSB_WVDC32(0, PP_CONTROL);
do {
pp_stat = PSB_RVDC32(PP_STATUS);
} while (pp_stat & 0x80000000);
/* Turn off the plane */
PSB_WVDC32(0x58000000, DSPACNTR);
PSB_WVDC32(0, DSPASURF);/*trigger the plane disable*/
/* Wait ~4 ticks */
msleep(4);
/* Turn off pipe */
PSB_WVDC32(0x0, PIPEACONF);
/* Wait ~8 ticks */
msleep(8);
/* Turn off PLLs */
PSB_WVDC32(0, MRST_DPLL_A);
} else {
PSB_WVDC32(DPI_SHUT_DOWN, DPI_CONTROL_REG);
PSB_WVDC32(0x0, PIPEACONF);
PSB_WVDC32(0x2faf0000, BLC_PWM_CTL);
while (REG_READ(0x70008) & 0x40000000)
cpu_relax();
while ((PSB_RVDC32(GEN_FIFO_STAT_REG) & DPI_FIFO_EMPTY)
!= DPI_FIFO_EMPTY)
cpu_relax();
PSB_WVDC32(0, DEVICE_READY_REG);
}
return 0;
}
......@@ -286,9 +287,6 @@ static void cdv_get_core_freq(struct drm_device *dev)
struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0);
struct drm_psb_private *dev_priv = dev->dev_private;
/*pci_write_config_dword(pci_root, 0xD4, 0x00C32004);*/
/*pci_write_config_dword(pci_root, 0xD0, 0xE0033000);*/
pci_write_config_dword(pci_root, 0xD0, 0xD0050300);
pci_read_config_dword(pci_root, 0xD4, &clock);
pci_dev_put(pci_root);
......@@ -326,7 +324,7 @@ static int cdv_chip_setup(struct drm_device *dev)
return 0;
}
/* CDV is much like Poulsbo but has MID like SGX offsets */
/* CDV is much like Poulsbo but has MID like SGX offsets and PM */
const struct psb_ops cdv_chip_ops = {
.name = "Cedartrail",
......@@ -335,8 +333,8 @@ const struct psb_ops cdv_chip_ops = {
.sgx_offset = MRST_SGX_OFFSET,
.chip_setup = cdv_chip_setup,
.crtc_helper = &psb_intel_helper_funcs,
.crtc_funcs = &psb_intel_crtc_funcs,
.crtc_helper = &cdv_intel_helper_funcs,
.crtc_funcs = &cdv_intel_crtc_funcs,
.output_init = cdv_output_init,
......@@ -350,4 +348,3 @@ const struct psb_ops cdv_chip_ops = {
.power_down = cdv_power_down,
.power_up = cdv_power_up,
};
This diff is collapsed.
This diff is collapsed.
......@@ -732,6 +732,10 @@ static void psb_setup_outputs(struct drm_device *dev)
/* valid crtcs */
switch (psb_intel_output->type) {
case INTEL_OUTPUT_ANALOG:
crtc_mask = (1 << 0);
clone_mask = (1 << INTEL_OUTPUT_ANALOG);
break;
case INTEL_OUTPUT_SDVO:
crtc_mask = ((1 << 0) | (1 << 1));
clone_mask = (1 << INTEL_OUTPUT_SDVO);
......@@ -752,7 +756,10 @@ static void psb_setup_outputs(struct drm_device *dev)
clone_mask = (1 << INTEL_OUTPUT_MIPI2);
break;
case INTEL_OUTPUT_HDMI:
crtc_mask = (1 << 1);
if (IS_MFLD(dev))
crtc_mask = (1 << 1);
else /* FIXME: review Oaktrail */
crtc_mask = (1 << 0); /* Cedarview */
clone_mask = (1 << INTEL_OUTPUT_HDMI);
break;
}
......
......@@ -395,12 +395,10 @@ int psb_gtt_init(struct drm_device *dev, int resume)
(void) PSB_RVDC32(PSB_PGETBL_CTL);
/* The root resource we allocate address space from */
dev_priv->gtt_mem = &dev->pdev->resource[PSB_GATT_RESOURCE];
dev_priv->gtt_initialized = 1;
pg->gtt_phys_start = dev_priv->pge_ctl & PAGE_MASK;
pg->gatt_start = pci_resource_start(dev->pdev, PSB_GATT_RESOURCE);
pg->gtt_phys_start = dev_priv->pge_ctl;
/*
* FIXME: video mmu has hw bug to access 0x0D0000000,
* then make gatt start at 0x0e000,0000
......@@ -410,8 +408,33 @@ int psb_gtt_init(struct drm_device *dev, int resume)
pg->gtt_start = pci_resource_start(dev->pdev, PSB_GTT_RESOURCE);
gtt_pages = pci_resource_len(dev->pdev, PSB_GTT_RESOURCE)
>> PAGE_SHIFT;
/* CDV workaround */
if (pg->gtt_start == 0 || gtt_pages == 0) {
dev_err(dev->dev, "GTT PCI BAR not initialized.\n");
gtt_pages = 64;
pg->gtt_start = dev_priv->pge_ctl;
}
pg->gatt_start = pci_resource_start(dev->pdev, PSB_GATT_RESOURCE);
pg->gatt_pages = pci_resource_len(dev->pdev, PSB_GATT_RESOURCE)
>> PAGE_SHIFT;
dev_priv->gtt_mem = &dev->pdev->resource[PSB_GATT_RESOURCE];
if (pg->gatt_pages == 0 || pg->gatt_start == 0) {
static struct resource fudge; /* Preferably peppermint */
/* This can occur on CDV SDV systems. Fudge it in this case.
We really don't care what imaginary space is being allocated
at this point */
dev_err(dev->dev, "GATT PCI BAR not initialized.\n");
pg->gatt_start = 0x40000000;
pg->gatt_pages = (128 * 1024 * 1024) >> PAGE_SHIFT;
fudge.start = 0x40000000;
fudge.end = 0x40000000 + 128 * 1024 * 1024 - 1;
fudge.name = "fudge";
fudge.flags = IORESOURCE_MEM;
dev_priv->gtt_mem = &fudge;
}
pci_read_config_dword(dev->pdev, PSB_BSM, &dev_priv->stolen_base);
vram_stolen_size = pg->gtt_phys_start - dev_priv->stolen_base
......@@ -463,7 +486,7 @@ int psb_gtt_init(struct drm_device *dev, int resume)
pfn_base = dev_priv->stolen_base >> PAGE_SHIFT;
vram_pages = num_pages = vram_stolen_size >> PAGE_SHIFT;
printk(KERN_INFO"Set up %d stolen pages starting at 0x%08x, GTT offset %dK\n",
num_pages, pfn_base, 0);
num_pages, pfn_base << PAGE_SHIFT, 0);
for (i = 0; i < num_pages; ++i) {
pte = psb_gtt_mask_pte(pfn_base + i, 0);
iowrite32(pte, dev_priv->gtt_map + i);
......
......@@ -1039,14 +1039,13 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc,
}
/* unpin the old bo */
if (psb_intel_crtc->cursor_obj && psb_intel_crtc->cursor_obj != obj) {
if (psb_intel_crtc->cursor_obj) {
gt = container_of(psb_intel_crtc->cursor_obj,
struct gtt_range, gem);
psb_gtt_unpin(gt);
drm_gem_object_unreference(psb_intel_crtc->cursor_obj);
psb_intel_crtc->cursor_obj = obj;
}
return 0;
}
......
......@@ -142,6 +142,8 @@
#define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */
#define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */
#define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */
#define DPLL_LOCK (1 << 15) /* CDV */
/*
* The i830 generation, in DAC/serial mode, defines p1 as two plus this
* bitfield, or just 2 if PLL_P1_DIVIDE_BY_TWO is set.
......@@ -271,6 +273,20 @@
#define TV_HOTPLUG_INT_EN (1 << 18)
#define CRT_HOTPLUG_INT_EN (1 << 9)
#define CRT_HOTPLUG_FORCE_DETECT (1 << 3)
/* CDV.. */
#define CRT_HOTPLUG_ACTIVATION_PERIOD_64 (1 << 8)
#define CRT_HOTPLUG_DAC_ON_TIME_2M (0 << 7)
#define CRT_HOTPLUG_DAC_ON_TIME_4M (1 << 7)
#define CRT_HOTPLUG_VOLTAGE_COMPARE_40 (0 << 5)
#define CRT_HOTPLUG_VOLTAGE_COMPARE_50 (1 << 5)
#define CRT_HOTPLUG_VOLTAGE_COMPARE_60 (2 << 5)
#define CRT_HOTPLUG_VOLTAGE_COMPARE_70 (3 << 5)
#define CRT_HOTPLUG_VOLTAGE_COMPARE_MASK (3 << 5)
#define CRT_HOTPLUG_DETECT_DELAY_1G (0 << 4)
#define CRT_HOTPLUG_DETECT_DELAY_2G (1 << 4)
#define CRT_HOTPLUG_DETECT_VOLTAGE_325MV (0 << 2)
#define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2)
#define CRT_HOTPLUG_DETECT_MASK 0x000000F8
#define PORT_HOTPLUG_STAT 0x61114
#define CRT_HOTPLUG_INT_STATUS (1 << 11)
......@@ -1141,4 +1157,79 @@ No status bits are changed.
#define SKU_100L 0x04
#define SKU_BYPASS 0x08
/* Some handy macros for playing with bitfields. */
#define PSB_MASK(high, low) (((1<<((high)-(low)+1))-1)<<(low))
#define SET_FIELD(value, field) (((value) << field ## _SHIFT) & field ## _MASK)
#define GET_FIELD(word, field) (((word) & field ## _MASK) >> field ## _SHIFT)
#define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a)))
/* PCI config space */
#define SB_PCKT 0x02100 /* cedarview */
# define SB_OPCODE_MASK PSB_MASK(31, 16)
# define SB_OPCODE_SHIFT 16
# define SB_OPCODE_READ 0
# define SB_OPCODE_WRITE 1
# define SB_DEST_MASK PSB_MASK(15, 8)
# define SB_DEST_SHIFT 8
# define SB_DEST_DPLL 0x88
# define SB_BYTE_ENABLE_MASK PSB_MASK(7, 4)
# define SB_BYTE_ENABLE_SHIFT 4
# define SB_BUSY (1 << 0)
/* 32-bit value read/written from the DPIO reg. */
#define SB_DATA 0x02104 /* cedarview */
/* 32-bit address of the DPIO reg to be read/written. */
#define SB_ADDR 0x02108 /* cedarview */
#define DPIO_CFG 0x02110 /* cedarview */
# define DPIO_MODE_SELECT_1 (1 << 3)
# define DPIO_MODE_SELECT_0 (1 << 2)
# define DPIO_SFR_BYPASS (1 << 1)
/* reset is active low */
# define DPIO_CMN_RESET_N (1 << 0)
/* Cedarview sideband registers */
#define _SB_M_A 0x8008
#define _SB_M_B 0x8028
#define SB_M(pipe) _PIPE(pipe, _SB_M_A, _SB_M_B)
# define SB_M_DIVIDER_MASK (0xFF << 24)
# define SB_M_DIVIDER_SHIFT 24
#define _SB_N_VCO_A 0x8014
#define _SB_N_VCO_B 0x8034
#define SB_N_VCO(pipe) _PIPE(pipe, _SB_N_VCO_A, _SB_N_VCO_B)
#define SB_N_VCO_SEL_MASK PSB_MASK(31, 30)
#define SB_N_VCO_SEL_SHIFT 30
#define SB_N_DIVIDER_MASK PSB_MASK(29, 26)
#define SB_N_DIVIDER_SHIFT 26
#define SB_N_CB_TUNE_MASK PSB_MASK(25, 24)
#define SB_N_CB_TUNE_SHIFT 24
#define _SB_REF_A 0x8018
#define _SB_REF_B 0x8038
#define SB_REF_SFR(pipe) _PIPE(pipe, _SB_REF_A, _SB_REF_B)
#define _SB_P_A 0x801c
#define _SB_P_B 0x803c
#define SB_P(pipe) _PIPE(pipe, _SB_P_A, _SB_P_B)
#define SB_P2_DIVIDER_MASK PSB_MASK(31, 30)
#define SB_P2_DIVIDER_SHIFT 30
#define SB_P2_10 0 /* HDMI, DP, DAC */
#define SB_P2_5 1 /* DAC */
#define SB_P2_14 2 /* LVDS single */
#define SB_P2_7 3 /* LVDS double */
#define SB_P1_DIVIDER_MASK PSB_MASK(15, 12)
#define SB_P1_DIVIDER_SHIFT 12
#define PSB_LANE0 0x120
#define PSB_LANE1 0x220
#define PSB_LANE2 0x2320
#define PSB_LANE3 0x2420
#define LANE_PLL_MASK (0x7 << 20)
#define LANE_PLL_ENABLE (0x3 << 20)
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment