diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-26 06:26:34 (GMT) |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-26 06:26:34 (GMT) |
commit | 138051659902da7e6a09d379fee5dade2a80fcfd (patch) | |
tree | e0a90e27451b1fcd812675092d30c1059369cb87 /drivers/staging/gma500 | |
parent | d5ef642355bdd9b383ff5c18cbc6102a06eecbaf (diff) | |
parent | e1703b329f7c7ea82ea181dc4c50020f25061a2c (diff) | |
download | linux-fsl-qoriq-138051659902da7e6a09d379fee5dade2a80fcfd.tar.xz |
Merge branch 'staging-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6
* 'staging-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6: (741 commits)
staging:iio:meter:ade7753 should be 16 bit read not 8 bit for mode register.
staging:iio:kfifo_buf fix double initialization of the ring device structure.
staging:iio:accel:lis3l02dq: fix incorrect pointer passed to spi_set_drvdata.
staging:iio:imu fix missing register table index for some channels
spectra: enable device before poking it
staging: rts_pstor: Fix a miswriting
staging/lirc_bt829: Return -ENODEV when no hardware is found.
staging/lirc_parallel: remove pointless prototypes.
staging/lirc_parallel: fix panic on rmmod
staging:iio:adc:ad7476: Incorrect pointer into spi_set_drvdata.
Staging: zram: Fix kunmapping order
Revert "gma500: Fix dependencies"
gma500: Add medfield header
gma500: wire up the mrst i2c bus from chip_info
gma500: Fix DPU build
gma500: Clean up the DPU config and make it runtime
gma500: resync with Medfield progress
gma500: Use the mrst helpers and power control for mode commit
gma500@ Fix backlight range error
gma500: More Moorestown muddle meddling means MM maybe might modeset
...
Fix up fairly trivial conflicts all over, mostly due to header file
cleanup conflicts, but some deleted files and some just context changes:
- Documentation/feature-removal-schedule.txt
- drivers/staging/bcm/headers.h
- drivers/staging/brcm80211/brcmfmac/dhd_linux.c
- drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
- drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h
- drivers/staging/brcm80211/brcmfmac/wl_iw.c
- drivers/staging/et131x/et131x_netdev.c
- drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
- drivers/staging/rtl8192e/r8192E.h
- drivers/staging/usbip/userspace/src/utils.h
Diffstat (limited to 'drivers/staging/gma500')
76 files changed, 18335 insertions, 3127 deletions
diff --git a/drivers/staging/gma500/Kconfig b/drivers/staging/gma500/Kconfig index ce8beda..bfe2166 100644 --- a/drivers/staging/gma500/Kconfig +++ b/drivers/staging/gma500/Kconfig @@ -1,5 +1,5 @@ config DRM_PSB - tristate "Intel GMA500 KMS Framebuffer" + tristate "Intel GMA5/600 KMS Framebuffer" depends on DRM && PCI && X86 select FB_CFB_COPYAREA select FB_CFB_FILLRECT @@ -7,6 +7,27 @@ config DRM_PSB select DRM_KMS_HELPER select DRM_TTM help - Say yes for an experimental KMS framebuffer driver for the - Intel GMA500 ('Poulsbo') graphics support. + Say yes for an experimental 2D KMS framebuffer driver for the + Intel GMA500 ('Poulsbo') and other Intel IMG based graphics + devices. +config DRM_PSB_MRST + bool "Intel GMA600 support (Experimental)" + depends on DRM_PSB + help + Say yes to include support for GMA600 (Intel Moorestown/Oaktrail) + platforms with LVDS ports. HDMI and MIPI are not currently + supported. + +config DRM_PSB_MFLD + bool "Intel Medfield support (Experimental)" + depends on DRM_PSB + help + Say yes to include support for Intel Medfield platforms with MIPI + interfaces. + +config DRM_PSB_CDV + bool "Intel Cedarview support (Experimental)" + depends on DRM_PSB + help + Say yes to include support for Intel Cedarview platforms diff --git a/drivers/staging/gma500/Makefile b/drivers/staging/gma500/Makefile index db73ec6..c729868 100644 --- a/drivers/staging/gma500/Makefile +++ b/drivers/staging/gma500/Makefile @@ -3,24 +3,50 @@ # ccflags-y += -Iinclude/drm -psb_gfx-y += psb_bl.o \ +psb_gfx-y += gem_glue.o \ + accel_2d.o \ + backlight.o \ + framebuffer.o \ + gem.o \ + gtt.o \ + intel_bios.o \ + intel_i2c.o \ + intel_opregion.o \ + mmu.o \ + power.o \ psb_drv.o \ - psb_gem.o \ - psb_fb.o \ - psb_2d.o \ - psb_gtt.o \ - psb_intel_bios.o \ - psb_intel_opregion.o \ psb_intel_display.o \ - psb_intel_i2c.o \ psb_intel_lvds.o \ psb_intel_modes.o \ psb_intel_sdvo.o \ psb_lid.o \ - psb_mmu.o \ - psb_powermgmt.o \ psb_irq.o \ + psb_device.o \ + mid_bios.o + +psb_gfx-$(CONFIG_DRM_PSB_CDV) += cdv_device.o \ + cdv_intel_crt.o \ + cdv_intel_display.o \ + cdv_intel_hdmi.o \ + cdv_intel_lvds.o + +psb_gfx-$(CONFIG_DRM_PSB_MRST) += mrst_device.o \ mrst_crtc.o \ - mrst_lvds.o + mrst_lvds.o \ + mrst_hdmi.o \ + mrst_hdmi_i2c.o + +psb_gfx-$(CONFIG_DRM_PSB_MFLD) += mdfld_device.o \ + mdfld_output.o \ + mdfld_pyr_cmd.o \ + mdfld_tmd_vid.o \ + mdfld_tpo_cmd.o \ + mdfld_tpo_vid.o \ + mdfld_dsi_pkg_sender.o \ + mdfld_dsi_dpi.o \ + mdfld_dsi_output.o \ + mdfld_dsi_dbi.o \ + mdfld_dsi_dbi_dpu.o \ + mdfld_intel_display.o obj-$(CONFIG_DRM_PSB) += psb_gfx.o diff --git a/drivers/staging/gma500/TODO b/drivers/staging/gma500/TODO index f692ce1..fc83615 100644 --- a/drivers/staging/gma500/TODO +++ b/drivers/staging/gma500/TODO @@ -1,26 +1,15 @@ -- Test on more platforms -- Clean up the various chunks of unused code - Sort out the power management side. Not important for Poulsbo but - matters for Moorestown -- Add Moorestown support (single pipe, no BIOS, no stolen memory, - some other differences) -- Sort out the bo and ttm code to support userframe buffers and DRM - interfaces rather than just faking it enough for a framebuffer + matters for Moorestown/Medfield +- Debug Oaktrail/Moorestown support (single pipe, no BIOS on mrst, + some other differences) - Add 2D acceleration via console and DRM +- Add scrolling acceleration using the GTT to do remapping on the main + framebuffer. +- HDMI testing +- Oaktrail HDMI and other features +- Oaktrail MIPI +- Medfield needs a lot of further love As per kernel policy and the in the interest of the safety of various kittens there is no support or plans to add hooks for the closed user space stuff. - - -Why bother ? -- Proper display configuration -- Can be made to work on Moorestown where VESA won't -- Works on systems where the VESA BIOS is bust or the tables are broken - without hacks -- 2D acceleration - -Currently tested on -+ Dell Mini 10 100x600 - - diff --git a/drivers/staging/gma500/psb_2d.c b/drivers/staging/gma500/accel_2d.c index 0bd834c..14400fc 100644 --- a/drivers/staging/gma500/psb_2d.c +++ b/drivers/staging/gma500/accel_2d.c @@ -1,5 +1,5 @@ /************************************************************************** - * Copyright (c) 2007, Intel Corporation. + * Copyright (c) 2007-2011, Intel Corporation. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it @@ -38,16 +38,23 @@ #include "psb_drv.h" #include "psb_reg.h" -#include "psb_drv.h" -#include "psb_fb.h" +#include "framebuffer.h" +/** + * psb_spank - reset the 2D engine + * @dev_priv: our PSB DRM device + * + * Soft reset the graphics engine and then reload the necessary registers. + * We use this at initialisation time but it will become relevant for + * accelerated X later + */ void psb_spank(struct drm_psb_private *dev_priv) { - PSB_WSGX32(_PSB_CS_RESET_BIF_RESET | _PSB_CS_RESET_DPM_RESET | + PSB_WSGX32(_PSB_CS_RESET_BIF_RESET | _PSB_CS_RESET_DPM_RESET | _PSB_CS_RESET_TA_RESET | _PSB_CS_RESET_USE_RESET | _PSB_CS_RESET_ISP_RESET | _PSB_CS_RESET_TSP_RESET | _PSB_CS_RESET_TWOD_RESET, PSB_CR_SOFT_RESET); - (void) PSB_RSGX32(PSB_CR_SOFT_RESET); + PSB_RSGX32(PSB_CR_SOFT_RESET); msleep(1); @@ -62,16 +69,24 @@ void psb_spank(struct drm_psb_private *dev_priv) PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) & ~_PSB_CB_CTRL_CLEAR_FAULT, PSB_CR_BIF_CTRL); (void) PSB_RSGX32(PSB_CR_BIF_CTRL); - PSB_WSGX32(dev_priv->pg->gatt_start, PSB_CR_BIF_TWOD_REQ_BASE); + PSB_WSGX32(dev_priv->gtt.gatt_start, PSB_CR_BIF_TWOD_REQ_BASE); } +/** + * psb2_2d_wait_available - wait for FIFO room + * @dev_priv: our DRM device + * @size: size (in dwords) of the command we want to issue + * + * Wait until there is room to load the FIFO with our data. If the + * device is not responding then reset it + */ static int psb_2d_wait_available(struct drm_psb_private *dev_priv, unsigned size) { uint32_t avail = PSB_RSGX32(PSB_CR_2D_SOCIF); unsigned long t = jiffies + HZ; - while(avail < size) { + while (avail < size) { avail = PSB_RSGX32(PSB_CR_2D_SOCIF); if (time_after(jiffies, t)) { psb_spank(dev_priv); @@ -81,151 +96,77 @@ static int psb_2d_wait_available(struct drm_psb_private *dev_priv, return 0; } -/* FIXME: Remember if we expose the 2D engine to the DRM we need to serialize - it with console use */ - -int psbfb_2d_submit(struct drm_psb_private *dev_priv, uint32_t *cmdbuf, - unsigned size) +/** + * psb_2d_submit - submit a 2D command + * @dev_priv: our DRM device + * @cmdbuf: command to issue + * @size: length (in dwords) + * + * Issue one or more 2D commands to the accelerator. This needs to be + * serialized later when we add the GEM interfaces for acceleration + */ +static int psbfb_2d_submit(struct drm_psb_private *dev_priv, uint32_t *cmdbuf, + unsigned size) { int ret = 0; int i; unsigned submit_size; + mutex_lock(&dev_priv->mutex_2d); while (size > 0) { submit_size = (size < 0x60) ? size : 0x60; size -= submit_size; ret = psb_2d_wait_available(dev_priv, submit_size); if (ret) - return ret; + break; submit_size <<= 2; - for (i = 0; i < submit_size; i += 4) { - PSB_WSGX32(*cmdbuf++, PSB_SGX_2D_SLAVE_PORT + i); - } - (void)PSB_RSGX32(PSB_SGX_2D_SLAVE_PORT + i - 4); - } - return 0; -} - -static int psb_accel_2d_fillrect(struct drm_psb_private *dev_priv, - uint32_t dst_offset, uint32_t dst_stride, - uint32_t dst_format, uint16_t dst_x, - uint16_t dst_y, uint16_t size_x, - uint16_t size_y, uint32_t fill) -{ - uint32_t buffer[10]; - uint32_t *buf; - - buf = buffer; - - *buf++ = PSB_2D_FENCE_BH; - - *buf++ = - PSB_2D_DST_SURF_BH | dst_format | (dst_stride << - PSB_2D_DST_STRIDE_SHIFT); - *buf++ = dst_offset; - - *buf++ = - PSB_2D_BLIT_BH | - PSB_2D_ROT_NONE | - PSB_2D_COPYORDER_TL2BR | - PSB_2D_DSTCK_DISABLE | - PSB_2D_SRCCK_DISABLE | PSB_2D_USE_FILL | PSB_2D_ROP3_PATCOPY; - - *buf++ = fill << PSB_2D_FILLCOLOUR_SHIFT; - *buf++ = - (dst_x << PSB_2D_DST_XSTART_SHIFT) | (dst_y << - PSB_2D_DST_YSTART_SHIFT); - *buf++ = - (size_x << PSB_2D_DST_XSIZE_SHIFT) | (size_y << - PSB_2D_DST_YSIZE_SHIFT); - *buf++ = PSB_2D_FLUSH_BH; - - return psbfb_2d_submit(dev_priv, buffer, buf - buffer); -} - -static void psbfb_fillrect_accel(struct fb_info *info, - const struct fb_fillrect *r) -{ - struct psb_fbdev *fbdev = info->par; - struct psb_framebuffer *psbfb = fbdev->pfb; - struct drm_device *dev = psbfb->base.dev; - struct drm_framebuffer *fb = fbdev->psb_fb_helper.fb; - struct drm_psb_private *dev_priv = dev->dev_private; - - uint32_t offset; - uint32_t stride; - uint32_t format; - if (!fb) - return; - - offset = psbfb->gtt->offset; - stride = fb->pitch; + for (i = 0; i < submit_size; i += 4) + PSB_WSGX32(*cmdbuf++, PSB_SGX_2D_SLAVE_PORT + i); - switch (fb->depth) { - case 8: - format = PSB_2D_DST_332RGB; - break; - case 15: - format = PSB_2D_DST_555RGB; - break; - case 16: - format = PSB_2D_DST_565RGB; - break; - case 24: - case 32: - /* this is wrong but since we don't do blending its okay */ - format = PSB_2D_DST_8888ARGB; - break; - default: - /* software fallback */ - cfb_fillrect(info, r); - return; + (void)PSB_RSGX32(PSB_SGX_2D_SLAVE_PORT + i - 4); } - - psb_accel_2d_fillrect(dev_priv, - offset, stride, format, - r->dx, r->dy, r->width, r->height, r->color); + mutex_unlock(&dev_priv->mutex_2d); + return ret; } -void psbfb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) -{ - if (unlikely(info->state != FBINFO_STATE_RUNNING)) - return; - - if (1 || (info->flags & FBINFO_HWACCEL_DISABLED)) - return cfb_fillrect(info, rect); - - /*psb_check_power_state(dev, PSB_DEVICE_SGX); */ - psbfb_fillrect_accel(info, rect); - /* Drop power again here on MRST FIXMEAC */ -} +/** + * psb_accel_2d_copy_direction - compute blit order + * @xdir: X direction of move + * @ydir: Y direction of move + * + * Compute the correct order setings to ensure that an overlapping blit + * correctly copies all the pixels. + */ static u32 psb_accel_2d_copy_direction(int xdir, int ydir) { if (xdir < 0) return (ydir < 0) ? PSB_2D_COPYORDER_BR2TL : - PSB_2D_COPYORDER_TR2BL; + PSB_2D_COPYORDER_TR2BL; else return (ydir < 0) ? PSB_2D_COPYORDER_BL2TR : - PSB_2D_COPYORDER_TL2BR; + PSB_2D_COPYORDER_TL2BR; } -/* - * @src_offset in bytes - * @src_stride in bytes - * @src_format psb 2D format defines - * @dst_offset in bytes - * @dst_stride in bytes - * @dst_format psb 2D format defines - * @src_x offset in pixels - * @src_y offset in pixels - * @dst_x offset in pixels - * @dst_y offset in pixels - * @size_x of the copied area - * @size_y of the copied area +/** + * psb_accel_2d_copy - accelerated 2D copy + * @dev_priv: our DRM device + * @src_offset in bytes + * @src_stride in bytes + * @src_format psb 2D format defines + * @dst_offset in bytes + * @dst_stride in bytes + * @dst_format psb 2D format defines + * @src_x offset in pixels + * @src_y offset in pixels + * @dst_x offset in pixels + * @dst_y offset in pixels + * @size_x of the copied area + * @size_y of the copied area + * + * Format and issue a 2D accelerated copy command. */ static int psb_accel_2d_copy(struct drm_psb_private *dev_priv, uint32_t src_offset, uint32_t src_stride, @@ -287,11 +228,18 @@ static int psb_accel_2d_copy(struct drm_psb_private *dev_priv, return psbfb_2d_submit(dev_priv, buffer, buf - buffer); } +/** + * psbfb_copyarea_accel - copyarea acceleration for /dev/fb + * @info: our framebuffer + * @a: copyarea parameters from the framebuffer core + * + * Perform a 2D copy via the accelerator + */ static void psbfb_copyarea_accel(struct fb_info *info, const struct fb_copyarea *a) { struct psb_fbdev *fbdev = info->par; - struct psb_framebuffer *psbfb = fbdev->pfb; + struct psb_framebuffer *psbfb = &fbdev->pfb; struct drm_device *dev = psbfb->base.dev; struct drm_framebuffer *fb = fbdev->psb_fb_helper.fb; struct drm_psb_private *dev_priv = dev->dev_private; @@ -331,48 +279,56 @@ static void psbfb_copyarea_accel(struct fb_info *info, return; } + if (!gma_power_begin(dev, false)) { + cfb_copyarea(info, a); + return; + } psb_accel_2d_copy(dev_priv, offset, stride, src_format, offset, stride, dst_format, a->sx, a->sy, a->dx, a->dy, a->width, a->height); + gma_power_end(dev); } +/** + * psbfb_copyarea - 2D copy interface + * @info: our framebuffer + * @region: region to copy + * + * Copy an area of the framebuffer console either by the accelerator + * or directly using the cfb helpers according to the request + */ void psbfb_copyarea(struct fb_info *info, const struct fb_copyarea *region) { if (unlikely(info->state != FBINFO_STATE_RUNNING)) return; - if (info->flags & FBINFO_HWACCEL_DISABLED) + /* Avoid the 8 pixel erratum */ + if (region->width == 8 || region->height == 8 || + (info->flags & FBINFO_HWACCEL_DISABLED)) return cfb_copyarea(info, region); - /* psb_check_power_state(dev, PSB_DEVICE_SGX); */ psbfb_copyarea_accel(info, region); - /* Need to power back off here for MRST FIXMEAC */ -} - -void psbfb_imageblit(struct fb_info *info, const struct fb_image *image) -{ - /* For now */ - cfb_imageblit(info, image); } +/** + * psbfb_sync - synchronize 2D + * @info: our framebuffer + * + * Wait for the 2D engine to quiesce so that we can do CPU + * access to the framebuffer again + */ int psbfb_sync(struct fb_info *info) { struct psb_fbdev *fbdev = info->par; - struct psb_framebuffer *psbfb = fbdev->pfb; + struct psb_framebuffer *psbfb = &fbdev->pfb; struct drm_device *dev = psbfb->base.dev; struct drm_psb_private *dev_priv = dev->dev_private; unsigned long _end = jiffies + DRM_HZ; int busy = 0; -#if 0 - /* Just a way to quickly test if cmd issue explodes */ - u32 test[2] = { - PSB_2D_FENCE_BH, - }; - psbfb_2d_submit(dev_priv, test, 1); -#endif + mutex_lock(&dev_priv->mutex_2d); /* * First idle the 2D engine. */ @@ -401,10 +357,56 @@ int psbfb_sync(struct fb_info *info) _PSB_C2B_STATUS_BUSY) != 0); out: + mutex_unlock(&dev_priv->mutex_2d); return (busy) ? -EBUSY : 0; } -/* - info->fix.accel = FB_ACCEL_I830; - info->flags = FBINFO_DEFAULT; -*/ +int psb_accel_ioctl(struct drm_device *dev, void *data, struct drm_file *file) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_2d_op *op = data; + u32 *op_ptr = &op->cmd[0]; + int i; + struct drm_gem_object *obj; + struct gtt_range *gtt; + int err = -EINVAL; + + if (!dev_priv->ops->accel_2d) + return -EOPNOTSUPP; + if (op->size > PSB_2D_OP_BUFLEN) + return -EINVAL; + + /* The GEM object being used. We need to support separate src/dst/etc + in the end but for now keep them all the same */ + obj = drm_gem_object_lookup(dev, file, op->src); + if (obj == NULL) + return -ENOENT; + gtt = container_of(obj, struct gtt_range, gem); + + if (psb_gtt_pin(gtt) < 0) + goto bad_2; + for (i = 0; i < op->size; i++, op_ptr++) { + u32 r = *op_ptr & 0xF0000000; + /* Fill in the GTT offsets for the command buffer */ + if (r == PSB_2D_SRC_SURF_BH || + r == PSB_2D_DST_SURF_BH || + r == PSB_2D_MASK_SURF_BH || + r == PSB_2D_PAT_SURF_BH) { + i++; + op_ptr++; + if (i == op->size) + goto bad; + if (*op_ptr) + goto bad; + *op_ptr = gtt->offset; + continue; + } + } + psbfb_2d_submit(dev_priv, op->cmd, op->size); + err = 0; +bad: + psb_gtt_unpin(gtt); +bad_2: + drm_gem_object_unreference(obj); + return err; +} diff --git a/drivers/staging/gma500/backlight.c b/drivers/staging/gma500/backlight.c new file mode 100644 index 0000000..2079395 --- /dev/null +++ b/drivers/staging/gma500/backlight.c @@ -0,0 +1,49 @@ +/* + * GMA500 Backlight Interface + * + * Copyright (c) 2009-2011, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * Authors: Eric Knopp + * + */ + +#include "psb_drv.h" +#include "psb_intel_reg.h" +#include "psb_intel_drv.h" +#include "intel_bios.h" +#include "power.h" + +int gma_backlight_init(struct drm_device *dev) +{ +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + struct drm_psb_private *dev_priv = dev->dev_private; + return dev_priv->ops->backlight_init(dev); +#else + return 0; +#endif +} + +void gma_backlight_exit(struct drm_device *dev) +{ +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + struct drm_psb_private *dev_priv = dev->dev_private; + if (dev_priv->backlight_device) { + dev_priv->backlight_device->props.brightness = 0; + backlight_update_status(dev_priv->backlight_device); + backlight_device_unregister(dev_priv->backlight_device); + } +#endif +} diff --git a/drivers/staging/gma500/cdv_device.c b/drivers/staging/gma500/cdv_device.c new file mode 100644 index 0000000..87614e0 --- /dev/null +++ b/drivers/staging/gma500/cdv_device.c @@ -0,0 +1,351 @@ +/************************************************************************** + * Copyright (c) 2011, Intel Corporation. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + **************************************************************************/ + +#include <linux/backlight.h> +#include <drm/drmP.h> +#include <drm/drm.h> +#include "psb_drm.h" +#include "psb_drv.h" +#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; + 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) + cdv_hdmi_init(dev, &dev_priv->mode_dev, SDVOB); + if (REG_READ(SDVOC) & SDVO_DETECTED) + cdv_hdmi_init(dev, &dev_priv->mode_dev, SDVOC); + return 0; +} + +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + +/* + * Poulsbo Backlight Interfaces + */ + +#define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */ +#define BLC_PWM_FREQ_CALC_CONSTANT 32 +#define MHz 1000000 + +#define PSB_BLC_PWM_PRECISION_FACTOR 10 +#define PSB_BLC_MAX_PWM_REG_FREQ 0xFFFE +#define PSB_BLC_MIN_PWM_REG_FREQ 0x2 + +#define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) +#define PSB_BACKLIGHT_PWM_CTL_SHIFT (16) + +static int cdv_brightness; +static struct backlight_device *cdv_backlight_device; + +static int cdv_get_brightness(struct backlight_device *bd) +{ + /* return locally cached var instead of HW read (due to DPST etc.) */ + /* FIXME: ideally return actual value in case firmware fiddled with + it */ + return cdv_brightness; +} + + +static int cdv_backlight_setup(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + unsigned long core_clock; + /* u32 bl_max_freq; */ + /* unsigned long value; */ + u16 bl_max_freq; + uint32_t value; + uint32_t blc_pwm_precision_factor; + + /* get bl_max_freq and pol from dev_priv*/ + if (!dev_priv->lvds_bl) { + dev_err(dev->dev, "Has no valid LVDS backlight info\n"); + return -ENOENT; + } + bl_max_freq = dev_priv->lvds_bl->freq; + blc_pwm_precision_factor = PSB_BLC_PWM_PRECISION_FACTOR; + + core_clock = dev_priv->core_freq; + + value = (core_clock * MHz) / BLC_PWM_FREQ_CALC_CONSTANT; + value *= blc_pwm_precision_factor; + value /= bl_max_freq; + value /= blc_pwm_precision_factor; + + if (value > (unsigned long long)PSB_BLC_MAX_PWM_REG_FREQ || + value < (unsigned long long)PSB_BLC_MIN_PWM_REG_FREQ) + return -ERANGE; + else { + /* FIXME */ + } + return 0; +} + +static int cdv_set_brightness(struct backlight_device *bd) +{ + int level = bd->props.brightness; + + /* Percentage 1-100% being valid */ + if (level < 1) + level = 1; + + /*cdv_intel_lvds_set_brightness(dev, level); FIXME */ + cdv_brightness = level; + return 0; +} + +static const struct backlight_ops cdv_ops = { + .get_brightness = cdv_get_brightness, + .update_status = cdv_set_brightness, +}; + +static int cdv_backlight_init(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + int ret; + struct backlight_properties props; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = 100; + props.type = BACKLIGHT_PLATFORM; + + cdv_backlight_device = backlight_device_register("psb-bl", + NULL, (void *)dev, &cdv_ops, &props); + if (IS_ERR(cdv_backlight_device)) + return PTR_ERR(cdv_backlight_device); + + ret = cdv_backlight_setup(dev); + if (ret < 0) { + backlight_device_unregister(cdv_backlight_device); + cdv_backlight_device = NULL; + return ret; + } + cdv_backlight_device->props.brightness = 100; + cdv_backlight_device->props.max_brightness = 100; + backlight_update_status(cdv_backlight_device); + dev_priv->backlight_device = cdv_backlight_device; + return 0; +} + +#endif + +/* + * 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 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); + } +} + +/** + * cdv_save_display_registers - save registers lost on suspend + * @dev: our DRM device + * + * 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) +{ + return 0; +} + +/** + * cdv_restore_display_registers - restore lost register state + * @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) +{ + return 0; +} + +static int cdv_power_down(struct drm_device *dev) +{ + return 0; +} + +static int cdv_power_up(struct drm_device *dev) +{ + return 0; +} + +/* FIXME ? - shared with Poulsbo */ +static void cdv_get_core_freq(struct drm_device *dev) +{ + uint32_t clock; + 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, 0xD0, 0xD0050300); + pci_read_config_dword(pci_root, 0xD4, &clock); + pci_dev_put(pci_root); + + switch (clock & 0x07) { + case 0: + dev_priv->core_freq = 100; + break; + case 1: + dev_priv->core_freq = 133; + break; + case 2: + dev_priv->core_freq = 150; + break; + case 3: + dev_priv->core_freq = 178; + break; + case 4: + dev_priv->core_freq = 200; + break; + case 5: + case 6: + case 7: + dev_priv->core_freq = 266; + default: + dev_priv->core_freq = 0; + } +} + +static int cdv_chip_setup(struct drm_device *dev) +{ + cdv_get_core_freq(dev); + gma_intel_opregion_init(dev); + psb_intel_init_bios(dev); + return 0; +} + +/* CDV is much like Poulsbo but has MID like SGX offsets and PM */ + +const struct psb_ops cdv_chip_ops = { + .name = "Cedartrail", + .accel_2d = 0, + .pipes = 2, + .sgx_offset = MRST_SGX_OFFSET, + .chip_setup = cdv_chip_setup, + + .crtc_helper = &cdv_intel_helper_funcs, + .crtc_funcs = &cdv_intel_crtc_funcs, + + .output_init = cdv_output_init, + +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + .backlight_init = cdv_backlight_init, +#endif + + .init_pm = cdv_init_pm, + .save_regs = cdv_save_display_registers, + .restore_regs = cdv_restore_display_registers, + .power_down = cdv_power_down, + .power_up = cdv_power_up, +}; diff --git a/drivers/staging/gma500/cdv_device.h b/drivers/staging/gma500/cdv_device.h new file mode 100644 index 0000000..2a88b7b --- /dev/null +++ b/drivers/staging/gma500/cdv_device.h @@ -0,0 +1,36 @@ +/* + * Copyright © 2011 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +extern const struct drm_crtc_helper_funcs cdv_intel_helper_funcs; +extern const struct drm_crtc_funcs cdv_intel_crtc_funcs; +extern void cdv_intel_crt_init(struct drm_device *dev, + struct psb_intel_mode_device *mode_dev); +extern void cdv_intel_lvds_init(struct drm_device *dev, + struct psb_intel_mode_device *mode_dev); +extern void cdv_hdmi_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev, + int reg); +extern struct drm_display_mode *cdv_intel_crtc_mode_get(struct drm_device *dev, + struct drm_crtc *crtc); + +extern inline void cdv_intel_wait_for_vblank(struct drm_device *dev) +{ + /* Wait for 20ms, i.e. one cycle at 50hz. */ + /* FIXME: msleep ?? */ + mdelay(20); +} + + diff --git a/drivers/staging/gma500/cdv_intel_crt.c b/drivers/staging/gma500/cdv_intel_crt.c new file mode 100644 index 0000000..efda63b --- /dev/null +++ b/drivers/staging/gma500/cdv_intel_crt.c @@ -0,0 +1,326 @@ +/* + * Copyright © 2006-2007 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: + * Eric Anholt <eric@anholt.net> + */ + +#include <linux/i2c.h> +#include <drm/drmP.h> + +#include "intel_bios.h" +#include "psb_drv.h" +#include "psb_intel_drv.h" +#include "psb_intel_reg.h" +#include "power.h" +#include <linux/pm_runtime.h> + + +static void cdv_intel_crt_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + u32 temp, reg; + reg = ADPA; + + temp = REG_READ(reg); + temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); + temp &= ~ADPA_DAC_ENABLE; + + switch (mode) { + case DRM_MODE_DPMS_ON: + temp |= ADPA_DAC_ENABLE; + break; + case DRM_MODE_DPMS_STANDBY: + temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE; + break; + case DRM_MODE_DPMS_SUSPEND: + temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE; + break; + case DRM_MODE_DPMS_OFF: + temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; + break; + } + + REG_WRITE(reg, temp); +} + +static int cdv_intel_crt_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + int max_clock = 0; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + + /* The lowest clock for CDV is 20000KHz */ + if (mode->clock < 20000) + return MODE_CLOCK_LOW; + + /* The max clock for CDV is 355 instead of 400 */ + max_clock = 355000; + if (mode->clock > max_clock) + return MODE_CLOCK_HIGH; + + if (mode->hdisplay > 1680 || mode->vdisplay > 1050) + return MODE_PANEL; + + return MODE_OK; +} + +static bool cdv_intel_crt_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void cdv_intel_crt_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + + struct drm_device *dev = encoder->dev; + struct drm_crtc *crtc = encoder->crtc; + struct psb_intel_crtc *psb_intel_crtc = + to_psb_intel_crtc(crtc); + int dpll_md_reg; + u32 adpa, dpll_md; + u32 adpa_reg; + + if (psb_intel_crtc->pipe == 0) + dpll_md_reg = DPLL_A_MD; + else + dpll_md_reg = DPLL_B_MD; + + adpa_reg = ADPA; + + /* + * Disable separate mode multiplier used when cloning SDVO to CRT + * XXX this needs to be adjusted when we really are cloning + */ + { + dpll_md = REG_READ(dpll_md_reg); + REG_WRITE(dpll_md_reg, + dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK); + } + + adpa = 0; + if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) + adpa |= ADPA_HSYNC_ACTIVE_HIGH; + if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) + adpa |= ADPA_VSYNC_ACTIVE_HIGH; + + if (psb_intel_crtc->pipe == 0) + adpa |= ADPA_PIPE_A_SELECT; + else + adpa |= ADPA_PIPE_B_SELECT; + + REG_WRITE(adpa_reg, adpa); +} + + +/** + * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence. + * + * \return true if CRT is connected. + * \return false if CRT is disconnected. + */ +static bool cdv_intel_crt_detect_hotplug(struct drm_connector *connector, + bool force) +{ + struct drm_device *dev = connector->dev; + u32 hotplug_en; + int i, tries = 0, ret = false; + u32 adpa_orig; + + /* disable the DAC when doing the hotplug detection */ + + adpa_orig = REG_READ(ADPA); + + REG_WRITE(ADPA, adpa_orig & ~(ADPA_DAC_ENABLE)); + + /* + * On a CDV thep, CRT detect sequence need to be done twice + * to get a reliable result. + */ + tries = 2; + + hotplug_en = REG_READ(PORT_HOTPLUG_EN); + hotplug_en &= ~(CRT_HOTPLUG_DETECT_MASK); + hotplug_en |= CRT_HOTPLUG_FORCE_DETECT; + + hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64; + hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; + + for (i = 0; i < tries ; i++) { + unsigned long timeout; + /* turn on the FORCE_DETECT */ + REG_WRITE(PORT_HOTPLUG_EN, hotplug_en); + timeout = jiffies + msecs_to_jiffies(1000); + /* wait for FORCE_DETECT to go off */ + do { + if (!(REG_READ(PORT_HOTPLUG_EN) & + CRT_HOTPLUG_FORCE_DETECT)) + break; + msleep(1); + } while (time_after(timeout, jiffies)); + } + + if ((REG_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) != + CRT_HOTPLUG_MONITOR_NONE) + ret = true; + + /* Restore the saved ADPA */ + REG_WRITE(ADPA, adpa_orig); + return ret; +} + +static enum drm_connector_status cdv_intel_crt_detect( + struct drm_connector *connector, bool force) +{ + if (cdv_intel_crt_detect_hotplug(connector, force)) + return connector_status_connected; + else + return connector_status_disconnected; +} + +static void cdv_intel_crt_destroy(struct drm_connector *connector) +{ + struct psb_intel_output *intel_output = to_psb_intel_output(connector); + + psb_intel_i2c_destroy(intel_output->ddc_bus); + drm_sysfs_connector_remove(connector); + drm_connector_cleanup(connector); + kfree(connector); +} + +static int cdv_intel_crt_get_modes(struct drm_connector *connector) +{ + struct psb_intel_output *intel_output = + to_psb_intel_output(connector); + return psb_intel_ddc_get_modes(intel_output); +} + +static int cdv_intel_crt_set_property(struct drm_connector *connector, + struct drm_property *property, + uint64_t value) +{ + return 0; +} + +/* + * Routines for controlling stuff on the analog port + */ + +static const struct drm_encoder_helper_funcs cdv_intel_crt_helper_funcs = { + .dpms = cdv_intel_crt_dpms, + .mode_fixup = cdv_intel_crt_mode_fixup, + .prepare = psb_intel_encoder_prepare, + .commit = psb_intel_encoder_commit, + .mode_set = cdv_intel_crt_mode_set, +}; + +static const struct drm_connector_funcs cdv_intel_crt_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .detect = cdv_intel_crt_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = cdv_intel_crt_destroy, + .set_property = cdv_intel_crt_set_property, +}; + +static const struct drm_connector_helper_funcs + cdv_intel_crt_connector_helper_funcs = { + .mode_valid = cdv_intel_crt_mode_valid, + .get_modes = cdv_intel_crt_get_modes, + .best_encoder = psb_intel_best_encoder, +}; + +static void cdv_intel_crt_enc_destroy(struct drm_encoder *encoder) +{ + drm_encoder_cleanup(encoder); +} + +static const struct drm_encoder_funcs cdv_intel_crt_enc_funcs = { + .destroy = cdv_intel_crt_enc_destroy, +}; + +void cdv_intel_crt_init(struct drm_device *dev, + struct psb_intel_mode_device *mode_dev) +{ + + struct psb_intel_output *psb_intel_output; + struct drm_connector *connector; + struct drm_encoder *encoder; + + u32 i2c_reg; + + psb_intel_output = kzalloc(sizeof(struct psb_intel_output), GFP_KERNEL); + if (!psb_intel_output) + return; + + psb_intel_output->mode_dev = mode_dev; + connector = &psb_intel_output->base; + drm_connector_init(dev, connector, + &cdv_intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); + + encoder = &psb_intel_output->enc; + drm_encoder_init(dev, encoder, + &cdv_intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC); + + drm_mode_connector_attach_encoder(&psb_intel_output->base, + &psb_intel_output->enc); + + /* Set up the DDC bus. */ + i2c_reg = GPIOA; + /* Remove the following code for CDV */ + /* + if (dev_priv->crt_ddc_bus != 0) + i2c_reg = dev_priv->crt_ddc_bus; + }*/ + psb_intel_output->ddc_bus = psb_intel_i2c_create(dev, + i2c_reg, "CRTDDC_A"); + if (!psb_intel_output->ddc_bus) { + dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " + "failed.\n"); + goto failed_ddc; + } + + psb_intel_output->type = INTEL_OUTPUT_ANALOG; + /* + psb_intel_output->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT); + psb_intel_output->crtc_mask = (1 << 0) | (1 << 1); + */ + connector->interlace_allowed = 0; + connector->doublescan_allowed = 0; + + drm_encoder_helper_add(encoder, &cdv_intel_crt_helper_funcs); + drm_connector_helper_add(connector, + &cdv_intel_crt_connector_helper_funcs); + + drm_sysfs_connector_add(connector); + + return; +failed_ddc: + drm_encoder_cleanup(&psb_intel_output->enc); + drm_connector_cleanup(&psb_intel_output->base); + kfree(psb_intel_output); + return; +} diff --git a/drivers/staging/gma500/cdv_intel_display.c b/drivers/staging/gma500/cdv_intel_display.c new file mode 100644 index 0000000..7b97c60 --- /dev/null +++ b/drivers/staging/gma500/cdv_intel_display.c @@ -0,0 +1,1508 @@ +/* + * Copyright © 2006-2011 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * Authors: + * Eric Anholt <eric@anholt.net> + */ + +#include <linux/i2c.h> +#include <linux/pm_runtime.h> + +#include <drm/drmP.h> +#include "framebuffer.h" +#include "psb_drv.h" +#include "psb_intel_drv.h" +#include "psb_intel_reg.h" +#include "psb_intel_display.h" +#include "power.h" +#include "cdv_device.h" + + +struct cdv_intel_range_t { + int min, max; +}; + +struct cdv_intel_p2_t { + int dot_limit; + int p2_slow, p2_fast; +}; + +struct cdv_intel_clock_t { + /* given values */ + int n; + int m1, m2; + int p1, p2; + /* derived values */ + int dot; + int vco; + int m; + int p; +}; + +#define INTEL_P2_NUM 2 + +struct cdv_intel_limit_t { + struct cdv_intel_range_t dot, vco, n, m, m1, m2, p, p1; + struct cdv_intel_p2_t p2; +}; + +#define CDV_LIMIT_SINGLE_LVDS_96 0 +#define CDV_LIMIT_SINGLE_LVDS_100 1 +#define CDV_LIMIT_DAC_HDMI_27 2 +#define CDV_LIMIT_DAC_HDMI_96 3 + +static const struct cdv_intel_limit_t cdv_intel_limits[] = { + { /* CDV_SIGNLE_LVDS_96MHz */ + .dot = {.min = 20000, .max = 115500}, + .vco = {.min = 1800000, .max = 3600000}, + .n = {.min = 2, .max = 6}, + .m = {.min = 60, .max = 160}, + .m1 = {.min = 0, .max = 0}, + .m2 = {.min = 58, .max = 158}, + .p = {.min = 28, .max = 140}, + .p1 = {.min = 2, .max = 10}, + .p2 = {.dot_limit = 200000, + .p2_slow = 14, .p2_fast = 14}, + }, + { /* CDV_SINGLE_LVDS_100MHz */ + .dot = {.min = 20000, .max = 115500}, + .vco = {.min = 1800000, .max = 3600000}, + .n = {.min = 2, .max = 6}, + .m = {.min = 60, .max = 160}, + .m1 = {.min = 0, .max = 0}, + .m2 = {.min = 58, .max = 158}, + .p = {.min = 28, .max = 140}, + .p1 = {.min = 2, .max = 10}, + /* The single-channel range is 25-112Mhz, and dual-channel + * is 80-224Mhz. Prefer single channel as much as possible. + */ + .p2 = {.dot_limit = 200000, .p2_slow = 14, .p2_fast = 14}, + }, + { /* CDV_DAC_HDMI_27MHz */ + .dot = {.min = 20000, .max = 400000}, + .vco = {.min = 1809000, .max = 3564000}, + .n = {.min = 1, .max = 1}, + .m = {.min = 67, .max = 132}, + .m1 = {.min = 0, .max = 0}, + .m2 = {.min = 65, .max = 130}, + .p = {.min = 5, .max = 90}, + .p1 = {.min = 1, .max = 9}, + .p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 5}, + }, + { /* CDV_DAC_HDMI_96MHz */ + .dot = {.min = 20000, .max = 400000}, + .vco = {.min = 1800000, .max = 3600000}, + .n = {.min = 2, .max = 6}, + .m = {.min = 60, .max = 160}, + .m1 = {.min = 0, .max = 0}, + .m2 = {.min = 58, .max = 158}, + .p = {.min = 5, .max = 100}, + .p1 = {.min = 1, .max = 10}, + .p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 5}, + }, +}; + +#define _wait_for(COND, MS, W) ({ \ + unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \ + int ret__ = 0; \ + while (!(COND)) { \ + if (time_after(jiffies, timeout__)) { \ + ret__ = -ETIMEDOUT; \ + break; \ + } \ + if (W && !in_dbg_master()) \ + msleep(W); \ + } \ + ret__; \ +}) + +#define wait_for(COND, MS) _wait_for(COND, MS, 1) + + +static int cdv_sb_read(struct drm_device *dev, u32 reg, u32 *val) +{ + int ret; + + ret = wait_for((REG_READ(SB_PCKT) & SB_BUSY) == 0, 1000); + if (ret) { + DRM_ERROR("timeout waiting for SB to idle before read\n"); + return ret; + } + + REG_WRITE(SB_ADDR, reg); + REG_WRITE(SB_PCKT, + SET_FIELD(SB_OPCODE_READ, SB_OPCODE) | + SET_FIELD(SB_DEST_DPLL, SB_DEST) | + SET_FIELD(0xf, SB_BYTE_ENABLE)); + + ret = wait_for((REG_READ(SB_PCKT) & SB_BUSY) == 0, 1000); + if (ret) { + DRM_ERROR("timeout waiting for SB to idle after read\n"); + return ret; + } + + *val = REG_READ(SB_DATA); + + return 0; +} + +static int cdv_sb_write(struct drm_device *dev, u32 reg, u32 val) +{ + int ret; + static bool dpio_debug = true; + u32 temp; + + if (dpio_debug) { + if (cdv_sb_read(dev, reg, &temp) == 0) + DRM_DEBUG_KMS("0x%08x: 0x%08x (before)\n", reg, temp); + DRM_DEBUG_KMS("0x%08x: 0x%08x\n", reg, val); + } + + ret = wait_for((REG_READ(SB_PCKT) & SB_BUSY) == 0, 1000); + if (ret) { + DRM_ERROR("timeout waiting for SB to idle before write\n"); + return ret; + } + + REG_WRITE(SB_ADDR, reg); + REG_WRITE(SB_DATA, val); + REG_WRITE(SB_PCKT, + SET_FIELD(SB_OPCODE_WRITE, SB_OPCODE) | + SET_FIELD(SB_DEST_DPLL, SB_DEST) | + SET_FIELD(0xf, SB_BYTE_ENABLE)); + + ret = wait_for((REG_READ(SB_PCKT) & SB_BUSY) == 0, 1000); + if (ret) { + DRM_ERROR("timeout waiting for SB to idle after write\n"); + return ret; + } + + if (dpio_debug) { + if (cdv_sb_read(dev, reg, &temp) == 0) + DRM_DEBUG_KMS("0x%08x: 0x%08x (after)\n", reg, temp); + } + + return 0; +} + +/* Reset the DPIO configuration register. The BIOS does this at every + * mode set. + */ +static void cdv_sb_reset(struct drm_device *dev) +{ + + REG_WRITE(DPIO_CFG, 0); + REG_READ(DPIO_CFG); + REG_WRITE(DPIO_CFG, DPIO_MODE_SELECT_0 | DPIO_CMN_RESET_N); +} + +/* Unlike most Intel display engines, on Cedarview the DPLL registers + * are behind this sideband bus. They must be programmed while the + * DPLL reference clock is on in the DPLL control register, but before + * the DPLL is enabled in the DPLL control register. + */ +static int +cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc, + struct cdv_intel_clock_t *clock) +{ + struct psb_intel_crtc *psb_crtc = + to_psb_intel_crtc(crtc); + int pipe = psb_crtc->pipe; + u32 m, n_vco, p; + int ret = 0; + int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; + u32 ref_value; + + cdv_sb_reset(dev); + + if ((REG_READ(dpll_reg) & DPLL_SYNCLOCK_ENABLE) == 0) { + DRM_ERROR("Attempting to set DPLL with refclk disabled\n"); + return -EBUSY; + } + + /* Follow the BIOS and write the REF/SFR Register. Hardcoded value */ + ref_value = 0x68A701; + + cdv_sb_write(dev, SB_REF_SFR(pipe), ref_value); + + /* We don't know what the other fields of these regs are, so + * leave them in place. + */ + ret = cdv_sb_read(dev, SB_M(pipe), &m); + if (ret) + return ret; + m &= ~SB_M_DIVIDER_MASK; + m |= ((clock->m2) << SB_M_DIVIDER_SHIFT); + ret = cdv_sb_write(dev, SB_M(pipe), m); + if (ret) + return ret; + + ret = cdv_sb_read(dev, SB_N_VCO(pipe), &n_vco); + if (ret) + return ret; + + /* Follow the BIOS to program the N_DIVIDER REG */ + n_vco &= 0xFFFF; + n_vco |= 0x107; + n_vco &= ~(SB_N_VCO_SEL_MASK | + SB_N_DIVIDER_MASK | + SB_N_CB_TUNE_MASK); + + n_vco |= ((clock->n) << SB_N_DIVIDER_SHIFT); + + if (clock->vco < 2250000) { + n_vco |= (2 << SB_N_CB_TUNE_SHIFT); + n_vco |= (0 << SB_N_VCO_SEL_SHIFT); + } else if (clock->vco < 2750000) { + n_vco |= (1 << SB_N_CB_TUNE_SHIFT); + n_vco |= (1 << SB_N_VCO_SEL_SHIFT); + } else if (clock->vco < 3300000) { + n_vco |= (0 << SB_N_CB_TUNE_SHIFT); + n_vco |= (2 << SB_N_VCO_SEL_SHIFT); + } else { + n_vco |= (0 << SB_N_CB_TUNE_SHIFT); + n_vco |= (3 << SB_N_VCO_SEL_SHIFT); + } + + ret = cdv_sb_write(dev, SB_N_VCO(pipe), n_vco); + if (ret) + return ret; + + ret = cdv_sb_read(dev, SB_P(pipe), &p); + if (ret) + return ret; + p &= ~(SB_P2_DIVIDER_MASK | SB_P1_DIVIDER_MASK); + p |= SET_FIELD(clock->p1, SB_P1_DIVIDER); + switch (clock->p2) { + case 5: + p |= SET_FIELD(SB_P2_5, SB_P2_DIVIDER); + break; + case 10: + p |= SET_FIELD(SB_P2_10, SB_P2_DIVIDER); + break; + case 14: + p |= SET_FIELD(SB_P2_14, SB_P2_DIVIDER); + break; + case 7: + p |= SET_FIELD(SB_P2_7, SB_P2_DIVIDER); + break; + default: + DRM_ERROR("Bad P2 clock: %d\n", clock->p2); + return -EINVAL; + } + ret = cdv_sb_write(dev, SB_P(pipe), p); + if (ret) + return ret; + + /* always Program the Lane Register for the Pipe A*/ + if (pipe == 0) { + /* Program the Lane0/1 for HDMI B */ + u32 lane_reg, lane_value; + + lane_reg = PSB_LANE0; + cdv_sb_read(dev, lane_reg, &lane_value); + lane_value &= ~(LANE_PLL_MASK); + lane_value |= LANE_PLL_ENABLE; + cdv_sb_write(dev, lane_reg, lane_value); + + lane_reg = PSB_LANE1; + cdv_sb_read(dev, lane_reg, &lane_value); + lane_value &= ~(LANE_PLL_MASK); + lane_value |= LANE_PLL_ENABLE; + cdv_sb_write(dev, lane_reg, lane_value); + + /* Program the Lane2/3 for HDMI C */ + lane_reg = PSB_LANE2; + cdv_sb_read(dev, lane_reg, &lane_value); + lane_value &= ~(LANE_PLL_MASK); + lane_value |= LANE_PLL_ENABLE; + cdv_sb_write(dev, lane_reg, lane_value); + + lane_reg = PSB_LANE3; + cdv_sb_read(dev, lane_reg, &lane_value); + lane_value &= ~(LANE_PLL_MASK); + lane_value |= LANE_PLL_ENABLE; + cdv_sb_write(dev, lane_reg, lane_value); + } + + return 0; +} + +/* + * Returns whether any output on the specified pipe is of the specified type + */ +bool cdv_intel_pipe_has_type(struct drm_crtc *crtc, int type) +{ + struct drm_device *dev = crtc->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + struct drm_connector *l_entry; + + list_for_each_entry(l_entry, &mode_config->connector_list, head) { + if (l_entry->encoder && l_entry->encoder->crtc == crtc) { + struct psb_intel_output *psb_intel_output = + to_psb_intel_output(l_entry); + if (psb_intel_output->type == type) + return true; + } + } + return false; +} + +static const struct cdv_intel_limit_t *cdv_intel_limit(struct drm_crtc *crtc, + int refclk) +{ + const struct cdv_intel_limit_t *limit; + if (cdv_intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + /* + * Now only single-channel LVDS is supported on CDV. If it is + * incorrect, please add the dual-channel LVDS. + */ + if (refclk == 96000) + limit = &cdv_intel_limits[CDV_LIMIT_SINGLE_LVDS_96]; + else + limit = &cdv_intel_limits[CDV_LIMIT_SINGLE_LVDS_100]; + } else { + if (refclk == 27000) + limit = &cdv_intel_limits[CDV_LIMIT_DAC_HDMI_27]; + else + limit = &cdv_intel_limits[CDV_LIMIT_DAC_HDMI_96]; + } + return limit; +} + +/* m1 is reserved as 0 in CDV, n is a ring counter */ +static void cdv_intel_clock(struct drm_device *dev, + int refclk, struct cdv_intel_clock_t *clock) +{ + clock->m = clock->m2 + 2; + clock->p = clock->p1 * clock->p2; + clock->vco = (refclk * clock->m) / clock->n; + clock->dot = clock->vco / clock->p; +} + + +#define INTELPllInvalid(s) { /* ErrorF (s) */; return false; } +static bool cdv_intel_PLL_is_valid(struct drm_crtc *crtc, + const struct cdv_intel_limit_t *limit, + struct cdv_intel_clock_t *clock) +{ + if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1) + INTELPllInvalid("p1 out of range\n"); + if (clock->p < limit->p.min || limit->p.max < clock->p) + INTELPllInvalid("p out of range\n"); + /* unnecessary to check the range of m(m1/M2)/n again */ + if (clock->vco < limit->vco.min || limit->vco.max < clock->vco) + INTELPllInvalid("vco out of range\n"); + /* XXX: We may need to be checking "Dot clock" + * depending on the multiplier, connector, etc., + * rather than just a single range. + */ + if (clock->dot < limit->dot.min || limit->dot.max < clock->dot) + INTELPllInvalid("dot out of range\n"); + + return true; +} + +static bool cdv_intel_find_best_PLL(struct drm_crtc *crtc, int target, + int refclk, + struct cdv_intel_clock_t *best_clock) +{ + struct drm_device *dev = crtc->dev; + struct cdv_intel_clock_t clock; + const struct cdv_intel_limit_t *limit = cdv_intel_limit(crtc, refclk); + int err = target; + + + if (cdv_intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && + (REG_READ(LVDS) & LVDS_PORT_EN) != 0) { + /* + * For LVDS, if the panel is on, just rely on its current + * settings for dual-channel. We haven't figured out how to + * reliably set up different single/dual channel state, if we + * even can. + */ + if ((REG_READ(LVDS) & LVDS_CLKB_POWER_MASK) == + LVDS_CLKB_POWER_UP) + clock.p2 = limit->p2.p2_fast; + else + clock.p2 = limit->p2.p2_slow; + } else { + if (target < limit->p2.dot_limit) + clock.p2 = limit->p2.p2_slow; + else + clock.p2 = limit->p2.p2_fast; + } + + memset(best_clock, 0, sizeof(*best_clock)); + clock.m1 = 0; + /* m1 is reserved as 0 in CDV, n is a ring counter. + So skip the m1 loop */ + for (clock.n = limit->n.min; clock.n <= limit->n.max; clock.n++) { + for (clock.m2 = limit->m2.min; clock.m2 <= limit->m2.max; + clock.m2++) { + for (clock.p1 = limit->p1.min; + clock.p1 <= limit->p1.max; + clock.p1++) { + int this_err; + + cdv_intel_clock(dev, refclk, &clock); + + if (!cdv_intel_PLL_is_valid(crtc, + limit, &clock)) + continue; + + this_err = abs(clock.dot - target); + if (this_err < err) { + *best_clock = clock; + err = this_err; + } + } + } + } + + return err != target; +} + +int cdv_intel_pipe_set_base(struct drm_crtc *crtc, + int x, int y, struct drm_framebuffer *old_fb) +{ + struct drm_device *dev = crtc->dev; + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb); + int pipe = psb_intel_crtc->pipe; + unsigned long start, offset; + int dspbase = (pipe == 0 ? DSPABASE : DSPBBASE); + int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF); + int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE; + int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; + u32 dspcntr; + int ret = 0; + + if (!gma_power_begin(dev, true)) + return 0; + + /* no fb bound */ + if (!crtc->fb) { + dev_err(dev->dev, "No FB bound\n"); + goto psb_intel_pipe_cleaner; + } + + + /* We are displaying this buffer, make sure it is actually loaded + into the GTT */ + ret = psb_gtt_pin(psbfb->gtt); + if (ret < 0) + goto psb_intel_pipe_set_base_exit; + start = psbfb->gtt->offset; + offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8); + + REG_WRITE(dspstride, crtc->fb->pitch); + + dspcntr = REG_READ(dspcntr_reg); + dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; + + switch (crtc->fb->bits_per_pixel) { + case 8: + dspcntr |= DISPPLANE_8BPP; + break; + case 16: + if (crtc->fb->depth == 15) + dspcntr |= DISPPLANE_15_16BPP; + else + dspcntr |= DISPPLANE_16BPP; + break; + case 24: + case 32: + dspcntr |= DISPPLANE_32BPP_NO_ALPHA; + break; + default: + dev_err(dev->dev, "Unknown color depth\n"); + ret = -EINVAL; + goto psb_intel_pipe_set_base_exit; + } + REG_WRITE(dspcntr_reg, dspcntr); + + dev_dbg(dev->dev, + "Writing base %08lX %08lX %d %d\n", start, offset, x, y); + + REG_WRITE(dspbase, offset); + REG_READ(dspbase); + REG_WRITE(dspsurf, start); + REG_READ(dspsurf); + +psb_intel_pipe_cleaner: + /* If there was a previous display we can now unpin it */ + if (old_fb) + psb_gtt_unpin(to_psb_fb(old_fb)->gtt); + +psb_intel_pipe_set_base_exit: + gma_power_end(dev); + return ret; +} + +/** + * 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 cdv_intel_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + struct drm_device *dev = crtc->dev; + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + int pipe = psb_intel_crtc->pipe; + int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; + int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; + int dspbase_reg = (pipe == 0) ? DSPABASE : DSPBBASE; + int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; + u32 temp; + bool enabled; + + /* 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(dpll_reg); + if ((temp & DPLL_VCO_ENABLE) == 0) { + REG_WRITE(dpll_reg, temp); + REG_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + udelay(150); + REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); + REG_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + udelay(150); + REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); + REG_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + udelay(150); + } + + /* Jim Bish - switch plan and pipe per scott */ + /* Enable the plane */ + temp = REG_READ(dspcntr_reg); + if ((temp & DISPLAY_PLANE_ENABLE) == 0) { + REG_WRITE(dspcntr_reg, + temp | DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); + } + + udelay(150); + + /* Enable the pipe */ + temp = REG_READ(pipeconf_reg); + if ((temp & PIPEACONF_ENABLE) == 0) + REG_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE); + + psb_intel_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 */ + + /* Disable the VGA plane that we never use */ + REG_WRITE(VGACNTRL, VGA_DISP_DISABLE); + + /* Jim Bish - changed pipe/plane here as well. */ + + /* Wait for vblank for the disable to take effect */ + cdv_intel_wait_for_vblank(dev); + + /* Next, disable display pipes */ + temp = REG_READ(pipeconf_reg); + if ((temp & PIPEACONF_ENABLE) != 0) { + REG_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); + REG_READ(pipeconf_reg); + } + + /* Wait for vblank for the disable to take effect. */ + cdv_intel_wait_for_vblank(dev); + + udelay(150); + + /* Disable display plane */ + temp = REG_READ(dspcntr_reg); + if ((temp & DISPLAY_PLANE_ENABLE) != 0) { + REG_WRITE(dspcntr_reg, + temp & ~DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); + REG_READ(dspbase_reg); + } + + temp = REG_READ(dpll_reg); + if ((temp & DPLL_VCO_ENABLE) != 0) { + REG_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE); + REG_READ(dpll_reg); + } + + /* Wait for the clocks to turn off. */ + udelay(150); + break; + } + enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF; + /*Set FIFO Watermarks*/ + REG_WRITE(DSPARB, 0x3F3E); +} + +static void cdv_intel_crtc_prepare(struct drm_crtc *crtc) +{ + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); +} + +static void cdv_intel_crtc_commit(struct drm_crtc *crtc) +{ + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); +} + +void cdv_intel_encoder_prepare(struct drm_encoder *encoder) +{ + struct drm_encoder_helper_funcs *encoder_funcs = + encoder->helper_private; + /* lvds has its own version of prepare see cdv_intel_lvds_prepare */ + encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF); +} + +void cdv_intel_encoder_commit(struct drm_encoder *encoder) +{ + struct drm_encoder_helper_funcs *encoder_funcs = + encoder->helper_private; + /* lvds has its own version of commit see cdv_intel_lvds_commit */ + encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); +} + +static bool cdv_intel_crtc_mode_fixup(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + + +/** + * Return the pipe currently connected to the panel fitter, + * or -1 if the panel fitter is not present or not in use + */ +static int cdv_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; + return (pfit_control >> 29) & 0x3; +} + +static int cdv_intel_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 psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + int pipe = psb_intel_crtc->pipe; + int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; + int dpll_md_reg = (psb_intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD; + int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; + int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; + int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; + int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; + int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; + int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; + int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; + int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; + int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE; + int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS; + int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC; + int refclk; + struct cdv_intel_clock_t clock; + u32 dpll = 0, dspcntr, pipeconf; + bool ok, is_sdvo = false, is_dvo = false; + bool is_crt = false, is_lvds = false, is_tv = false; + bool is_hdmi = false; + struct drm_mode_config *mode_config = &dev->mode_config; + struct drm_connector *connector; + + list_for_each_entry(connector, &mode_config->connector_list, head) { + struct psb_intel_output *psb_intel_output = + to_psb_intel_output(connector); + + if (!connector->encoder + || connector->encoder->crtc != crtc) + continue; + + switch (psb_intel_output->type) { + case INTEL_OUTPUT_LVDS: + is_lvds = true; + break; + case INTEL_OUTPUT_SDVO: + is_sdvo = true; + break; + case INTEL_OUTPUT_DVO: + is_dvo = true; + break; + case INTEL_OUTPUT_TVOUT: + is_tv = true; + break; + case INTEL_OUTPUT_ANALOG: + is_crt = true; + break; + case INTEL_OUTPUT_HDMI: + is_hdmi = true; + break; + } + } + + refclk = 96000; + + /* Hack selection about ref clk for CRT */ + /* Select 27MHz as the reference clk for HDMI */ + if (is_crt || is_hdmi) + refclk = 27000; + + drm_mode_debug_printmodeline(adjusted_mode); + + ok = cdv_intel_find_best_PLL(crtc, adjusted_mode->clock, refclk, + &clock); + if (!ok) { + dev_err(dev->dev, "Couldn't find PLL settings for mode!\n"); + return 0; + } + + dpll = DPLL_VGA_MODE_DIS; + if (is_tv) { + /* XXX: just matching BIOS for now */ +/* dpll |= PLL_REF_INPUT_TVCLKINBC; */ + dpll |= 3; + } + dpll |= PLL_REF_INPUT_DREFCLK; + + dpll |= DPLL_SYNCLOCK_ENABLE; + dpll |= DPLL_VGA_MODE_DIS; + if (is_lvds) + dpll |= DPLLB_MODE_LVDS; + else + dpll |= DPLLB_MODE_DAC_SERIAL; + /* dpll |= (2 << 11); */ + + /* setup pipeconf */ + pipeconf = REG_READ(pipeconf_reg); + + /* Set up the display plane register */ + dspcntr = DISPPLANE_GAMMA_ENABLE; + + if (pipe == 0) + dspcntr |= DISPPLANE_SEL_PIPE_A; + else + dspcntr |= DISPPLANE_SEL_PIPE_B; + + dspcntr |= DISPLAY_PLANE_ENABLE; + pipeconf |= PIPEACONF_ENABLE; + + REG_WRITE(dpll_reg, dpll | DPLL_VGA_MODE_DIS | DPLL_SYNCLOCK_ENABLE); + REG_READ(dpll_reg); + + cdv_dpll_set_clock_cdv(dev, crtc, &clock); + + udelay(150); + + + /* The LVDS pin pair needs to be on before the DPLLs are enabled. + * This is an exception to the general rule that mode_set doesn't turn + * things on. + */ + if (is_lvds) { + u32 lvds = REG_READ(LVDS); + + lvds |= + LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | + LVDS_PIPEB_SELECT; + /* Set the B0-B3 data pairs corresponding to + * whether we're going to + * set the DPLLs for dual-channel mode or not. + */ + if (clock.p2 == 7) + lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; + else + lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); + + /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) + * appropriately here, but we need to look more + * thoroughly into how panels behave in the two modes. + */ + + REG_WRITE(LVDS, lvds); + REG_READ(LVDS); + } + + dpll |= DPLL_VCO_ENABLE; + + /* Disable the panel fitter if it was on our pipe */ + if (cdv_intel_panel_fitter_pipe(dev) == pipe) + REG_WRITE(PFIT_CONTROL, 0); + + DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); + drm_mode_debug_printmodeline(mode); + + REG_WRITE(dpll_reg, + (REG_READ(dpll_reg) & ~DPLL_LOCK) | DPLL_VCO_ENABLE); + REG_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + udelay(150); /* 42 usec w/o calibration, 110 with. rounded up. */ + + if (!(REG_READ(dpll_reg) & DPLL_LOCK)) { + dev_err(dev->dev, "Failed to get DPLL lock\n"); + return -EBUSY; + } + + { + int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; + REG_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); + } + + REG_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) | + ((adjusted_mode->crtc_htotal - 1) << 16)); + REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | + ((adjusted_mode->crtc_hblank_end - 1) << 16)); + REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | + ((adjusted_mode->crtc_hsync_end - 1) << 16)); + REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | + ((adjusted_mode->crtc_vtotal - 1) << 16)); + REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | + ((adjusted_mode->crtc_vblank_end - 1) << 16)); + REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | + ((adjusted_mode->crtc_vsync_end - 1) << 16)); + /* pipesrc and dspsize control the size that is scaled from, + * which should always be the user's requested size. + */ + REG_WRITE(dspsize_reg, + ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); + REG_WRITE(dsppos_reg, 0); + REG_WRITE(pipesrc_reg, + ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); + REG_WRITE(pipeconf_reg, pipeconf); + REG_READ(pipeconf_reg); + + cdv_intel_wait_for_vblank(dev); + + REG_WRITE(dspcntr_reg, dspcntr); + + /* Flush the plane changes */ + { + struct drm_crtc_helper_funcs *crtc_funcs = + crtc->helper_private; + crtc_funcs->mode_set_base(crtc, x, y, old_fb); + } + + cdv_intel_wait_for_vblank(dev); + + return 0; +} + +/** Loads the palette/gamma unit for the CRTC with the prepared values */ +void cdv_intel_crtc_load_lut(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_psb_private *dev_priv = + (struct drm_psb_private *)dev->dev_private; + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + int palreg = PALETTE_A; + int i; + + /* The clocks have to be on to load the palette. */ + if (!crtc->enabled) + return; + + switch (psb_intel_crtc->pipe) { + case 0: + break; + case 1: + palreg = PALETTE_B; + break; + case 2: + palreg = PALETTE_C; + break; + default: + dev_err(dev->dev, "Illegal Pipe Number.\n"); + return; + } + + if (gma_power_begin(dev, false)) { + for (i = 0; i < 256; i++) { + REG_WRITE(palreg + 4 * i, + ((psb_intel_crtc->lut_r[i] + + psb_intel_crtc->lut_adj[i]) << 16) | + ((psb_intel_crtc->lut_g[i] + + psb_intel_crtc->lut_adj[i]) << 8) | + (psb_intel_crtc->lut_b[i] + + psb_intel_crtc->lut_adj[i])); + } + gma_power_end(dev); + } else { + for (i = 0; i < 256; i++) { + dev_priv->save_palette_a[i] = + ((psb_intel_crtc->lut_r[i] + + psb_intel_crtc->lut_adj[i]) << 16) | + ((psb_intel_crtc->lut_g[i] + + psb_intel_crtc->lut_adj[i]) << 8) | + (psb_intel_crtc->lut_b[i] + + psb_intel_crtc->lut_adj[i]); + } + + } +} + +/** + * Save HW states of giving crtc + */ +static void cdv_intel_crtc_save(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + /* struct drm_psb_private *dev_priv = + (struct drm_psb_private *)dev->dev_private; */ + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + struct psb_intel_crtc_state *crtc_state = psb_intel_crtc->crtc_state; + int pipeA = (psb_intel_crtc->pipe == 0); + uint32_t paletteReg; + int i; + + if (!crtc_state) { + dev_dbg(dev->dev, "No CRTC state found\n"); + return; + } + + crtc_state->saveDSPCNTR = REG_READ(pipeA ? DSPACNTR : DSPBCNTR); + crtc_state->savePIPECONF = REG_READ(pipeA ? PIPEACONF : PIPEBCONF); + crtc_state->savePIPESRC = REG_READ(pipeA ? PIPEASRC : PIPEBSRC); + crtc_state->saveFP0 = REG_READ(pipeA ? FPA0 : FPB0); + crtc_state->saveFP1 = REG_READ(pipeA ? FPA1 : FPB1); + crtc_state->saveDPLL = REG_READ(pipeA ? DPLL_A : DPLL_B); + crtc_state->saveHTOTAL = REG_READ(pipeA ? HTOTAL_A : HTOTAL_B); + crtc_state->saveHBLANK = REG_READ(pipeA ? HBLANK_A : HBLANK_B); + crtc_state->saveHSYNC = REG_READ(pipeA ? HSYNC_A : HSYNC_B); + crtc_state->saveVTOTAL = REG_READ(pipeA ? VTOTAL_A : VTOTAL_B); + crtc_state->saveVBLANK = REG_READ(pipeA ? VBLANK_A : VBLANK_B); + crtc_state->saveVSYNC = REG_READ(pipeA ? VSYNC_A : VSYNC_B); + crtc_state->saveDSPSTRIDE = REG_READ(pipeA ? DSPASTRIDE : DSPBSTRIDE); + + /*NOTE: DSPSIZE DSPPOS only for psb*/ + crtc_state->saveDSPSIZE = REG_READ(pipeA ? DSPASIZE : DSPBSIZE); + crtc_state->saveDSPPOS = REG_READ(pipeA ? DSPAPOS : DSPBPOS); + + crtc_state->saveDSPBASE = REG_READ(pipeA ? DSPABASE : DSPBBASE); + + DRM_DEBUG("(%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x)\n", + crtc_state->saveDSPCNTR, + crtc_state->savePIPECONF, + crtc_state->savePIPESRC, + crtc_state->saveFP0, + crtc_state->saveFP1, + crtc_state->saveDPLL, + crtc_state->saveHTOTAL, + crtc_state->saveHBLANK, + crtc_state->saveHSYNC, + crtc_state->saveVTOTAL, + crtc_state->saveVBLANK, + crtc_state->saveVSYNC, + crtc_state->saveDSPSTRIDE, + crtc_state->saveDSPSIZE, + crtc_state->saveDSPPOS, + crtc_state->saveDSPBASE + ); + + paletteReg = pipeA ? PALETTE_A : PALETTE_B; + for (i = 0; i < 256; ++i) + crtc_state->savePalette[i] = REG_READ(paletteReg + (i << 2)); +} + +/** + * Restore HW states of giving crtc + */ +static void cdv_intel_crtc_restore(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + /* struct drm_psb_private * dev_priv = + (struct drm_psb_private *)dev->dev_private; */ + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + struct psb_intel_crtc_state *crtc_state = psb_intel_crtc->crtc_state; + /* struct drm_crtc_helper_funcs * crtc_funcs = crtc->helper_private; */ + int pipeA = (psb_intel_crtc->pipe == 0); + uint32_t paletteReg; + int i; + + if (!crtc_state) { + dev_dbg(dev->dev, "No crtc state\n"); + return; + } + + DRM_DEBUG( + "current:(%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x)\n", + REG_READ(pipeA ? DSPACNTR : DSPBCNTR), + REG_READ(pipeA ? PIPEACONF : PIPEBCONF), + REG_READ(pipeA ? PIPEASRC : PIPEBSRC), + REG_READ(pipeA ? FPA0 : FPB0), + REG_READ(pipeA ? FPA1 : FPB1), + REG_READ(pipeA ? DPLL_A : DPLL_B), + REG_READ(pipeA ? HTOTAL_A : HTOTAL_B), + REG_READ(pipeA ? HBLANK_A : HBLANK_B), + REG_READ(pipeA ? HSYNC_A : HSYNC_B), + REG_READ(pipeA ? VTOTAL_A : VTOTAL_B), + REG_READ(pipeA ? VBLANK_A : VBLANK_B), + REG_READ(pipeA ? VSYNC_A : VSYNC_B), + REG_READ(pipeA ? DSPASTRIDE : DSPBSTRIDE), + REG_READ(pipeA ? DSPASIZE : DSPBSIZE), + REG_READ(pipeA ? DSPAPOS : DSPBPOS), + REG_READ(pipeA ? DSPABASE : DSPBBASE) + ); + + DRM_DEBUG( + "saved: (%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x)\n", + crtc_state->saveDSPCNTR, + crtc_state->savePIPECONF, + crtc_state->savePIPESRC, + crtc_state->saveFP0, + crtc_state->saveFP1, + crtc_state->saveDPLL, + crtc_state->saveHTOTAL, + crtc_state->saveHBLANK, + crtc_state->saveHSYNC, + crtc_state->saveVTOTAL, + crtc_state->saveVBLANK, + crtc_state->saveVSYNC, + crtc_state->saveDSPSTRIDE, + crtc_state->saveDSPSIZE, + crtc_state->saveDSPPOS, + crtc_state->saveDSPBASE + ); + + + if (crtc_state->saveDPLL & DPLL_VCO_ENABLE) { + REG_WRITE(pipeA ? DPLL_A : DPLL_B, + crtc_state->saveDPLL & ~DPLL_VCO_ENABLE); + REG_READ(pipeA ? DPLL_A : DPLL_B); + DRM_DEBUG("write dpll: %x\n", + REG_READ(pipeA ? DPLL_A : DPLL_B)); + udelay(150); + } + + REG_WRITE(pipeA ? FPA0 : FPB0, crtc_state->saveFP0); + REG_READ(pipeA ? FPA0 : FPB0); + + REG_WRITE(pipeA ? FPA1 : FPB1, crtc_state->saveFP1); + REG_READ(pipeA ? FPA1 : FPB1); + + REG_WRITE(pipeA ? DPLL_A : DPLL_B, crtc_state->saveDPLL); + REG_READ(pipeA ? DPLL_A : DPLL_B); + udelay(150); + + REG_WRITE(pipeA ? HTOTAL_A : HTOTAL_B, crtc_state->saveHTOTAL); + REG_WRITE(pipeA ? HBLANK_A : HBLANK_B, crtc_state->saveHBLANK); + REG_WRITE(pipeA ? HSYNC_A : HSYNC_B, crtc_state->saveHSYNC); + REG_WRITE(pipeA ? VTOTAL_A : VTOTAL_B, crtc_state->saveVTOTAL); + REG_WRITE(pipeA ? VBLANK_A : VBLANK_B, crtc_state->saveVBLANK); + REG_WRITE(pipeA ? VSYNC_A : VSYNC_B, crtc_state->saveVSYNC); + REG_WRITE(pipeA ? DSPASTRIDE : DSPBSTRIDE, crtc_state->saveDSPSTRIDE); + + REG_WRITE(pipeA ? DSPASIZE : DSPBSIZE, crtc_state->saveDSPSIZE); + REG_WRITE(pipeA ? DSPAPOS : DSPBPOS, crtc_state->saveDSPPOS); + + REG_WRITE(pipeA ? PIPEASRC : PIPEBSRC, crtc_state->savePIPESRC); + REG_WRITE(pipeA ? DSPABASE : DSPBBASE, crtc_state->saveDSPBASE); + REG_WRITE(pipeA ? PIPEACONF : PIPEBCONF, crtc_state->savePIPECONF); + + cdv_intel_wait_for_vblank(dev); + + REG_WRITE(pipeA ? DSPACNTR : DSPBCNTR, crtc_state->saveDSPCNTR); + REG_WRITE(pipeA ? DSPABASE : DSPBBASE, crtc_state->saveDSPBASE); + + cdv_intel_wait_for_vblank(dev); + + paletteReg = pipeA ? PALETTE_A : PALETTE_B; + for (i = 0; i < 256; ++i) + REG_WRITE(paletteReg + (i << 2), crtc_state->savePalette[i]); +} + +static int cdv_intel_crtc_cursor_set(struct drm_crtc *crtc, + struct drm_file *file_priv, + uint32_t handle, + uint32_t width, uint32_t height) +{ + struct drm_device *dev = crtc->dev; + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + int pipe = psb_intel_crtc->pipe; + uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR; + uint32_t base = (pipe == 0) ? CURABASE : CURBBASE; + uint32_t temp; + size_t addr = 0; + struct gtt_range *gt; + struct drm_gem_object *obj; + int ret; + + /* if we want to turn of the cursor ignore width and height */ + if (!handle) { + /* turn off the cursor */ + temp = CURSOR_MODE_DISABLE; + + if (gma_power_begin(dev, false)) { + REG_WRITE(control, temp); + REG_WRITE(base, 0); + gma_power_end(dev); + } + + /* unpin the old GEM object */ + 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 = NULL; + } + + return 0; + } + + /* Currently we only support 64x64 cursors */ + if (width != 64 || height != 64) { + dev_dbg(dev->dev, "we currently only support 64x64 cursors\n"); + return -EINVAL; + } + + obj = drm_gem_object_lookup(dev, file_priv, handle); + if (!obj) + return -ENOENT; + + if (obj->size < width * height * 4) { + dev_dbg(dev->dev, "buffer is to small\n"); + return -ENOMEM; + } + + gt = container_of(obj, struct gtt_range, gem); + + /* Pin the memory into the GTT */ + ret = psb_gtt_pin(gt); + if (ret) { + dev_err(dev->dev, "Can not pin down handle 0x%x\n", handle); + return ret; + } + + addr = gt->offset; /* Or resource.start ??? */ + + psb_intel_crtc->cursor_addr = addr; + + temp = 0; + /* set the pipe for the cursor */ + temp |= (pipe << 28); + temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; + + if (gma_power_begin(dev, false)) { + REG_WRITE(control, temp); + REG_WRITE(base, addr); + gma_power_end(dev); + } + + /* unpin the old GEM object */ + 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; +} + +static int cdv_intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) +{ + struct drm_device *dev = crtc->dev; + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + int pipe = psb_intel_crtc->pipe; + uint32_t temp = 0; + uint32_t adder; + + + if (x < 0) { + temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT); + x = -x; + } + if (y < 0) { + temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT); + y = -y; + } + + temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT); + temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); + + adder = psb_intel_crtc->cursor_addr; + + if (gma_power_begin(dev, false)) { + REG_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp); + REG_WRITE((pipe == 0) ? CURABASE : CURBBASE, adder); + gma_power_end(dev); + } + return 0; +} + +static void cdv_intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, + u16 *green, u16 *blue, uint32_t start, uint32_t size) +{ + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + int i; + int end = (start + size > 256) ? 256 : start + size; + + for (i = start; i < end; i++) { + psb_intel_crtc->lut_r[i] = red[i] >> 8; + psb_intel_crtc->lut_g[i] = green[i] >> 8; + psb_intel_crtc->lut_b[i] = blue[i] >> 8; + } + + cdv_intel_crtc_load_lut(crtc); +} + +static int cdv_crtc_set_config(struct drm_mode_set *set) +{ + int ret = 0; + struct drm_device *dev = set->crtc->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + + if (!dev_priv->rpm_enabled) + return drm_crtc_helper_set_config(set); + + pm_runtime_forbid(&dev->pdev->dev); + + ret = drm_crtc_helper_set_config(set); + + pm_runtime_allow(&dev->pdev->dev); + + return ret; +} + +/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ + +/* FIXME: why are we using this, should it be cdv_ in this tree ? */ + +static void i8xx_clock(int refclk, struct cdv_intel_clock_t *clock) +{ + clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); + clock->p = clock->p1 * clock->p2; + clock->vco = refclk * clock->m / (clock->n + 2); + clock->dot = clock->vco / clock->p; +} + +/* Returns the clock of the currently programmed mode of the given pipe. */ +static int cdv_intel_crtc_clock_get(struct drm_device *dev, + struct drm_crtc *crtc) +{ + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + int pipe = psb_intel_crtc->pipe; + u32 dpll; + u32 fp; + struct cdv_intel_clock_t clock; + bool is_lvds; + struct drm_psb_private *dev_priv = dev->dev_private; + + if (gma_power_begin(dev, false)) { + dpll = REG_READ((pipe == 0) ? DPLL_A : DPLL_B); + if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) + fp = REG_READ((pipe == 0) ? FPA0 : FPB0); + else + fp = REG_READ((pipe == 0) ? FPA1 : FPB1); + is_lvds = (pipe == 1) && (REG_READ(LVDS) & LVDS_PORT_EN); + gma_power_end(dev); + } else { + dpll = (pipe == 0) ? + dev_priv->saveDPLL_A : dev_priv->saveDPLL_B; + + if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) + fp = (pipe == 0) ? + dev_priv->saveFPA0 : + dev_priv->saveFPB0; + else + fp = (pipe == 0) ? + dev_priv->saveFPA1 : + dev_priv->saveFPB1; + + is_lvds = (pipe == 1) && (dev_priv->saveLVDS & LVDS_PORT_EN); + } + + clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; + clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; + clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT; + + if (is_lvds) { + clock.p1 = + ffs((dpll & + DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> + DPLL_FPA01_P1_POST_DIV_SHIFT); + if (clock.p1 == 0) { + clock.p1 = 4; + dev_err(dev->dev, "PLL %d\n", dpll); + } + clock.p2 = 14; + + if ((dpll & PLL_REF_INPUT_MASK) == + PLLB_REF_INPUT_SPREADSPECTRUMIN) { + /* XXX: might not be 66MHz */ + i8xx_clock(66000, &clock); + } else + i8xx_clock(48000, &clock); + } else { + if (dpll & PLL_P1_DIVIDE_BY_TWO) + clock.p1 = 2; + else { + clock.p1 = + ((dpll & + DPLL_FPA01_P1_POST_DIV_MASK_I830) >> + DPLL_FPA01_P1_POST_DIV_SHIFT) + 2; + } + if (dpll & PLL_P2_DIVIDE_BY_4) + clock.p2 = 4; + else + clock.p2 = 2; + + i8xx_clock(48000, &clock); + } + + /* XXX: It would be nice to validate the clocks, but we can't reuse + * i830PllIsValid() because it relies on the xf86_config connector + * configuration being accurate, which it isn't necessarily. + */ + + return clock.dot; +} + +/** Returns the currently programmed mode of the given pipe. */ +struct drm_display_mode *cdv_intel_crtc_mode_get(struct drm_device *dev, + struct drm_crtc *crtc) +{ + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + int pipe = psb_intel_crtc->pipe; + struct drm_display_mode *mode; + int htot; + int hsync; + int vtot; + int vsync; + struct drm_psb_private *dev_priv = dev->dev_private; + + if (gma_power_begin(dev, false)) { + htot = REG_READ((pipe == 0) ? HTOTAL_A : HTOTAL_B); + hsync = REG_READ((pipe == 0) ? HSYNC_A : HSYNC_B); + vtot = REG_READ((pipe == 0) ? VTOTAL_A : VTOTAL_B); + vsync = REG_READ((pipe == 0) ? VSYNC_A : VSYNC_B); + gma_power_end(dev); + } else { + htot = (pipe == 0) ? + dev_priv->saveHTOTAL_A : dev_priv->saveHTOTAL_B; + hsync = (pipe == 0) ? + dev_priv->saveHSYNC_A : dev_priv->saveHSYNC_B; + vtot = (pipe == 0) ? + dev_priv->saveVTOTAL_A : dev_priv->saveVTOTAL_B; + vsync = (pipe == 0) ? + dev_priv->saveVSYNC_A : dev_priv->saveVSYNC_B; + } + + mode = kzalloc(sizeof(*mode), GFP_KERNEL); + if (!mode) + return NULL; + + mode->clock = cdv_intel_crtc_clock_get(dev, crtc); + mode->hdisplay = (htot & 0xffff) + 1; + mode->htotal = ((htot & 0xffff0000) >> 16) + 1; + mode->hsync_start = (hsync & 0xffff) + 1; + mode->hsync_end = ((hsync & 0xffff0000) >> 16) + 1; + mode->vdisplay = (vtot & 0xffff) + 1; + mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1; + mode->vsync_start = (vsync & 0xffff) + 1; + mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1; + + drm_mode_set_name(mode); + drm_mode_set_crtcinfo(mode, 0); + + return mode; +} + +static void cdv_intel_crtc_destroy(struct drm_crtc *crtc) +{ + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + + kfree(psb_intel_crtc->crtc_state); + drm_crtc_cleanup(crtc); + kfree(psb_intel_crtc); +} + +const struct drm_crtc_helper_funcs cdv_intel_helper_funcs = { + .dpms = cdv_intel_crtc_dpms, + .mode_fixup = cdv_intel_crtc_mode_fixup, + .mode_set = cdv_intel_crtc_mode_set, + .mode_set_base = cdv_intel_pipe_set_base, + .prepare = cdv_intel_crtc_prepare, + .commit = cdv_intel_crtc_commit, +}; + +const struct drm_crtc_funcs cdv_intel_crtc_funcs = { + .save = cdv_intel_crtc_save, + .restore = cdv_intel_crtc_restore, + .cursor_set = cdv_intel_crtc_cursor_set, + .cursor_move = cdv_intel_crtc_cursor_move, + .gamma_set = cdv_intel_crtc_gamma_set, + .set_config = cdv_crtc_set_config, + .destroy = cdv_intel_crtc_destroy, +}; + +/* + * Set the default value of cursor control and base register + * to zero. This is a workaround for h/w defect on oaktrail + */ +void cdv_intel_cursor_init(struct drm_device *dev, int pipe) +{ + uint32_t control; + uint32_t base; + + switch (pipe) { + case 0: + control = CURACNTR; + base = CURABASE; + break; + case 1: + control = CURBCNTR; + base = CURBBASE; + break; + case 2: + control = CURCCNTR; + base = CURCBASE; + break; + default: + return; + } + + REG_WRITE(control, 0); + REG_WRITE(base, 0); +} + diff --git a/drivers/staging/gma500/cdv_intel_hdmi.c b/drivers/staging/gma500/cdv_intel_hdmi.c new file mode 100644 index 0000000..cbca2b0 --- /dev/null +++ b/drivers/staging/gma500/cdv_intel_hdmi.c @@ -0,0 +1,376 @@ +/* + * Copyright © 2006-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. + * + * Authors: + * jim liu <jim.liu@intel.com> + * + * FIXME: + * We should probably make this generic and share it with Medfield + */ + +#include <drm/drmP.h> +#include <drm/drm.h> +#include <drm/drm_crtc.h> +#include <drm/drm_edid.h> +#include "psb_intel_drv.h" +#include "psb_drv.h" +#include "psb_intel_reg.h" +#include <linux/pm_runtime.h> + +/* hdmi control bits */ +#define HDMI_NULL_PACKETS_DURING_VSYNC (1 << 9) +#define HDMI_BORDER_ENABLE (1 << 7) +#define HDMI_AUDIO_ENABLE (1 << 6) +#define HDMI_VSYNC_ACTIVE_HIGH (1 << 4) +#define HDMI_HSYNC_ACTIVE_HIGH (1 << 3) +/* hdmi-b control bits */ +#define HDMIB_PIPE_B_SELECT (1 << 30) + + +struct mid_intel_hdmi_priv { + u32 hdmi_reg; + u32 save_HDMIB; + bool has_hdmi_sink; + 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; +}; + +static void cdv_hdmi_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct psb_intel_output *output = enc_to_psb_intel_output(encoder); + struct mid_intel_hdmi_priv *hdmi_priv = output->dev_priv; + u32 hdmib; + struct drm_crtc *crtc = encoder->crtc; + struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc); + + hdmib = (2 << 10); + + if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) + hdmib |= HDMI_VSYNC_ACTIVE_HIGH; + if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) + hdmib |= HDMI_HSYNC_ACTIVE_HIGH; + + if (intel_crtc->pipe == 1) + hdmib |= HDMIB_PIPE_B_SELECT; + + if (hdmi_priv->has_hdmi_audio) { + hdmib |= HDMI_AUDIO_ENABLE; + hdmib |= HDMI_NULL_PACKETS_DURING_VSYNC; + } + + REG_WRITE(hdmi_priv->hdmi_reg, hdmib); + REG_READ(hdmi_priv->hdmi_reg); +} + +static bool cdv_hdmi_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void cdv_hdmi_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct psb_intel_output *output = enc_to_psb_intel_output(encoder); + struct mid_intel_hdmi_priv *hdmi_priv = output->dev_priv; + u32 hdmib; + + hdmib = REG_READ(hdmi_priv->hdmi_reg); + + if (mode != DRM_MODE_DPMS_ON) + REG_WRITE(hdmi_priv->hdmi_reg, hdmib & ~HDMIB_PORT_EN); + else + REG_WRITE(hdmi_priv->hdmi_reg, hdmib | HDMIB_PORT_EN); + REG_READ(hdmi_priv->hdmi_reg); +} + +static void cdv_hdmi_save(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct psb_intel_output *output = to_psb_intel_output(connector); + struct mid_intel_hdmi_priv *hdmi_priv = output->dev_priv; + + hdmi_priv->save_HDMIB = REG_READ(hdmi_priv->hdmi_reg); +} + +static void cdv_hdmi_restore(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct psb_intel_output *output = to_psb_intel_output(connector); + struct mid_intel_hdmi_priv *hdmi_priv = output->dev_priv; + + REG_WRITE(hdmi_priv->hdmi_reg, hdmi_priv->save_HDMIB); + REG_READ(hdmi_priv->hdmi_reg); +} + +static enum drm_connector_status cdv_hdmi_detect( + struct drm_connector *connector, bool force) +{ + struct psb_intel_output *psb_intel_output = + to_psb_intel_output(connector); + struct mid_intel_hdmi_priv *hdmi_priv = psb_intel_output->dev_priv; + struct edid *edid = NULL; + enum drm_connector_status status = connector_status_disconnected; + + edid = drm_get_edid(&psb_intel_output->base, + psb_intel_output->hdmi_i2c_adapter); + + hdmi_priv->has_hdmi_sink = false; + hdmi_priv->has_hdmi_audio = false; + if (edid) { + if (edid->input & DRM_EDID_INPUT_DIGITAL) { + status = connector_status_connected; + hdmi_priv->has_hdmi_sink = + drm_detect_hdmi_monitor(edid); + hdmi_priv->has_hdmi_audio = + drm_detect_monitor_audio(edid); + } + + psb_intel_output->base.display_info.raw_edid = NULL; + kfree(edid); + } + return status; +} + +static int cdv_hdmi_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 psb_intel_crtc *crtc = to_psb_intel_crtc(encoder->crtc); + bool centre; + uint64_t curValue; + + if (!crtc) + return -1; + + switch (value) { + case DRM_MODE_SCALE_FULLSCREEN: + break; + case DRM_MODE_SCALE_NO_SCALE: + break; + case DRM_MODE_SCALE_ASPECT: + break; + default: + return -1; + } + + if (drm_connector_property_get_value(connector, + property, &curValue)) + return -1; + + if (curValue == value) + return 0; + + if (drm_connector_property_set_value(connector, + property, value)) + return -1; + + centre = (curValue == DRM_MODE_SCALE_NO_SCALE) || + (value == DRM_MODE_SCALE_NO_SCALE); + + if (crtc->saved_mode.hdisplay != 0 && + crtc->saved_mode.vdisplay != 0) { + if (centre) { + if (!drm_crtc_helper_set_mode(encoder->crtc, &crtc->saved_mode, + encoder->crtc->x, encoder->crtc->y, encoder->crtc->fb)) + return -1; + } else { + struct drm_encoder_helper_funcs *helpers + = encoder->helper_private; + helpers->mode_set(encoder, &crtc->saved_mode, + &crtc->saved_adjusted_mode); + } + } + } + return 0; +} + +/* + * Return the list of HDMI DDC modes if available. + */ +static int cdv_hdmi_get_modes(struct drm_connector *connector) +{ + struct psb_intel_output *psb_intel_output = + to_psb_intel_output(connector); + struct edid *edid = NULL; + int ret = 0; + + edid = drm_get_edid(&psb_intel_output->base, + psb_intel_output->hdmi_i2c_adapter); + if (edid) { + drm_mode_connector_update_edid_property(&psb_intel_output-> + base, edid); + ret = drm_add_edid_modes(&psb_intel_output->base, edid); + kfree(edid); + } + return ret; +} + +static int cdv_hdmi_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + + if (mode->clock > 165000) + return MODE_CLOCK_HIGH; + if (mode->clock < 20000) + return MODE_CLOCK_HIGH; + + /* just in case */ + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + + /* just in case */ + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + return MODE_NO_INTERLACE; + + /* + * FIXME: for now we limit the size to 1680x1050 on CDV, otherwise it + * will go beyond the stolen memory size allocated to the framebuffer + */ + if (mode->hdisplay > 1680) + return MODE_PANEL; + if (mode->vdisplay > 1050) + return MODE_PANEL; + return MODE_OK; +} + +static void cdv_hdmi_destroy(struct drm_connector *connector) +{ + struct psb_intel_output *psb_intel_output = + to_psb_intel_output(connector); + + if (psb_intel_output->ddc_bus) + psb_intel_i2c_destroy(psb_intel_output->ddc_bus); + drm_sysfs_connector_remove(connector); + drm_connector_cleanup(connector); + kfree(connector); +} + +static const struct drm_encoder_helper_funcs cdv_hdmi_helper_funcs = { + .dpms = cdv_hdmi_dpms, + .mode_fixup = cdv_hdmi_mode_fixup, + .prepare = psb_intel_encoder_prepare, + .mode_set = cdv_hdmi_mode_set, + .commit = psb_intel_encoder_commit, +}; + +static const struct drm_connector_helper_funcs + cdv_hdmi_connector_helper_funcs = { + .get_modes = cdv_hdmi_get_modes, + .mode_valid = cdv_hdmi_mode_valid, + .best_encoder = psb_intel_best_encoder, +}; + +static const struct drm_connector_funcs cdv_hdmi_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .save = cdv_hdmi_save, + .restore = cdv_hdmi_restore, + .detect = cdv_hdmi_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .set_property = cdv_hdmi_set_property, + .destroy = cdv_hdmi_destroy, +}; + +void cdv_hdmi_init(struct drm_device *dev, + struct psb_intel_mode_device *mode_dev, int reg) +{ + struct psb_intel_output *psb_intel_output; + struct drm_connector *connector; + struct drm_encoder *encoder; + struct mid_intel_hdmi_priv *hdmi_priv; + int ddc_bus; + + psb_intel_output = kzalloc(sizeof(struct psb_intel_output) + + sizeof(struct mid_intel_hdmi_priv), GFP_KERNEL); + if (!psb_intel_output) + return; + + hdmi_priv = (struct mid_intel_hdmi_priv *)(psb_intel_output + 1); + psb_intel_output->mode_dev = mode_dev; + connector = &psb_intel_output->base; + encoder = &psb_intel_output->enc; + drm_connector_init(dev, &psb_intel_output->base, + &cdv_hdmi_connector_funcs, + DRM_MODE_CONNECTOR_DVID); + + drm_encoder_init(dev, &psb_intel_output->enc, &psb_intel_lvds_enc_funcs, + DRM_MODE_ENCODER_TMDS); + + drm_mode_connector_attach_encoder(&psb_intel_output->base, + &psb_intel_output->enc); + psb_intel_output->type = INTEL_OUTPUT_HDMI; + hdmi_priv->hdmi_reg = reg; + hdmi_priv->has_hdmi_sink = false; + psb_intel_output->dev_priv = hdmi_priv; + + drm_encoder_helper_add(encoder, &cdv_hdmi_helper_funcs); + drm_connector_helper_add(connector, + &cdv_hdmi_connector_helper_funcs); + connector->display_info.subpixel_order = SubPixelHorizontalRGB; + connector->interlace_allowed = false; + connector->doublescan_allowed = false; + + drm_connector_attach_property(connector, + dev->mode_config.scaling_mode_property, DRM_MODE_SCALE_FULLSCREEN); + + switch (reg) { + case SDVOB: + ddc_bus = GPIOE; + break; + case SDVOC: + ddc_bus = GPIOD; + break; + default: + DRM_ERROR("unknown reg 0x%x for HDMI\n", reg); + goto failed_ddc; + break; + } + + psb_intel_output->ddc_bus = psb_intel_i2c_create(dev, + ddc_bus, (reg == SDVOB) ? "HDMIB" : "HDMIC"); + + if (!psb_intel_output->ddc_bus) { + dev_err(dev->dev, "No ddc adapter available!\n"); + goto failed_ddc; + } + psb_intel_output->hdmi_i2c_adapter = + &(psb_intel_output->ddc_bus->adapter); + hdmi_priv->dev = dev; + drm_sysfs_connector_add(connector); + return; + +failed_ddc: + drm_encoder_cleanup(&psb_intel_output->enc); + drm_connector_cleanup(&psb_intel_output->base); + kfree(psb_intel_output); +} diff --git a/drivers/staging/gma500/cdv_intel_lvds.c b/drivers/staging/gma500/cdv_intel_lvds.c new file mode 100644 index 0000000..988b2d0 --- /dev/null +++ b/drivers/staging/gma500/cdv_intel_lvds.c @@ -0,0 +1,721 @@ +/* + * Copyright © 2006-2011 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * Authors: + * Eric Anholt <eric@anholt.net> + * Dave Airlie <airlied@linux.ie> + * Jesse Barnes <jesse.barnes@intel.com> + */ + +#include <linux/i2c.h> +#include <linux/dmi.h> +#include <drm/drmP.h> + +#include "intel_bios.h" +#include "psb_drv.h" +#include "psb_intel_drv.h" +#include "psb_intel_reg.h" +#include "power.h" +#include <linux/pm_runtime.h> +#include "cdv_device.h" + +/** + * LVDS I2C backlight control macros + */ +#define BRIGHTNESS_MAX_LEVEL 100 +#define BRIGHTNESS_MASK 0xFF +#define BLC_I2C_TYPE 0x01 +#define BLC_PWM_TYPT 0x02 + +#define BLC_POLARITY_NORMAL 0 +#define BLC_POLARITY_INVERSE 1 + +#define PSB_BLC_MAX_PWM_REG_FREQ (0xFFFE) +#define PSB_BLC_MIN_PWM_REG_FREQ (0x2) +#define PSB_BLC_PWM_PRECISION_FACTOR (10) +#define PSB_BACKLIGHT_PWM_CTL_SHIFT (16) +#define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) + +struct cdv_intel_lvds_priv { + /** + * Saved LVDO output states + */ + uint32_t savePP_ON; + uint32_t savePP_OFF; + uint32_t saveLVDS; + uint32_t savePP_CONTROL; + uint32_t savePP_CYCLE; + uint32_t savePFIT_CONTROL; + uint32_t savePFIT_PGM_RATIOS; + uint32_t saveBLC_PWM_CTL; +}; + +/* + * Returns the maximum level of the backlight duty cycle field. + */ +static u32 cdv_intel_lvds_get_max_backlight(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + u32 retval; + + if (gma_power_begin(dev, false)) { + retval = ((REG_READ(BLC_PWM_CTL) & + BACKLIGHT_MODULATION_FREQ_MASK) >> + BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; + + gma_power_end(dev); + } else + retval = ((dev_priv->saveBLC_PWM_CTL & + BACKLIGHT_MODULATION_FREQ_MASK) >> + BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; + + return retval; +} + +/* + * Set LVDS backlight level by I2C command + */ +static int cdv_lvds_i2c_set_brightness(struct drm_device *dev, + unsigned int level) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct psb_intel_i2c_chan *lvds_i2c_bus = dev_priv->lvds_i2c_bus; + u8 out_buf[2]; + unsigned int blc_i2c_brightness; + + struct i2c_msg msgs[] = { + { + .addr = lvds_i2c_bus->slave_addr, + .flags = 0, + .len = 2, + .buf = out_buf, + } + }; + + blc_i2c_brightness = BRIGHTNESS_MASK & ((unsigned int)level * + BRIGHTNESS_MASK / + BRIGHTNESS_MAX_LEVEL); + + if (dev_priv->lvds_bl->pol == BLC_POLARITY_INVERSE) + blc_i2c_brightness = BRIGHTNESS_MASK - blc_i2c_brightness; + + out_buf[0] = dev_priv->lvds_bl->brightnesscmd; + out_buf[1] = (u8)blc_i2c_brightness; + + if (i2c_transfer(&lvds_i2c_bus->adapter, msgs, 1) == 1) + return 0; + + DRM_ERROR("I2C transfer error\n"); + return -1; +} + + +static int cdv_lvds_pwm_set_brightness(struct drm_device *dev, int level) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + + u32 max_pwm_blc; + u32 blc_pwm_duty_cycle; + + max_pwm_blc = cdv_intel_lvds_get_max_backlight(dev); + + /*BLC_PWM_CTL Should be initiated while backlight device init*/ + BUG_ON((max_pwm_blc & PSB_BLC_MAX_PWM_REG_FREQ) == 0); + + blc_pwm_duty_cycle = level * max_pwm_blc / BRIGHTNESS_MAX_LEVEL; + + if (dev_priv->lvds_bl->pol == BLC_POLARITY_INVERSE) + blc_pwm_duty_cycle = max_pwm_blc - blc_pwm_duty_cycle; + + blc_pwm_duty_cycle &= PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR; + REG_WRITE(BLC_PWM_CTL, + (max_pwm_blc << PSB_BACKLIGHT_PWM_CTL_SHIFT) | + (blc_pwm_duty_cycle)); + + return 0; +} + +/* + * Set LVDS backlight level either by I2C or PWM + */ +void cdv_intel_lvds_set_brightness(struct drm_device *dev, int level) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + + if (!dev_priv->lvds_bl) { + DRM_ERROR("NO LVDS Backlight Info\n"); + return; + } + + if (dev_priv->lvds_bl->type == BLC_I2C_TYPE) + cdv_lvds_i2c_set_brightness(dev, level); + else + cdv_lvds_pwm_set_brightness(dev, level); +} + +/** + * Sets the backlight level. + * + * level backlight level, from 0 to cdv_intel_lvds_get_max_backlight(). + */ +static void cdv_intel_lvds_set_backlight(struct drm_device *dev, int level) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + u32 blc_pwm_ctl; + + if (gma_power_begin(dev, false)) { + blc_pwm_ctl = + REG_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; + REG_WRITE(BLC_PWM_CTL, + (blc_pwm_ctl | + (level << BACKLIGHT_DUTY_CYCLE_SHIFT))); + gma_power_end(dev); + } else { + blc_pwm_ctl = dev_priv->saveBLC_PWM_CTL & + ~BACKLIGHT_DUTY_CYCLE_MASK; + dev_priv->saveBLC_PWM_CTL = (blc_pwm_ctl | + (level << BACKLIGHT_DUTY_CYCLE_SHIFT)); + } +} + +/** + * Sets the power state for the panel. + */ +static void cdv_intel_lvds_set_power(struct drm_device *dev, + struct psb_intel_output *output, bool on) +{ + u32 pp_status; + + if (!gma_power_begin(dev, true)) + return; + + if (on) { + REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) | + POWER_TARGET_ON); + do { + pp_status = REG_READ(PP_STATUS); + } while ((pp_status & PP_ON) == 0); + + cdv_intel_lvds_set_backlight(dev, + output-> + mode_dev->backlight_duty_cycle); + } else { + cdv_intel_lvds_set_backlight(dev, 0); + + REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) & + ~POWER_TARGET_ON); + do { + pp_status = REG_READ(PP_STATUS); + } while (pp_status & PP_ON); + } + gma_power_end(dev); +} + +static void cdv_intel_lvds_encoder_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct psb_intel_output *output = enc_to_psb_intel_output(encoder); + if (mode == DRM_MODE_DPMS_ON) + cdv_intel_lvds_set_power(dev, output, true); + else + cdv_intel_lvds_set_power(dev, output, false); + /* XXX: We never power down the LVDS pairs. */ +} + +static void cdv_intel_lvds_save(struct drm_connector *connector) +{ +} + +static void cdv_intel_lvds_restore(struct drm_connector *connector) +{ +} + +int cdv_intel_lvds_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct psb_intel_output *psb_intel_output = + to_psb_intel_output(connector); + struct drm_display_mode *fixed_mode = + psb_intel_output->mode_dev->panel_fixed_mode; + + /* just in case */ + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + + /* just in case */ + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + return MODE_NO_INTERLACE; + + if (fixed_mode) { + if (mode->hdisplay > fixed_mode->hdisplay) + return MODE_PANEL; + if (mode->vdisplay > fixed_mode->vdisplay) + return MODE_PANEL; + } + return MODE_OK; +} + +bool cdv_intel_lvds_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct psb_intel_mode_device *mode_dev = + enc_to_psb_intel_output(encoder)->mode_dev; + struct drm_device *dev = encoder->dev; + struct drm_encoder *tmp_encoder; + struct drm_display_mode *panel_fixed_mode = mode_dev->panel_fixed_mode; + + /* Should never happen!! */ + list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list, + head) { + if (tmp_encoder != encoder + && tmp_encoder->crtc == encoder->crtc) { + printk(KERN_ERR "Can't enable LVDS and another " + "encoder on the same pipe\n"); + return false; + } + } + + /* + * If we have timings from the BIOS for the panel, put them in + * to the adjusted mode. The CRTC will be set up for this mode, + * with the panel scaling set up to source from the H/VDisplay + * of the original mode. + */ + if (panel_fixed_mode != NULL) { + adjusted_mode->hdisplay = panel_fixed_mode->hdisplay; + adjusted_mode->hsync_start = panel_fixed_mode->hsync_start; + adjusted_mode->hsync_end = panel_fixed_mode->hsync_end; + adjusted_mode->htotal = panel_fixed_mode->htotal; + adjusted_mode->vdisplay = panel_fixed_mode->vdisplay; + adjusted_mode->vsync_start = panel_fixed_mode->vsync_start; + adjusted_mode->vsync_end = panel_fixed_mode->vsync_end; + adjusted_mode->vtotal = panel_fixed_mode->vtotal; + adjusted_mode->clock = panel_fixed_mode->clock; + drm_mode_set_crtcinfo(adjusted_mode, + CRTC_INTERLACE_HALVE_V); + } + + /* + * XXX: It would be nice to support lower refresh rates on the + * panels to reduce power consumption, and perhaps match the + * user's requested refresh rate. + */ + + return true; +} + +static void cdv_intel_lvds_prepare(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct psb_intel_output *output = enc_to_psb_intel_output(encoder); + struct psb_intel_mode_device *mode_dev = output->mode_dev; + + if (!gma_power_begin(dev, true)) + return; + + mode_dev->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL); + mode_dev->backlight_duty_cycle = (mode_dev->saveBLC_PWM_CTL & + BACKLIGHT_DUTY_CYCLE_MASK); + + cdv_intel_lvds_set_power(dev, output, false); + + gma_power_end(dev); +} + +static void cdv_intel_lvds_commit(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct psb_intel_output *output = enc_to_psb_intel_output(encoder); + struct psb_intel_mode_device *mode_dev = output->mode_dev; + + if (mode_dev->backlight_duty_cycle == 0) + mode_dev->backlight_duty_cycle = + cdv_intel_lvds_get_max_backlight(dev); + + cdv_intel_lvds_set_power(dev, output, true); +} + +static void cdv_intel_lvds_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + u32 pfit_control; + + /* + * The LVDS pin pair will already have been turned on in the + * cdv_intel_crtc_mode_set since it has a large impact on the DPLL + * settings. + */ + + /* + * Enable automatic panel scaling so that non-native modes fill the + * screen. Should be enabled before the pipe is enabled, according to + * register description and PRM. + */ + if (mode->hdisplay != adjusted_mode->hdisplay || + mode->vdisplay != adjusted_mode->vdisplay) + pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE | + HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR | + HORIZ_INTERP_BILINEAR); + else + pfit_control = 0; + + if (dev_priv->lvds_dither) + pfit_control |= PANEL_8TO6_DITHER_ENABLE; + + REG_WRITE(PFIT_CONTROL, pfit_control); +} + +/** + * Detect the LVDS connection. + * + * This always returns CONNECTOR_STATUS_CONNECTED. + * This connector should only have + * been set up if the LVDS was actually connected anyway. + */ +static enum drm_connector_status cdv_intel_lvds_detect( + struct drm_connector *connector, bool force) +{ + return connector_status_connected; +} + +/** + * Return the list of DDC modes if available, or the BIOS fixed mode otherwise. + */ +static int cdv_intel_lvds_get_modes(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct psb_intel_output *psb_intel_output = + to_psb_intel_output(connector); + struct psb_intel_mode_device *mode_dev = + psb_intel_output->mode_dev; + int ret; + + ret = psb_intel_ddc_get_modes(psb_intel_output); + + if (ret) + return ret; + + /* Didn't get an EDID, so + * Set wide sync ranges so we get all modes + * handed to valid_mode for checking + */ + connector->display_info.min_vfreq = 0; + connector->display_info.max_vfreq = 200; + connector->display_info.min_hfreq = 0; + connector->display_info.max_hfreq = 200; + if (mode_dev->panel_fixed_mode != NULL) { + struct drm_display_mode *mode = + drm_mode_duplicate(dev, mode_dev->panel_fixed_mode); + drm_mode_probed_add(connector, mode); + return 1; + } + + return 0; +} + +/** + * cdv_intel_lvds_destroy - unregister and free LVDS structures + * @connector: connector to free + * + * Unregister the DDC bus for this connector then free the driver private + * structure. + */ +void cdv_intel_lvds_destroy(struct drm_connector *connector) +{ + struct psb_intel_output *psb_intel_output = + to_psb_intel_output(connector); + + if (psb_intel_output->ddc_bus) + psb_intel_i2c_destroy(psb_intel_output->ddc_bus); + drm_sysfs_connector_remove(connector); + drm_connector_cleanup(connector); + kfree(connector); +} + +int cdv_intel_lvds_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 psb_intel_crtc *crtc = + to_psb_intel_crtc(encoder->crtc); + uint64_t curValue; + + if (!crtc) + return -1; + + switch (value) { + case DRM_MODE_SCALE_FULLSCREEN: + break; + case DRM_MODE_SCALE_NO_SCALE: + break; + case DRM_MODE_SCALE_ASPECT: + break; + default: + return -1; + } + + if (drm_connector_property_get_value(connector, + property, + &curValue)) + return -1; + + if (curValue == value) + return 0; + + if (drm_connector_property_set_value(connector, + property, + value)) + return -1; + + if (crtc->saved_mode.hdisplay != 0 && + crtc->saved_mode.vdisplay != 0) { + if (!drm_crtc_helper_set_mode(encoder->crtc, + &crtc->saved_mode, + encoder->crtc->x, + encoder->crtc->y, + encoder->crtc->fb)) + return -1; + } + } else if (!strcmp(property->name, "backlight") && encoder) { + if (drm_connector_property_set_value(connector, + property, + value)) + return -1; + else { +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + struct drm_psb_private *dev_priv = + encoder->dev->dev_private; + struct backlight_device *bd = + dev_priv->backlight_device; + bd->props.brightness = value; + backlight_update_status(bd); +#endif + } + } else if (!strcmp(property->name, "DPMS") && encoder) { + struct drm_encoder_helper_funcs *helpers = + encoder->helper_private; + helpers->dpms(encoder, value); + } + return 0; +} + +static const struct drm_encoder_helper_funcs + cdv_intel_lvds_helper_funcs = { + .dpms = cdv_intel_lvds_encoder_dpms, + .mode_fixup = cdv_intel_lvds_mode_fixup, + .prepare = cdv_intel_lvds_prepare, + .mode_set = cdv_intel_lvds_mode_set, + .commit = cdv_intel_lvds_commit, +}; + +static const struct drm_connector_helper_funcs + cdv_intel_lvds_connector_helper_funcs = { + .get_modes = cdv_intel_lvds_get_modes, + .mode_valid = cdv_intel_lvds_mode_valid, + .best_encoder = psb_intel_best_encoder, +}; + +static const struct drm_connector_funcs cdv_intel_lvds_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .save = cdv_intel_lvds_save, + .restore = cdv_intel_lvds_restore, + .detect = cdv_intel_lvds_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .set_property = cdv_intel_lvds_set_property, + .destroy = cdv_intel_lvds_destroy, +}; + + +static void cdv_intel_lvds_enc_destroy(struct drm_encoder *encoder) +{ + drm_encoder_cleanup(encoder); +} + +const struct drm_encoder_funcs cdv_intel_lvds_enc_funcs = { + .destroy = cdv_intel_lvds_enc_destroy, +}; + +/** + * cdv_intel_lvds_init - setup LVDS connectors on this device + * @dev: drm device + * + * Create the connector, register the LVDS DDC bus, and try to figure out what + * modes we can display on the LVDS panel (if present). + */ +void cdv_intel_lvds_init(struct drm_device *dev, + struct psb_intel_mode_device *mode_dev) +{ + struct psb_intel_output *psb_intel_output; + struct cdv_intel_lvds_priv *lvds_priv; + struct drm_connector *connector; + struct drm_encoder *encoder; + struct drm_display_mode *scan; + struct drm_crtc *crtc; + struct drm_psb_private *dev_priv = dev->dev_private; + u32 lvds; + int pipe; + + psb_intel_output = kzalloc(sizeof(struct psb_intel_output) + + sizeof(struct cdv_intel_lvds_priv), GFP_KERNEL); + if (!psb_intel_output) + return; + + lvds_priv = (struct cdv_intel_lvds_priv *)(psb_intel_output + 1); + + psb_intel_output->dev_priv = lvds_priv; + + psb_intel_output->mode_dev = mode_dev; + connector = &psb_intel_output->base; + encoder = &psb_intel_output->enc; + + + drm_connector_init(dev, &psb_intel_output->base, + &cdv_intel_lvds_connector_funcs, + DRM_MODE_CONNECTOR_LVDS); + + drm_encoder_init(dev, &psb_intel_output->enc, + &cdv_intel_lvds_enc_funcs, + DRM_MODE_ENCODER_LVDS); + + + drm_mode_connector_attach_encoder(&psb_intel_output->base, + &psb_intel_output->enc); + psb_intel_output->type = INTEL_OUTPUT_LVDS; + + drm_encoder_helper_add(encoder, &cdv_intel_lvds_helper_funcs); + drm_connector_helper_add(connector, + &cdv_intel_lvds_connector_helper_funcs); + connector->display_info.subpixel_order = SubPixelHorizontalRGB; + connector->interlace_allowed = false; + connector->doublescan_allowed = false; + + /*Attach connector properties*/ + drm_connector_attach_property(connector, + dev->mode_config.scaling_mode_property, + DRM_MODE_SCALE_FULLSCREEN); + drm_connector_attach_property(connector, + dev_priv->backlight_property, + BRIGHTNESS_MAX_LEVEL); + + /** + * Set up I2C bus + * FIXME: distroy i2c_bus when exit + */ + psb_intel_output->i2c_bus = psb_intel_i2c_create(dev, + GPIOB, + "LVDSBLC_B"); + if (!psb_intel_output->i2c_bus) { + dev_printk(KERN_ERR, + &dev->pdev->dev, "I2C bus registration failed.\n"); + goto failed_blc_i2c; + } + psb_intel_output->i2c_bus->slave_addr = 0x2C; + dev_priv->lvds_i2c_bus = psb_intel_output->i2c_bus; + + /* + * LVDS discovery: + * 1) check for EDID on DDC + * 2) check for VBT data + * 3) check to see if LVDS is already on + * if none of the above, no panel + * 4) make sure lid is open + * if closed, act like it's not there for now + */ + + /* Set up the DDC bus. */ + psb_intel_output->ddc_bus = psb_intel_i2c_create(dev, + GPIOC, + "LVDSDDC_C"); + if (!psb_intel_output->ddc_bus) { + dev_printk(KERN_ERR, &dev->pdev->dev, + "DDC bus registration " "failed.\n"); + goto failed_ddc; + } + + /* + * Attempt to get the fixed panel mode from DDC. Assume that the + * preferred mode is the right one. + */ + psb_intel_ddc_get_modes(psb_intel_output); + list_for_each_entry(scan, &connector->probed_modes, head) { + if (scan->type & DRM_MODE_TYPE_PREFERRED) { + mode_dev->panel_fixed_mode = + drm_mode_duplicate(dev, scan); + goto out; /* FIXME: check for quirks */ + } + } + + /* Failed to get EDID, what about VBT? do we need this?*/ + if (dev_priv->lfp_lvds_vbt_mode) { + mode_dev->panel_fixed_mode = + drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); + if (mode_dev->panel_fixed_mode) { + mode_dev->panel_fixed_mode->type |= + DRM_MODE_TYPE_PREFERRED; + goto out; /* FIXME: check for quirks */ + } + } + /* + * If we didn't get EDID, try checking if the panel is already turned + * on. If so, assume that whatever is currently programmed is the + * correct mode. + */ + lvds = REG_READ(LVDS); + pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; + crtc = psb_intel_get_crtc_from_pipe(dev, pipe); + + if (crtc && (lvds & LVDS_PORT_EN)) { + mode_dev->panel_fixed_mode = + cdv_intel_crtc_mode_get(dev, crtc); + if (mode_dev->panel_fixed_mode) { + mode_dev->panel_fixed_mode->type |= + DRM_MODE_TYPE_PREFERRED; + goto out; /* FIXME: check for quirks */ + } + } + + /* If we still don't have a mode after all that, give up. */ + if (!mode_dev->panel_fixed_mode) { + DRM_DEBUG + ("Found no modes on the lvds, ignoring the LVDS\n"); + goto failed_find; + } + +out: + drm_sysfs_connector_add(connector); + return; + +failed_find: + printk(KERN_ERR "Failed find\n"); + if (psb_intel_output->ddc_bus) + psb_intel_i2c_destroy(psb_intel_output->ddc_bus); +failed_ddc: + printk(KERN_ERR "Failed DDC\n"); + if (psb_intel_output->i2c_bus) + psb_intel_i2c_destroy(psb_intel_output->i2c_bus); +failed_blc_i2c: + printk(KERN_ERR "Failed BLC\n"); + drm_encoder_cleanup(encoder); + drm_connector_cleanup(connector); + kfree(connector); +} diff --git a/drivers/staging/gma500/displays/hdmi.h b/drivers/staging/gma500/displays/hdmi.h new file mode 100644 index 0000000..d58ba9b --- /dev/null +++ b/drivers/staging/gma500/displays/hdmi.h @@ -0,0 +1,33 @@ +/* + * 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, 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: + * Thomas Eaton <thomas.g.eaton@intel.com> + * Scott Rowe <scott.m.rowe@intel.com> + */ + +#ifndef HDMI_H +#define HDMI_H + +extern void hdmi_init(struct drm_device *dev); + +#endif diff --git a/drivers/staging/gma500/displays/pyr_cmd.h b/drivers/staging/gma500/displays/pyr_cmd.h new file mode 100644 index 0000000..84bae5c --- /dev/null +++ b/drivers/staging/gma500/displays/pyr_cmd.h @@ -0,0 +1,34 @@ +/* + * 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 PYR_CMD_H +#define PYR_CMD_H + +extern void pyr_cmd_init(struct drm_device *dev, struct panel_funcs *p_funcs); + +#endif + diff --git a/drivers/staging/gma500/displays/pyr_vid.h b/drivers/staging/gma500/displays/pyr_vid.h new file mode 100644 index 0000000..ce98860 --- /dev/null +++ b/drivers/staging/gma500/displays/pyr_vid.h @@ -0,0 +1,34 @@ +/* + * 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 PYR_VID_H +#define PYR_VID_H + +extern void pyr_vid_init(struct drm_device *dev, struct panel_funcs *p_funcs); +extern struct drm_display_mode *pyr_vid_get_config_mode(struct drm_device* dev); + +#endif diff --git a/drivers/staging/gma500/displays/tmd_cmd.h b/drivers/staging/gma500/displays/tmd_cmd.h new file mode 100644 index 0000000..641e85e --- /dev/null +++ b/drivers/staging/gma500/displays/tmd_cmd.h @@ -0,0 +1,34 @@ +/* + * 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 TMD_CMD_H +#define TMD_CMD_H + +extern void tmd_cmd_init(struct drm_device *dev, struct panel_funcs *p_funcs); +extern struct drm_display_mode *tmd_cmd_get_config_mode(struct drm_device *dev); + +#endif diff --git a/drivers/staging/gma500/displays/tmd_vid.h b/drivers/staging/gma500/displays/tmd_vid.h new file mode 100644 index 0000000..7a5fa3b --- /dev/null +++ b/drivers/staging/gma500/displays/tmd_vid.h @@ -0,0 +1,34 @@ +/* + * 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 TMD_VID_H +#define TMD_VID_H + +extern void tmd_vid_init(struct drm_device *dev, struct panel_funcs *p_funcs); +extern struct drm_display_mode *tmd_vid_get_config_mode(struct drm_device *dev); + +#endif diff --git a/drivers/staging/gma500/displays/tpo_cmd.h b/drivers/staging/gma500/displays/tpo_cmd.h new file mode 100644 index 0000000..6105527 --- /dev/null +++ b/drivers/staging/gma500/displays/tpo_cmd.h @@ -0,0 +1,35 @@ +/* + * 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 TPO_CMD_H +#define TPO_CMD_H + +extern void tpo_cmd_init(struct drm_device *dev, struct panel_funcs *p_funcs); +/* extern struct drm_display_mode * */ +/* tpo_cmd_get_config_mode(struct drm_device *dev); */ + +#endif diff --git a/drivers/staging/gma500/displays/tpo_vid.h b/drivers/staging/gma500/displays/tpo_vid.h new file mode 100644 index 0000000..c24f057 --- /dev/null +++ b/drivers/staging/gma500/displays/tpo_vid.h @@ -0,0 +1,33 @@ +/* + * 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 TPO_VID_H +#define TPO_VID_H + +extern void tpo_vid_init(struct drm_device *dev, struct panel_funcs *p_funcs); + +#endif diff --git a/drivers/staging/gma500/psb_fb.c b/drivers/staging/gma500/framebuffer.c index 084c36b..ebfde13 100644 --- a/drivers/staging/gma500/psb_fb.c +++ b/drivers/staging/gma500/framebuffer.c @@ -1,5 +1,5 @@ /************************************************************************** - * Copyright (c) 2007, Intel Corporation. + * Copyright (c) 2007-2011, Intel Corporation. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it @@ -36,7 +36,9 @@ #include "psb_drv.h" #include "psb_intel_reg.h" #include "psb_intel_drv.h" -#include "psb_fb.h" +#include "framebuffer.h" + +#include "mdfld_output.h" static void psb_user_framebuffer_destroy(struct drm_framebuffer *fb); static int psb_user_framebuffer_create_handle(struct drm_framebuffer *fb, @@ -50,14 +52,6 @@ static const struct drm_framebuffer_funcs psb_fb_funcs = { #define CMAP_TOHW(_val, _width) ((((_val) << (_width)) + 0x7FFF - (_val)) >> 16) -void *psbfb_vdc_reg(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv; - dev_priv = (struct drm_psb_private *) dev->dev_private; - return dev_priv->vdc_reg; -} -/*EXPORT_SYMBOL(psbfb_vdc_reg); */ - static int psbfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) @@ -97,109 +91,60 @@ static int psbfb_setcolreg(unsigned regno, unsigned red, unsigned green, return 0; } -static int psbfb_kms_off(struct drm_device *dev, int suspend) + +void psbfb_suspend(struct drm_device *dev) { struct drm_framebuffer *fb = 0; struct psb_framebuffer *psbfb = to_psb_fb(fb); - DRM_DEBUG("psbfb_kms_off_ioctl\n"); + console_lock(); mutex_lock(&dev->mode_config.mutex); list_for_each_entry(fb, &dev->mode_config.fb_list, head) { struct fb_info *info = psbfb->fbdev; - - if (suspend) { - fb_set_suspend(info, 1); - drm_fb_helper_blank(FB_BLANK_POWERDOWN, info); - } + fb_set_suspend(info, 1); + drm_fb_helper_blank(FB_BLANK_POWERDOWN, info); } mutex_unlock(&dev->mode_config.mutex); - return 0; -} - -int psbfb_kms_off_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - int ret; - - if (drm_psb_no_fb) - return 0; - console_lock(); - ret = psbfb_kms_off(dev, 0); console_unlock(); - - return ret; } -static int psbfb_kms_on(struct drm_device *dev, int resume) +void psbfb_resume(struct drm_device *dev) { struct drm_framebuffer *fb = 0; struct psb_framebuffer *psbfb = to_psb_fb(fb); - DRM_DEBUG("psbfb_kms_on_ioctl\n"); - + console_lock(); mutex_lock(&dev->mode_config.mutex); list_for_each_entry(fb, &dev->mode_config.fb_list, head) { struct fb_info *info = psbfb->fbdev; - - if (resume) { - fb_set_suspend(info, 0); - drm_fb_helper_blank(FB_BLANK_UNBLANK, info); - } + fb_set_suspend(info, 0); + drm_fb_helper_blank(FB_BLANK_UNBLANK, info); } mutex_unlock(&dev->mode_config.mutex); - - return 0; -} - -int psbfb_kms_on_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - int ret; - - if (drm_psb_no_fb) - return 0; - console_lock(); - ret = psbfb_kms_on(dev, 0); - console_unlock(); - drm_helper_disable_unused_functions(dev); - return ret; -} - -void psbfb_suspend(struct drm_device *dev) -{ - console_lock(); - psbfb_kms_off(dev, 1); - console_unlock(); -} - -void psbfb_resume(struct drm_device *dev) -{ - console_lock(); - psbfb_kms_on(dev, 1); console_unlock(); drm_helper_disable_unused_functions(dev); } static int psbfb_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { - int page_num = 0; - int i; - unsigned long address = 0; - int ret; - unsigned long pfn; struct psb_framebuffer *psbfb = vma->vm_private_data; struct drm_device *dev = psbfb->base.dev; struct drm_psb_private *dev_priv = dev->dev_private; + int page_num; + int i; + unsigned long address; + int ret; + unsigned long pfn; + /* FIXME: assumes fb at stolen base which may not be true */ unsigned long phys_addr = (unsigned long)dev_priv->stolen_base; page_num = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; - address = (unsigned long)vmf->virtual_address; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); for (i = 0; i < page_num; i++) { - pfn = (phys_addr >> PAGE_SHIFT); /* phys_to_pfn(phys_addr); */ + pfn = (phys_addr >> PAGE_SHIFT); ret = vm_insert_mixed(vma, address, pfn); if (unlikely((ret == -EBUSY) || (ret != 0 && i > 0))) @@ -208,22 +153,18 @@ static int psbfb_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ret = (ret == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS; return ret; } - address += PAGE_SIZE; phys_addr += PAGE_SIZE; } - return VM_FAULT_NOPAGE; } static void psbfb_vm_open(struct vm_area_struct *vma) { - DRM_DEBUG("vm_open\n"); } static void psbfb_vm_close(struct vm_area_struct *vma) { - DRM_DEBUG("vm_close\n"); } static struct vm_operations_struct psbfb_vm_ops = { @@ -235,10 +176,7 @@ static struct vm_operations_struct psbfb_vm_ops = { static int psbfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct psb_fbdev *fbdev = info->par; - struct psb_framebuffer *psbfb = fbdev->pfb; - char *fb_screen_base = NULL; - struct drm_device *dev = psbfb->base.dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct psb_framebuffer *psbfb = &fbdev->pfb; if (vma->vm_pgoff != 0) return -EINVAL; @@ -247,51 +185,22 @@ static int psbfb_mmap(struct fb_info *info, struct vm_area_struct *vma) if (!psbfb->addr_space) psbfb->addr_space = vma->vm_file->f_mapping; - - fb_screen_base = (char *)info->screen_base; - - DRM_DEBUG("vm_pgoff 0x%lx, screen base %p vram_addr %p\n", - vma->vm_pgoff, fb_screen_base, - dev_priv->vram_addr); - - /* FIXME: ultimately this needs to become 'if entirely stolen memory' */ - if (1 || fb_screen_base == dev_priv->vram_addr) { - vma->vm_ops = &psbfb_vm_ops; - vma->vm_private_data = (void *)psbfb; - vma->vm_flags |= VM_RESERVED | VM_IO | - VM_MIXEDMAP | VM_DONTEXPAND; - } else { - /* GTT memory backed by kernel/user pages, needs a different - approach ? - GEM ? */ - } - + /* + * If this is a GEM object then info->screen_base is the virtual + * kernel remapping of the object. FIXME: Review if this is + * suitable for our mmap work + */ + vma->vm_ops = &psbfb_vm_ops; + vma->vm_private_data = (void *)psbfb; + vma->vm_flags |= VM_RESERVED | VM_IO | + VM_MIXEDMAP | VM_DONTEXPAND; return 0; } -static int psbfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +static int psbfb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) { - struct psb_fbdev *fbdev = info->par; - struct psb_framebuffer *psbfb = fbdev->pfb; - struct drm_device *dev = psbfb->base.dev; - struct drm_psb_private *dev_priv = dev->dev_private; - u32 __user *p = (u32 __user *)arg; - u32 l; - u32 buf[32]; - switch (cmd) { - case 0x12345678: - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - if (get_user(l, p)) - return -EFAULT; - if (l > 32) - return -EMSGSIZE; - if (copy_from_user(buf, p + 1, l * sizeof(u32))) - return -EFAULT; - psbfb_2d_submit(dev_priv, buf, l); - return 0; - default: - return -ENOTTY; - } + return -ENOTTY; } static struct fb_ops psbfb_ops = { @@ -300,16 +209,80 @@ static struct fb_ops psbfb_ops = { .fb_set_par = drm_fb_helper_set_par, .fb_blank = drm_fb_helper_blank, .fb_setcolreg = psbfb_setcolreg, - .fb_fillrect = psbfb_fillrect, + .fb_fillrect = cfb_fillrect, .fb_copyarea = psbfb_copyarea, - .fb_imageblit = psbfb_imageblit, + .fb_imageblit = cfb_imageblit, .fb_mmap = psbfb_mmap, .fb_sync = psbfb_sync, .fb_ioctl = psbfb_ioctl, }; +static struct fb_ops psbfb_unaccel_ops = { + .owner = THIS_MODULE, + .fb_check_var = drm_fb_helper_check_var, + .fb_set_par = drm_fb_helper_set_par, + .fb_blank = drm_fb_helper_blank, + .fb_setcolreg = psbfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_mmap = psbfb_mmap, + .fb_ioctl = psbfb_ioctl, +}; + +/** + * psb_framebuffer_init - initialize a framebuffer + * @dev: our DRM device + * @fb: framebuffer to set up + * @mode_cmd: mode description + * @gt: backing object + * + * Configure and fill in the boilerplate for our frame buffer. Return + * 0 on success or an error code if we fail. + */ +static int psb_framebuffer_init(struct drm_device *dev, + struct psb_framebuffer *fb, + struct drm_mode_fb_cmd *mode_cmd, + struct gtt_range *gt) +{ + int ret; + + if (mode_cmd->pitch & 63) + return -EINVAL; + switch (mode_cmd->bpp) { + case 8: + case 16: + case 24: + case 32: + break; + default: + return -EINVAL; + } + ret = drm_framebuffer_init(dev, &fb->base, &psb_fb_funcs); + if (ret) { + dev_err(dev->dev, "framebuffer init failed: %d\n", ret); + return ret; + } + drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd); + fb->gtt = gt; + return 0; +} + +/** + * psb_framebuffer_create - create a framebuffer backed by gt + * @dev: our DRM device + * @mode_cmd: the description of the requested mode + * @gt: the backing object + * + * Create a framebuffer object backed by the gt, and fill in the + * boilerplate required + * + * TODO: review object references + */ + static struct drm_framebuffer *psb_framebuffer_create - (struct drm_device *dev, struct drm_mode_fb_cmd *r, + (struct drm_device *dev, + struct drm_mode_fb_cmd *mode_cmd, struct gtt_range *gt) { struct psb_framebuffer *fb; @@ -317,22 +290,14 @@ static struct drm_framebuffer *psb_framebuffer_create fb = kzalloc(sizeof(*fb), GFP_KERNEL); if (!fb) - return NULL; - - ret = drm_framebuffer_init(dev, &fb->base, &psb_fb_funcs); - - if (ret) - goto err; - - drm_helper_mode_fill_fb_struct(&fb->base, r); - - fb->gtt = gt; + return ERR_PTR(-ENOMEM); + ret = psb_framebuffer_init(dev, fb, mode_cmd, gt); + if (ret) { + kfree(fb); + return ERR_PTR(ret); + } return &fb->base; - -err: - kfree(fb); - return NULL; } /** @@ -345,15 +310,22 @@ err: * stolen memory or the system has no stolen memory we allocate a range * and back it with a GEM object. * - * In this case the GEM object has no handle. + * In this case the GEM object has no handle. + * + * FIXME: console speed up - allocate twice the space if room and use + * hardware scrolling for acceleration. */ static struct gtt_range *psbfb_alloc(struct drm_device *dev, int aligned_size) { struct gtt_range *backing; /* Begin by trying to use stolen memory backing */ backing = psb_gtt_alloc_range(dev, aligned_size, "fb", 1); - if (backing) - return backing; + if (backing) { + if (drm_gem_private_object_init(dev, + &backing->gem, aligned_size) == 0) + return backing; + psb_gtt_free_range(dev, backing); + } /* Next try using GEM host memory */ backing = psb_gtt_alloc_range(dev, aligned_size, "fb(gem)", 0); if (backing == NULL) @@ -366,7 +338,7 @@ static struct gtt_range *psbfb_alloc(struct drm_device *dev, int aligned_size) } return backing; } - + /** * psbfb_create - create a framebuffer * @fbdev: the framebuffer device @@ -381,74 +353,96 @@ static int psbfb_create(struct psb_fbdev *fbdev, struct drm_psb_private *dev_priv = dev->dev_private; struct fb_info *info; struct drm_framebuffer *fb; - struct psb_framebuffer *psbfb; + struct psb_framebuffer *psbfb = &fbdev->pfb; struct drm_mode_fb_cmd mode_cmd; struct device *device = &dev->pdev->dev; - int size, aligned_size; + int size; int ret; struct gtt_range *backing; mode_cmd.width = sizes->surface_width; mode_cmd.height = sizes->surface_height; + mode_cmd.bpp = sizes->surface_bpp; + + /* No 24bit packed */ + if (mode_cmd.bpp == 24) + mode_cmd.bpp = 32; - mode_cmd.bpp = 32; /* HW requires pitch to be 64 byte aligned */ - mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 1) / 8), 64); - mode_cmd.depth = 24; + mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 7) / 8), 64); + mode_cmd.depth = sizes->surface_depth; size = mode_cmd.pitch * mode_cmd.height; - aligned_size = ALIGN(size, PAGE_SIZE); + size = ALIGN(size, PAGE_SIZE); /* Allocate the framebuffer in the GTT with stolen page backing */ - backing = psbfb_alloc(dev, aligned_size); + backing = psbfb_alloc(dev, size); if (backing == NULL) - return -ENOMEM; + return -ENOMEM; mutex_lock(&dev->struct_mutex); - fb = psb_framebuffer_create(dev, &mode_cmd, backing); - if (!fb) { - DRM_ERROR("failed to allocate fb.\n"); - ret = -ENOMEM; - goto out_err1; - } - psbfb = to_psb_fb(fb); - info = framebuffer_alloc(sizeof(struct psb_fbdev), device); + info = framebuffer_alloc(0, device); if (!info) { ret = -ENOMEM; - goto out_err0; + goto out_err1; } - info->par = fbdev; + ret = psb_framebuffer_init(dev, psbfb, &mode_cmd, backing); + if (ret) + goto out_unref; + + fb = &psbfb->base; psbfb->fbdev = info; fbdev->psb_fb_helper.fb = fb; fbdev->psb_fb_helper.fbdev = info; - fbdev->pfb = psbfb; strcpy(info->fix.id, "psbfb"); info->flags = FBINFO_DEFAULT; - info->fbops = &psbfb_ops; + /* No 2D engine */ + if (!dev_priv->ops->accel_2d) + info->fbops = &psbfb_unaccel_ops; + else + info->fbops = &psbfb_ops; + + ret = fb_alloc_cmap(&info->cmap, 256, 0); + if (ret) { + ret = -ENOMEM; + goto out_unref; + } + info->fix.smem_start = dev->mode_config.fb_base; info->fix.smem_len = size; - /* Accessed via stolen memory directly, This only works for stolem - memory however. Need to address this once we start using gtt - pages we allocate */ - info->screen_base = (char *)dev_priv->vram_addr + backing->offset; + if (backing->stolen) { + /* Accessed stolen memory directly */ + info->screen_base = (char *)dev_priv->vram_addr + + backing->offset; + } else { + /* Pin the pages into the GTT and create a mapping to them */ + psb_gtt_pin(backing); + info->screen_base = vm_map_ram(backing->pages, backing->npage, + -1, PAGE_KERNEL); + if (info->screen_base == NULL) { + psb_gtt_unpin(backing); + ret = -ENOMEM; + goto out_unref; + } + psbfb->vm_map = 1; + } info->screen_size = size; - memset(info->screen_base, 0, size); - if (dev_priv->pg->stolen_size) { + if (dev_priv->gtt.stolen_size) { info->apertures = alloc_apertures(1); if (!info->apertures) { ret = -ENOMEM; - goto out_err0; + goto out_unref; } info->apertures->ranges[0].base = dev->mode_config.fb_base; - info->apertures->ranges[0].size = dev_priv->pg->stolen_size; + info->apertures->ranges[0].size = dev_priv->gtt.stolen_size; } drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); @@ -464,17 +458,19 @@ static int psbfb_create(struct psb_fbdev *fbdev, info->pixmap.flags = FB_PIXMAP_SYSTEM; info->pixmap.scan_align = 1; - DRM_DEBUG("fb depth is %d\n", fb->depth); - DRM_DEBUG(" pitch is %d\n", fb->pitch); - - printk(KERN_INFO"allocated %dx%d fb\n", - psbfb->base.width, psbfb->base.height); + dev_info(dev->dev, "allocated %dx%d fb\n", + psbfb->base.width, psbfb->base.height); mutex_unlock(&dev->struct_mutex); - return 0; -out_err0: - fb->funcs->destroy(fb); +out_unref: + if (backing->stolen) + psb_gtt_free_range(dev, backing); + else { + if (psbfb->vm_map) + vm_unmap_ram(info->screen_base, backing->npage); + drm_gem_object_unreference(&backing->gem); + } out_err1: mutex_unlock(&dev->struct_mutex); psb_gtt_free_range(dev, backing); @@ -493,45 +489,30 @@ static struct drm_framebuffer *psb_user_framebuffer_create (struct drm_device *dev, struct drm_file *filp, struct drm_mode_fb_cmd *cmd) { - struct gtt_range *r; - struct drm_gem_object *obj; - struct psb_framebuffer *psbfb; + struct gtt_range *r; + struct drm_gem_object *obj; - /* Find the GEM object and thus the gtt range object that is - to back this space */ + /* + * Find the GEM object and thus the gtt range object that is + * to back this space + */ obj = drm_gem_object_lookup(dev, filp, cmd->handle); if (obj == NULL) - return ERR_PTR(-ENOENT); - - /* Allocate a framebuffer */ - psbfb = kzalloc(sizeof(*psbfb), GFP_KERNEL); - if (psbfb == NULL) { - drm_gem_object_unreference_unlocked(obj); - return ERR_PTR(-ENOMEM); - } - - /* Let the core code do all the work */ - r = container_of(obj, struct gtt_range, gem); - if (psb_framebuffer_create(dev, cmd, r) == NULL) { - drm_gem_object_unreference_unlocked(obj); - kfree(psbfb); - return ERR_PTR(-EINVAL); - } - /* Return the drm_framebuffer contained within the psb fbdev which - has been initialized by the framebuffer creation */ - return &psbfb->base; + return ERR_PTR(-ENOENT); + + /* Let the core code do all the work */ + r = container_of(obj, struct gtt_range, gem); + return psb_framebuffer_create(dev, cmd, r); } static void psbfb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno) { - DRM_DEBUG("%s\n", __func__); } static void psbfb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, int regno) { - DRM_DEBUG("%s\n", __func__); } static int psbfb_probe(struct drm_fb_helper *helper, @@ -541,8 +522,6 @@ static int psbfb_probe(struct drm_fb_helper *helper, int new_fb = 0; int ret; - DRM_DEBUG("%s\n", __func__); - if (!helper->fb) { ret = psbfb_create(psb_fbdev, sizes); if (ret) @@ -561,24 +540,27 @@ struct drm_fb_helper_funcs psb_fb_helper_funcs = { int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev) { struct fb_info *info; - struct psb_framebuffer *psbfb = fbdev->pfb; + struct psb_framebuffer *psbfb = &fbdev->pfb; if (fbdev->psb_fb_helper.fbdev) { info = fbdev->psb_fb_helper.fbdev; - /* FIXME: this is a bit more inside knowledge than I'd like - but I don't see how to make a fake GEM object of the - stolen space nicely */ - if (psbfb->gtt->stolen) - psb_gtt_free_range(dev, psbfb->gtt); - else - drm_gem_object_unreference(&psbfb->gtt->gem); + + /* If this is our base framebuffer then kill any virtual map + for the framebuffer layer and unpin it */ + if (psbfb->vm_map) { + vm_unmap_ram(info->screen_base, psbfb->gtt->npage); + psb_gtt_unpin(psbfb->gtt); + } unregister_framebuffer(info); - iounmap(info->screen_base); + if (info->cmap.len) + fb_dealloc_cmap(&info->cmap); framebuffer_release(info); } - drm_fb_helper_fini(&fbdev->psb_fb_helper); drm_framebuffer_cleanup(&psbfb->base); + + if (psbfb->gtt) + drm_gem_object_unreference(&psbfb->gtt->gem); return 0; } @@ -586,20 +568,17 @@ int psb_fbdev_init(struct drm_device *dev) { struct psb_fbdev *fbdev; struct drm_psb_private *dev_priv = dev->dev_private; - int num_crtc; fbdev = kzalloc(sizeof(struct psb_fbdev), GFP_KERNEL); if (!fbdev) { - DRM_ERROR("no memory\n"); + dev_err(dev->dev, "no memory\n"); return -ENOMEM; } dev_priv->fbdev = fbdev; fbdev->psb_fb_helper.funcs = &psb_fb_helper_funcs; - num_crtc = 2; - - drm_fb_helper_init(dev, &fbdev->psb_fb_helper, num_crtc, + drm_fb_helper_init(dev, &fbdev->psb_fb_helper, dev_priv->ops->crtcs, INTELFB_CONN_LIMIT); drm_fb_helper_single_add_all_connectors(&fbdev->psb_fb_helper); @@ -626,22 +605,6 @@ static void psbfb_output_poll_changed(struct drm_device *dev) drm_fb_helper_hotplug_event(&fbdev->psb_fb_helper); } -int psbfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) -{ - struct fb_info *info; - struct psb_framebuffer *psbfb = to_psb_fb(fb); - - if (drm_psb_no_fb) - return 0; - - info = psbfb->fbdev; - - if (info) - framebuffer_release(info); - return 0; -} -/*EXPORT_SYMBOL(psbfb_remove); */ - /** * psb_user_framebuffer_create_handle - add hamdle to a framebuffer * @fb: framebuffer @@ -656,11 +619,9 @@ static int psb_user_framebuffer_create_handle(struct drm_framebuffer *fb, struct drm_file *file_priv, unsigned int *handle) { - struct psb_framebuffer *psbfb = to_psb_fb(fb); - struct gtt_range *r = psbfb->gtt; - if (r->stolen) - return -EOPNOTSUPP; - return drm_gem_handle_create(file_priv, &r->gem, handle); + struct psb_framebuffer *psbfb = to_psb_fb(fb); + struct gtt_range *r = psbfb->gtt; + return drm_gem_handle_create(file_priv, &r->gem, handle); } /** @@ -672,18 +633,37 @@ static int psb_user_framebuffer_create_handle(struct drm_framebuffer *fb, */ static void psb_user_framebuffer_destroy(struct drm_framebuffer *fb) { - struct drm_device *dev = fb->dev; struct psb_framebuffer *psbfb = to_psb_fb(fb); struct gtt_range *r = psbfb->gtt; - - if (psbfb->fbdev) - psbfb_remove(dev, fb); - - /* Let DRM do its clean up */ + struct drm_device *dev = fb->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + struct psb_fbdev *fbdev = dev_priv->fbdev; + struct drm_crtc *crtc; + int reset = 0; + + /* Should never get stolen memory for a user fb */ + WARN_ON(r->stolen); + + /* Check if we are erroneously live */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + if (crtc->fb == fb) + reset = 1; + + if (reset) + /* + * Now force a sane response before we permit the DRM CRTC + * layer to do stupid things like blank the display. Instead + * we reset this framebuffer as if the user had forced a reset. + * We must do this before the cleanup so that the DRM layer + * doesn't get a chance to stick its oar in where it isn't + * wanted. + */ + drm_fb_helper_restore_fbdev_mode(&fbdev->psb_fb_helper); + + /* Let DRM do its clean up */ drm_framebuffer_cleanup(fb); /* We are no longer using the resource in GEM */ drm_gem_object_unreference_unlocked(&r->gem); - kfree(fb); } @@ -694,17 +674,14 @@ static const struct drm_mode_config_funcs psb_mode_funcs = { static int psb_create_backlight_property(struct drm_device *dev) { - struct drm_psb_private *dev_priv - = (struct drm_psb_private *) dev->dev_private; + struct drm_psb_private *dev_priv = dev->dev_private; struct drm_property *backlight; if (dev_priv->backlight_property) return 0; - backlight = drm_property_create(dev, - DRM_MODE_PROP_RANGE, - "backlight", - 2); + backlight = drm_property_create(dev, DRM_MODE_PROP_RANGE, + "backlight", 2); backlight->values[0] = 0; backlight->values[1] = 100; @@ -715,25 +692,13 @@ static int psb_create_backlight_property(struct drm_device *dev) static void psb_setup_outputs(struct drm_device *dev) { - struct drm_psb_private *dev_priv = - (struct drm_psb_private *) dev->dev_private; + struct drm_psb_private *dev_priv = dev->dev_private; struct drm_connector *connector; - PSB_DEBUG_ENTRY("\n"); - drm_mode_create_scaling_mode_property(dev); - psb_create_backlight_property(dev); - if (IS_MRST(dev)) { - if (dev_priv->iLVDS_enable) - mrst_lvds_init(dev, &dev_priv->mode_dev); - else - DRM_ERROR("DSI is not supported\n"); - } else { - psb_intel_lvds_init(dev, &dev_priv->mode_dev); - psb_intel_sdvo_init(dev, SDVOB); - } + dev_priv->ops->output_init(dev); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { @@ -744,12 +709,15 @@ 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); break; case INTEL_OUTPUT_LVDS: - PSB_DEBUG_ENTRY("LVDS.\n"); if (IS_MRST(dev)) crtc_mask = (1 << 0); else @@ -757,26 +725,24 @@ static void psb_setup_outputs(struct drm_device *dev) clone_mask = (1 << INTEL_OUTPUT_LVDS); break; case INTEL_OUTPUT_MIPI: - PSB_DEBUG_ENTRY("MIPI.\n"); crtc_mask = (1 << 0); clone_mask = (1 << INTEL_OUTPUT_MIPI); break; case INTEL_OUTPUT_MIPI2: - PSB_DEBUG_ENTRY("MIPI2.\n"); crtc_mask = (1 << 2); clone_mask = (1 << INTEL_OUTPUT_MIPI2); break; case INTEL_OUTPUT_HDMI: - PSB_DEBUG_ENTRY("HDMI.\n"); - 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; } - encoder->possible_crtcs = crtc_mask; encoder->possible_clones = psb_intel_connector_clones(dev, clone_mask); - } } @@ -787,8 +753,6 @@ void psb_modeset_init(struct drm_device *dev) struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; int i; - PSB_DEBUG_ENTRY("\n"); - drm_mode_config_init(dev); dev->mode_config.min_width = 0; @@ -809,9 +773,6 @@ void psb_modeset_init(struct drm_device *dev) dev->mode_config.max_height = 2048; psb_setup_outputs(dev); - - /* setup fbs */ - /* drm_initial_config(dev); */ } void psb_modeset_cleanup(struct drm_device *dev) @@ -820,7 +781,6 @@ void psb_modeset_cleanup(struct drm_device *dev) drm_kms_helper_poll_fini(dev); psb_fbdev_fini(dev); - drm_mode_config_cleanup(dev); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/staging/gma500/psb_fb.h b/drivers/staging/gma500/framebuffer.h index c8ec0d6..d1b2289 100644 --- a/drivers/staging/gma500/psb_fb.h +++ b/drivers/staging/gma500/framebuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Intel Corporation + * Copyright (c) 2008-2011, Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,10 +19,9 @@ * */ -#ifndef _PSB_FB_H_ -#define _PSB_FB_H_ +#ifndef _FRAMEBUFFER_H_ +#define _FRAMEBUFFER_H_ -#include <linux/version.h> #include <drm/drmP.h> #include <drm/drm_fb_helper.h> @@ -33,14 +32,14 @@ struct psb_framebuffer { struct address_space *addr_space; struct fb_info *fbdev; struct gtt_range *gtt; + bool vm_map; /* True if we must undo a vm_map_ram */ }; struct psb_fbdev { struct drm_fb_helper psb_fb_helper; - struct psb_framebuffer *pfb; + struct psb_framebuffer pfb; }; - #define to_psb_fb(x) container_of(x, struct psb_framebuffer, base) extern int psb_intel_connector_clones(struct drm_device *dev, int type_mask); diff --git a/drivers/staging/gma500/psb_gem.c b/drivers/staging/gma500/gem.c index 76ff7ba..65fdd6b 100644 --- a/drivers/staging/gma500/psb_gem.c +++ b/drivers/staging/gma500/gem.c @@ -19,12 +19,8 @@ * Authors: Alan Cox * * TODO: - * - we don't actually put GEM objects into the GART yet - * - we need to work out if the MMU is relevant as well (eg for + * - we need to work out if the MMU is relevant (eg for * accelerated operations on a GEM object) - * - cache coherency - * - * ie this is just an initial framework to get us going. */ #include <drm/drmP.h> @@ -40,17 +36,9 @@ int psb_gem_init_object(struct drm_gem_object *obj) void psb_gem_free_object(struct drm_gem_object *obj) { struct gtt_range *gtt = container_of(obj, struct gtt_range, gem); + drm_gem_object_release_wrap(obj); + /* This must occur last as it frees up the memory of the GEM object */ psb_gtt_free_range(obj->dev, gtt); - if (obj->map_list.map) { - /* Do things GEM should do for us */ - struct drm_gem_mm *mm = obj->dev->mm_private; - struct drm_map_list *list = &obj->map_list; - drm_ht_remove_item(&mm->offset_hash, &list->hash); - drm_mm_put_block(list->file_offset_node); - kfree(list->map); - list->map = NULL; - } - drm_gem_object_release(obj); } int psb_gem_get_aperture(struct drm_device *dev, void *data, @@ -60,59 +48,6 @@ int psb_gem_get_aperture(struct drm_device *dev, void *data, } /** - * psb_gem_create_mmap_offset - invent an mmap offset - * @obj: our object - * - * This is basically doing by hand a pile of ugly crap which should - * be done automatically by the GEM library code but isn't - */ -static int psb_gem_create_mmap_offset(struct drm_gem_object *obj) -{ - struct drm_device *dev = obj->dev; - struct drm_gem_mm *mm = dev->mm_private; - struct drm_map_list *list; - struct drm_local_map *map; - int ret; - - list = &obj->map_list; - list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL); - if (list->map == NULL) - return -ENOMEM; - map = list->map; - map->type = _DRM_GEM; - map->size = obj->size; - map->handle =obj; - - list->file_offset_node = drm_mm_search_free(&mm->offset_manager, - obj->size / PAGE_SIZE, 0, 0); - if (!list->file_offset_node) { - DRM_ERROR("failed to allocate offset for bo %d\n", obj->name); - ret = -ENOSPC; - goto free_it; - } - list->file_offset_node = drm_mm_get_block(list->file_offset_node, - obj->size / PAGE_SIZE, 0); - if (!list->file_offset_node) { - ret = -ENOMEM; - goto free_it; - } - list->hash.key = list->file_offset_node->start; - ret = drm_ht_insert_item(&mm->offset_hash, &list->hash); - if (ret) { - DRM_ERROR("failed to add to map hash\n"); - goto free_mm; - } - return 0; - -free_mm: - drm_mm_put_block(list->file_offset_node); -free_it: - kfree(list->map); - list->map = NULL; - return ret; -} - -/** * psb_gem_dumb_map_gtt - buffer mapping for dumb interface * @file: our drm client file * @dev: drm device @@ -129,7 +64,7 @@ int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev, if (!(dev->driver->driver_features & DRIVER_GEM)) return -ENODEV; - + mutex_lock(&dev->struct_mutex); /* GEM does all our handle to object mapping */ @@ -139,10 +74,10 @@ int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev, goto unlock; } /* What validation is needed here ? */ - + /* Make it mmapable */ if (!obj->map_list.map) { - ret = psb_gem_create_mmap_offset(obj); + ret = gem_create_mmap_offset(obj); if (ret) goto out; } @@ -175,21 +110,26 @@ static int psb_gem_create(struct drm_file *file, size = roundup(size, PAGE_SIZE); - /* Allocate our object - for now a direct gtt range which is not + /* Allocate our object - for now a direct gtt range which is not stolen memory backed */ r = psb_gtt_alloc_range(dev, size, "gem", 0); - if (r == NULL) + if (r == NULL) { + dev_err(dev->dev, "no memory for %lld byte GEM object\n", size); return -ENOSPC; + } /* Initialize the extra goodies GEM needs to do all the hard work */ if (drm_gem_object_init(dev, &r->gem, size) != 0) { psb_gtt_free_range(dev, r); /* GEM doesn't give an error code and we don't have an EGEMSUCKS so make something up for now - FIXME */ + dev_err(dev->dev, "GEM init failed for %lld\n", size); return -ENOMEM; } /* Give the object a handle so we can carry it more easily */ ret = drm_gem_handle_create(file, &r->gem, &handle); if (ret) { + dev_err(dev->dev, "GEM handle failed for %p, %lld\n", + &r->gem, size); drm_gem_object_release(&r->gem); psb_gtt_free_range(dev, r); return ret; @@ -245,19 +185,13 @@ int psb_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev, * but we need to do the actual page work. * * This code eventually needs to handle faulting objects in and out - * of the GART and repacking it when we run out of space. We can put + * of the GTT and repacking it when we run out of space. We can put * that off for now and for our simple uses * * The VMA was set up by GEM. In doing so it also ensured that the * vma->vm_private_data points to the GEM object that is backing this * mapping. * - * To avoid aliasing and cache funnies we want to map the object - * through the GART. For the moment this is slightly hackish. It would - * be nicer if GEM provided mmap opened/closed hooks for us giving - * the object so that we could track things nicely. That needs changes - * to the core GEM code so must be tackled post staging - * * FIXME */ int psb_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) @@ -268,9 +202,11 @@ int psb_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) unsigned long pfn; pgoff_t page_offset; struct drm_device *dev; + struct drm_psb_private *dev_priv; obj = vma->vm_private_data; /* GEM object */ dev = obj->dev; + dev_priv = dev->dev_private; r = container_of(obj, struct gtt_range, gem); /* Get the gtt range */ @@ -283,30 +219,26 @@ int psb_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (r->mmapping == 0) { ret = psb_gtt_pin(r); if (ret < 0) { - DRM_ERROR("gma500: pin failed: %d\n", ret); - goto fail; - } + dev_err(dev->dev, "gma500: pin failed: %d\n", ret); + goto fail; + } r->mmapping = 1; } - /* FIXME: Locking. We may also need to repack the GART sometimes */ - - /* Page relative to the VMA start */ + /* Page relative to the VMA start - we must calculate this ourselves + because vmf->pgoff is the fake GEM offset */ page_offset = ((unsigned long) vmf->virtual_address - vma->vm_start) >> PAGE_SHIFT; - /* Bus address of the page is gart + object offset + page offset */ - /* Assumes gtt allocations are page aligned */ - pfn = (r->resource.start >> PAGE_SHIFT) + page_offset; - - pr_debug("Object GTT base at %p\n", (void *)(r->resource.start)); - pr_debug("Inserting %p pfn %lx, pa %lx\n", vmf->virtual_address, - pfn, pfn << PAGE_SHIFT); - + /* CPU view of the page, don't go via the GART for CPU writes */ + if (r->stolen) + pfn = (dev_priv->stolen_base + r->offset) >> PAGE_SHIFT; + else + pfn = page_to_pfn(r->pages[page_offset]); ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); fail: - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev->struct_mutex); switch (ret) { case 0: case -ERESTARTSYS: @@ -318,3 +250,46 @@ fail: return VM_FAULT_SIGBUS; } } + +static int psb_gem_create_stolen(struct drm_file *file, struct drm_device *dev, + int size, u32 *handle) +{ + struct gtt_range *gtt = psb_gtt_alloc_range(dev, size, "gem", 1); + if (gtt == NULL) + return -ENOMEM; + if (drm_gem_private_object_init(dev, >t->gem, size) != 0) + goto free_gtt; + if (drm_gem_handle_create(file, >t->gem, handle) == 0) + return 0; +free_gtt: + psb_gtt_free_range(dev, gtt); + return -ENOMEM; +} + +/* + * GEM interfaces for our specific client + */ +int psb_gem_create_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_psb_gem_create *args = data; + int ret; + if (args->flags & PSB_GEM_CREATE_STOLEN) { + ret = psb_gem_create_stolen(file, dev, args->size, + &args->handle); + if (ret == 0) + return 0; + /* Fall throguh */ + args->flags &= ~PSB_GEM_CREATE_STOLEN; + } + return psb_gem_create(file, dev, args->size, &args->handle); +} + +int psb_gem_mmap_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_psb_gem_mmap *args = data; + return dev->driver->dumb_map_offset(file, dev, + args->handle, &args->offset); +} + diff --git a/drivers/staging/gma500/gem_glue.c b/drivers/staging/gma500/gem_glue.c new file mode 100644 index 0000000..779ac1a --- /dev/null +++ b/drivers/staging/gma500/gem_glue.c @@ -0,0 +1,110 @@ +/************************************************************************** + * Copyright (c) 2011, Intel Corporation. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + **************************************************************************/ + +#include <drm/drmP.h> +#include <drm/drm.h> + +/** + * Initialize an already allocated GEM object of the specified size with + * no GEM provided backing store. Instead the caller is responsible for + * backing the object and handling it. + */ +int drm_gem_private_object_init(struct drm_device *dev, + struct drm_gem_object *obj, size_t size) +{ + BUG_ON((size & (PAGE_SIZE - 1)) != 0); + + obj->dev = dev; + obj->filp = NULL; + + kref_init(&obj->refcount); + atomic_set(&obj->handle_count, 0); + obj->size = size; + + return 0; +} + +void drm_gem_object_release_wrap(struct drm_gem_object *obj) +{ + /* Remove the list map if one is present */ + if (obj->map_list.map) { + struct drm_gem_mm *mm = obj->dev->mm_private; + struct drm_map_list *list = &obj->map_list; + drm_ht_remove_item(&mm->offset_hash, &list->hash); + drm_mm_put_block(list->file_offset_node); + kfree(list->map); + list->map = NULL; + } + if (obj->filp) + drm_gem_object_release(obj); +} + +/** + * gem_create_mmap_offset - invent an mmap offset + * @obj: our object + * + * Standard implementation of offset generation for mmap as is + * duplicated in several drivers. This belongs in GEM. + */ +int gem_create_mmap_offset(struct drm_gem_object *obj) +{ + struct drm_device *dev = obj->dev; + struct drm_gem_mm *mm = dev->mm_private; + struct drm_map_list *list; + struct drm_local_map *map; + int ret; + + list = &obj->map_list; + list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL); + if (list->map == NULL) + return -ENOMEM; + map = list->map; + map->type = _DRM_GEM; + map->size = obj->size; + map->handle = obj; + + list->file_offset_node = drm_mm_search_free(&mm->offset_manager, + obj->size / PAGE_SIZE, 0, 0); + if (!list->file_offset_node) { + dev_err(dev->dev, "failed to allocate offset for bo %d\n", + obj->name); + ret = -ENOSPC; + goto free_it; + } + list->file_offset_node = drm_mm_get_block(list->file_offset_node, + obj->size / PAGE_SIZE, 0); + if (!list->file_offset_node) { + ret = -ENOMEM; + goto free_it; + } + list->hash.key = list->file_offset_node->start; + ret = drm_ht_insert_item(&mm->offset_hash, &list->hash); + if (ret) { + dev_err(dev->dev, "failed to add to map hash\n"); + goto free_mm; + } + return 0; + +free_mm: + drm_mm_put_block(list->file_offset_node); +free_it: + kfree(list->map); + list->map = NULL; + return ret; +} diff --git a/drivers/staging/gma500/gem_glue.h b/drivers/staging/gma500/gem_glue.h new file mode 100644 index 0000000..a0f2bc4 --- /dev/null +++ b/drivers/staging/gma500/gem_glue.h @@ -0,0 +1,4 @@ +extern void drm_gem_object_release_wrap(struct drm_gem_object *obj); +extern int drm_gem_private_object_init(struct drm_device *dev, + struct drm_gem_object *obj, size_t size); +extern int gem_create_mmap_offset(struct drm_gem_object *obj); diff --git a/drivers/staging/gma500/psb_gtt.c b/drivers/staging/gma500/gtt.c index 74c5a65..461ead2 100644 --- a/drivers/staging/gma500/psb_gtt.c +++ b/drivers/staging/gma500/gtt.c @@ -28,11 +28,11 @@ */ /** - * psb_gtt_mask_pte - generate GART pte entry + * psb_gtt_mask_pte - generate GTT pte entry * @pfn: page number to encode - * @type: type of memory in the GART + * @type: type of memory in the GTT * - * Set the GART entry for the appropriate memory type. + * Set the GTT entry for the appropriate memory type. */ static inline uint32_t psb_gtt_mask_pte(uint32_t pfn, int type) { @@ -49,16 +49,16 @@ static inline uint32_t psb_gtt_mask_pte(uint32_t pfn, int type) } /** - * psb_gtt_entry - find the GART entries for a gtt_range + * psb_gtt_entry - find the GTT entries for a gtt_range * @dev: our DRM device * @r: our GTT range - * - * Given a gtt_range object return the GART offset of the page table + * + * Given a gtt_range object return the GTT offset of the page table * entries for this gtt_range */ u32 *psb_gtt_entry(struct drm_device *dev, struct gtt_range *r) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = dev->dev_private; unsigned long offset; offset = r->resource.start - dev_priv->gtt_mem->start; @@ -67,20 +67,18 @@ u32 *psb_gtt_entry(struct drm_device *dev, struct gtt_range *r) } /** - * psb_gtt_insert - put an object into the GART + * psb_gtt_insert - put an object into the GTT * @dev: our DRM device * @r: our GTT range * * Take our preallocated GTT range and insert the GEM object into - * the GART. + * the GTT. * * FIXME: gtt lock ? */ static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r) { - struct drm_psb_private *dev_priv = dev->dev_private; u32 *gtt_slot, pte; - int numpages = (r->resource.end + 1 - r->resource.start) >> PAGE_SHIFT; struct page **pages; int i; @@ -94,26 +92,25 @@ static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r) gtt_slot = psb_gtt_entry(dev, r); pages = r->pages; - /* Make sure we have no alias present */ - wbinvd(); + /* Make sure changes are visible to the GPU */ + set_pages_array_uc(pages, r->npage); - /* Write our page entries into the GART itself */ - for (i = 0; i < numpages; i++) { + /* Write our page entries into the GTT itself */ + for (i = 0; i < r->npage; i++) { pte = psb_gtt_mask_pte(page_to_pfn(*pages++), 0/*type*/); iowrite32(pte, gtt_slot++); } /* Make sure all the entries are set before we return */ ioread32(gtt_slot - 1); - return 0; } /** - * psb_gtt_remove - remove an object from the GART + * psb_gtt_remove - remove an object from the GTT * @dev: our DRM device * @r: our GTT range * - * Remove a preallocated GTT range from the GART. Overwrite all the + * Remove a preallocated GTT range from the GTT. Overwrite all the * page table entries with the dummy page */ @@ -121,17 +118,17 @@ static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r) { struct drm_psb_private *dev_priv = dev->dev_private; u32 *gtt_slot, pte; - int numpages = (r->resource.end + 1 - r->resource.start) >> PAGE_SHIFT; int i; WARN_ON(r->stolen); gtt_slot = psb_gtt_entry(dev, r); - pte = psb_gtt_mask_pte(page_to_pfn(dev_priv->scratch_page), 0);; + pte = psb_gtt_mask_pte(page_to_pfn(dev_priv->scratch_page), 0); - for (i = 0; i < numpages; i++) + for (i = 0; i < r->npage; i++) iowrite32(pte, gtt_slot++); ioread32(gtt_slot - 1); + set_pages_array_wb(r->pages, r->npage); } /** @@ -140,8 +137,6 @@ static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r) * * Pin and build an in kernel list of the pages that back our GEM object. * While we hold this the pages cannot be swapped out - * - * FIXME: Do we need to cache flush when we update the GTT */ static int psb_gtt_attach_pages(struct gtt_range *gt) { @@ -149,7 +144,7 @@ static int psb_gtt_attach_pages(struct gtt_range *gt) struct address_space *mapping; int i; struct page *p; - int pages = (gt->resource.end + 1 - gt->resource.start) >> PAGE_SHIFT; + int pages = gt->gem.size / PAGE_SIZE; WARN_ON(gt->pages); @@ -160,6 +155,8 @@ static int psb_gtt_attach_pages(struct gtt_range *gt) gt->pages = kmalloc(pages * sizeof(struct page *), GFP_KERNEL); if (gt->pages == NULL) return -ENOMEM; + gt->npage = pages; + for (i = 0; i < pages; i++) { /* FIXME: review flags later */ p = read_cache_page_gfp(mapping, i, @@ -183,20 +180,15 @@ err: * @gt: the gtt range * * Undo the effect of psb_gtt_attach_pages. At this point the pages - * must have been removed from the GART as they could now be paged out + * must have been removed from the GTT as they could now be paged out * and move bus address. - * - * FIXME: Do we need to cache flush when we update the GTT */ static void psb_gtt_detach_pages(struct gtt_range *gt) { int i; - int pages = (gt->resource.end + 1 - gt->resource.start) >> PAGE_SHIFT; - - for (i = 0; i < pages; i++) { + for (i = 0; i < gt->npage; i++) { /* FIXME: do we need to force dirty */ set_page_dirty(gt->pages[i]); - /* Undo the reference we took when populating the table */ page_cache_release(gt->pages[i]); } kfree(gt->pages); @@ -215,7 +207,7 @@ static void psb_gtt_detach_pages(struct gtt_range *gt) */ int psb_gtt_pin(struct gtt_range *gt) { - int ret; + int ret = 0; struct drm_device *dev = gt->gem.dev; struct drm_psb_private *dev_priv = dev->dev_private; @@ -264,7 +256,7 @@ void psb_gtt_unpin(struct gtt_range *gt) } mutex_unlock(&dev_priv->gtt_mutex); } - + /* * GTT resource allocator - allocate and manage GTT address space */ @@ -291,50 +283,45 @@ struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len, struct resource *r = dev_priv->gtt_mem; int ret; unsigned long start, end; - + if (backed) { - /* The start of the GTT is the stolen pages */ - start = r->start; - end = r->start + dev_priv->pg->stolen_size - 1; - } else { - /* The rest we will use for GEM backed objects */ - start = r->start + dev_priv->pg->stolen_size; - end = r->end; - } + /* The start of the GTT is the stolen pages */ + start = r->start; + end = r->start + dev_priv->gtt.stolen_size - 1; + } else { + /* The rest we will use for GEM backed objects */ + start = r->start + dev_priv->gtt.stolen_size; + end = r->end; + } gt = kzalloc(sizeof(struct gtt_range), GFP_KERNEL); if (gt == NULL) return NULL; - gt->resource.name = name; - gt->stolen = backed; - gt->in_gart = backed; - /* Ensure this is set for non GEM objects */ - gt->gem.dev = dev; - kref_init(>->kref); - + gt->resource.name = name; + gt->stolen = backed; + gt->in_gart = backed; + /* Ensure this is set for non GEM objects */ + gt->gem.dev = dev; ret = allocate_resource(dev_priv->gtt_mem, >->resource, len, start, end, PAGE_SIZE, NULL, NULL); if (ret == 0) { - gt->offset = gt->resource.start - r->start; + gt->offset = gt->resource.start - r->start; return gt; - } + } kfree(gt); return NULL; } /** - * psb_gtt_destroy - final free up of a gtt - * @kref: the kref of the gtt - * - * Called from the kernel kref put when the final reference to our - * GTT object is dropped. At that point we can free up the resources. + * psb_gtt_free_range - release GTT address space + * @dev: our DRM device + * @gt: a mapping created with psb_gtt_alloc_range * - * For now we handle mmap clean up here to work around limits in GEM + * Release a resource that was allocated with psb_gtt_alloc_range. If the + * object has been pinned by mmap users we clean this up here currently. */ -static void psb_gtt_destroy(struct kref *kref) +void psb_gtt_free_range(struct drm_device *dev, struct gtt_range *gt) { - struct gtt_range *gt = container_of(kref, struct gtt_range, kref); - /* Undo the mmap pin if we are destroying the object */ if (gt->mmapping) { psb_gtt_unpin(gt); @@ -345,48 +332,16 @@ static void psb_gtt_destroy(struct kref *kref) kfree(gt); } -/** - * psb_gtt_kref_put - drop reference to a GTT object - * @gt: the GT being dropped - * - * Drop a reference to a psb gtt - */ -void psb_gtt_kref_put(struct gtt_range *gt) +void psb_gtt_alloc(struct drm_device *dev) { - kref_put(>->kref, psb_gtt_destroy); -} - -/** - * psb_gtt_free_range - release GTT address space - * @dev: our DRM device - * @gt: a mapping created with psb_gtt_alloc_range - * - * Release a resource that was allocated with psb_gtt_alloc_range - */ -void psb_gtt_free_range(struct drm_device *dev, struct gtt_range *gt) -{ - psb_gtt_kref_put(gt); -} - - -struct psb_gtt *psb_gtt_alloc(struct drm_device *dev) -{ - struct psb_gtt *tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); - - if (!tmp) - return NULL; - - init_rwsem(&tmp->sem); - tmp->dev = dev; - - return tmp; + struct drm_psb_private *dev_priv = dev->dev_private; + init_rwsem(&dev_priv->gtt.sem); } void psb_gtt_takedown(struct drm_device *dev) { struct drm_psb_private *dev_priv = dev->dev_private; - /* FIXME: iounmap dev_priv->vram_addr etc */ if (dev_priv->gtt_map) { iounmap(dev_priv->gtt_map); dev_priv->gtt_map = NULL; @@ -397,8 +352,8 @@ void psb_gtt_takedown(struct drm_device *dev) PSB_WVDC32(dev_priv->pge_ctl, PSB_PGETBL_CTL); (void) PSB_RVDC32(PSB_PGETBL_CTL); } - kfree(dev_priv->pg); - dev_priv->pg = NULL; + if (dev_priv->vram_addr) + iounmap(dev_priv->gtt_map); } int psb_gtt_init(struct drm_device *dev, int resume) @@ -409,8 +364,6 @@ int psb_gtt_init(struct drm_device *dev, int resume) unsigned i, num_pages; unsigned pfn_base; uint32_t vram_pages; - uint32_t tt_pages; - uint32_t *ttm_gtt_map; uint32_t dvmt_mode = 0; struct psb_gtt *pg; @@ -419,10 +372,10 @@ int psb_gtt_init(struct drm_device *dev, int resume) mutex_init(&dev_priv->gtt_mutex); - dev_priv->pg = pg = psb_gtt_alloc(dev); - if (pg == NULL) - return -ENOMEM; + psb_gtt_alloc(dev); + pg = &dev_priv->gtt; + /* Enable the GTT */ pci_read_config_word(dev->pdev, PSB_GMCH_CTRL, &dev_priv->gmch_ctrl); pci_write_config_word(dev->pdev, PSB_GMCH_CTRL, dev_priv->gmch_ctrl | _PSB_GMCH_ENABLED); @@ -432,31 +385,53 @@ 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); - /* fix me: video mmu has hw bug to access 0x0D0000000, - * then make gatt start at 0x0e000,0000 */ + /* + * FIXME: video mmu has hw bug to access 0x0D0000000, + * then make gatt start at 0x0e000,0000 + */ pg->mmu_gatt_start = 0xE0000000; + pg->gtt_start = pci_resource_start(dev->pdev, PSB_GTT_RESOURCE); - gtt_pages = - pci_resource_len(dev->pdev, PSB_GTT_RESOURCE) >> PAGE_SHIFT; + 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; + >> 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 - PAGE_SIZE; + vram_stolen_size = pg->gtt_phys_start - dev_priv->stolen_base + - PAGE_SIZE; stolen_size = vram_stolen_size; - printk(KERN_INFO"GMMADR(region 0) start: 0x%08x (%dM).\n", - pg->gatt_start, pg->gatt_pages/256); - printk(KERN_INFO"GTTADR(region 3) start: 0x%08x (can map %dM RAM), and actual RAM base 0x%08x.\n", - pg->gtt_start, gtt_pages * 4, pg->gtt_phys_start); printk(KERN_INFO "Stolen memory information\n"); printk(KERN_INFO " base in RAM: 0x%x\n", dev_priv->stolen_base); printk(KERN_INFO " size: %luK, calculated by (GTT RAM base) - (Stolen base), seems wrong\n", @@ -467,7 +442,7 @@ int psb_gtt_init(struct drm_device *dev, int resume) if (resume && (gtt_pages != pg->gtt_pages) && (stolen_size != pg->stolen_size)) { - DRM_ERROR("GTT resume error.\n"); + dev_err(dev->dev, "GTT resume error.\n"); ret = -EINVAL; goto out_err; } @@ -475,62 +450,48 @@ int psb_gtt_init(struct drm_device *dev, int resume) pg->gtt_pages = gtt_pages; pg->stolen_size = stolen_size; dev_priv->vram_stolen_size = vram_stolen_size; - dev_priv->gtt_map = - ioremap_nocache(pg->gtt_phys_start, gtt_pages << PAGE_SHIFT); + + /* + * Map the GTT and the stolen memory area + */ + dev_priv->gtt_map = ioremap_nocache(pg->gtt_phys_start, + gtt_pages << PAGE_SHIFT); if (!dev_priv->gtt_map) { - DRM_ERROR("Failure to map gtt.\n"); + dev_err(dev->dev, "Failure to map gtt.\n"); ret = -ENOMEM; goto out_err; } dev_priv->vram_addr = ioremap_wc(dev_priv->stolen_base, stolen_size); if (!dev_priv->vram_addr) { - DRM_ERROR("Failure to map stolen base.\n"); + dev_err(dev->dev, "Failure to map stolen base.\n"); ret = -ENOMEM; goto out_err; } - DRM_DEBUG("%s: vram kernel virtual address %p\n", dev_priv->vram_addr); - - tt_pages = (pg->gatt_pages < PSB_TT_PRIV0_PLIMIT) ? - (pg->gatt_pages) : PSB_TT_PRIV0_PLIMIT; - - ttm_gtt_map = dev_priv->gtt_map + tt_pages / 2; - /* - * insert vram stolen pages. + * Insert vram stolen pages into the GTT */ 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); } /* - * Init rest of gtt managed by IMG. - */ - pfn_base = page_to_pfn(dev_priv->scratch_page); - pte = psb_gtt_mask_pte(pfn_base, 0); - for (; i < tt_pages / 2 - 1; ++i) - iowrite32(pte, dev_priv->gtt_map + i); - - /* - * Init rest of gtt managed by TTM. + * Init rest of GTT to the scratch page to avoid accidents or scribbles */ pfn_base = page_to_pfn(dev_priv->scratch_page); pte = psb_gtt_mask_pte(pfn_base, 0); - PSB_DEBUG_INIT("Initializing the rest of a total " - "of %d gtt pages.\n", pg->gatt_pages); + for (; i < gtt_pages; ++i) + iowrite32(pte, dev_priv->gtt_map + i); - for (; i < pg->gatt_pages - tt_pages / 2; ++i) - iowrite32(pte, ttm_gtt_map + i); (void) ioread32(dev_priv->gtt_map + i - 1); - return 0; out_err: diff --git a/drivers/staging/gma500/psb_gtt.h b/drivers/staging/gma500/gtt.h index 535ae00..e0e1cb6 100644 --- a/drivers/staging/gma500/psb_gtt.h +++ b/drivers/staging/gma500/gtt.h @@ -22,8 +22,8 @@ #include <drm/drmP.h> +/* This wants cleaning up with respect to the psb_dev and un-needed stuff */ struct psb_gtt { - struct drm_device *dev; uint32_t gatt_start; uint32_t mmu_gatt_start; uint32_t gtt_start; @@ -35,20 +35,20 @@ struct psb_gtt { struct rw_semaphore sem; }; -/*Exported functions*/ +/* Exported functions */ extern int psb_gtt_init(struct drm_device *dev, int resume); extern void psb_gtt_takedown(struct drm_device *dev); /* Each gtt_range describes an allocation in the GTT area */ struct gtt_range { - struct resource resource; - u32 offset; - struct kref kref; + struct resource resource; /* Resource for our allocation */ + u32 offset; /* GTT offset of our object */ struct drm_gem_object gem; /* GEM high level stuff */ int in_gart; /* Currently in the GART (ref ct) */ - bool stolen; /* Backed from stolen RAM */ - bool mmapping; /* Is mmappable */ + bool stolen; /* Backed from stolen RAM */ + bool mmapping; /* Is mmappable */ struct page **pages; /* Backing pages if present */ + int npage; /* Number of backing pages */ }; extern struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len, diff --git a/drivers/staging/gma500/psb_intel_bios.c b/drivers/staging/gma500/intel_bios.c index 417965d..096757f 100644 --- a/drivers/staging/gma500/psb_intel_bios.c +++ b/drivers/staging/gma500/intel_bios.c @@ -24,7 +24,7 @@ #include "psb_drv.h" #include "psb_intel_drv.h" #include "psb_intel_reg.h" -#include "psb_intel_bios.h" +#include "intel_bios.h" static void *find_section(struct bdb_header *bdb, int section_id) @@ -96,25 +96,20 @@ static void parse_backlight_data(struct drm_psb_private *dev_priv, dev_priv->lvds_bl = NULL; - if (lvds_opts) { - DRM_DEBUG("lvds_options found at %p\n", lvds_opts); + if (lvds_opts) p_type = lvds_opts->panel_type; - } else { - DRM_DEBUG("no lvds_options\n"); + else return; - } bl_start = find_section(bdb, BDB_LVDS_BACKLIGHT); vbt_lvds_bl = (struct bdb_lvds_backlight *)(bl_start + 1) + p_type; lvds_bl = kzalloc(sizeof(*vbt_lvds_bl), GFP_KERNEL); if (!lvds_bl) { - DRM_DEBUG("No memory\n"); + dev_err(dev_priv->dev->dev, "out of memory for backlight data\n"); return; } - memcpy(lvds_bl, vbt_lvds_bl, sizeof(*vbt_lvds_bl)); - dev_priv->lvds_bl = lvds_bl; } @@ -144,26 +139,28 @@ static void parse_lfp_panel_data(struct drm_psb_private *dev_priv, if (!lvds_lfp_data) return; - dev_priv->lvds_vbt = 1; entry = &lvds_lfp_data->data[lvds_options->panel_type]; dvo_timing = &entry->dvo_timing; panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); + if (panel_fixed_mode == NULL) { + dev_err(dev_priv->dev->dev, "out of memory for fixed panel mode\n"); + return; + } + dev_priv->lvds_vbt = 1; fill_detail_timing_data(panel_fixed_mode, dvo_timing); if (panel_fixed_mode->htotal > 0 && panel_fixed_mode->vtotal > 0) { dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode; - DRM_DEBUG("Found panel mode in BIOS VBT tables:\n"); drm_mode_debug_printmodeline(panel_fixed_mode); } else { - DRM_DEBUG("Ignoring bogus LVDS VBT mode.\n"); + dev_dbg(dev_priv->dev->dev, "ignoring invalid LVDS VBT\n"); dev_priv->lvds_vbt = 0; kfree(panel_fixed_mode); } - return; } @@ -257,7 +254,7 @@ bool psb_intel_init_bios(struct drm_device *dev) } if (!vbt) { - DRM_ERROR("VBT signature missing\n"); + dev_err(dev->dev, "VBT signature missing\n"); pci_unmap_rom(pdev, bios); return -1; } diff --git a/drivers/staging/gma500/psb_intel_bios.h b/drivers/staging/gma500/intel_bios.h index 70f1bf0..70f1bf0 100644 --- a/drivers/staging/gma500/psb_intel_bios.h +++ b/drivers/staging/gma500/intel_bios.h diff --git a/drivers/staging/gma500/psb_intel_i2c.c b/drivers/staging/gma500/intel_i2c.c index e33432d..e33432d 100644 --- a/drivers/staging/gma500/psb_intel_i2c.c +++ b/drivers/staging/gma500/intel_i2c.c diff --git a/drivers/staging/gma500/psb_intel_opregion.c b/drivers/staging/gma500/intel_opregion.c index 65e3e9b..d2e6037 100644 --- a/drivers/staging/gma500/psb_intel_opregion.c +++ b/drivers/staging/gma500/intel_opregion.c @@ -33,24 +33,23 @@ struct opregion_header { u8 driver_ver[16]; u32 mboxes; u8 reserved[164]; -} __attribute__((packed)); +} __packed; struct opregion_apci { /*FIXME: add it later*/ -} __attribute__((packed)); +} __packed; struct opregion_swsci { /*FIXME: add it later*/ -} __attribute__((packed)); +} __packed; struct opregion_acpi { /*FIXME: add it later*/ -} __attribute__((packed)); +} __packed; -int psb_intel_opregion_init(struct drm_device *dev) +int gma_intel_opregion_init(struct drm_device *dev) { struct drm_psb_private *dev_priv = dev->dev_private; - /*struct psb_intel_opregion * opregion = &dev_priv->opregion;*/ u32 opregion_phy; void *base; u32 *lid_state; @@ -58,11 +57,8 @@ int psb_intel_opregion_init(struct drm_device *dev) dev_priv->lid_state = NULL; pci_read_config_dword(dev->pdev, 0xfc, &opregion_phy); - if (opregion_phy == 0) { - DRM_DEBUG("Opregion not supported, won't support lid-switch\n"); + if (opregion_phy == 0) return -ENOTSUPP; - } - DRM_DEBUG("OpRegion detected at 0x%8x\n", opregion_phy); base = ioremap(opregion_phy, 8*1024); if (!base) @@ -70,9 +66,15 @@ int psb_intel_opregion_init(struct drm_device *dev) lid_state = base + 0x01ac; - DRM_DEBUG("Lid switch state 0x%08x\n", *lid_state); - dev_priv->lid_state = lid_state; - dev_priv->lid_last_state = *lid_state; + dev_priv->lid_last_state = readl(lid_state); + return 0; +} + +int gma_intel_opregion_exit(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + if (dev_priv->lid_state) + iounmap(dev_priv->lid_state); return 0; } diff --git a/drivers/staging/gma500/mdfld_device.c b/drivers/staging/gma500/mdfld_device.c new file mode 100644 index 0000000..f47aeb7 --- /dev/null +++ b/drivers/staging/gma500/mdfld_device.c @@ -0,0 +1,714 @@ +/************************************************************************** + * Copyright (c) 2011, Intel Corporation. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + **************************************************************************/ + +#include <linux/backlight.h> +#include <drm/drmP.h> +#include <drm/drm.h> +#include "psb_reg.h" +#include "psb_intel_reg.h" +#include "psb_drm.h" +#include "psb_drv.h" +#include "mdfld_output.h" +#include "mdfld_dsi_output.h" +#include "mid_bios.h" + +/* + * Provide the Medfield specific backlight management + */ + +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + +static int mdfld_brightness; +struct backlight_device *mdfld_backlight_device; + +static int mfld_set_brightness(struct backlight_device *bd) +{ + struct drm_device *dev = bl_get_data(mdfld_backlight_device); + struct drm_psb_private *dev_priv = dev->dev_private; + int level = bd->props.brightness; + + /* Percentage 1-100% being valid */ + if (level < 1) + level = 1; + + if (gma_power_begin(dev, 0)) { + /* Calculate and set the brightness value */ + u32 adjusted_level; + + /* Adjust the backlight level with the percent in + * dev_priv->blc_adj2; + */ + adjusted_level = level * dev_priv->blc_adj2; + adjusted_level = adjusted_level / 100; +#if 0 +#ifndef CONFIG_MDFLD_DSI_DPU + if(!(dev_priv->dsr_fb_update & MDFLD_DSR_MIPI_CONTROL) && + (dev_priv->dbi_panel_on || dev_priv->dbi_panel_on2)){ + mdfld_dsi_dbi_exit_dsr(dev,MDFLD_DSR_MIPI_CONTROL, 0, 0); + dev_dbg(dev->dev, "Out of DSR before set brightness to %d.\n",adjusted_level); + } +#endif + mdfld_dsi_brightness_control(dev, 0, adjusted_level); + + if ((dev_priv->dbi_panel_on2) || (dev_priv->dpi_panel_on2)) + mdfld_dsi_brightness_control(dev, 2, adjusted_level); +#endif + gma_power_end(dev); + } + mdfld_brightness = level; + return 0; +} + +int psb_get_brightness(struct backlight_device *bd) +{ + /* return locally cached var instead of HW read (due to DPST etc.) */ + /* FIXME: ideally return actual value in case firmware fiddled with + it */ + return mdfld_brightness; +} + +static const struct backlight_ops mfld_ops = { + .get_brightness = psb_get_brightness, + .update_status = mfld_set_brightness, +}; + +static int mdfld_backlight_init(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct backlight_properties props; + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = 100; + props.type = BACKLIGHT_PLATFORM; + + mdfld_backlight_device = backlight_device_register("mfld-bl", + NULL, (void *)dev, &mfld_ops, &props); + + if (IS_ERR(mdfld_backlight_device)) + return PTR_ERR(mdfld_backlight_device); + + dev_priv->blc_adj1 = 100; + dev_priv->blc_adj2 = 100; + mdfld_backlight_device->props.brightness = 100; + mdfld_backlight_device->props.max_brightness = 100; + backlight_update_status(mdfld_backlight_device); + dev_priv->backlight_device = mdfld_backlight_device; + return 0; +} + +#endif + +/* + * Provide the Medfield specific chip logic and low level methods for + * power management. + */ + +static void mdfld_init_pm(struct drm_device *dev) +{ + /* No work needed here yet */ +} + +/** + * mdfld_save_display_registers - save registers for pipe + * @dev: our device + * @pipe: pipe to save + * + * Save the pipe state of the device before we power it off. Keep everything + * we need to put it back again + */ +static int mdfld_save_display_registers(struct drm_device *dev, int pipe) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + int i; + + /* register */ + u32 dpll_reg = MRST_DPLL_A; + u32 fp_reg = MRST_FPA0; + u32 pipeconf_reg = PIPEACONF; + u32 htot_reg = HTOTAL_A; + u32 hblank_reg = HBLANK_A; + u32 hsync_reg = HSYNC_A; + u32 vtot_reg = VTOTAL_A; + u32 vblank_reg = VBLANK_A; + u32 vsync_reg = VSYNC_A; + u32 pipesrc_reg = PIPEASRC; + u32 dspstride_reg = DSPASTRIDE; + u32 dsplinoff_reg = DSPALINOFF; + u32 dsptileoff_reg = DSPATILEOFF; + u32 dspsize_reg = DSPASIZE; + u32 dsppos_reg = DSPAPOS; + u32 dspsurf_reg = DSPASURF; + u32 mipi_reg = MIPI; + u32 dspcntr_reg = DSPACNTR; + u32 dspstatus_reg = PIPEASTAT; + u32 palette_reg = PALETTE_A; + + /* pointer to values */ + u32 *dpll_val = &dev_priv->saveDPLL_A; + u32 *fp_val = &dev_priv->saveFPA0; + u32 *pipeconf_val = &dev_priv->savePIPEACONF; + u32 *htot_val = &dev_priv->saveHTOTAL_A; + u32 *hblank_val = &dev_priv->saveHBLANK_A; + u32 *hsync_val = &dev_priv->saveHSYNC_A; + u32 *vtot_val = &dev_priv->saveVTOTAL_A; + u32 *vblank_val = &dev_priv->saveVBLANK_A; + u32 *vsync_val = &dev_priv->saveVSYNC_A; + u32 *pipesrc_val = &dev_priv->savePIPEASRC; + u32 *dspstride_val = &dev_priv->saveDSPASTRIDE; + u32 *dsplinoff_val = &dev_priv->saveDSPALINOFF; + u32 *dsptileoff_val = &dev_priv->saveDSPATILEOFF; + u32 *dspsize_val = &dev_priv->saveDSPASIZE; + u32 *dsppos_val = &dev_priv->saveDSPAPOS; + u32 *dspsurf_val = &dev_priv->saveDSPASURF; + u32 *mipi_val = &dev_priv->saveMIPI; + u32 *dspcntr_val = &dev_priv->saveDSPACNTR; + u32 *dspstatus_val = &dev_priv->saveDSPASTATUS; + u32 *palette_val = dev_priv->save_palette_a; + + switch (pipe) { + case 0: + break; + case 1: + /* register */ + dpll_reg = MDFLD_DPLL_B; + fp_reg = MDFLD_DPLL_DIV0; + pipeconf_reg = PIPEBCONF; + htot_reg = HTOTAL_B; + hblank_reg = HBLANK_B; + hsync_reg = HSYNC_B; + vtot_reg = VTOTAL_B; + vblank_reg = VBLANK_B; + vsync_reg = VSYNC_B; + pipesrc_reg = PIPEBSRC; + dspstride_reg = DSPBSTRIDE; + dsplinoff_reg = DSPBLINOFF; + dsptileoff_reg = DSPBTILEOFF; + dspsize_reg = DSPBSIZE; + dsppos_reg = DSPBPOS; + dspsurf_reg = DSPBSURF; + dspcntr_reg = DSPBCNTR; + dspstatus_reg = PIPEBSTAT; + palette_reg = PALETTE_B; + + /* values */ + dpll_val = &dev_priv->saveDPLL_B; + fp_val = &dev_priv->saveFPB0; + pipeconf_val = &dev_priv->savePIPEBCONF; + htot_val = &dev_priv->saveHTOTAL_B; + hblank_val = &dev_priv->saveHBLANK_B; + hsync_val = &dev_priv->saveHSYNC_B; + vtot_val = &dev_priv->saveVTOTAL_B; + vblank_val = &dev_priv->saveVBLANK_B; + vsync_val = &dev_priv->saveVSYNC_B; + pipesrc_val = &dev_priv->savePIPEBSRC; + dspstride_val = &dev_priv->saveDSPBSTRIDE; + dsplinoff_val = &dev_priv->saveDSPBLINOFF; + dsptileoff_val = &dev_priv->saveDSPBTILEOFF; + dspsize_val = &dev_priv->saveDSPBSIZE; + dsppos_val = &dev_priv->saveDSPBPOS; + dspsurf_val = &dev_priv->saveDSPBSURF; + dspcntr_val = &dev_priv->saveDSPBCNTR; + dspstatus_val = &dev_priv->saveDSPBSTATUS; + palette_val = dev_priv->save_palette_b; + break; + case 2: + /* register */ + pipeconf_reg = PIPECCONF; + htot_reg = HTOTAL_C; + hblank_reg = HBLANK_C; + hsync_reg = HSYNC_C; + vtot_reg = VTOTAL_C; + vblank_reg = VBLANK_C; + vsync_reg = VSYNC_C; + pipesrc_reg = PIPECSRC; + dspstride_reg = DSPCSTRIDE; + dsplinoff_reg = DSPCLINOFF; + dsptileoff_reg = DSPCTILEOFF; + dspsize_reg = DSPCSIZE; + dsppos_reg = DSPCPOS; + dspsurf_reg = DSPCSURF; + mipi_reg = MIPI_C; + dspcntr_reg = DSPCCNTR; + dspstatus_reg = PIPECSTAT; + palette_reg = PALETTE_C; + + /* pointer to values */ + pipeconf_val = &dev_priv->savePIPECCONF; + htot_val = &dev_priv->saveHTOTAL_C; + hblank_val = &dev_priv->saveHBLANK_C; + hsync_val = &dev_priv->saveHSYNC_C; + vtot_val = &dev_priv->saveVTOTAL_C; + vblank_val = &dev_priv->saveVBLANK_C; + vsync_val = &dev_priv->saveVSYNC_C; + pipesrc_val = &dev_priv->savePIPECSRC; + dspstride_val = &dev_priv->saveDSPCSTRIDE; + dsplinoff_val = &dev_priv->saveDSPCLINOFF; + dsptileoff_val = &dev_priv->saveDSPCTILEOFF; + dspsize_val = &dev_priv->saveDSPCSIZE; + dsppos_val = &dev_priv->saveDSPCPOS; + dspsurf_val = &dev_priv->saveDSPCSURF; + mipi_val = &dev_priv->saveMIPI_C; + dspcntr_val = &dev_priv->saveDSPCCNTR; + dspstatus_val = &dev_priv->saveDSPCSTATUS; + palette_val = dev_priv->save_palette_c; + break; + default: + DRM_ERROR("%s, invalid pipe number.\n", __func__); + return -EINVAL; + } + + /* Pipe & plane A info */ + *dpll_val = PSB_RVDC32(dpll_reg); + *fp_val = PSB_RVDC32(fp_reg); + *pipeconf_val = PSB_RVDC32(pipeconf_reg); + *htot_val = PSB_RVDC32(htot_reg); + *hblank_val = PSB_RVDC32(hblank_reg); + *hsync_val = PSB_RVDC32(hsync_reg); + *vtot_val = PSB_RVDC32(vtot_reg); + *vblank_val = PSB_RVDC32(vblank_reg); + *vsync_val = PSB_RVDC32(vsync_reg); + *pipesrc_val = PSB_RVDC32(pipesrc_reg); + *dspstride_val = PSB_RVDC32(dspstride_reg); + *dsplinoff_val = PSB_RVDC32(dsplinoff_reg); + *dsptileoff_val = PSB_RVDC32(dsptileoff_reg); + *dspsize_val = PSB_RVDC32(dspsize_reg); + *dsppos_val = PSB_RVDC32(dsppos_reg); + *dspsurf_val = PSB_RVDC32(dspsurf_reg); + *dspcntr_val = PSB_RVDC32(dspcntr_reg); + *dspstatus_val = PSB_RVDC32(dspstatus_reg); + + /*save palette (gamma) */ + for (i = 0; i < 256; i++) + palette_val[i] = PSB_RVDC32(palette_reg + (i<<2)); + + if (pipe == 1) { + dev_priv->savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL); + dev_priv->savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS); + dev_priv->saveHDMIPHYMISCCTL = PSB_RVDC32(HDMIPHYMISCCTL); + dev_priv->saveHDMIB_CONTROL = PSB_RVDC32(HDMIB_CONTROL); + return 0; + } + *mipi_val = PSB_RVDC32(mipi_reg); + return 0; +} + +/** + * mdfld_save_cursor_overlay_registers - save cursor overlay info + * @dev: our device + * + * Save the cursor and overlay register state + */ +static int mdfld_save_cursor_overlay_registers(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + + /* Save cursor regs */ + dev_priv->saveDSPACURSOR_CTRL = PSB_RVDC32(CURACNTR); + dev_priv->saveDSPACURSOR_BASE = PSB_RVDC32(CURABASE); + dev_priv->saveDSPACURSOR_POS = PSB_RVDC32(CURAPOS); + + dev_priv->saveDSPBCURSOR_CTRL = PSB_RVDC32(CURBCNTR); + dev_priv->saveDSPBCURSOR_BASE = PSB_RVDC32(CURBBASE); + dev_priv->saveDSPBCURSOR_POS = PSB_RVDC32(CURBPOS); + + dev_priv->saveDSPCCURSOR_CTRL = PSB_RVDC32(CURCCNTR); + dev_priv->saveDSPCCURSOR_BASE = PSB_RVDC32(CURCBASE); + dev_priv->saveDSPCCURSOR_POS = PSB_RVDC32(CURCPOS); + + /* HW overlay */ + dev_priv->saveOV_OVADD = PSB_RVDC32(OV_OVADD); + dev_priv->saveOV_OGAMC0 = PSB_RVDC32(OV_OGAMC0); + dev_priv->saveOV_OGAMC1 = PSB_RVDC32(OV_OGAMC1); + dev_priv->saveOV_OGAMC2 = PSB_RVDC32(OV_OGAMC2); + dev_priv->saveOV_OGAMC3 = PSB_RVDC32(OV_OGAMC3); + dev_priv->saveOV_OGAMC4 = PSB_RVDC32(OV_OGAMC4); + dev_priv->saveOV_OGAMC5 = PSB_RVDC32(OV_OGAMC5); + + dev_priv->saveOV_OVADD_C = PSB_RVDC32(OV_OVADD + OV_C_OFFSET); + dev_priv->saveOV_OGAMC0_C = PSB_RVDC32(OV_OGAMC0 + OV_C_OFFSET); + dev_priv->saveOV_OGAMC1_C = PSB_RVDC32(OV_OGAMC1 + OV_C_OFFSET); + dev_priv->saveOV_OGAMC2_C = PSB_RVDC32(OV_OGAMC2 + OV_C_OFFSET); + dev_priv->saveOV_OGAMC3_C = PSB_RVDC32(OV_OGAMC3 + OV_C_OFFSET); + dev_priv->saveOV_OGAMC4_C = PSB_RVDC32(OV_OGAMC4 + OV_C_OFFSET); + dev_priv->saveOV_OGAMC5_C = PSB_RVDC32(OV_OGAMC5 + OV_C_OFFSET); + + return 0; +} +/* + * mdfld_restore_display_registers - restore the state of a pipe + * @dev: our device + * @pipe: the pipe to restore + * + * Restore the state of a pipe to that which was saved by the register save + * functions. + */ +static int mdfld_restore_display_registers(struct drm_device *dev, int pipe) +{ + /* To get panel out of ULPS mode */ + struct drm_psb_private *dev_priv = dev->dev_private; + struct mdfld_dsi_config *dsi_config = NULL; + u32 i = 0; + u32 dpll = 0; + u32 timeout = 0; + u32 reg_offset = 0; + + /* register */ + u32 dpll_reg = MRST_DPLL_A; + u32 fp_reg = MRST_FPA0; + u32 pipeconf_reg = PIPEACONF; + u32 htot_reg = HTOTAL_A; + u32 hblank_reg = HBLANK_A; + u32 hsync_reg = HSYNC_A; + u32 vtot_reg = VTOTAL_A; + u32 vblank_reg = VBLANK_A; + u32 vsync_reg = VSYNC_A; + u32 pipesrc_reg = PIPEASRC; + u32 dspstride_reg = DSPASTRIDE; + u32 dsplinoff_reg = DSPALINOFF; + u32 dsptileoff_reg = DSPATILEOFF; + u32 dspsize_reg = DSPASIZE; + u32 dsppos_reg = DSPAPOS; + u32 dspsurf_reg = DSPASURF; + u32 dspstatus_reg = PIPEASTAT; + u32 mipi_reg = MIPI; + u32 dspcntr_reg = DSPACNTR; + u32 palette_reg = PALETTE_A; + + /* values */ + u32 dpll_val = dev_priv->saveDPLL_A & ~DPLL_VCO_ENABLE; + u32 fp_val = dev_priv->saveFPA0; + u32 pipeconf_val = dev_priv->savePIPEACONF; + u32 htot_val = dev_priv->saveHTOTAL_A; + u32 hblank_val = dev_priv->saveHBLANK_A; + u32 hsync_val = dev_priv->saveHSYNC_A; + u32 vtot_val = dev_priv->saveVTOTAL_A; + u32 vblank_val = dev_priv->saveVBLANK_A; + u32 vsync_val = dev_priv->saveVSYNC_A; + u32 pipesrc_val = dev_priv->savePIPEASRC; + u32 dspstride_val = dev_priv->saveDSPASTRIDE; + u32 dsplinoff_val = dev_priv->saveDSPALINOFF; + u32 dsptileoff_val = dev_priv->saveDSPATILEOFF; + u32 dspsize_val = dev_priv->saveDSPASIZE; + u32 dsppos_val = dev_priv->saveDSPAPOS; + u32 dspsurf_val = dev_priv->saveDSPASURF; + u32 dspstatus_val = dev_priv->saveDSPASTATUS; + u32 mipi_val = dev_priv->saveMIPI; + u32 dspcntr_val = dev_priv->saveDSPACNTR; + u32 *palette_val = dev_priv->save_palette_a; + + switch (pipe) { + case 0: + dsi_config = dev_priv->dsi_configs[0]; + break; + case 1: + /* register */ + dpll_reg = MDFLD_DPLL_B; + fp_reg = MDFLD_DPLL_DIV0; + pipeconf_reg = PIPEBCONF; + htot_reg = HTOTAL_B; + hblank_reg = HBLANK_B; + hsync_reg = HSYNC_B; + vtot_reg = VTOTAL_B; + vblank_reg = VBLANK_B; + vsync_reg = VSYNC_B; + pipesrc_reg = PIPEBSRC; + dspstride_reg = DSPBSTRIDE; + dsplinoff_reg = DSPBLINOFF; + dsptileoff_reg = DSPBTILEOFF; + dspsize_reg = DSPBSIZE; + dsppos_reg = DSPBPOS; + dspsurf_reg = DSPBSURF; + dspcntr_reg = DSPBCNTR; + palette_reg = PALETTE_B; + dspstatus_reg = PIPEBSTAT; + + /* values */ + dpll_val = dev_priv->saveDPLL_B & ~DPLL_VCO_ENABLE; + fp_val = dev_priv->saveFPB0; + pipeconf_val = dev_priv->savePIPEBCONF; + htot_val = dev_priv->saveHTOTAL_B; + hblank_val = dev_priv->saveHBLANK_B; + hsync_val = dev_priv->saveHSYNC_B; + vtot_val = dev_priv->saveVTOTAL_B; + vblank_val = dev_priv->saveVBLANK_B; + vsync_val = dev_priv->saveVSYNC_B; + pipesrc_val = dev_priv->savePIPEBSRC; + dspstride_val = dev_priv->saveDSPBSTRIDE; + dsplinoff_val = dev_priv->saveDSPBLINOFF; + dsptileoff_val = dev_priv->saveDSPBTILEOFF; + dspsize_val = dev_priv->saveDSPBSIZE; + dsppos_val = dev_priv->saveDSPBPOS; + dspsurf_val = dev_priv->saveDSPBSURF; + dspcntr_val = dev_priv->saveDSPBCNTR; + dspstatus_val = dev_priv->saveDSPBSTATUS; + palette_val = dev_priv->save_palette_b; + break; + case 2: + reg_offset = MIPIC_REG_OFFSET; + + /* register */ + pipeconf_reg = PIPECCONF; + htot_reg = HTOTAL_C; + hblank_reg = HBLANK_C; + hsync_reg = HSYNC_C; + vtot_reg = VTOTAL_C; + vblank_reg = VBLANK_C; + vsync_reg = VSYNC_C; + pipesrc_reg = PIPECSRC; + dspstride_reg = DSPCSTRIDE; + dsplinoff_reg = DSPCLINOFF; + dsptileoff_reg = DSPCTILEOFF; + dspsize_reg = DSPCSIZE; + dsppos_reg = DSPCPOS; + dspsurf_reg = DSPCSURF; + mipi_reg = MIPI_C; + dspcntr_reg = DSPCCNTR; + palette_reg = PALETTE_C; + dspstatus_reg = PIPECSTAT; + + /* values */ + pipeconf_val = dev_priv->savePIPECCONF; + htot_val = dev_priv->saveHTOTAL_C; + hblank_val = dev_priv->saveHBLANK_C; + hsync_val = dev_priv->saveHSYNC_C; + vtot_val = dev_priv->saveVTOTAL_C; + vblank_val = dev_priv->saveVBLANK_C; + vsync_val = dev_priv->saveVSYNC_C; + pipesrc_val = dev_priv->savePIPECSRC; + dspstride_val = dev_priv->saveDSPCSTRIDE; + dsplinoff_val = dev_priv->saveDSPCLINOFF; + dsptileoff_val = dev_priv->saveDSPCTILEOFF; + dspsize_val = dev_priv->saveDSPCSIZE; + dsppos_val = dev_priv->saveDSPCPOS; + dspsurf_val = dev_priv->saveDSPCSURF; + dspstatus_val = dev_priv->saveDSPCSTATUS; + mipi_val = dev_priv->saveMIPI_C; + dspcntr_val = dev_priv->saveDSPCCNTR; + palette_val = dev_priv->save_palette_c; + + dsi_config = dev_priv->dsi_configs[1]; + break; + default: + DRM_ERROR("%s, invalid pipe number.\n", __func__); + return -EINVAL; + } + + /* Make sure VGA plane is off. it initializes to on after reset!*/ + PSB_WVDC32(0x80000000, VGACNTRL); + if (pipe == 1) { + PSB_WVDC32(dpll_val & ~DPLL_VCO_ENABLE, dpll_reg); + PSB_RVDC32(dpll_reg); + + PSB_WVDC32(fp_val, fp_reg); + } else { + dpll = PSB_RVDC32(dpll_reg); + + if (!(dpll & DPLL_VCO_ENABLE)) { + + /* When ungating power of DPLL, needs to wait 0.5us before enable the VCO */ + if (dpll & MDFLD_PWR_GATE_EN) { + dpll &= ~MDFLD_PWR_GATE_EN; + PSB_WVDC32(dpll, dpll_reg); + udelay(500); /* FIXME: 1 ? */ + } + + PSB_WVDC32(fp_val, fp_reg); + PSB_WVDC32(dpll_val, dpll_reg); + /* FIXME_MDFLD PO - change 500 to 1 after PO */ + udelay(500); + + dpll_val |= DPLL_VCO_ENABLE; + PSB_WVDC32(dpll_val, dpll_reg); + PSB_RVDC32(dpll_reg); + + /* wait for DSI PLL to lock */ + while ((timeout < 20000) && !(PSB_RVDC32(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) { + udelay(150); + timeout++; + } + + if (timeout == 20000) { + DRM_ERROR("%s, can't lock DSIPLL.\n", + __func__); + return -EINVAL; + } + } + } + /* Restore mode */ + PSB_WVDC32(htot_val, htot_reg); + PSB_WVDC32(hblank_val, hblank_reg); + PSB_WVDC32(hsync_val, hsync_reg); + PSB_WVDC32(vtot_val, vtot_reg); + PSB_WVDC32(vblank_val, vblank_reg); + PSB_WVDC32(vsync_val, vsync_reg); + PSB_WVDC32(pipesrc_val, pipesrc_reg); + PSB_WVDC32(dspstatus_val, dspstatus_reg); + + /* Set up the plane */ + PSB_WVDC32(dspstride_val, dspstride_reg); + PSB_WVDC32(dsplinoff_val, dsplinoff_reg); + PSB_WVDC32(dsptileoff_val, dsptileoff_reg); + PSB_WVDC32(dspsize_val, dspsize_reg); + PSB_WVDC32(dsppos_val, dsppos_reg); + PSB_WVDC32(dspsurf_val, dspsurf_reg); + + if (pipe == 1) { + PSB_WVDC32(dev_priv->savePFIT_CONTROL, PFIT_CONTROL); + PSB_WVDC32(dev_priv->savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS); + PSB_WVDC32(dev_priv->saveHDMIPHYMISCCTL, HDMIPHYMISCCTL); + PSB_WVDC32(dev_priv->saveHDMIB_CONTROL, HDMIB_CONTROL); + + } else { + /* Set up pipe related registers */ + PSB_WVDC32(mipi_val, mipi_reg); + /* Setup MIPI adapter + MIPI IP registers */ + mdfld_dsi_controller_init(dsi_config, pipe); + msleep(20); + } + /* Enable the plane */ + PSB_WVDC32(dspcntr_val, dspcntr_reg); + msleep(20); + /* Enable the pipe */ + PSB_WVDC32(pipeconf_val, pipeconf_reg); + + for (i = 0; i < 256; i++) + PSB_WVDC32(palette_val[i], palette_reg + (i<<2)); + if (pipe == 1) + return 0; + if (!mdfld_panel_dpi(dev)) + mdfld_enable_te(dev, pipe); + return 0; +} + +/** + * mdfld_restore_cursor_overlay_registers - restore cursor + * @dev: our device + * + * Restore the cursor and overlay state that was saved earlier + */ +static int mdfld_restore_cursor_overlay_registers(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + + /* Enable Cursor A */ + PSB_WVDC32(dev_priv->saveDSPACURSOR_CTRL, CURACNTR); + PSB_WVDC32(dev_priv->saveDSPACURSOR_POS, CURAPOS); + PSB_WVDC32(dev_priv->saveDSPACURSOR_BASE, CURABASE); + + PSB_WVDC32(dev_priv->saveDSPBCURSOR_CTRL, CURBCNTR); + PSB_WVDC32(dev_priv->saveDSPBCURSOR_POS, CURBPOS); + PSB_WVDC32(dev_priv->saveDSPBCURSOR_BASE, CURBBASE); + + PSB_WVDC32(dev_priv->saveDSPCCURSOR_CTRL, CURCCNTR); + PSB_WVDC32(dev_priv->saveDSPCCURSOR_POS, CURCPOS); + PSB_WVDC32(dev_priv->saveDSPCCURSOR_BASE, CURCBASE); + + /* Restore HW overlay */ + PSB_WVDC32(dev_priv->saveOV_OVADD, OV_OVADD); + PSB_WVDC32(dev_priv->saveOV_OGAMC0, OV_OGAMC0); + PSB_WVDC32(dev_priv->saveOV_OGAMC1, OV_OGAMC1); + PSB_WVDC32(dev_priv->saveOV_OGAMC2, OV_OGAMC2); + PSB_WVDC32(dev_priv->saveOV_OGAMC3, OV_OGAMC3); + PSB_WVDC32(dev_priv->saveOV_OGAMC4, OV_OGAMC4); + PSB_WVDC32(dev_priv->saveOV_OGAMC5, OV_OGAMC5); + + PSB_WVDC32(dev_priv->saveOV_OVADD_C, OV_OVADD + OV_C_OFFSET); + PSB_WVDC32(dev_priv->saveOV_OGAMC0_C, OV_OGAMC0 + OV_C_OFFSET); + PSB_WVDC32(dev_priv->saveOV_OGAMC1_C, OV_OGAMC1 + OV_C_OFFSET); + PSB_WVDC32(dev_priv->saveOV_OGAMC2_C, OV_OGAMC2 + OV_C_OFFSET); + PSB_WVDC32(dev_priv->saveOV_OGAMC3_C, OV_OGAMC3 + OV_C_OFFSET); + PSB_WVDC32(dev_priv->saveOV_OGAMC4_C, OV_OGAMC4 + OV_C_OFFSET); + PSB_WVDC32(dev_priv->saveOV_OGAMC5_C, OV_OGAMC5 + OV_C_OFFSET); + + return 0; +} + +/** + * mdfld_save_display_registers - save registers lost on suspend + * @dev: our DRM device + * + * Save the state we need in order to be able to restore the interface + * upon resume from suspend + */ +static int mdfld_save_registers(struct drm_device *dev) +{ + /* FIXME: We need to shut down panels here if using them + and once the right bits are merged */ + mdfld_save_cursor_overlay_registers(dev); + mdfld_save_display_registers(dev, 0); + mdfld_save_display_registers(dev, 0); + mdfld_save_display_registers(dev, 2); + mdfld_save_display_registers(dev, 1); + mdfld_disable_crtc(dev, 0); + mdfld_disable_crtc(dev, 2); + mdfld_disable_crtc(dev, 1); + return 0; +} + +/** + * mdfld_restore_display_registers - restore lost register state + * @dev: our DRM device + * + * Restore register state that was lost during suspend and resume. + */ +static int mdfld_restore_registers(struct drm_device *dev) +{ + mdfld_restore_display_registers(dev, 1); + mdfld_restore_display_registers(dev, 0); + mdfld_restore_display_registers(dev, 2); + mdfld_restore_cursor_overlay_registers(dev); + return 0; +} + +static int mdfld_power_down(struct drm_device *dev) +{ + /* FIXME */ + return 0; +} + +static int mdfld_power_up(struct drm_device *dev) +{ + /* FIXME */ + return 0; +} + +const struct psb_ops mdfld_chip_ops = { + .name = "Medfield", + .accel_2d = 0, + .pipes = 3, + .crtcs = 2, + .sgx_offset = MRST_SGX_OFFSET, + + .chip_setup = mid_chip_setup, + + .crtc_helper = &mdfld_helper_funcs, + .crtc_funcs = &mdfld_intel_crtc_funcs, + + .output_init = mdfld_output_init, + +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + .backlight_init = mdfld_backlight_init, +#endif + + .init_pm = mdfld_init_pm, + .save_regs = mdfld_save_registers, + .restore_regs = mdfld_restore_registers, + .power_down = mdfld_power_down, + .power_up = mdfld_power_up, +}; + diff --git a/drivers/staging/gma500/mdfld_dsi_dbi.c b/drivers/staging/gma500/mdfld_dsi_dbi.c new file mode 100644 index 0000000..02e17c9 --- /dev/null +++ b/drivers/staging/gma500/mdfld_dsi_dbi.c @@ -0,0 +1,760 @@ +/* + * 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_dbi.h" +#include "mdfld_dsi_dbi_dpu.h" +#include "mdfld_dsi_pkg_sender.h" + +#include "power.h" +#include <linux/pm_runtime.h> + +int enable_gfx_rtpm; + +extern struct drm_device *gpDrmDevice; +extern int gfxrtdelay; +int enter_dsr; +struct mdfld_dsi_dbi_output *gdbi_output; +extern bool gbgfxsuspended; +extern int enable_gfx_rtpm; +extern int gfxrtdelay; + +#define MDFLD_DSR_MAX_IDLE_COUNT 2 + +/* + * set refreshing area + */ +int mdfld_dsi_dbi_update_area(struct mdfld_dsi_dbi_output *dbi_output, + u16 x1, u16 y1, u16 x2, u16 y2) +{ + struct mdfld_dsi_pkg_sender *sender = + mdfld_dsi_encoder_get_pkg_sender(&dbi_output->base); + u8 param[4]; + u8 cmd; + int err; + + if (!sender) { + WARN_ON(1); + return -EINVAL; + } + + /* Set column */ + cmd = DCS_SET_COLUMN_ADDRESS; + param[0] = x1 >> 8; + param[1] = x1; + param[2] = x2 >> 8; + param[3] = x2; + + err = mdfld_dsi_send_dcs(sender, + cmd, + param, + 4, + CMD_DATA_SRC_SYSTEM_MEM, + MDFLD_DSI_QUEUE_PACKAGE); + if (err) { + dev_err(sender->dev->dev, "DCS 0x%x sent failed\n", cmd); + goto err_out; + } + + /* Set page */ + cmd = DCS_SET_PAGE_ADDRESS; + param[0] = y1 >> 8; + param[1] = y1; + param[2] = y2 >> 8; + param[3] = y2; + + err = mdfld_dsi_send_dcs(sender, + cmd, + param, + 4, + CMD_DATA_SRC_SYSTEM_MEM, + MDFLD_DSI_QUEUE_PACKAGE); + if (err) { + dev_err(sender->dev->dev, "DCS 0x%x sent failed\n", cmd); + goto err_out; + } + + /*update screen*/ + err = mdfld_dsi_send_dcs(sender, + write_mem_start, + NULL, + 0, + CMD_DATA_SRC_PIPE, + MDFLD_DSI_QUEUE_PACKAGE); + if (err) { + dev_err(sender->dev->dev, "DCS 0x%x sent failed\n", cmd); + goto err_out; + } + mdfld_dsi_cmds_kick_out(sender); +err_out: + return err; +} + +/* + * set panel's power state + */ +int mdfld_dsi_dbi_update_power(struct mdfld_dsi_dbi_output *dbi_output, + int mode) +{ + struct drm_device *dev = dbi_output->dev; + struct mdfld_dsi_pkg_sender *sender = + mdfld_dsi_encoder_get_pkg_sender(&dbi_output->base); + u8 param = 0; + u32 err = 0; + + if (!sender) { + WARN_ON(1); + return -EINVAL; + } + + if (mode == DRM_MODE_DPMS_ON) { + /* Exit sleep mode */ + err = mdfld_dsi_send_dcs(sender, + DCS_EXIT_SLEEP_MODE, + NULL, + 0, + CMD_DATA_SRC_SYSTEM_MEM, + MDFLD_DSI_QUEUE_PACKAGE); + if (err) { + dev_err(dev->dev, "DCS 0x%x sent failed\n", + DCS_EXIT_SLEEP_MODE); + goto power_err; + } + + /* Set display on */ + err = mdfld_dsi_send_dcs(sender, + DCS_SET_DISPLAY_ON, + NULL, + 0, + CMD_DATA_SRC_SYSTEM_MEM, + MDFLD_DSI_QUEUE_PACKAGE); + if (err) { + dev_err(dev->dev, "DCS 0x%x sent failed\n", + DCS_SET_DISPLAY_ON); + goto power_err; + } + + /* set tear effect on */ + err = mdfld_dsi_send_dcs(sender, + DCS_SET_TEAR_ON, + ¶m, + 1, + CMD_DATA_SRC_SYSTEM_MEM, + MDFLD_DSI_QUEUE_PACKAGE); + if (err) { + dev_err(dev->dev, "DCS 0x%x sent failed\n", + set_tear_on); + goto power_err; + } + + /** + * FIXME: remove this later + */ + err = mdfld_dsi_send_dcs(sender, + DCS_WRITE_MEM_START, + NULL, + 0, + CMD_DATA_SRC_PIPE, + MDFLD_DSI_QUEUE_PACKAGE); + if (err) { + dev_err(dev->dev, "DCS 0x%x sent failed\n", + DCS_WRITE_MEM_START); + goto power_err; + } + } else { + /* Set tear effect off */ + err = mdfld_dsi_send_dcs(sender, + DCS_SET_TEAR_OFF, + NULL, + 0, + CMD_DATA_SRC_SYSTEM_MEM, + MDFLD_DSI_QUEUE_PACKAGE); + if (err) { + dev_err(dev->dev, "DCS 0x%x sent failed\n", + DCS_SET_TEAR_OFF); + goto power_err; + } + + /* Turn display off */ + err = mdfld_dsi_send_dcs(sender, + DCS_SET_DISPLAY_OFF, + NULL, + 0, + CMD_DATA_SRC_SYSTEM_MEM, + MDFLD_DSI_QUEUE_PACKAGE); + if (err) { + dev_err(dev->dev, "DCS 0x%x sent failed\n", + DCS_SET_DISPLAY_OFF); + goto power_err; + } + + /* Now enter sleep mode */ + err = mdfld_dsi_send_dcs(sender, + DCS_ENTER_SLEEP_MODE, + NULL, + 0, + CMD_DATA_SRC_SYSTEM_MEM, + MDFLD_DSI_QUEUE_PACKAGE); + if (err) { + dev_err(dev->dev, "DCS 0x%x sent failed\n", + DCS_ENTER_SLEEP_MODE); + goto power_err; + } + } + mdfld_dsi_cmds_kick_out(sender); +power_err: + return err; +} + +/* + * send a generic DCS command with a parameter list + */ +int mdfld_dsi_dbi_send_dcs(struct mdfld_dsi_dbi_output *dbi_output, + u8 dcs, u8 *param, u32 num, u8 data_src) +{ + struct mdfld_dsi_pkg_sender *sender = + mdfld_dsi_encoder_get_pkg_sender(&dbi_output->base); + int ret; + + if (!sender) { + WARN_ON(1); + return -EINVAL; + } + + ret = mdfld_dsi_send_dcs(sender, + dcs, + param, + num, + data_src, + MDFLD_DSI_SEND_PACKAGE); + + return ret; +} + +/* + * Enter DSR + */ +void mdfld_dsi_dbi_enter_dsr(struct mdfld_dsi_dbi_output *dbi_output, int pipe) +{ + u32 reg_val; + struct drm_device *dev = dbi_output->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc = dbi_output->base.base.crtc; + struct psb_intel_crtc *psb_crtc = (crtc) ? + to_psb_intel_crtc(crtc) : NULL; + u32 dpll_reg = MRST_DPLL_A; + u32 pipeconf_reg = PIPEACONF; + u32 dspcntr_reg = DSPACNTR; + + if (!dbi_output) + return; + + /* FIXME check if can go */ + dev_priv->is_in_idle = true; + + gdbi_output = dbi_output; + if ((dbi_output->mode_flags & MODE_SETTING_ON_GOING) || + (psb_crtc && psb_crtc->mode_flags & MODE_SETTING_ON_GOING)) + return; + + if (pipe == 2) { + dpll_reg = MRST_DPLL_A; + pipeconf_reg = PIPECCONF; + dspcntr_reg = DSPCCNTR; + } + + if (!gma_power_begin(dev, true)) { + dev_err(dev->dev, "hw begin failed\n"); + return; + } + /* Disable te interrupts */ + mdfld_disable_te(dev, pipe); + + /* Disable plane */ + reg_val = REG_READ(dspcntr_reg); + if (!(reg_val & DISPLAY_PLANE_ENABLE)) { + REG_WRITE(dspcntr_reg, reg_val & ~DISPLAY_PLANE_ENABLE); + REG_READ(dspcntr_reg); + } + + /* Disable pipe */ + reg_val = REG_READ(pipeconf_reg); + if (!(reg_val & DISPLAY_PLANE_ENABLE)) { + reg_val &= ~DISPLAY_PLANE_ENABLE; + reg_val |= (PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF); + REG_WRITE(pipeconf_reg, reg_val); + REG_READ(pipeconf_reg); + mdfldWaitForPipeDisable(dev, pipe); + } + + /* Disable DPLL */ + reg_val = REG_READ(dpll_reg); + if (!(reg_val & DPLL_VCO_ENABLE)) { + reg_val &= ~DPLL_VCO_ENABLE; + REG_WRITE(dpll_reg, reg_val); + REG_READ(dpll_reg); + udelay(500); + } + + gma_power_end(dev); + dbi_output->mode_flags |= MODE_SETTING_IN_DSR; + if (pipe == 2) { + enter_dsr = 1; + /* pm_schedule_suspend(&dev->pdev->dev, gfxrtdelay); */ + } +} + +static void mdfld_dbi_output_exit_dsr(struct mdfld_dsi_dbi_output *dbi_output, + int pipe) +{ + struct drm_device *dev = dbi_output->dev; + struct drm_crtc *crtc = dbi_output->base.base.crtc; + struct psb_intel_crtc *psb_crtc = (crtc) ? + to_psb_intel_crtc(crtc) : NULL; + u32 reg_val; + u32 dpll_reg = MRST_DPLL_A; + u32 pipeconf_reg = PIPEACONF; + u32 dspcntr_reg = DSPACNTR; + u32 reg_offset = 0; + + /*if mode setting on-going, back off*/ + if ((dbi_output->mode_flags & MODE_SETTING_ON_GOING) || + (psb_crtc && psb_crtc->mode_flags & MODE_SETTING_ON_GOING)) + return; + + if (pipe == 2) { + dpll_reg = MRST_DPLL_A; + pipeconf_reg = PIPECCONF; + dspcntr_reg = DSPCCNTR; + reg_offset = MIPIC_REG_OFFSET; + } + + if (!gma_power_begin(dev, true)) { + dev_err(dev->dev, "hw begin failed\n"); + return; + } + + /* Enable DPLL */ + reg_val = REG_READ(dpll_reg); + if (!(reg_val & DPLL_VCO_ENABLE)) { + if (reg_val & MDFLD_PWR_GATE_EN) { + reg_val &= ~MDFLD_PWR_GATE_EN; + REG_WRITE(dpll_reg, reg_val); + REG_READ(dpll_reg); + udelay(500); + } + + reg_val |= DPLL_VCO_ENABLE; + REG_WRITE(dpll_reg, reg_val); + REG_READ(dpll_reg); + udelay(500); + + /* Add timeout */ + while (!(REG_READ(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) + cpu_relax(); + } + + /* Enable pipe */ + reg_val = REG_READ(pipeconf_reg); + if (!(reg_val & PIPEACONF_ENABLE)) { + reg_val |= PIPEACONF_ENABLE; + REG_WRITE(pipeconf_reg, reg_val); + REG_READ(pipeconf_reg); + udelay(500); + mdfldWaitForPipeEnable(dev, pipe); + } + + /* Enable plane */ + reg_val = REG_READ(dspcntr_reg); + if (!(reg_val & DISPLAY_PLANE_ENABLE)) { + reg_val |= DISPLAY_PLANE_ENABLE; + REG_WRITE(dspcntr_reg, reg_val); + REG_READ(dspcntr_reg); + udelay(500); + } + + /* Enable TE interrupt on this pipe */ + mdfld_enable_te(dev, pipe); + gma_power_end(dev); + + /*clean IN_DSR flag*/ + dbi_output->mode_flags &= ~MODE_SETTING_IN_DSR; +} + +/* + * Exit from DSR + */ +void mdfld_dsi_dbi_exit_dsr(struct drm_device *dev, u32 update_src) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct mdfld_dbi_dsr_info *dsr_info = dev_priv->dbi_dsr_info; + struct mdfld_dsi_dbi_output **dbi_output; + int i; + int pipe; + + /* FIXME can go ? */ + dev_priv->is_in_idle = false; + dbi_output = dsr_info->dbi_outputs; + +#ifdef CONFIG_PM_RUNTIME + if (!enable_gfx_rtpm) { +/* pm_runtime_allow(&gpDrmDevice->pdev->dev); */ +/* schedule_delayed_work(&rtpm_work, 30 * 1000);*/ /* FIXME: HZ ? */ + } +#endif + + /* For each output, exit dsr */ + for (i = 0; i < dsr_info->dbi_output_num; i++) { + /* If panel has been turned off, skip */ + if (!dbi_output[i] || !dbi_output[i]->dbi_panel_on) + continue; + pipe = dbi_output[i]->channel_num ? 2 : 0; + enter_dsr = 0; + mdfld_dbi_output_exit_dsr(dbi_output[i], pipe); + } + dev_priv->dsr_fb_update |= update_src; +} + +static bool mdfld_dbi_is_in_dsr(struct drm_device *dev) +{ + if (REG_READ(MRST_DPLL_A) & DPLL_VCO_ENABLE) + return false; + if ((REG_READ(PIPEACONF) & PIPEACONF_ENABLE) || + (REG_READ(PIPECCONF) & PIPEACONF_ENABLE)) + return false; + if ((REG_READ(DSPACNTR) & DISPLAY_PLANE_ENABLE) || + (REG_READ(DSPCCNTR) & DISPLAY_PLANE_ENABLE)) + return false; + + return true; +} + +/* Periodically update dbi panel */ +void mdfld_dbi_update_panel(struct drm_device *dev, int pipe) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct mdfld_dbi_dsr_info *dsr_info = dev_priv->dbi_dsr_info; + struct mdfld_dsi_dbi_output **dbi_outputs; + struct mdfld_dsi_dbi_output *dbi_output; + int i; + int can_enter_dsr = 0; + u32 damage_mask; + + dbi_outputs = dsr_info->dbi_outputs; + dbi_output = pipe ? dbi_outputs[1] : dbi_outputs[0]; + + if (!dbi_output) + return; + + if (pipe == 0) + damage_mask = dev_priv->dsr_fb_update & MDFLD_DSR_DAMAGE_MASK_0; + else if (pipe == 2) + damage_mask = dev_priv->dsr_fb_update & MDFLD_DSR_DAMAGE_MASK_2; + else + return; + + /* If FB is damaged and panel is on update on-panel FB */ + if (damage_mask && dbi_output->dbi_panel_on) { + dbi_output->dsr_fb_update_done = false; + + if (dbi_output->p_funcs->update_fb) + dbi_output->p_funcs->update_fb(dbi_output, pipe); + + if (dev_priv->dsr_enable && dbi_output->dsr_fb_update_done) + dev_priv->dsr_fb_update &= ~damage_mask; + + /*clean IN_DSR flag*/ + dbi_output->mode_flags &= ~MODE_SETTING_IN_DSR; + + dbi_output->dsr_idle_count = 0; + } else { + dbi_output->dsr_idle_count++; + } + + switch (dsr_info->dbi_output_num) { + case 1: + if (dbi_output->dsr_idle_count > MDFLD_DSR_MAX_IDLE_COUNT) + can_enter_dsr = 1; + break; + case 2: + if (dbi_outputs[0]->dsr_idle_count > MDFLD_DSR_MAX_IDLE_COUNT + && dbi_outputs[1]->dsr_idle_count > MDFLD_DSR_MAX_IDLE_COUNT) + can_enter_dsr = 1; + break; + default: + DRM_ERROR("Wrong DBI output number\n"); + } + + /* Try to enter DSR */ + if (can_enter_dsr) { + for (i = 0; i < dsr_info->dbi_output_num; i++) { + if (!mdfld_dbi_is_in_dsr(dev) && dbi_outputs[i] && + !(dbi_outputs[i]->mode_flags & MODE_SETTING_ON_GOING)) { + mdfld_dsi_dbi_enter_dsr(dbi_outputs[i], + dbi_outputs[i]->channel_num ? 2 : 0); +#if 0 + enter_dsr = 1; + pr_err("%s: enter_dsr = 1\n", __func__); +#endif + } + } + /*schedule rpm suspend after gfxrtdelay*/ +#ifdef CONFIG_GFX_RTPM + if (!dev_priv->rpm_enabled + || !enter_dsr + /* || (REG_READ(HDMIB_CONTROL) & HDMIB_PORT_EN) */ + || pm_schedule_suspend(&dev->pdev->dev, gfxrtdelay)) + dev_warn(dev->dev, + "Runtime PM schedule suspend failed, rpm %d\n", + dev_priv->rpm_enabled); +#endif + } +} + +int mdfld_dbi_dsr_init(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct mdfld_dbi_dsr_info *dsr_info = dev_priv->dbi_dsr_info; + + if (!dsr_info || IS_ERR(dsr_info)) { + dsr_info = kzalloc(sizeof(struct mdfld_dbi_dsr_info), + GFP_KERNEL); + if (!dsr_info) { + dev_err(dev->dev, "No memory\n"); + return -ENOMEM; + } + dev_priv->dbi_dsr_info = dsr_info; + } + return 0; +} + +void mdfld_dbi_dsr_exit(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct mdfld_dbi_dsr_info *dsr_info = dev_priv->dbi_dsr_info; + + if (dsr_info) { + kfree(dsr_info); + dev_priv->dbi_dsr_info = NULL; + } +} + +void mdfld_dsi_controller_dbi_init(struct mdfld_dsi_config *dsi_config, + int pipe) +{ + struct drm_device *dev = dsi_config->dev; + u32 reg_offset = pipe ? MIPIC_REG_OFFSET : 0; + int lane_count = dsi_config->lane_count; + u32 val = 0; + + dev_dbg(dev->dev, "Init DBI interface on pipe %d...\n", pipe); + + /* Un-ready device */ + REG_WRITE((MIPIA_DEVICE_READY_REG + reg_offset), 0x00000000); + + /* Init dsi adapter before kicking off */ + REG_WRITE((MIPIA_CONTROL_REG + reg_offset), 0x00000018); + + /* TODO: figure out how to setup these registers */ + REG_WRITE((MIPIA_DPHY_PARAM_REG + reg_offset), 0x150c3408); + REG_WRITE((MIPIA_CLK_LANE_SWITCH_TIME_CNT_REG + reg_offset), + 0x000a0014); + REG_WRITE((MIPIA_DBI_BW_CTRL_REG + reg_offset), 0x00000400); + REG_WRITE((MIPIA_DBI_FIFO_THROTTLE_REG + reg_offset), 0x00000001); + REG_WRITE((MIPIA_HS_LS_DBI_ENABLE_REG + reg_offset), 0x00000000); + + /* Enable all interrupts */ + REG_WRITE((MIPIA_INTR_EN_REG + reg_offset), 0xffffffff); + /* Max value: 20 clock cycles of txclkesc */ + REG_WRITE((MIPIA_TURN_AROUND_TIMEOUT_REG + reg_offset), 0x0000001f); + /* Min 21 txclkesc, max: ffffh */ + REG_WRITE((MIPIA_DEVICE_RESET_TIMER_REG + reg_offset), 0x0000ffff); + /* Min: 7d0 max: 4e20 */ + REG_WRITE((MIPIA_INIT_COUNT_REG + reg_offset), 0x00000fa0); + + /* Set up func_prg */ + val |= lane_count; + val |= (dsi_config->channel_num << DSI_DBI_VIRT_CHANNEL_OFFSET); + val |= DSI_DBI_COLOR_FORMAT_OPTION2; + REG_WRITE((MIPIA_DSI_FUNC_PRG_REG + reg_offset), val); + + REG_WRITE((MIPIA_HS_TX_TIMEOUT_REG + reg_offset), 0x3fffff); + REG_WRITE((MIPIA_LP_RX_TIMEOUT_REG + reg_offset), 0xffff); + + /* De-assert dbi_stall when half of DBI FIFO is empty */ + /* REG_WRITE((MIPIA_DBI_FIFO_THROTTLE_REG + reg_offset), 0x00000000); */ + + REG_WRITE((MIPIA_HIGH_LOW_SWITCH_COUNT_REG + reg_offset), 0x46); + REG_WRITE((MIPIA_EOT_DISABLE_REG + reg_offset), 0x00000000); + REG_WRITE((MIPIA_LP_BYTECLK_REG + reg_offset), 0x00000004); + REG_WRITE((MIPIA_DEVICE_READY_REG + reg_offset), 0x00000001); +} + +#if 0 +/*DBI encoder helper funcs*/ +static const struct drm_encoder_helper_funcs mdfld_dsi_dbi_helper_funcs = { + .dpms = mdfld_dsi_dbi_dpms, + .mode_fixup = mdfld_dsi_dbi_mode_fixup, + .prepare = mdfld_dsi_dbi_prepare, + .mode_set = mdfld_dsi_dbi_mode_set, + .commit = mdfld_dsi_dbi_commit, +}; + +/*DBI encoder funcs*/ +static const struct drm_encoder_funcs mdfld_dsi_dbi_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +#endif + +/* + * Init DSI DBI encoder. + * Allocate an mdfld_dsi_encoder and attach it to given @dsi_connector + * return pointer of newly allocated DBI encoder, NULL on error + */ +struct mdfld_dsi_encoder *mdfld_dsi_dbi_init(struct drm_device *dev, + struct mdfld_dsi_connector *dsi_connector, + struct panel_funcs *p_funcs) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct mdfld_dsi_dbi_output *dbi_output = NULL; + struct mdfld_dsi_config *dsi_config; + struct drm_connector *connector = NULL; + struct drm_encoder *encoder = NULL; + struct drm_display_mode *fixed_mode = NULL; + struct psb_gtt *pg = dev_priv ? (&dev_priv->gtt) : NULL; + struct mdfld_dbi_dpu_info *dpu_info = dev_priv ? (dev_priv->dbi_dpu_info) : NULL; + struct mdfld_dbi_dsr_info *dsr_info = dev_priv ? (dev_priv->dbi_dsr_info) : NULL; + u32 data = 0; + int pipe; + int ret; + + if (!pg || !dsi_connector || !p_funcs) { + WARN_ON(1); + return NULL; + } + + dsi_config = mdfld_dsi_get_config(dsi_connector); + pipe = dsi_connector->pipe; + + /*panel hard-reset*/ + if (p_funcs->reset) { + ret = p_funcs->reset(pipe); + if (ret) { + DRM_ERROR("Panel %d hard-reset failed\n", pipe); + return NULL; + } + } + /* Panel drvIC init */ + if (p_funcs->drv_ic_init) + p_funcs->drv_ic_init(dsi_config, pipe); + + /* Panel power mode detect */ + ret = mdfld_dsi_get_power_mode(dsi_config, + &data, + MDFLD_DSI_HS_TRANSMISSION); + if (ret) { + DRM_ERROR("Panel %d get power mode failed\n", pipe); + dsi_connector->status = connector_status_disconnected; + } else { + DRM_INFO("pipe %d power mode 0x%x\n", pipe, data); + dsi_connector->status = connector_status_connected; + } + + /*TODO: get panel info from DDB*/ + + dbi_output = kzalloc(sizeof(struct mdfld_dsi_dbi_output), GFP_KERNEL); + if (!dbi_output) { + dev_err(dev->dev, "No memory\n"); + return NULL; + } + + if (dsi_connector->pipe == 0) { + dbi_output->channel_num = 0; + dev_priv->dbi_output = dbi_output; + } else if (dsi_connector->pipe == 2) { + dbi_output->channel_num = 1; + dev_priv->dbi_output2 = dbi_output; + } else { + dev_err(dev->dev, "only support 2 DSI outputs\n"); + goto out_err1; + } + + dbi_output->dev = dev; + dbi_output->p_funcs = p_funcs; + fixed_mode = dsi_config->fixed_mode; + dbi_output->panel_fixed_mode = fixed_mode; + + /* Create drm encoder object */ + connector = &dsi_connector->base.base; + encoder = &dbi_output->base.base; + drm_encoder_init(dev, + encoder, + p_funcs->encoder_funcs, + DRM_MODE_ENCODER_MIPI); + drm_encoder_helper_add(encoder, p_funcs->encoder_helper_funcs); + + /* Attach to given connector */ + drm_mode_connector_attach_encoder(connector, encoder); + + /* Set possible CRTCs and clones */ + if (dsi_connector->pipe) { + encoder->possible_crtcs = (1 << 2); + encoder->possible_clones = (1 << 1); + } else { + encoder->possible_crtcs = (1 << 0); + encoder->possible_clones = (1 << 0); + } + + dev_priv->dsr_fb_update = 0; + dev_priv->dsr_enable = false; + dev_priv->exit_idle = mdfld_dsi_dbi_exit_dsr; + + dbi_output->first_boot = true; + dbi_output->mode_flags = MODE_SETTING_IN_ENCODER; + + /* Add this output to dpu_info if in DPU mode */ + if (dpu_info && dsi_connector->status == connector_status_connected) { + if (dsi_connector->pipe == 0) + dpu_info->dbi_outputs[0] = dbi_output; + else + dpu_info->dbi_outputs[1] = dbi_output; + + dpu_info->dbi_output_num++; + } else if (dsi_connector->status == connector_status_connected) { + /* Add this output to dsr_info if not */ + if (dsi_connector->pipe == 0) + dsr_info->dbi_outputs[0] = dbi_output; + else + dsr_info->dbi_outputs[1] = dbi_output; + + dsr_info->dbi_output_num++; + } + return &dbi_output->base; +out_err1: + kfree(dbi_output); + return NULL; +} diff --git a/drivers/staging/gma500/mdfld_dsi_dbi.h b/drivers/staging/gma500/mdfld_dsi_dbi.h new file mode 100644 index 0000000..dc6242c --- /dev/null +++ b/drivers/staging/gma500/mdfld_dsi_dbi.h @@ -0,0 +1,176 @@ +/* + * 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_DBI_H__ +#define __MDFLD_DSI_DBI_H__ + +#include <linux/backlight.h> +#include <drm/drmP.h> +#include <drm/drm.h> +#include <drm/drm_crtc.h> +#include <drm/drm_edid.h> + +#include "psb_drv.h" +#include "psb_intel_drv.h" +#include "psb_intel_reg.h" +#include "power.h" + +#include "mdfld_dsi_output.h" +#include "mdfld_output.h" + +#define DRM_MODE_ENCODER_MIPI 5 + + +/* + * DBI encoder which inherits from mdfld_dsi_encoder + */ +struct mdfld_dsi_dbi_output { + struct mdfld_dsi_encoder base; + struct drm_display_mode *panel_fixed_mode; + u8 last_cmd; + u8 lane_count; + u8 channel_num; + struct drm_device *dev; + + /* Backlight operations */ + + /* DSR timer */ + u32 dsr_idle_count; + bool dsr_fb_update_done; + + /* Mode setting flags */ + u32 mode_flags; + + /* Panel status */ + bool dbi_panel_on; + bool first_boot; + struct panel_funcs *p_funcs; + + /* DPU */ + u32 *dbi_cb_addr; + u32 dbi_cb_phy; + spinlock_t cb_lock; + u32 cb_write; +}; + +#define MDFLD_DSI_DBI_OUTPUT(dsi_encoder) \ + container_of(dsi_encoder, struct mdfld_dsi_dbi_output, base) + +struct mdfld_dbi_dsr_info { + int dbi_output_num; + struct mdfld_dsi_dbi_output *dbi_outputs[2]; + + u32 dsr_idle_count; +}; + +#define DBI_CB_TIMEOUT_COUNT 0xffff + +/* Offsets */ +#define CMD_MEM_ADDR_OFFSET 0 + +#define CMD_DATA_SRC_SYSTEM_MEM 0 +#define CMD_DATA_SRC_PIPE 1 + +static inline int mdfld_dsi_dbi_fifo_ready(struct mdfld_dsi_dbi_output *dbi_output) +{ + struct drm_device *dev = dbi_output->dev; + u32 retry = DBI_CB_TIMEOUT_COUNT; + int reg_offset = (dbi_output->channel_num == 1) ? MIPIC_REG_OFFSET : 0; + int ret = 0; + + /* Query the dbi fifo status*/ + while (retry--) { + if (REG_READ(MIPIA_GEN_FIFO_STAT_REG + reg_offset) & (1 << 27)) + break; + } + + if (!retry) { + DRM_ERROR("Timeout waiting for DBI FIFO empty\n"); + ret = -EAGAIN; + } + return ret; +} + +static inline int mdfld_dsi_dbi_cmd_sent(struct mdfld_dsi_dbi_output *dbi_output) +{ + struct drm_device *dev = dbi_output->dev; + u32 retry = DBI_CB_TIMEOUT_COUNT; + int reg_offset = (dbi_output->channel_num == 1) ? MIPIC_REG_OFFSET : 0; + int ret = 0; + + /* Query the command execution status */ + while (retry--) + if (!(REG_READ(MIPIA_CMD_ADD_REG + reg_offset) & (1 << 0))) + break; + + if (!retry) { + DRM_ERROR("Timeout waiting for DBI command status\n"); + ret = -EAGAIN; + } + + return ret; +} + +static inline int mdfld_dsi_dbi_cb_ready(struct mdfld_dsi_dbi_output *dbi_output) +{ + int ret = 0; + + /* Query the command execution status*/ + ret = mdfld_dsi_dbi_cmd_sent(dbi_output); + if (ret) { + DRM_ERROR("Peripheral is busy\n"); + ret = -EAGAIN; + } + /* Query the dbi fifo status*/ + ret = mdfld_dsi_dbi_fifo_ready(dbi_output); + if (ret) { + DRM_ERROR("DBI FIFO is not empty\n"); + ret = -EAGAIN; + } + return ret; +} + +extern void mdfld_dsi_dbi_output_init(struct drm_device *dev, + struct psb_intel_mode_device *mode_dev, int pipe); +extern void mdfld_dsi_dbi_exit_dsr(struct drm_device *dev, u32 update_src); +extern void mdfld_dsi_dbi_enter_dsr(struct mdfld_dsi_dbi_output *dbi_output, + int pipe); +extern int mdfld_dbi_dsr_init(struct drm_device *dev); +extern void mdfld_dbi_dsr_exit(struct drm_device *dev); +extern struct mdfld_dsi_encoder *mdfld_dsi_dbi_init(struct drm_device *dev, + struct mdfld_dsi_connector *dsi_connector, + struct panel_funcs *p_funcs); +extern int mdfld_dsi_dbi_send_dcs(struct mdfld_dsi_dbi_output *dbi_output, + u8 dcs, u8 *param, u32 num, u8 data_src); +extern int mdfld_dsi_dbi_update_area(struct mdfld_dsi_dbi_output *dbi_output, + u16 x1, u16 y1, u16 x2, u16 y2); +extern int mdfld_dsi_dbi_update_power(struct mdfld_dsi_dbi_output *dbi_output, + int mode); +extern void mdfld_dsi_controller_dbi_init(struct mdfld_dsi_config *dsi_config, + int pipe); + +#endif /*__MDFLD_DSI_DBI_H__*/ diff --git a/drivers/staging/gma500/mdfld_dsi_dbi_dpu.c b/drivers/staging/gma500/mdfld_dsi_dbi_dpu.c new file mode 100644 index 0000000..a4e2ff4 --- /dev/null +++ b/drivers/staging/gma500/mdfld_dsi_dbi_dpu.c @@ -0,0 +1,778 @@ +/* + * Copyright © 2010-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. + * + * Authors: + * Jim Liu <jim.liu@intel.com> + * Jackie Li<yaodong.li@intel.com> + */ + +#include "mdfld_dsi_dbi_dpu.h" +#include "mdfld_dsi_dbi.h" + +/* + * NOTE: all mdlfd_x_damage funcs should be called by holding dpu_update_lock + */ + +static int mdfld_cursor_damage(struct mdfld_dbi_dpu_info *dpu_info, + mdfld_plane_t plane, + struct psb_drm_dpu_rect *damaged_rect) +{ + int x, y; + int new_x, new_y; + struct psb_drm_dpu_rect *rect; + struct psb_drm_dpu_rect *pipe_rect; + int cursor_size; + struct mdfld_cursor_info *cursor; + mdfld_plane_t fb_plane; + + if (plane == MDFLD_CURSORA) { + cursor = &dpu_info->cursors[0]; + x = dpu_info->cursors[0].x; + y = dpu_info->cursors[0].y; + cursor_size = dpu_info->cursors[0].size; + pipe_rect = &dpu_info->damage_pipea; + fb_plane = MDFLD_PLANEA; + } else { + cursor = &dpu_info->cursors[1]; + x = dpu_info->cursors[1].x; + y = dpu_info->cursors[1].y; + cursor_size = dpu_info->cursors[1].size; + pipe_rect = &dpu_info->damage_pipec; + fb_plane = MDFLD_PLANEC; + } + new_x = damaged_rect->x; + new_y = damaged_rect->y; + + if (x == new_x && y == new_y) + return 0; + + rect = &dpu_info->damaged_rects[plane]; + /* Move to right */ + if (new_x >= x) { + if (new_y > y) { + rect->x = x; + rect->y = y; + rect->width = (new_x + cursor_size) - x; + rect->height = (new_y + cursor_size) - y; + goto cursor_out; + } else { + rect->x = x; + rect->y = new_y; + rect->width = (new_x + cursor_size) - x; + rect->height = (y - new_y); + goto cursor_out; + } + } else { + if (new_y > y) { + rect->x = new_x; + rect->y = y; + rect->width = (x + cursor_size) - new_x; + rect->height = new_y - y; + goto cursor_out; + } else { + rect->x = new_x; + rect->y = new_y; + rect->width = (x + cursor_size) - new_x; + rect->height = (y + cursor_size) - new_y; + } + } +cursor_out: + if (new_x < 0) + cursor->x = 0; + else if (new_x > 864) + cursor->x = 864; + else + cursor->x = new_x; + + if (new_y < 0) + cursor->y = 0; + else if (new_y > 480) + cursor->y = 480; + else + cursor->y = new_y; + + /* + * FIXME: this is a workaround for cursor plane update, + * remove it later! + */ + rect->x = 0; + rect->y = 0; + rect->width = 864; + rect->height = 480; + + mdfld_check_boundary(dpu_info, rect); + mdfld_dpu_region_extent(pipe_rect, rect); + + /* Update pending status of dpu_info */ + dpu_info->pending |= (1 << plane); + /* Update fb panel as well */ + dpu_info->pending |= (1 << fb_plane); + return 0; +} + +static int mdfld_fb_damage(struct mdfld_dbi_dpu_info *dpu_info, + mdfld_plane_t plane, + struct psb_drm_dpu_rect *damaged_rect) +{ + struct psb_drm_dpu_rect *rect; + + if (plane == MDFLD_PLANEA) + rect = &dpu_info->damage_pipea; + else + rect = &dpu_info->damage_pipec; + + mdfld_check_boundary(dpu_info, damaged_rect); + + /* Add fb damage area to this pipe */ + mdfld_dpu_region_extent(rect, damaged_rect); + + /* Update pending status of dpu_info */ + dpu_info->pending |= (1 << plane); + return 0; +} + +/* Do nothing here, right now */ +static int mdfld_overlay_damage(struct mdfld_dbi_dpu_info *dpu_info, + mdfld_plane_t plane, + struct psb_drm_dpu_rect *damaged_rect) +{ + return 0; +} + +int mdfld_dbi_dpu_report_damage(struct drm_device *dev, + mdfld_plane_t plane, + struct psb_drm_dpu_rect *rect) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct mdfld_dbi_dpu_info *dpu_info = dev_priv->dbi_dpu_info; + int ret = 0; + + /* DPU not in use, no damage reporting needed */ + if (dpu_info == NULL) + return 0; + + spin_lock(&dpu_info->dpu_update_lock); + + switch (plane) { + case MDFLD_PLANEA: + case MDFLD_PLANEC: + mdfld_fb_damage(dpu_info, plane, rect); + break; + case MDFLD_CURSORA: + case MDFLD_CURSORC: + mdfld_cursor_damage(dpu_info, plane, rect); + break; + case MDFLD_OVERLAYA: + case MDFLD_OVERLAYC: + mdfld_overlay_damage(dpu_info, plane, rect); + break; + default: + DRM_ERROR("Invalid plane type %d\n", plane); + ret = -EINVAL; + } + spin_unlock(&dpu_info->dpu_update_lock); + return ret; +} + +int mdfld_dbi_dpu_report_fullscreen_damage(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv; + struct mdfld_dbi_dpu_info *dpu_info; + struct mdfld_dsi_config *dsi_config; + struct psb_drm_dpu_rect rect; + int i; + + if (!dev) { + DRM_ERROR("Invalid parameter\n"); + return -EINVAL; + } + + dev_priv = dev->dev_private; + dpu_info = dev_priv->dbi_dpu_info; + + /* This is fine - we may be in non DPU mode */ + if (!dpu_info) + return -EINVAL; + + for (i = 0; i < dpu_info->dbi_output_num; i++) { + dsi_config = dev_priv->dsi_configs[i]; + if (dsi_config) { + rect.x = rect.y = 0; + rect.width = dsi_config->fixed_mode->hdisplay; + rect.height = dsi_config->fixed_mode->vdisplay; + mdfld_dbi_dpu_report_damage(dev, + i ? (MDFLD_PLANEC) : (MDFLD_PLANEA), + &rect); + } + } + /* Exit DSR state */ + mdfld_dpu_exit_dsr(dev); + return 0; +} + +int mdfld_dsi_dbi_dsr_off(struct drm_device *dev, + struct psb_drm_dpu_rect *rect) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct mdfld_dbi_dpu_info *dpu_info = dev_priv->dbi_dpu_info; + + mdfld_dbi_dpu_report_damage(dev, MDFLD_PLANEA, rect); + + /* If dual display mode */ + if (dpu_info->dbi_output_num == 2) + mdfld_dbi_dpu_report_damage(dev, MDFLD_PLANEC, rect); + + /* Force dsi to exit DSR mode */ + mdfld_dpu_exit_dsr(dev); + return 0; +} + +static void mdfld_dpu_cursor_plane_flush(struct mdfld_dbi_dpu_info *dpu_info, + mdfld_plane_t plane) +{ + struct drm_device *dev = dpu_info->dev; + u32 curpos_reg = CURAPOS; + u32 curbase_reg = CURABASE; + u32 curcntr_reg = CURACNTR; + struct mdfld_cursor_info *cursor = &dpu_info->cursors[0]; + + if (plane == MDFLD_CURSORC) { + curpos_reg = CURCPOS; + curbase_reg = CURCBASE; + curcntr_reg = CURCCNTR; + cursor = &dpu_info->cursors[1]; + } + + REG_WRITE(curcntr_reg, REG_READ(curcntr_reg)); + REG_WRITE(curpos_reg, + (((cursor->x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) | + ((cursor->y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT))); + REG_WRITE(curbase_reg, REG_READ(curbase_reg)); +} + +static void mdfld_dpu_fb_plane_flush(struct mdfld_dbi_dpu_info *dpu_info, + mdfld_plane_t plane) +{ + u32 pipesrc_reg = PIPEASRC; + u32 dspsize_reg = DSPASIZE; + u32 dspoff_reg = DSPALINOFF; + u32 dspsurf_reg = DSPASURF; + u32 dspstride_reg = DSPASTRIDE; + u32 stride; + struct psb_drm_dpu_rect *rect = &dpu_info->damage_pipea; + struct drm_device *dev = dpu_info->dev; + + if (plane == MDFLD_PLANEC) { + pipesrc_reg = PIPECSRC; + dspsize_reg = DSPCSIZE; + dspoff_reg = DSPCLINOFF; + dspsurf_reg = DSPCSURF; + dspstride_reg = DSPCSTRIDE; + rect = &dpu_info->damage_pipec; + } + + stride = REG_READ(dspstride_reg); + /* FIXME: should I do the pipe src update here? */ + REG_WRITE(pipesrc_reg, ((rect->width - 1) << 16) | (rect->height - 1)); + /* Flush plane */ + REG_WRITE(dspsize_reg, ((rect->height - 1) << 16) | (rect->width - 1)); + REG_WRITE(dspoff_reg, ((rect->x * 4) + (rect->y * stride))); + REG_WRITE(dspsurf_reg, REG_READ(dspsurf_reg)); + + /* + * TODO: wait for flip finished and restore the pipesrc reg, + * or cursor will be show at a wrong position + */ +} + +static void mdfld_dpu_overlay_plane_flush(struct mdfld_dbi_dpu_info *dpu_info, + mdfld_plane_t plane) +{ +} + +/* + * TODO: we are still in dbi normal mode now, we will try to use partial + * mode later. + */ +static int mdfld_dbi_prepare_cb(struct mdfld_dsi_dbi_output *dbi_output, + struct mdfld_dbi_dpu_info *dpu_info, int pipe) +{ + u8 *cb_addr = (u8 *)dbi_output->dbi_cb_addr; + u32 *index; + struct psb_drm_dpu_rect *rect = pipe ? + (&dpu_info->damage_pipec) : (&dpu_info->damage_pipea); + + /* FIXME: lock command buffer, this may lead to a deadlock, + as we already hold the dpu_update_lock */ + if (!spin_trylock(&dbi_output->cb_lock)) { + DRM_ERROR("lock command buffer failed, try again\n"); + return -EAGAIN; + } + + index = &dbi_output->cb_write; + + if (*index) { + DRM_ERROR("DBI command buffer unclean\n"); + return -EAGAIN; + } + + /* Column address */ + *(cb_addr + ((*index)++)) = set_column_address; + *(cb_addr + ((*index)++)) = rect->x >> 8; + *(cb_addr + ((*index)++)) = rect->x; + *(cb_addr + ((*index)++)) = (rect->x + rect->width - 1) >> 8; + *(cb_addr + ((*index)++)) = (rect->x + rect->width - 1); + + *index = 8; + + /* Page address */ + *(cb_addr + ((*index)++)) = set_page_addr; + *(cb_addr + ((*index)++)) = rect->y >> 8; + *(cb_addr + ((*index)++)) = rect->y; + *(cb_addr + ((*index)++)) = (rect->y + rect->height - 1) >> 8; + *(cb_addr + ((*index)++)) = (rect->y + rect->height - 1); + + *index = 16; + + /*write memory*/ + *(cb_addr + ((*index)++)) = write_mem_start; + + return 0; +} + +static int mdfld_dbi_flush_cb(struct mdfld_dsi_dbi_output *dbi_output, int pipe) +{ + u32 cmd_phy = dbi_output->dbi_cb_phy; + u32 *index = &dbi_output->cb_write; + int reg_offset = pipe ? MIPIC_REG_OFFSET : 0; + struct drm_device *dev = dbi_output->dev; + + if (*index == 0 || !dbi_output) + return 0; + + REG_WRITE((MIPIA_CMD_LEN_REG + reg_offset), 0x010505); + REG_WRITE((MIPIA_CMD_ADD_REG + reg_offset), cmd_phy | 3); + + *index = 0; + + /* FIXME: unlock command buffer */ + spin_unlock(&dbi_output->cb_lock); + return 0; +} + +static int mdfld_dpu_update_pipe(struct mdfld_dsi_dbi_output *dbi_output, + struct mdfld_dbi_dpu_info *dpu_info, int pipe) +{ + struct drm_device *dev = dbi_output->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + mdfld_plane_t cursor_plane = MDFLD_CURSORA; + mdfld_plane_t fb_plane = MDFLD_PLANEA; + mdfld_plane_t overlay_plane = MDFLD_OVERLAYA; + int ret = 0; + u32 plane_mask = MDFLD_PIPEA_PLANE_MASK; + + /* Damaged rects on this pipe */ + if (pipe) { + cursor_plane = MDFLD_CURSORC; + fb_plane = MDFLD_PLANEC; + overlay_plane = MDFLD_OVERLAYC; + plane_mask = MDFLD_PIPEC_PLANE_MASK; + } + + /*update cursor which assigned to @pipe*/ + if (dpu_info->pending & (1 << cursor_plane)) + mdfld_dpu_cursor_plane_flush(dpu_info, cursor_plane); + + /*update fb which assigned to @pipe*/ + if (dpu_info->pending & (1 << fb_plane)) + mdfld_dpu_fb_plane_flush(dpu_info, fb_plane); + + /* TODO: update overlay */ + if (dpu_info->pending & (1 << overlay_plane)) + mdfld_dpu_overlay_plane_flush(dpu_info, overlay_plane); + + /* Flush damage area to panel fb */ + if (dpu_info->pending & plane_mask) { + ret = mdfld_dbi_prepare_cb(dbi_output, dpu_info, pipe); + /* + * TODO: remove b_dsr_enable later, + * added it so that text console could boot smoothly + */ + /* Clean pending flags on this pipe */ + if (!ret && dev_priv->dsr_enable) { + dpu_info->pending &= ~plane_mask; + /* Reset overlay pipe damage rect */ + mdfld_dpu_init_damage(dpu_info, pipe); + } + } + return ret; +} + +static int mdfld_dpu_update_fb(struct drm_device *dev) +{ + struct drm_crtc *crtc; + struct psb_intel_crtc *psb_crtc; + struct mdfld_dsi_dbi_output **dbi_output; + struct drm_psb_private *dev_priv = dev->dev_private; + struct mdfld_dbi_dpu_info *dpu_info = dev_priv->dbi_dpu_info; + bool pipe_updated[2]; + unsigned long irq_flags; + u32 dpll_reg = MRST_DPLL_A; + u32 dspcntr_reg = DSPACNTR; + u32 pipeconf_reg = PIPEACONF; + u32 dsplinoff_reg = DSPALINOFF; + u32 dspsurf_reg = DSPASURF; + u32 mipi_state_reg = MIPIA_INTR_STAT_REG; + u32 reg_offset = 0; + int pipe; + int i; + int ret; + + dbi_output = dpu_info->dbi_outputs; + pipe_updated[0] = pipe_updated[1] = false; + + if (!gma_power_begin(dev, true)) + return -EAGAIN; + + /* Try to prevent any new damage reports */ + if (!spin_trylock_irqsave(&dpu_info->dpu_update_lock, irq_flags)) + return -EAGAIN; + + for (i = 0; i < dpu_info->dbi_output_num; i++) { + crtc = dbi_output[i]->base.base.crtc; + psb_crtc = (crtc) ? to_psb_intel_crtc(crtc) : NULL; + + pipe = dbi_output[i]->channel_num ? 2 : 0; + + if (pipe == 2) { + dspcntr_reg = DSPCCNTR; + pipeconf_reg = PIPECCONF; + dsplinoff_reg = DSPCLINOFF; + dspsurf_reg = DSPCSURF; + reg_offset = MIPIC_REG_OFFSET; + } + + if (!(REG_READ((MIPIA_GEN_FIFO_STAT_REG + reg_offset)) + & (1 << 27)) || + !(REG_READ(dpll_reg) & DPLL_VCO_ENABLE) || + !(REG_READ(dspcntr_reg) & DISPLAY_PLANE_ENABLE) || + !(REG_READ(pipeconf_reg) & DISPLAY_PLANE_ENABLE)) { + dev_err(dev->dev, + "DBI FIFO is busy, DSI %d state %x\n", + pipe, + REG_READ(mipi_state_reg + reg_offset)); + continue; + } + + /* + * If DBI output is in a exclusive state then the pipe + * change won't be updated + */ + if (dbi_output[i]->dbi_panel_on && + !(dbi_output[i]->mode_flags & MODE_SETTING_ON_GOING) && + !(psb_crtc && + psb_crtc->mode_flags & MODE_SETTING_ON_GOING) && + !(dbi_output[i]->mode_flags & MODE_SETTING_IN_DSR)) { + ret = mdfld_dpu_update_pipe(dbi_output[i], + dpu_info, dbi_output[i]->channel_num ? 2 : 0); + if (!ret) + pipe_updated[i] = true; + } + } + + for (i = 0; i < dpu_info->dbi_output_num; i++) + if (pipe_updated[i]) + mdfld_dbi_flush_cb(dbi_output[i], + dbi_output[i]->channel_num ? 2 : 0); + + spin_unlock_irqrestore(&dpu_info->dpu_update_lock, irq_flags); + gma_power_end(dev); + return 0; +} + +static int __mdfld_dbi_exit_dsr(struct mdfld_dsi_dbi_output *dbi_output, + int pipe) +{ + struct drm_device *dev = dbi_output->dev; + struct drm_crtc *crtc = dbi_output->base.base.crtc; + struct psb_intel_crtc *psb_crtc = (crtc) ? to_psb_intel_crtc(crtc) + : NULL; + u32 reg_val; + u32 dpll_reg = MRST_DPLL_A; + u32 pipeconf_reg = PIPEACONF; + u32 dspcntr_reg = DSPACNTR; + u32 dspbase_reg = DSPABASE; + u32 dspsurf_reg = DSPASURF; + u32 reg_offset = 0; + + if (!dbi_output) + return 0; + + /* If mode setting on-going, back off */ + if ((dbi_output->mode_flags & MODE_SETTING_ON_GOING) || + (psb_crtc && psb_crtc->mode_flags & MODE_SETTING_ON_GOING)) + return -EAGAIN; + + if (pipe == 2) { + dpll_reg = MRST_DPLL_A; + pipeconf_reg = PIPECCONF; + dspcntr_reg = DSPCCNTR; + dspbase_reg = MDFLD_DSPCBASE; + dspsurf_reg = DSPCSURF; + + reg_offset = MIPIC_REG_OFFSET; + } + + if (!gma_power_begin(dev, true)) + return -EAGAIN; + + /* Enable DPLL */ + reg_val = REG_READ(dpll_reg); + if (!(reg_val & DPLL_VCO_ENABLE)) { + + if (reg_val & MDFLD_PWR_GATE_EN) { + reg_val &= ~MDFLD_PWR_GATE_EN; + REG_WRITE(dpll_reg, reg_val); + REG_READ(dpll_reg); + udelay(500); + } + + reg_val |= DPLL_VCO_ENABLE; + REG_WRITE(dpll_reg, reg_val); + REG_READ(dpll_reg); + udelay(500); + + /* FIXME: add timeout */ + while (!(REG_READ(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) + cpu_relax(); + } + + /* Enable pipe */ + reg_val = REG_READ(pipeconf_reg); + if (!(reg_val & PIPEACONF_ENABLE)) { + reg_val |= PIPEACONF_ENABLE; + REG_WRITE(pipeconf_reg, reg_val); + REG_READ(pipeconf_reg); + udelay(500); + mdfldWaitForPipeEnable(dev, pipe); + } + + /* Enable plane */ + reg_val = REG_READ(dspcntr_reg); + if (!(reg_val & DISPLAY_PLANE_ENABLE)) { + reg_val |= DISPLAY_PLANE_ENABLE; + REG_WRITE(dspcntr_reg, reg_val); + REG_READ(dspcntr_reg); + udelay(500); + } + + gma_power_end(dev); + + /* Clean IN_DSR flag */ + dbi_output->mode_flags &= ~MODE_SETTING_IN_DSR; + + return 0; +} + +int mdfld_dpu_exit_dsr(struct drm_device *dev) +{ + struct mdfld_dsi_dbi_output **dbi_output; + struct drm_psb_private *dev_priv = dev->dev_private; + struct mdfld_dbi_dpu_info *dpu_info = dev_priv->dbi_dpu_info; + int i; + int pipe; + + dbi_output = dpu_info->dbi_outputs; + + for (i = 0; i < dpu_info->dbi_output_num; i++) { + /* If this output is not in DSR mode, don't call exit dsr */ + if (dbi_output[i]->mode_flags & MODE_SETTING_IN_DSR) + __mdfld_dbi_exit_dsr(dbi_output[i], + dbi_output[i]->channel_num ? 2 : 0); + } + + /* Enable TE interrupt */ + for (i = 0; i < dpu_info->dbi_output_num; i++) { + /* If this output is not in DSR mode, don't call exit dsr */ + pipe = dbi_output[i]->channel_num ? 2 : 0; + if (dbi_output[i]->dbi_panel_on && pipe) { + mdfld_disable_te(dev, 0); + mdfld_enable_te(dev, 2); + } else if (dbi_output[i]->dbi_panel_on && !pipe) { + mdfld_disable_te(dev, 2); + mdfld_enable_te(dev, 0); + } + } + return 0; +} + +static int mdfld_dpu_enter_dsr(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct mdfld_dbi_dpu_info *dpu_info = dev_priv->dbi_dpu_info; + struct mdfld_dsi_dbi_output **dbi_output; + int i; + + dbi_output = dpu_info->dbi_outputs; + + for (i = 0; i < dpu_info->dbi_output_num; i++) { + /* If output is off or already in DSR state, don't re-enter */ + if (dbi_output[i]->dbi_panel_on && + !(dbi_output[i]->mode_flags & MODE_SETTING_IN_DSR)) { + mdfld_dsi_dbi_enter_dsr(dbi_output[i], + dbi_output[i]->channel_num ? 2 : 0); + } + } + + return 0; +} + +static void mdfld_dbi_dpu_timer_func(unsigned long data) +{ + struct drm_device *dev = (struct drm_device *)data; + struct drm_psb_private *dev_priv = dev->dev_private; + struct mdfld_dbi_dpu_info *dpu_info = dev_priv->dbi_dpu_info; + struct timer_list *dpu_timer = &dpu_info->dpu_timer; + unsigned long flags; + + if (dpu_info->pending) { + dpu_info->idle_count = 0; + /* Update panel fb with damaged area */ + mdfld_dpu_update_fb(dev); + } else { + dpu_info->idle_count++; + } + + if (dpu_info->idle_count >= MDFLD_MAX_IDLE_COUNT) { + mdfld_dpu_enter_dsr(dev); + /* Stop timer by return */ + return; + } + + spin_lock_irqsave(&dpu_info->dpu_timer_lock, flags); + if (!timer_pending(dpu_timer)) { + dpu_timer->expires = jiffies + MDFLD_DSR_DELAY; + add_timer(dpu_timer); + } + spin_unlock_irqrestore(&dpu_info->dpu_timer_lock, flags); +} + +void mdfld_dpu_update_panel(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct mdfld_dbi_dpu_info *dpu_info = dev_priv->dbi_dpu_info; + + if (dpu_info->pending) { + dpu_info->idle_count = 0; + + /*update panel fb with damaged area*/ + mdfld_dpu_update_fb(dev); + } else { + dpu_info->idle_count++; + } + + if (dpu_info->idle_count >= MDFLD_MAX_IDLE_COUNT) { + /*enter dsr*/ + mdfld_dpu_enter_dsr(dev); + } +} + +static int mdfld_dbi_dpu_timer_init(struct drm_device *dev, + struct mdfld_dbi_dpu_info *dpu_info) +{ + struct timer_list *dpu_timer = &dpu_info->dpu_timer; + unsigned long flags; + + spin_lock_init(&dpu_info->dpu_timer_lock); + spin_lock_irqsave(&dpu_info->dpu_timer_lock, flags); + + init_timer(dpu_timer); + + dpu_timer->data = (unsigned long)dev; + dpu_timer->function = mdfld_dbi_dpu_timer_func; + dpu_timer->expires = jiffies + MDFLD_DSR_DELAY; + + spin_unlock_irqrestore(&dpu_info->dpu_timer_lock, flags); + + return 0; +} + +void mdfld_dbi_dpu_timer_start(struct mdfld_dbi_dpu_info *dpu_info) +{ + struct timer_list *dpu_timer = &dpu_info->dpu_timer; + unsigned long flags; + + spin_lock_irqsave(&dpu_info->dpu_timer_lock, flags); + if (!timer_pending(dpu_timer)) { + dpu_timer->expires = jiffies + MDFLD_DSR_DELAY; + add_timer(dpu_timer); + } + spin_unlock_irqrestore(&dpu_info->dpu_timer_lock, flags); +} + +int mdfld_dbi_dpu_init(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct mdfld_dbi_dpu_info *dpu_info = dev_priv->dbi_dpu_info; + + if (!dpu_info || IS_ERR(dpu_info)) { + dpu_info = kzalloc(sizeof(struct mdfld_dbi_dpu_info), + GFP_KERNEL); + if (!dpu_info) { + DRM_ERROR("No memory\n"); + return -ENOMEM; + } + dev_priv->dbi_dpu_info = dpu_info; + } + + dpu_info->dev = dev; + + dpu_info->cursors[0].size = MDFLD_CURSOR_SIZE; + dpu_info->cursors[1].size = MDFLD_CURSOR_SIZE; + + /*init dpu_update_lock*/ + spin_lock_init(&dpu_info->dpu_update_lock); + + /*init dpu refresh timer*/ + mdfld_dbi_dpu_timer_init(dev, dpu_info); + + /*init pipe damage area*/ + mdfld_dpu_init_damage(dpu_info, 0); + mdfld_dpu_init_damage(dpu_info, 2); + + return 0; +} + +void mdfld_dbi_dpu_exit(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct mdfld_dbi_dpu_info *dpu_info = dev_priv->dbi_dpu_info; + + if (!dpu_info) + return; + + del_timer_sync(&dpu_info->dpu_timer); + kfree(dpu_info); + dev_priv->dbi_dpu_info = NULL; +} + + diff --git a/drivers/staging/gma500/mdfld_dsi_dbi_dpu.h b/drivers/staging/gma500/mdfld_dsi_dbi_dpu.h new file mode 100644 index 0000000..42367ed --- /dev/null +++ b/drivers/staging/gma500/mdfld_dsi_dbi_dpu.h @@ -0,0 +1,154 @@ +/* + * 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_DBI_DPU_H__ +#define __MDFLD_DSI_DBI_DPU_H__ + +#include "mdfld_dsi_dbi.h" + +typedef enum { + MDFLD_PLANEA, + MDFLD_PLANEC, + MDFLD_CURSORA, + MDFLD_CURSORC, + MDFLD_OVERLAYA, + MDFLD_OVERLAYC, + MDFLD_PLANE_NUM, +} mdfld_plane_t; + +#define MDFLD_PIPEA_PLANE_MASK 0x15 +#define MDFLD_PIPEC_PLANE_MASK 0x2A + +struct mdfld_cursor_info { + int x, y; + int size; +}; + +#define MDFLD_CURSOR_SIZE 64 + +/* + * enter DSR mode if screen has no update for 2 frames. + */ +#define MDFLD_MAX_IDLE_COUNT 2 + +struct mdfld_dbi_dpu_info { + struct drm_device *dev; + /* Lock */ + spinlock_t dpu_update_lock; + + /* Cursor postion */ + struct mdfld_cursor_info cursors[2]; + + /* Damaged area for each plane */ + struct psb_drm_dpu_rect damaged_rects[MDFLD_PLANE_NUM]; + + /* Final damaged area */ + struct psb_drm_dpu_rect damage_pipea; + struct psb_drm_dpu_rect damage_pipec; + + /* Pending */ + u32 pending; + + /* DPU timer */ + struct timer_list dpu_timer; + spinlock_t dpu_timer_lock; + + /* DPU idle count */ + u32 idle_count; + + /* DSI outputs */ + struct mdfld_dsi_dbi_output *dbi_outputs[2]; + int dbi_output_num; +}; + +static inline int mdfld_dpu_region_extent(struct psb_drm_dpu_rect *origin, + struct psb_drm_dpu_rect *rect) +{ + int x1, y1, x2, y2; + + x1 = origin->x + origin->width; + y1 = origin->y + origin->height; + + x2 = rect->x + rect->width; + y2 = rect->y + rect->height; + + origin->x = min(origin->x, rect->x); + origin->y = min(origin->y, rect->y); + origin->width = max(x1, x2) - origin->x; + origin->height = max(y1, y2) - origin->y; + + return 0; +} + +static inline void mdfld_check_boundary(struct mdfld_dbi_dpu_info *dpu_info, + struct psb_drm_dpu_rect *rect) +{ + if (rect->x < 0) + rect->x = 0; + if (rect->y < 0) + rect->y = 0; + + if (rect->x + rect->width > 864) + rect->width = 864 - rect->x; + if (rect->y + rect->height > 480) + rect->height = 480 - rect->height; + + if (!rect->width) + rect->width = 1; + if (!rect->height) + rect->height = 1; +} + +static inline void mdfld_dpu_init_damage(struct mdfld_dbi_dpu_info *dpu_info, + int pipe) +{ + struct psb_drm_dpu_rect *rect; + + if (pipe == 0) + rect = &dpu_info->damage_pipea; + else + rect = &dpu_info->damage_pipec; + + rect->x = 864; + rect->y = 480; + rect->width = -864; + rect->height = -480; +} + +extern int mdfld_dsi_dbi_dsr_off(struct drm_device *dev, + struct psb_drm_dpu_rect *rect); +extern int mdfld_dbi_dpu_report_damage(struct drm_device *dev, + mdfld_plane_t plane, + struct psb_drm_dpu_rect *rect); +extern int mdfld_dbi_dpu_report_fullscreen_damage(struct drm_device *dev); +extern int mdfld_dpu_exit_dsr(struct drm_device *dev); +extern void mdfld_dbi_dpu_timer_start(struct mdfld_dbi_dpu_info *dpu_info); +extern int mdfld_dbi_dpu_init(struct drm_device *dev); +extern void mdfld_dbi_dpu_exit(struct drm_device *dev); +extern void mdfld_dpu_update_panel(struct drm_device *dev); + +#endif /*__MDFLD_DSI_DBI_DPU_H__*/ diff --git a/drivers/staging/gma500/mdfld_dsi_dpi.c b/drivers/staging/gma500/mdfld_dsi_dpi.c new file mode 100644 index 0000000..6e03a91 --- /dev/null +++ b/drivers/staging/gma500/mdfld_dsi_dpi.c @@ -0,0 +1,800 @@ +/* + * 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" +#include "mdfld_output.h" +#include "mdfld_dsi_pkg_sender.h" + + +static void mdfld_wait_for_HS_DATA_FIFO(struct drm_device *dev, u32 pipe) +{ + u32 gen_fifo_stat_reg = MIPIA_GEN_FIFO_STAT_REG; + int timeout = 0; + + if (pipe == 2) + gen_fifo_stat_reg += MIPIC_REG_OFFSET; + + udelay(500); + + /* This will time out after approximately 2+ seconds */ + while ((timeout < 20000) && (REG_READ(gen_fifo_stat_reg) & DSI_FIFO_GEN_HS_DATA_FULL)) { + udelay(100); + timeout++; + } + + if (timeout == 20000) + dev_warn(dev->dev, "MIPI: HS Data FIFO was never cleared!\n"); +} + +static void mdfld_wait_for_HS_CTRL_FIFO(struct drm_device *dev, u32 pipe) +{ + u32 gen_fifo_stat_reg = MIPIA_GEN_FIFO_STAT_REG; + int timeout = 0; + + if (pipe == 2) + gen_fifo_stat_reg += MIPIC_REG_OFFSET; + + udelay(500); + + /* This will time out after approximately 2+ seconds */ + while ((timeout < 20000) && (REG_READ(gen_fifo_stat_reg) & DSI_FIFO_GEN_HS_CTRL_FULL)) { + udelay(100); + timeout++; + } + if (timeout == 20000) + dev_warn(dev->dev, "MIPI: HS CMD FIFO was never cleared!\n"); +} + +static void mdfld_wait_for_DPI_CTRL_FIFO(struct drm_device *dev, u32 pipe) +{ + u32 gen_fifo_stat_reg = MIPIA_GEN_FIFO_STAT_REG; + int timeout = 0; + + if (pipe == 2) + gen_fifo_stat_reg += MIPIC_REG_OFFSET; + + udelay(500); + + /* This will time out after approximately 2+ seconds */ + while ((timeout < 20000) && ((REG_READ(gen_fifo_stat_reg) & DPI_FIFO_EMPTY) + != DPI_FIFO_EMPTY)) { + udelay(100); + timeout++; + } + + if (timeout == 20000) + dev_warn(dev->dev, "MIPI: DPI FIFO was never cleared!\n"); +} + +static void mdfld_wait_for_SPL_PKG_SENT(struct drm_device *dev, u32 pipe) +{ + u32 intr_stat_reg = MIPIA_INTR_STAT_REG; + int timeout = 0; + + if (pipe == 2) + intr_stat_reg += MIPIC_REG_OFFSET; + + udelay(500); + + /* This will time out after approximately 2+ seconds */ + while ((timeout < 20000) && (!(REG_READ(intr_stat_reg) & DSI_INTR_STATE_SPL_PKG_SENT))) { + udelay(100); + timeout++; + } + + if (timeout == 20000) + dev_warn(dev->dev, "MIPI: SPL_PKT_SENT_INTERRUPT was not sent successfully!\n"); +} + + +/* ************************************************************************* *\ + * FUNCTION: mdfld_dsi_tpo_ic_init + * + * 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! +\* ************************************************************************* */ +void mdfld_dsi_tpo_ic_init(struct mdfld_dsi_config *dsi_config, u32 pipe) +{ + struct drm_device *dev = dsi_config->dev; + u32 dcsChannelNumber = dsi_config->channel_num; + u32 gen_data_reg = MIPIA_HS_GEN_DATA_REG; + u32 gen_ctrl_reg = MIPIA_HS_GEN_CTRL_REG; + u32 gen_ctrl_val = GEN_LONG_WRITE; + + if (pipe == 2) { + gen_data_reg = HS_GEN_DATA_REG + MIPIC_REG_OFFSET; + gen_ctrl_reg = HS_GEN_CTRL_REG + MIPIC_REG_OFFSET; + } + + gen_ctrl_val |= dcsChannelNumber << DCS_CHANNEL_NUMBER_POS; + + /* Flip page order */ + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x00008036); + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x02 << WORD_COUNTS_POS)); + + /* 0xF0 */ + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x005a5af0); + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS)); + + /* Write protection key */ + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x005a5af1); + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS)); + + /* 0xFC */ + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x005a5afc); + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS)); + + /* 0xB7 */ + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x770000b7); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x00000044); + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x05 << WORD_COUNTS_POS)); + + /* 0xB6 */ + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x000a0ab6); + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS)); + + /* 0xF2 */ + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x081010f2); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x4a070708); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x000000c5); + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x09 << WORD_COUNTS_POS)); + + /* 0xF8 */ + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x024003f8); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x01030a04); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x0e020220); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x00000004); + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x0d << WORD_COUNTS_POS)); + + /* 0xE2 */ + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x398fc3e2); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x0000916f); + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x06 << WORD_COUNTS_POS)); + + /* 0xB0 */ + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x000000b0); + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x02 << WORD_COUNTS_POS)); + + /* 0xF4 */ + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x240242f4); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x78ee2002); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x2a071050); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x507fee10); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x10300710); + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x14 << WORD_COUNTS_POS)); + + /* 0xBA */ + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x19fe07ba); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x101c0a31); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x00000010); + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x09 << WORD_COUNTS_POS)); + + /* 0xBB */ + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x28ff07bb); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x24280a31); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x00000034); + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x09 << WORD_COUNTS_POS)); + + /* 0xFB */ + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x535d05fb); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x1b1a2130); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x221e180e); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x131d2120); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x535d0508); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x1c1a2131); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x231f160d); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x111b2220); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x535c2008); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x1f1d2433); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x2c251a10); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x2c34372d); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x00000023); + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x31 << WORD_COUNTS_POS)); + + /* 0xFA */ + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x525c0bfa); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x1c1c232f); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x2623190e); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x18212625); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x545d0d0e); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x1e1d2333); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x26231a10); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x1a222725); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x545d280f); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x21202635); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x31292013); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x31393d33); + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x00000029); + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x31 << WORD_COUNTS_POS)); + + /* Set DM */ + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); + REG_WRITE(gen_data_reg, 0x000100f7); + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS)); +} + +static u16 mdfld_dsi_dpi_to_byte_clock_count(int pixel_clock_count, + int num_lane, int bpp) +{ + return (u16)((pixel_clock_count * bpp) / (num_lane * 8)); +} + +/* + * Calculate the dpi time basing on a given drm mode @mode + * return 0 on success. + * FIXME: I was using proposed mode value for calculation, may need to + * use crtc mode values later + */ +int mdfld_dsi_dpi_timing_calculation(struct drm_display_mode *mode, + struct mdfld_dsi_dpi_timing *dpi_timing, + int num_lane, int bpp) +{ + int pclk_hsync, pclk_hfp, pclk_hbp, pclk_hactive; + int pclk_vsync, pclk_vfp, pclk_vbp, pclk_vactive; + + if(!mode || !dpi_timing) { + DRM_ERROR("Invalid parameter\n"); + return -EINVAL; + } + + pclk_hactive = mode->hdisplay; + pclk_hfp = mode->hsync_start - mode->hdisplay; + pclk_hsync = mode->hsync_end - mode->hsync_start; + pclk_hbp = mode->htotal - mode->hsync_end; + + pclk_vactive = mode->vdisplay; + pclk_vfp = mode->vsync_start - mode->vdisplay; + pclk_vsync = mode->vsync_end - mode->vsync_start; + pclk_vbp = mode->vtotal - mode->vsync_end; + + /* + * byte clock counts were calculated by following formula + * bclock_count = pclk_count * bpp / num_lane / 8 + */ + dpi_timing->hsync_count = mdfld_dsi_dpi_to_byte_clock_count(pclk_hsync, num_lane, bpp); + dpi_timing->hbp_count = mdfld_dsi_dpi_to_byte_clock_count(pclk_hbp, num_lane, bpp); + dpi_timing->hfp_count = mdfld_dsi_dpi_to_byte_clock_count(pclk_hfp, num_lane, bpp); + dpi_timing->hactive_count = mdfld_dsi_dpi_to_byte_clock_count(pclk_hactive, num_lane, bpp); + dpi_timing->vsync_count = mdfld_dsi_dpi_to_byte_clock_count(pclk_vsync, num_lane, bpp); + dpi_timing->vbp_count = mdfld_dsi_dpi_to_byte_clock_count(pclk_vbp, num_lane, bpp); + dpi_timing->vfp_count = mdfld_dsi_dpi_to_byte_clock_count(pclk_vfp, num_lane, bpp); + + return 0; +} + +void mdfld_dsi_dpi_controller_init(struct mdfld_dsi_config *dsi_config, int pipe) +{ + struct drm_device *dev = dsi_config->dev; + u32 reg_offset = pipe ? MIPIC_REG_OFFSET : 0; + int lane_count = dsi_config->lane_count; + struct mdfld_dsi_dpi_timing dpi_timing; + struct drm_display_mode *mode = dsi_config->mode; + u32 val = 0; + + /*un-ready device*/ + REG_WRITE((MIPIA_DEVICE_READY_REG + reg_offset), 0x00000000); + + /*init dsi adapter before kicking off*/ + REG_WRITE((MIPIA_CONTROL_REG + reg_offset), 0x00000018); + + /*enable all interrupts*/ + REG_WRITE((MIPIA_INTR_EN_REG + reg_offset), 0xffffffff); + + + /*set up func_prg*/ + val |= lane_count; + val |= dsi_config->channel_num << DSI_DPI_VIRT_CHANNEL_OFFSET; + + switch(dsi_config->bpp) { + case 16: + val |= DSI_DPI_COLOR_FORMAT_RGB565; + break; + case 18: + val |= DSI_DPI_COLOR_FORMAT_RGB666; + break; + case 24: + val |= DSI_DPI_COLOR_FORMAT_RGB888; + break; + default: + DRM_ERROR("unsupported color format, bpp = %d\n", dsi_config->bpp); + } + REG_WRITE((MIPIA_DSI_FUNC_PRG_REG + reg_offset), val); + + REG_WRITE((MIPIA_HS_TX_TIMEOUT_REG + reg_offset), + (mode->vtotal * mode->htotal * dsi_config->bpp / (8 * lane_count)) & DSI_HS_TX_TIMEOUT_MASK); + REG_WRITE((MIPIA_LP_RX_TIMEOUT_REG + reg_offset), 0xffff & DSI_LP_RX_TIMEOUT_MASK); + + /*max value: 20 clock cycles of txclkesc*/ + REG_WRITE((MIPIA_TURN_AROUND_TIMEOUT_REG + reg_offset), 0x14 & DSI_TURN_AROUND_TIMEOUT_MASK); + + /*min 21 txclkesc, max: ffffh*/ + REG_WRITE((MIPIA_DEVICE_RESET_TIMER_REG + reg_offset), 0xffff & DSI_RESET_TIMER_MASK); + + REG_WRITE((MIPIA_DPI_RESOLUTION_REG + reg_offset), mode->vdisplay << 16 | mode->hdisplay); + + /*set DPI timing registers*/ + mdfld_dsi_dpi_timing_calculation(mode, &dpi_timing, dsi_config->lane_count, dsi_config->bpp); + + REG_WRITE((MIPIA_HSYNC_COUNT_REG + reg_offset), dpi_timing.hsync_count & DSI_DPI_TIMING_MASK); + REG_WRITE((MIPIA_HBP_COUNT_REG + reg_offset), dpi_timing.hbp_count & DSI_DPI_TIMING_MASK); + REG_WRITE((MIPIA_HFP_COUNT_REG + reg_offset), dpi_timing.hfp_count & DSI_DPI_TIMING_MASK); + REG_WRITE((MIPIA_HACTIVE_COUNT_REG + reg_offset), dpi_timing.hactive_count & DSI_DPI_TIMING_MASK); + REG_WRITE((MIPIA_VSYNC_COUNT_REG + reg_offset), dpi_timing.vsync_count & DSI_DPI_TIMING_MASK); + REG_WRITE((MIPIA_VBP_COUNT_REG + reg_offset), dpi_timing.vbp_count & DSI_DPI_TIMING_MASK); + REG_WRITE((MIPIA_VFP_COUNT_REG + reg_offset), dpi_timing.vfp_count & DSI_DPI_TIMING_MASK); + + REG_WRITE((MIPIA_HIGH_LOW_SWITCH_COUNT_REG + reg_offset), 0x46); + + /*min: 7d0 max: 4e20*/ + REG_WRITE((MIPIA_INIT_COUNT_REG + reg_offset), 0x000007d0); + + /*set up video mode*/ + val = 0; + val = dsi_config->video_mode | DSI_DPI_COMPLETE_LAST_LINE; + REG_WRITE((MIPIA_VIDEO_MODE_FORMAT_REG + reg_offset), val); + + REG_WRITE((MIPIA_EOT_DISABLE_REG + reg_offset), 0x00000000); + + REG_WRITE((MIPIA_LP_BYTECLK_REG + reg_offset), 0x00000004); + + /*TODO: figure out how to setup these registers*/ + REG_WRITE((MIPIA_DPHY_PARAM_REG + reg_offset), 0x150c3408); + + REG_WRITE((MIPIA_CLK_LANE_SWITCH_TIME_CNT_REG + reg_offset), (0xa << 16) | 0x14); + /*set device ready*/ + REG_WRITE((MIPIA_DEVICE_READY_REG + reg_offset), 0x00000001); +} + +void mdfld_dsi_dpi_turn_on(struct mdfld_dsi_dpi_output *output, int pipe) +{ + struct drm_device *dev = output->dev; + u32 reg_offset = 0; + + if(output->panel_on) + return; + + if(pipe) + reg_offset = MIPIC_REG_OFFSET; + + /* clear special packet sent bit */ + if(REG_READ(MIPIA_INTR_STAT_REG + reg_offset) & DSI_INTR_STATE_SPL_PKG_SENT) { + REG_WRITE((MIPIA_INTR_STAT_REG + reg_offset), DSI_INTR_STATE_SPL_PKG_SENT); + } + + /*send turn on package*/ + REG_WRITE((MIPIA_DPI_CONTROL_REG + reg_offset), DSI_DPI_CTRL_HS_TURN_ON); + + /*wait for SPL_PKG_SENT interrupt*/ + mdfld_wait_for_SPL_PKG_SENT(dev, pipe); + + if(REG_READ(MIPIA_INTR_STAT_REG + reg_offset) & DSI_INTR_STATE_SPL_PKG_SENT) { + REG_WRITE((MIPIA_INTR_STAT_REG + reg_offset), DSI_INTR_STATE_SPL_PKG_SENT); + } + + output->panel_on = 1; + + /* FIXME the following is disabled to WA the X slow start issue for TMD panel */ + /* if(pipe == 2) */ + /* dev_priv->dpi_panel_on2 = true; */ + /* else if (pipe == 0) */ + /* dev_priv->dpi_panel_on = true; */ +} + +static void mdfld_dsi_dpi_shut_down(struct mdfld_dsi_dpi_output *output, int pipe) +{ + struct drm_device *dev = output->dev; + u32 reg_offset = 0; + + /*if output is on, or mode setting didn't happen, ignore this*/ + if((!output->panel_on) || output->first_boot) { + output->first_boot = 0; + return; + } + + if(pipe) + reg_offset = MIPIC_REG_OFFSET; + + /* Wait for dpi fifo to empty */ + mdfld_wait_for_DPI_CTRL_FIFO(dev, pipe); + + /* Clear the special packet interrupt bit if set */ + if(REG_READ(MIPIA_INTR_STAT_REG + reg_offset) & DSI_INTR_STATE_SPL_PKG_SENT) { + REG_WRITE((MIPIA_INTR_STAT_REG + reg_offset), DSI_INTR_STATE_SPL_PKG_SENT); + } + + if(REG_READ(MIPIA_DPI_CONTROL_REG + reg_offset) == DSI_DPI_CTRL_HS_SHUTDOWN) { + dev_warn(dev->dev, "try to send the same package again, abort!"); + goto shutdown_out; + } + + REG_WRITE((MIPIA_DPI_CONTROL_REG + reg_offset), DSI_DPI_CTRL_HS_SHUTDOWN); + +shutdown_out: + output->panel_on = 0; + output->first_boot = 0; + + /* FIXME the following is disabled to WA the X slow start issue for TMD panel */ + /* if(pipe == 2) */ + /* dev_priv->dpi_panel_on2 = false; */ + /* else if (pipe == 0) */ + /* dev_priv->dpi_panel_on = false; */ + /* #ifdef CONFIG_PM_RUNTIME*/ + /* if (drm_psb_ospm && !enable_gfx_rtpm) { */ + /* pm_runtime_allow(&gpDrmDevice->pdev->dev); */ + /* schedule_delayed_work(&dev_priv->rtpm_work, 30 * 1000); */ + /* } */ + /*if (enable_gfx_rtpm) */ + /* pm_schedule_suspend(&dev->pdev->dev, gfxrtdelay); */ + /* #endif */ +} + +void mdfld_dsi_dpi_set_power(struct drm_encoder *encoder, bool on) +{ + struct mdfld_dsi_encoder *dsi_encoder = MDFLD_DSI_ENCODER(encoder); + struct mdfld_dsi_dpi_output *dpi_output = MDFLD_DSI_DPI_OUTPUT(dsi_encoder); + struct mdfld_dsi_config *dsi_config = mdfld_dsi_encoder_get_config(dsi_encoder); + int pipe = mdfld_dsi_encoder_get_pipe(dsi_encoder); + struct drm_device *dev = dsi_config->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + u32 mipi_reg = MIPI; + u32 pipeconf_reg = PIPEACONF; + + if(pipe) { + mipi_reg = MIPI_C; + pipeconf_reg = PIPECCONF; + } + + /* Start up display island if it was shutdown */ + if (!gma_power_begin(dev, true)) + return; + + if(on) { + if (mdfld_get_panel_type(dev, pipe) == TMD_VID){ + mdfld_dsi_dpi_turn_on(dpi_output, pipe); + } else { + /* Enable mipi port */ + REG_WRITE(mipi_reg, (REG_READ(mipi_reg) | (1 << 31))); + REG_READ(mipi_reg); + + mdfld_dsi_dpi_turn_on(dpi_output, pipe); + mdfld_dsi_tpo_ic_init(dsi_config, pipe); + } + + if(pipe == 2) { + dev_priv->dpi_panel_on2 = true; + } + else { + dev_priv->dpi_panel_on = true; + } + + } else { + if (mdfld_get_panel_type(dev, pipe) == TMD_VID) { + mdfld_dsi_dpi_shut_down(dpi_output, pipe); + } else { + mdfld_dsi_dpi_shut_down(dpi_output, pipe); + /* Disable mipi port */ + REG_WRITE(mipi_reg, (REG_READ(mipi_reg) & ~(1<<31))); + REG_READ(mipi_reg); + } + + if(pipe == 2) + dev_priv->dpi_panel_on2 = false; + else + dev_priv->dpi_panel_on = false; + } + gma_power_end(dev); +} + +void mdfld_dsi_dpi_dpms(struct drm_encoder *encoder, int mode) +{ + dev_dbg(encoder->dev->dev, "DPMS %s\n", + (mode == DRM_MODE_DPMS_ON ? "on":"off")); + + if (mode == DRM_MODE_DPMS_ON) + mdfld_dsi_dpi_set_power(encoder, true); + else { + mdfld_dsi_dpi_set_power(encoder, false); +#if 0 /* FIXME */ +#ifdef CONFIG_PM_RUNTIME + if (enable_gfx_rtpm) + pm_schedule_suspend(&gpDrmDevice->pdev->dev, gfxrtdelay); +#endif +#endif + } +} + +bool mdfld_dsi_dpi_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct mdfld_dsi_encoder *dsi_encoder = MDFLD_DSI_ENCODER(encoder); + struct mdfld_dsi_config *dsi_config = mdfld_dsi_encoder_get_config(dsi_encoder); + struct drm_display_mode *fixed_mode = dsi_config->fixed_mode; + + if(fixed_mode) { + adjusted_mode->hdisplay = fixed_mode->hdisplay; + adjusted_mode->hsync_start = fixed_mode->hsync_start; + adjusted_mode->hsync_end = fixed_mode->hsync_end; + adjusted_mode->htotal = fixed_mode->htotal; + adjusted_mode->vdisplay = fixed_mode->vdisplay; + adjusted_mode->vsync_start = fixed_mode->vsync_start; + adjusted_mode->vsync_end = fixed_mode->vsync_end; + adjusted_mode->vtotal = fixed_mode->vtotal; + adjusted_mode->clock = fixed_mode->clock; + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); + } + + return true; +} + +void mdfld_dsi_dpi_prepare(struct drm_encoder *encoder) +{ + mdfld_dsi_dpi_set_power(encoder, false); +} + +void mdfld_dsi_dpi_commit(struct drm_encoder *encoder) +{ + mdfld_dsi_dpi_set_power(encoder, true); +} + +void mdfld_dsi_dpi_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct mdfld_dsi_encoder *dsi_encoder = MDFLD_DSI_ENCODER(encoder); + struct mdfld_dsi_dpi_output *dpi_output = MDFLD_DSI_DPI_OUTPUT(dsi_encoder); + struct mdfld_dsi_config *dsi_config = mdfld_dsi_encoder_get_config(dsi_encoder); + struct drm_device *dev = dsi_config->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + int pipe = mdfld_dsi_encoder_get_pipe(dsi_encoder); + + u32 pipeconf_reg = PIPEACONF; + u32 dspcntr_reg = DSPACNTR; + u32 mipi_reg = MIPI; + u32 reg_offset = 0; + + u32 pipeconf = dev_priv->pipeconf; + u32 dspcntr = dev_priv->dspcntr; + u32 mipi = MIPI_PORT_EN | PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX; + + dev_dbg(dev->dev, "set mode %dx%d on pipe %d\n", + mode->hdisplay, mode->vdisplay, pipe); + + if(pipe) { + pipeconf_reg = PIPECCONF; + dspcntr_reg = DSPCCNTR; + mipi_reg = MIPI_C; + reg_offset = MIPIC_REG_OFFSET; + } else { + mipi |= 2; + } + + if (!gma_power_begin(dev, true)) + return; + + /* Set up mipi port FIXME: do at init time */ + REG_WRITE(mipi_reg, mipi); + REG_READ(mipi_reg); + + /* Set up DSI controller DPI interface */ + mdfld_dsi_dpi_controller_init(dsi_config, pipe); + + if (mdfld_get_panel_type(dev, pipe) != TMD_VID) { + /* Turn on DPI interface */ + mdfld_dsi_dpi_turn_on(dpi_output, pipe); + } + + /* Set up pipe */ + REG_WRITE(pipeconf_reg, pipeconf); + REG_READ(pipeconf_reg); + + /* Set up display plane */ + REG_WRITE(dspcntr_reg, dspcntr); + REG_READ(dspcntr_reg); + + msleep(20); /* FIXME: this should wait for vblank */ + + dev_dbg(dev->dev, "State %x, power %d\n", + REG_READ(MIPIA_INTR_STAT_REG + reg_offset), + dpi_output->panel_on); + + if (mdfld_get_panel_type(dev, pipe) != TMD_VID) { + /* Init driver ic */ + mdfld_dsi_tpo_ic_init(dsi_config, pipe); + /* Init backlight */ + mdfld_dsi_brightness_init(dsi_config, pipe); + } + gma_power_end(dev); +} + + +/* + * Init DSI DPI encoder. + * Allocate an mdfld_dsi_encoder and attach it to given @dsi_connector + * return pointer of newly allocated DPI encoder, NULL on error + */ +struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev, + struct mdfld_dsi_connector *dsi_connector, + struct panel_funcs *p_funcs) +{ + struct mdfld_dsi_dpi_output *dpi_output = NULL; + struct mdfld_dsi_config *dsi_config; + struct drm_connector *connector = NULL; + struct drm_encoder *encoder = NULL; + struct drm_display_mode *fixed_mode = NULL; + int pipe; + u32 data; + int ret; + + if (!dsi_connector || !p_funcs) { + WARN_ON(1); + return NULL; + } + + dsi_config = mdfld_dsi_get_config(dsi_connector); + pipe = dsi_connector->pipe; + + /* Panel hard-reset */ + if (p_funcs->reset) { + ret = p_funcs->reset(pipe); + if (ret) { + DRM_ERROR("Panel %d hard-reset failed\n", pipe); + return NULL; + } + } + + /* Panel drvIC init */ + if (p_funcs->drv_ic_init) + p_funcs->drv_ic_init(dsi_config, pipe); + + /* Panel power mode detect */ + ret = mdfld_dsi_get_power_mode(dsi_config, + &data, + MDFLD_DSI_LP_TRANSMISSION); + if (ret) { + DRM_ERROR("Panel %d get power mode failed\n", pipe); + dsi_connector->status = connector_status_disconnected; + } else { + DRM_INFO("pipe %d power mode 0x%x\n", pipe, data); + dsi_connector->status = connector_status_connected; + } + + dpi_output = kzalloc(sizeof(struct mdfld_dsi_dpi_output), GFP_KERNEL); + if(!dpi_output) { + dev_err(dev->dev, "No memory for dsi_dpi_output\n"); + return NULL; + } + + if(dsi_connector->pipe) + dpi_output->panel_on = 0; + else + dpi_output->panel_on = 0; + + dpi_output->dev = dev; + dpi_output->p_funcs = p_funcs; + dpi_output->first_boot = 1; + + /* Get fixed mode */ + dsi_config = mdfld_dsi_get_config(dsi_connector); + fixed_mode = dsi_config->fixed_mode; + + /* Create drm encoder object */ + connector = &dsi_connector->base.base; + encoder = &dpi_output->base.base; + drm_encoder_init(dev, + encoder, + p_funcs->encoder_funcs, + DRM_MODE_ENCODER_MIPI); + drm_encoder_helper_add(encoder, + p_funcs->encoder_helper_funcs); + + /* Attach to given connector */ + drm_mode_connector_attach_encoder(connector, encoder); + + /* Set possible crtcs and clones */ + if(dsi_connector->pipe) { + encoder->possible_crtcs = (1 << 2); + encoder->possible_clones = (1 << 1); + } else { + encoder->possible_crtcs = (1 << 0); + encoder->possible_clones = (1 << 0); + } + return &dpi_output->base; +} + diff --git a/drivers/staging/gma500/mdfld_dsi_dpi.h b/drivers/staging/gma500/mdfld_dsi_dpi.h new file mode 100644 index 0000000..ed92d45 --- /dev/null +++ b/drivers/staging/gma500/mdfld_dsi_dpi.h @@ -0,0 +1,78 @@ +/* + * 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; + + struct panel_funcs *p_funcs; +}; + +#define MDFLD_DSI_DPI_OUTPUT(dsi_encoder) \ + container_of(dsi_encoder, struct mdfld_dsi_dpi_output, base) + +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, + struct panel_funcs *p_funcs); + +/* Medfield DPI helper functions */ +extern void mdfld_dsi_dpi_dpms(struct drm_encoder *encoder, int mode); +extern bool mdfld_dsi_dpi_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +extern void mdfld_dsi_dpi_prepare(struct drm_encoder *encoder); +extern void mdfld_dsi_dpi_commit(struct drm_encoder *encoder); +extern void mdfld_dsi_dpi_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +extern void mdfld_dsi_dpi_turn_on(struct mdfld_dsi_dpi_output *output, + int pipe); +extern void mdfld_dsi_dpi_controller_init(struct mdfld_dsi_config *si_config, + int pipe); +#endif /*__MDFLD_DSI_DPI_H__*/ diff --git a/drivers/staging/gma500/mdfld_dsi_output.c b/drivers/staging/gma500/mdfld_dsi_output.c new file mode 100644 index 0000000..7536095 --- /dev/null +++ b/drivers/staging/gma500/mdfld_dsi_output.c @@ -0,0 +1,1011 @@ +/* + * 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_output.h" +#include "mdfld_dsi_dbi.h" +#include "mdfld_dsi_dpi.h" +#include "mdfld_output.h" +#include <asm/intel_scu_ipc.h> +#include "mdfld_dsi_pkg_sender.h" +#include <linux/pm_runtime.h> + +#define MDFLD_DSI_BRIGHTNESS_MAX_LEVEL 100 + +static int CABC_control = 1; +static int LABC_control = 1; + +module_param (CABC_control, int, 0644); +module_param (LABC_control, int, 0644); + +/** + * make these MCS command global + * we don't need 'movl' everytime we send them. + * FIXME: these datas were provided by OEM, we should get them from GCT. + **/ +static u32 mdfld_dbi_mcs_hysteresis[] = { + 0x42000f57, 0x8c006400, 0xff00bf00, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x38000aff, 0x82005000, 0xff00ab00, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0x000000ff, +}; + +static u32 mdfld_dbi_mcs_display_profile[] = { + 0x50281450, 0x0000c882, 0x00000000, 0x00000000, + 0x00000000, +}; + +static u32 mdfld_dbi_mcs_kbbc_profile[] = { + 0x00ffcc60, 0x00000000, 0x00000000, 0x00000000, +}; + +static u32 mdfld_dbi_mcs_gamma_profile[] = { + 0x81111158, 0x88888888, 0x88888888, +}; + +/* + * write hysteresis values. + */ +static void mdfld_dsi_write_hysteresis (struct mdfld_dsi_config *dsi_config, + int pipe) +{ + struct mdfld_dsi_pkg_sender *sender = mdfld_dsi_get_pkg_sender(dsi_config); + + if(!sender) { + WARN_ON(1); + return; + } + mdfld_dsi_send_mcs_long_hs(sender, + mdfld_dbi_mcs_hysteresis, + 17, + MDFLD_DSI_SEND_PACKAGE); +} + +/* + * write display profile values. + */ +static void mdfld_dsi_write_display_profile(struct mdfld_dsi_config *dsi_config, int pipe) +{ + struct mdfld_dsi_pkg_sender *sender = mdfld_dsi_get_pkg_sender(dsi_config); + + if(!sender) { + WARN_ON(1); + return; + } + mdfld_dsi_send_mcs_long_hs(sender, + mdfld_dbi_mcs_display_profile, + 5, + MDFLD_DSI_SEND_PACKAGE); +} + +/* + * write KBBC profile values. + */ +static void mdfld_dsi_write_kbbc_profile (struct mdfld_dsi_config * dsi_config, int pipe) +{ + struct mdfld_dsi_pkg_sender *sender = mdfld_dsi_get_pkg_sender(dsi_config); + + if(!sender) { + WARN_ON(1); + return; + } + mdfld_dsi_send_mcs_long_hs(sender, + mdfld_dbi_mcs_kbbc_profile, + 4, + MDFLD_DSI_SEND_PACKAGE); +} + +/* + * write gamma setting. + */ +static void mdfld_dsi_write_gamma_setting (struct mdfld_dsi_config *dsi_config, int pipe) +{ + struct mdfld_dsi_pkg_sender *sender = mdfld_dsi_get_pkg_sender(dsi_config); + + if(!sender) { + WARN_ON(1); + return; + } + mdfld_dsi_send_mcs_long_hs(sender, + mdfld_dbi_mcs_gamma_profile, + 3, + MDFLD_DSI_SEND_PACKAGE); +} + +/* + * 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 = 0; + + /* 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) + dev_err(dev->dev, + "mdfld_dsi_gen_fifo_ready, Timeout. gen_fifo_stat_reg = 0x%x. \n", + gen_fifo_stat_reg); +} + +/* + * Manage the DSI MIPI keyboard and display brightness. + * FIXME: this is exported to OSPM code. should work out an specific + * display interface to OSPM. + */ +void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config, int pipe) +{ + struct mdfld_dsi_pkg_sender *sender = mdfld_dsi_get_pkg_sender(dsi_config); + struct drm_device *dev = sender->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + u32 gen_ctrl_val; + + if(!sender) { + WARN_ON(1); + return; + } + /* Set default display backlight value to 85% (0xd8)*/ + mdfld_dsi_send_mcs_short_hs(sender, + write_display_brightness, + 0xd8, + 1, + MDFLD_DSI_SEND_PACKAGE); + + /* Set minimum brightness setting of CABC function to 20% (0x33)*/ + mdfld_dsi_send_mcs_short_hs(sender, + write_cabc_min_bright, + 0x33, + 1, + MDFLD_DSI_SEND_PACKAGE); + + mdfld_dsi_write_hysteresis(dsi_config, pipe); + mdfld_dsi_write_display_profile (dsi_config, pipe); + mdfld_dsi_write_kbbc_profile (dsi_config, pipe); + mdfld_dsi_write_gamma_setting (dsi_config, pipe); + + /* Enable backlight or/and LABC */ + gen_ctrl_val = BRIGHT_CNTL_BLOCK_ON | DISPLAY_DIMMING_ON| BACKLIGHT_ON; + if (LABC_control == 1 || CABC_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_hs(sender, + write_ctrl_display, + (u8)gen_ctrl_val, + 1, + MDFLD_DSI_SEND_PACKAGE); + + if (CABC_control == 0) + return; + mdfld_dsi_send_mcs_short_hs(sender, + write_ctrl_cabc, + UI_IMAGE, + 1, + MDFLD_DSI_SEND_PACKAGE); +} + +/* + * Manage the mipi display brightness. + * TODO: refine this interface later + */ +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; + int p_type; + + if (!dev || (pipe != 0 && pipe != 2)) { + dev_err(dev->dev, "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) { + WARN_ON(1); + return; + } + + gen_ctrl_val = ((level * 0xff) / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL) & 0xff; + + dev_dbg(dev->dev, + "pipe = %d, gen_ctrl_val = %d. \n", pipe, gen_ctrl_val); + + if(p_type == TMD_VID || p_type == TMD_CMD){ + /* Set display backlight value */ + mdfld_dsi_send_mcs_short_hs(sender, + tmd_write_display_brightness, + (u8)gen_ctrl_val, + 1, + MDFLD_DSI_SEND_PACKAGE); + } else { + /* Set display backlight value */ + mdfld_dsi_send_mcs_short_hs(sender, + write_display_brightness, + (u8)gen_ctrl_val, + 1, + MDFLD_DSI_SEND_PACKAGE); + + + /* Enable backlight control */ + if (level == 0) + gen_ctrl_val = 0; + else + gen_ctrl_val = dev_priv->mipi_ctrl_display; + + mdfld_dsi_send_mcs_short_hs(sender, + write_ctrl_display, + (u8)gen_ctrl_val, + 1, + MDFLD_DSI_SEND_PACKAGE); + } +} + +/* + * shut down DSI controller + */ +void mdfld_dsi_controller_shutdown(struct mdfld_dsi_config * dsi_config, int pipe) +{ + struct drm_device * dev; + u32 reg_offset = pipe ? MIPIC_REG_OFFSET : 0; + int retry = 100; + + if (!dsi_config) { + WARN_ON(1); + return; + } + + dev = dsi_config->dev; + + if (!gma_power_begin(dev, true)) { + dev_err(dev->dev, "hw begin failed\n"); + return; + } + + if(!(REG_READ(MIPIA_DEVICE_READY_REG + reg_offset) & DSI_DEVICE_READY)) + goto shutdown_out; + + /* Send shut down package, clean packet send bit first */ + if(REG_READ(MIPIA_INTR_STAT_REG + reg_offset) & DSI_INTR_STATE_SPL_PKG_SENT) { + REG_WRITE((MIPIA_INTR_STAT_REG + reg_offset), + (REG_READ(MIPIA_INTR_STAT_REG + reg_offset) | DSI_INTR_STATE_SPL_PKG_SENT)); + } + + /*send shut down package in HS*/ + REG_WRITE((MIPIA_DPI_CONTROL_REG + reg_offset), DSI_DPI_CTRL_HS_SHUTDOWN); + + + /* + * make sure shut down is sent. + * FIXME: add max retry counter + */ + while(!(REG_READ(MIPIA_INTR_STAT_REG + reg_offset) & DSI_INTR_STATE_SPL_PKG_SENT)) { + retry--; + + if(!retry) { + dev_err(dev->dev, "timeout\n"); + break; + } + } + + /*sleep 1 ms to ensure shutdown finished*/ + msleep(100); + + /*un-ready device*/ + REG_WRITE((MIPIA_DEVICE_READY_REG + reg_offset), + (REG_READ(MIPIA_DEVICE_READY_REG + reg_offset) & ~DSI_DEVICE_READY)); + +shutdown_out: + gma_power_end(dev); +} + +void mdfld_dsi_controller_startup(struct mdfld_dsi_config * dsi_config, int pipe) +{ + struct drm_device * dev; + u32 reg_offset = pipe ? MIPIC_REG_OFFSET : 0; + int retry = 100; + + + if (!dsi_config) { + WARN_ON(1); + return; + } + + dev = dsi_config->dev; + dev_dbg(dev->dev, "starting up DSI controller on pipe %d...\n", pipe); + + if (!gma_power_begin(dev, true)) { + dev_err(dev->dev, "hw begin failed\n"); + return; + } + + if((REG_READ(MIPIA_DEVICE_READY_REG + reg_offset) & DSI_DEVICE_READY)) + goto startup_out; + + /*if config DPI, turn on DPI interface*/ + if(dsi_config->type == MDFLD_DSI_ENCODER_DPI) { + if(REG_READ(MIPIA_INTR_STAT_REG + reg_offset) & DSI_INTR_STATE_SPL_PKG_SENT) { + REG_WRITE((MIPIA_INTR_STAT_REG + reg_offset), DSI_INTR_STATE_SPL_PKG_SENT); + } + + REG_WRITE((MIPIA_DPI_CONTROL_REG + reg_offset), DSI_DPI_CTRL_HS_TURN_ON); + + /* + * make sure shut down is sent. + * FIXME: add max retry counter + */ + while(!(REG_READ(MIPIA_INTR_STAT_REG + reg_offset) & DSI_INTR_STATE_SPL_PKG_SENT)) { + retry--; + if(!retry) { + dev_err(dev->dev, "timeout\n"); + break; + } + } + + msleep(100); + } + + /*set device ready*/ + REG_WRITE((MIPIA_DEVICE_READY_REG + reg_offset), + (REG_READ(MIPIA_DEVICE_READY_REG + reg_offset) | DSI_DEVICE_READY)); + +startup_out: + gma_power_end(dev); +} + + +static int mdfld_dsi_get_panel_status(struct mdfld_dsi_config *dsi_config, + u8 dcs, + u32 *data, + u8 transmission) +{ + struct mdfld_dsi_pkg_sender *sender + = mdfld_dsi_get_pkg_sender(dsi_config); + + if (!sender || !data) { + DRM_ERROR("Invalid parameter\n"); + return -EINVAL; + } + + if (transmission == MDFLD_DSI_HS_TRANSMISSION) + return mdfld_dsi_read_mcs_hs(sender, dcs, data, 1); + else if (transmission == MDFLD_DSI_LP_TRANSMISSION) + return mdfld_dsi_read_mcs_lp(sender, dcs, data, 1); + else + return -EINVAL; +} + +int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config, + u32 *mode, + u8 transmission) +{ + if (!dsi_config || !mode) { + DRM_ERROR("Invalid parameter\n"); + return -EINVAL; + } + + return mdfld_dsi_get_panel_status(dsi_config, 0x0a, mode, transmission); +} + +int mdfld_dsi_get_diagnostic_result(struct mdfld_dsi_config *dsi_config, + u32 *result, + u8 transmission) +{ + if (!dsi_config || !result) { + DRM_ERROR("Invalid parameter\n"); + return -EINVAL; + } + + return mdfld_dsi_get_panel_status(dsi_config, 0x0f, result, + transmission); +} + +/* + * 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))) { + WARN_ON(1); + return; + } + + if(dsi_config->type) + mdfld_dsi_dpi_controller_init(dsi_config, pipe); + else + mdfld_dsi_controller_dbi_init(dsi_config, pipe); +} + +static void mdfld_dsi_connector_save(struct drm_connector * connector) +{ +} + +static void mdfld_dsi_connector_restore(struct drm_connector * connector) +{ +} + +static enum drm_connector_status mdfld_dsi_connector_detect(struct drm_connector * connector, bool force) +{ + struct psb_intel_output *psb_output + = to_psb_intel_output(connector); + struct mdfld_dsi_connector *dsi_connector + = MDFLD_DSI_CONNECTOR(psb_output); + 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 psb_intel_crtc * psb_crtc = to_psb_intel_crtc(encoder->crtc); + bool bTransitionFromToCentered; + uint64_t curValue; + + if (!psb_crtc) + goto set_prop_error; + + switch (value) { + case DRM_MODE_SCALE_FULLSCREEN: + break; + case DRM_MODE_SCALE_NO_SCALE: + break; + case DRM_MODE_SCALE_ASPECT: + break; + default: + goto set_prop_error; + } + + if (drm_connector_property_get_value(connector, property, &curValue)) + goto set_prop_error; + + if (curValue == value) + goto set_prop_done; + + if (drm_connector_property_set_value(connector, property, value)) + goto set_prop_error; + + bTransitionFromToCentered = (curValue == DRM_MODE_SCALE_NO_SCALE) || + (value == DRM_MODE_SCALE_NO_SCALE); + + if (psb_crtc->saved_mode.hdisplay != 0 && + psb_crtc->saved_mode.vdisplay != 0) { + if (bTransitionFromToCentered) { + if (!drm_crtc_helper_set_mode(encoder->crtc, &psb_crtc->saved_mode, + encoder->crtc->x, encoder->crtc->y, encoder->crtc->fb)) + goto set_prop_error; + } else { + struct drm_encoder_helper_funcs *pEncHFuncs = encoder->helper_private; + pEncHFuncs->mode_set(encoder, &psb_crtc->saved_mode, + &psb_crtc->saved_adjusted_mode); + } + } +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + } else if (!strcmp(property->name, "backlight") && encoder) { + struct drm_psb_private *dev_priv = encoder->dev->dev_private; + struct backlight_device *psb_bd = dev_priv->backlight_device; + dev_dbg(encoder->dev->dev, "backlight level = %d\n", (int)value); + if (drm_connector_property_set_value(connector, property, value)) + goto set_prop_error; + else { + dev_dbg(encoder->dev->dev, + "set brightness to %d", (int)value); + if (psb_bd) { + psb_bd->props.brightness = value; + backlight_update_status(psb_bd); + } + } +#endif + } +set_prop_done: + return 0; +set_prop_error: + return -1; +} + +static void mdfld_dsi_connector_destroy(struct drm_connector *connector) +{ + struct psb_intel_output * psb_output = to_psb_intel_output(connector); + struct mdfld_dsi_connector * dsi_connector = MDFLD_DSI_CONNECTOR(psb_output); + struct mdfld_dsi_pkg_sender * sender; + + if(!dsi_connector) + return; + + drm_sysfs_connector_remove(connector); + drm_connector_cleanup(connector); + + sender = dsi_connector->pkg_sender; + + mdfld_dsi_pkg_sender_destroy(sender); + + kfree(dsi_connector); +} + +static int mdfld_dsi_connector_get_modes(struct drm_connector * connector) +{ + struct psb_intel_output * psb_output = to_psb_intel_output(connector); + struct mdfld_dsi_connector * dsi_connector = MDFLD_DSI_CONNECTOR(psb_output); + struct mdfld_dsi_config * dsi_config = mdfld_dsi_get_config(dsi_connector); + struct drm_display_mode * fixed_mode = dsi_config->fixed_mode; + struct drm_display_mode * dup_mode = NULL; + struct drm_device * dev = connector->dev; + + connector->display_info.min_vfreq = 0; + connector->display_info.max_vfreq = 200; + connector->display_info.min_hfreq = 0; + connector->display_info.max_hfreq = 200; + + if(fixed_mode) { + dev_dbg(dev->dev, "fixed_mode %dx%d\n", + fixed_mode->hdisplay, fixed_mode->vdisplay); + + dup_mode = drm_mode_duplicate(dev, fixed_mode); + drm_mode_probed_add(connector, dup_mode); + return 1; + } + dev_err(dev->dev, "Didn't get any modes!\n"); + return 0; +} + +static int mdfld_dsi_connector_mode_valid(struct drm_connector * connector, struct drm_display_mode * mode) +{ + struct psb_intel_output * psb_output = to_psb_intel_output(connector); + struct mdfld_dsi_connector * dsi_connector = MDFLD_DSI_CONNECTOR(psb_output); + struct mdfld_dsi_config * dsi_config = mdfld_dsi_get_config(dsi_connector); + struct drm_display_mode * fixed_mode = dsi_config->fixed_mode; + + dev_dbg(connector->dev->dev, "mode %p, fixed mode %p\n", + mode, fixed_mode); + + if(mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + + if(mode->flags & DRM_MODE_FLAG_INTERLACE) + return MODE_NO_INTERLACE; + + /** + * FIXME: current DC has no fitting unit, reject any mode setting request + * will figure out a way to do up-scaling(pannel fitting) later. + **/ + if(fixed_mode) { + if(mode->hdisplay != fixed_mode->hdisplay) + return MODE_PANEL; + + if(mode->vdisplay != fixed_mode->vdisplay) + return MODE_PANEL; + } + dev_dbg(connector->dev->dev, "mode ok\n"); + + return MODE_OK; +} + +static void mdfld_dsi_connector_dpms(struct drm_connector *connector, int mode) +{ +#ifdef CONFIG_PM_RUNTIME + struct drm_device * dev = connector->dev; + struct drm_psb_private * dev_priv = dev->dev_private; + bool panel_on, panel_on2; +#endif + /* First, execute DPMS */ + drm_helper_connector_dpms(connector, mode); + +#ifdef CONFIG_PM_RUNTIME + if(mdfld_panel_dpi(dev)) { + /* DPI panel */ + panel_on = dev_priv->dpi_panel_on; + panel_on2 = dev_priv->dpi_panel_on2; + } else { + /* DBI panel */ + panel_on = dev_priv->dbi_panel_on; + panel_on2 = dev_priv->dbi_panel_on2; + } + + /* Then check all display panels + monitors status */ + /* Make sure that the Display (B) sub-system status isn't i3 when + * R/W the DC register, otherwise "Fabric error" issue would occur + * during S0i3 state. */ + if(!panel_on && !panel_on2 && !(REG_READ(HDMIB_CONTROL) + & HDMIB_PORT_EN)) { + /* Request rpm idle */ + if(dev_priv->rpm_enabled) + pm_request_idle(&dev->pdev->dev); + } + /* + * if rpm wasn't enabled yet, try to allow it + * FIXME: won't enable rpm for DPI since DPI + * CRTC setting is a little messy now. + * Enable it later! + */ +#if 0 + if(!dev_priv->rpm_enabled && !mdfld_panel_dpi(dev)) + ospm_runtime_pm_allow(dev); +#endif +#endif +} + +static struct drm_encoder *mdfld_dsi_connector_best_encoder( + struct drm_connector *connector) +{ + struct psb_intel_output * psb_output = to_psb_intel_output(connector); + struct mdfld_dsi_connector * dsi_connector = MDFLD_DSI_CONNECTOR(psb_output); + struct mdfld_dsi_config * dsi_config = mdfld_dsi_get_config(dsi_connector); + struct mdfld_dsi_encoder * encoder = NULL; + + if(dsi_config->type == MDFLD_DSI_ENCODER_DBI) + encoder = dsi_config->encoders[MDFLD_DSI_ENCODER_DBI]; + else if (dsi_config->type == MDFLD_DSI_ENCODER_DPI) + encoder = dsi_config->encoders[MDFLD_DSI_ENCODER_DPI]; + + dev_dbg(connector->dev->dev, "get encoder %p\n", encoder); + + if(!encoder) { + dev_err(connector->dev->dev, + "Invalid encoder for type %d\n", dsi_config->type); + return NULL; + } + dsi_config->encoder = encoder; + return &encoder->base; +} + +/* DSI connector funcs */ +static const struct drm_connector_funcs mdfld_dsi_connector_funcs = { + .dpms = /*drm_helper_connector_dpms*/mdfld_dsi_connector_dpms, + .save = mdfld_dsi_connector_save, + .restore = mdfld_dsi_connector_restore, + .detect = mdfld_dsi_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .set_property = mdfld_dsi_connector_set_property, + .destroy = mdfld_dsi_connector_destroy, +}; + +/* DSI connector helper funcs */ +static const struct drm_connector_helper_funcs mdfld_dsi_connector_helper_funcs = { + .get_modes = mdfld_dsi_connector_get_modes, + .mode_valid = mdfld_dsi_connector_mode_valid, + .best_encoder = mdfld_dsi_connector_best_encoder, +}; + +static int mdfld_dsi_get_default_config(struct drm_device * dev, + struct mdfld_dsi_config * config, int pipe) +{ + if(!dev || !config) { + WARN_ON(1); + return -EINVAL; + } + + config->bpp = 24; + config->type = mdfld_panel_dpi(dev); + config->lane_count = 2; + config->channel_num = 0; + /*NOTE: video mode is ignored when type is MDFLD_DSI_ENCODER_DBI*/ + if (mdfld_get_panel_type(dev, pipe) == TMD_VID) { + config->video_mode = MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE; + } else { + config->video_mode = MDFLD_DSI_VIDEO_BURST_MODE; + } + + return 0; +} + +/* + * Returns the panel fixed mode from configuration. + */ +struct drm_display_mode * +mdfld_dsi_get_configuration_mode(struct mdfld_dsi_config * dsi_config, int pipe) +{ + struct drm_device *dev = dsi_config->dev; + struct drm_display_mode *mode; + struct drm_psb_private *dev_priv = dev->dev_private; + struct mrst_timing_info *ti = &dev_priv->gct_data.DTD; + bool use_gct = false; + + mode = kzalloc(sizeof(*mode), GFP_KERNEL); + if (!mode) { + dev_err(dev->dev, "Out of memory for mode\n"); + return NULL; + } + if (use_gct) { + dev_dbg(dev->dev, "gct find MIPI panel.\n"); + + 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; + } else { + if(dsi_config->type == MDFLD_DSI_ENCODER_DPI) { + if (mdfld_get_panel_type(dev, pipe) == TMD_VID) { + 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; + } else { + mode->hdisplay = 864; + mode->vdisplay = 480; + mode->hsync_start = 873; + mode->hsync_end = 876; + mode->htotal = 887; + mode->vsync_start = 487; + mode->vsync_end = 490; + mode->vtotal = 499; + mode->clock = 33264; + } + } else if(dsi_config->type == MDFLD_DSI_ENCODER_DBI) { + mode->hdisplay = 864; + mode->vdisplay = 480; + mode->hsync_start = 872; + mode->hsync_end = 876; + mode->htotal = 884; + mode->vsync_start = 482; + mode->vsync_end = 494; + mode->vtotal = 486; + mode->clock = 25777; + + } + } + + drm_mode_set_name(mode); + drm_mode_set_crtcinfo(mode, 0); + + mode->type |= DRM_MODE_TYPE_PREFERRED; + + return mode; +} + +int mdfld_dsi_panel_reset(int pipe) +{ + unsigned gpio; + int ret = 0; + + switch (pipe) { + case 0: + gpio = 128; + break; + case 2: + gpio = 34; + break; + default: + DRM_ERROR("Invalid output\n"); + return -EINVAL; + } + + ret = gpio_request(gpio, "gfx"); + if (ret) { + DRM_ERROR("gpio_rqueset failed\n"); + return ret; + } + + ret = gpio_direction_output(gpio, 1); + if (ret) { + DRM_ERROR("gpio_direction_output failed\n"); + goto gpio_error; + } + + gpio_get_value(128); + +gpio_error: + if (gpio_is_valid(gpio)) + gpio_free(gpio); + + return ret; +} + +/* + * MIPI output init + * @dev drm device + * @pipe pipe number. 0 or 2 + * @config + * + * Do the initialization of a MIPI output, including create DRM mode objects + * initialization of DSI output on @pipe + */ +void mdfld_dsi_output_init(struct drm_device *dev, + int pipe, + struct mdfld_dsi_config *config, + struct panel_funcs* p_cmd_funcs, + struct panel_funcs* p_vid_funcs) +{ + struct mdfld_dsi_config * dsi_config; + struct mdfld_dsi_connector * dsi_connector; + struct psb_intel_output * psb_output; + struct drm_connector * connector; + struct mdfld_dsi_encoder * encoder; + struct drm_psb_private * dev_priv = dev->dev_private; + struct panel_info dsi_panel_info; + u32 width_mm, height_mm; + + dev_dbg(dev->dev, "init DSI output on pipe %d\n", pipe); + + if(!dev || ((pipe != 0) && (pipe != 2))) { + WARN_ON(1); + return; + } + + /*create a new connetor*/ + dsi_connector = kzalloc(sizeof(struct mdfld_dsi_connector), GFP_KERNEL); + if(!dsi_connector) { + DRM_ERROR("No memory"); + return; + } + + dsi_connector->pipe = pipe; + + /*set DSI config*/ + if(config) { + dsi_config = config; + } else { + dsi_config = kzalloc(sizeof(struct mdfld_dsi_config), GFP_KERNEL); + if(!dsi_config) { + dev_err(dev->dev, + "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; + + /* Init fixed mode basing on DSI config type */ + if(dsi_config->type == MDFLD_DSI_ENCODER_DBI) { + dsi_config->fixed_mode = p_cmd_funcs->get_config_mode(dev); + if(p_cmd_funcs->get_panel_info(dev, pipe, &dsi_panel_info)) + goto dsi_init_err0; + } else if(dsi_config->type == MDFLD_DSI_ENCODER_DPI) { + 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) { + dev_err(dev->dev, "No pannel fixed mode was found\n"); + goto dsi_init_err0; + } + + if(pipe && dev_priv->dsi_configs[0]) { + dsi_config->dvr_ic_inited = 0; + dev_priv->dsi_configs[1] = dsi_config; + } else if(pipe == 0) { + dsi_config->dvr_ic_inited = 1; + dev_priv->dsi_configs[0] = dsi_config; + } else { + dev_err(dev->dev, "Trying to init MIPI1 before MIPI0\n"); + goto dsi_init_err0; + } + + /*init drm connector object*/ + psb_output = &dsi_connector->base; + + psb_output->type = (pipe == 0) ? INTEL_OUTPUT_MIPI : INTEL_OUTPUT_MIPI2; + + connector = &psb_output->base; + drm_connector_init(dev, connector, &mdfld_dsi_connector_funcs, DRM_MODE_CONNECTOR_MIPI); + drm_connector_helper_add(connector, &mdfld_dsi_connector_helper_funcs); + + connector->display_info.subpixel_order = SubPixelHorizontalRGB; + connector->display_info.width_mm = width_mm; + connector->display_info.height_mm = height_mm; + connector->interlace_allowed = false; + connector->doublescan_allowed = false; + + /* Attach properties */ + drm_connector_attach_property(connector, dev->mode_config.scaling_mode_property, DRM_MODE_SCALE_FULLSCREEN); + drm_connector_attach_property(connector, dev_priv->backlight_property, MDFLD_DSI_BRIGHTNESS_MAX_LEVEL); + + /* Init DSI package sender on this output */ + if (mdfld_dsi_pkg_sender_init(dsi_connector, pipe)) { + DRM_ERROR("Package Sender initialization failed on pipe %d\n", pipe); + goto dsi_init_err0; + } + + /* Init DBI & DPI encoders */ + if (p_cmd_funcs) { + encoder = mdfld_dsi_dbi_init(dev, dsi_connector, p_cmd_funcs); + if(!encoder) { + dev_err(dev->dev, "Create DBI encoder failed\n"); + goto dsi_init_err1; + } + encoder->private = dsi_config; + dsi_config->encoders[MDFLD_DSI_ENCODER_DBI] = encoder; + } + + if(p_vid_funcs) { + encoder = mdfld_dsi_dpi_init(dev, dsi_connector, p_vid_funcs); + if(!encoder) { + dev_err(dev->dev, "Create DPI encoder failed\n"); + goto dsi_init_err1; + } + encoder->private = dsi_config; + dsi_config->encoders[MDFLD_DSI_ENCODER_DPI] = encoder; + } + + drm_sysfs_connector_add(connector); + return; + + /*TODO: add code to destroy outputs on error*/ +dsi_init_err1: + /*destroy sender*/ + mdfld_dsi_pkg_sender_destroy(dsi_connector->pkg_sender); + + drm_connector_cleanup(connector); + kfree(dsi_config->fixed_mode); + kfree(dsi_config); +dsi_init_err0: + kfree(dsi_connector); +} diff --git a/drivers/staging/gma500/mdfld_dsi_output.h b/drivers/staging/gma500/mdfld_dsi_output.h new file mode 100644 index 0000000..4699267 --- /dev/null +++ b/drivers/staging/gma500/mdfld_dsi_output.h @@ -0,0 +1,138 @@ +/* + * 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 <drm/drmP.h> +#include <drm/drm.h> +#include <drm/drm_crtc.h> +#include <drm/drm_edid.h> + +#include "psb_drv.h" +#include "psb_intel_drv.h" +#include "psb_intel_reg.h" +#include "power.h" +#include "mdfld_output.h" + +#include <asm/mrst.h> + + +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; +} + +extern void mdfld_dsi_gen_fifo_ready(struct drm_device *dev, + u32 gen_fifo_stat_reg, u32 fifo_stat); +extern void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config, + int pipe); +extern void mdfld_dsi_brightness_control(struct drm_device *dev, int pipe, + int level); +extern void mdfld_dsi_output_init(struct drm_device *dev, int pipe, + struct mdfld_dsi_config *config, + struct panel_funcs *p_cmd_funcs, + 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, + u8 transmission); +extern int mdfld_dsi_get_diagnostic_result(struct mdfld_dsi_config *dsi_config, + u32 *result, + u8 transmission); +extern int mdfld_dsi_panel_reset(int pipe); + +#endif /*__MDFLD_DSI_OUTPUT_H__*/ diff --git a/drivers/staging/gma500/mdfld_dsi_pkg_sender.c b/drivers/staging/gma500/mdfld_dsi_pkg_sender.c new file mode 100644 index 0000000..9b96a5c --- /dev/null +++ b/drivers/staging/gma500/mdfld_dsi_pkg_sender.c @@ -0,0 +1,1484 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Jackie Li<yaodong.li@intel.com> + */ + +#include <linux/freezer.h> + +#include "mdfld_dsi_output.h" +#include "mdfld_dsi_pkg_sender.h" +#include "mdfld_dsi_dbi.h" +#include "mdfld_dsi_dpi.h" + +#define MDFLD_DSI_DBI_FIFO_TIMEOUT 100 +#define MDFLD_DSI_MAX_RETURN_PACKET_SIZE 512 +#define MDFLD_DSI_READ_MAX_COUNT 5000 + +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 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); + } + dev_err(dev->dev, "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, (1 << 2) | (1 << 10) | (1 << 18) + | (1 << 26) | (1 << 27) | (1 << 28)); +} + +static int wait_for_lp_fifos_empty(struct mdfld_dsi_pkg_sender *sender) +{ + return wait_for_gen_fifo_empty(sender, (1 << 10) | (1 << 26)); +} + +static int wait_for_hs_fifos_empty(struct mdfld_dsi_pkg_sender *sender) +{ + return wait_for_gen_fifo_empty(sender, (1 << 2) | (1 << 18)); +} + +static int wait_for_dbi_fifo_empty(struct mdfld_dsi_pkg_sender *sender) +{ + return wait_for_gen_fifo_empty(sender, (1 << 27)); +} + +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; + + switch (mask) { + case (1 << 0): + case (1 << 1): + case (1 << 2): + case (1 << 3): + case (1 << 4): + case (1 << 5): + case (1 << 6): + case (1 << 7): + case (1 << 8): + case (1 << 9): + case (1 << 10): + case (1 << 11): + case (1 << 12): + case (1 << 13): + break; + case (1 << 14): + /*wait for all fifo empty*/ + /*wait_for_all_fifos_empty(sender)*/; + break; + case (1 << 15): + break; + case (1 << 16): + break; + case (1 << 17): + break; + case (1 << 18): + case (1 << 19): + /*wait for contention recovery time*/ + /*mdelay(10);*/ + /*wait for all fifo empty*/ + if (0) + wait_for_all_fifos_empty(sender); + break; + case (1 << 20): + break; + case (1 << 21): + /*wait for all fifo empty*/ + /*wait_for_all_fifos_empty(sender);*/ + break; + case (1 << 22): + break; + case (1 << 23): + case (1 << 24): + case (1 << 25): + case (1 << 26): + case (1 << 27): + /* HS Gen fifo full */ + REG_WRITE(intr_stat_reg, mask); + wait_for_hs_fifos_empty(sender); + break; + case (1 << 28): + /* LP Gen fifo full\n */ + REG_WRITE(intr_stat_reg, mask); + wait_for_lp_fifos_empty(sender); + break; + case (1 << 29): + case (1 << 30): + case (1 << 31): + break; + } + + if (mask & REG_READ(intr_stat_reg)) + dev_warn(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(dev->dev, "[DSI]: %s\n", dsi_errors[i]); + err = handle_dsi_error(sender, mask); + if (err) + dev_err(dev->dev, "Cannot handle error\n"); + } + } + return err; +} + +static inline int dbi_cmd_sent(struct mdfld_dsi_pkg_sender *sender) +{ + struct drm_device *dev = sender->dev; + u32 retry = 0xffff; + u32 dbi_cmd_addr_reg = sender->mipi_cmd_addr_reg; + + /* Query the command execution status */ + while (retry--) { + if (!(REG_READ(dbi_cmd_addr_reg) & (1 << 0))) + break; + } + + if (!retry) { + dev_err(dev->dev, "Timeout waiting for DBI Command status\n"); + return -EAGAIN; + } + return 0; +} + +/* + * NOTE: this interface is abandoned expect for write_mem_start DCS + * other DCS are sent via generic pkg interfaces + */ +static int send_dcs_pkg(struct mdfld_dsi_pkg_sender *sender, + struct mdfld_dsi_pkg *pkg) +{ + struct drm_device *dev = sender->dev; + struct mdfld_dsi_dcs_pkg *dcs_pkg = &pkg->pkg.dcs_pkg; + u32 dbi_cmd_len_reg = sender->mipi_cmd_len_reg; + u32 dbi_cmd_addr_reg = sender->mipi_cmd_addr_reg; + u32 cb_phy = sender->dbi_cb_phy; + u32 index = 0; + u8 *cb = (u8 *)sender->dbi_cb_addr; + int i; + int ret; + + if (!sender->dbi_pkg_support) { + dev_err(dev->dev, "Trying to send DCS on a non DBI output, abort!\n"); + return -ENOTSUPP; + } + + /*wait for DBI fifo empty*/ + wait_for_dbi_fifo_empty(sender); + + *(cb + (index++)) = dcs_pkg->cmd; + if (dcs_pkg->param_num) { + for (i = 0; i < dcs_pkg->param_num; i++) + *(cb + (index++)) = *(dcs_pkg->param + i); + } + + REG_WRITE(dbi_cmd_len_reg, (1 + dcs_pkg->param_num)); + REG_WRITE(dbi_cmd_addr_reg, + (cb_phy << CMD_MEM_ADDR_OFFSET) + | (1 << 0) + | ((dcs_pkg->data_src == CMD_DATA_SRC_PIPE) ? (1 << 1) : 0)); + + ret = dbi_cmd_sent(sender); + if (ret) { + dev_err(dev->dev, "command 0x%x not complete\n", dcs_pkg->cmd); + return -EAGAIN; + } + return 0; +} + +static int __send_short_pkg(struct mdfld_dsi_pkg_sender *sender, + struct mdfld_dsi_pkg *pkg) +{ + struct drm_device *dev = sender->dev; + u32 hs_gen_ctrl_reg = sender->mipi_hs_gen_ctrl_reg; + u32 lp_gen_ctrl_reg = sender->mipi_lp_gen_ctrl_reg; + u32 gen_ctrl_val = 0; + struct mdfld_dsi_gen_short_pkg *short_pkg = &pkg->pkg.short_pkg; + + gen_ctrl_val |= short_pkg->cmd << MCS_COMMANDS_POS; + gen_ctrl_val |= 0 << DCS_CHANNEL_NUMBER_POS; + gen_ctrl_val |= pkg->pkg_type; + gen_ctrl_val |= short_pkg->param << MCS_PARAMETER_POS; + + if (pkg->transmission_type == MDFLD_DSI_HS_TRANSMISSION) { + /* wait for hs fifo empty */ + /* wait_for_hs_fifos_empty(sender); */ + /* Send pkg */ + REG_WRITE(hs_gen_ctrl_reg, gen_ctrl_val); + } else if (pkg->transmission_type == MDFLD_DSI_LP_TRANSMISSION) { + /* wait_for_lp_fifos_empty(sender); */ + /* Send pkg*/ + REG_WRITE(lp_gen_ctrl_reg, gen_ctrl_val); + } else { + dev_err(dev->dev, "Unknown transmission type %d\n", + pkg->transmission_type); + return -EINVAL; + } + + return 0; +} + +static int __send_long_pkg(struct mdfld_dsi_pkg_sender *sender, + struct mdfld_dsi_pkg *pkg) +{ + struct drm_device *dev = sender->dev; + u32 hs_gen_ctrl_reg = sender->mipi_hs_gen_ctrl_reg; + u32 hs_gen_data_reg = sender->mipi_hs_gen_data_reg; + u32 lp_gen_ctrl_reg = sender->mipi_lp_gen_ctrl_reg; + u32 lp_gen_data_reg = sender->mipi_lp_gen_data_reg; + u32 gen_ctrl_val = 0; + u32 *dp; + int i; + struct mdfld_dsi_gen_long_pkg *long_pkg = &pkg->pkg.long_pkg; + + dp = long_pkg->data; + + /* + * Set up word count for long pkg + * FIXME: double check word count field. + * currently, using the byte counts of the payload as the word count. + * ------------------------------------------------------------ + * | DI | WC | ECC| PAYLOAD |CHECKSUM| + * ------------------------------------------------------------ + */ + gen_ctrl_val |= (long_pkg->len << 2) << WORD_COUNTS_POS; + gen_ctrl_val |= 0 << DCS_CHANNEL_NUMBER_POS; + gen_ctrl_val |= pkg->pkg_type; + + if (pkg->transmission_type == MDFLD_DSI_HS_TRANSMISSION) { + /* Wait for hs ctrl and data fifos to be empty */ + /* wait_for_hs_fifos_empty(sender); */ + for (i = 0; i < long_pkg->len; i++) + REG_WRITE(hs_gen_data_reg, *(dp + i)); + REG_WRITE(hs_gen_ctrl_reg, gen_ctrl_val); + } else if (pkg->transmission_type == MDFLD_DSI_LP_TRANSMISSION) { + /* wait_for_lp_fifos_empty(sender); */ + for (i = 0; i < long_pkg->len; i++) + REG_WRITE(lp_gen_data_reg, *(dp + i)); + REG_WRITE(lp_gen_ctrl_reg, gen_ctrl_val); + } else { + dev_err(dev->dev, "Unknown transmission type %d\n", + pkg->transmission_type); + return -EINVAL; + } + + return 0; + +} + +static int send_mcs_short_pkg(struct mdfld_dsi_pkg_sender *sender, + struct mdfld_dsi_pkg *pkg) +{ + return __send_short_pkg(sender, pkg); +} + +static int send_mcs_long_pkg(struct mdfld_dsi_pkg_sender *sender, + struct mdfld_dsi_pkg *pkg) +{ + return __send_long_pkg(sender, pkg); +} + +static int send_gen_short_pkg(struct mdfld_dsi_pkg_sender *sender, + struct mdfld_dsi_pkg *pkg) +{ + return __send_short_pkg(sender, pkg); +} + +static int send_gen_long_pkg(struct mdfld_dsi_pkg_sender *sender, + struct mdfld_dsi_pkg *pkg) +{ + return __send_long_pkg(sender, pkg); +} + +static int send_pkg_prepare(struct mdfld_dsi_pkg_sender *sender, + struct mdfld_dsi_pkg *pkg) +{ + u8 cmd; + u8 *data; + + switch (pkg->pkg_type) { + case MDFLD_DSI_PKG_DCS: + cmd = pkg->pkg.dcs_pkg.cmd; + break; + case MDFLD_DSI_PKG_MCS_SHORT_WRITE_0: + case MDFLD_DSI_PKG_MCS_SHORT_WRITE_1: + cmd = pkg->pkg.short_pkg.cmd; + break; + case MDFLD_DSI_PKG_MCS_LONG_WRITE: + data = (u8 *)pkg->pkg.long_pkg.data; + cmd = *data; + break; + default: + return 0; + } + + /* This prevents other package sending while doing msleep */ + sender->status = MDFLD_DSI_PKG_SENDER_BUSY; + + /* Check panel mode v.s. sending command */ + if ((sender->panel_mode & MDFLD_DSI_PANEL_MODE_SLEEP) && + cmd != exit_sleep_mode) { + dev_err(sender->dev->dev, + "sending 0x%x when panel sleep in\n", cmd); + sender->status = MDFLD_DSI_PKG_SENDER_FREE; + return -EINVAL; + } + + /* Wait for 120 milliseconds in case exit_sleep_mode just be sent */ + if (cmd == DCS_ENTER_SLEEP_MODE) { + /*TODO: replace it with msleep later*/ + mdelay(120); + } + return 0; +} + +static int send_pkg_done(struct mdfld_dsi_pkg_sender *sender, + struct mdfld_dsi_pkg *pkg) +{ + u8 cmd; + u8 *data; + + switch (pkg->pkg_type) { + case MDFLD_DSI_PKG_DCS: + cmd = pkg->pkg.dcs_pkg.cmd; + break; + case MDFLD_DSI_PKG_MCS_SHORT_WRITE_0: + case MDFLD_DSI_PKG_MCS_SHORT_WRITE_1: + cmd = pkg->pkg.short_pkg.cmd; + break; + case MDFLD_DSI_PKG_MCS_LONG_WRITE: + data = (u8 *)pkg->pkg.long_pkg.data; + cmd = *data; + break; + default: + return 0; + } + + /* Update panel status */ + if (cmd == DCS_ENTER_SLEEP_MODE) { + sender->panel_mode |= MDFLD_DSI_PANEL_MODE_SLEEP; + /*TODO: replace it with msleep later*/ + mdelay(120); + } else if (cmd == DCS_EXIT_SLEEP_MODE) { + sender->panel_mode &= ~MDFLD_DSI_PANEL_MODE_SLEEP; + /*TODO: replace it with msleep later*/ + mdelay(120); + } else if (unlikely(cmd == DCS_SOFT_RESET)) { + /*TODO: replace it with msleep later*/ + mdelay(5); + } + sender->status = MDFLD_DSI_PKG_SENDER_FREE; + return 0; + +} + +static int do_send_pkg(struct mdfld_dsi_pkg_sender *sender, + struct mdfld_dsi_pkg *pkg) +{ + int ret; + + if (sender->status == MDFLD_DSI_PKG_SENDER_BUSY) { + dev_err(sender->dev->dev, "sender is busy\n"); + return -EAGAIN; + } + + ret = send_pkg_prepare(sender, pkg); + if (ret) { + dev_err(sender->dev->dev, "send_pkg_prepare error\n"); + return ret; + } + + switch (pkg->pkg_type) { + case MDFLD_DSI_PKG_DCS: + ret = send_dcs_pkg(sender, pkg); + break; + case MDFLD_DSI_PKG_GEN_SHORT_WRITE_0: + case MDFLD_DSI_PKG_GEN_SHORT_WRITE_1: + case MDFLD_DSI_PKG_GEN_SHORT_WRITE_2: + case MDFLD_DSI_PKG_GEN_READ_0: + case MDFLD_DSI_PKG_GEN_READ_1: + case MDFLD_DSI_PKG_GEN_READ_2: + ret = send_gen_short_pkg(sender, pkg); + break; + case MDFLD_DSI_PKG_GEN_LONG_WRITE: + ret = send_gen_long_pkg(sender, pkg); + break; + case MDFLD_DSI_PKG_MCS_SHORT_WRITE_0: + case MDFLD_DSI_PKG_MCS_SHORT_WRITE_1: + case MDFLD_DSI_PKG_MCS_READ: + ret = send_mcs_short_pkg(sender, pkg); + break; + case MDFLD_DSI_PKG_MCS_LONG_WRITE: + ret = send_mcs_long_pkg(sender, pkg); + break; + default: + dev_err(sender->dev->dev, "Invalid pkg type 0x%x\n", + pkg->pkg_type); + ret = -EINVAL; + } + send_pkg_done(sender, pkg); + return ret; +} + +static int send_pkg(struct mdfld_dsi_pkg_sender *sender, + struct mdfld_dsi_pkg *pkg) +{ + int err ; + + /* Handle DSI error */ + err = dsi_error_handler(sender); + if (err) { + dev_err(sender->dev->dev, "Error handling failed\n"); + err = -EAGAIN; + goto send_pkg_err; + } + + /* Send pkg */ + err = do_send_pkg(sender, pkg); + if (err) { + dev_err(sender->dev->dev, "sent pkg failed\n"); + err = -EAGAIN; + goto send_pkg_err; + } + + /* FIXME: should I query complete and fifo empty here? */ +send_pkg_err: + return err; +} + +static struct mdfld_dsi_pkg *pkg_sender_get_pkg_locked( + struct mdfld_dsi_pkg_sender *sender) +{ + struct mdfld_dsi_pkg *pkg; + + if (list_empty(&sender->free_list)) { + dev_err(sender->dev->dev, "No free pkg left\n"); + return NULL; + } + pkg = list_first_entry(&sender->free_list, struct mdfld_dsi_pkg, entry); + /* Detach from free list */ + list_del_init(&pkg->entry); + return pkg; +} + +static void pkg_sender_put_pkg_locked(struct mdfld_dsi_pkg_sender *sender, + struct mdfld_dsi_pkg *pkg) +{ + memset(pkg, 0, sizeof(struct mdfld_dsi_pkg)); + INIT_LIST_HEAD(&pkg->entry); + list_add_tail(&pkg->entry, &sender->free_list); +} + +static int mdfld_dbi_cb_init(struct mdfld_dsi_pkg_sender *sender, + struct psb_gtt *pg, int pipe) +{ + unsigned long phys; + void *virt_addr = NULL; + + switch (pipe) { + case 0: + /* FIXME: Doesn't this collide with stolen space ? */ + phys = pg->gtt_phys_start - 0x1000; + break; + case 2: + phys = pg->gtt_phys_start - 0x800; + break; + default: + dev_err(sender->dev->dev, "Unsupported channel %d\n", pipe); + return -EINVAL; + } + + virt_addr = ioremap_nocache(phys, 0x800); + if (!virt_addr) { + dev_err(sender->dev->dev, "Map DBI command buffer error\n"); + return -ENOMEM; + } + sender->dbi_cb_phy = phys; + sender->dbi_cb_addr = virt_addr; + return 0; +} + +static void mdfld_dbi_cb_destroy(struct mdfld_dsi_pkg_sender *sender) +{ + if (sender && sender->dbi_cb_addr) + iounmap(sender->dbi_cb_addr); +} + +static void pkg_sender_queue_pkg(struct mdfld_dsi_pkg_sender *sender, + struct mdfld_dsi_pkg *pkg, + int delay) +{ + unsigned long flags; + + spin_lock_irqsave(&sender->lock, flags); + + if (!delay) { + send_pkg(sender, pkg); + pkg_sender_put_pkg_locked(sender, pkg); + } else { + /* Queue it */ + list_add_tail(&pkg->entry, &sender->pkg_list); + } + spin_unlock_irqrestore(&sender->lock, flags); +} + +static void process_pkg_list(struct mdfld_dsi_pkg_sender *sender) +{ + struct mdfld_dsi_pkg *pkg; + unsigned long flags; + + spin_lock_irqsave(&sender->lock, flags); + + while (!list_empty(&sender->pkg_list)) { + pkg = list_first_entry(&sender->pkg_list, + struct mdfld_dsi_pkg, entry); + send_pkg(sender, pkg); + list_del_init(&pkg->entry); + pkg_sender_put_pkg_locked(sender, pkg); + } + + spin_unlock_irqrestore(&sender->lock, flags); +} + +static int mdfld_dsi_send_mcs_long(struct mdfld_dsi_pkg_sender *sender, + u32 *data, u32 len, u8 transmission, int delay) +{ + struct mdfld_dsi_pkg *pkg; + unsigned long flags; + + spin_lock_irqsave(&sender->lock, flags); + pkg = pkg_sender_get_pkg_locked(sender); + spin_unlock_irqrestore(&sender->lock, flags); + + if (!pkg) { + dev_err(sender->dev->dev, "No memory\n"); + return -ENOMEM; + } + pkg->pkg_type = MDFLD_DSI_PKG_MCS_LONG_WRITE; + pkg->transmission_type = transmission; + pkg->pkg.long_pkg.data = data; + pkg->pkg.long_pkg.len = len; + INIT_LIST_HEAD(&pkg->entry); + + pkg_sender_queue_pkg(sender, pkg, delay); + return 0; +} + +static int mdfld_dsi_send_mcs_short(struct mdfld_dsi_pkg_sender *sender, + u8 cmd, u8 param, u8 param_num, + u8 transmission, + int delay) +{ + struct mdfld_dsi_pkg *pkg; + unsigned long flags; + + spin_lock_irqsave(&sender->lock, flags); + pkg = pkg_sender_get_pkg_locked(sender); + spin_unlock_irqrestore(&sender->lock, flags); + + if (!pkg) { + dev_err(sender->dev->dev, "No memory\n"); + return -ENOMEM; + } + + if (param_num) { + pkg->pkg_type = MDFLD_DSI_PKG_MCS_SHORT_WRITE_1; + pkg->pkg.short_pkg.param = param; + } else { + pkg->pkg_type = MDFLD_DSI_PKG_MCS_SHORT_WRITE_0; + pkg->pkg.short_pkg.param = 0; + } + pkg->transmission_type = transmission; + pkg->pkg.short_pkg.cmd = cmd; + INIT_LIST_HEAD(&pkg->entry); + + pkg_sender_queue_pkg(sender, pkg, delay); + return 0; +} + +static int mdfld_dsi_send_gen_short(struct mdfld_dsi_pkg_sender *sender, + u8 param0, u8 param1, u8 param_num, + u8 transmission, + int delay) +{ + struct mdfld_dsi_pkg *pkg; + unsigned long flags; + + spin_lock_irqsave(&sender->lock, flags); + pkg = pkg_sender_get_pkg_locked(sender); + spin_unlock_irqrestore(&sender->lock, flags); + + if (!pkg) { + dev_err(sender->dev->dev, "No pkg memory\n"); + return -ENOMEM; + } + + switch (param_num) { + case 0: + pkg->pkg_type = MDFLD_DSI_PKG_GEN_SHORT_WRITE_0; + pkg->pkg.short_pkg.cmd = 0; + pkg->pkg.short_pkg.param = 0; + break; + case 1: + pkg->pkg_type = MDFLD_DSI_PKG_GEN_SHORT_WRITE_1; + pkg->pkg.short_pkg.cmd = param0; + pkg->pkg.short_pkg.param = 0; + break; + case 2: + pkg->pkg_type = MDFLD_DSI_PKG_GEN_SHORT_WRITE_2; + pkg->pkg.short_pkg.cmd = param0; + pkg->pkg.short_pkg.param = param1; + break; + } + + pkg->transmission_type = transmission; + INIT_LIST_HEAD(&pkg->entry); + + pkg_sender_queue_pkg(sender, pkg, delay); + return 0; +} + +static int mdfld_dsi_send_gen_long(struct mdfld_dsi_pkg_sender *sender, + u32 *data, u32 len, u8 transmission, int delay) +{ + struct mdfld_dsi_pkg *pkg; + unsigned long flags; + + spin_lock_irqsave(&sender->lock, flags); + pkg = pkg_sender_get_pkg_locked(sender); + spin_unlock_irqrestore(&sender->lock, flags); + + if (!pkg) { + dev_err(sender->dev->dev, "No pkg memory\n"); + return -ENOMEM; + } + + pkg->pkg_type = MDFLD_DSI_PKG_GEN_LONG_WRITE; + pkg->transmission_type = transmission; + pkg->pkg.long_pkg.data = data; + pkg->pkg.long_pkg.len = len; + + INIT_LIST_HEAD(&pkg->entry); + + pkg_sender_queue_pkg(sender, pkg, delay); + + return 0; +} + +static int __read_panel_data(struct mdfld_dsi_pkg_sender *sender, + struct mdfld_dsi_pkg *pkg, + u32 *data, + u16 len) +{ + unsigned long flags; + struct drm_device *dev = sender->dev; + int i; + u32 gen_data_reg; + int retry = MDFLD_DSI_READ_MAX_COUNT; + u8 transmission = pkg->transmission_type; + + /* + * 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, 1 << 29); + + if ((REG_READ(sender->mipi_intr_stat_reg) & (1 << 29))) + DRM_ERROR("Can NOT clean read data valid interrupt\n"); + + /*send out read request*/ + send_pkg(sender, pkg); + + pkg_sender_put_pkg_locked(sender, pkg); + + /*polling read data avail interrupt*/ + while (retry && !(REG_READ(sender->mipi_intr_stat_reg) & (1 << 29))) { + udelay(100); + retry--; + } + + if (!retry) { + spin_unlock_irqrestore(&sender->lock, flags); + return -ETIMEDOUT; + } + + REG_WRITE(sender->mipi_intr_stat_reg, (1 << 29)); + + /*read data*/ + if (transmission == MDFLD_DSI_HS_TRANSMISSION) + gen_data_reg = sender->mipi_hs_gen_data_reg; + else if (transmission == MDFLD_DSI_LP_TRANSMISSION) + gen_data_reg = sender->mipi_lp_gen_data_reg; + else { + DRM_ERROR("Unknown transmission"); + spin_unlock_irqrestore(&sender->lock, flags); + return -EINVAL; + } + + for (i=0; i<len; i++) + *(data + i) = REG_READ(gen_data_reg); + + spin_unlock_irqrestore(&sender->lock, flags); + + return 0; +} + +static int mdfld_dsi_read_gen(struct mdfld_dsi_pkg_sender *sender, + u8 param0, + u8 param1, + u8 param_num, + u32 *data, + u16 len, + u8 transmission) +{ + struct mdfld_dsi_pkg *pkg; + unsigned long flags; + + spin_lock_irqsave(&sender->lock, flags); + + pkg = pkg_sender_get_pkg_locked(sender); + + spin_unlock_irqrestore(&sender->lock,flags); + + if (!pkg) { + dev_err(sender->dev->dev, "No pkg memory\n"); + return -ENOMEM; + } + + switch (param_num) { + case 0: + pkg->pkg_type = MDFLD_DSI_PKG_GEN_READ_0; + pkg->pkg.short_pkg.cmd = 0; + pkg->pkg.short_pkg.param = 0; + break; + case 1: + pkg->pkg_type = MDFLD_DSI_PKG_GEN_READ_1; + pkg->pkg.short_pkg.cmd = param0; + pkg->pkg.short_pkg.param = 0; + break; + case 2: + pkg->pkg_type = MDFLD_DSI_PKG_GEN_READ_2; + pkg->pkg.short_pkg.cmd = param0; + pkg->pkg.short_pkg.param = param1; + break; + } + + pkg->transmission_type = transmission; + + INIT_LIST_HEAD(&pkg->entry); + + return __read_panel_data(sender, pkg, data, len); +} + +static int mdfld_dsi_read_mcs(struct mdfld_dsi_pkg_sender *sender, + u8 cmd, + u32 *data, + u16 len, + u8 transmission) +{ + struct mdfld_dsi_pkg *pkg; + unsigned long flags; + + spin_lock_irqsave(&sender->lock, flags); + + pkg = pkg_sender_get_pkg_locked(sender); + + spin_unlock_irqrestore(&sender->lock, flags); + + if (!pkg) { + dev_err(sender->dev->dev, "No pkg memory\n"); + return -ENOMEM; + } + + pkg->pkg_type = MDFLD_DSI_PKG_MCS_READ; + pkg->pkg.short_pkg.cmd = cmd; + pkg->pkg.short_pkg.param = 0; + + pkg->transmission_type = transmission; + + INIT_LIST_HEAD(&pkg->entry); + + return __read_panel_data(sender, pkg, data, len); +} + +void dsi_controller_dbi_init(struct mdfld_dsi_config * dsi_config, int pipe) +{ + struct drm_device * dev = dsi_config->dev; + u32 reg_offset = pipe ? MIPIC_REG_OFFSET : 0; + int lane_count = dsi_config->lane_count; + u32 val = 0; + + /*un-ready device*/ + REG_WRITE((MIPIA_DEVICE_READY_REG + reg_offset), 0x00000000); + + /*init dsi adapter before kicking off*/ + REG_WRITE((MIPIA_CONTROL_REG + reg_offset), 0x00000018); + + /*TODO: figure out how to setup these registers*/ + REG_WRITE((MIPIA_DPHY_PARAM_REG + reg_offset), 0x150c3408); + REG_WRITE((MIPIA_CLK_LANE_SWITCH_TIME_CNT_REG + reg_offset), 0x000a0014); + REG_WRITE((MIPIA_DBI_BW_CTRL_REG + reg_offset), 0x00000400); + REG_WRITE((MIPIA_DBI_FIFO_THROTTLE_REG + reg_offset), 0x00000001); + REG_WRITE((MIPIA_HS_LS_DBI_ENABLE_REG + reg_offset), 0x00000000); + + /*enable all interrupts*/ + REG_WRITE((MIPIA_INTR_EN_REG + reg_offset), 0xffffffff); + /*max value: 20 clock cycles of txclkesc*/ + REG_WRITE((MIPIA_TURN_AROUND_TIMEOUT_REG + reg_offset), 0x0000001f); + /*min 21 txclkesc, max: ffffh*/ + REG_WRITE((MIPIA_DEVICE_RESET_TIMER_REG + reg_offset), 0x0000ffff); + /*min: 7d0 max: 4e20*/ + REG_WRITE((MIPIA_INIT_COUNT_REG + reg_offset), 0x00000fa0); + + /*set up max return packet size*/ + REG_WRITE((MIPIA_MAX_RETURN_PACK_SIZE_REG + reg_offset), + MDFLD_DSI_MAX_RETURN_PACKET_SIZE); + + /*set up func_prg*/ + val |= lane_count; + val |= (dsi_config->channel_num << DSI_DBI_VIRT_CHANNEL_OFFSET); + val |= DSI_DBI_COLOR_FORMAT_OPTION2; + REG_WRITE((MIPIA_DSI_FUNC_PRG_REG + reg_offset), val); + + REG_WRITE((MIPIA_HS_TX_TIMEOUT_REG + reg_offset), 0x3fffff); + REG_WRITE((MIPIA_LP_RX_TIMEOUT_REG + reg_offset), 0xffff); + + REG_WRITE((MIPIA_HIGH_LOW_SWITCH_COUNT_REG + reg_offset), 0x46); + REG_WRITE((MIPIA_EOT_DISABLE_REG + reg_offset), 0x00000000); + REG_WRITE((MIPIA_LP_BYTECLK_REG + reg_offset), 0x00000004); + REG_WRITE((MIPIA_DEVICE_READY_REG + reg_offset), 0x00000001); +} + +void dsi_controller_dpi_init(struct mdfld_dsi_config * dsi_config, int pipe) +{ + struct drm_device * dev = dsi_config->dev; + u32 reg_offset = pipe ? MIPIC_REG_OFFSET : 0; + int lane_count = dsi_config->lane_count; + struct mdfld_dsi_dpi_timing dpi_timing; + struct drm_display_mode * mode = dsi_config->mode; + u32 val = 0; + + /*un-ready device*/ + REG_WRITE((MIPIA_DEVICE_READY_REG + reg_offset), 0x00000000); + + /*init dsi adapter before kicking off*/ + REG_WRITE((MIPIA_CONTROL_REG + reg_offset), 0x00000018); + + /*enable all interrupts*/ + REG_WRITE((MIPIA_INTR_EN_REG + reg_offset), 0xffffffff); + + /*set up func_prg*/ + val |= lane_count; + val |= dsi_config->channel_num << DSI_DPI_VIRT_CHANNEL_OFFSET; + + switch(dsi_config->bpp) { + case 16: + val |= DSI_DPI_COLOR_FORMAT_RGB565; + break; + case 18: + val |= DSI_DPI_COLOR_FORMAT_RGB666; + break; + case 24: + val |= DSI_DPI_COLOR_FORMAT_RGB888; + break; + default: + DRM_ERROR("unsupported color format, bpp = %d\n", dsi_config->bpp); + } + + REG_WRITE((MIPIA_DSI_FUNC_PRG_REG + reg_offset), val); + + REG_WRITE((MIPIA_HS_TX_TIMEOUT_REG + reg_offset), + (mode->vtotal * mode->htotal * dsi_config->bpp / (8 * lane_count)) & DSI_HS_TX_TIMEOUT_MASK); + REG_WRITE((MIPIA_LP_RX_TIMEOUT_REG + reg_offset), 0xffff & DSI_LP_RX_TIMEOUT_MASK); + + /*max value: 20 clock cycles of txclkesc*/ + REG_WRITE((MIPIA_TURN_AROUND_TIMEOUT_REG + reg_offset), 0x14 & DSI_TURN_AROUND_TIMEOUT_MASK); + + /*min 21 txclkesc, max: ffffh*/ + REG_WRITE((MIPIA_DEVICE_RESET_TIMER_REG + reg_offset), 0xffff & DSI_RESET_TIMER_MASK); + + REG_WRITE((MIPIA_DPI_RESOLUTION_REG + reg_offset), mode->vdisplay << 16 | mode->hdisplay); + + /*set DPI timing registers*/ + mdfld_dsi_dpi_timing_calculation(mode, &dpi_timing, dsi_config->lane_count, dsi_config->bpp); + + REG_WRITE((MIPIA_HSYNC_COUNT_REG + reg_offset), dpi_timing.hsync_count & DSI_DPI_TIMING_MASK); + REG_WRITE((MIPIA_HBP_COUNT_REG + reg_offset), dpi_timing.hbp_count & DSI_DPI_TIMING_MASK); + REG_WRITE((MIPIA_HFP_COUNT_REG + reg_offset), dpi_timing.hfp_count & DSI_DPI_TIMING_MASK); + REG_WRITE((MIPIA_HACTIVE_COUNT_REG + reg_offset), dpi_timing.hactive_count & DSI_DPI_TIMING_MASK); + REG_WRITE((MIPIA_VSYNC_COUNT_REG + reg_offset), dpi_timing.vsync_count & DSI_DPI_TIMING_MASK); + REG_WRITE((MIPIA_VBP_COUNT_REG + reg_offset), dpi_timing.vbp_count & DSI_DPI_TIMING_MASK); + REG_WRITE((MIPIA_VFP_COUNT_REG + reg_offset), dpi_timing.vfp_count & DSI_DPI_TIMING_MASK); + + REG_WRITE((MIPIA_HIGH_LOW_SWITCH_COUNT_REG + reg_offset), 0x46); + + /*min: 7d0 max: 4e20*/ + REG_WRITE((MIPIA_INIT_COUNT_REG + reg_offset), 0x000007d0); + + /*set up video mode*/ + val = dsi_config->video_mode | DSI_DPI_COMPLETE_LAST_LINE; + REG_WRITE((MIPIA_VIDEO_MODE_FORMAT_REG + reg_offset), val); + + REG_WRITE((MIPIA_EOT_DISABLE_REG + reg_offset), 0x00000000); + + REG_WRITE((MIPIA_LP_BYTECLK_REG + reg_offset), 0x00000004); + + /*TODO: figure out how to setup these registers*/ + REG_WRITE((MIPIA_DPHY_PARAM_REG + reg_offset), 0x150c3408); + + REG_WRITE((MIPIA_CLK_LANE_SWITCH_TIME_CNT_REG + reg_offset), (0xa << 16) | 0x14); + + /*set device ready*/ + REG_WRITE((MIPIA_DEVICE_READY_REG + reg_offset), 0x00000001); +} + +static void dsi_controller_init(struct mdfld_dsi_config * dsi_config, int pipe) +{ + if (!dsi_config || ((pipe != 0) && (pipe != 2))) { + DRM_ERROR("Invalid parameters\n"); + return; + } + + if (dsi_config->type == MDFLD_DSI_ENCODER_DPI) + dsi_controller_dpi_init(dsi_config, pipe); + else if (dsi_config->type == MDFLD_DSI_ENCODER_DBI) + dsi_controller_dbi_init(dsi_config, pipe); + else + DRM_ERROR("Bad DSI encoder type\n"); +} + +void mdfld_dsi_cmds_kick_out(struct mdfld_dsi_pkg_sender *sender) +{ + process_pkg_list(sender); +} + +int mdfld_dsi_send_dcs(struct mdfld_dsi_pkg_sender *sender, + u8 dcs, u8 *param, u32 param_num, u8 data_src, + int delay) +{ + struct mdfld_dsi_pkg *pkg; + u32 cb_phy = sender->dbi_cb_phy; + struct drm_device *dev = sender->dev; + u32 index = 0; + u8 *cb = (u8 *)sender->dbi_cb_addr; + unsigned long flags; + int retry; + u8 *dst = NULL; + u32 len; + + if (!sender) { + WARN_ON(1); + return -EINVAL; + } + + if (!sender->dbi_pkg_support) { + dev_err(dev->dev, "No DBI pkg sending on this sender\n"); + return -ENOTSUPP; + } + + if (param_num > MDFLD_MAX_DCS_PARAM) { + dev_err(dev->dev, "Sender only supports up to %d DCS params\n", + MDFLD_MAX_DCS_PARAM); + return -EINVAL; + } + + /* + * If dcs is write_mem_start, send it directly using DSI adapter + * interface + */ + if (dcs == DCS_WRITE_MEM_START) { + if (!spin_trylock(&sender->lock)) + return -EAGAIN; + + /* + * query whether DBI FIFO is empty, + * if not wait it becoming empty + */ + retry = MDFLD_DSI_DBI_FIFO_TIMEOUT; + while (retry && + !(REG_READ(sender->mipi_gen_fifo_stat_reg) & (1 << 27))) { + udelay(500); + retry--; + } + + /* If DBI FIFO timeout, drop this frame */ + if (!retry) { + spin_unlock(&sender->lock); + return 0; + } + + *(cb + (index++)) = write_mem_start; + + REG_WRITE(sender->mipi_cmd_len_reg, 1); + REG_WRITE(sender->mipi_cmd_addr_reg, + cb_phy | (1 << 0) | (1 << 1)); + + retry = MDFLD_DSI_DBI_FIFO_TIMEOUT; + while (retry && + (REG_READ(sender->mipi_cmd_addr_reg) & (1 << 0))) { + udelay(1); + retry--; + } + + spin_unlock(&sender->lock); + return 0; + } + + /* Get a free pkg */ + spin_lock_irqsave(&sender->lock, flags); + pkg = pkg_sender_get_pkg_locked(sender); + spin_unlock_irqrestore(&sender->lock, flags); + + if (!pkg) { + dev_err(dev->dev, "No packages memory\n"); + return -ENOMEM; + } + + dst = pkg->pkg.dcs_pkg.param; + memcpy(dst, param, param_num); + + pkg->pkg_type = MDFLD_DSI_PKG_DCS; + pkg->transmission_type = MDFLD_DSI_DCS; + pkg->pkg.dcs_pkg.cmd = dcs; + pkg->pkg.dcs_pkg.param_num = param_num; + pkg->pkg.dcs_pkg.data_src = data_src; + + INIT_LIST_HEAD(&pkg->entry); + + if (param_num == 0) + return mdfld_dsi_send_mcs_short_hs(sender, dcs, 0, 0, delay); + else if (param_num == 1) + return mdfld_dsi_send_mcs_short_hs(sender, dcs, + param[0], 1, delay); + else if (param_num > 1) { + len = (param_num + 1) / 4; + if ((param_num + 1) % 4) + len++; + return mdfld_dsi_send_mcs_long_hs(sender, + (u32 *)&pkg->pkg.dcs_pkg, len, delay); + } + return 0; +} + +int mdfld_dsi_send_mcs_short_hs(struct mdfld_dsi_pkg_sender *sender, + u8 cmd, u8 param, u8 param_num, int delay) +{ + if (!sender) { + WARN_ON(1); + return -EINVAL; + } + return mdfld_dsi_send_mcs_short(sender, cmd, param, param_num, + MDFLD_DSI_HS_TRANSMISSION, delay); +} + +int mdfld_dsi_send_mcs_short_lp(struct mdfld_dsi_pkg_sender *sender, + u8 cmd, u8 param, u8 param_num, int delay) +{ + if (!sender) { + WARN_ON(1); + return -EINVAL; + } + return mdfld_dsi_send_mcs_short(sender, cmd, param, param_num, + MDFLD_DSI_LP_TRANSMISSION, delay); +} + +int mdfld_dsi_send_mcs_long_hs(struct mdfld_dsi_pkg_sender *sender, + u32 *data, + u32 len, + int delay) +{ + if (!sender || !data || !len) { + DRM_ERROR("Invalid parameters\n"); + return -EINVAL; + } + return mdfld_dsi_send_mcs_long(sender, data, len, + MDFLD_DSI_HS_TRANSMISSION, delay); +} + +int mdfld_dsi_send_mcs_long_lp(struct mdfld_dsi_pkg_sender *sender, + u32 *data, + u32 len, + int delay) +{ + if (!sender || !data || !len) { + WARN_ON(1); + return -EINVAL; + } + return mdfld_dsi_send_mcs_long(sender, data, len, + MDFLD_DSI_LP_TRANSMISSION, delay); +} + +int mdfld_dsi_send_gen_short_hs(struct mdfld_dsi_pkg_sender *sender, + u8 param0, u8 param1, u8 param_num, int delay) +{ + if (!sender) { + WARN_ON(1); + return -EINVAL; + } + return mdfld_dsi_send_gen_short(sender, param0, param1, param_num, + MDFLD_DSI_HS_TRANSMISSION, delay); +} + +int mdfld_dsi_send_gen_short_lp(struct mdfld_dsi_pkg_sender *sender, + u8 param0, u8 param1, u8 param_num, int delay) +{ + if (!sender || param_num < 0 || param_num > 2) { + WARN_ON(1); + return -EINVAL; + } + return mdfld_dsi_send_gen_short(sender, param0, param1, param_num, + MDFLD_DSI_LP_TRANSMISSION, delay); +} + +int mdfld_dsi_send_gen_long_hs(struct mdfld_dsi_pkg_sender *sender, + u32 *data, + u32 len, + int delay) +{ + if (!sender || !data || !len) { + WARN_ON(1); + return -EINVAL; + } + return mdfld_dsi_send_gen_long(sender, data, len, + MDFLD_DSI_HS_TRANSMISSION, delay); +} + +int mdfld_dsi_send_gen_long_lp(struct mdfld_dsi_pkg_sender *sender, + u32 *data, + u32 len, + int delay) +{ + if (!sender || !data || !len) { + WARN_ON(1); + return -EINVAL; + } + return mdfld_dsi_send_gen_long(sender, data, len, + MDFLD_DSI_LP_TRANSMISSION, delay); +} + +int mdfld_dsi_read_gen_hs(struct mdfld_dsi_pkg_sender *sender, + u8 param0, + u8 param1, + u8 param_num, + u32 *data, + u16 len) +{ + if (!sender || !data || param_num < 0 || param_num > 2 + || !data || !len) { + DRM_ERROR("Invalid parameters\n"); + return -EINVAL; + } + + return mdfld_dsi_read_gen(sender, param0, param1, param_num, + data, len, MDFLD_DSI_HS_TRANSMISSION); + +} + +int mdfld_dsi_read_gen_lp(struct mdfld_dsi_pkg_sender *sender, + u8 param0, + u8 param1, + u8 param_num, + u32 *data, + u16 len) +{ + if (!sender || !data || param_num < 0 || param_num > 2 + || !data || !len) { + DRM_ERROR("Invalid parameters\n"); + return -EINVAL; + } + + return mdfld_dsi_read_gen(sender, param0, param1, param_num, + data, len, MDFLD_DSI_LP_TRANSMISSION); +} + +int mdfld_dsi_read_mcs_hs(struct mdfld_dsi_pkg_sender *sender, + u8 cmd, + u32 *data, + u16 len) +{ + if (!sender || !data || !len) { + DRM_ERROR("Invalid parameters\n"); + return -EINVAL; + } + + return mdfld_dsi_read_mcs(sender, cmd, data, len, + MDFLD_DSI_HS_TRANSMISSION); +} + +int mdfld_dsi_read_mcs_lp(struct mdfld_dsi_pkg_sender *sender, + u8 cmd, + u32 *data, + u16 len) +{ + if (!sender || !data || !len) { + WARN_ON(1); + return -EINVAL; + } + + return mdfld_dsi_read_mcs(sender, cmd, data, len, + MDFLD_DSI_LP_TRANSMISSION); +} + +int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector, + int pipe) +{ + int ret; + 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; + struct psb_gtt *pg = &dev_priv->gtt; + int i; + struct mdfld_dsi_pkg *pkg, *tmp; + u32 mipi_val = 0; + + if (!dsi_connector) { + WARN_ON(1); + 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) { + dev_err(dev->dev, "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 dbi command buffer*/ + + if (dsi_config->type == MDFLD_DSI_ENCODER_DBI) { + pkg_sender->dbi_pkg_support = 1; + ret = mdfld_dbi_cb_init(pkg_sender, pg, pipe); + if (ret) { + dev_err(dev->dev, "DBI command buffer map failed\n"); + goto mapping_err; + } + } + + /* Init regs */ + if (pipe == 0) { + pkg_sender->dpll_reg = MRST_DPLL_A; + pkg_sender->dspcntr_reg = DSPACNTR; + pkg_sender->pipeconf_reg = PIPEACONF; + pkg_sender->dsplinoff_reg = DSPALINOFF; + pkg_sender->dspsurf_reg = DSPASURF; + pkg_sender->pipestat_reg = PIPEASTAT; + + pkg_sender->mipi_intr_stat_reg = MIPIA_INTR_STAT_REG; + pkg_sender->mipi_lp_gen_data_reg = MIPIA_LP_GEN_DATA_REG; + pkg_sender->mipi_hs_gen_data_reg = MIPIA_HS_GEN_DATA_REG; + pkg_sender->mipi_lp_gen_ctrl_reg = MIPIA_LP_GEN_CTRL_REG; + pkg_sender->mipi_hs_gen_ctrl_reg = MIPIA_HS_GEN_CTRL_REG; + pkg_sender->mipi_gen_fifo_stat_reg = MIPIA_GEN_FIFO_STAT_REG; + pkg_sender->mipi_data_addr_reg = MIPIA_DATA_ADD_REG; + pkg_sender->mipi_data_len_reg = MIPIA_DATA_LEN_REG; + pkg_sender->mipi_cmd_addr_reg = MIPIA_CMD_ADD_REG; + pkg_sender->mipi_cmd_len_reg = MIPIA_CMD_LEN_REG; + } else if (pipe == 2) { + pkg_sender->dpll_reg = MRST_DPLL_A; + pkg_sender->dspcntr_reg = DSPCCNTR; + pkg_sender->pipeconf_reg = PIPECCONF; + pkg_sender->dsplinoff_reg = DSPCLINOFF; + pkg_sender->dspsurf_reg = DSPCSURF; + pkg_sender->pipestat_reg = PIPECSTAT; + + pkg_sender->mipi_intr_stat_reg = + MIPIA_INTR_STAT_REG + MIPIC_REG_OFFSET; + pkg_sender->mipi_lp_gen_data_reg = + MIPIA_LP_GEN_DATA_REG + MIPIC_REG_OFFSET; + pkg_sender->mipi_hs_gen_data_reg = + MIPIA_HS_GEN_DATA_REG + MIPIC_REG_OFFSET; + pkg_sender->mipi_lp_gen_ctrl_reg = + MIPIA_LP_GEN_CTRL_REG + MIPIC_REG_OFFSET; + pkg_sender->mipi_hs_gen_ctrl_reg = + MIPIA_HS_GEN_CTRL_REG + MIPIC_REG_OFFSET; + pkg_sender->mipi_gen_fifo_stat_reg = + MIPIA_GEN_FIFO_STAT_REG + MIPIC_REG_OFFSET; + pkg_sender->mipi_data_addr_reg = + MIPIA_DATA_ADD_REG + MIPIC_REG_OFFSET; + pkg_sender->mipi_data_len_reg = + MIPIA_DATA_LEN_REG + MIPIC_REG_OFFSET; + pkg_sender->mipi_cmd_addr_reg = + MIPIA_CMD_ADD_REG + MIPIC_REG_OFFSET; + pkg_sender->mipi_cmd_len_reg = + MIPIA_CMD_LEN_REG + MIPIC_REG_OFFSET; + } + + /* Init pkg list */ + INIT_LIST_HEAD(&pkg_sender->pkg_list); + INIT_LIST_HEAD(&pkg_sender->free_list); + + spin_lock_init(&pkg_sender->lock); + + /* Allocate free pkg pool */ + for (i = 0; i < MDFLD_MAX_PKG_NUM; i++) { + pkg = kzalloc(sizeof(struct mdfld_dsi_pkg), GFP_KERNEL); + if (!pkg) { + dev_err(dev->dev, "Out of memory allocating pkg pool"); + ret = -ENOMEM; + goto pkg_alloc_err; + } + INIT_LIST_HEAD(&pkg->entry); + list_add_tail(&pkg->entry, &pkg_sender->free_list); + } + + /* + * For video mode, don't enable DPI timing output here, + * will init the DPI timing output during mode setting. + */ + if (dsi_config->type == MDFLD_DSI_ENCODER_DPI) + mipi_val = PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX; + else if (dsi_config->type == MDFLD_DSI_ENCODER_DBI) + mipi_val = PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX + | TE_TRIGGER_GPIO_PIN; + else + DRM_ERROR("Bad DSI encoder type\n"); + + if (pipe == 0) { + mipi_val |= 0x2; + REG_WRITE(MIPI, mipi_val); + REG_READ(MIPI); + } else if (pipe == 2) { + REG_WRITE(MIPI_C, mipi_val); + REG_READ(MIPI_C); + } + + /*do dsi controller init*/ + dsi_controller_init(dsi_config, pipe); + + return 0; + +pkg_alloc_err: + list_for_each_entry_safe(pkg, tmp, &pkg_sender->free_list, entry) { + list_del(&pkg->entry); + kfree(pkg); + } + + /* Free mapped command buffer */ + mdfld_dbi_cb_destroy(pkg_sender); +mapping_err: + kfree(pkg_sender); + dsi_connector->pkg_sender = NULL; + return ret; +} + +void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender) +{ + struct mdfld_dsi_pkg *pkg, *tmp; + + if (!sender || IS_ERR(sender)) + return; + + /* Free pkg pool */ + list_for_each_entry_safe(pkg, tmp, &sender->free_list, entry) { + list_del(&pkg->entry); + kfree(pkg); + } + /* Free pkg list */ + list_for_each_entry_safe(pkg, tmp, &sender->pkg_list, entry) { + list_del(&pkg->entry); + kfree(pkg); + } + mdfld_dbi_cb_destroy(sender); /* free mapped command buffer */ + kfree(sender); +} diff --git a/drivers/staging/gma500/mdfld_dsi_pkg_sender.h b/drivers/staging/gma500/mdfld_dsi_pkg_sender.h new file mode 100644 index 0000000..f24abc7 --- /dev/null +++ b/drivers/staging/gma500/mdfld_dsi_pkg_sender.h @@ -0,0 +1,184 @@ +/* + * 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 +#define MDFLD_MAX_PKG_NUM 2048 + +enum { + MDFLD_DSI_PKG_DCS, + MDFLD_DSI_PKG_GEN_SHORT_WRITE_0 = 0x03, + MDFLD_DSI_PKG_GEN_SHORT_WRITE_1 = 0x13, + MDFLD_DSI_PKG_GEN_SHORT_WRITE_2 = 0x23, + MDFLD_DSI_PKG_GEN_READ_0 = 0x04, + MDFLD_DSI_PKG_GEN_READ_1 = 0x14, + MDFLD_DSI_PKG_GEN_READ_2 = 0x24, + MDFLD_DSI_PKG_GEN_LONG_WRITE = 0x29, + MDFLD_DSI_PKG_MCS_SHORT_WRITE_0 = 0x05, + MDFLD_DSI_PKG_MCS_SHORT_WRITE_1 = 0x15, + MDFLD_DSI_PKG_MCS_READ = 0x06, + MDFLD_DSI_PKG_MCS_LONG_WRITE = 0x39, +}; + +enum { + MDFLD_DSI_LP_TRANSMISSION, + MDFLD_DSI_HS_TRANSMISSION, + MDFLD_DSI_DCS, +}; + +enum { + MDFLD_DSI_PANEL_MODE_SLEEP = 0x1, +}; + +enum { + MDFLD_DSI_PKG_SENDER_FREE = 0x0, + MDFLD_DSI_PKG_SENDER_BUSY = 0x1, +}; + +enum { + MDFLD_DSI_SEND_PACKAGE, + MDFLD_DSI_QUEUE_PACKAGE, +}; + +struct mdfld_dsi_gen_short_pkg { + u8 cmd; + u8 param; +}; + +struct mdfld_dsi_gen_long_pkg { + u32 *data; + u32 len; +}; + +struct mdfld_dsi_dcs_pkg { + u8 cmd; + u8 param[MDFLD_MAX_DCS_PARAM]; + u32 param_num; + u8 data_src; +}; + +struct mdfld_dsi_pkg { + u8 pkg_type; + u8 transmission_type; + + union { + struct mdfld_dsi_gen_short_pkg short_pkg; + struct mdfld_dsi_gen_long_pkg long_pkg; + struct mdfld_dsi_dcs_pkg dcs_pkg; + } pkg; + + struct list_head entry; +}; + +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; + struct list_head pkg_list; + struct list_head free_list; + + u32 pkg_num; + + int dbi_pkg_support; + + u32 dbi_cb_phy; + void *dbi_cb_addr; + + /* Registers */ + u32 dpll_reg; + u32 dspcntr_reg; + u32 pipeconf_reg; + u32 pipestat_reg; + u32 dsplinoff_reg; + u32 dspsurf_reg; + + u32 mipi_intr_stat_reg; + u32 mipi_lp_gen_data_reg; + u32 mipi_hs_gen_data_reg; + u32 mipi_lp_gen_ctrl_reg; + u32 mipi_hs_gen_ctrl_reg; + u32 mipi_gen_fifo_stat_reg; + u32 mipi_data_addr_reg; + u32 mipi_data_len_reg; + u32 mipi_cmd_addr_reg; + u32 mipi_cmd_len_reg; +}; + +/* DCS definitions */ +#define DCS_SOFT_RESET 0x01 +#define DCS_ENTER_SLEEP_MODE 0x10 +#define DCS_EXIT_SLEEP_MODE 0x11 +#define DCS_SET_DISPLAY_OFF 0x28 +#define DCS_SET_DISPLAY_ON 0x29 +#define DCS_SET_COLUMN_ADDRESS 0x2a +#define DCS_SET_PAGE_ADDRESS 0x2b +#define DCS_WRITE_MEM_START 0x2c +#define DCS_SET_TEAR_OFF 0x34 +#define DCS_SET_TEAR_ON 0x35 + +extern int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector, + int pipe); +extern void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender); +extern int mdfld_dsi_send_dcs(struct mdfld_dsi_pkg_sender *sender, u8 dcs, + u8 *param, u32 param_num, u8 data_src, int delay); +extern int mdfld_dsi_send_mcs_short_hs(struct mdfld_dsi_pkg_sender *sender, + u8 cmd, u8 param, u8 param_num, int delay); +extern int mdfld_dsi_send_mcs_short_lp(struct mdfld_dsi_pkg_sender *sender, + u8 cmd, u8 param, u8 param_num, int delay); +extern int mdfld_dsi_send_mcs_long_hs(struct mdfld_dsi_pkg_sender *sender, + u32 *data, u32 len, int delay); +extern int mdfld_dsi_send_mcs_long_lp(struct mdfld_dsi_pkg_sender *sender, + u32 *data, u32 len, int delay); +extern int mdfld_dsi_send_gen_short_hs(struct mdfld_dsi_pkg_sender *sender, + u8 param0, u8 param1, u8 param_num, int delay); +extern int mdfld_dsi_send_gen_short_lp(struct mdfld_dsi_pkg_sender *sender, + u8 param0, u8 param1, u8 param_num, int delay); +extern int mdfld_dsi_send_gen_long_hs(struct mdfld_dsi_pkg_sender *sender, + u32 *data, u32 len, int delay); +extern int mdfld_dsi_send_gen_long_lp(struct mdfld_dsi_pkg_sender *sender, + u32 *data, u32 len, int delay); + +extern int mdfld_dsi_read_gen_hs(struct mdfld_dsi_pkg_sender *sender, + u8 param0, u8 param1, u8 param_num, u32 *data, u16 len); +extern int mdfld_dsi_read_gen_lp(struct mdfld_dsi_pkg_sender *sender, + u8 param0, u8 param1, u8 param_num, u32 *data, u16 len); +extern int mdfld_dsi_read_mcs_hs(struct mdfld_dsi_pkg_sender *sender, + u8 cmd, u32 *data, u16 len); +extern int mdfld_dsi_read_mcs_lp(struct mdfld_dsi_pkg_sender *sender, + u8 cmd, u32 *data, u16 len); + +extern void mdfld_dsi_cmds_kick_out(struct mdfld_dsi_pkg_sender *sender); + +#endif /* __MDFLD_DSI_PKG_SENDER_H__ */ diff --git a/drivers/staging/gma500/mdfld_intel_display.c b/drivers/staging/gma500/mdfld_intel_display.c new file mode 100644 index 0000000..aa2ff55 --- /dev/null +++ b/drivers/staging/gma500/mdfld_intel_display.c @@ -0,0 +1,1402 @@ +/* + * Copyright © 2006-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. + * + * Authors: + * Eric Anholt <eric@anholt.net> + */ + +#include "framebuffer.h" +#include "psb_intel_display.h" +#include "mdfld_dsi_dbi.h" +#include "mdfld_dsi_dpi.h" +#include "mdfld_dsi_dbi_dpu.h" + +#include <linux/pm_runtime.h> + +#ifdef MIN +#undef MIN +#endif + +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) + +/* Hardcoded currently */ +static int ksel = KSEL_CRYSTAL_19; + +extern void mdfld_save_display(struct drm_device *dev); +extern bool gbgfxsuspended; + +struct psb_intel_range_t { + int min, max; +}; + +struct mdfld_limit_t { + struct psb_intel_range_t dot, m, p1; +}; + +struct mdfld_intel_clock_t { + /* given values */ + int n; + int m1, m2; + int p1, p2; + /* derived values */ + int dot; + int vco; + int m; + int p; +}; + + + +#define COUNT_MAX 0x10000000 + +void mdfldWaitForPipeDisable(struct drm_device *dev, int pipe) +{ + int count, temp; + u32 pipeconf_reg = PIPEACONF; + + switch (pipe) { + case 0: + break; + case 1: + pipeconf_reg = PIPEBCONF; + break; + case 2: + pipeconf_reg = PIPECCONF; + break; + default: + DRM_ERROR("Illegal Pipe Number. \n"); + return; + } + + /* FIXME JLIU7_PO */ + psb_intel_wait_for_vblank(dev); + return; + + /* Wait for for the pipe disable to take effect. */ + for (count = 0; count < COUNT_MAX; count++) { + temp = REG_READ(pipeconf_reg); + if ((temp & PIPEACONF_PIPE_STATE) == 0) + break; + } +} + +void mdfldWaitForPipeEnable(struct drm_device *dev, int pipe) +{ + int count, temp; + u32 pipeconf_reg = PIPEACONF; + + switch (pipe) { + case 0: + break; + case 1: + pipeconf_reg = PIPEBCONF; + break; + case 2: + pipeconf_reg = PIPECCONF; + break; + default: + dev_err(dev->dev, "Illegal Pipe Number.\n"); + return; + } + + /* FIXME JLIU7_PO */ + psb_intel_wait_for_vblank(dev); + return; + + /* Wait for for the pipe enable to take effect. */ + for (count = 0; count < COUNT_MAX; count++) { + temp = REG_READ(pipeconf_reg); + if ((temp & PIPEACONF_PIPE_STATE) == 1) + break; + } +} + + +static int mdfld_intel_crtc_cursor_set(struct drm_crtc *crtc, + struct drm_file *file_priv, + uint32_t handle, + uint32_t width, uint32_t height) +{ + struct drm_device *dev = crtc->dev; + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + int pipe = psb_intel_crtc->pipe; + uint32_t control = CURACNTR; + uint32_t base = CURABASE; + uint32_t temp; + size_t addr = 0; + struct gtt_range *gt; + struct drm_gem_object *obj; + int ret; + + switch (pipe) { + case 0: + break; + case 1: + control = CURBCNTR; + base = CURBBASE; + break; + case 2: + control = CURCCNTR; + base = CURCBASE; + break; + default: + dev_err(dev->dev, "Illegal Pipe Number. \n"); + return -EINVAL; + } + +#if 1 /* FIXME_JLIU7 can't enalbe cursorB/C HW issue. need to remove after HW fix */ + if (pipe != 0) + return 0; +#endif + /* if we want to turn of the cursor ignore width and height */ + if (!handle) { + dev_dbg(dev->dev, "cursor off\n"); + /* turn off the cursor */ + temp = 0; + temp |= CURSOR_MODE_DISABLE; + + if (gma_power_begin(dev, true)) { + REG_WRITE(control, temp); + REG_WRITE(base, 0); + gma_power_end(dev); + } + /* Unpin the old GEM object */ + 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 = NULL; + } + return 0; + } + + /* Currently we only support 64x64 cursors */ + if (width != 64 || height != 64) { + DRM_ERROR("we currently only support 64x64 cursors\n"); + return -EINVAL; + } + + obj = drm_gem_object_lookup(dev, file_priv, handle); + if (!obj) + return -ENOENT; + + if (obj->size < width * height * 4) { + dev_dbg(dev->dev, "buffer is to small\n"); + return -ENOMEM; + } + + gt = container_of(obj, struct gtt_range, gem); + + /* Pin the memory into the GTT */ + ret = psb_gtt_pin(gt); + if (ret) { + dev_err(dev->dev, "Can not pin down handle 0x%x\n", handle); + return ret; + } + + + addr = gt->offset; /* Or resource.start ??? */ + + psb_intel_crtc->cursor_addr = addr; + + temp = 0; + /* set the pipe for the cursor */ + temp |= (pipe << 28); + temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; + + if (gma_power_begin(dev, true)) { + REG_WRITE(control, temp); + REG_WRITE(base, addr); + gma_power_end(dev); + } + /* unpin the old GEM object */ + 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; +} + +static int mdfld_intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) +{ + struct drm_device *dev = crtc->dev; + struct drm_psb_private * dev_priv = (struct drm_psb_private *)dev->dev_private; + struct mdfld_dbi_dpu_info *dpu_info = dev_priv->dbi_dpu_info; + struct psb_drm_dpu_rect rect; + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + int pipe = psb_intel_crtc->pipe; + uint32_t pos = CURAPOS; + uint32_t base = CURABASE; + uint32_t temp = 0; + uint32_t addr; + + switch (pipe) { + case 0: + if (dpu_info) { + rect.x = x; + rect.y = y; + + mdfld_dbi_dpu_report_damage(dev, MDFLD_CURSORA, &rect); + mdfld_dpu_exit_dsr(dev); + } else if (!(dev_priv->dsr_fb_update & MDFLD_DSR_CURSOR_0)) + mdfld_dsi_dbi_exit_dsr(dev, MDFLD_DSR_CURSOR_0); + break; + case 1: + pos = CURBPOS; + base = CURBBASE; + break; + case 2: + if (dpu_info) { + mdfld_dbi_dpu_report_damage(dev, MDFLD_CURSORC, &rect); + mdfld_dpu_exit_dsr(dev); + } else if (!(dev_priv->dsr_fb_update & MDFLD_DSR_CURSOR_2)) + mdfld_dsi_dbi_exit_dsr(dev, MDFLD_DSR_CURSOR_2); + pos = CURCPOS; + base = CURCBASE; + break; + default: + DRM_ERROR("Illegal Pipe Number. \n"); + return -EINVAL; + } + +#if 1 /* FIXME_JLIU7 can't enalbe cursorB/C HW issue. need to remove after HW fix */ + if (pipe != 0) + return 0; +#endif + if (x < 0) { + temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT); + x = -x; + } + if (y < 0) { + temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT); + y = -y; + } + + temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT); + temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); + + addr = psb_intel_crtc->cursor_addr; + + if (gma_power_begin(dev, true)) { + REG_WRITE(pos, temp); + REG_WRITE(base, addr); + gma_power_end(dev); + } + + return 0; +} + +const struct drm_crtc_funcs mdfld_intel_crtc_funcs = { + .cursor_set = mdfld_intel_crtc_cursor_set, + .cursor_move = mdfld_intel_crtc_cursor_move, + .gamma_set = psb_intel_crtc_gamma_set, + .set_config = drm_crtc_helper_set_config, + .destroy = psb_intel_crtc_destroy, +}; + +static struct drm_device globle_dev; + +void mdfld__intel_plane_set_alpha(int enable) +{ + struct drm_device *dev = &globle_dev; + int dspcntr_reg = DSPACNTR; + u32 dspcntr; + + dspcntr = REG_READ(dspcntr_reg); + + if (enable) { + dspcntr &= ~DISPPLANE_32BPP_NO_ALPHA; + dspcntr |= DISPPLANE_32BPP; + } else { + dspcntr &= ~DISPPLANE_32BPP; + dspcntr |= DISPPLANE_32BPP_NO_ALPHA; + } + + REG_WRITE(dspcntr_reg, dspcntr); +} + +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_i915_master_private *master_priv; */ + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb); + int pipe = psb_intel_crtc->pipe; + unsigned long start, offset; + int dsplinoff = DSPALINOFF; + int dspsurf = DSPASURF; + int dspstride = DSPASTRIDE; + int dspcntr_reg = DSPACNTR; + u32 dspcntr; + int ret = 0; + + memcpy(&globle_dev, dev, sizeof(struct drm_device)); + + if (!gma_power_begin(dev, true)) + return 0; + + /* no fb bound */ + if (!crtc->fb) { + dev_err(dev->dev, "No FB bound\n"); + goto psb_intel_pipe_cleaner; + } + + switch (pipe) { + case 0: + dsplinoff = DSPALINOFF; + break; + case 1: + dsplinoff = DSPBLINOFF; + dspsurf = DSPBSURF; + dspstride = DSPBSTRIDE; + dspcntr_reg = DSPBCNTR; + break; + case 2: + dsplinoff = DSPCLINOFF; + dspsurf = DSPCSURF; + dspstride = DSPCSTRIDE; + dspcntr_reg = DSPCCNTR; + break; + default: + dev_err(dev->dev, "Illegal Pipe Number.\n"); + return -EINVAL; + } + + ret = psb_gtt_pin(psbfb->gtt); + if (ret < 0) + goto psb_intel_pipe_set_base_exit; + + start = psbfb->gtt->offset; + offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8); + + REG_WRITE(dspstride, crtc->fb->pitch); + dspcntr = REG_READ(dspcntr_reg); + dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; + + switch (crtc->fb->bits_per_pixel) { + case 8: + dspcntr |= DISPPLANE_8BPP; + break; + case 16: + if (crtc->fb->depth == 15) + dspcntr |= DISPPLANE_15_16BPP; + else + dspcntr |= DISPPLANE_16BPP; + break; + case 24: + case 32: + dspcntr |= DISPPLANE_32BPP_NO_ALPHA; + break; + default: + dev_err(dev->dev, "Unknown color depth\n"); + ret = -EINVAL; + goto psb_intel_pipe_set_base_exit; + } + REG_WRITE(dspcntr_reg, dspcntr); + + dev_dbg(dev->dev, "Writing base %08lX %08lX %d %d\n", + start, offset, x, y); + + REG_WRITE(dsplinoff, offset); + REG_READ(dsplinoff); + REG_WRITE(dspsurf, start); + REG_READ(dspsurf); + +psb_intel_pipe_cleaner: + /* If there was a previous display we can now unpin it */ + if (old_fb) + psb_gtt_unpin(to_psb_fb(old_fb)->gtt); + +psb_intel_pipe_set_base_exit: + gma_power_end(dev); + return ret; +} + +/** + * Disable the pipe, plane and pll. + * + */ +void mdfld_disable_crtc (struct drm_device *dev, int pipe) +{ + int dpll_reg = MRST_DPLL_A; + int dspcntr_reg = DSPACNTR; + int dspbase_reg = MRST_DSPABASE; + int pipeconf_reg = PIPEACONF; + u32 gen_fifo_stat_reg = GEN_FIFO_STAT_REG; + u32 temp; + + switch (pipe) { + case 0: + break; + case 1: + dpll_reg = MDFLD_DPLL_B; + dspcntr_reg = DSPBCNTR; + dspbase_reg = DSPBSURF; + pipeconf_reg = PIPEBCONF; + break; + case 2: + dpll_reg = MRST_DPLL_A; + dspcntr_reg = DSPCCNTR; + dspbase_reg = MDFLD_DSPCBASE; + pipeconf_reg = PIPECCONF; + gen_fifo_stat_reg = GEN_FIFO_STAT_REG + MIPIC_REG_OFFSET; + break; + default: + dev_err(dev->dev, "Illegal Pipe Number. \n"); + return; + } + + if (pipe != 1) + mdfld_dsi_gen_fifo_ready (dev, gen_fifo_stat_reg, HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY); + + /* Disable display plane */ + temp = REG_READ(dspcntr_reg); + if ((temp & DISPLAY_PLANE_ENABLE) != 0) { + REG_WRITE(dspcntr_reg, + temp & ~DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); + REG_READ(dspbase_reg); + } + + /* FIXME_JLIU7 MDFLD_PO revisit */ + /* Wait for vblank for the disable to take effect */ +// MDFLD_PO_JLIU7 psb_intel_wait_for_vblank(dev); + + /* Next, disable display pipes */ + temp = REG_READ(pipeconf_reg); + if ((temp & PIPEACONF_ENABLE) != 0) { + temp &= ~PIPEACONF_ENABLE; + temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF; + REG_WRITE(pipeconf_reg, temp); + REG_READ(pipeconf_reg); + + /* Wait for for the pipe disable to take effect. */ + mdfldWaitForPipeDisable(dev, pipe); + } + + temp = REG_READ(dpll_reg); + if (temp & DPLL_VCO_ENABLE) { + if (((pipe != 1) && !((REG_READ(PIPEACONF) | REG_READ(PIPECCONF)) & PIPEACONF_ENABLE)) + || (pipe == 1)){ + temp &= ~(DPLL_VCO_ENABLE); + REG_WRITE(dpll_reg, temp); + REG_READ(dpll_reg); + /* 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(dpll_reg, 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 psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + int pipe = psb_intel_crtc->pipe; + int dpll_reg = MRST_DPLL_A; + int dspcntr_reg = DSPACNTR; + int dspbase_reg = MRST_DSPABASE; + int pipeconf_reg = PIPEACONF; + u32 pipestat_reg = PIPEASTAT; + u32 gen_fifo_stat_reg = GEN_FIFO_STAT_REG; + u32 pipeconf = dev_priv->pipeconf; + u32 dspcntr = dev_priv->dspcntr; + u32 mipi_enable_reg = MIPIA_DEVICE_READY_REG; + u32 temp; + bool enabled; + int timeout = 0; + + if (!gma_power_begin(dev, true)) + return; + + /* Ignore if system is already in DSR and in suspended state. */ + if(/*gbgfxsuspended */0 && dev_priv->dispstatus == false && mode == 3){ + if(dev_priv->rpm_enabled && pipe == 1){ + // dev_priv->is_mipi_on = false; + pm_request_idle(&dev->pdev->dev); + } + return; + }else if(mode == 0) { + //do not need to set gbdispstatus=true in crtc. + //this will be set in encoder such as mdfld_dsi_dbi_dpms + //gbdispstatus = true; + } + + +/* FIXME_JLIU7 MDFLD_PO replaced w/ the following function */ +/* mdfld_dbi_dpms (struct drm_device *dev, int pipe, bool enabled) */ + + switch (pipe) { + case 0: + break; + case 1: + dpll_reg = DPLL_B; + dspcntr_reg = DSPBCNTR; + dspbase_reg = MRST_DSPBBASE; + pipeconf_reg = PIPEBCONF; + pipeconf = dev_priv->pipeconf1; + dspcntr = dev_priv->dspcntr1; + dpll_reg = MDFLD_DPLL_B; + break; + case 2: + dpll_reg = MRST_DPLL_A; + dspcntr_reg = DSPCCNTR; + dspbase_reg = MDFLD_DSPCBASE; + pipeconf_reg = PIPECCONF; + pipestat_reg = PIPECSTAT; + pipeconf = dev_priv->pipeconf2; + dspcntr = dev_priv->dspcntr2; + gen_fifo_stat_reg = GEN_FIFO_STAT_REG + MIPIC_REG_OFFSET; + mipi_enable_reg = MIPIA_DEVICE_READY_REG + MIPIC_REG_OFFSET; + break; + default: + dev_err(dev->dev, "Illegal Pipe Number.\n"); + 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(dpll_reg); + + 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(dpll_reg, temp); + /* FIXME_MDFLD PO - change 500 to 1 after PO */ + udelay(500); + } + + REG_WRITE(dpll_reg, temp); + REG_READ(dpll_reg); + /* FIXME_MDFLD PO - change 500 to 1 after PO */ + udelay(500); + + REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); + REG_READ(dpll_reg); + + /** + * 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(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) { + udelay(150); + timeout ++; + } + } + + /* Enable the plane */ + temp = REG_READ(dspcntr_reg); + if ((temp & DISPLAY_PLANE_ENABLE) == 0) { + REG_WRITE(dspcntr_reg, + temp | DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); + } + + /* Enable the pipe */ + temp = REG_READ(pipeconf_reg); + if ((temp & PIPEACONF_ENABLE) == 0) { + REG_WRITE(pipeconf_reg, 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) && + (mdfld_panel_dpi(dev) == true)) { + REG_WRITE(pipestat_reg, REG_READ(pipestat_reg)); + msleep(100); + if(PIPE_VBLANK_STATUS & REG_READ(pipestat_reg)) { + printk(KERN_ALERT "OK"); + } else { + printk(KERN_ALERT "STUCK!!!!"); + /*shutdown controller*/ + temp = REG_READ(dspcntr_reg); + REG_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE); + REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); + /*mdfld_dsi_dpi_shut_down(dev, pipe);*/ + REG_WRITE(0xb048, 1); + msleep(100); + temp = REG_READ(pipeconf_reg); + temp &= ~PIPEACONF_ENABLE; + REG_WRITE(pipeconf_reg, temp); + msleep(100); /*wait for pipe disable*/ + /*printk(KERN_ALERT "70008 is %x\n", REG_READ(0x70008)); + printk(KERN_ALERT "b074 is %x\n", REG_READ(0xb074));*/ + REG_WRITE(mipi_enable_reg, 0); + msleep(100); + printk(KERN_ALERT "70008 is %x\n", REG_READ(0x70008)); + printk(KERN_ALERT "b074 is %x\n", REG_READ(0xb074)); + REG_WRITE(0xb004, REG_READ(0xb004)); + /* try to bring the controller back up again*/ + REG_WRITE(mipi_enable_reg, 1); + temp = REG_READ(dspcntr_reg); + REG_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE); + REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); + /*mdfld_dsi_dpi_turn_on(dev, pipe);*/ + REG_WRITE(0xb048, 2); + msleep(100); + temp = REG_READ(pipeconf_reg); + temp |= PIPEACONF_ENABLE; + REG_WRITE(pipeconf_reg, temp); + } + } + + psb_intel_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, gen_fifo_stat_reg, 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(dspcntr_reg); + if ((temp & DISPLAY_PLANE_ENABLE) != 0) { + REG_WRITE(dspcntr_reg, + temp & ~DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); + REG_READ(dspbase_reg); + } + + /* FIXME_JLIU7 MDFLD_PO revisit */ + /* Wait for vblank for the disable to take effect */ +// MDFLD_PO_JLIU7 psb_intel_wait_for_vblank(dev); + + /* Next, disable display pipes */ + temp = REG_READ(pipeconf_reg); + if ((temp & PIPEACONF_ENABLE) != 0) { + temp &= ~PIPEACONF_ENABLE; + temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF; + REG_WRITE(pipeconf_reg, temp); +// REG_WRITE(pipeconf_reg, 0); + REG_READ(pipeconf_reg); + + /* Wait for for the pipe disable to take effect. */ + mdfldWaitForPipeDisable(dev, pipe); + } + + temp = REG_READ(dpll_reg); + if (temp & DPLL_VCO_ENABLE) { + if (((pipe != 1) && !((REG_READ(PIPEACONF) | REG_READ(PIPECCONF)) & PIPEACONF_ENABLE)) + || (pipe == 1)){ + temp &= ~(DPLL_VCO_ENABLE); + REG_WRITE(dpll_reg, temp); + REG_READ(dpll_reg); + /* Wait for the clocks to turn off. */ + /* FIXME_MDFLD PO may need more delay */ + udelay(500); +#if 0 /* MDFLD_PO_JLIU7 */ + if (!(temp & MDFLD_PWR_GATE_EN)) { + /* gating power of DPLL */ + REG_WRITE(dpll_reg, temp | MDFLD_PWR_GATE_EN); + /* FIXME_MDFLD PO - change 500 to 1 after PO */ + udelay(5000); + } +#endif /* MDFLD_PO_JLIU7 */ + } + } + break; + } + + enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF; + +#if 0 /* JB: Add vblank support later */ + if (enabled) + dev_priv->vblank_pipe |= (1 << pipe); + else + dev_priv->vblank_pipe &= ~(1 << pipe); +#endif + + 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 /* FIXME_MDFLD JLIU7 need to find out min & max for MDFLD */ +#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 mdfld_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 mdfld_limit_t *mdfld_limit(struct drm_crtc *crtc) +{ + const struct mdfld_limit_t *limit = NULL; + struct drm_device *dev = crtc->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + + if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_MIPI) + || psb_intel_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 (psb_intel_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_err(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 mdfld_intel_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 mdfld_intel_clock_t *best_clock) +{ + struct mdfld_intel_clock_t clock; + const struct mdfld_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; +} + +/** + * Return the pipe currently connected to the panel fitter, + * or -1 if the panel fitter is not present or not in use + */ +static int mdfld_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; + return (pfit_control >> 29) & 3; +} + +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 psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + struct drm_psb_private *dev_priv = dev->dev_private; + int pipe = psb_intel_crtc->pipe; + int fp_reg = MRST_FPA0; + int dpll_reg = MRST_DPLL_A; + int dspcntr_reg = DSPACNTR; + int pipeconf_reg = PIPEACONF; + int htot_reg = HTOTAL_A; + int hblank_reg = HBLANK_A; + int hsync_reg = HSYNC_A; + int vtot_reg = VTOTAL_A; + int vblank_reg = VBLANK_A; + int vsync_reg = VSYNC_A; + int dspsize_reg = DSPASIZE; + int dsppos_reg = DSPAPOS; + int pipesrc_reg = PIPEASRC; + u32 *pipeconf = &dev_priv->pipeconf; + u32 *dspcntr = &dev_priv->dspcntr; + int refclk = 0; + int clk_n = 0, clk_p2 = 0, clk_byte = 1, clk = 0, m_conv = 0, clk_tmp = 0; + struct mdfld_intel_clock_t clock; + bool ok; + u32 dpll = 0, fp = 0; + bool is_crt = false, is_lvds = false, is_tv = false; + bool is_mipi = false, is_mipi2 = false, is_hdmi = false; + struct drm_mode_config *mode_config = &dev->mode_config; + struct psb_intel_output *psb_intel_output = NULL; + uint64_t scalingType = DRM_MODE_SCALE_FULLSCREEN; + struct drm_encoder *encoder; + struct drm_connector *connector; + int timeout = 0; + + dev_dbg(dev->dev, "pipe = 0x%x \n", pipe); + + switch (pipe) { + case 0: + break; + case 1: + fp_reg = FPB0; + dpll_reg = DPLL_B; + dspcntr_reg = DSPBCNTR; + pipeconf_reg = PIPEBCONF; + htot_reg = HTOTAL_B; + hblank_reg = HBLANK_B; + hsync_reg = HSYNC_B; + vtot_reg = VTOTAL_B; + vblank_reg = VBLANK_B; + vsync_reg = VSYNC_B; + dspsize_reg = DSPBSIZE; + dsppos_reg = DSPBPOS; + pipesrc_reg = PIPEBSRC; + pipeconf = &dev_priv->pipeconf1; + dspcntr = &dev_priv->dspcntr1; + fp_reg = MDFLD_DPLL_DIV0; + dpll_reg = MDFLD_DPLL_B; + break; + case 2: + dpll_reg = MRST_DPLL_A; + dspcntr_reg = DSPCCNTR; + pipeconf_reg = PIPECCONF; + htot_reg = HTOTAL_C; + hblank_reg = HBLANK_C; + hsync_reg = HSYNC_C; + vtot_reg = VTOTAL_C; + vblank_reg = VBLANK_C; + vsync_reg = VSYNC_C; + dspsize_reg = DSPCSIZE; + dsppos_reg = DSPCPOS; + pipesrc_reg = PIPECSRC; + pipeconf = &dev_priv->pipeconf2; + dspcntr = &dev_priv->dspcntr2; + break; + default: + DRM_ERROR("Illegal Pipe Number. \n"); + return 0; + } + + 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(&psb_intel_crtc->saved_mode, mode, sizeof(struct drm_display_mode)); + memcpy(&psb_intel_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; + + psb_intel_output = to_psb_intel_output(connector); + + dev_dbg(dev->dev, "output->type = 0x%x \n", psb_intel_output->type); + + switch (psb_intel_output->type) { + case INTEL_OUTPUT_LVDS: + is_lvds = true; + break; + case INTEL_OUTPUT_TVOUT: + is_tv = true; + break; + case INTEL_OUTPUT_ANALOG: + is_crt = true; + break; + 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 (mdfld_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(dspsize_reg, ((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(pipesrc_reg, ((mode->crtc_hdisplay - 1) << 16) + | (mode->crtc_vdisplay - 1)); + } else { + REG_WRITE(dspsize_reg, ((mode->crtc_vdisplay - 1) << 16) | (mode->crtc_hdisplay - 1)); + REG_WRITE(pipesrc_reg, ((mode->crtc_hdisplay - 1) << 16) | (mode->crtc_vdisplay - 1)); + } + + REG_WRITE(dsppos_reg, 0); + + if (psb_intel_output) + drm_connector_property_get_value(&psb_intel_output->base, + dev->mode_config.scaling_mode_property, &scalingType); + + if (scalingType == DRM_MODE_SCALE_NO_SCALE) { + /*Moorestown 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(htot_reg, (mode->crtc_hdisplay - 1) | + ((adjusted_mode->crtc_htotal - 1) << 16)); + REG_WRITE(vtot_reg, (mode->crtc_vdisplay - 1) | + ((adjusted_mode->crtc_vtotal - 1) << 16)); + REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - offsetX - 1) | + ((adjusted_mode->crtc_hblank_end - offsetX - 1) << 16)); + REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - offsetX - 1) | + ((adjusted_mode->crtc_hsync_end - offsetX - 1) << 16)); + REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - offsetY - 1) | + ((adjusted_mode->crtc_vblank_end - offsetY - 1) << 16)); + REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - offsetY - 1) | + ((adjusted_mode->crtc_vsync_end - offsetY - 1) << 16)); + } else { + REG_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) | + ((adjusted_mode->crtc_htotal - 1) << 16)); + REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | + ((adjusted_mode->crtc_vtotal - 1) << 16)); + REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | + ((adjusted_mode->crtc_hblank_end - 1) << 16)); + REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | + ((adjusted_mode->crtc_hsync_end - 1) << 16)); + REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | + ((adjusted_mode->crtc_vblank_end - 1) << 16)); + REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | + ((adjusted_mode->crtc_vsync_end - 1) << 16)); + } + + /* Flush the plane changes */ + { + struct drm_crtc_helper_funcs *crtc_funcs = + crtc->helper_private; + crtc_funcs->mode_set_base(crtc, x, y, old_fb); + } + + /* setup pipeconf */ + *pipeconf = PIPEACONF_ENABLE; /* FIXME_JLIU7 REG_READ(pipeconf_reg); */ + + /* Set up the display plane register */ + *dspcntr = REG_READ(dspcntr_reg); + *dspcntr |= pipe << DISPPLANE_SEL_PIPE_POS; + *dspcntr |= DISPLAY_PLANE_ENABLE; +/* MDFLD_PO_JLIU7 dspcntr |= DISPPLANE_BOTTOM; */ +/* MDFLD_PO_JLIU7 dspcntr |= DISPPLANE_GAMMA_ENABLE; */ + + if (is_mipi2) + { + goto mrst_crtc_mode_set_exit; + } +/* FIXME JLIU7 Add MDFLD HDMI supports */ +/* FIXME_MDFLD JLIU7 DSIPLL clock *= 8? */ +/* FIXME_MDFLD JLIU7 need to revist for dual MIPI supports */ + 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) { + dev_err(dev->dev, + "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(dpll_reg); + + if (dpll & DPLL_VCO_ENABLE) { + dpll &= ~DPLL_VCO_ENABLE; + REG_WRITE(dpll_reg, dpll); + REG_READ(dpll_reg); + + /* 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(fp_reg, 0); + dpll &= ~MDFLD_P1_MASK; + REG_WRITE(dpll_reg, 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(dpll_reg, dpll); + /* FIXME_MDFLD PO - change 500 to 1 after PO */ + udelay(500); + } + + dpll = 0; + +#if 0 /* FIXME revisit later */ + if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19) || (ksel == KSEL_BYPASS_25)) { + dpll &= ~MDFLD_INPUT_REF_SEL; + } else if (ksel == KSEL_BYPASS_83_100) { + dpll |= MDFLD_INPUT_REF_SEL; + } +#endif /* FIXME revisit later */ + + 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; + +#if 0 /* 1080p30 & 720p */ + dpll = 0x00050000; + fp = 0x000001be; +#endif +#if 0 /* 480p */ + dpll = 0x02010000; + fp = 0x000000d2; +#endif + } else { +#if 0 /*DBI_TPO_480x864*/ + dpll = 0x00020000; + fp = 0x00000156; +#endif /* DBI_TPO_480x864 */ /* get from spec. */ + + dpll = 0x00800000; + fp = 0x000000c1; +} + + REG_WRITE(fp_reg, fp); + REG_WRITE(dpll_reg, dpll); + /* FIXME_MDFLD PO - change 500 to 1 after PO */ + udelay(500); + + dpll |= DPLL_VCO_ENABLE; + REG_WRITE(dpll_reg, dpll); + REG_READ(dpll_reg); + + /* wait for DSI PLL to lock */ + while ((timeout < 20000) && !(REG_READ(pipeconf_reg) & 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(pipeconf_reg, *pipeconf); + REG_READ(pipeconf_reg); + + /* Wait for for the pipe enable to take effect. */ +//FIXME_JLIU7 HDMI mrstWaitForPipeEnable(dev); + + REG_WRITE(dspcntr_reg, *dspcntr); + psb_intel_wait_for_vblank(dev); + +mrst_crtc_mode_set_exit: + + gma_power_end(dev); + + return 0; +} + +static void mdfld_crtc_prepare(struct drm_crtc *crtc) +{ + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); +} + +static void mdfld_crtc_commit(struct drm_crtc *crtc) +{ + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); +} + +static bool mdfld_crtc_mode_fixup(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +const struct drm_crtc_helper_funcs mdfld_helper_funcs = { + .dpms = mdfld_crtc_dpms, + .mode_fixup = mdfld_crtc_mode_fixup, + .mode_set = mdfld_crtc_mode_set, + .mode_set_base = mdfld__intel_pipe_set_base, + .prepare = mdfld_crtc_prepare, + .commit = mdfld_crtc_commit, +}; diff --git a/drivers/staging/gma500/mdfld_msic.h b/drivers/staging/gma500/mdfld_msic.h new file mode 100644 index 0000000..a7ad6547 --- /dev/null +++ b/drivers/staging/gma500/mdfld_msic.h @@ -0,0 +1,31 @@ +/* + * 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> + */ + +#define MSIC_PCI_DEVICE_ID 0x831 + +int msic_regsiter_driver(void); +int msic_unregister_driver(void); +extern void hpd_notify_um(void); diff --git a/drivers/staging/gma500/mdfld_output.c b/drivers/staging/gma500/mdfld_output.c new file mode 100644 index 0000000..ee55f87 --- /dev/null +++ b/drivers/staging/gma500/mdfld_output.c @@ -0,0 +1,170 @@ +/* + * 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 <linux/init.h> +#include "mdfld_dsi_dbi.h" +#include "mdfld_dsi_dpi.h" +#include "mdfld_dsi_output.h" +#include "mdfld_output.h" +#include "mdfld_dsi_dbi_dpu.h" + +#include "displays/tpo_cmd.h" +#include "displays/tpo_vid.h" +#include "displays/tmd_cmd.h" +#include "displays/tmd_vid.h" +#include "displays/pyr_cmd.h" +#include "displays/pyr_vid.h" +/* #include "displays/hdmi.h" */ + +static int mdfld_dual_mipi; +static int mdfld_hdmi; +static int mdfld_dpu; + +module_param(mdfld_dual_mipi, int, 0600); +MODULE_PARM_DESC(mdfld_dual_mipi, "Enable dual MIPI configuration"); +module_param(mdfld_hdmi, int, 0600); +MODULE_PARM_DESC(mdfld_hdmi, "Enable Medfield HDMI"); +module_param(mdfld_dpu, int, 0600); +MODULE_PARM_DESC(mdfld_dpu, "Enable Medfield DPU"); + +/* For now a single type per device is all we cope with */ +int mdfld_get_panel_type(struct drm_device *dev, int pipe) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + return dev_priv->panel_id; +} + +int mdfld_panel_dpi(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + + switch (dev_priv->panel_id) { + case TMD_VID: + case TPO_VID: + case PYR_VID: + return true; + case TMD_CMD: + case TPO_CMD: + case PYR_CMD: + default: + return false; + } +} + +static int init_panel(struct drm_device *dev, int mipi_pipe, int p_type) +{ + struct panel_funcs *p_cmd_funcs; + struct panel_funcs *p_vid_funcs; + + /* Oh boy ... FIXME */ + p_cmd_funcs = kzalloc(sizeof(struct panel_funcs), GFP_KERNEL); + if (p_cmd_funcs == NULL) + return -ENODEV; + p_vid_funcs = kzalloc(sizeof(struct panel_funcs), GFP_KERNEL); + if (p_vid_funcs == NULL) { + kfree(p_cmd_funcs); + return -ENODEV; + } + + switch (p_type) { + case TPO_CMD: + tpo_cmd_init(dev, p_cmd_funcs); + mdfld_dsi_output_init(dev, mipi_pipe, NULL, p_cmd_funcs, NULL); + break; + case TPO_VID: + tpo_vid_init(dev, p_vid_funcs); + mdfld_dsi_output_init(dev, mipi_pipe, NULL, NULL, p_vid_funcs); + break; + case TMD_CMD: + /*tmd_cmd_init(dev, p_cmd_funcs); */ + mdfld_dsi_output_init(dev, mipi_pipe, NULL, p_cmd_funcs, NULL); + break; + case TMD_VID: + tmd_vid_init(dev, p_vid_funcs); + mdfld_dsi_output_init(dev, mipi_pipe, NULL, NULL, p_vid_funcs); + break; + case PYR_CMD: + pyr_cmd_init(dev, p_cmd_funcs); + mdfld_dsi_output_init(dev, mipi_pipe, NULL, p_cmd_funcs, NULL); + break; + case PYR_VID: + mdfld_dsi_output_init(dev, mipi_pipe, NULL, NULL, p_vid_funcs); + break; + case TPO: /* TPO panel supports both cmd & vid interfaces */ + tpo_cmd_init(dev, p_cmd_funcs); + tpo_vid_init(dev, p_vid_funcs); + mdfld_dsi_output_init(dev, mipi_pipe, NULL, p_cmd_funcs, + p_vid_funcs); + break; + case TMD: + break; + case PYR: + break; +#if 0 + case HDMI: + dev_dbg(dev->dev, "Initializing HDMI"); + mdfld_hdmi_init(dev, &dev_priv->mode_dev); + break; +#endif + default: + dev_err(dev->dev, "Unsupported interface %d", p_type); + return -ENODEV; + } + return 0; +} + +int mdfld_output_init(struct drm_device *dev) +{ + int type; + + /* MIPI panel 1 */ + type = mdfld_get_panel_type(dev, 0); + dev_info(dev->dev, "panel 1: type is %d\n", type); + init_panel(dev, 0, type); + + if (mdfld_dual_mipi) { + /* MIPI panel 2 */ + type = mdfld_get_panel_type(dev, 2); + dev_info(dev->dev, "panel 2: type is %d\n", type); + init_panel(dev, 2, type); + } + if (mdfld_hdmi) + /* HDMI panel */ + init_panel(dev, 0, HDMI); + return 0; +} + +void mdfld_output_setup(struct drm_device *dev) +{ + /* FIXME: this is not the right place for this stuff ! */ + if (IS_MFLD(dev)) { + if (mdfld_dpu) + mdfld_dbi_dpu_init(dev); + else + mdfld_dbi_dsr_init(dev); + } +}
\ No newline at end of file diff --git a/drivers/staging/gma500/mdfld_output.h b/drivers/staging/gma500/mdfld_output.h new file mode 100644 index 0000000..daf33e7 --- /dev/null +++ b/drivers/staging/gma500/mdfld_output.h @@ -0,0 +1,41 @@ +/* + * 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 + +int mdfld_output_init(struct drm_device *dev); +int mdfld_panel_dpi(struct drm_device *dev); +int mdfld_get_panel_type(struct drm_device *dev, int pipe); +void mdfld_disable_crtc (struct drm_device *dev, int pipe); + +extern const struct drm_crtc_helper_funcs mdfld_helper_funcs; +extern const struct drm_crtc_funcs mdfld_intel_crtc_funcs; + +extern void mdfld_output_setup(struct drm_device *dev); + +#endif diff --git a/drivers/staging/gma500/mdfld_pyr_cmd.c b/drivers/staging/gma500/mdfld_pyr_cmd.c new file mode 100644 index 0000000..523f2d8 --- /dev/null +++ b/drivers/staging/gma500/mdfld_pyr_cmd.c @@ -0,0 +1,558 @@ +/* + * 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_dsi_dbi.h" +#include "mdfld_dsi_dpi.h" +#include "mdfld_dsi_output.h" +#include "mdfld_output.h" +#include "mdfld_dsi_dbi_dpu.h" +#include "mdfld_dsi_pkg_sender.h" + +#include "displays/pyr_cmd.h" + +static struct drm_display_mode *pyr_cmd_get_config_mode(struct drm_device *dev) +{ + struct drm_display_mode *mode; + + mode = kzalloc(sizeof(*mode), GFP_KERNEL); + if (!mode) { + dev_err(dev->dev, "Out of memory\n"); + return NULL; + } + + 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); + + mode->hdisplay = 480; + mode->vdisplay = 864; + mode->hsync_start = 487; + mode->hsync_end = 490; + mode->htotal = 499; + mode->vsync_start = 874; + mode->vsync_end = 878; + mode->vtotal = 886; + mode->clock = 25777; + + drm_mode_set_name(mode); + drm_mode_set_crtcinfo(mode, 0); + + mode->type |= DRM_MODE_TYPE_PREFERRED; + + return mode; +} + +static bool pyr_dsi_dbi_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_display_mode *fixed_mode = pyr_cmd_get_config_mode(dev); + + if (fixed_mode) { + adjusted_mode->hdisplay = fixed_mode->hdisplay; + adjusted_mode->hsync_start = fixed_mode->hsync_start; + adjusted_mode->hsync_end = fixed_mode->hsync_end; + adjusted_mode->htotal = fixed_mode->htotal; + adjusted_mode->vdisplay = fixed_mode->vdisplay; + adjusted_mode->vsync_start = fixed_mode->vsync_start; + adjusted_mode->vsync_end = fixed_mode->vsync_end; + adjusted_mode->vtotal = fixed_mode->vtotal; + adjusted_mode->clock = fixed_mode->clock; + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); + kfree(fixed_mode); + } + return true; +} + +static void pyr_dsi_dbi_set_power(struct drm_encoder *encoder, bool on) +{ + int ret = 0; + struct mdfld_dsi_encoder *dsi_encoder = MDFLD_DSI_ENCODER(encoder); + struct mdfld_dsi_dbi_output *dbi_output = + MDFLD_DSI_DBI_OUTPUT(dsi_encoder); + struct drm_device *dev = encoder->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + u32 reg_offset = 0; + int pipe = (dbi_output->channel_num == 0) ? 0 : 2; + + dev_dbg(dev->dev, "pipe %d : %s, panel on: %s\n", pipe, + on ? "On" : "Off", + dbi_output->dbi_panel_on ? "True" : "False"); + + if (pipe == 2) { + if (on) + dev_priv->dual_mipi = true; + else + dev_priv->dual_mipi = false; + + reg_offset = MIPIC_REG_OFFSET; + } else { + if (!on) + dev_priv->dual_mipi = false; + } + + if (!gma_power_begin(dev, true)) { + dev_err(dev->dev, "hw begin failed\n"); + return; + } + + + if (on) { + if (dbi_output->dbi_panel_on) + goto out_err; + + ret = mdfld_dsi_dbi_update_power(dbi_output, DRM_MODE_DPMS_ON); + if (ret) { + dev_err(dev->dev, "power on error\n"); + goto out_err; + } + + dbi_output->dbi_panel_on = true; + + if (pipe == 2) { + dev_priv->dbi_panel_on2 = true; + } else { + dev_priv->dbi_panel_on = true; + mdfld_enable_te(dev, 0); + } + } else { + if (!dbi_output->dbi_panel_on && !dbi_output->first_boot) + goto out_err; + + dbi_output->dbi_panel_on = false; + dbi_output->first_boot = false; + + if (pipe == 2) { + dev_priv->dbi_panel_on2 = false; + mdfld_disable_te(dev, 2); + } else { + dev_priv->dbi_panel_on = false; + mdfld_disable_te(dev, 0); + + if (dev_priv->dbi_panel_on2) + mdfld_enable_te(dev, 2); + } + + ret = mdfld_dsi_dbi_update_power(dbi_output, DRM_MODE_DPMS_OFF); + if (ret) { + dev_err(dev->dev, "power on error\n"); + goto out_err; + } + } + +out_err: + gma_power_end(dev); + + if (ret) + dev_err(dev->dev, "failed\n"); +} + +static void pyr_dsi_controller_dbi_init(struct mdfld_dsi_config *dsi_config, + int pipe) +{ + struct drm_device *dev = dsi_config->dev; + u32 reg_offset = pipe ? MIPIC_REG_OFFSET : 0; + int lane_count = dsi_config->lane_count; + u32 val = 0; + + dev_dbg(dev->dev, "Init DBI interface on pipe %d...\n", pipe); + + /* Un-ready device */ + REG_WRITE((MIPIA_DEVICE_READY_REG + reg_offset), 0x00000000); + + /* Init dsi adapter before kicking off */ + REG_WRITE((MIPIA_CONTROL_REG + reg_offset), 0x00000018); + + /* TODO: figure out how to setup these registers */ + REG_WRITE((MIPIA_DPHY_PARAM_REG + reg_offset), 0x150c600F); + REG_WRITE((MIPIA_CLK_LANE_SWITCH_TIME_CNT_REG + reg_offset), + 0x000a0014); + REG_WRITE((MIPIA_DBI_BW_CTRL_REG + reg_offset), 0x00000400); + REG_WRITE((MIPIA_HS_LS_DBI_ENABLE_REG + reg_offset), 0x00000000); + + /* Enable all interrupts */ + REG_WRITE((MIPIA_INTR_EN_REG + reg_offset), 0xffffffff); + /* Max value: 20 clock cycles of txclkesc */ + REG_WRITE((MIPIA_TURN_AROUND_TIMEOUT_REG + reg_offset), 0x0000001f); + /* Min 21 txclkesc, max: ffffh */ + REG_WRITE((MIPIA_DEVICE_RESET_TIMER_REG + reg_offset), 0x0000ffff); + /* Min: 7d0 max: 4e20 */ + REG_WRITE((MIPIA_INIT_COUNT_REG + reg_offset), 0x00000fa0); + + /* Set up func_prg */ + val |= lane_count; + val |= (dsi_config->channel_num << DSI_DBI_VIRT_CHANNEL_OFFSET); + val |= DSI_DBI_COLOR_FORMAT_OPTION2; + REG_WRITE((MIPIA_DSI_FUNC_PRG_REG + reg_offset), val); + + REG_WRITE((MIPIA_HS_TX_TIMEOUT_REG + reg_offset), 0x3fffff); + REG_WRITE((MIPIA_LP_RX_TIMEOUT_REG + reg_offset), 0xffff); + + /* De-assert dbi_stall when half of DBI FIFO is empty */ + /* REG_WRITE((MIPIA_DBI_FIFO_THROTTLE_REG + reg_offset), 0x00000000); */ + + REG_WRITE((MIPIA_HIGH_LOW_SWITCH_COUNT_REG + reg_offset), 0x46); + REG_WRITE((MIPIA_EOT_DISABLE_REG + reg_offset), 0x00000002); + REG_WRITE((MIPIA_LP_BYTECLK_REG + reg_offset), 0x00000004); + REG_WRITE((MIPIA_DEVICE_READY_REG + reg_offset), 0x00000001); +} + +static void pyr_dsi_dbi_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + int ret = 0; + struct drm_device *dev = encoder->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + struct mdfld_dsi_encoder *dsi_encoder = MDFLD_DSI_ENCODER(encoder); + struct mdfld_dsi_dbi_output *dsi_output = + MDFLD_DSI_DBI_OUTPUT(dsi_encoder); + struct mdfld_dsi_config *dsi_config = + mdfld_dsi_encoder_get_config(dsi_encoder); + struct mdfld_dsi_connector *dsi_connector = dsi_config->connector; + int pipe = dsi_connector->pipe; + u8 param = 0; + + /* Regs */ + u32 mipi_reg = MIPI; + u32 dspcntr_reg = DSPACNTR; + u32 pipeconf_reg = PIPEACONF; + u32 reg_offset = 0; + + /* Values */ + u32 dspcntr_val = dev_priv->dspcntr; + u32 pipeconf_val = dev_priv->pipeconf; + u32 h_active_area = mode->hdisplay; + u32 v_active_area = mode->vdisplay; + u32 mipi_val = (PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX | + TE_TRIGGER_GPIO_PIN); + + dev_dbg(dev->dev, "mipi_val =0x%x\n", mipi_val); + + dev_dbg(dev->dev, "type %s\n", (pipe == 2) ? "MIPI2" : "MIPI"); + dev_dbg(dev->dev, "h %d v %d\n", mode->hdisplay, mode->vdisplay); + + if (pipe == 2) { + mipi_reg = MIPI_C; + dspcntr_reg = DSPCCNTR; + pipeconf_reg = PIPECCONF; + + reg_offset = MIPIC_REG_OFFSET; + + dspcntr_val = dev_priv->dspcntr2; + pipeconf_val = dev_priv->pipeconf2; + } else { + mipi_val |= 0x2; /* Two lanes for port A and C respectively */ + } + + if (!gma_power_begin(dev, true)) { + dev_err(dev->dev, "hw begin failed\n"); + return; + } + + /* Set up pipe related registers */ + REG_WRITE(mipi_reg, mipi_val); + REG_READ(mipi_reg); + + pyr_dsi_controller_dbi_init(dsi_config, pipe); + + msleep(20); + + REG_WRITE(dspcntr_reg, dspcntr_val); + REG_READ(dspcntr_reg); + + /* 20ms delay before sending exit_sleep_mode */ + msleep(20); + + /* Send exit_sleep_mode DCS */ + ret = mdfld_dsi_dbi_send_dcs(dsi_output, exit_sleep_mode, NULL, + 0, CMD_DATA_SRC_SYSTEM_MEM); + if (ret) { + dev_err(dev->dev, "sent exit_sleep_mode faild\n"); + goto out_err; + } + + /*send set_tear_on DCS*/ + ret = mdfld_dsi_dbi_send_dcs(dsi_output, set_tear_on, + ¶m, 1, CMD_DATA_SRC_SYSTEM_MEM); + if (ret) { + dev_err(dev->dev, "%s - sent set_tear_on faild\n", __func__); + goto out_err; + } + + /* Do some init stuff */ + mdfld_dsi_brightness_init(dsi_config, pipe); + mdfld_dsi_gen_fifo_ready(dev, (MIPIA_GEN_FIFO_STAT_REG + reg_offset), + HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY); + + REG_WRITE(pipeconf_reg, pipeconf_val | PIPEACONF_DSR); + REG_READ(pipeconf_reg); + + /* TODO: this looks ugly, try to move it to CRTC mode setting */ + if (pipe == 2) + dev_priv->pipeconf2 |= PIPEACONF_DSR; + else + dev_priv->pipeconf |= PIPEACONF_DSR; + + dev_dbg(dev->dev, "pipeconf %x\n", REG_READ(pipeconf_reg)); + + ret = mdfld_dsi_dbi_update_area(dsi_output, 0, 0, + h_active_area - 1, v_active_area - 1); + if (ret) { + dev_err(dev->dev, "update area failed\n"); + goto out_err; + } + +out_err: + gma_power_end(dev); + + if (ret) + dev_err(dev->dev, "mode set failed\n"); + else + dev_dbg(dev->dev, "mode set done successfully\n"); +} + +static void pyr_dsi_dbi_prepare(struct drm_encoder *encoder) +{ + struct mdfld_dsi_encoder *dsi_encoder = MDFLD_DSI_ENCODER(encoder); + struct mdfld_dsi_dbi_output *dbi_output = + MDFLD_DSI_DBI_OUTPUT(dsi_encoder); + + dbi_output->mode_flags |= MODE_SETTING_IN_ENCODER; + dbi_output->mode_flags &= ~MODE_SETTING_ENCODER_DONE; + + pyr_dsi_dbi_set_power(encoder, false); +} + +static void pyr_dsi_dbi_commit(struct drm_encoder *encoder) +{ + struct mdfld_dsi_encoder *dsi_encoder = MDFLD_DSI_ENCODER(encoder); + struct mdfld_dsi_dbi_output *dbi_output = + MDFLD_DSI_DBI_OUTPUT(dsi_encoder); + struct drm_device *dev = dbi_output->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + struct psb_drm_dpu_rect rect; + + pyr_dsi_dbi_set_power(encoder, true); + + dbi_output->mode_flags &= ~MODE_SETTING_IN_ENCODER; + + rect.x = rect.y = 0; + rect.width = 864; + rect.height = 480; + + if (dbi_output->channel_num == 1) { + dev_priv->dsr_fb_update |= MDFLD_DSR_2D_3D_2; + /* If DPU enabled report a fullscreen damage */ + mdfld_dbi_dpu_report_damage(dev, MDFLD_PLANEC, &rect); + } else { + dev_priv->dsr_fb_update |= MDFLD_DSR_2D_3D_0; + mdfld_dbi_dpu_report_damage(dev, MDFLD_PLANEA, &rect); + } + dbi_output->mode_flags |= MODE_SETTING_ENCODER_DONE; +} + +static void pyr_dsi_dbi_dpms(struct drm_encoder *encoder, int mode) +{ + struct mdfld_dsi_encoder *dsi_encoder = MDFLD_DSI_ENCODER(encoder); + struct mdfld_dsi_dbi_output *dbi_output = + MDFLD_DSI_DBI_OUTPUT(dsi_encoder); + struct drm_device *dev = dbi_output->dev; + + dev_dbg(dev->dev, "%s\n", (mode == DRM_MODE_DPMS_ON ? "on" : "off")); + + if (mode == DRM_MODE_DPMS_ON) + pyr_dsi_dbi_set_power(encoder, true); + else + pyr_dsi_dbi_set_power(encoder, false); +} + +/* + * Update the DBI MIPI Panel Frame Buffer. + */ +static void pyr_dsi_dbi_update_fb(struct mdfld_dsi_dbi_output *dbi_output, + int pipe) +{ + struct mdfld_dsi_pkg_sender *sender = + mdfld_dsi_encoder_get_pkg_sender(&dbi_output->base); + struct drm_device *dev = dbi_output->dev; + struct drm_crtc *crtc = dbi_output->base.base.crtc; + struct psb_intel_crtc *psb_crtc = (crtc) ? + to_psb_intel_crtc(crtc) : NULL; + + u32 dpll_reg = MRST_DPLL_A; + u32 dspcntr_reg = DSPACNTR; + u32 pipeconf_reg = PIPEACONF; + u32 dsplinoff_reg = DSPALINOFF; + u32 dspsurf_reg = DSPASURF; + u32 hs_gen_ctrl_reg = HS_GEN_CTRL_REG; + u32 gen_fifo_stat_reg = GEN_FIFO_STAT_REG; + u32 reg_offset = 0; + + u32 intr_status; + u32 fifo_stat_reg_val; + u32 dpll_reg_val; + u32 dspcntr_reg_val; + u32 pipeconf_reg_val; + + /* If mode setting on-going, back off */ + if ((dbi_output->mode_flags & MODE_SETTING_ON_GOING) || + (psb_crtc && psb_crtc->mode_flags & MODE_SETTING_ON_GOING) || + !(dbi_output->mode_flags & MODE_SETTING_ENCODER_DONE)) + return; + + /* + * Look for errors here. In particular we're checking for whatever + * error status might have appeared during the last frame transmit + * (memory write). + * + * Normally, the bits we're testing here would be set infrequently, + * if at all. However, one panel (at least) returns at least one + * error bit on most frames. So we've disabled the kernel message + * for now. + * + * Still clear whatever error bits are set, except don't clear the + * ones that would make the Penwell DSI controller reset if we + * cleared them. + */ + intr_status = REG_READ(INTR_STAT_REG); + if ((intr_status & 0x26FFFFFF) != 0) { + /* dev_err(dev->dev, "DSI status: 0x%08X\n", intr_status); */ + intr_status &= 0x26F3FFFF; + REG_WRITE(INTR_STAT_REG, intr_status); + } + + if (pipe == 2) { + dspcntr_reg = DSPCCNTR; + pipeconf_reg = PIPECCONF; + dsplinoff_reg = DSPCLINOFF; + dspsurf_reg = DSPCSURF; + + hs_gen_ctrl_reg = HS_GEN_CTRL_REG + MIPIC_REG_OFFSET; + gen_fifo_stat_reg = GEN_FIFO_STAT_REG + MIPIC_REG_OFFSET, + + reg_offset = MIPIC_REG_OFFSET; + } + + if (!gma_power_begin(dev, true)) { + dev_err(dev->dev, "hw begin failed\n"); + return; + } + + fifo_stat_reg_val = REG_READ(MIPIA_GEN_FIFO_STAT_REG + reg_offset); + dpll_reg_val = REG_READ(dpll_reg); + dspcntr_reg_val = REG_READ(dspcntr_reg); + pipeconf_reg_val = REG_READ(pipeconf_reg); + + if (!(fifo_stat_reg_val & (1 << 27)) || + (dpll_reg_val & DPLL_VCO_ENABLE) || + !(dspcntr_reg_val & DISPLAY_PLANE_ENABLE) || + !(pipeconf_reg_val & DISPLAY_PLANE_ENABLE)) { + goto update_fb_out0; + } + + /* Refresh plane changes */ + REG_WRITE(dsplinoff_reg, REG_READ(dsplinoff_reg)); + REG_WRITE(dspsurf_reg, REG_READ(dspsurf_reg)); + REG_READ(dspsurf_reg); + + mdfld_dsi_send_dcs(sender, + write_mem_start, + NULL, + 0, + CMD_DATA_SRC_PIPE, + MDFLD_DSI_SEND_PACKAGE); + + /* + * The idea here is to transmit a Generic Read command after the + * Write Memory Start/Continue commands finish. This asks for + * the panel to return an "ACK No Errors," or (if it has errors + * to report) an Error Report. This allows us to monitor the + * panel's perception of the health of the DSI. + */ + mdfld_dsi_gen_fifo_ready(dev, gen_fifo_stat_reg, + HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY); + REG_WRITE(hs_gen_ctrl_reg, (1 << WORD_COUNTS_POS) | GEN_READ_0); + + dbi_output->dsr_fb_update_done = true; +update_fb_out0: + gma_power_end(dev); +} + +/* + * TODO: will be removed later, should work out display interfaces for power + */ +void pyr_dsi_adapter_init(struct mdfld_dsi_config *dsi_config, int pipe) +{ + if (!dsi_config || (pipe != 0 && pipe != 2)) { + WARN_ON(1); + return; + } + pyr_dsi_controller_dbi_init(dsi_config, pipe); +} + +static int pyr_cmd_get_panel_info(struct drm_device *dev, int pipe, + struct panel_info *pi) +{ + if (!dev || !pi) + return -EINVAL; + + pi->width_mm = PYR_PANEL_WIDTH; + pi->height_mm = PYR_PANEL_HEIGHT; + + return 0; +} + +/* PYR DBI encoder helper funcs */ +static const struct drm_encoder_helper_funcs pyr_dsi_dbi_helper_funcs = { + .dpms = pyr_dsi_dbi_dpms, + .mode_fixup = pyr_dsi_dbi_mode_fixup, + .prepare = pyr_dsi_dbi_prepare, + .mode_set = pyr_dsi_dbi_mode_set, + .commit = pyr_dsi_dbi_commit, +}; + +/* PYR DBI encoder funcs */ +static const struct drm_encoder_funcs mdfld_dsi_dbi_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +void pyr_cmd_init(struct drm_device *dev, struct panel_funcs *p_funcs) +{ + p_funcs->encoder_funcs = &mdfld_dsi_dbi_encoder_funcs; + p_funcs->encoder_helper_funcs = &pyr_dsi_dbi_helper_funcs; + p_funcs->get_config_mode = &pyr_cmd_get_config_mode; + p_funcs->update_fb = pyr_dsi_dbi_update_fb; + p_funcs->get_panel_info = pyr_cmd_get_panel_info; +} diff --git a/drivers/staging/gma500/mdfld_tmd_vid.c b/drivers/staging/gma500/mdfld_tmd_vid.c new file mode 100644 index 0000000..affdc09 --- /dev/null +++ b/drivers/staging/gma500/mdfld_tmd_vid.c @@ -0,0 +1,206 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Jim Liu <jim.liu@intel.com> + * Jackie Li<yaodong.li@intel.com> + * Gideon Eaton <eaton. + * Scott Rowe <scott.m.rowe@intel.com> + */ + +#include "mdfld_dsi_dbi.h" +#include "mdfld_dsi_dpi.h" +#include "mdfld_dsi_output.h" +#include "mdfld_output.h" + +#include "mdfld_dsi_pkg_sender.h" + +#include "displays/tmd_vid.h" + +/* FIXME: 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 mrst_timing_info *ti = &dev_priv->gct_data.DTD; + bool use_gct = false; /*Disable GCT for now*/ + + mode = kzalloc(sizeof(*mode), GFP_KERNEL); + if (!mode) { + dev_err(dev->dev, "Out of memory\n"); + return NULL; + } + + if (use_gct) { + dev_dbg(dev->dev, "gct find MIPI panel.\n"); + + 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; +} + +/* + * mdfld_init_TMD_MIPI - initialise a TMD interface + * @dsi_config: configuration + * @pipe: pipe to configure + * + * 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! + */ + + +static void mdfld_dsi_tmd_drv_ic_init(struct mdfld_dsi_config *dsi_config, + int pipe) +{ + 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}; + + 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); + + mdfld_dsi_send_gen_long_lp(sender, tmd_cmd_mcap_off, 1, 0); + mdfld_dsi_send_gen_long_lp(sender, tmd_cmd_enable_lane_switch, 1, 0); + mdfld_dsi_send_gen_long_lp(sender, tmd_cmd_set_lane_num, 1, 0); + mdfld_dsi_send_gen_long_lp(sender, tmd_cmd_pushing_clock0, 1, 0); + mdfld_dsi_send_gen_long_lp(sender, tmd_cmd_pushing_clock1, 1, 0); + mdfld_dsi_send_gen_long_lp(sender, tmd_cmd_set_mode, 1, 0); + mdfld_dsi_send_gen_long_lp(sender, tmd_cmd_set_sync_pulse_mode, 1, 0); + mdfld_dsi_send_mcs_long_lp(sender, tmd_cmd_set_column, 2, 0); + mdfld_dsi_send_mcs_long_lp(sender, tmd_cmd_set_page, 2, 0); + mdfld_dsi_send_gen_long_lp(sender, tmd_cmd_set_video_mode, 1, 0); + mdfld_dsi_send_gen_long_lp(sender, tmd_cmd_enable_backlight, 1, 0); + mdfld_dsi_send_gen_long_lp(sender, tmd_cmd_set_backlight_dimming, 1, 0); + + dsi_config->dvr_ic_inited = 1; +} + +/* TMD 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, +}; + +/* TMD DPI encoder funcs */ +static const struct drm_encoder_funcs mdfld_tpo_dpi_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +void tmd_vid_init(struct drm_device *dev, struct panel_funcs *p_funcs) +{ + if (!dev || !p_funcs) { + dev_err(dev->dev, "Invalid parameters\n"); + return; + } + + p_funcs->encoder_funcs = &mdfld_tpo_dpi_encoder_funcs; + p_funcs->encoder_helper_funcs = &mdfld_tpo_dpi_encoder_helper_funcs; + p_funcs->get_config_mode = &tmd_vid_get_config_mode; + p_funcs->update_fb = NULL; + p_funcs->get_panel_info = tmd_vid_get_panel_info; + p_funcs->reset = mdfld_dsi_panel_reset; + p_funcs->drv_ic_init = mdfld_dsi_tmd_drv_ic_init; +} diff --git a/drivers/staging/gma500/mdfld_tpo_cmd.c b/drivers/staging/gma500/mdfld_tpo_cmd.c new file mode 100644 index 0000000..c7f7c9c --- /dev/null +++ b/drivers/staging/gma500/mdfld_tpo_cmd.c @@ -0,0 +1,509 @@ +/* + * 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_dsi_dbi.h" +#include "mdfld_dsi_dpi.h" +#include "mdfld_dsi_output.h" +#include "mdfld_output.h" +#include "mdfld_dsi_dbi_dpu.h" +#include "mdfld_dsi_pkg_sender.h" + +#include "displays/tpo_cmd.h" + +static struct drm_display_mode *tpo_cmd_get_config_mode(struct drm_device *dev) +{ + struct drm_display_mode *mode; + struct drm_psb_private *dev_priv = dev->dev_private; + struct mrst_timing_info *ti = &dev_priv->gct_data.DTD; + bool use_gct = false; + + mode = kzalloc(sizeof(*mode), GFP_KERNEL); + if (!mode) + return NULL; + + if (use_gct) { + dev_dbg(dev->dev, "gct find MIPI panel.\n"); + + mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo; + mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo; + mode->hsync_start = mode->hdisplay + \ + ((ti->hsync_offset_hi << 8) | \ + ti->hsync_offset_lo); + mode->hsync_end = mode->hsync_start + \ + ((ti->hsync_pulse_width_hi << 8) | \ + ti->hsync_pulse_width_lo); + mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) | \ + ti->hblank_lo); + mode->vsync_start = \ + mode->vdisplay + ((ti->vsync_offset_hi << 8) | \ + ti->vsync_offset_lo); + mode->vsync_end = \ + mode->vsync_start + ((ti->vsync_pulse_width_hi << 8) | \ + ti->vsync_pulse_width_lo); + mode->vtotal = mode->vdisplay + \ + ((ti->vblank_hi << 8) | ti->vblank_lo); + mode->clock = ti->pixel_clock * 10; + + dev_dbg(dev->dev, "hdisplay is %d\n", mode->hdisplay); + dev_dbg(dev->dev, "vdisplay is %d\n", mode->vdisplay); + dev_dbg(dev->dev, "HSS is %d\n", mode->hsync_start); + dev_dbg(dev->dev, "HSE is %d\n", mode->hsync_end); + dev_dbg(dev->dev, "htotal is %d\n", mode->htotal); + dev_dbg(dev->dev, "VSS is %d\n", mode->vsync_start); + dev_dbg(dev->dev, "VSE is %d\n", mode->vsync_end); + dev_dbg(dev->dev, "vtotal is %d\n", mode->vtotal); + dev_dbg(dev->dev, "clock is %d\n", mode->clock); + } else { + mode->hdisplay = 864; + mode->vdisplay = 480; + mode->hsync_start = 872; + mode->hsync_end = 876; + mode->htotal = 884; + mode->vsync_start = 482; + mode->vsync_end = 494; + mode->vtotal = 486; + mode->clock = 25777; + } + + drm_mode_set_name(mode); + drm_mode_set_crtcinfo(mode, 0); + + mode->type |= DRM_MODE_TYPE_PREFERRED; + + return mode; +} + +static bool mdfld_dsi_dbi_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_display_mode *fixed_mode = tpo_cmd_get_config_mode(dev); + + if (fixed_mode) { + adjusted_mode->hdisplay = fixed_mode->hdisplay; + adjusted_mode->hsync_start = fixed_mode->hsync_start; + adjusted_mode->hsync_end = fixed_mode->hsync_end; + adjusted_mode->htotal = fixed_mode->htotal; + adjusted_mode->vdisplay = fixed_mode->vdisplay; + adjusted_mode->vsync_start = fixed_mode->vsync_start; + adjusted_mode->vsync_end = fixed_mode->vsync_end; + adjusted_mode->vtotal = fixed_mode->vtotal; + adjusted_mode->clock = fixed_mode->clock; + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); + kfree(fixed_mode); + } + return true; +} + +static void mdfld_dsi_dbi_set_power(struct drm_encoder *encoder, bool on) +{ + int ret = 0; + struct mdfld_dsi_encoder *dsi_encoder = MDFLD_DSI_ENCODER(encoder); + struct mdfld_dsi_dbi_output *dbi_output = + MDFLD_DSI_DBI_OUTPUT(dsi_encoder); + struct mdfld_dsi_config *dsi_config = + mdfld_dsi_encoder_get_config(dsi_encoder); + struct mdfld_dsi_pkg_sender *sender = + mdfld_dsi_encoder_get_pkg_sender(dsi_encoder); + struct drm_device *dev = encoder->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + u32 reg_offset = 0; + int pipe = (dbi_output->channel_num == 0) ? 0 : 2; + u32 data = 0; + + dev_dbg(dev->dev, "pipe %d : %s, panel on: %s\n", + pipe, on ? "On" : "Off", + dbi_output->dbi_panel_on ? "True" : "False"); + + if (pipe == 2) { + if (on) + dev_priv->dual_mipi = true; + else + dev_priv->dual_mipi = false; + reg_offset = MIPIC_REG_OFFSET; + } else { + if (!on) + dev_priv->dual_mipi = false; + } + + if (!gma_power_begin(dev, true)) { + dev_err(dev->dev, "hw begin failed\n"); + return; + } + + if (on) { + if (dbi_output->dbi_panel_on) + goto out_err; + + ret = mdfld_dsi_dbi_update_power(dbi_output, DRM_MODE_DPMS_ON); + if (ret) { + dev_err(dev->dev, "power on error\n"); + goto out_err; + } + + dbi_output->dbi_panel_on = true; + + if (pipe == 2) + dev_priv->dbi_panel_on2 = true; + else + dev_priv->dbi_panel_on = true; + mdfld_enable_te(dev, pipe); + } else { + if (!dbi_output->dbi_panel_on && !dbi_output->first_boot) + goto out_err; + + dbi_output->dbi_panel_on = false; + dbi_output->first_boot = false; + + if (pipe == 2) + dev_priv->dbi_panel_on2 = false; + else + dev_priv->dbi_panel_on = false; + + mdfld_disable_te(dev, pipe); + + ret = mdfld_dsi_dbi_update_power(dbi_output, DRM_MODE_DPMS_OFF); + if (ret) { + dev_err(dev->dev, "power on error\n"); + goto out_err; + } + } + + /* + * FIXME: this is a WA for TPO panel crash on DPMS on & off around + * 83 times. the root cause of this issue is that Booster in + * drvIC crashed. Add this WA so that we can resume the driver IC + * once we found that booster has a fault + */ + mdfld_dsi_get_power_mode(dsi_config, + &data, + MDFLD_DSI_HS_TRANSMISSION); + + if (on && data && !(data & (1 << 7))) { + /* Soft reset */ + mdfld_dsi_send_dcs(sender, + DCS_SOFT_RESET, + NULL, + 0, + CMD_DATA_SRC_PIPE, + MDFLD_DSI_SEND_PACKAGE); + + /* Init drvIC */ + if (dbi_output->p_funcs->drv_ic_init) + dbi_output->p_funcs->drv_ic_init(dsi_config, + pipe); + } + +out_err: + gma_power_end(dev); + if (ret) + dev_err(dev->dev, "failed\n"); +} + + +static void mdfld_dsi_dbi_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + int ret = 0; + struct drm_device *dev = encoder->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + struct mdfld_dsi_encoder *dsi_encoder = MDFLD_DSI_ENCODER(encoder); + struct mdfld_dsi_dbi_output *dsi_output = + MDFLD_DSI_DBI_OUTPUT(dsi_encoder); + struct mdfld_dsi_config *dsi_config = + mdfld_dsi_encoder_get_config(dsi_encoder); + struct mdfld_dsi_connector *dsi_connector = dsi_config->connector; + int pipe = dsi_connector->pipe; + u8 param = 0; + + /* Regs */ + u32 mipi_reg = MIPI; + u32 dspcntr_reg = DSPACNTR; + u32 pipeconf_reg = PIPEACONF; + u32 reg_offset = 0; + + /* Values */ + u32 dspcntr_val = dev_priv->dspcntr; + u32 pipeconf_val = dev_priv->pipeconf; + u32 h_active_area = mode->hdisplay; + u32 v_active_area = mode->vdisplay; + u32 mipi_val; + + mipi_val = (PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX | + TE_TRIGGER_GPIO_PIN); + + dev_dbg(dev->dev, "mipi_val =0x%x\n", mipi_val); + + dev_dbg(dev->dev, "type %s\n", (pipe == 2) ? "MIPI2" : "MIPI"); + dev_dbg(dev->dev, "h %d v %d\n", mode->hdisplay, mode->vdisplay); + + if (pipe == 2) { + mipi_reg = MIPI_C; + dspcntr_reg = DSPCCNTR; + pipeconf_reg = PIPECCONF; + + reg_offset = MIPIC_REG_OFFSET; + + dspcntr_val = dev_priv->dspcntr2; + pipeconf_val = dev_priv->pipeconf2; + } else { + mipi_val |= 0x2; /*two lanes for port A and C respectively*/ + } + + if (!gma_power_begin(dev, true)) { + dev_err(dev->dev, "hw begin failed\n"); + return; + } + + REG_WRITE(dspcntr_reg, dspcntr_val); + REG_READ(dspcntr_reg); + + /* 20ms delay before sending exit_sleep_mode */ + msleep(20); + + /* Send exit_sleep_mode DCS */ + ret = mdfld_dsi_dbi_send_dcs(dsi_output, DCS_EXIT_SLEEP_MODE, + NULL, 0, CMD_DATA_SRC_SYSTEM_MEM); + if (ret) { + dev_err(dev->dev, "sent exit_sleep_mode faild\n"); + goto out_err; + } + + /* Send set_tear_on DCS */ + ret = mdfld_dsi_dbi_send_dcs(dsi_output, DCS_SET_TEAR_ON, + ¶m, 1, CMD_DATA_SRC_SYSTEM_MEM); + if (ret) { + dev_err(dev->dev, "%s - sent set_tear_on faild\n", __func__); + goto out_err; + } + + /* Do some init stuff */ + REG_WRITE(pipeconf_reg, pipeconf_val | PIPEACONF_DSR); + REG_READ(pipeconf_reg); + + /* TODO: this looks ugly, try to move it to CRTC mode setting*/ + if (pipe == 2) + dev_priv->pipeconf2 |= PIPEACONF_DSR; + else + dev_priv->pipeconf |= PIPEACONF_DSR; + + dev_dbg(dev->dev, "pipeconf %x\n", REG_READ(pipeconf_reg)); + + ret = mdfld_dsi_dbi_update_area(dsi_output, 0, 0, + h_active_area - 1, v_active_area - 1); + if (ret) { + dev_err(dev->dev, "update area failed\n"); + goto out_err; + } + +out_err: + gma_power_end(dev); + + if (ret) + dev_err(dev->dev, "mode set failed\n"); +} + +static void mdfld_dsi_dbi_prepare(struct drm_encoder *encoder) +{ + struct mdfld_dsi_encoder *dsi_encoder = MDFLD_DSI_ENCODER(encoder); + struct mdfld_dsi_dbi_output *dbi_output + = MDFLD_DSI_DBI_OUTPUT(dsi_encoder); + + dbi_output->mode_flags |= MODE_SETTING_IN_ENCODER; + dbi_output->mode_flags &= ~MODE_SETTING_ENCODER_DONE; + + mdfld_dsi_dbi_set_power(encoder, false); +} + +static void mdfld_dsi_dbi_commit(struct drm_encoder *encoder) +{ + struct mdfld_dsi_encoder *dsi_encoder = MDFLD_DSI_ENCODER(encoder); + struct mdfld_dsi_dbi_output *dbi_output = + MDFLD_DSI_DBI_OUTPUT(dsi_encoder); + struct drm_device *dev = dbi_output->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + struct psb_drm_dpu_rect rect; + + mdfld_dsi_dbi_set_power(encoder, true); + dbi_output->mode_flags &= ~MODE_SETTING_IN_ENCODER; + + rect.x = rect.y = 0; + rect.width = 864; + rect.height = 480; + + if (dbi_output->channel_num == 1) { + dev_priv->dsr_fb_update |= MDFLD_DSR_2D_3D_2; + /*if dpu enabled report a fullscreen damage*/ + mdfld_dbi_dpu_report_damage(dev, MDFLD_PLANEC, &rect); + } else { + dev_priv->dsr_fb_update |= MDFLD_DSR_2D_3D_0; + mdfld_dbi_dpu_report_damage(dev, MDFLD_PLANEA, &rect); + } + dbi_output->mode_flags |= MODE_SETTING_ENCODER_DONE; +} + +static void mdfld_dsi_dbi_dpms(struct drm_encoder *encoder, int mode) +{ + struct mdfld_dsi_encoder *dsi_encoder = MDFLD_DSI_ENCODER(encoder); + struct mdfld_dsi_dbi_output *dbi_output + = MDFLD_DSI_DBI_OUTPUT(dsi_encoder); + struct drm_device *dev = dbi_output->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + static bool bdispoff; + + dev_dbg(dev->dev, "%s\n", (mode == DRM_MODE_DPMS_ON ? "on" : "off")); + + if (mode == DRM_MODE_DPMS_ON) { + /* + * FIXME: in case I am wrong! + * we don't need to exit dsr here to wake up plane/pipe/pll + * if everything goes right, hw_begin will resume them all + * during set_power. + */ + if (bdispoff /* FIXME && gbgfxsuspended */) { + mdfld_dsi_dbi_exit_dsr(dev, MDFLD_DSR_2D_3D); + bdispoff = false; + dev_priv->dispstatus = true; + } + + mdfld_dsi_dbi_set_power(encoder, true); + /* FIXME if (gbgfxsuspended) + gbgfxsuspended = false; */ + } else { + /* + * I am not sure whether this is the perfect place to + * turn rpm on since we still have a lot of CRTC turnning + * on work to do. + */ + bdispoff = true; + dev_priv->dispstatus = false; + mdfld_dsi_dbi_set_power(encoder, false); + } +} + + +/* + * Update the DBI MIPI Panel Frame Buffer. + */ +static void mdfld_dsi_dbi_update_fb(struct mdfld_dsi_dbi_output *dbi_output, + int pipe) +{ + struct mdfld_dsi_pkg_sender *sender = + mdfld_dsi_encoder_get_pkg_sender(&dbi_output->base); + struct drm_device *dev = dbi_output->dev; + struct drm_crtc *crtc = dbi_output->base.base.crtc; + struct psb_intel_crtc *psb_crtc = (crtc) ? + to_psb_intel_crtc(crtc) : NULL; + u32 dpll_reg = MRST_DPLL_A; + u32 dspcntr_reg = DSPACNTR; + u32 pipeconf_reg = PIPEACONF; + u32 dsplinoff_reg = DSPALINOFF; + u32 dspsurf_reg = DSPASURF; + u32 reg_offset = 0; + + /* If mode setting on-going, back off */ + if ((dbi_output->mode_flags & MODE_SETTING_ON_GOING) || + (psb_crtc && psb_crtc->mode_flags & MODE_SETTING_ON_GOING) || + !(dbi_output->mode_flags & MODE_SETTING_ENCODER_DONE)) + return; + + if (pipe == 2) { + dspcntr_reg = DSPCCNTR; + pipeconf_reg = PIPECCONF; + dsplinoff_reg = DSPCLINOFF; + dspsurf_reg = DSPCSURF; + reg_offset = MIPIC_REG_OFFSET; + } + + if (!gma_power_begin(dev, true)) { + dev_err(dev->dev, "hw begin failed\n"); + return; + } + + /* Check DBI FIFO status */ + if (!(REG_READ(dpll_reg) & DPLL_VCO_ENABLE) || + !(REG_READ(dspcntr_reg) & DISPLAY_PLANE_ENABLE) || + !(REG_READ(pipeconf_reg) & DISPLAY_PLANE_ENABLE)) + goto update_fb_out0; + + /* Refresh plane changes */ + REG_WRITE(dsplinoff_reg, REG_READ(dsplinoff_reg)); + REG_WRITE(dspsurf_reg, REG_READ(dspsurf_reg)); + REG_READ(dspsurf_reg); + + mdfld_dsi_send_dcs(sender, + DCS_WRITE_MEM_START, + NULL, + 0, + CMD_DATA_SRC_PIPE, + MDFLD_DSI_SEND_PACKAGE); + + dbi_output->dsr_fb_update_done = true; +update_fb_out0: + gma_power_end(dev); +} + +static int tpo_cmd_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 DBI encoder helper funcs */ +static const struct drm_encoder_helper_funcs mdfld_dsi_dbi_helper_funcs = { + .dpms = mdfld_dsi_dbi_dpms, + .mode_fixup = mdfld_dsi_dbi_mode_fixup, + .prepare = mdfld_dsi_dbi_prepare, + .mode_set = mdfld_dsi_dbi_mode_set, + .commit = mdfld_dsi_dbi_commit, +}; + +/* TPO DBI encoder funcs */ +static const struct drm_encoder_funcs mdfld_dsi_dbi_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +void tpo_cmd_init(struct drm_device *dev, struct panel_funcs *p_funcs) +{ + p_funcs->encoder_funcs = &mdfld_dsi_dbi_encoder_funcs; + p_funcs->encoder_helper_funcs = &mdfld_dsi_dbi_helper_funcs; + p_funcs->get_config_mode = &tpo_cmd_get_config_mode; + p_funcs->update_fb = mdfld_dsi_dbi_update_fb; + p_funcs->get_panel_info = tpo_cmd_get_panel_info; + p_funcs->reset = mdfld_dsi_panel_reset; + p_funcs->drv_ic_init = mdfld_dsi_brightness_init; +} diff --git a/drivers/staging/gma500/mdfld_tpo_vid.c b/drivers/staging/gma500/mdfld_tpo_vid.c new file mode 100644 index 0000000..9549017 --- /dev/null +++ b/drivers/staging/gma500/mdfld_tpo_vid.c @@ -0,0 +1,140 @@ +/* + * 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_dbi.h" +#include "mdfld_dsi_dpi.h" +#include "mdfld_dsi_output.h" +#include "mdfld_output.h" + +#include "mdfld_dsi_pkg_sender.h" + +#include "displays/tpo_vid.h" + +static struct drm_display_mode *tpo_vid_get_config_mode(struct drm_device *dev) +{ + struct drm_display_mode *mode; + struct drm_psb_private *dev_priv = dev->dev_private; + struct mrst_timing_info *ti = &dev_priv->gct_data.DTD; + bool use_gct = false; + + mode = kzalloc(sizeof(*mode), GFP_KERNEL); + if (!mode) { + dev_err(dev->dev, "out of memory\n"); + return NULL; + } + + if (use_gct) { + mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo; + mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo; + mode->hsync_start = mode->hdisplay + \ + ((ti->hsync_offset_hi << 8) | \ + ti->hsync_offset_lo); + mode->hsync_end = mode->hsync_start + \ + ((ti->hsync_pulse_width_hi << 8) | \ + ti->hsync_pulse_width_lo); + mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) | \ + ti->hblank_lo); + mode->vsync_start = \ + mode->vdisplay + ((ti->vsync_offset_hi << 8) | \ + ti->vsync_offset_lo); + mode->vsync_end = \ + mode->vsync_start + ((ti->vsync_pulse_width_hi << 8) | \ + ti->vsync_pulse_width_lo); + mode->vtotal = mode->vdisplay + \ + ((ti->vblank_hi << 8) | ti->vblank_lo); + mode->clock = ti->pixel_clock * 10; + + dev_dbg(dev->dev, "hdisplay is %d\n", mode->hdisplay); + dev_dbg(dev->dev, "vdisplay is %d\n", mode->vdisplay); + dev_dbg(dev->dev, "HSS is %d\n", mode->hsync_start); + dev_dbg(dev->dev, "HSE is %d\n", mode->hsync_end); + dev_dbg(dev->dev, "htotal is %d\n", mode->htotal); + dev_dbg(dev->dev, "VSS is %d\n", mode->vsync_start); + dev_dbg(dev->dev, "VSE is %d\n", mode->vsync_end); + dev_dbg(dev->dev, "vtotal is %d\n", mode->vtotal); + dev_dbg(dev->dev, "clock is %d\n", mode->clock); + } else { + mode->hdisplay = 864; + mode->vdisplay = 480; + mode->hsync_start = 873; + mode->hsync_end = 876; + mode->htotal = 887; + mode->vsync_start = 487; + mode->vsync_end = 490; + mode->vtotal = 499; + mode->clock = 33264; + } + + drm_mode_set_name(mode); + drm_mode_set_crtcinfo(mode, 0); + + mode->type |= DRM_MODE_TYPE_PREFERRED; + + return mode; +} + +static int tpo_vid_get_panel_info(struct drm_device *dev, + int pipe, + struct panel_info *pi) +{ + if (!dev || !pi) + return -EINVAL; + + pi->width_mm = TPO_PANEL_WIDTH; + pi->height_mm = TPO_PANEL_HEIGHT; + + return 0; +} + +/*TPO DPI encoder helper funcs*/ +static const struct drm_encoder_helper_funcs + mdfld_tpo_dpi_encoder_helper_funcs = { + .dpms = mdfld_dsi_dpi_dpms, + .mode_fixup = mdfld_dsi_dpi_mode_fixup, + .prepare = mdfld_dsi_dpi_prepare, + .mode_set = mdfld_dsi_dpi_mode_set, + .commit = mdfld_dsi_dpi_commit, +}; + +/*TPO DPI encoder funcs*/ +static const struct drm_encoder_funcs mdfld_tpo_dpi_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +void tpo_vid_init(struct drm_device *dev, struct panel_funcs *p_funcs) +{ + if (!dev || !p_funcs) { + dev_err(dev->dev, "tpo_vid_init: Invalid parameters\n"); + return; + } + + p_funcs->encoder_funcs = &mdfld_tpo_dpi_encoder_funcs; + p_funcs->encoder_helper_funcs = &mdfld_tpo_dpi_encoder_helper_funcs; + p_funcs->get_config_mode = &tpo_vid_get_config_mode; + p_funcs->update_fb = NULL; + p_funcs->get_panel_info = tpo_vid_get_panel_info; +} diff --git a/drivers/staging/gma500/medfield.h b/drivers/staging/gma500/medfield.h new file mode 100644 index 0000000..38165e8 --- /dev/null +++ b/drivers/staging/gma500/medfield.h @@ -0,0 +1,270 @@ +/* + * 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. + */ + +#define DRM_MODE_ENCODER_MIPI 5 + +/* Medfield DSI controller registers */ + +#define MIPIA_DEVICE_READY_REG 0xb000 +#define MIPIA_INTR_STAT_REG 0xb004 +#define MIPIA_INTR_EN_REG 0xb008 +#define MIPIA_DSI_FUNC_PRG_REG 0xb00c +#define MIPIA_HS_TX_TIMEOUT_REG 0xb010 +#define MIPIA_LP_RX_TIMEOUT_REG 0xb014 +#define MIPIA_TURN_AROUND_TIMEOUT_REG 0xb018 +#define MIPIA_DEVICE_RESET_TIMER_REG 0xb01c +#define MIPIA_DPI_RESOLUTION_REG 0xb020 +#define MIPIA_DBI_FIFO_THROTTLE_REG 0xb024 +#define MIPIA_HSYNC_COUNT_REG 0xb028 +#define MIPIA_HBP_COUNT_REG 0xb02c +#define MIPIA_HFP_COUNT_REG 0xb030 +#define MIPIA_HACTIVE_COUNT_REG 0xb034 +#define MIPIA_VSYNC_COUNT_REG 0xb038 +#define MIPIA_VBP_COUNT_REG 0xb03c +#define MIPIA_VFP_COUNT_REG 0xb040 +#define MIPIA_HIGH_LOW_SWITCH_COUNT_REG 0xb044 +#define MIPIA_DPI_CONTROL_REG 0xb048 +#define MIPIA_DPI_DATA_REG 0xb04c +#define MIPIA_INIT_COUNT_REG 0xb050 +#define MIPIA_MAX_RETURN_PACK_SIZE_REG 0xb054 +#define MIPIA_VIDEO_MODE_FORMAT_REG 0xb058 +#define MIPIA_EOT_DISABLE_REG 0xb05c +#define MIPIA_LP_BYTECLK_REG 0xb060 +#define MIPIA_LP_GEN_DATA_REG 0xb064 +#define MIPIA_HS_GEN_DATA_REG 0xb068 +#define MIPIA_LP_GEN_CTRL_REG 0xb06c +#define MIPIA_HS_GEN_CTRL_REG 0xb070 +#define MIPIA_GEN_FIFO_STAT_REG 0xb074 +#define MIPIA_HS_LS_DBI_ENABLE_REG 0xb078 +#define MIPIA_DPHY_PARAM_REG 0xb080 +#define MIPIA_DBI_BW_CTRL_REG 0xb084 +#define MIPIA_CLK_LANE_SWITCH_TIME_CNT_REG 0xb088 + +#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 1 + +#define DSI_INTR_STATE_SPL_PKG_SENT (1 << 30) +#define DSI_INTR_STATE_TE (1 << 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 (1 << 0) +#define DSI_FIFO_GEN_HS_DATA_HALF_EMPTY (1 << 1) +#define DSI_FIFO_GEN_HS_DATA_EMPTY (1 << 2) +#define DSI_FIFO_GEN_LP_DATA_FULL (1 << 8) +#define DSI_FIFO_GEN_LP_DATA_HALF_EMPTY (1 << 9) +#define DSI_FIFO_GEN_LP_DATA_EMPTY (1 << 10) +#define DSI_FIFO_GEN_HS_CTRL_FULL (1 << 16) +#define DSI_FIFO_GEN_HS_CTRL_HALF_EMPTY (1 << 17) +#define DSI_FIFO_GEN_HS_CTRL_EMPTY (1 << 18) +#define DSI_FIFO_GEN_LP_CTRL_FULL (1 << 24) +#define DSI_FIFO_GEN_LP_CTRL_HALF_EMPTY (1 << 25) +#define DSI_FIFO_GEN_LP_CTRL_EMPTY (1 << 26) +#define DSI_FIFO_DBI_EMPTY (1 << 27) +#define DSI_FIFO_DPI_EMPTY (1 << 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) + +/* Medfield DSI adapter registers */ +#define MIPIA_CONTROL_REG 0xb104 +#define MIPIA_DATA_ADD_REG 0xb108 +#define MIPIA_DATA_LEN_REG 0xb10c +#define MIPIA_CMD_ADD_REG 0xb110 +#define MIPIA_CMD_LEN_REG 0xb114 + +/*dsi power modes*/ +#define DSI_POWER_MODE_DISPLAY_ON (1 << 2) +#define DSI_POWER_MODE_NORMAL_ON (1 << 3) +#define DSI_POWER_MODE_SLEEP_OUT (1 << 4) +#define DSI_POWER_MODE_PARTIAL_ON (1 << 5) +#define DSI_POWER_MODE_IDLE_ON (1 << 6) + +enum { + MDFLD_DSI_ENCODER_DBI = 0, + MDFLD_DSI_ENCODER_DPI, +}; + +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 (1 << 2) +#define DSI_DPI_DISABLE_BTA (1 << 3) +/* Panel types */ +enum { + TPO_CMD, + TPO_VID, + TMD_CMD, + TMD_VID, + PYR_CMD, + PYR_VID, + TPO, + TMD, + PYR, + HDMI, + GCT_DETECT +}; + +/* Junk that belongs elsewhere */ +#define TPO_PANEL_WIDTH 84 +#define TPO_PANEL_HEIGHT 46 +#define TMD_PANEL_WIDTH 39 +#define TMD_PANEL_HEIGHT 71 +#define PYR_PANEL_WIDTH 53 +#define PYR_PANEL_HEIGHT 95 + +/* Panel interface */ +struct panel_info { + u32 width_mm; + u32 height_mm; +}; + +struct mdfld_dsi_dbi_output; + +struct mdfld_dsi_connector_state { + u32 mipi_ctrl_reg; +}; + +struct mdfld_dsi_encoder_state { + +}; + +struct mdfld_dsi_connector { + /* + * This is ugly, but I have to use connector in it! :-( + * FIXME: use drm_connector instead. + */ + struct psb_intel_output base; + + int pipe; + void *private; + void *pkg_sender; + + /* Connection status */ + enum drm_connector_status status; +}; + +struct mdfld_dsi_encoder { + struct drm_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 *encoders[DRM_CONNECTOR_MAX_ENCODER]; + struct mdfld_dsi_encoder *encoder; + + int changed; + + int bpp; + int type; + int lane_count; + /*Virtual channel number for this encoder*/ + int channel_num; + /*video mode configure*/ + int video_mode; + + int dvr_ic_inited; +}; + +#define MDFLD_DSI_CONNECTOR(psb_output) \ + (container_of(psb_output, struct mdfld_dsi_connector, base)) + +#define MDFLD_DSI_ENCODER(encoder) \ + (container_of(encoder, struct mdfld_dsi_encoder, base)) + +struct panel_funcs { + const struct drm_encoder_funcs *encoder_funcs; + const struct drm_encoder_helper_funcs *encoder_helper_funcs; + struct drm_display_mode *(*get_config_mode) (struct drm_device *); + void (*update_fb) (struct mdfld_dsi_dbi_output *, int); + int (*get_panel_info) (struct drm_device *, int, struct panel_info *); + int (*reset)(int pipe); + void (*drv_ic_init)(struct mdfld_dsi_config *dsi_config, int pipe); +}; + diff --git a/drivers/staging/gma500/mid_bios.c b/drivers/staging/gma500/mid_bios.c new file mode 100644 index 0000000..8cfe301 --- /dev/null +++ b/drivers/staging/gma500/mid_bios.c @@ -0,0 +1,269 @@ +/************************************************************************** + * Copyright (c) 2011, Intel Corporation. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + **************************************************************************/ + +/* TODO + * - Split functions by vbt type + * - Make them all take drm_device + * - Check ioremap failures + */ + +#include <drm/drmP.h> +#include <drm/drm.h> +#include "psb_drm.h" +#include "psb_drv.h" +#include "mid_bios.h" +#include "mdfld_output.h" + +static int panel_id = GCT_DETECT; +module_param_named(panel_id, panel_id, int, 0600); +MODULE_PARM_DESC(panel_id, "Panel Identifier"); + + +static void mid_get_fuse_settings(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0); + uint32_t fuse_value = 0; + uint32_t fuse_value_tmp = 0; + +#define FB_REG06 0xD0810600 +#define FB_MIPI_DISABLE (1 << 11) +#define FB_REG09 0xD0810900 +#define FB_REG09 0xD0810900 +#define FB_SKU_MASK 0x7000 +#define FB_SKU_SHIFT 12 +#define FB_SKU_100 0 +#define FB_SKU_100L 1 +#define FB_SKU_83 2 + pci_write_config_dword(pci_root, 0xD0, FB_REG06); + pci_read_config_dword(pci_root, 0xD4, &fuse_value); + + /* FB_MIPI_DISABLE doesn't mean LVDS on with Medfield */ + if (IS_MRST(dev)) + dev_priv->iLVDS_enable = fuse_value & FB_MIPI_DISABLE; + + DRM_INFO("internal display is %s\n", + dev_priv->iLVDS_enable ? "LVDS display" : "MIPI display"); + + /* Prevent runtime suspend at start*/ + if (dev_priv->iLVDS_enable) { + dev_priv->is_lvds_on = true; + dev_priv->is_mipi_on = false; + } else { + dev_priv->is_mipi_on = true; + dev_priv->is_lvds_on = false; + } + + dev_priv->video_device_fuse = fuse_value; + + pci_write_config_dword(pci_root, 0xD0, FB_REG09); + pci_read_config_dword(pci_root, 0xD4, &fuse_value); + + dev_dbg(dev->dev, "SKU values is 0x%x.\n", fuse_value); + fuse_value_tmp = (fuse_value & FB_SKU_MASK) >> FB_SKU_SHIFT; + + dev_priv->fuse_reg_value = fuse_value; + + switch (fuse_value_tmp) { + case FB_SKU_100: + dev_priv->core_freq = 200; + break; + case FB_SKU_100L: + dev_priv->core_freq = 100; + break; + case FB_SKU_83: + dev_priv->core_freq = 166; + break; + default: + dev_warn(dev->dev, "Invalid SKU values, SKU value = 0x%08x\n", + fuse_value_tmp); + dev_priv->core_freq = 0; + } + dev_dbg(dev->dev, "LNC core clk is %dMHz.\n", dev_priv->core_freq); + pci_dev_put(pci_root); +} + +/* + * Get the revison ID, B0:D2:F0;0x08 + */ +static void mid_get_pci_revID(struct drm_psb_private *dev_priv) +{ + uint32_t platform_rev_id = 0; + struct pci_dev *pci_gfx_root = pci_get_bus_and_slot(0, PCI_DEVFN(2, 0)); + + pci_read_config_dword(pci_gfx_root, 0x08, &platform_rev_id); + dev_priv->platform_rev_id = (uint8_t) platform_rev_id; + pci_dev_put(pci_gfx_root); + dev_dbg(dev_priv->dev->dev, "platform_rev_id is %x\n", + dev_priv->platform_rev_id); +} + +static void mid_get_vbt_data(struct drm_psb_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct mrst_vbt *vbt = &dev_priv->vbt_data; + u32 addr; + u16 new_size; + u8 *vbt_virtual; + u8 bpi; + u8 number_desc = 0; + struct mrst_timing_info *dp_ti = &dev_priv->gct_data.DTD; + struct gct_r10_timing_info ti; + void *pGCT; + struct pci_dev *pci_gfx_root = pci_get_bus_and_slot(0, PCI_DEVFN(2, 0)); + + /* Get the address of the platform config vbt, B0:D2:F0;0xFC */ + pci_read_config_dword(pci_gfx_root, 0xFC, &addr); + pci_dev_put(pci_gfx_root); + + dev_dbg(dev->dev, "drm platform config address is %x\n", addr); + + /* check for platform config address == 0. */ + /* this means fw doesn't support vbt */ + + if (addr == 0) { + vbt->size = 0; + return; + } + + /* get the virtual address of the vbt */ + vbt_virtual = ioremap(addr, sizeof(*vbt)); + + memcpy(vbt, vbt_virtual, sizeof(*vbt)); + iounmap(vbt_virtual); /* Free virtual address space */ + + dev_dbg(dev->dev, "GCT revision is %x\n", vbt->revision); + + switch (vbt->revision) { + case 0: + vbt->mrst_gct = ioremap(addr + sizeof(*vbt) - 4, + vbt->size - sizeof(*vbt) + 4); + pGCT = vbt->mrst_gct; + bpi = ((struct mrst_gct_v1 *)pGCT)->PD.BootPanelIndex; + dev_priv->gct_data.bpi = bpi; + dev_priv->gct_data.pt = + ((struct mrst_gct_v1 *)pGCT)->PD.PanelType; + memcpy(&dev_priv->gct_data.DTD, + &((struct mrst_gct_v1 *)pGCT)->panel[bpi].DTD, + sizeof(struct mrst_timing_info)); + dev_priv->gct_data.Panel_Port_Control = + ((struct mrst_gct_v1 *)pGCT)->panel[bpi].Panel_Port_Control; + dev_priv->gct_data.Panel_MIPI_Display_Descriptor = + ((struct mrst_gct_v1 *)pGCT)->panel[bpi].Panel_MIPI_Display_Descriptor; + break; + case 1: + vbt->mrst_gct = ioremap(addr + sizeof(*vbt) - 4, + vbt->size - sizeof(*vbt) + 4); + pGCT = vbt->mrst_gct; + bpi = ((struct mrst_gct_v2 *)pGCT)->PD.BootPanelIndex; + dev_priv->gct_data.bpi = bpi; + dev_priv->gct_data.pt = + ((struct mrst_gct_v2 *)pGCT)->PD.PanelType; + memcpy(&dev_priv->gct_data.DTD, + &((struct mrst_gct_v2 *)pGCT)->panel[bpi].DTD, + sizeof(struct mrst_timing_info)); + dev_priv->gct_data.Panel_Port_Control = + ((struct mrst_gct_v2 *)pGCT)->panel[bpi].Panel_Port_Control; + dev_priv->gct_data.Panel_MIPI_Display_Descriptor = + ((struct mrst_gct_v2 *)pGCT)->panel[bpi].Panel_MIPI_Display_Descriptor; + break; + case 0x10: + /*header definition changed from rev 01 (v2) to rev 10h. */ + /*so, some values have changed location*/ + new_size = vbt->checksum; /*checksum contains lo size byte*/ + /*LSB of mrst_gct contains hi size byte*/ + new_size |= ((0xff & (unsigned int)vbt->mrst_gct)) << 8; + + vbt->checksum = vbt->size; /*size contains the checksum*/ + if (new_size > 0xff) + vbt->size = 0xff; /*restrict size to 255*/ + else + vbt->size = new_size; + + /* number of descriptors defined in the GCT */ + number_desc = ((0xff00 & (unsigned int)vbt->mrst_gct)) >> 8; + bpi = ((0xff0000 & (unsigned int)vbt->mrst_gct)) >> 16; + vbt->mrst_gct = ioremap(addr + GCT_R10_HEADER_SIZE, + GCT_R10_DISPLAY_DESC_SIZE * number_desc); + pGCT = vbt->mrst_gct; + pGCT = (u8 *)pGCT + (bpi*GCT_R10_DISPLAY_DESC_SIZE); + dev_priv->gct_data.bpi = bpi; /*save boot panel id*/ + + /*copy the GCT display timings into a temp structure*/ + memcpy(&ti, pGCT, sizeof(struct gct_r10_timing_info)); + + /*now copy the temp struct into the dev_priv->gct_data*/ + dp_ti->pixel_clock = ti.pixel_clock; + dp_ti->hactive_hi = ti.hactive_hi; + dp_ti->hactive_lo = ti.hactive_lo; + dp_ti->hblank_hi = ti.hblank_hi; + dp_ti->hblank_lo = ti.hblank_lo; + dp_ti->hsync_offset_hi = ti.hsync_offset_hi; + dp_ti->hsync_offset_lo = ti.hsync_offset_lo; + dp_ti->hsync_pulse_width_hi = ti.hsync_pulse_width_hi; + dp_ti->hsync_pulse_width_lo = ti.hsync_pulse_width_lo; + dp_ti->vactive_hi = ti.vactive_hi; + dp_ti->vactive_lo = ti.vactive_lo; + dp_ti->vblank_hi = ti.vblank_hi; + dp_ti->vblank_lo = ti.vblank_lo; + dp_ti->vsync_offset_hi = ti.vsync_offset_hi; + dp_ti->vsync_offset_lo = ti.vsync_offset_lo; + dp_ti->vsync_pulse_width_hi = ti.vsync_pulse_width_hi; + dp_ti->vsync_pulse_width_lo = ti.vsync_pulse_width_lo; + + /* Move the MIPI_Display_Descriptor data from GCT to dev priv */ + dev_priv->gct_data.Panel_MIPI_Display_Descriptor = + *((u8 *)pGCT + 0x0d); + dev_priv->gct_data.Panel_MIPI_Display_Descriptor |= + (*((u8 *)pGCT + 0x0e)) << 8; + break; + default: + dev_err(dev->dev, "Unknown revision of GCT!\n"); + vbt->size = 0; + } + if (IS_MFLD(dev_priv->dev)) { + if (panel_id == GCT_DETECT) { + if (dev_priv->gct_data.bpi == 2) { + dev_info(dev->dev, "[GFX] PYR Panel Detected\n"); + dev_priv->panel_id = PYR_CMD; + panel_id = PYR_CMD; + } else if (dev_priv->gct_data.bpi == 0) { + dev_info(dev->dev, "[GFX] TMD Panel Detected.\n"); + dev_priv->panel_id = TMD_VID; + panel_id = TMD_VID; + } else { + dev_info(dev->dev, "[GFX] Default Panel (TPO)\n"); + dev_priv->panel_id = TPO_CMD; + panel_id = TPO_CMD; + } + } else { + dev_info(dev->dev, "[GFX] Panel Parameter Passed in through cmd line\n"); + dev_priv->panel_id = panel_id; + } + } +} + +int mid_chip_setup(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + mid_get_fuse_settings(dev); + mid_get_vbt_data(dev_priv); + mid_get_pci_revID(dev_priv); + return 0; +} diff --git a/drivers/staging/gma500/mid_bios.h b/drivers/staging/gma500/mid_bios.h new file mode 100644 index 0000000..00e7d56 --- /dev/null +++ b/drivers/staging/gma500/mid_bios.h @@ -0,0 +1,21 @@ +/************************************************************************** + * Copyright (c) 2011, Intel Corporation. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + **************************************************************************/ + +extern int mid_chip_setup(struct drm_device *dev); + diff --git a/drivers/staging/gma500/psb_mmu.c b/drivers/staging/gma500/mmu.c index c904d73..c904d73 100644 --- a/drivers/staging/gma500/psb_mmu.c +++ b/drivers/staging/gma500/mmu.c diff --git a/drivers/staging/gma500/mrst.h b/drivers/staging/gma500/mrst.h index 5e4aaeb..b563dbc 100644 --- a/drivers/staging/gma500/mrst.h +++ b/drivers/staging/gma500/mrst.h @@ -25,7 +25,7 @@ struct mrst_vbt { u8 size; u8 checksum; void *mrst_gct; -} __attribute__ ((packed)); +} __packed; struct mrst_timing_info { u16 pixel_clock; @@ -58,7 +58,7 @@ struct mrst_timing_info { u8 stereo:1; u8 unknown6:1; u8 interlaced:1; -} __attribute__((packed)); +} __packed; struct gct_r10_timing_info { u16 pixel_clock; @@ -82,7 +82,7 @@ struct gct_r10_timing_info { u16 vsync_pulse_width_hi:2; u16 vsync_positive:1; u16 rsvd_2:3; -} __attribute__((packed)); +} __packed; struct mrst_panel_descriptor_v1 { u32 Panel_Port_Control; /* 1 dword, Register 0x61180 if LVDS */ @@ -111,7 +111,7 @@ struct mrst_panel_descriptor_v1 { /* Bit 6, Reserved, 2 bits, 00b */ /* Bit 8, Minimum Supported Frame Rate, 6 bits, 0 - 63Hz */ /* Bit 14, Reserved, 2 bits, 00b */ -} __attribute__ ((packed)); +} __packed; struct mrst_panel_descriptor_v2 { u32 Panel_Port_Control; /* 1 dword, Register 0x61180 if LVDS */ @@ -141,10 +141,10 @@ struct mrst_panel_descriptor_v2 { /* Bit 6, Reserved, 2 bits, 00b */ /* Bit 8, Minimum Supported Frame Rate, 6 bits, 0 - 63Hz */ /* Bit 14, Reserved, 2 bits, 00b */ -} __attribute__ ((packed)); +} __packed; union mrst_panel_rx { - struct{ + struct { u16 NumberOfLanes:2; /*Num of Lanes, 2 bits,0 = 1 lane,*/ /* 1 = 2 lanes, 2 = 3 lanes, 3 = 4 lanes. */ u16 MaxLaneFreq:3; /* 0: 100MHz, 1: 200MHz, 2: 300MHz, */ @@ -159,10 +159,10 @@ union mrst_panel_rx { u16 Rsvd:5;/*5 bits,00000b */ } panelrx; u16 panel_receiver; -} __attribute__ ((packed)); +} __packed; struct mrst_gct_v1 { - union{ /*8 bits,Defined as follows: */ + union { /*8 bits,Defined as follows: */ struct { u8 PanelType:4; /*4 bits, Bit field for panels*/ /* 0 - 3: 0 = LVDS, 1 = MIPI*/ @@ -176,10 +176,10 @@ struct mrst_gct_v1 { }; struct mrst_panel_descriptor_v1 panel[4];/*panel descrs,38 bytes each*/ union mrst_panel_rx panelrx[4]; /* panel receivers*/ -} __attribute__ ((packed)); +} __packed; struct mrst_gct_v2 { - union{ /*8 bits,Defined as follows: */ + union { /*8 bits,Defined as follows: */ struct { u8 PanelType:4; /*4 bits, Bit field for panels*/ /* 0 - 3: 0 = LVDS, 1 = MIPI*/ @@ -193,7 +193,7 @@ struct mrst_gct_v2 { }; struct mrst_panel_descriptor_v2 panel[4];/*panel descrs,38 bytes each*/ union mrst_panel_rx panelrx[4]; /* panel receivers*/ -} __attribute__ ((packed)); +} __packed; struct mrst_gct_data { u8 bpi; /* boot panel index, number of panel used during boot */ @@ -205,13 +205,48 @@ struct mrst_gct_data { u32 PP_Cycle_Delay; u16 Panel_Backlight_Inverter_Descriptor; u16 Panel_MIPI_Display_Descriptor; -} __attribute__ ((packed)); - -#define MODE_SETTING_IN_CRTC 0x1 -#define MODE_SETTING_IN_ENCODER 0x2 -#define MODE_SETTING_ON_GOING 0x3 -#define MODE_SETTING_IN_DSR 0x4 -#define MODE_SETTING_ENCODER_DONE 0x8 -#define GCT_R10_HEADER_SIZE 16 +} __packed; + +#define MODE_SETTING_IN_CRTC 0x1 +#define MODE_SETTING_IN_ENCODER 0x2 +#define MODE_SETTING_ON_GOING 0x3 +#define MODE_SETTING_IN_DSR 0x4 +#define MODE_SETTING_ENCODER_DONE 0x8 + +#define GCT_R10_HEADER_SIZE 16 #define GCT_R10_DISPLAY_DESC_SIZE 28 +/* + * Moorestown HDMI interfaces + */ + +struct mrst_hdmi_dev { + struct pci_dev *dev; + void __iomem *regs; + unsigned int mmio, mmio_len; + int dpms_mode; + struct hdmi_i2c_dev *i2c_dev; + + /* register state */ + u32 saveDPLL_CTRL; + u32 saveDPLL_DIV_CTRL; + u32 saveDPLL_ADJUST; + u32 saveDPLL_UPDATE; + u32 saveDPLL_CLK_ENABLE; + u32 savePCH_HTOTAL_B; + u32 savePCH_HBLANK_B; + u32 savePCH_HSYNC_B; + u32 savePCH_VTOTAL_B; + u32 savePCH_VBLANK_B; + u32 savePCH_VSYNC_B; + u32 savePCH_PIPEBCONF; + u32 savePCH_PIPEBSRC; +}; + +extern void mrst_hdmi_setup(struct drm_device *dev); +extern void mrst_hdmi_teardown(struct drm_device *dev); +extern int mrst_hdmi_i2c_init(struct pci_dev *dev); +extern void mrst_hdmi_i2c_exit(struct pci_dev *dev); +extern void mrst_hdmi_save(struct drm_device *dev); +extern void mrst_hdmi_restore(struct drm_device *dev); +extern void mrst_hdmi_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev); diff --git a/drivers/staging/gma500/mrst_crtc.c b/drivers/staging/gma500/mrst_crtc.c index e4a0c03..72464dd 100644 --- a/drivers/staging/gma500/mrst_crtc.c +++ b/drivers/staging/gma500/mrst_crtc.c @@ -19,12 +19,12 @@ #include <linux/pm_runtime.h> #include <drm/drmP.h> -#include "psb_fb.h" +#include "framebuffer.h" #include "psb_drv.h" #include "psb_intel_drv.h" #include "psb_intel_reg.h" #include "psb_intel_display.h" -#include "psb_powermgmt.h" +#include "power.h" struct psb_intel_range_t { int min, max; @@ -86,7 +86,7 @@ static const struct mrst_limit_t *mrst_limit(struct drm_crtc *crtc) { const struct mrst_limit_t *limit = NULL; struct drm_device *dev = crtc->dev; - DRM_DRIVER_PRIVATE_T *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = dev->dev_private; if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_MIPI)) { @@ -103,7 +103,7 @@ static const struct mrst_limit_t *mrst_limit(struct drm_crtc *crtc) } } else { limit = NULL; - PSB_DEBUG_ENTRY("mrst_limit Wrong display type.\n"); + dev_err(dev->dev, "mrst_limit Wrong display type.\n"); } return limit; @@ -117,7 +117,7 @@ static void mrst_clock(int refclk, struct mrst_clock_t *clock) void mrstPrintPll(char *prefix, struct mrst_clock_t *clock) { - PSB_DEBUG_ENTRY("%s: dotclock = %d, m = %d, p1 = %d.\n", + pr_debug("%s: dotclock = %d, m = %d, p1 = %d.\n", prefix, clock->dot, clock->m, clock->p1); } @@ -149,8 +149,7 @@ mrstFindBestPLL(struct drm_crtc *crtc, int target, int refclk, } } } - DRM_DEBUG("mrstFindBestPLL err = %d.\n", err); - + dev_dbg(crtc->dev->dev, "mrstFindBestPLL err = %d.\n", err); return err != target; } @@ -172,8 +171,6 @@ static void mrst_crtc_dpms(struct drm_crtc *crtc, int mode) u32 temp; bool enabled; - PSB_DEBUG_ENTRY("mode = %d, pipe = %d\n", mode, pipe); - if (!gma_power_begin(dev, true)) return; @@ -296,7 +293,7 @@ static int mrst_crtc_mode_set(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); - DRM_DRIVER_PRIVATE_T *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = dev->dev_private; int pipe = psb_intel_crtc->pipe; int fp_reg = (pipe == 0) ? MRST_FPA0 : FPB0; int dpll_reg = (pipe == 0) ? MRST_DPLL_A : DPLL_B; @@ -320,8 +317,6 @@ static int mrst_crtc_mode_set(struct drm_crtc *crtc, uint64_t scalingType = DRM_MODE_SCALE_FULLSCREEN; struct drm_encoder *encoder; - PSB_DEBUG_ENTRY("pipe = 0x%x\n", pipe); - if (!gma_power_begin(dev, true)) return 0; @@ -446,10 +441,9 @@ static int mrst_crtc_mode_set(struct drm_crtc *crtc, ok = mrstFindBestPLL(crtc, adjusted_mode->clock, refclk, &clock); if (!ok) { - PSB_DEBUG_ENTRY( - "mrstFindBestPLL fail in mrst_crtc_mode_set.\n"); + dev_dbg(dev->dev, "mrstFindBestPLL fail in mrst_crtc_mode_set.\n"); } else { - PSB_DEBUG_ENTRY("mrst_crtc_mode_set pixel clock = %d," + dev_dbg(dev->dev, "mrst_crtc_mode_set pixel clock = %d," "m = %x, p1 = %x.\n", clock.dot, clock.m, clock.p1); } @@ -540,11 +534,9 @@ int mrst_pipe_set_base(struct drm_crtc *crtc, u32 dspcntr; int ret = 0; - PSB_DEBUG_ENTRY("\n"); - /* no fb bound */ if (!crtc->fb) { - DRM_DEBUG("No FB bound\n"); + dev_dbg(dev->dev, "No FB bound\n"); return 0; } @@ -574,13 +566,12 @@ int mrst_pipe_set_base(struct drm_crtc *crtc, dspcntr |= DISPPLANE_32BPP_NO_ALPHA; break; default: - DRM_ERROR("Unknown color depth\n"); + dev_err(dev->dev, "Unknown color depth\n"); ret = -EINVAL; goto pipe_set_base_exit; } REG_WRITE(dspcntr_reg, dspcntr); - DRM_DEBUG("Writing base %08lX %08lX %d %d\n", start, offset, x, y); if (0 /* FIXMEAC - check what PSB needs */) { REG_WRITE(dspbase, offset); REG_READ(dspbase); diff --git a/drivers/staging/gma500/mrst_device.c b/drivers/staging/gma500/mrst_device.c new file mode 100644 index 0000000..6707faf --- /dev/null +++ b/drivers/staging/gma500/mrst_device.c @@ -0,0 +1,634 @@ +/************************************************************************** + * Copyright (c) 2011, Intel Corporation. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + **************************************************************************/ + +#include <linux/backlight.h> +#include <linux/module.h> +#include <linux/dmi.h> +#include <drm/drmP.h> +#include <drm/drm.h> +#include "psb_drm.h" +#include "psb_drv.h" +#include "psb_reg.h" +#include "psb_intel_reg.h" +#include <asm/mrst.h> +#include <asm/intel_scu_ipc.h> +#include "mid_bios.h" + +static int devtype; + +module_param_named(type, devtype, int, 0600); +MODULE_PARM_DESC(type, "Moorestown/Oaktrail device type"); + +#define DEVICE_MOORESTOWN 1 +#define DEVICE_OAKTRAIL 2 +#define DEVICE_MOORESTOWN_MM 3 + +static int mrst_device_ident(struct drm_device *dev) +{ + /* User forced */ + if (devtype) + return devtype; + if (dmi_match(DMI_PRODUCT_NAME, "OakTrail") || + dmi_match(DMI_PRODUCT_NAME, "OakTrail platform")) + return DEVICE_OAKTRAIL; +#if defined(CONFIG_X86_MRST) + if (dmi_match(DMI_PRODUCT_NAME, "MM") || + dmi_match(DMI_PRODUCT_NAME, "MM 10")) + return DEVICE_MOORESTOWN_MM; + if (mrst_identify_cpu()) + return DEVICE_MOORESTOWN; +#endif + return DEVICE_OAKTRAIL; +} + + +/* IPC message and command defines used to enable/disable mipi panel voltages */ +#define IPC_MSG_PANEL_ON_OFF 0xE9 +#define IPC_CMD_PANEL_ON 1 +#define IPC_CMD_PANEL_OFF 0 + +static int mrst_output_init(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + if (dev_priv->iLVDS_enable) + mrst_lvds_init(dev, &dev_priv->mode_dev); + else + dev_err(dev->dev, "DSI is not supported\n"); + if (dev_priv->hdmi_priv) + mrst_hdmi_init(dev, &dev_priv->mode_dev); + return 0; +} + +/* + * Provide the low level interfaces for the Moorestown backlight + */ + +#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 BLC_ADJUSTMENT_MAX 100 + +static struct backlight_device *mrst_backlight_device; +static int mrst_brightness; + +static int mrst_set_brightness(struct backlight_device *bd) +{ + struct drm_device *dev = bl_get_data(mrst_backlight_device); + struct drm_psb_private *dev_priv = dev->dev_private; + int level = bd->props.brightness; + u32 blc_pwm_ctl; + u32 max_pwm_blc; + + /* Percentage 1-100% being valid */ + if (level < 1) + level = 1; + + if (gma_power_begin(dev, 0)) { + /* Calculate and set the brightness value */ + max_pwm_blc = REG_READ(BLC_PWM_CTL) >> 16; + blc_pwm_ctl = level * max_pwm_blc / 100; + + /* Adjust the backlight level with the percent in + * dev_priv->blc_adj1; + */ + blc_pwm_ctl = blc_pwm_ctl * dev_priv->blc_adj1; + blc_pwm_ctl = blc_pwm_ctl / 100; + + /* Adjust the backlight level with the percent in + * dev_priv->blc_adj2; + */ + blc_pwm_ctl = blc_pwm_ctl * dev_priv->blc_adj2; + blc_pwm_ctl = blc_pwm_ctl / 100; + + /* force PWM bit on */ + REG_WRITE(BLC_PWM_CTL2, (0x80000000 | REG_READ(BLC_PWM_CTL2))); + REG_WRITE(BLC_PWM_CTL, (max_pwm_blc << 16) | blc_pwm_ctl); + gma_power_end(dev); + } + mrst_brightness = level; + return 0; +} + +static int mrst_get_brightness(struct backlight_device *bd) +{ + /* return locally cached var instead of HW read (due to DPST etc.) */ + /* FIXME: ideally return actual value in case firmware fiddled with + it */ + return mrst_brightness; +} + +static int device_backlight_init(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + unsigned long core_clock; + u16 bl_max_freq; + uint32_t value; + uint32_t blc_pwm_precision_factor; + + dev_priv->blc_adj1 = BLC_ADJUSTMENT_MAX; + dev_priv->blc_adj2 = BLC_ADJUSTMENT_MAX; + bl_max_freq = 256; + /* this needs to be set elsewhere */ + blc_pwm_precision_factor = BLC_PWM_PRECISION_FACTOR; + + core_clock = dev_priv->core_freq; + + value = (core_clock * MHz) / BLC_PWM_FREQ_CALC_CONSTANT; + value *= blc_pwm_precision_factor; + value /= bl_max_freq; + value /= blc_pwm_precision_factor; + + if (value > (unsigned long long)MRST_BLC_MAX_PWM_REG_FREQ) + return -ERANGE; + + if (gma_power_begin(dev, false)) { + REG_WRITE(BLC_PWM_CTL2, (0x80000000 | REG_READ(BLC_PWM_CTL2))); + REG_WRITE(BLC_PWM_CTL, value | (value << 16)); + gma_power_end(dev); + } + return 0; +} + +static const struct backlight_ops mrst_ops = { + .get_brightness = mrst_get_brightness, + .update_status = mrst_set_brightness, +}; + +int mrst_backlight_init(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + int ret; + struct backlight_properties props; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = 100; + props.type = BACKLIGHT_PLATFORM; + + mrst_backlight_device = backlight_device_register("mrst-bl", + NULL, (void *)dev, &mrst_ops, &props); + + if (IS_ERR(mrst_backlight_device)) + return PTR_ERR(mrst_backlight_device); + + ret = device_backlight_init(dev); + if (ret < 0) { + backlight_device_unregister(mrst_backlight_device); + return ret; + } + mrst_backlight_device->props.brightness = 100; + mrst_backlight_device->props.max_brightness = 100; + backlight_update_status(mrst_backlight_device); + dev_priv->backlight_device = mrst_backlight_device; + return 0; +} + +#endif + +/* + * Provide the Moorestown specific chip logic and low level methods + * for power management + */ + +static void mrst_init_pm(struct drm_device *dev) +{ +} + +/** + * mrst_save_display_registers - save registers lost on suspend + * @dev: our DRM device + * + * Save the state we need in order to be able to restore the interface + * upon resume from suspend + */ +static int mrst_save_display_registers(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + int i; + u32 pp_stat; + + /* 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); + + /* Pipe & plane A info */ + dev_priv->savePIPEACONF = PSB_RVDC32(PIPEACONF); + dev_priv->savePIPEASRC = PSB_RVDC32(PIPEASRC); + dev_priv->saveFPA0 = PSB_RVDC32(MRST_FPA0); + dev_priv->saveFPA1 = PSB_RVDC32(MRST_FPA1); + dev_priv->saveDPLL_A = PSB_RVDC32(MRST_DPLL_A); + dev_priv->saveHTOTAL_A = PSB_RVDC32(HTOTAL_A); + dev_priv->saveHBLANK_A = PSB_RVDC32(HBLANK_A); + dev_priv->saveHSYNC_A = PSB_RVDC32(HSYNC_A); + dev_priv->saveVTOTAL_A = PSB_RVDC32(VTOTAL_A); + dev_priv->saveVBLANK_A = PSB_RVDC32(VBLANK_A); + dev_priv->saveVSYNC_A = PSB_RVDC32(VSYNC_A); + dev_priv->saveBCLRPAT_A = PSB_RVDC32(BCLRPAT_A); + dev_priv->saveDSPACNTR = PSB_RVDC32(DSPACNTR); + dev_priv->saveDSPASTRIDE = PSB_RVDC32(DSPASTRIDE); + dev_priv->saveDSPAADDR = PSB_RVDC32(DSPABASE); + dev_priv->saveDSPASURF = PSB_RVDC32(DSPASURF); + dev_priv->saveDSPALINOFF = PSB_RVDC32(DSPALINOFF); + dev_priv->saveDSPATILEOFF = PSB_RVDC32(DSPATILEOFF); + + /* Save cursor regs */ + dev_priv->saveDSPACURSOR_CTRL = PSB_RVDC32(CURACNTR); + dev_priv->saveDSPACURSOR_BASE = PSB_RVDC32(CURABASE); + dev_priv->saveDSPACURSOR_POS = PSB_RVDC32(CURAPOS); + + /* Save palette (gamma) */ + for (i = 0; i < 256; i++) + dev_priv->save_palette_a[i] = PSB_RVDC32(PALETTE_A + (i << 2)); + + if (dev_priv->hdmi_priv) + mrst_hdmi_save(dev); + + /* Save performance state */ + dev_priv->savePERF_MODE = PSB_RVDC32(MRST_PERF_MODE); + + /* LVDS state */ + dev_priv->savePP_CONTROL = PSB_RVDC32(PP_CONTROL); + dev_priv->savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS); + dev_priv->savePFIT_AUTO_RATIOS = PSB_RVDC32(PFIT_AUTO_RATIOS); + dev_priv->saveBLC_PWM_CTL = PSB_RVDC32(BLC_PWM_CTL); + dev_priv->saveBLC_PWM_CTL2 = PSB_RVDC32(BLC_PWM_CTL2); + dev_priv->saveLVDS = PSB_RVDC32(LVDS); + dev_priv->savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL); + dev_priv->savePP_ON_DELAYS = PSB_RVDC32(LVDSPP_ON); + dev_priv->savePP_OFF_DELAYS = PSB_RVDC32(LVDSPP_OFF); + dev_priv->savePP_DIVISOR = PSB_RVDC32(PP_CYCLE); + + /* HW overlay */ + dev_priv->saveOV_OVADD = PSB_RVDC32(OV_OVADD); + dev_priv->saveOV_OGAMC0 = PSB_RVDC32(OV_OGAMC0); + dev_priv->saveOV_OGAMC1 = PSB_RVDC32(OV_OGAMC1); + dev_priv->saveOV_OGAMC2 = PSB_RVDC32(OV_OGAMC2); + dev_priv->saveOV_OGAMC3 = PSB_RVDC32(OV_OGAMC3); + dev_priv->saveOV_OGAMC4 = PSB_RVDC32(OV_OGAMC4); + dev_priv->saveOV_OGAMC5 = PSB_RVDC32(OV_OGAMC5); + + /* DPST registers */ + dev_priv->saveHISTOGRAM_INT_CONTROL_REG = + PSB_RVDC32(HISTOGRAM_INT_CONTROL); + dev_priv->saveHISTOGRAM_LOGIC_CONTROL_REG = + PSB_RVDC32(HISTOGRAM_LOGIC_CONTROL); + dev_priv->savePWM_CONTROL_LOGIC = PSB_RVDC32(PWM_CONTROL_LOGIC); + + if (dev_priv->iLVDS_enable) { + /* Shut down 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); + /* Trigger the plane disable */ + PSB_WVDC32(0, DSPASURF); + + /* 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); + } + return 0; +} + +/** + * mrst_restore_display_registers - restore lost register state + * @dev: our DRM device + * + * Restore register state that was lost during suspend and resume. + */ +static int mrst_restore_display_registers(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + u32 pp_stat; + int i; + + /* 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); + + /* set the plls */ + PSB_WVDC32(dev_priv->saveFPA0, MRST_FPA0); + PSB_WVDC32(dev_priv->saveFPA1, MRST_FPA1); + + /* Actually enable it */ + PSB_WVDC32(dev_priv->saveDPLL_A, MRST_DPLL_A); + DRM_UDELAY(150); + + /* Restore mode */ + PSB_WVDC32(dev_priv->saveHTOTAL_A, HTOTAL_A); + PSB_WVDC32(dev_priv->saveHBLANK_A, HBLANK_A); + PSB_WVDC32(dev_priv->saveHSYNC_A, HSYNC_A); + PSB_WVDC32(dev_priv->saveVTOTAL_A, VTOTAL_A); + PSB_WVDC32(dev_priv->saveVBLANK_A, VBLANK_A); + PSB_WVDC32(dev_priv->saveVSYNC_A, VSYNC_A); + PSB_WVDC32(dev_priv->savePIPEASRC, PIPEASRC); + PSB_WVDC32(dev_priv->saveBCLRPAT_A, BCLRPAT_A); + + /* Restore performance mode*/ + PSB_WVDC32(dev_priv->savePERF_MODE, MRST_PERF_MODE); + + /* Enable the pipe*/ + if (dev_priv->iLVDS_enable) + PSB_WVDC32(dev_priv->savePIPEACONF, PIPEACONF); + + /* Set up the plane*/ + PSB_WVDC32(dev_priv->saveDSPALINOFF, DSPALINOFF); + PSB_WVDC32(dev_priv->saveDSPASTRIDE, DSPASTRIDE); + PSB_WVDC32(dev_priv->saveDSPATILEOFF, DSPATILEOFF); + + /* Enable the plane */ + PSB_WVDC32(dev_priv->saveDSPACNTR, DSPACNTR); + PSB_WVDC32(dev_priv->saveDSPASURF, DSPASURF); + + /* Enable Cursor A */ + PSB_WVDC32(dev_priv->saveDSPACURSOR_CTRL, CURACNTR); + PSB_WVDC32(dev_priv->saveDSPACURSOR_POS, CURAPOS); + PSB_WVDC32(dev_priv->saveDSPACURSOR_BASE, CURABASE); + + /* Restore palette (gamma) */ + for (i = 0; i < 256; i++) + PSB_WVDC32(dev_priv->save_palette_a[i], PALETTE_A + (i << 2)); + + if (dev_priv->hdmi_priv) + mrst_hdmi_restore(dev); + + if (dev_priv->iLVDS_enable) { + PSB_WVDC32(dev_priv->saveBLC_PWM_CTL2, BLC_PWM_CTL2); + PSB_WVDC32(dev_priv->saveLVDS, LVDS); /*port 61180h*/ + PSB_WVDC32(dev_priv->savePFIT_CONTROL, PFIT_CONTROL); + PSB_WVDC32(dev_priv->savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS); + PSB_WVDC32(dev_priv->savePFIT_AUTO_RATIOS, PFIT_AUTO_RATIOS); + PSB_WVDC32(dev_priv->saveBLC_PWM_CTL, BLC_PWM_CTL); + PSB_WVDC32(dev_priv->savePP_ON_DELAYS, LVDSPP_ON); + PSB_WVDC32(dev_priv->savePP_OFF_DELAYS, LVDSPP_OFF); + PSB_WVDC32(dev_priv->savePP_DIVISOR, PP_CYCLE); + PSB_WVDC32(dev_priv->savePP_CONTROL, PP_CONTROL); + } + + /* Wait for cycle delay */ + do { + pp_stat = PSB_RVDC32(PP_STATUS); + } while (pp_stat & 0x08000000); + + /* Wait for panel power up */ + do { + pp_stat = PSB_RVDC32(PP_STATUS); + } while (pp_stat & 0x10000000); + + /* Restore HW overlay */ + PSB_WVDC32(dev_priv->saveOV_OVADD, OV_OVADD); + PSB_WVDC32(dev_priv->saveOV_OGAMC0, OV_OGAMC0); + PSB_WVDC32(dev_priv->saveOV_OGAMC1, OV_OGAMC1); + PSB_WVDC32(dev_priv->saveOV_OGAMC2, OV_OGAMC2); + PSB_WVDC32(dev_priv->saveOV_OGAMC3, OV_OGAMC3); + PSB_WVDC32(dev_priv->saveOV_OGAMC4, OV_OGAMC4); + PSB_WVDC32(dev_priv->saveOV_OGAMC5, OV_OGAMC5); + + /* DPST registers */ + PSB_WVDC32(dev_priv->saveHISTOGRAM_INT_CONTROL_REG, + HISTOGRAM_INT_CONTROL); + PSB_WVDC32(dev_priv->saveHISTOGRAM_LOGIC_CONTROL_REG, + HISTOGRAM_LOGIC_CONTROL); + PSB_WVDC32(dev_priv->savePWM_CONTROL_LOGIC, PWM_CONTROL_LOGIC); + + return 0; +} + +/** + * mrst_power_down - power down the display island + * @dev: our DRM device + * + * Power down the display interface of our device + */ +static int mrst_power_down(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + u32 pwr_mask ; + u32 pwr_sts; + + pwr_mask = PSB_PWRGT_DISPLAY_MASK; + outl(pwr_mask, dev_priv->ospm_base + PSB_PM_SSC); + + while (true) { + pwr_sts = inl(dev_priv->ospm_base + PSB_PM_SSS); + if ((pwr_sts & pwr_mask) == pwr_mask) + break; + else + udelay(10); + } + return 0; +} + +/* + * mrst_power_up + * + * Restore power to the specified island(s) (powergating) + */ +static int mrst_power_up(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + u32 pwr_mask = PSB_PWRGT_DISPLAY_MASK; + u32 pwr_sts, pwr_cnt; + + pwr_cnt = inl(dev_priv->ospm_base + PSB_PM_SSC); + pwr_cnt &= ~pwr_mask; + outl(pwr_cnt, (dev_priv->ospm_base + PSB_PM_SSC)); + + while (true) { + pwr_sts = inl(dev_priv->ospm_base + PSB_PM_SSS); + if ((pwr_sts & pwr_mask) == 0) + break; + else + udelay(10); + } + return 0; +} + +#if defined(CONFIG_X86_MRST) +static void mrst_lvds_cache_bl(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + + intel_scu_ipc_ioread8(0x28, &(dev_priv->saveBKLTCNT)); + intel_scu_ipc_ioread8(0x29, &(dev_priv->saveBKLTREQ)); + intel_scu_ipc_ioread8(0x2A, &(dev_priv->saveBKLTBRTL)); +} + +static void mrst_mm_bl_power(struct drm_device *dev, bool on) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + + if (on) { + intel_scu_ipc_iowrite8(0x2A, dev_priv->saveBKLTBRTL); + intel_scu_ipc_iowrite8(0x28, dev_priv->saveBKLTCNT); + intel_scu_ipc_iowrite8(0x29, dev_priv->saveBKLTREQ); + } else { + intel_scu_ipc_iowrite8(0x2A, 0); + intel_scu_ipc_iowrite8(0x28, 0); + intel_scu_ipc_iowrite8(0x29, 0); + } +} + +static const struct psb_ops mrst_mm_chip_ops = { + .name = "Moorestown MM ", + .accel_2d = 1, + .pipes = 1, + .crtcs = 1, + .sgx_offset = MRST_SGX_OFFSET, + + .crtc_helper = &mrst_helper_funcs, + .crtc_funcs = &psb_intel_crtc_funcs, + + .output_init = mrst_output_init, + + .lvds_bl_power = mrst_mm_bl_power, +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + .backlight_init = mrst_backlight_init, +#endif + + .init_pm = mrst_init_pm, + .save_regs = mrst_save_display_registers, + .restore_regs = mrst_restore_display_registers, + .power_down = mrst_power_down, + .power_up = mrst_power_up, + + .i2c_bus = 0, +}; + +#endif + +static void oaktrail_teardown(struct drm_device *dev) +{ + mrst_hdmi_teardown(dev); +} + +static const struct psb_ops oaktrail_chip_ops = { + .name = "Oaktrail", + .accel_2d = 1, + .pipes = 2, + .crtcs = 2, + .sgx_offset = MRST_SGX_OFFSET, + + .chip_setup = mid_chip_setup, + .chip_teardown = oaktrail_teardown, + .crtc_helper = &mrst_helper_funcs, + .crtc_funcs = &psb_intel_crtc_funcs, + + .output_init = mrst_output_init, + +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + .backlight_init = mrst_backlight_init, +#endif + + .init_pm = mrst_init_pm, + .save_regs = mrst_save_display_registers, + .restore_regs = mrst_restore_display_registers, + .power_down = mrst_power_down, + .power_up = mrst_power_up, + + .i2c_bus = 1, +}; + +/** + * mrst_chip_setup - perform the initial chip init + * @dev: Our drm_device + * + * Figure out which incarnation we are and then scan the firmware for + * tables and information. + */ +static int mrst_chip_setup(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + + switch (mrst_device_ident(dev)) { + case DEVICE_OAKTRAIL: + /* Dual CRTC, PC compatible, HDMI, I2C #2 */ + dev_priv->ops = &oaktrail_chip_ops; + mrst_hdmi_setup(dev); + return mid_chip_setup(dev); +#if defined(CONFIG_X86_MRST) + case DEVICE_MOORESTOWN_MM: + /* Single CRTC, No HDMI, I2C #0, BL control */ + mrst_lvds_cache_bl(dev); + dev_priv->ops = &mrst_mm_chip_ops; + return mid_chip_setup(dev); + case DEVICE_MOORESTOWN: + /* Dual CRTC, No HDMI(?), I2C #1 */ + return mid_chip_setup(dev); +#endif + default: + dev_err(dev->dev, "unsupported device type.\n"); + return -ENODEV; + } +} + +const struct psb_ops mrst_chip_ops = { + .name = "Moorestown", + .accel_2d = 1, + .pipes = 2, + .crtcs = 2, + .sgx_offset = MRST_SGX_OFFSET, + + .chip_setup = mrst_chip_setup, + .crtc_helper = &mrst_helper_funcs, + .crtc_funcs = &psb_intel_crtc_funcs, + + .output_init = mrst_output_init, + +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + .backlight_init = mrst_backlight_init, +#endif + + .init_pm = mrst_init_pm, + .save_regs = mrst_save_display_registers, + .restore_regs = mrst_restore_display_registers, + .power_down = mrst_power_down, + .power_up = mrst_power_up, + + .i2c_bus = 2, +}; + diff --git a/drivers/staging/gma500/mrst_hdmi.c b/drivers/staging/gma500/mrst_hdmi.c new file mode 100644 index 0000000..d6a5179 --- /dev/null +++ b/drivers/staging/gma500/mrst_hdmi.c @@ -0,0 +1,852 @@ +/* + * 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: + * Li Peng <peng.li@intel.com> + */ + +#include <drm/drmP.h> +#include <drm/drm.h> +#include "psb_intel_drv.h" +#include "psb_intel_reg.h" +#include "psb_drv.h" + +#define HDMI_READ(reg) readl(hdmi_dev->regs + (reg)) +#define HDMI_WRITE(reg, val) writel(val, hdmi_dev->regs + (reg)) + +#define HDMI_HCR 0x1000 +#define HCR_ENABLE_HDCP (1 << 5) +#define HCR_ENABLE_AUDIO (1 << 2) +#define HCR_ENABLE_PIXEL (1 << 1) +#define HCR_ENABLE_TMDS (1 << 0) + +#define HDMI_HICR 0x1004 +#define HDMI_HSR 0x1008 +#define HDMI_HISR 0x100C +#define HDMI_DETECT_HDP (1 << 0) + +#define HDMI_VIDEO_REG 0x3000 +#define HDMI_UNIT_EN (1 << 7) +#define HDMI_MODE_OUTPUT (1 << 0) +#define HDMI_HBLANK_A 0x3100 + +#define HDMI_AUDIO_CTRL 0x4000 +#define HDMI_ENABLE_AUDIO (1 << 0) + +#define PCH_HTOTAL_B 0x3100 +#define PCH_HBLANK_B 0x3104 +#define PCH_HSYNC_B 0x3108 +#define PCH_VTOTAL_B 0x310C +#define PCH_VBLANK_B 0x3110 +#define PCH_VSYNC_B 0x3114 +#define PCH_PIPEBSRC 0x311C + +#define PCH_PIPEB_DSL 0x3800 +#define PCH_PIPEB_SLC 0x3804 +#define PCH_PIPEBCONF 0x3808 +#define PCH_PIPEBSTAT 0x3824 + +#define CDVO_DFT 0x5000 +#define CDVO_SLEWRATE 0x5004 +#define CDVO_STRENGTH 0x5008 +#define CDVO_RCOMP 0x500C + +#define DPLL_CTRL 0x6000 +#define DPLL_PDIV_SHIFT 16 +#define DPLL_PDIV_MASK (0xf << 16) +#define DPLL_PWRDN (1 << 4) +#define DPLL_RESET (1 << 3) +#define DPLL_FASTEN (1 << 2) +#define DPLL_ENSTAT (1 << 1) +#define DPLL_DITHEN (1 << 0) + +#define DPLL_DIV_CTRL 0x6004 +#define DPLL_CLKF_MASK 0xffffffc0 +#define DPLL_CLKR_MASK (0x3f) + +#define DPLL_CLK_ENABLE 0x6008 +#define DPLL_EN_DISP (1 << 31) +#define DPLL_SEL_HDMI (1 << 8) +#define DPLL_EN_HDMI (1 << 1) +#define DPLL_EN_VGA (1 << 0) + +#define DPLL_ADJUST 0x600C +#define DPLL_STATUS 0x6010 +#define DPLL_UPDATE 0x6014 +#define DPLL_DFT 0x6020 + +struct intel_range { + int min, max; +}; + +struct mrst_hdmi_limit { + struct intel_range vco, np, nr, nf; +}; + +struct mrst_hdmi_clock { + int np; + int nr; + int nf; + int dot; +}; + +#define VCO_MIN 320000 +#define VCO_MAX 1650000 +#define NP_MIN 1 +#define NP_MAX 15 +#define NR_MIN 1 +#define NR_MAX 64 +#define NF_MIN 2 +#define NF_MAX 4095 + +static const struct mrst_hdmi_limit mrst_hdmi_limit = { + .vco = { .min = VCO_MIN, .max = VCO_MAX }, + .np = { .min = NP_MIN, .max = NP_MAX }, + .nr = { .min = NR_MIN, .max = NR_MAX }, + .nf = { .min = NF_MIN, .max = NF_MAX }, +}; + +static void wait_for_vblank(struct drm_device *dev) +{ + /* FIXME: Can we do this as a sleep ? */ + /* Wait for 20ms, i.e. one cycle at 50hz. */ + udelay(20000); +} + +static void scu_busy_loop(void *scu_base) +{ + u32 status = 0; + u32 loop_count = 0; + + status = readl(scu_base + 0x04); + while (status & 1) { + udelay(1); /* scu processing time is in few u secods */ + status = readl(scu_base + 0x04); + loop_count++; + /* break if scu doesn't reset busy bit after huge retry */ + if (loop_count > 1000) { + DRM_DEBUG_KMS("SCU IPC timed out"); + return; + } + } +} + +static void mrst_hdmi_reset(struct drm_device *dev) +{ + void *base; + /* FIXME: at least make these defines */ + unsigned int scu_ipc_mmio = 0xff11c000; + int scu_len = 1024; + + base = ioremap((resource_size_t)scu_ipc_mmio, scu_len); + if (base == NULL) { + DRM_ERROR("failed to map SCU mmio\n"); + return; + } + + /* scu ipc: assert hdmi controller reset */ + writel(0xff11d118, base + 0x0c); + writel(0x7fffffdf, base + 0x80); + writel(0x42005, base + 0x0); + scu_busy_loop(base); + + /* scu ipc: de-assert hdmi controller reset */ + writel(0xff11d118, base + 0x0c); + writel(0x7fffffff, base + 0x80); + writel(0x42005, base + 0x0); + scu_busy_loop(base); + + iounmap(base); +} + +static void mrst_hdmi_audio_enable(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct mrst_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; + + HDMI_WRITE(HDMI_HCR, 0x67); + HDMI_READ(HDMI_HCR); + + HDMI_WRITE(0x51a8, 0x10); + HDMI_READ(0x51a8); + + HDMI_WRITE(HDMI_AUDIO_CTRL, 0x1); + HDMI_READ(HDMI_AUDIO_CTRL); +} + +static void mrst_hdmi_audio_disable(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct mrst_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; + + HDMI_WRITE(0x51a8, 0x0); + HDMI_READ(0x51a8); + + HDMI_WRITE(HDMI_AUDIO_CTRL, 0x0); + HDMI_READ(HDMI_AUDIO_CTRL); + + HDMI_WRITE(HDMI_HCR, 0x47); + HDMI_READ(HDMI_HCR); +} + +void mrst_crtc_hdmi_dpms(struct drm_crtc *crtc, int mode) +{ + struct drm_device *dev = crtc->dev; + u32 temp; + + switch (mode) { + case DRM_MODE_DPMS_OFF: + /* Disable VGACNTRL */ + REG_WRITE(VGACNTRL, 0x80000000); + + /* Disable plane */ + temp = REG_READ(DSPBCNTR); + if ((temp & DISPLAY_PLANE_ENABLE) != 0) { + REG_WRITE(DSPBCNTR, temp & ~DISPLAY_PLANE_ENABLE); + REG_READ(DSPBCNTR); + /* Flush the plane changes */ + REG_WRITE(DSPBSURF, REG_READ(DSPBSURF)); + REG_READ(DSPBSURF); + } + + /* Disable pipe B */ + temp = REG_READ(PIPEBCONF); + if ((temp & PIPEACONF_ENABLE) != 0) { + REG_WRITE(PIPEBCONF, temp & ~PIPEACONF_ENABLE); + REG_READ(PIPEBCONF); + } + + /* Disable LNW Pipes, etc */ + temp = REG_READ(PCH_PIPEBCONF); + if ((temp & PIPEACONF_ENABLE) != 0) { + REG_WRITE(PCH_PIPEBCONF, temp & ~PIPEACONF_ENABLE); + REG_READ(PCH_PIPEBCONF); + } + /* wait for pipe off */ + udelay(150); + /* Disable dpll */ + temp = REG_READ(DPLL_CTRL); + if ((temp & DPLL_PWRDN) == 0) { + REG_WRITE(DPLL_CTRL, temp | (DPLL_PWRDN | DPLL_RESET)); + REG_WRITE(DPLL_STATUS, 0x1); + } + /* wait for dpll off */ + udelay(150); + break; + case DRM_MODE_DPMS_ON: + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + /* Enable dpll */ + temp = REG_READ(DPLL_CTRL); + if ((temp & DPLL_PWRDN) != 0) { + REG_WRITE(DPLL_CTRL, temp & ~(DPLL_PWRDN | DPLL_RESET)); + temp = REG_READ(DPLL_CLK_ENABLE); + REG_WRITE(DPLL_CLK_ENABLE, temp | DPLL_EN_DISP | DPLL_SEL_HDMI | DPLL_EN_HDMI); + REG_READ(DPLL_CLK_ENABLE); + } + /* wait for dpll warm up */ + udelay(150); + + /* Enable pipe B */ + temp = REG_READ(PIPEBCONF); + if ((temp & PIPEACONF_ENABLE) == 0) { + REG_WRITE(PIPEBCONF, temp | PIPEACONF_ENABLE); + REG_READ(PIPEBCONF); + } + + /* Enable LNW Pipe B */ + temp = REG_READ(PCH_PIPEBCONF); + if ((temp & PIPEACONF_ENABLE) == 0) { + REG_WRITE(PCH_PIPEBCONF, temp | PIPEACONF_ENABLE); + REG_READ(PCH_PIPEBCONF); + } + wait_for_vblank(dev); + + /* Enable plane */ + temp = REG_READ(DSPBCNTR); + if ((temp & DISPLAY_PLANE_ENABLE) == 0) { + REG_WRITE(DSPBCNTR, temp | DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + REG_WRITE(DSPBSURF, REG_READ(DSPBSURF)); + REG_READ(DSPBSURF); + } + psb_intel_crtc_load_lut(crtc); + } + /* DSPARB */ + REG_WRITE(DSPARB, 0x00003fbf); + /* FW1 */ + REG_WRITE(0x70034, 0x3f880a0a); + /* FW2 */ + REG_WRITE(0x70038, 0x0b060808); + /* FW4 */ + REG_WRITE(0x70050, 0x08030404); + /* FW5 */ + REG_WRITE(0x70054, 0x04040404); + /* LNC Chicken Bits */ + REG_WRITE(0x70400, 0x4000); +} + + +static void mrst_hdmi_dpms(struct drm_encoder *encoder, int mode) +{ + static int dpms_mode = -1; + + struct drm_device *dev = encoder->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + struct mrst_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; + u32 temp; + + if (dpms_mode == mode) + return; + + if (mode != DRM_MODE_DPMS_ON) + temp = 0x0; + else + temp = 0x99; + + dpms_mode = mode; + HDMI_WRITE(HDMI_VIDEO_REG, temp); +} + +static unsigned int htotal_calculate(struct drm_display_mode *mode) +{ + u32 htotal, new_crtc_htotal; + + htotal = (mode->crtc_hdisplay - 1) | ((mode->crtc_htotal - 1) << 16); + + /* + * 1024 x 768 new_crtc_htotal = 0x1024; + * 1280 x 1024 new_crtc_htotal = 0x0c34; + */ + new_crtc_htotal = (mode->crtc_htotal - 1) * 200 * 1000 / mode->clock; + + return (mode->crtc_hdisplay - 1) | (new_crtc_htotal << 16); +} + +static void mrst_hdmi_find_dpll(struct drm_crtc *crtc, int target, + int refclk, struct mrst_hdmi_clock *best_clock) +{ + int np_min, np_max, nr_min, nr_max; + int np, nr, nf; + + np_min = DIV_ROUND_UP(mrst_hdmi_limit.vco.min, target * 10); + np_max = mrst_hdmi_limit.vco.max / (target * 10); + if (np_min < mrst_hdmi_limit.np.min) + np_min = mrst_hdmi_limit.np.min; + if (np_max > mrst_hdmi_limit.np.max) + np_max = mrst_hdmi_limit.np.max; + + nr_min = DIV_ROUND_UP((refclk * 1000), (target * 10 * np_max)); + nr_max = DIV_ROUND_UP((refclk * 1000), (target * 10 * np_min)); + if (nr_min < mrst_hdmi_limit.nr.min) + nr_min = mrst_hdmi_limit.nr.min; + if (nr_max > mrst_hdmi_limit.nr.max) + nr_max = mrst_hdmi_limit.nr.max; + + np = DIV_ROUND_UP((refclk * 1000), (target * 10 * nr_max)); + nr = DIV_ROUND_UP((refclk * 1000), (target * 10 * np)); + nf = DIV_ROUND_CLOSEST((target * 10 * np * nr), refclk); + DRM_DEBUG_KMS("np, nr, nf %d %d %d\n", np, nr, nf); + + /* + * 1024 x 768 np = 1; nr = 0x26; nf = 0x0fd8000; + * 1280 x 1024 np = 1; nr = 0x17; nf = 0x1034000; + */ + best_clock->np = np; + best_clock->nr = nr - 1; + best_clock->nf = (nf << 14); +} + +int mrst_crtc_hdmi_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 drm_psb_private *dev_priv = dev->dev_private; + struct mrst_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; + int pipe = 1; + int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; + int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; + int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; + int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; + int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; + int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; + int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE; + int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS; + int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC; + int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; + int refclk; + struct mrst_hdmi_clock clock; + u32 dspcntr, pipeconf, dpll, temp; + int dspcntr_reg = DSPBCNTR; + + /* Disable the VGA plane that we never use */ + REG_WRITE(VGACNTRL, VGA_DISP_DISABLE); + + /* XXX: Disable the panel fitter if it was on our pipe */ + + /* Disable dpll if necessary */ + dpll = REG_READ(DPLL_CTRL); + if ((dpll & DPLL_PWRDN) == 0) { + REG_WRITE(DPLL_CTRL, dpll | (DPLL_PWRDN | DPLL_RESET)); + REG_WRITE(DPLL_DIV_CTRL, 0x00000000); + REG_WRITE(DPLL_STATUS, 0x1); + } + udelay(150); + + /* reset controller: FIXME - can we sort out the ioremap mess ? */ + iounmap(hdmi_dev->regs); + mrst_hdmi_reset(dev); + + /* program and enable dpll */ + refclk = 25000; + mrst_hdmi_find_dpll(crtc, adjusted_mode->clock, refclk, &clock); + + /* Setting DPLL */ + dpll = REG_READ(DPLL_CTRL); + dpll &= ~DPLL_PDIV_MASK; + dpll &= ~(DPLL_PWRDN | DPLL_RESET); + REG_WRITE(DPLL_CTRL, 0x00000008); + REG_WRITE(DPLL_DIV_CTRL, ((clock.nf << 6) | clock.nr)); + REG_WRITE(DPLL_ADJUST, ((clock.nf >> 14) - 1)); + REG_WRITE(DPLL_CTRL, (dpll | (clock.np << DPLL_PDIV_SHIFT) | DPLL_ENSTAT | DPLL_DITHEN)); + REG_WRITE(DPLL_UPDATE, 0x80000000); + REG_WRITE(DPLL_CLK_ENABLE, 0x80050102); + udelay(150); + + hdmi_dev->regs = ioremap(hdmi_dev->mmio, hdmi_dev->mmio_len); + if (hdmi_dev->regs == NULL) { + DRM_ERROR("failed to do hdmi mmio mapping\n"); + return -ENOMEM; + } + + /* configure HDMI */ + HDMI_WRITE(0x1004, 0x1fd); + HDMI_WRITE(0x2000, 0x1); + HDMI_WRITE(0x2008, 0x0); + HDMI_WRITE(0x3130, 0x8); + HDMI_WRITE(0x101c, 0x1800810); + + temp = htotal_calculate(adjusted_mode); + REG_WRITE(htot_reg, temp); + REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | ((adjusted_mode->crtc_hblank_end - 1) << 16)); + REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | ((adjusted_mode->crtc_hsync_end - 1) << 16)); + REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | ((adjusted_mode->crtc_vtotal - 1) << 16)); + REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | ((adjusted_mode->crtc_vblank_end - 1) << 16)); + REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | ((adjusted_mode->crtc_vsync_end - 1) << 16)); + REG_WRITE(pipesrc_reg, + ((mode->crtc_hdisplay - 1) << 16) | (mode->crtc_vdisplay - 1)); + + REG_WRITE(PCH_HTOTAL_B, (adjusted_mode->crtc_hdisplay - 1) | ((adjusted_mode->crtc_htotal - 1) << 16)); + REG_WRITE(PCH_HBLANK_B, (adjusted_mode->crtc_hblank_start - 1) | ((adjusted_mode->crtc_hblank_end - 1) << 16)); + REG_WRITE(PCH_HSYNC_B, (adjusted_mode->crtc_hsync_start - 1) | ((adjusted_mode->crtc_hsync_end - 1) << 16)); + REG_WRITE(PCH_VTOTAL_B, (adjusted_mode->crtc_vdisplay - 1) | ((adjusted_mode->crtc_vtotal - 1) << 16)); + REG_WRITE(PCH_VBLANK_B, (adjusted_mode->crtc_vblank_start - 1) | ((adjusted_mode->crtc_vblank_end - 1) << 16)); + REG_WRITE(PCH_VSYNC_B, (adjusted_mode->crtc_vsync_start - 1) | ((adjusted_mode->crtc_vsync_end - 1) << 16)); + REG_WRITE(PCH_PIPEBSRC, + ((mode->crtc_hdisplay - 1) << 16) | (mode->crtc_vdisplay - 1)); + + temp = adjusted_mode->crtc_hblank_end - adjusted_mode->crtc_hblank_start; + HDMI_WRITE(HDMI_HBLANK_A, ((adjusted_mode->crtc_hdisplay - 1) << 16) | temp); + + REG_WRITE(dspsize_reg, + ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); + REG_WRITE(dsppos_reg, 0); + + /* Flush the plane changes */ + { + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + crtc_funcs->mode_set_base(crtc, x, y, old_fb); + } + + /* Set up the display plane register */ + dspcntr = REG_READ(dspcntr_reg); + dspcntr |= DISPPLANE_GAMMA_ENABLE; + dspcntr |= DISPPLANE_SEL_PIPE_B; + dspcntr |= DISPLAY_PLANE_ENABLE; + + /* setup pipeconf */ + pipeconf = REG_READ(pipeconf_reg); + pipeconf |= PIPEACONF_ENABLE; + + REG_WRITE(pipeconf_reg, pipeconf); + REG_READ(pipeconf_reg); + + REG_WRITE(PCH_PIPEBCONF, pipeconf); + REG_READ(PCH_PIPEBCONF); + wait_for_vblank(dev); + + REG_WRITE(dspcntr_reg, dspcntr); + wait_for_vblank(dev); + + return 0; +} + +static int mrst_hdmi_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + if (mode->clock > 165000) + return MODE_CLOCK_HIGH; + if (mode->clock < 20000) + return MODE_CLOCK_LOW; + + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + + return MODE_OK; +} + +static bool mrst_hdmi_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static enum drm_connector_status +mrst_hdmi_detect(struct drm_connector *connector, bool force) +{ + enum drm_connector_status status; + struct drm_device *dev = connector->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + struct mrst_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; + u32 temp; + + temp = HDMI_READ(HDMI_HSR); + DRM_DEBUG_KMS("HDMI_HSR %x\n", temp); + + if ((temp & HDMI_DETECT_HDP) != 0) + status = connector_status_connected; + else + status = connector_status_disconnected; + + return status; +} + +static const unsigned char raw_edid[] = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x10, 0xac, 0x2f, 0xa0, + 0x53, 0x55, 0x33, 0x30, 0x16, 0x13, 0x01, 0x03, 0x0e, 0x3a, 0x24, 0x78, + 0xea, 0xe9, 0xf5, 0xac, 0x51, 0x30, 0xb4, 0x25, 0x11, 0x50, 0x54, 0xa5, + 0x4b, 0x00, 0x81, 0x80, 0xa9, 0x40, 0x71, 0x4f, 0xb3, 0x00, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x28, 0x3c, 0x80, 0xa0, 0x70, 0xb0, + 0x23, 0x40, 0x30, 0x20, 0x36, 0x00, 0x46, 0x6c, 0x21, 0x00, 0x00, 0x1a, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x47, 0x4e, 0x37, 0x32, 0x31, 0x39, 0x35, + 0x52, 0x30, 0x33, 0x55, 0x53, 0x0a, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x44, + 0x45, 0x4c, 0x4c, 0x20, 0x32, 0x37, 0x30, 0x39, 0x57, 0x0a, 0x20, 0x20, + 0x00, 0x00, 0x00, 0xfd, 0x00, 0x38, 0x4c, 0x1e, 0x53, 0x11, 0x00, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x8d +}; + +static int mrst_hdmi_get_modes(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + struct i2c_adapter *i2c_adap; + struct edid *edid; + struct drm_display_mode *mode, *t; + int i = 0, ret = 0; + + i2c_adap = i2c_get_adapter(3); + if (i2c_adap == NULL) { + DRM_ERROR("No ddc adapter available!\n"); + edid = (struct edid *)raw_edid; + } else { + edid = (struct edid *)raw_edid; + /* FIXME ? edid = drm_get_edid(connector, i2c_adap); */ + } + + if (edid) { + drm_mode_connector_update_edid_property(connector, edid); + ret = drm_add_edid_modes(connector, edid); + connector->display_info.raw_edid = NULL; + } + + /* + * prune modes that require frame buffer bigger than stolen mem + */ + list_for_each_entry_safe(mode, t, &connector->probed_modes, head) { + if ((mode->hdisplay * mode->vdisplay * 4) >= dev_priv->vram_stolen_size) { + i++; + drm_mode_remove(connector, mode); + } + } + return ret - i; +} + +static void mrst_hdmi_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + + mrst_hdmi_audio_enable(dev); + return; +} + +static void mrst_hdmi_destroy(struct drm_connector *connector) +{ + return; +} + +static const struct drm_encoder_helper_funcs mrst_hdmi_helper_funcs = { + .dpms = mrst_hdmi_dpms, + .mode_fixup = mrst_hdmi_mode_fixup, + .prepare = psb_intel_encoder_prepare, + .mode_set = mrst_hdmi_mode_set, + .commit = psb_intel_encoder_commit, +}; + +static const struct drm_connector_helper_funcs + mrst_hdmi_connector_helper_funcs = { + .get_modes = mrst_hdmi_get_modes, + .mode_valid = mrst_hdmi_mode_valid, + .best_encoder = psb_intel_best_encoder, +}; + +static const struct drm_connector_funcs mrst_hdmi_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .detect = mrst_hdmi_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = mrst_hdmi_destroy, +}; + +static void mrst_hdmi_enc_destroy(struct drm_encoder *encoder) +{ + drm_encoder_cleanup(encoder); +} + +static const struct drm_encoder_funcs mrst_hdmi_enc_funcs = { + .destroy = mrst_hdmi_enc_destroy, +}; + +void mrst_hdmi_init(struct drm_device *dev, + struct psb_intel_mode_device *mode_dev) +{ + struct psb_intel_output *psb_intel_output; + struct drm_connector *connector; + struct drm_encoder *encoder; + + psb_intel_output = kzalloc(sizeof(struct psb_intel_output), GFP_KERNEL); + if (!psb_intel_output) + return; + + psb_intel_output->mode_dev = mode_dev; + connector = &psb_intel_output->base; + encoder = &psb_intel_output->enc; + drm_connector_init(dev, &psb_intel_output->base, + &mrst_hdmi_connector_funcs, + DRM_MODE_CONNECTOR_DVID); + + drm_encoder_init(dev, &psb_intel_output->enc, + &mrst_hdmi_enc_funcs, + DRM_MODE_ENCODER_TMDS); + + drm_mode_connector_attach_encoder(&psb_intel_output->base, + &psb_intel_output->enc); + + psb_intel_output->type = INTEL_OUTPUT_HDMI; + drm_encoder_helper_add(encoder, &mrst_hdmi_helper_funcs); + drm_connector_helper_add(connector, &mrst_hdmi_connector_helper_funcs); + + connector->display_info.subpixel_order = SubPixelHorizontalRGB; + connector->interlace_allowed = false; + connector->doublescan_allowed = false; + drm_sysfs_connector_add(connector); + + return; +} + +static DEFINE_PCI_DEVICE_TABLE(hdmi_ids) = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080d) }, + {} +}; + +void mrst_hdmi_setup(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct pci_dev *pdev; + struct mrst_hdmi_dev *hdmi_dev; + int ret; + + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x080d, NULL); + if (!pdev) + return; + + hdmi_dev = kzalloc(sizeof(struct mrst_hdmi_dev), GFP_KERNEL); + if (!hdmi_dev) { + dev_err(dev->dev, "failed to allocate memory\n"); + goto out; + } + + + ret = pci_enable_device(pdev); + if (ret) { + dev_err(dev->dev, "failed to enable hdmi controller\n"); + goto free; + } + + hdmi_dev->mmio = pci_resource_start(pdev, 0); + hdmi_dev->mmio_len = pci_resource_len(pdev, 0); + hdmi_dev->regs = ioremap(hdmi_dev->mmio, hdmi_dev->mmio_len); + if (!hdmi_dev->regs) { + dev_err(dev->dev, "failed to map hdmi mmio\n"); + goto free; + } + + hdmi_dev->dev = pdev; + pci_set_drvdata(pdev, hdmi_dev); + + /* Initialize i2c controller */ + ret = mrst_hdmi_i2c_init(hdmi_dev->dev); + if (ret) + dev_err(dev->dev, "HDMI I2C initialization failed\n"); + + dev_priv->hdmi_priv = hdmi_dev; + mrst_hdmi_audio_disable(dev); + return; + +free: + kfree(hdmi_dev); +out: + return; +} + +void mrst_hdmi_teardown(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct mrst_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; + struct pci_dev *pdev; + + if (hdmi_dev) { + pdev = hdmi_dev->dev; + pci_set_drvdata(pdev, NULL); + mrst_hdmi_i2c_exit(pdev); + iounmap(hdmi_dev->regs); + kfree(hdmi_dev); + pci_dev_put(pdev); + } +} + +/* save HDMI register state */ +void mrst_hdmi_save(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct mrst_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; + int i; + + /* dpll */ + hdmi_dev->saveDPLL_CTRL = PSB_RVDC32(DPLL_CTRL); + hdmi_dev->saveDPLL_DIV_CTRL = PSB_RVDC32(DPLL_DIV_CTRL); + hdmi_dev->saveDPLL_ADJUST = PSB_RVDC32(DPLL_ADJUST); + hdmi_dev->saveDPLL_UPDATE = PSB_RVDC32(DPLL_UPDATE); + hdmi_dev->saveDPLL_CLK_ENABLE = PSB_RVDC32(DPLL_CLK_ENABLE); + + /* pipe B */ + dev_priv->savePIPEBCONF = PSB_RVDC32(PIPEBCONF); + dev_priv->savePIPEBSRC = PSB_RVDC32(PIPEBSRC); + dev_priv->saveHTOTAL_B = PSB_RVDC32(HTOTAL_B); + dev_priv->saveHBLANK_B = PSB_RVDC32(HBLANK_B); + dev_priv->saveHSYNC_B = PSB_RVDC32(HSYNC_B); + dev_priv->saveVTOTAL_B = PSB_RVDC32(VTOTAL_B); + dev_priv->saveVBLANK_B = PSB_RVDC32(VBLANK_B); + dev_priv->saveVSYNC_B = PSB_RVDC32(VSYNC_B); + + hdmi_dev->savePCH_PIPEBCONF = PSB_RVDC32(PCH_PIPEBCONF); + hdmi_dev->savePCH_PIPEBSRC = PSB_RVDC32(PCH_PIPEBSRC); + hdmi_dev->savePCH_HTOTAL_B = PSB_RVDC32(PCH_HTOTAL_B); + hdmi_dev->savePCH_HBLANK_B = PSB_RVDC32(PCH_HBLANK_B); + hdmi_dev->savePCH_HSYNC_B = PSB_RVDC32(PCH_HSYNC_B); + hdmi_dev->savePCH_VTOTAL_B = PSB_RVDC32(PCH_VTOTAL_B); + hdmi_dev->savePCH_VBLANK_B = PSB_RVDC32(PCH_VBLANK_B); + hdmi_dev->savePCH_VSYNC_B = PSB_RVDC32(PCH_VSYNC_B); + + /* plane */ + dev_priv->saveDSPBCNTR = PSB_RVDC32(DSPBCNTR); + dev_priv->saveDSPBSTRIDE = PSB_RVDC32(DSPBSTRIDE); + dev_priv->saveDSPBADDR = PSB_RVDC32(DSPBBASE); + dev_priv->saveDSPBSURF = PSB_RVDC32(DSPBSURF); + dev_priv->saveDSPBLINOFF = PSB_RVDC32(DSPBLINOFF); + dev_priv->saveDSPBTILEOFF = PSB_RVDC32(DSPBTILEOFF); + + /* cursor B */ + dev_priv->saveDSPBCURSOR_CTRL = PSB_RVDC32(CURBCNTR); + dev_priv->saveDSPBCURSOR_BASE = PSB_RVDC32(CURBBASE); + dev_priv->saveDSPBCURSOR_POS = PSB_RVDC32(CURBPOS); + + /* save palette */ + for (i = 0; i < 256; i++) + dev_priv->save_palette_b[i] = PSB_RVDC32(PALETTE_B + (i << 2)); +} + +/* restore HDMI register state */ +void mrst_hdmi_restore(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + struct mrst_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; + int i; + + /* dpll */ + PSB_WVDC32(hdmi_dev->saveDPLL_CTRL, DPLL_CTRL); + PSB_WVDC32(hdmi_dev->saveDPLL_DIV_CTRL, DPLL_DIV_CTRL); + PSB_WVDC32(hdmi_dev->saveDPLL_ADJUST, DPLL_ADJUST); + PSB_WVDC32(hdmi_dev->saveDPLL_UPDATE, DPLL_UPDATE); + PSB_WVDC32(hdmi_dev->saveDPLL_CLK_ENABLE, DPLL_CLK_ENABLE); + DRM_UDELAY(150); + + /* pipe */ + PSB_WVDC32(dev_priv->savePIPEBSRC, PIPEBSRC); + PSB_WVDC32(dev_priv->saveHTOTAL_B, HTOTAL_B); + PSB_WVDC32(dev_priv->saveHBLANK_B, HBLANK_B); + PSB_WVDC32(dev_priv->saveHSYNC_B, HSYNC_B); + PSB_WVDC32(dev_priv->saveVTOTAL_B, VTOTAL_B); + PSB_WVDC32(dev_priv->saveVBLANK_B, VBLANK_B); + PSB_WVDC32(dev_priv->saveVSYNC_B, VSYNC_B); + + PSB_WVDC32(hdmi_dev->savePCH_PIPEBSRC, PCH_PIPEBSRC); + PSB_WVDC32(hdmi_dev->savePCH_HTOTAL_B, PCH_HTOTAL_B); + PSB_WVDC32(hdmi_dev->savePCH_HBLANK_B, PCH_HBLANK_B); + PSB_WVDC32(hdmi_dev->savePCH_HSYNC_B, PCH_HSYNC_B); + PSB_WVDC32(hdmi_dev->savePCH_VTOTAL_B, PCH_VTOTAL_B); + PSB_WVDC32(hdmi_dev->savePCH_VBLANK_B, PCH_VBLANK_B); + PSB_WVDC32(hdmi_dev->savePCH_VSYNC_B, PCH_VSYNC_B); + + PSB_WVDC32(dev_priv->savePIPEBCONF, PIPEBCONF); + PSB_WVDC32(hdmi_dev->savePCH_PIPEBCONF, PCH_PIPEBCONF); + + /* plane */ + PSB_WVDC32(dev_priv->saveDSPBLINOFF, DSPBLINOFF); + PSB_WVDC32(dev_priv->saveDSPBSTRIDE, DSPBSTRIDE); + PSB_WVDC32(dev_priv->saveDSPBTILEOFF, DSPBTILEOFF); + PSB_WVDC32(dev_priv->saveDSPBCNTR, DSPBCNTR); + PSB_WVDC32(dev_priv->saveDSPBSURF, DSPBSURF); + + /* cursor B */ + PSB_WVDC32(dev_priv->saveDSPBCURSOR_CTRL, CURBCNTR); + PSB_WVDC32(dev_priv->saveDSPBCURSOR_POS, CURBPOS); + PSB_WVDC32(dev_priv->saveDSPBCURSOR_BASE, CURBBASE); + + /* restore palette */ + for (i = 0; i < 256; i++) + PSB_WVDC32(dev_priv->save_palette_b[i], PALETTE_B + (i << 2)); +} diff --git a/drivers/staging/gma500/mrst_hdmi_i2c.c b/drivers/staging/gma500/mrst_hdmi_i2c.c new file mode 100644 index 0000000..351b9d8 --- /dev/null +++ b/drivers/staging/gma500/mrst_hdmi_i2c.c @@ -0,0 +1,327 @@ +/* + * 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: + * Li Peng <peng.li@intel.com> + */ + +#include <linux/mutex.h> +#include <linux/pci.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include "psb_drv.h" + +#define HDMI_READ(reg) readl(hdmi_dev->regs + (reg)) +#define HDMI_WRITE(reg, val) writel(val, hdmi_dev->regs + (reg)) + +#define HDMI_HCR 0x1000 +#define HCR_DETECT_HDP (1 << 6) +#define HCR_ENABLE_HDCP (1 << 5) +#define HCR_ENABLE_AUDIO (1 << 2) +#define HCR_ENABLE_PIXEL (1 << 1) +#define HCR_ENABLE_TMDS (1 << 0) +#define HDMI_HICR 0x1004 +#define HDMI_INTR_I2C_ERROR (1 << 4) +#define HDMI_INTR_I2C_FULL (1 << 3) +#define HDMI_INTR_I2C_DONE (1 << 2) +#define HDMI_INTR_HPD (1 << 0) +#define HDMI_HSR 0x1008 +#define HDMI_HISR 0x100C +#define HDMI_HI2CRDB0 0x1200 +#define HDMI_HI2CHCR 0x1240 +#define HI2C_HDCP_WRITE (0 << 2) +#define HI2C_HDCP_RI_READ (1 << 2) +#define HI2C_HDCP_READ (2 << 2) +#define HI2C_EDID_READ (3 << 2) +#define HI2C_READ_CONTINUE (1 << 1) +#define HI2C_ENABLE_TRANSACTION (1 << 0) + +#define HDMI_ICRH 0x1100 +#define HDMI_HI2CTDR0 0x1244 +#define HDMI_HI2CTDR1 0x1248 + +#define I2C_STAT_INIT 0 +#define I2C_READ_DONE 1 +#define I2C_TRANSACTION_DONE 2 + +struct hdmi_i2c_dev { + struct i2c_adapter *adap; + struct mutex i2c_lock; + struct completion complete; + int status; + struct i2c_msg *msg; + int buf_offset; +}; + +static void hdmi_i2c_irq_enable(struct mrst_hdmi_dev *hdmi_dev) +{ + u32 temp; + + temp = HDMI_READ(HDMI_HICR); + temp |= (HDMI_INTR_I2C_ERROR | HDMI_INTR_I2C_FULL | HDMI_INTR_I2C_DONE); + HDMI_WRITE(HDMI_HICR, temp); + HDMI_READ(HDMI_HICR); +} + +static void hdmi_i2c_irq_disable(struct mrst_hdmi_dev *hdmi_dev) +{ + HDMI_WRITE(HDMI_HICR, 0x0); + HDMI_READ(HDMI_HICR); +} + +static int xfer_read(struct i2c_adapter *adap, struct i2c_msg *pmsg) +{ + struct mrst_hdmi_dev *hdmi_dev = i2c_get_adapdata(adap); + struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev; + u32 temp; + + i2c_dev->status = I2C_STAT_INIT; + i2c_dev->msg = pmsg; + i2c_dev->buf_offset = 0; + INIT_COMPLETION(i2c_dev->complete); + + /* Enable I2C transaction */ + temp = ((pmsg->len) << 20) | HI2C_EDID_READ | HI2C_ENABLE_TRANSACTION; + HDMI_WRITE(HDMI_HI2CHCR, temp); + HDMI_READ(HDMI_HI2CHCR); + + while (i2c_dev->status != I2C_TRANSACTION_DONE) + wait_for_completion_interruptible_timeout(&i2c_dev->complete, + 10 * HZ); + + return 0; +} + +static int xfer_write(struct i2c_adapter *adap, struct i2c_msg *pmsg) +{ + /* + * XXX: i2c write seems isn't useful for EDID probe, don't do anything + */ + return 0; +} + +static int mrst_hdmi_i2c_access(struct i2c_adapter *adap, + struct i2c_msg *pmsg, + int num) +{ + struct mrst_hdmi_dev *hdmi_dev = i2c_get_adapdata(adap); + struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev; + int i, err = 0; + + mutex_lock(&i2c_dev->i2c_lock); + + /* Enable i2c unit */ + HDMI_WRITE(HDMI_ICRH, 0x00008760); + + /* Enable irq */ + hdmi_i2c_irq_enable(hdmi_dev); + for (i = 0; i < num; i++) { + if (pmsg->len && pmsg->buf) { + if (pmsg->flags & I2C_M_RD) + err = xfer_read(adap, pmsg); + else + err = xfer_write(adap, pmsg); + } + pmsg++; /* next message */ + } + + /* Disable irq */ + hdmi_i2c_irq_disable(hdmi_dev); + + mutex_unlock(&i2c_dev->i2c_lock); + + return i; +} + +static u32 mrst_hdmi_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR; +} + +static const struct i2c_algorithm mrst_hdmi_i2c_algorithm = { + .master_xfer = mrst_hdmi_i2c_access, + .functionality = mrst_hdmi_i2c_func, +}; + +static struct i2c_adapter mrst_hdmi_i2c_adapter = { + .name = "mrst_hdmi_i2c", + .nr = 3, + .owner = THIS_MODULE, + .class = I2C_CLASS_DDC, + .algo = &mrst_hdmi_i2c_algorithm, +}; + +static void hdmi_i2c_read(struct mrst_hdmi_dev *hdmi_dev) +{ + struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev; + struct i2c_msg *msg = i2c_dev->msg; + u8 *buf = msg->buf; + u32 temp; + int i, offset; + + offset = i2c_dev->buf_offset; + for (i = 0; i < 0x10; i++) { + temp = HDMI_READ(HDMI_HI2CRDB0 + (i * 4)); + memcpy(buf + (offset + i * 4), &temp, 4); + } + i2c_dev->buf_offset += (0x10 * 4); + + /* clearing read buffer full intr */ + temp = HDMI_READ(HDMI_HISR); + HDMI_WRITE(HDMI_HISR, temp | HDMI_INTR_I2C_FULL); + HDMI_READ(HDMI_HISR); + + /* continue read transaction */ + temp = HDMI_READ(HDMI_HI2CHCR); + HDMI_WRITE(HDMI_HI2CHCR, temp | HI2C_READ_CONTINUE); + HDMI_READ(HDMI_HI2CHCR); + + i2c_dev->status = I2C_READ_DONE; + return; +} + +static void hdmi_i2c_transaction_done(struct mrst_hdmi_dev *hdmi_dev) +{ + struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev; + u32 temp; + + /* clear transaction done intr */ + temp = HDMI_READ(HDMI_HISR); + HDMI_WRITE(HDMI_HISR, temp | HDMI_INTR_I2C_DONE); + HDMI_READ(HDMI_HISR); + + + temp = HDMI_READ(HDMI_HI2CHCR); + HDMI_WRITE(HDMI_HI2CHCR, temp & ~HI2C_ENABLE_TRANSACTION); + HDMI_READ(HDMI_HI2CHCR); + + i2c_dev->status = I2C_TRANSACTION_DONE; + return; +} + +static irqreturn_t mrst_hdmi_i2c_handler(int this_irq, void *dev) +{ + struct mrst_hdmi_dev *hdmi_dev = dev; + struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev; + u32 stat; + + stat = HDMI_READ(HDMI_HISR); + + if (stat & HDMI_INTR_HPD) { + HDMI_WRITE(HDMI_HISR, stat | HDMI_INTR_HPD); + HDMI_READ(HDMI_HISR); + } + + if (stat & HDMI_INTR_I2C_FULL) + hdmi_i2c_read(hdmi_dev); + + if (stat & HDMI_INTR_I2C_DONE) + hdmi_i2c_transaction_done(hdmi_dev); + + complete(&i2c_dev->complete); + + return IRQ_HANDLED; +} + +/* + * choose alternate function 2 of GPIO pin 52, 53, + * which is used by HDMI I2C logic + */ +static void mrst_hdmi_i2c_gpio_fix(void) +{ + void *base; + unsigned int gpio_base = 0xff12c000; + int gpio_len = 0x1000; + u32 temp; + + base = ioremap((resource_size_t)gpio_base, gpio_len); + if (base == NULL) { + DRM_ERROR("gpio ioremap fail\n"); + return; + } + + temp = readl(base + 0x44); + DRM_DEBUG_DRIVER("old gpio val %x\n", temp); + writel((temp | 0x00000a00), (base + 0x44)); + temp = readl(base + 0x44); + DRM_DEBUG_DRIVER("new gpio val %x\n", temp); + + iounmap(base); +} + +int mrst_hdmi_i2c_init(struct pci_dev *dev) +{ + struct mrst_hdmi_dev *hdmi_dev; + struct hdmi_i2c_dev *i2c_dev; + int ret; + + hdmi_dev = pci_get_drvdata(dev); + + i2c_dev = kzalloc(sizeof(struct hdmi_i2c_dev), GFP_KERNEL); + if (i2c_dev == NULL) { + DRM_ERROR("Can't allocate interface\n"); + ret = -ENOMEM; + goto exit; + } + + i2c_dev->adap = &mrst_hdmi_i2c_adapter; + i2c_dev->status = I2C_STAT_INIT; + init_completion(&i2c_dev->complete); + mutex_init(&i2c_dev->i2c_lock); + i2c_set_adapdata(&mrst_hdmi_i2c_adapter, hdmi_dev); + hdmi_dev->i2c_dev = i2c_dev; + + /* Enable HDMI I2C function on gpio */ + mrst_hdmi_i2c_gpio_fix(); + + /* request irq */ + ret = request_irq(dev->irq, mrst_hdmi_i2c_handler, IRQF_SHARED, + mrst_hdmi_i2c_adapter.name, hdmi_dev); + if (ret) { + DRM_ERROR("Failed to request IRQ for I2C controller\n"); + goto err; + } + + /* Adapter registration */ + ret = i2c_add_numbered_adapter(&mrst_hdmi_i2c_adapter); + return ret; + +err: + kfree(i2c_dev); +exit: + return ret; +} + +void mrst_hdmi_i2c_exit(struct pci_dev *dev) +{ + struct mrst_hdmi_dev *hdmi_dev; + struct hdmi_i2c_dev *i2c_dev; + + hdmi_dev = pci_get_drvdata(dev); + if (i2c_del_adapter(&mrst_hdmi_i2c_adapter)) + DRM_DEBUG_DRIVER("Failed to delete hdmi-i2c adapter\n"); + + i2c_dev = hdmi_dev->i2c_dev; + kfree(i2c_dev); + free_irq(dev->irq, hdmi_dev); +} diff --git a/drivers/staging/gma500/mrst_lvds.c b/drivers/staging/gma500/mrst_lvds.c index 4a08b74..e7999a2 100644 --- a/drivers/staging/gma500/mrst_lvds.c +++ b/drivers/staging/gma500/mrst_lvds.c @@ -24,11 +24,11 @@ #include <drm/drmP.h> #include <asm/mrst.h> -#include "psb_intel_bios.h" +#include "intel_bios.h" #include "psb_drv.h" #include "psb_intel_drv.h" #include "psb_intel_reg.h" -#include "psb_powermgmt.h" +#include "power.h" #include <linux/pm_runtime.h> /* The max/min PWM frequency in BPCR[31:17] - */ @@ -46,8 +46,7 @@ static void mrst_lvds_set_power(struct drm_device *dev, struct psb_intel_output *output, bool on) { u32 pp_status; - DRM_DRIVER_PRIVATE_T *dev_priv = dev->dev_private; - PSB_DEBUG_ENTRY("\n"); + struct drm_psb_private *dev_priv = dev->dev_private; if (!gma_power_begin(dev, true)) return; @@ -59,7 +58,11 @@ static void mrst_lvds_set_power(struct drm_device *dev, pp_status = REG_READ(PP_STATUS); } while ((pp_status & (PP_ON | PP_READY)) == PP_READY); dev_priv->is_lvds_on = true; + if (dev_priv->ops->lvds_bl_power) + dev_priv->ops->lvds_bl_power(dev, true); } else { + if (dev_priv->ops->lvds_bl_power) + dev_priv->ops->lvds_bl_power(dev, false); REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) & ~POWER_TARGET_ON); do { @@ -68,7 +71,6 @@ static void mrst_lvds_set_power(struct drm_device *dev, dev_priv->is_lvds_on = false; pm_request_idle(&dev->pdev->dev); } - gma_power_end(dev); } @@ -77,8 +79,6 @@ static void mrst_lvds_dpms(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct psb_intel_output *output = enc_to_psb_intel_output(encoder); - PSB_DEBUG_ENTRY("\n"); - if (mode == DRM_MODE_DPMS_ON) mrst_lvds_set_power(dev, output, true); else @@ -94,11 +94,10 @@ static void mrst_lvds_mode_set(struct drm_encoder *encoder, struct psb_intel_mode_device *mode_dev = enc_to_psb_intel_output(encoder)->mode_dev; struct drm_device *dev = encoder->dev; + struct drm_psb_private *dev_priv = dev->dev_private; u32 lvds_port; uint64_t v = DRM_MODE_SCALE_FULLSCREEN; - PSB_DEBUG_ENTRY("\n"); - if (!gma_power_begin(dev, true)) return; @@ -112,7 +111,9 @@ static void mrst_lvds_mode_set(struct drm_encoder *encoder, LVDS_PORT_EN | LVDS_BORDER_EN; - if (mode_dev->panel_wants_dither) + /* If the firmware says dither on Moorestown, or the BIOS does + on Oaktrail then enable dithering */ + if (mode_dev->panel_wants_dither || dev_priv->lvds_dither) lvds_port |= MRST_PANEL_8TO6_DITHER_ENABLE; REG_WRITE(LVDS, lvds_port); @@ -146,13 +147,59 @@ static void mrst_lvds_mode_set(struct drm_encoder *encoder, gma_power_end(dev); } +static void mrst_lvds_prepare(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct psb_intel_output *output = enc_to_psb_intel_output(encoder); + struct psb_intel_mode_device *mode_dev = output->mode_dev; + + if (!gma_power_begin(dev, true)) + return; + + mode_dev->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL); + mode_dev->backlight_duty_cycle = (mode_dev->saveBLC_PWM_CTL & + BACKLIGHT_DUTY_CYCLE_MASK); + mrst_lvds_set_power(dev, output, false); + gma_power_end(dev); +} + +static u32 mrst_lvds_get_max_backlight(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + u32 ret; + + if (gma_power_begin(dev, false)) { + ret = ((REG_READ(BLC_PWM_CTL) & + BACKLIGHT_MODULATION_FREQ_MASK) >> + BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; + + gma_power_end(dev); + } else + ret = ((dev_priv->saveBLC_PWM_CTL & + BACKLIGHT_MODULATION_FREQ_MASK) >> + BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; + + return ret; +} + +static void mrst_lvds_commit(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct psb_intel_output *output = enc_to_psb_intel_output(encoder); + struct psb_intel_mode_device *mode_dev = output->mode_dev; + + if (mode_dev->backlight_duty_cycle == 0) + mode_dev->backlight_duty_cycle = + mrst_lvds_get_max_backlight(dev); + mrst_lvds_set_power(dev, output, true); +} static const struct drm_encoder_helper_funcs mrst_lvds_helper_funcs = { .dpms = mrst_lvds_dpms, .mode_fixup = psb_intel_lvds_mode_fixup, - .prepare = psb_intel_lvds_prepare, + .prepare = mrst_lvds_prepare, .mode_set = mrst_lvds_mode_set, - .commit = psb_intel_lvds_commit, + .commit = mrst_lvds_commit, }; static struct drm_display_mode lvds_configuration_modes[] = { @@ -252,8 +299,6 @@ void mrst_lvds_init(struct drm_device *dev, struct i2c_adapter *i2c_adap; struct drm_display_mode *scan; /* *modes, *bios_mode; */ - PSB_DEBUG_ENTRY("\n"); - psb_intel_output = kzalloc(sizeof(struct psb_intel_output), GFP_KERNEL); if (!psb_intel_output) return; @@ -302,16 +347,10 @@ void mrst_lvds_init(struct drm_device *dev, * if closed, act like it's not there for now */ - /* This ifdef can go once the cpu ident stuff is cleaned up in arch */ -#if defined(CONFIG_X86_MRST) - if (mrst_identify_cpu()) - i2c_adap = i2c_get_adapter(2); - else /* Oaktrail uses I2C 1 */ -#endif - i2c_adap = i2c_get_adapter(1); + i2c_adap = i2c_get_adapter(dev_priv->ops->i2c_bus); if (i2c_adap == NULL) - printk(KERN_ALERT "No ddc adapter available!\n"); + dev_err(dev->dev, "No ddc adapter available!\n"); /* * Attempt to get the fixed panel mode from DDC. Assume that the * preferred mode is the right one. @@ -333,7 +372,6 @@ void mrst_lvds_init(struct drm_device *dev, } } } - /* * If we didn't get EDID, try geting panel timing * from configuration data @@ -341,15 +379,13 @@ void mrst_lvds_init(struct drm_device *dev, mode_dev->panel_fixed_mode = mrst_lvds_get_configuration_mode(dev); if (mode_dev->panel_fixed_mode) { - mode_dev->panel_fixed_mode->type |= - DRM_MODE_TYPE_PREFERRED; + mode_dev->panel_fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; goto out; /* FIXME: check for quirks */ } /* If we still don't have a mode after all that, give up. */ if (!mode_dev->panel_fixed_mode) { - DRM_DEBUG - ("Found no modes on the lvds, ignoring the LVDS\n"); + dev_err(dev->dev, "Found no modes on the lvds, ignoring the LVDS\n"); goto failed_find; } @@ -358,7 +394,7 @@ out: return; failed_find: - DRM_DEBUG("No LVDS modes found, disabling.\n"); + dev_dbg(dev->dev, "No LVDS modes found, disabling.\n"); if (psb_intel_output->ddc_bus) psb_intel_i2c_destroy(psb_intel_output->ddc_bus); diff --git a/drivers/staging/gma500/psb_powermgmt.c b/drivers/staging/gma500/power.c index 1495415..972bea7 100644 --- a/drivers/staging/gma500/psb_powermgmt.c +++ b/drivers/staging/gma500/power.c @@ -1,7 +1,7 @@ /************************************************************************** - * Copyright (c) 2009, Intel Corporation. + * Copyright (c) 2009-2011, Intel Corporation. * All Rights Reserved. - + * * 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 @@ -27,14 +27,16 @@ * Massively reworked * Alan Cox <alan@linux.intel.com> */ -#include "psb_powermgmt.h" + +#include "power.h" #include "psb_drv.h" #include "psb_reg.h" #include "psb_intel_reg.h" #include <linux/mutex.h> #include <linux/pm_runtime.h> -static struct mutex power_mutex; +static struct mutex power_mutex; /* Serialize power ops */ +static spinlock_t power_ctrl_lock; /* Serialize power claim */ /** * gma_power_init - initialise power manager @@ -46,23 +48,17 @@ void gma_power_init(struct drm_device *dev) { struct drm_psb_private *dev_priv = dev->dev_private; + /* FIXME: Move APM/OSPM base into relevant device code */ dev_priv->apm_base = dev_priv->apm_reg & 0xffff; dev_priv->ospm_base &= 0xffff; dev_priv->display_power = true; /* We start active */ dev_priv->display_count = 0; /* Currently no users */ dev_priv->suspended = false; /* And not suspended */ + spin_lock_init(&power_ctrl_lock); mutex_init(&power_mutex); - if (!IS_MRST(dev)) { - /* FIXME: wants further review */ - u32 gating = PSB_RSGX32(PSB_CR_CLKGATECTL); - /* Disable 2D clock gating */ - gating &= ~3; - gating |= 1; - PSB_WSGX32(gating, PSB_CR_CLKGATECTL); - PSB_RSGX32(PSB_CR_CLKGATECTL); - } + dev_priv->ops->init_pm(dev); } /** @@ -73,114 +69,10 @@ void gma_power_init(struct drm_device *dev) */ void gma_power_uninit(struct drm_device *dev) { - mutex_destroy(&power_mutex); pm_runtime_disable(&dev->pdev->dev); pm_runtime_set_suspended(&dev->pdev->dev); } - -/** - * save_display_registers - save registers lost on suspend - * @dev: our DRM device - * - * Save the state we need in order to be able to restore the interface - * upon resume from suspend - */ -static int 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; -} - -/** - * restore_display_registers - restore lost register state - * @dev: our DRM device - * - * Restore register state that was lost during suspend and resume. - */ -static int restore_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 + 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); - return 0; -} - -/** - * power_down - power down the display island - * @dev: our DRM device - * - * Power down the display interface of our device - */ -static void power_down(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - u32 pwr_mask ; - u32 pwr_sts; - - if (IS_MRST(dev)) { - pwr_mask = PSB_PWRGT_DISPLAY_MASK; - outl(pwr_mask, dev_priv->ospm_base + PSB_PM_SSC); - - while (true) { - pwr_sts = inl(dev_priv->ospm_base + PSB_PM_SSS); - if ((pwr_sts & pwr_mask) == pwr_mask) - break; - else - udelay(10); - } - dev_priv->display_power = false; - } -} - - /** * gma_suspend_display - suspend the display logic * @dev: our DRM device @@ -190,73 +82,12 @@ static void power_down(struct drm_device *dev) static void gma_suspend_display(struct drm_device *dev) { struct drm_psb_private *dev_priv = dev->dev_private; - int pp_stat; if (dev_priv->suspended) return; - - save_display_registers(dev); - - 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); - while ((PSB_RVDC32(GEN_FIFO_STAT_REG) & DPI_FIFO_EMPTY) - != DPI_FIFO_EMPTY); - PSB_WVDC32(0, DEVICE_READY_REG); - /* turn off panel power */ - } - power_down(dev); -} - -/* - * power_up - * - * Description: Restore power to the specified island(s) (powergating) - */ -static void power_up(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - u32 pwr_mask = PSB_PWRGT_DISPLAY_MASK; - u32 pwr_sts, pwr_cnt; - - if (IS_MRST(dev)) { - pwr_cnt = inl(dev_priv->ospm_base + PSB_PM_SSC); - pwr_cnt &= ~pwr_mask; - outl(pwr_cnt, (dev_priv->ospm_base + PSB_PM_SSC)); - - while (true) { - pwr_sts = inl(dev_priv->ospm_base + PSB_PM_SSS); - if ((pwr_sts & pwr_mask) == 0) - break; - else - udelay(10); - } - } - dev_priv->suspended = false; - dev_priv->display_power = true; + dev_priv->ops->save_regs(dev); + dev_priv->ops->power_down(dev); + dev_priv->display_power = false; } /** @@ -274,20 +105,14 @@ static void gma_resume_display(struct pci_dev *pdev) return; /* turn on the display power island */ - power_up(dev); + dev_priv->ops->power_up(dev); + dev_priv->suspended = false; + dev_priv->display_power = true; PSB_WVDC32(dev_priv->pge_ctl | _PSB_PGETBL_ENABLED, PSB_PGETBL_CTL); pci_write_config_word(pdev, PSB_GMCH_CTRL, dev_priv->gmch_ctrl | _PSB_GMCH_ENABLED); - - /* Don't reinitialize the GTT as it is unnecessary. The gtt is - * stored in memory so it will automatically be restored. All - * we need to do is restore the PGETBL_CTL which we already do - * above. - */ - /*psb_gtt_init(dev_priv->pg, 1);*/ - - restore_display_registers(dev); + dev_priv->ops->restore_regs(dev); } /** @@ -339,7 +164,7 @@ static bool gma_resume_pci(struct pci_dev *pdev) pci_restore_state(pdev); pci_write_config_dword(pdev, 0x5c, dev_priv->saveBSM); pci_write_config_dword(pdev, 0xFC, dev_priv->saveVBT); - /* retoring MSI address and data in PCIx space */ + /* restoring MSI address and data in PCIx space */ pci_write_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, dev_priv->msi_addr); pci_write_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, dev_priv->msi_data); ret = pci_enable_device(pdev); @@ -360,8 +185,9 @@ static bool gma_resume_pci(struct pci_dev *pdev) * perform the necessary shut down steps and save enough state that * we can undo this when resume is called. */ -int gma_power_suspend(struct pci_dev *pdev, pm_message_t state) +int gma_power_suspend(struct device *_dev) { + struct pci_dev *pdev = container_of(_dev, struct pci_dev, dev); struct drm_device *dev = pci_get_drvdata(pdev); struct drm_psb_private *dev_priv = dev->dev_private; @@ -379,15 +205,15 @@ int gma_power_suspend(struct pci_dev *pdev, pm_message_t state) return 0; } - /** * gma_power_resume - resume power * @pdev: PCI device * * Resume the PCI side of the graphics and then the displays */ -int gma_power_resume(struct pci_dev *pdev) +int gma_power_resume(struct device *_dev) { + struct pci_dev *pdev = container_of(_dev, struct pci_dev, dev); struct drm_device *dev = pci_get_drvdata(pdev); mutex_lock(&power_mutex); @@ -399,8 +225,6 @@ int gma_power_resume(struct pci_dev *pdev) return 0; } - - /** * gma_power_is_on - returne true if power is on * @dev: our DRM device @@ -413,7 +237,6 @@ bool gma_power_is_on(struct drm_device *dev) return dev_priv->display_power; } - /** * gma_power_begin - begin requiring power * @dev: our DRM device @@ -421,22 +244,23 @@ bool gma_power_is_on(struct drm_device *dev) * * Begin an action that requires the display power island is enabled. * We refcount the islands. - * - * FIXME: locking */ bool gma_power_begin(struct drm_device *dev, bool force_on) { struct drm_psb_private *dev_priv = dev->dev_private; int ret; + unsigned long flags; + spin_lock_irqsave(&power_ctrl_lock, flags); /* Power already on ? */ if (dev_priv->display_power) { dev_priv->display_count++; pm_runtime_get(&dev->pdev->dev); + spin_unlock_irqrestore(&power_ctrl_lock, flags); return true; } if (force_on == false) - return false; + goto out_false; /* Ok power up needed */ ret = gma_resume_pci(dev->pdev); @@ -445,12 +269,14 @@ bool gma_power_begin(struct drm_device *dev, bool force_on) psb_irq_postinstall(dev); pm_runtime_get(&dev->pdev->dev); dev_priv->display_count++; + spin_unlock_irqrestore(&power_ctrl_lock, flags); return true; } +out_false: + spin_unlock_irqrestore(&power_ctrl_lock, flags); return false; } - /** * gma_power_end - end use of power * @dev: Our DRM device @@ -461,15 +287,17 @@ bool gma_power_begin(struct drm_device *dev, bool force_on) void gma_power_end(struct drm_device *dev) { struct drm_psb_private *dev_priv = dev->dev_private; + unsigned long flags; + spin_lock_irqsave(&power_ctrl_lock, flags); dev_priv->display_count--; WARN_ON(dev_priv->display_count < 0); + spin_unlock_irqrestore(&power_ctrl_lock, flags); pm_runtime_put(&dev->pdev->dev); } int psb_runtime_suspend(struct device *dev) { - static pm_message_t dummy; - return gma_power_suspend(to_pci_dev(dev), dummy); + return gma_power_suspend(dev); } int psb_runtime_resume(struct device *dev) @@ -486,4 +314,3 @@ int psb_runtime_idle(struct device *dev) else return 1; } - diff --git a/drivers/staging/gma500/psb_powermgmt.h b/drivers/staging/gma500/power.h index e005229..1969d2e 100644 --- a/drivers/staging/gma500/psb_powermgmt.h +++ b/drivers/staging/gma500/power.h @@ -1,5 +1,5 @@ /************************************************************************** - * Copyright (c) 2009, Intel Corporation. + * Copyright (c) 2009-2011, Intel Corporation. * All Rights Reserved. * Permission is hereby granted, free of charge, to any person obtaining a @@ -39,8 +39,8 @@ void gma_power_uninit(struct drm_device *dev); /* * The kernel bus power management will call these functions */ -int gma_power_suspend(struct pci_dev *pdev, pm_message_t state); -int gma_power_resume(struct pci_dev *pdev); +int gma_power_suspend(struct device *dev); +int gma_power_resume(struct device *dev); /* * These are the functions the driver should use to wrap all hw access diff --git a/drivers/staging/gma500/psb_bl.c b/drivers/staging/gma500/psb_bl.c deleted file mode 100644 index 5dffc71..0000000 --- a/drivers/staging/gma500/psb_bl.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * psb backlight interface - * - * Copyright (c) 2009, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Authors: Eric Knopp - * - */ - -#include <linux/backlight.h> -#include <linux/version.h> -#include "psb_drv.h" -#include "psb_intel_reg.h" -#include "psb_intel_drv.h" -#include "psb_intel_bios.h" -#include "psb_powermgmt.h" - -#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_MASK 0xFF -#define BLC_POLARITY_NORMAL 0 -#define BLC_POLARITY_INVERSE 1 -#define BLC_ADJUSTMENT_MAX 100 - -#define PSB_BLC_PWM_PRECISION_FACTOR 10 -#define PSB_BLC_MAX_PWM_REG_FREQ 0xFFFE -#define PSB_BLC_MIN_PWM_REG_FREQ 0x2 - -#define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) -#define PSB_BACKLIGHT_PWM_CTL_SHIFT (16) - -static int psb_brightness; -static struct backlight_device *psb_backlight_device; -static u8 blc_brightnesscmd; -static u8 blc_pol; -static u8 blc_type; - -int psb_set_brightness(struct backlight_device *bd) -{ - struct drm_device *dev = bl_get_data(psb_backlight_device); - int level = bd->props.brightness; - - DRM_DEBUG_DRIVER("backlight level set to %d\n", level); - - /* Percentage 1-100% being valid */ - if (level < 1) - level = 1; - - psb_intel_lvds_set_brightness(dev, level); - psb_brightness = level; - return 0; -} - -int mrst_set_brightness(struct backlight_device *bd) -{ - struct drm_device *dev = bl_get_data(psb_backlight_device); - struct drm_psb_private *dev_priv = dev->dev_private; - int level = bd->props.brightness; - u32 blc_pwm_ctl; - u32 max_pwm_blc; - - DRM_DEBUG_DRIVER("backlight level set to %d\n", level); - - /* Percentage 1-100% being valid */ - if (level < 1) - level = 1; - - if (gma_power_begin(dev, 0)) { - /* Calculate and set the brightness value */ - max_pwm_blc = REG_READ(BLC_PWM_CTL) >> 16; - blc_pwm_ctl = level * max_pwm_blc / 100; - - /* Adjust the backlight level with the percent in - * dev_priv->blc_adj1; - */ - blc_pwm_ctl = blc_pwm_ctl * dev_priv->blc_adj1; - blc_pwm_ctl = blc_pwm_ctl / 100; - - /* Adjust the backlight level with the percent in - * dev_priv->blc_adj2; - */ - blc_pwm_ctl = blc_pwm_ctl * dev_priv->blc_adj2; - blc_pwm_ctl = blc_pwm_ctl / 100; - - if (blc_pol == BLC_POLARITY_INVERSE) - blc_pwm_ctl = max_pwm_blc - blc_pwm_ctl; - /* force PWM bit on */ - REG_WRITE(BLC_PWM_CTL2, (0x80000000 | REG_READ(BLC_PWM_CTL2))); - REG_WRITE(BLC_PWM_CTL, (max_pwm_blc << 16) | blc_pwm_ctl); - gma_power_end(dev); - } - psb_brightness = level; - return 0; -} - -int psb_get_brightness(struct backlight_device *bd) -{ - DRM_DEBUG_DRIVER("brightness = 0x%x\n", psb_brightness); - - /* return locally cached var instead of HW read (due to DPST etc.) */ - /* FIXME: ideally return actual value in case firmware fiddled with - it */ - return psb_brightness; -} - -static const struct backlight_ops psb_ops = { - .get_brightness = psb_get_brightness, - .update_status = psb_set_brightness, -}; - -static int device_backlight_init(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - unsigned long core_clock; - /* u32 bl_max_freq; */ - /* unsigned long value; */ - u16 bl_max_freq; - uint32_t value; - uint32_t blc_pwm_precision_factor; - - if (IS_MRST(dev)) { - dev_priv->blc_adj1 = BLC_ADJUSTMENT_MAX; - dev_priv->blc_adj2 = BLC_ADJUSTMENT_MAX; - bl_max_freq = 256; - /* this needs to be set elsewhere */ - blc_pol = BLC_POLARITY_NORMAL; - blc_pwm_precision_factor = BLC_PWM_PRECISION_FACTOR; - } else { - /* get bl_max_freq and pol from dev_priv*/ - if (!dev_priv->lvds_bl) { - DRM_ERROR("Has no valid LVDS backlight info\n"); - return 1; - } - bl_max_freq = dev_priv->lvds_bl->freq; - blc_pol = dev_priv->lvds_bl->pol; - blc_pwm_precision_factor = PSB_BLC_PWM_PRECISION_FACTOR; - blc_brightnesscmd = dev_priv->lvds_bl->brightnesscmd; - blc_type = dev_priv->lvds_bl->type; - } - - core_clock = dev_priv->core_freq; - - value = (core_clock * MHz) / BLC_PWM_FREQ_CALC_CONSTANT; - value *= blc_pwm_precision_factor; - value /= bl_max_freq; - value /= blc_pwm_precision_factor; - - if (gma_power_begin(dev, false)) { - if (IS_MRST(dev)) { - if (value > (unsigned long long)MRST_BLC_MAX_PWM_REG_FREQ) - return 2; - else { - REG_WRITE(BLC_PWM_CTL2, - (0x80000000 | REG_READ(BLC_PWM_CTL2))); - REG_WRITE(BLC_PWM_CTL, value | (value << 16)); - } - } else { - if (value > (unsigned long long)PSB_BLC_MAX_PWM_REG_FREQ || - value < (unsigned long long)PSB_BLC_MIN_PWM_REG_FREQ) - return 2; - else { - value &= PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR; - REG_WRITE(BLC_PWM_CTL, - (value << PSB_BACKLIGHT_PWM_CTL_SHIFT) | - (value)); - } - } - gma_power_end(dev); - } - return 0; -} - -int psb_backlight_init(struct drm_device *dev) -{ -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE - int ret = 0; - - struct backlight_properties props; - memset(&props, 0, sizeof(struct backlight_properties)); - props.max_brightness = 100; - props.type = BACKLIGHT_PLATFORM; - - psb_backlight_device = backlight_device_register("psb-bl", NULL, - (void *)dev, &psb_ops, &props); - if (IS_ERR(psb_backlight_device)) - return PTR_ERR(psb_backlight_device); - - ret = device_backlight_init(dev); - if (ret < 0) - return ret; - - psb_backlight_device->props.brightness = 100; - psb_backlight_device->props.max_brightness = 100; - backlight_update_status(psb_backlight_device); -#endif - return 0; -} - -void psb_backlight_exit(void) -{ -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE - psb_backlight_device->props.brightness = 0; - backlight_update_status(psb_backlight_device); - backlight_device_unregister(psb_backlight_device); -#endif -} - -struct backlight_device *psb_get_backlight_device(void) -{ - return psb_backlight_device; -} diff --git a/drivers/staging/gma500/psb_device.c b/drivers/staging/gma500/psb_device.c new file mode 100644 index 0000000..4659132 --- /dev/null +++ b/drivers/staging/gma500/psb_device.c @@ -0,0 +1,353 @@ +/************************************************************************** + * Copyright (c) 2011, Intel Corporation. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + **************************************************************************/ + +#include <linux/backlight.h> +#include <drm/drmP.h> +#include <drm/drm.h> +#include "psb_drm.h" +#include "psb_drv.h" +#include "psb_reg.h" +#include "psb_intel_reg.h" +#include "intel_bios.h" + + +static int psb_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); + return 0; +} + +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + +/* + * Poulsbo Backlight Interfaces + */ + +#define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */ +#define BLC_PWM_FREQ_CALC_CONSTANT 32 +#define MHz 1000000 + +#define PSB_BLC_PWM_PRECISION_FACTOR 10 +#define PSB_BLC_MAX_PWM_REG_FREQ 0xFFFE +#define PSB_BLC_MIN_PWM_REG_FREQ 0x2 + +#define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) +#define PSB_BACKLIGHT_PWM_CTL_SHIFT (16) + +static int psb_brightness; +static struct backlight_device *psb_backlight_device; + +static int psb_get_brightness(struct backlight_device *bd) +{ + /* return locally cached var instead of HW read (due to DPST etc.) */ + /* FIXME: ideally return actual value in case firmware fiddled with + it */ + return psb_brightness; +} + + +static int psb_backlight_setup(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + unsigned long core_clock; + /* u32 bl_max_freq; */ + /* unsigned long value; */ + u16 bl_max_freq; + uint32_t value; + uint32_t blc_pwm_precision_factor; + + /* get bl_max_freq and pol from dev_priv*/ + if (!dev_priv->lvds_bl) { + dev_err(dev->dev, "Has no valid LVDS backlight info\n"); + return -ENOENT; + } + bl_max_freq = dev_priv->lvds_bl->freq; + blc_pwm_precision_factor = PSB_BLC_PWM_PRECISION_FACTOR; + + core_clock = dev_priv->core_freq; + + value = (core_clock * MHz) / BLC_PWM_FREQ_CALC_CONSTANT; + value *= blc_pwm_precision_factor; + value /= bl_max_freq; + value /= blc_pwm_precision_factor; + + if (value > (unsigned long long)PSB_BLC_MAX_PWM_REG_FREQ || + value < (unsigned long long)PSB_BLC_MIN_PWM_REG_FREQ) + return -ERANGE; + else { + value &= PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR; + REG_WRITE(BLC_PWM_CTL, + (value << PSB_BACKLIGHT_PWM_CTL_SHIFT) | (value)); + } + return 0; +} + +static int psb_set_brightness(struct backlight_device *bd) +{ + struct drm_device *dev = bl_get_data(psb_backlight_device); + int level = bd->props.brightness; + + /* Percentage 1-100% being valid */ + if (level < 1) + level = 1; + + psb_intel_lvds_set_brightness(dev, level); + psb_brightness = level; + return 0; +} + +static const struct backlight_ops psb_ops = { + .get_brightness = psb_get_brightness, + .update_status = psb_set_brightness, +}; + +static int psb_backlight_init(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + int ret; + struct backlight_properties props; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = 100; + props.type = BACKLIGHT_PLATFORM; + + psb_backlight_device = backlight_device_register("psb-bl", + NULL, (void *)dev, &psb_ops, &props); + if (IS_ERR(psb_backlight_device)) + return PTR_ERR(psb_backlight_device); + + ret = psb_backlight_setup(dev); + if (ret < 0) { + backlight_device_unregister(psb_backlight_device); + psb_backlight_device = NULL; + return ret; + } + psb_backlight_device->props.brightness = 100; + psb_backlight_device->props.max_brightness = 100; + backlight_update_status(psb_backlight_device); + dev_priv->backlight_device = psb_backlight_device; + return 0; +} + +#endif + +/* + * Provide the Poulsbo specific chip logic and low level methods + * for power management + */ + +static void psb_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); +} + +/** + * psb_save_display_registers - save registers lost on suspend + * @dev: our DRM device + * + * Save the state we need in order to be able to restore the interface + * upon resume from suspend + */ +static int psb_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; +} + +/** + * psb_restore_display_registers - restore lost register state + * @dev: our DRM device + * + * Restore register state that was lost during suspend and resume. + */ +static int psb_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; +} + +static int psb_power_down(struct drm_device *dev) +{ + return 0; +} + +static int psb_power_up(struct drm_device *dev) +{ + return 0; +} + +static void psb_get_core_freq(struct drm_device *dev) +{ + uint32_t clock; + 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); + + switch (clock & 0x07) { + case 0: + dev_priv->core_freq = 100; + break; + case 1: + dev_priv->core_freq = 133; + break; + case 2: + dev_priv->core_freq = 150; + break; + case 3: + dev_priv->core_freq = 178; + break; + case 4: + dev_priv->core_freq = 200; + break; + case 5: + case 6: + case 7: + dev_priv->core_freq = 266; + default: + dev_priv->core_freq = 0; + } +} + +static int psb_chip_setup(struct drm_device *dev) +{ + psb_get_core_freq(dev); + gma_intel_opregion_init(dev); + psb_intel_init_bios(dev); + return 0; +} + +const struct psb_ops psb_chip_ops = { + .name = "Poulsbo", + .accel_2d = 1, + .pipes = 2, + .crtcs = 2, + .sgx_offset = PSB_SGX_OFFSET, + .chip_setup = psb_chip_setup, + + .crtc_helper = &psb_intel_helper_funcs, + .crtc_funcs = &psb_intel_crtc_funcs, + + .output_init = psb_output_init, + +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + .backlight_init = psb_backlight_init, +#endif + + .init_pm = psb_init_pm, + .save_regs = psb_save_display_registers, + .restore_regs = psb_restore_display_registers, + .power_down = psb_power_down, + .power_up = psb_power_up, +}; + diff --git a/drivers/staging/gma500/psb_drm.h b/drivers/staging/gma500/psb_drm.h index 49ffdd5..0da8468 100644 --- a/drivers/staging/gma500/psb_drm.h +++ b/drivers/staging/gma500/psb_drm.h @@ -1,5 +1,5 @@ /************************************************************************** - * Copyright (c) 2007, Intel Corporation. + * Copyright (c) 2007-2011, Intel Corporation. * All Rights Reserved. * Copyright (c) 2008, Tungsten Graphics Inc. Cedar Park, TX., USA. * All Rights Reserved. @@ -22,84 +22,8 @@ #ifndef _PSB_DRM_H_ #define _PSB_DRM_H_ -#if defined(__linux__) && !defined(__KERNEL__) -#include<stdint.h> -#include <linux/types.h> -#include "drm_mode.h" -#endif - -#define DRM_PSB_SAREA_MAJOR 0 -#define DRM_PSB_SAREA_MINOR 2 -#define PSB_FIXED_SHIFT 16 - #define PSB_NUM_PIPE 3 -/* - * Public memory types. - */ - -typedef s32 psb_fixed; -typedef u32 psb_ufixed; - -static inline s32 psb_int_to_fixed(int a) -{ - return a * (1 << PSB_FIXED_SHIFT); -} - -static inline u32 psb_unsigned_to_ufixed(unsigned int a) -{ - return a << PSB_FIXED_SHIFT; -} - -/*Status of the command sent to the gfx device.*/ -typedef enum { - DRM_CMD_SUCCESS, - DRM_CMD_FAILED, - DRM_CMD_HANG -} drm_cmd_status_t; - -struct drm_psb_scanout { - u32 buffer_id; /* DRM buffer object ID */ - u32 rotation; /* Rotation as in RR_rotation definitions */ - u32 stride; /* Buffer stride in bytes */ - u32 depth; /* Buffer depth in bits (NOT) bpp */ - u32 width; /* Buffer width in pixels */ - u32 height; /* Buffer height in lines */ - s32 transform[3][3]; /* Buffer composite transform */ - /* (scaling, rot, reflect) */ -}; - -#define DRM_PSB_SAREA_OWNERS 16 -#define DRM_PSB_SAREA_OWNER_2D 0 -#define DRM_PSB_SAREA_OWNER_3D 1 - -#define DRM_PSB_SAREA_SCANOUTS 3 - -struct drm_psb_sarea { - /* Track changes of this data structure */ - - u32 major; - u32 minor; - - /* Last context to touch part of hw */ - u32 ctx_owners[DRM_PSB_SAREA_OWNERS]; - - /* Definition of front- and rotated buffers */ - u32 num_scanouts; - struct drm_psb_scanout scanouts[DRM_PSB_SAREA_SCANOUTS]; - - int planeA_x; - int planeA_y; - int planeA_w; - int planeA_h; - int planeB_x; - int planeB_y; - int planeB_w; - int planeB_h; - /* Number of active scanouts */ - u32 num_active_scanouts; -}; - #define PSB_GPU_ACCESS_READ (1ULL << 32) #define PSB_GPU_ACCESS_WRITE (1ULL << 33) #define PSB_GPU_ACCESS_MASK (PSB_GPU_ACCESS_READ | PSB_GPU_ACCESS_WRITE) @@ -194,10 +118,10 @@ struct drm_psb_register_rw_arg { u32 OGAMC3; u32 OGAMC4; u32 OGAMC5; - u32 IEP_ENABLED; - u32 IEP_BLE_MINMAX; - u32 IEP_BSSCC_CONTROL; - u32 b_wait_vblank; + u32 IEP_ENABLED; + u32 IEP_BLE_MINMAX; + u32 IEP_BSSCC_CONTROL; + u32 b_wait_vblank; } overlay; u32 sprite_enable_mask; @@ -221,44 +145,27 @@ struct drm_psb_register_rw_arg { /* Controlling the kernel modesetting buffers */ -#define DRM_PSB_KMS_OFF 0x00 -#define DRM_PSB_KMS_ON 0x01 -#define DRM_PSB_VT_LEAVE 0x02 -#define DRM_PSB_VT_ENTER 0x03 -#define DRM_PSB_EXTENSION 0x06 #define DRM_PSB_SIZES 0x07 #define DRM_PSB_FUSE_REG 0x08 -#define DRM_PSB_VBT 0x09 #define DRM_PSB_DC_STATE 0x0A #define DRM_PSB_ADB 0x0B #define DRM_PSB_MODE_OPERATION 0x0C #define DRM_PSB_STOLEN_MEMORY 0x0D #define DRM_PSB_REGISTER_RW 0x0E -#define DRM_PSB_GTT_MAP 0x0F -#define DRM_PSB_GTT_UNMAP 0x10 -#define DRM_PSB_GETPAGEADDRS 0x11 -/** + +/* * NOTE: Add new commands here, but increment * the values below and increment their * corresponding defines where they're * defined elsewhere. */ -#define DRM_PVR_RESERVED1 0x12 -#define DRM_PVR_RESERVED2 0x13 -#define DRM_PVR_RESERVED3 0x14 -#define DRM_PVR_RESERVED4 0x15 -#define DRM_PVR_RESERVED5 0x16 - -#define DRM_PSB_HIST_ENABLE 0x17 -#define DRM_PSB_HIST_STATUS 0x18 -#define DRM_PSB_UPDATE_GUARD 0x19 -#define DRM_PSB_INIT_COMM 0x1A + +#define DRM_PSB_GEM_CREATE 0x10 +#define DRM_PSB_2D_OP 0x11 +#define DRM_PSB_GEM_MMAP 0x12 #define DRM_PSB_DPST 0x1B #define DRM_PSB_GAMMA 0x1C #define DRM_PSB_DPST_BL 0x1D - -#define DRM_PVR_RESERVED6 0x1E - #define DRM_PSB_GET_PIPE_FROM_CRTC_ID 0x1F #define PSB_MODE_OPERATION_MODE_VALID 0x01 @@ -272,4 +179,41 @@ struct drm_psb_get_pipe_from_crtc_id_arg { u32 pipe; }; +/* FIXME: move this into a medfield header once we are sure it isn't needed for an + ioctl */ +struct psb_drm_dpu_rect { + int x, y; + int width, height; +}; + +struct drm_psb_gem_create { + __u64 size; + __u32 handle; + __u32 flags; +#define PSB_GEM_CREATE_STOLEN 1 /* Stolen memory can be used */ +}; + +#define PSB_2D_OP_BUFLEN 16 + +struct drm_psb_2d_op { + __u32 src; /* Handles, only src supported right now */ + __u32 dst; + __u32 mask; + __u32 pat; + __u32 size; /* In dwords of command */ + __u32 spare; /* And bumps array to u64 align */ + __u32 cmd[PSB_2D_OP_BUFLEN]; +}; + +struct drm_psb_gem_mmap { + __u32 handle; + __u32 pad; + /** + * Fake offset to use for subsequent mmap call + * + * This is a fixed-size type for 32/64 compatibility. + */ + __u64 offset; +}; + #endif diff --git a/drivers/staging/gma500/psb_drv.c b/drivers/staging/gma500/psb_drv.c index aa87b1b..b2cdce7 100644 --- a/drivers/staging/gma500/psb_drv.c +++ b/drivers/staging/gma500/psb_drv.c @@ -1,5 +1,5 @@ /************************************************************************** - * Copyright (c) 2007, Intel Corporation. + * Copyright (c) 2007-2011, Intel Corporation. * All Rights Reserved. * Copyright (c) 2008, Tungsten Graphics, Inc. Cedar Park, TX., USA. * All Rights Reserved. @@ -23,44 +23,65 @@ #include <drm/drm.h> #include "psb_drm.h" #include "psb_drv.h" -#include "psb_fb.h" +#include "framebuffer.h" #include "psb_reg.h" #include "psb_intel_reg.h" -#include "psb_intel_bios.h" +#include "intel_bios.h" +#include "mid_bios.h" +#include "mdfld_dsi_dbi.h" #include <drm/drm_pciids.h> -#include "psb_powermgmt.h" +#include "power.h" #include <linux/cpu.h> #include <linux/notifier.h> #include <linux/spinlock.h> #include <linux/pm_runtime.h> #include <acpi/video.h> -int drm_psb_debug; static int drm_psb_trap_pagefaults; int drm_psb_no_fb; static int psb_probe(struct pci_dev *pdev, const struct pci_device_id *ent); -MODULE_PARM_DESC(debug, "Enable debug output"); MODULE_PARM_DESC(no_fb, "Disable FBdev"); MODULE_PARM_DESC(trap_pagefaults, "Error and reset on MMU pagefaults"); -module_param_named(debug, drm_psb_debug, int, 0600); module_param_named(no_fb, drm_psb_no_fb, int, 0600); module_param_named(trap_pagefaults, drm_psb_trap_pagefaults, int, 0600); -static struct pci_device_id pciidlist[] = { - { 0x8086, 0x8108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PSB_8108 }, - { 0x8086, 0x8109, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PSB_8109 }, - { 0x8086, 0x4100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MRST_4100}, - { 0x8086, 0x4101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MRST_4100}, - { 0x8086, 0x4102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MRST_4100}, - { 0x8086, 0x4103, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MRST_4100}, - { 0x8086, 0x4104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MRST_4100}, - { 0x8086, 0x4105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MRST_4100}, - { 0x8086, 0x4106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MRST_4100}, - { 0x8086, 0x4107, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MRST_4100}, +static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { + { 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_PSB_MRST) + { 0x8086, 0x4100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mrst_chip_ops}, + { 0x8086, 0x4101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mrst_chip_ops}, + { 0x8086, 0x4102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mrst_chip_ops}, + { 0x8086, 0x4103, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mrst_chip_ops}, + { 0x8086, 0x4104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mrst_chip_ops}, + { 0x8086, 0x4105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mrst_chip_ops}, + { 0x8086, 0x4106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mrst_chip_ops}, + { 0x8086, 0x4107, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mrst_chip_ops}, +#endif +#if defined(CONFIG_DRM_PSB_MFLD) + { 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_PSB_CDV) + { 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}, + { 0x8086, 0x0be3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, + { 0x8086, 0x0be4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, + { 0x8086, 0x0be5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, + { 0x8086, 0x0be6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, + { 0x8086, 0x0be7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, +#endif { 0, 0, 0} }; MODULE_DEVICE_TABLE(pci, pciidlist); @@ -69,10 +90,6 @@ MODULE_DEVICE_TABLE(pci, pciidlist); * Standard IOCTLs. */ -#define DRM_IOCTL_PSB_KMS_OFF \ - DRM_IO(DRM_PSB_KMS_OFF + DRM_COMMAND_BASE) -#define DRM_IOCTL_PSB_KMS_ON \ - DRM_IO(DRM_PSB_KMS_ON + DRM_COMMAND_BASE) #define DRM_IOCTL_PSB_SIZES \ DRM_IOR(DRM_PSB_SIZES + DRM_COMMAND_BASE, \ struct drm_psb_sizes_arg) @@ -104,6 +121,15 @@ MODULE_DEVICE_TABLE(pci, pciidlist); #define DRM_IOCTL_PSB_GET_PIPE_FROM_CRTC_ID \ DRM_IOWR(DRM_PSB_GET_PIPE_FROM_CRTC_ID + DRM_COMMAND_BASE, \ struct drm_psb_get_pipe_from_crtc_id_arg) +#define DRM_IOCTL_PSB_GEM_CREATE \ + DRM_IOWR(DRM_PSB_GEM_CREATE + DRM_COMMAND_BASE, \ + struct drm_psb_gem_create) +#define DRM_IOCTL_PSB_2D_OP \ + DRM_IOW(DRM_PSB_2D_OP + DRM_COMMAND_BASE, \ + struct drm_psb_2d_op) +#define DRM_IOCTL_PSB_GEM_MMAP \ + DRM_IOWR(DRM_PSB_GEM_MMAP + DRM_COMMAND_BASE, \ + struct drm_psb_gem_mmap) static int psb_sizes_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -128,11 +154,6 @@ static int psb_dpst_bl_ioctl(struct drm_device *dev, void *data, [DRM_IOCTL_NR(ioctl) - DRM_COMMAND_BASE] = {ioctl, flags, func} static struct drm_ioctl_desc psb_ioctls[] = { - PSB_IOCTL_DEF(DRM_IOCTL_PSB_KMS_OFF, psbfb_kms_off_ioctl, - DRM_ROOT_ONLY), - PSB_IOCTL_DEF(DRM_IOCTL_PSB_KMS_ON, - psbfb_kms_on_ioctl, - DRM_ROOT_ONLY), PSB_IOCTL_DEF(DRM_IOCTL_PSB_SIZES, psb_sizes_ioctl, DRM_AUTH), PSB_IOCTL_DEF(DRM_IOCTL_PSB_DC_STATE, psb_dc_state_ioctl, DRM_AUTH), PSB_IOCTL_DEF(DRM_IOCTL_PSB_ADB, psb_adb_ioctl, DRM_AUTH), @@ -147,7 +168,12 @@ static struct drm_ioctl_desc psb_ioctls[] = { PSB_IOCTL_DEF(DRM_IOCTL_PSB_DPST_BL, psb_dpst_bl_ioctl, DRM_AUTH), PSB_IOCTL_DEF(DRM_IOCTL_PSB_GET_PIPE_FROM_CRTC_ID, psb_intel_get_pipe_from_crtc_id, 0), - + PSB_IOCTL_DEF(DRM_IOCTL_PSB_GEM_CREATE, psb_gem_create_ioctl, + DRM_UNLOCKED | DRM_AUTH), + PSB_IOCTL_DEF(DRM_IOCTL_PSB_2D_OP, psb_accel_ioctl, + DRM_UNLOCKED| DRM_AUTH), + PSB_IOCTL_DEF(DRM_IOCTL_PSB_GEM_MMAP, psb_gem_mmap_ioctl, + DRM_UNLOCKED | DRM_AUTH), }; static void psb_lastclose(struct drm_device *dev) @@ -160,262 +186,17 @@ static void psb_do_takedown(struct drm_device *dev) /* FIXME: do we need to clean up the gtt here ? */ } -void mrst_get_fuse_settings(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0); - uint32_t fuse_value = 0; - uint32_t fuse_value_tmp = 0; - -#define FB_REG06 0xD0810600 -#define FB_MIPI_DISABLE (1 << 11) -#define FB_REG09 0xD0810900 -#define FB_REG09 0xD0810900 -#define FB_SKU_MASK 0x7000 -#define FB_SKU_SHIFT 12 -#define FB_SKU_100 0 -#define FB_SKU_100L 1 -#define FB_SKU_83 2 - pci_write_config_dword(pci_root, 0xD0, FB_REG06); - pci_read_config_dword(pci_root, 0xD4, &fuse_value); - - dev_priv->iLVDS_enable = fuse_value & FB_MIPI_DISABLE; - - DRM_INFO("internal display is %s\n", - dev_priv->iLVDS_enable ? "LVDS display" : "MIPI display"); - - /*prevent Runtime suspend at start*/ - if (dev_priv->iLVDS_enable) { - dev_priv->is_lvds_on = true; - dev_priv->is_mipi_on = false; - } - else { - dev_priv->is_mipi_on = true; - dev_priv->is_lvds_on = false; - } - - dev_priv->video_device_fuse = fuse_value; - - pci_write_config_dword(pci_root, 0xD0, FB_REG09); - pci_read_config_dword(pci_root, 0xD4, &fuse_value); - - DRM_INFO("SKU values is 0x%x. \n", fuse_value); - fuse_value_tmp = (fuse_value & FB_SKU_MASK) >> FB_SKU_SHIFT; - - dev_priv->fuse_reg_value = fuse_value; - - switch (fuse_value_tmp) { - case FB_SKU_100: - dev_priv->core_freq = 200; - break; - case FB_SKU_100L: - dev_priv->core_freq = 100; - break; - case FB_SKU_83: - dev_priv->core_freq = 166; - break; - default: - DRM_ERROR("Invalid SKU values, SKU value = 0x%08x\n", fuse_value_tmp); - dev_priv->core_freq = 0; - } - DRM_INFO("LNC core clk is %dMHz.\n", dev_priv->core_freq); - pci_dev_put(pci_root); -} - -void mid_get_pci_revID (struct drm_psb_private *dev_priv) -{ - uint32_t platform_rev_id = 0; - struct pci_dev *pci_gfx_root = pci_get_bus_and_slot(0, PCI_DEVFN(2, 0)); - - /*get the revison ID, B0:D2:F0;0x08 */ - pci_read_config_dword(pci_gfx_root, 0x08, &platform_rev_id); - dev_priv->platform_rev_id = (uint8_t) platform_rev_id; - pci_dev_put(pci_gfx_root); - PSB_DEBUG_ENTRY("platform_rev_id is %x\n", dev_priv->platform_rev_id); -} - -void mrst_get_vbt_data(struct drm_psb_private *dev_priv) -{ - struct mrst_vbt *vbt = &dev_priv->vbt_data; - u32 platform_config_address; - u16 new_size; - u8 *vbt_virtual; - u8 bpi; - u8 number_desc = 0; - struct mrst_timing_info *dp_ti = &dev_priv->gct_data.DTD; - struct gct_r10_timing_info ti; - void *pGCT; - struct pci_dev *pci_gfx_root = pci_get_bus_and_slot(0, PCI_DEVFN(2, 0)); - - /*get the address of the platform config vbt, B0:D2:F0;0xFC */ - pci_read_config_dword(pci_gfx_root, 0xFC, &platform_config_address); - pci_dev_put(pci_gfx_root); - DRM_INFO("drm platform config address is %x\n", - platform_config_address); - - /* check for platform config address == 0. */ - /* this means fw doesn't support vbt */ - - if (platform_config_address == 0) { - vbt->size = 0; - return; - } - - /* get the virtual address of the vbt */ - vbt_virtual = ioremap(platform_config_address, sizeof(*vbt)); - - memcpy(vbt, vbt_virtual, sizeof(*vbt)); - iounmap(vbt_virtual); /* Free virtual address space */ - - printk(KERN_ALERT "GCT revision is %x\n", vbt->revision); - - switch (vbt->revision) { - case 0: - vbt->mrst_gct = NULL; - vbt->mrst_gct = \ - ioremap(platform_config_address + sizeof(*vbt) - 4, - vbt->size - sizeof(*vbt) + 4); - pGCT = vbt->mrst_gct; - bpi = ((struct mrst_gct_v1 *)pGCT)->PD.BootPanelIndex; - dev_priv->gct_data.bpi = bpi; - dev_priv->gct_data.pt = - ((struct mrst_gct_v1 *)pGCT)->PD.PanelType; - memcpy(&dev_priv->gct_data.DTD, - &((struct mrst_gct_v1 *)pGCT)->panel[bpi].DTD, - sizeof(struct mrst_timing_info)); - dev_priv->gct_data.Panel_Port_Control = - ((struct mrst_gct_v1 *)pGCT)->panel[bpi].Panel_Port_Control; - dev_priv->gct_data.Panel_MIPI_Display_Descriptor = - ((struct mrst_gct_v1 *)pGCT)->panel[bpi].Panel_MIPI_Display_Descriptor; - break; - case 1: - vbt->mrst_gct = NULL; - vbt->mrst_gct = \ - ioremap(platform_config_address + sizeof(*vbt) - 4, - vbt->size - sizeof(*vbt) + 4); - pGCT = vbt->mrst_gct; - bpi = ((struct mrst_gct_v2 *)pGCT)->PD.BootPanelIndex; - dev_priv->gct_data.bpi = bpi; - dev_priv->gct_data.pt = - ((struct mrst_gct_v2 *)pGCT)->PD.PanelType; - memcpy(&dev_priv->gct_data.DTD, - &((struct mrst_gct_v2 *)pGCT)->panel[bpi].DTD, - sizeof(struct mrst_timing_info)); - dev_priv->gct_data.Panel_Port_Control = - ((struct mrst_gct_v2 *)pGCT)->panel[bpi].Panel_Port_Control; - dev_priv->gct_data.Panel_MIPI_Display_Descriptor = - ((struct mrst_gct_v2 *)pGCT)->panel[bpi].Panel_MIPI_Display_Descriptor; - break; - case 0x10: - /*header definition changed from rev 01 (v2) to rev 10h. */ - /*so, some values have changed location*/ - new_size = vbt->checksum; /*checksum contains lo size byte*/ - /*LSB of mrst_gct contains hi size byte*/ - new_size |= ((0xff & (unsigned int)vbt->mrst_gct)) << 8; - - vbt->checksum = vbt->size; /*size contains the checksum*/ - if (new_size > 0xff) - vbt->size = 0xff; /*restrict size to 255*/ - else - vbt->size = new_size; - - /* number of descriptors defined in the GCT */ - number_desc = ((0xff00 & (unsigned int)vbt->mrst_gct)) >> 8; - bpi = ((0xff0000 & (unsigned int)vbt->mrst_gct)) >> 16; - vbt->mrst_gct = NULL; - vbt->mrst_gct = \ - ioremap(platform_config_address + GCT_R10_HEADER_SIZE, - GCT_R10_DISPLAY_DESC_SIZE * number_desc); - pGCT = vbt->mrst_gct; - pGCT = (u8 *)pGCT + (bpi*GCT_R10_DISPLAY_DESC_SIZE); - dev_priv->gct_data.bpi = bpi; /*save boot panel id*/ - - /*copy the GCT display timings into a temp structure*/ - memcpy(&ti, pGCT, sizeof(struct gct_r10_timing_info)); - - /*now copy the temp struct into the dev_priv->gct_data*/ - dp_ti->pixel_clock = ti.pixel_clock; - dp_ti->hactive_hi = ti.hactive_hi; - dp_ti->hactive_lo = ti.hactive_lo; - dp_ti->hblank_hi = ti.hblank_hi; - dp_ti->hblank_lo = ti.hblank_lo; - dp_ti->hsync_offset_hi = ti.hsync_offset_hi; - dp_ti->hsync_offset_lo = ti.hsync_offset_lo; - dp_ti->hsync_pulse_width_hi = ti.hsync_pulse_width_hi; - dp_ti->hsync_pulse_width_lo = ti.hsync_pulse_width_lo; - dp_ti->vactive_hi = ti.vactive_hi; - dp_ti->vactive_lo = ti.vactive_lo; - dp_ti->vblank_hi = ti.vblank_hi; - dp_ti->vblank_lo = ti.vblank_lo; - dp_ti->vsync_offset_hi = ti.vsync_offset_hi; - dp_ti->vsync_offset_lo = ti.vsync_offset_lo; - dp_ti->vsync_pulse_width_hi = ti.vsync_pulse_width_hi; - dp_ti->vsync_pulse_width_lo = ti.vsync_pulse_width_lo; - - /*mov the MIPI_Display_Descriptor data from GCT to dev priv*/ - dev_priv->gct_data.Panel_MIPI_Display_Descriptor = - *((u8 *)pGCT + 0x0d); - dev_priv->gct_data.Panel_MIPI_Display_Descriptor |= - (*((u8 *)pGCT + 0x0e)) << 8; - break; - default: - printk(KERN_ERR "Unknown revision of GCT!\n"); - vbt->size = 0; - } -} - -static void psb_get_core_freq(struct drm_device *dev) -{ - uint32_t clock; - 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); - - switch (clock & 0x07) { - case 0: - dev_priv->core_freq = 100; - break; - case 1: - dev_priv->core_freq = 133; - break; - case 2: - dev_priv->core_freq = 150; - break; - case 3: - dev_priv->core_freq = 178; - break; - case 4: - dev_priv->core_freq = 200; - break; - case 5: - case 6: - case 7: - dev_priv->core_freq = 266; - default: - dev_priv->core_freq = 0; - } -} - static int psb_do_init(struct drm_device *dev) { - struct drm_psb_private *dev_priv = - (struct drm_psb_private *) dev->dev_private; - struct psb_gtt *pg = dev_priv->pg; + struct drm_psb_private *dev_priv = dev->dev_private; + struct psb_gtt *pg = &dev_priv->gtt; uint32_t stolen_gtt; - uint32_t tt_start; - uint32_t tt_pages; int ret = -ENOMEM; if (pg->mmu_gatt_start & 0x0FFFFFFF) { - DRM_ERROR("Gatt must be 256M aligned. This is a bug.\n"); + dev_err(dev->dev, "Gatt must be 256M aligned. This is a bug.\n"); ret = -EINVAL; goto out_err; } @@ -448,24 +229,17 @@ static int psb_do_init(struct drm_device *dev) spin_lock_init(&dev_priv->irqmask_lock); - - tt_pages = (pg->gatt_pages < PSB_TT_PRIV0_PLIMIT) ? - pg->gatt_pages : PSB_TT_PRIV0_PLIMIT; - tt_start = dev_priv->gatt_free_offset - pg->mmu_gatt_start; - tt_pages -= tt_start >> PAGE_SHIFT; - /* FIXME: can we kill ta_mem_size ? */ - dev_priv->sizes.ta_mem_size = 0; + mutex_init(&dev_priv->mutex_2d); PSB_WSGX32(0x00000000, PSB_CR_BIF_BANK0); PSB_WSGX32(0x00000000, PSB_CR_BIF_BANK1); PSB_RSGX32(PSB_CR_BIF_BANK1); - PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) | _PSB_MMU_ER_MASK, + PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) | _PSB_MMU_ER_MASK, PSB_CR_BIF_CTRL); psb_spank(dev_priv); /* mmu_gatt ?? */ - PSB_WSGX32(pg->gatt_start, PSB_CR_BIF_TWOD_REQ_BASE); - + PSB_WSGX32(pg->gatt_start, PSB_CR_BIF_TWOD_REQ_BASE); return 0; out_err: psb_do_takedown(dev); @@ -474,19 +248,21 @@ out_err: static int psb_driver_unload(struct drm_device *dev) { - struct drm_psb_private *dev_priv = - (struct drm_psb_private *) dev->dev_private; + struct drm_psb_private *dev_priv = dev->dev_private; /* Kill vblank etc here */ - psb_backlight_exit(); /*writes minimum value to backlight HW reg */ + gma_backlight_exit(dev); if (drm_psb_no_fb == 0) psb_modeset_cleanup(dev); if (dev_priv) { psb_lid_timer_takedown(dev_priv); + gma_intel_opregion_exit(dev); + if (dev_priv->ops->chip_teardown) + dev_priv->ops->chip_teardown(dev); psb_do_takedown(dev); @@ -495,7 +271,7 @@ static int psb_driver_unload(struct drm_device *dev) dev_priv->pf_pd = NULL; } if (dev_priv->mmu) { - struct psb_gtt *pg = dev_priv->pg; + struct psb_gtt *pg = &dev_priv->gtt; down_read(&pg->sem); psb_mmu_remove_pfn_sequence( @@ -549,17 +325,12 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) if (dev_priv == NULL) return -ENOMEM; - if (IS_MRST(dev)) - dev_priv->num_pipe = 1; - else - dev_priv->num_pipe = 2; - + dev_priv->ops = (struct psb_ops *)chipset; dev_priv->dev = dev; - dev->dev_private = (void *) dev_priv; - dev_priv->chipset = chipset; - PSB_DEBUG_INIT("Mapping MMIO\n"); + dev_priv->num_pipe = dev_priv->ops->pipes; + resource_start = pci_resource_start(dev->pdev, PSB_MMIO_RESOURCE); dev_priv->vdc_reg = @@ -567,25 +338,14 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) if (!dev_priv->vdc_reg) goto out_err; - if (IS_MRST(dev)) - dev_priv->sgx_reg = ioremap(resource_start + MRST_SGX_OFFSET, - PSB_SGX_SIZE); - else - dev_priv->sgx_reg = ioremap(resource_start + PSB_SGX_OFFSET, + dev_priv->sgx_reg = ioremap(resource_start + dev_priv->ops->sgx_offset, PSB_SGX_SIZE); - if (!dev_priv->sgx_reg) goto out_err; - if (IS_MRST(dev)) { - mrst_get_fuse_settings(dev); - mrst_get_vbt_data(dev_priv); - mid_get_pci_revID(dev_priv); - } else { - psb_get_core_freq(dev); - psb_intel_opregion_init(dev); - psb_intel_init_bios(dev); - } + ret = dev_priv->ops->chip_setup(dev); + if (ret) + goto out_err; /* Init OSPM support */ gma_power_init(dev); @@ -608,7 +368,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) if (!dev_priv->mmu) goto out_err; - pg = dev_priv->pg; + pg = &dev_priv->gtt; tt_pages = (pg->gatt_pages < PSB_TT_PRIV0_PLIMIT) ? (pg->gatt_pages) : PSB_TT_PRIV0_PLIMIT; @@ -659,6 +419,10 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) dev->driver->get_vblank_counter = psb_get_vblank_counter; +#if defined(CONFIG_DRM_PSB_MFLD) + /* FIXME: this is not the right place for this stuff ! */ + mdfld_output_setup(dev); +#endif if (drm_psb_no_fb == 0) { psb_modeset_init(dev); psb_fbdev_init(dev); @@ -672,7 +436,8 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) switch (psb_intel_output->type) { case INTEL_OUTPUT_LVDS: - ret = psb_backlight_init(dev); + case INTEL_OUTPUT_MIPI: + ret = gma_backlight_init(dev); break; } } @@ -685,7 +450,6 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) pm_runtime_set_active(&dev->pdev->dev); #endif /*Intel drm driver load is done, continue doing pvr load*/ - DRM_DEBUG("Pvr driver load\n"); return 0; out_err: psb_driver_unload(dev); @@ -720,6 +484,11 @@ static int psb_dc_state_ioctl(struct drm_device *dev, void * data, struct drm_psb_dc_state_arg *arg = (struct drm_psb_dc_state_arg *)data; + + /* Double check MRST case */ + if (IS_MRST(dev) || IS_MFLD(dev)) + return -EOPNOTSUPP; + flags = arg->flags; obj_id = arg->obj_id; @@ -727,7 +496,7 @@ static int psb_dc_state_ioctl(struct drm_device *dev, void * data, obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_CRTC); if (!obj) { - DRM_DEBUG("Invalid CRTC object.\n"); + dev_dbg(dev->dev, "Invalid CRTC object.\n"); return -EINVAL; } @@ -747,7 +516,7 @@ static int psb_dc_state_ioctl(struct drm_device *dev, void * data, obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_CONNECTOR); if (!obj) { - DRM_DEBUG("Invalid connector id.\n"); + dev_dbg(dev->dev, "Invalid connector id.\n"); return -EINVAL; } @@ -759,23 +528,27 @@ static int psb_dc_state_ioctl(struct drm_device *dev, void * data, return 0; } - - DRM_DEBUG("Bad flags 0x%x\n", flags); return -EINVAL; } +static inline void get_brightness(struct backlight_device *bd) +{ +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + if (bd) { + bd->props.brightness = bd->ops->get_brightness(bd); + backlight_update_status(bd); + } +#endif +} + static int psb_dpst_bl_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_psb_private *dev_priv = psb_priv(dev); uint32_t *arg = data; - struct backlight_device bd; - dev_priv->blc_adj2 = *arg; -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE - bd.props.brightness = psb_get_brightness(&bd); - psb_set_brightness(&bd); -#endif + dev_priv->blc_adj2 = *arg; + get_brightness(dev_priv->backlight_device); return 0; } @@ -784,13 +557,9 @@ static int psb_adb_ioctl(struct drm_device *dev, void *data, { struct drm_psb_private *dev_priv = psb_priv(dev); uint32_t *arg = data; - struct backlight_device bd; - dev_priv->blc_adj1 = *arg; -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE - bd.props.brightness = psb_get_brightness(&bd); - psb_set_brightness(&bd); -#endif + dev_priv->blc_adj1 = *arg; + get_brightness(dev_priv->backlight_device); return 0; } @@ -838,7 +607,7 @@ static int psb_gamma_ioctl(struct drm_device *dev, void *data, obj_id = lut_arg->output_id; obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_CONNECTOR); if (!obj) { - DRM_DEBUG("Invalid Connector object.\n"); + dev_dbg(dev->dev, "Invalid Connector object.\n"); return -EINVAL; } @@ -879,7 +648,7 @@ static int psb_mode_operation_ioctl(struct drm_device *dev, void *data, case PSB_MODE_OPERATION_SET_DC_BASE: obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_FB); if (!obj) { - DRM_ERROR("Invalid FB id %d\n", obj_id); + dev_dbg(dev->dev, "Invalid FB id %d\n", obj_id); return -EINVAL; } @@ -951,7 +720,7 @@ mode_op_out: return ret; default: - DRM_DEBUG("Unsupported psb mode operation"); + dev_dbg(dev->dev, "Unsupported psb mode operation\n"); return -EOPNOTSUPP; } @@ -970,6 +739,7 @@ static int psb_stolen_memory_ioctl(struct drm_device *dev, void *data, return 0; } +/* FIXME: needs Medfield changes */ static int psb_register_rw_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -1342,9 +1112,6 @@ static long psb_unlocked_ioctl(struct file *filp, unsigned int cmd, struct drm_device *dev = file_priv->minor->dev; struct drm_psb_private *dev_priv = dev->dev_private; static unsigned int runtime_allowed; - unsigned int nr = DRM_IOCTL_NR(cmd); - - DRM_DEBUG("cmd = %x, nr = %x\n", cmd, nr); if (runtime_allowed == 1 && dev_priv->is_lvds_on) { runtime_allowed++; @@ -1352,7 +1119,6 @@ static long psb_unlocked_ioctl(struct file *filp, unsigned int cmd, dev_priv->rpm_enabled = 1; } return drm_ioctl(filp, cmd, arg); - /* FIXME: do we need to wrap the other side of this */ } @@ -1371,6 +1137,8 @@ static void psb_remove(struct pci_dev *pdev) } static const struct dev_pm_ops psb_pm_ops = { + .resume = gma_power_resume, + .suspend = gma_power_suspend, .runtime_suspend = psb_runtime_suspend, .runtime_resume = psb_runtime_resume, .runtime_idle = psb_runtime_idle, @@ -1384,7 +1152,7 @@ static struct vm_operations_struct psb_gem_vm_ops = { static struct drm_driver driver = { .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | \ - DRIVER_IRQ_VBL | DRIVER_MODESET| DRIVER_GEM , + DRIVER_IRQ_VBL | DRIVER_MODESET | DRIVER_GEM , .load = psb_driver_load, .unload = psb_driver_unload, @@ -1432,20 +1200,16 @@ static struct drm_driver driver = { static struct pci_driver psb_pci_driver = { .name = DRIVER_NAME, .id_table = pciidlist, - .resume = gma_power_resume, - .suspend = gma_power_suspend, .probe = psb_probe, .remove = psb_remove, -#ifdef CONFIG_PM .driver.pm = &psb_pm_ops, -#endif }; static int psb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { /* MLD Added this from Inaky's patch */ if (pci_enable_msi(pdev)) - DRM_ERROR("Enable MSI failed!\n"); + dev_warn(&pdev->dev, "Enable MSI failed!\n"); return drm_get_pci_dev(pdev, ent, &driver); } @@ -1462,6 +1226,6 @@ static void __exit psb_exit(void) late_initcall(psb_init); module_exit(psb_exit); -MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_AUTHOR("Alan Cox <alan@linux.intel.com> and others"); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/gma500/psb_drv.h b/drivers/staging/gma500/psb_drv.h index e19a454..72f487a 100644 --- a/drivers/staging/gma500/psb_drv.h +++ b/drivers/staging/gma500/psb_drv.h @@ -1,5 +1,5 @@ /************************************************************************** - * Copyright (c) 2007-2008, Intel Corporation. + * Copyright (c) 2007-2011, Intel Corporation. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it @@ -20,52 +20,48 @@ #ifndef _PSB_DRV_H_ #define _PSB_DRV_H_ -#include <linux/version.h> #include <linux/kref.h> #include <drm/drmP.h> #include "drm_global.h" +#include "gem_glue.h" #include "psb_drm.h" #include "psb_reg.h" #include "psb_intel_drv.h" -#include "psb_gtt.h" -#include "psb_powermgmt.h" +#include "gtt.h" +#include "power.h" #include "mrst.h" +#include "medfield.h" -/*Append new drm mode definition here, align with libdrm definition*/ -#define DRM_MODE_SCALE_NO_SCALE 2 +/* Append new drm mode definition here, align with libdrm definition */ +#define DRM_MODE_SCALE_NO_SCALE 2 +#define DRM_MODE_CONNECTOR_MIPI 15 enum { - CHIP_PSB_8108 = 0, - CHIP_PSB_8109 = 1, - CHIP_MRST_4100 = 2, + CHIP_PSB_8108 = 0, /* Poulsbo */ + CHIP_PSB_8109 = 1, /* Poulsbo */ + CHIP_MRST_4100 = 2, /* Moorestown/Oaktrail */ + CHIP_MFLD_0130 = 3, /* Medfield */ }; #define IS_MRST(dev) (((dev)->pci_device & 0xfffc) == 0x4100) +#define IS_MFLD(dev) (((dev)->pci_device & 0xfff8) == 0x0130) /* - *Hardware bugfixes + * Driver definitions */ -#define DRIVER_NAME "pvrsrvkm" -#define DRIVER_DESC "drm driver for the Intel GMA500" -#define DRIVER_AUTHOR "Intel Corporation" +#define DRIVER_NAME "gma500" +#define DRIVER_DESC "DRM driver for the Intel GMA500" -#define PSB_DRM_DRIVER_DATE "2009-03-10" -#define PSB_DRM_DRIVER_MAJOR 8 -#define PSB_DRM_DRIVER_MINOR 1 +#define PSB_DRM_DRIVER_DATE "2011-06-06" +#define PSB_DRM_DRIVER_MAJOR 1 +#define PSB_DRM_DRIVER_MINOR 0 #define PSB_DRM_DRIVER_PATCHLEVEL 0 /* - *TTM driver private offsets. + * Hardware offsets */ - -#define DRM_PSB_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT) - -#define PSB_OBJECT_HASH_ORDER 13 -#define PSB_FILE_OBJECT_HASH_ORDER 12 -#define PSB_BO_HASH_ORDER 12 - #define PSB_VDC_OFFSET 0x00000000 #define PSB_VDC_SIZE 0x000080000 #define MRST_MMIO_SIZE 0x0000C0000 @@ -73,42 +69,52 @@ enum { #define PSB_SGX_SIZE 0x8000 #define PSB_SGX_OFFSET 0x00040000 #define MRST_SGX_OFFSET 0x00080000 +/* + * PCI resource identifiers + */ #define PSB_MMIO_RESOURCE 0 #define PSB_GATT_RESOURCE 2 #define PSB_GTT_RESOURCE 3 +/* + * PCI configuration + */ #define PSB_GMCH_CTRL 0x52 #define PSB_BSM 0x5C #define _PSB_GMCH_ENABLED 0x4 #define PSB_PGETBL_CTL 0x2020 #define _PSB_PGETBL_ENABLED 0x00000001 #define PSB_SGX_2D_SLAVE_PORT 0x4000 + +/* To get rid of */ #define PSB_TT_PRIV0_LIMIT (256*1024*1024) #define PSB_TT_PRIV0_PLIMIT (PSB_TT_PRIV0_LIMIT >> PAGE_SHIFT) -#define PSB_NUM_VALIDATE_BUFFERS 2048 /* - *Flags for external memory type field. + * SGX side MMU definitions (these can probably go) */ +/* + * Flags for external memory type field. + */ #define PSB_MMU_CACHED_MEMORY 0x0001 /* Bind to MMU only */ #define PSB_MMU_RO_MEMORY 0x0002 /* MMU RO memory */ #define PSB_MMU_WO_MEMORY 0x0004 /* MMU WO memory */ - /* - *PTE's and PDE's + * PTE's and PDE's */ - #define PSB_PDE_MASK 0x003FFFFF #define PSB_PDE_SHIFT 22 #define PSB_PTE_SHIFT 12 - +/* + * Cache control + */ #define PSB_PTE_VALID 0x0001 /* PTE / PDE valid */ #define PSB_PTE_WO 0x0002 /* Write only */ #define PSB_PTE_RO 0x0004 /* Read only */ #define PSB_PTE_CACHED 0x0008 /* CPU cache coherent */ /* - *VDC registers and bits + * VDC registers and bits */ #define PSB_MSVDX_CLOCKGATING 0x2064 #define PSB_TOPAZ_CLOCKGATING 0x2068 @@ -130,8 +136,12 @@ enum { #define _LNC_IRQ_TOPAZ_FLAG (1<<20) /* 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 _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 @@ -197,10 +207,25 @@ enum { #define PSB_WATCHDOG_DELAY (DRM_HZ * 2) #define PSB_LID_DELAY (DRM_HZ / 10) -#define MDFLD_PNW_A0 0x00 #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 (DRM_HZ / MDFLD_DSR_RR) + #define PSB_PWR_STATE_ON 1 #define PSB_PWR_STATE_OFF 2 @@ -214,6 +239,12 @@ enum { #define PSB_PCIx_MSI_ADDR_LOC 0x94 #define PSB_PCIx_MSI_DATA_LOC 0x98 +/* Medfield crystal settings */ +#define KSEL_CRYSTAL_19 1 +#define KSEL_BYPASS_19 5 +#define KSEL_BYPASS_25 6 +#define KSEL_BYPASS_83_100 7 + struct opregion_header; struct opregion_acpi; struct opregion_swsci; @@ -227,13 +258,13 @@ struct psb_intel_opregion { int enabled; }; +struct psb_ops; struct drm_psb_private { struct drm_device *dev; + const struct psb_ops *ops; - unsigned long chipset; - - struct psb_gtt *pg; + struct psb_gtt gtt; /* GTT Memory manager */ struct psb_gtt_mm *gtt_mm; @@ -271,14 +302,14 @@ struct drm_psb_private { /* * Power - */ + */ bool suspended; bool display_power; int display_count; /* - *Modesetting + * Modesetting */ struct psb_intel_mode_device mode_dev; @@ -287,12 +318,8 @@ struct drm_psb_private { uint32_t num_pipe; /* - *Memory managers + * OSPM info (Power management base) (can go ?) */ - - /* - *OSPM info - */ uint32_t ospm_base; /* @@ -304,11 +331,11 @@ struct drm_psb_private { u32 fuse_reg_value; u32 video_device_fuse; - /* pci revision id for B0:D2:F0 */ + /* PCI revision ID for B0:D2:F0 */ uint8_t platform_rev_id; /* - *LVDS info + * LVDS info */ int backlight_duty_cycle; /* restore backlight to this value */ bool panel_wants_dither; @@ -316,10 +343,10 @@ struct drm_psb_private { struct drm_display_mode *lfp_lvds_vbt_mode; struct drm_display_mode *sdvo_lvds_vbt_mode; - struct bdb_lvds_backlight *lvds_bl; /*LVDS backlight info from VBT*/ + struct bdb_lvds_backlight *lvds_bl; /* LVDS backlight info from VBT */ struct psb_intel_i2c_chan *lvds_i2c_bus; - /* Feature bits from the VBIOS*/ + /* Feature bits from the VBIOS */ unsigned int int_tv_support:1; unsigned int lvds_dither:1; unsigned int lvds_vbt:1; @@ -328,17 +355,30 @@ struct drm_psb_private { int lvds_ssc_freq; bool is_lvds_on; bool is_mipi_on; + u32 mipi_ctrl_display; unsigned int core_freq; uint32_t iLVDS_enable; - /*runtime PM state*/ + /* Runtime PM state */ int rpm_enabled; - /* Moorestown specific */ + /* MID specific */ struct mrst_vbt vbt_data; struct mrst_gct_data gct_data; + /* MIPI Panel type etc */ + int panel_id; + bool dual_mipi; /* dual display - DPI & DBI */ + bool dpi_panel_on; /* The DPI panel power is on */ + bool dpi_panel_on2; /* The DPI panel power is on */ + bool dbi_panel_on; /* The DBI panel power is on */ + bool dbi_panel_on2; /* The DBI panel power is on */ + u32 dsr_fb_update; /* DSR FB update counter */ + + /* Moorestown HDMI state */ + struct mrst_hdmi_dev *hdmi_priv; + /* Moorestown pipe config register value cache */ uint32_t pipeconf; uint32_t pipeconf1; @@ -349,8 +389,13 @@ struct drm_psb_private { uint32_t dspcntr1; uint32_t dspcntr2; + /* Moorestown MM backlight cache */ + uint8_t saveBKLTCNT; + uint8_t saveBKLTREQ; + uint8_t saveBKLTBRTL; + /* - *Register state + * Register state */ uint32_t saveDSPACNTR; uint32_t saveDSPBCNTR; @@ -373,6 +418,7 @@ struct drm_psb_private { uint32_t saveDSPAPOS; uint32_t saveDSPABASE; uint32_t saveDSPASURF; + uint32_t saveDSPASTATUS; uint32_t saveFPB0; uint32_t saveFPB1; uint32_t saveDPLL_B; @@ -388,6 +434,7 @@ struct drm_psb_private { uint32_t saveDSPBPOS; uint32_t saveDSPBBASE; uint32_t saveDSPBSURF; + uint32_t saveDSPBSTATUS; uint32_t saveVCLK_DIVISOR_VGA0; uint32_t saveVCLK_DIVISOR_VGA1; uint32_t saveVCLK_POST_DIV; @@ -458,6 +505,77 @@ struct drm_psb_private { uint32_t msi_addr; uint32_t msi_data; + /* Medfield specific register save state */ + uint32_t saveHDMIPHYMISCCTL; + uint32_t saveHDMIB_CONTROL; + uint32_t saveDSPCCNTR; + uint32_t savePIPECCONF; + uint32_t savePIPECSRC; + uint32_t saveHTOTAL_C; + uint32_t saveHBLANK_C; + uint32_t saveHSYNC_C; + uint32_t saveVTOTAL_C; + uint32_t saveVBLANK_C; + uint32_t saveVSYNC_C; + uint32_t saveDSPCSTRIDE; + uint32_t saveDSPCSIZE; + uint32_t saveDSPCPOS; + uint32_t saveDSPCSURF; + uint32_t saveDSPCSTATUS; + uint32_t saveDSPCLINOFF; + uint32_t saveDSPCTILEOFF; + uint32_t saveDSPCCURSOR_CTRL; + uint32_t saveDSPCCURSOR_BASE; + uint32_t saveDSPCCURSOR_POS; + uint32_t save_palette_c[256]; + uint32_t saveOV_OVADD_C; + uint32_t saveOV_OGAMC0_C; + uint32_t saveOV_OGAMC1_C; + uint32_t saveOV_OGAMC2_C; + uint32_t saveOV_OGAMC3_C; + uint32_t saveOV_OGAMC4_C; + uint32_t saveOV_OGAMC5_C; + + /* DSI register save */ + uint32_t saveDEVICE_READY_REG; + uint32_t saveINTR_EN_REG; + uint32_t saveDSI_FUNC_PRG_REG; + uint32_t saveHS_TX_TIMEOUT_REG; + uint32_t saveLP_RX_TIMEOUT_REG; + uint32_t saveTURN_AROUND_TIMEOUT_REG; + uint32_t saveDEVICE_RESET_REG; + uint32_t saveDPI_RESOLUTION_REG; + uint32_t saveHORIZ_SYNC_PAD_COUNT_REG; + uint32_t saveHORIZ_BACK_PORCH_COUNT_REG; + uint32_t saveHORIZ_FRONT_PORCH_COUNT_REG; + uint32_t saveHORIZ_ACTIVE_AREA_COUNT_REG; + uint32_t saveVERT_SYNC_PAD_COUNT_REG; + uint32_t saveVERT_BACK_PORCH_COUNT_REG; + uint32_t saveVERT_FRONT_PORCH_COUNT_REG; + uint32_t saveHIGH_LOW_SWITCH_COUNT_REG; + uint32_t saveINIT_COUNT_REG; + uint32_t saveMAX_RET_PAK_REG; + uint32_t saveVIDEO_FMT_REG; + uint32_t saveEOT_DISABLE_REG; + uint32_t saveLP_BYTECLK_REG; + uint32_t saveHS_LS_DBI_ENABLE_REG; + uint32_t saveTXCLKESC_REG; + uint32_t saveDPHY_PARAM_REG; + uint32_t saveMIPI_CONTROL_REG; + uint32_t saveMIPI; + uint32_t saveMIPI_C; + + /* DPST register save */ + uint32_t saveHISTOGRAM_INT_CONTROL_REG; + uint32_t saveHISTOGRAM_LOGIC_CONTROL_REG; + uint32_t savePWM_CONTROL_LOGIC; + + /* + * DSI info. + */ + void * dbi_dsr_info; + void * dbi_dpu_info; + void * dsi_configs[2]; /* * LID-Switch */ @@ -468,7 +586,7 @@ struct drm_psb_private { u32 lid_last_state; /* - *Watchdog + * Watchdog */ uint32_t apm_reg; @@ -478,14 +596,71 @@ struct drm_psb_private { * Used for modifying backlight from * xrandr -- consider removing and using HAL instead */ + struct backlight_device *backlight_device; struct drm_property *backlight_property; uint32_t blc_adj1; uint32_t blc_adj2; - void * fbdev; + void *fbdev; + /* DPST state */ + uint32_t dsr_idle_count; + bool is_in_idle; + bool dsr_enable; + void (*exit_idle)(struct drm_device *dev, u32 update_src); + + /* 2D acceleration */ + struct mutex mutex_2d; + + /* FIXME: Arrays anyone ? */ + struct mdfld_dsi_encoder *encoder0; + struct mdfld_dsi_encoder *encoder2; + struct mdfld_dsi_dbi_output * dbi_output; + struct mdfld_dsi_dbi_output * dbi_output2; + u32 bpp; + u32 bpp2; + + bool dispstatus; +}; + + +/* + * Operations for each board type + */ + +struct psb_ops { + const char *name; + unsigned int accel_2d:1; + int pipes; /* Number of output pipes */ + int crtcs; /* Number of CRTCs */ + int sgx_offset; /* Base offset of SGX device */ + + /* Sub functions */ + struct drm_crtc_helper_funcs const *crtc_helper; + struct drm_crtc_funcs const *crtc_funcs; + + /* Setup hooks */ + int (*chip_setup)(struct drm_device *dev); + void (*chip_teardown)(struct drm_device *dev); + + /* Display management hooks */ + int (*output_init)(struct drm_device *dev); + /* Power management hooks */ + void (*init_pm)(struct drm_device *dev); + int (*save_regs)(struct drm_device *dev); + int (*restore_regs)(struct drm_device *dev); + int (*power_up)(struct drm_device *dev); + int (*power_down)(struct drm_device *dev); + + void (*lvds_bl_power)(struct drm_device *dev, bool on); +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + /* Backlight */ + int (*backlight_init)(struct drm_device *dev); +#endif + int i2c_bus; /* I2C bus identifier for Moorestown */ }; + struct psb_mmu_driver; extern int drm_crtc_probe_output_modes(struct drm_device *dev, int, int); @@ -497,7 +672,7 @@ static inline struct drm_psb_private *psb_priv(struct drm_device *dev) } /* - *MMU stuff. + * MMU stuff. */ extern struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers, @@ -525,7 +700,7 @@ extern int psb_mmu_virtual_to_pfn(struct psb_mmu_pd *pd, uint32_t virtual, unsigned long *pfn); /* - *Enable / disable MMU for different requestors. + * Enable / disable MMU for different requestors. */ @@ -552,7 +727,7 @@ extern void psb_irq_turn_on_dpst(struct drm_device *dev); extern void psb_irq_turn_off_dpst(struct drm_device *dev); extern void psb_irq_uninstall_islands(struct drm_device *dev, int hw_islands); -extern int psb_vblank_wait2(struct drm_device *dev,unsigned int *sequence); +extern int psb_vblank_wait2(struct drm_device *dev, unsigned int *sequence); extern int psb_vblank_wait(struct drm_device *dev, unsigned int *sequence); extern int psb_enable_vblank(struct drm_device *dev, int crtc); extern void psb_disable_vblank(struct drm_device *dev, int crtc); @@ -564,41 +739,33 @@ psb_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask); extern u32 psb_get_vblank_counter(struct drm_device *dev, int crtc); +extern int mdfld_enable_te(struct drm_device *dev, int pipe); +extern void mdfld_disable_te(struct drm_device *dev, int pipe); + /* - * psb_opregion.c + * intel_opregion.c */ -extern int psb_intel_opregion_init(struct drm_device *dev); +extern int gma_intel_opregion_init(struct drm_device *dev); +extern int gma_intel_opregion_exit(struct drm_device *dev); /* - *psb_fb.c + * framebuffer.c */ extern int psbfb_probed(struct drm_device *dev); extern int psbfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); -extern int psbfb_kms_off_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -extern int psbfb_kms_on_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -extern void *psbfb_vdc_reg(struct drm_device* dev); - /* - * psb_2d.c + * accel_2d.c */ -extern void psbfb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect); extern void psbfb_copyarea(struct fb_info *info, const struct fb_copyarea *region); -extern void psbfb_imageblit(struct fb_info *info, - const struct fb_image *image); extern int psbfb_sync(struct fb_info *info); - extern void psb_spank(struct drm_psb_private *dev_priv); - -extern int psbfb_2d_submit(struct drm_psb_private *dev_priv, uint32_t *cmdbuf, - unsigned size); +extern int psb_accel_ioctl(struct drm_device *dev, void *data, + struct drm_file *file); /* - *psb_reset.c + * psb_reset.c */ extern void psb_lid_timer_init(struct drm_psb_private *dev_priv); @@ -608,14 +775,11 @@ extern void psb_print_pagefault(struct drm_psb_private *dev_priv); /* modesetting */ extern void psb_modeset_init(struct drm_device *dev); extern void psb_modeset_cleanup(struct drm_device *dev); -extern int psb_fbdev_init(struct drm_device * dev); +extern int psb_fbdev_init(struct drm_device *dev); -/* psb_bl.c */ -int psb_backlight_init(struct drm_device *dev); -void psb_backlight_exit(void); -int psb_set_brightness(struct backlight_device *bd); -int psb_get_brightness(struct backlight_device *bd); -struct backlight_device * psb_get_backlight_device(void); +/* backlight.c */ +int gma_backlight_init(struct drm_device *dev); +void gma_backlight_exit(struct drm_device *dev); /* mrst_crtc.c */ extern const struct drm_crtc_helper_funcs mrst_helper_funcs; @@ -624,26 +788,43 @@ extern const struct drm_crtc_helper_funcs mrst_helper_funcs; extern void mrst_lvds_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev); +/* psb_intel_display.c */ +extern const struct drm_crtc_helper_funcs psb_intel_helper_funcs; +extern const struct drm_crtc_funcs psb_intel_crtc_funcs; + /* psb_intel_lvds.c */ -extern void psb_intel_lvds_prepare(struct drm_encoder *encoder); -extern void psb_intel_lvds_commit(struct drm_encoder *encoder); extern const struct drm_connector_helper_funcs psb_intel_lvds_connector_helper_funcs; extern const struct drm_connector_funcs psb_intel_lvds_connector_funcs; -/* psb_gem.c */ +/* gem.c */ extern int psb_gem_init_object(struct drm_gem_object *obj); extern void psb_gem_free_object(struct drm_gem_object *obj); extern int psb_gem_get_aperture(struct drm_device *dev, void *data, - struct drm_file *file); + struct drm_file *file); extern int psb_gem_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args); extern int psb_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev, uint32_t handle); extern int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev, - uint32_t handle, uint64_t *offset); + uint32_t handle, uint64_t *offset); extern int psb_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); +extern int psb_gem_create_ioctl(struct drm_device *dev, void *data, + struct drm_file *file); +extern int psb_gem_mmap_ioctl(struct drm_device *dev, void *data, + struct drm_file *file); + +/* psb_device.c */ +extern const struct psb_ops psb_chip_ops; + +/* mrst_device.c */ +extern const struct psb_ops mrst_chip_ops; + +/* mdfld_device.c */ +extern const struct psb_ops mdfld_chip_ops; +/* cdv_device.c */ +extern const struct psb_ops cdv_chip_ops; /* * Debug print bits setting @@ -661,110 +842,62 @@ extern int psb_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); #define PSB_D_MSVDX (1 << 9) #define PSB_D_TOPAZ (1 << 10) -#ifndef DRM_DEBUG_CODE -/* To enable debug printout, set drm_psb_debug in psb_drv.c - * to any combination of above print flags. - */ -/* #define DRM_DEBUG_CODE 2 */ -#endif - -extern int drm_psb_debug; extern int drm_psb_no_fb; extern int drm_idle_check_interval; -#define PSB_DEBUG_GENERAL(_fmt, _arg...) \ - PSB_DEBUG(PSB_D_GENERAL, _fmt, ##_arg) -#define PSB_DEBUG_INIT(_fmt, _arg...) \ - PSB_DEBUG(PSB_D_INIT, _fmt, ##_arg) -#define PSB_DEBUG_IRQ(_fmt, _arg...) \ - PSB_DEBUG(PSB_D_IRQ, _fmt, ##_arg) -#define PSB_DEBUG_ENTRY(_fmt, _arg...) \ - PSB_DEBUG(PSB_D_ENTRY, _fmt, ##_arg) -#define PSB_DEBUG_HV(_fmt, _arg...) \ - PSB_DEBUG(PSB_D_HV, _fmt, ##_arg) -#define PSB_DEBUG_DBI_BF(_fmt, _arg...) \ - PSB_DEBUG(PSB_D_DBI_BF, _fmt, ##_arg) -#define PSB_DEBUG_PM(_fmt, _arg...) \ - PSB_DEBUG(PSB_D_PM, _fmt, ##_arg) -#define PSB_DEBUG_RENDER(_fmt, _arg...) \ - PSB_DEBUG(PSB_D_RENDER, _fmt, ##_arg) -#define PSB_DEBUG_REG(_fmt, _arg...) \ - PSB_DEBUG(PSB_D_REG, _fmt, ##_arg) -#define PSB_DEBUG_MSVDX(_fmt, _arg...) \ - PSB_DEBUG(PSB_D_MSVDX, _fmt, ##_arg) -#define PSB_DEBUG_TOPAZ(_fmt, _arg...) \ - PSB_DEBUG(PSB_D_TOPAZ, _fmt, ##_arg) - -#if DRM_DEBUG_CODE -#define PSB_DEBUG(_flag, _fmt, _arg...) \ - do { \ - if (unlikely((_flag) & drm_psb_debug)) \ - printk(KERN_DEBUG \ - "[psb:0x%02x:%s] " _fmt , _flag, \ - __func__ , ##_arg); \ - } while (0) -#else -#define PSB_DEBUG(_fmt, _arg...) do { } while (0) -#endif - /* - *Utilities + * Utilities */ -#define DRM_DRIVER_PRIVATE_T struct drm_psb_private static inline u32 MRST_MSG_READ32(uint port, uint offset) { int mcr = (0xD0<<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); + 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 MRST_MSG_WRITE32(uint port, uint offset, u32 value) { int mcr = (0xE0<<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); + 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); } static inline u32 MDFLD_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); + 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 MDFLD_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); + 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); } static inline uint32_t REGISTER_READ(struct drm_device *dev, uint32_t reg) { struct drm_psb_private *dev_priv = dev->dev_private; - int reg_val = ioread32(dev_priv->vdc_reg + (reg)); - PSB_DEBUG_REG("reg = 0x%x. reg_val = 0x%x. \n", reg, reg_val); - return reg_val; + return ioread32(dev_priv->vdc_reg + reg); } #define REG_READ(reg) REGISTER_READ(dev, (reg)) + static inline void REGISTER_WRITE(struct drm_device *dev, uint32_t reg, uint32_t val) { struct drm_psb_private *dev_priv = dev->dev_private; - if ((reg < 0x70084 || reg >0x70088) && (reg < 0xa000 || reg >0xa3ff)) - PSB_DEBUG_REG("reg = 0x%x, val = 0x%x. \n", reg, val); - iowrite32((val), dev_priv->vdc_reg + (reg)); } @@ -774,9 +907,6 @@ static inline void REGISTER_WRITE16(struct drm_device *dev, uint32_t reg, uint32_t val) { struct drm_psb_private *dev_priv = dev->dev_private; - - PSB_DEBUG_REG("reg = 0x%x, val = 0x%x. \n", reg, val); - iowrite16((val), dev_priv->vdc_reg + (reg)); } @@ -786,60 +916,34 @@ static inline void REGISTER_WRITE8(struct drm_device *dev, uint32_t reg, uint32_t val) { struct drm_psb_private *dev_priv = dev->dev_private; - - PSB_DEBUG_REG("reg = 0x%x, val = 0x%x. \n", reg, val); - iowrite8((val), dev_priv->vdc_reg + (reg)); } -#define REG_WRITE8(reg, val) REGISTER_WRITE8(dev, (reg), (val)) +#define REG_WRITE8(reg, val) REGISTER_WRITE8(dev, (reg), (val)) -#define PSB_ALIGN_TO(_val, _align) \ - (((_val) + ((_align) - 1)) & ~((_align) - 1)) -#define PSB_WVDC32(_val, _offs) \ - iowrite32(_val, dev_priv->vdc_reg + (_offs)) -#define PSB_RVDC32(_offs) \ - ioread32(dev_priv->vdc_reg + (_offs)) +#define PSB_WVDC32(_val, _offs) iowrite32(_val, dev_priv->vdc_reg + (_offs)) +#define PSB_RVDC32(_offs) ioread32(dev_priv->vdc_reg + (_offs)) /* #define TRAP_SGX_PM_FAULT 1 */ #ifdef TRAP_SGX_PM_FAULT -#define PSB_RSGX32(_offs) \ -({ \ - if (inl(dev_priv->apm_base + PSB_APM_STS) & 0x3) { \ - printk(KERN_ERR "access sgx when it's off!! (READ) %s, %d\n", \ - __FILE__, __LINE__); \ - mdelay(1000); \ - } \ - ioread32(dev_priv->sgx_reg + (_offs)); \ +#define PSB_RSGX32(_offs) \ +({ \ + if (inl(dev_priv->apm_base + PSB_APM_STS) & 0x3) { \ + printk(KERN_ERR \ + "access sgx when it's off!! (READ) %s, %d\n", \ + __FILE__, __LINE__); \ + melay(1000); \ + } \ + ioread32(dev_priv->sgx_reg + (_offs)); \ }) #else -#define PSB_RSGX32(_offs) \ - ioread32(dev_priv->sgx_reg + (_offs)) +#define PSB_RSGX32(_offs) ioread32(dev_priv->sgx_reg + (_offs)) #endif -#define PSB_WSGX32(_val, _offs) \ - iowrite32(_val, dev_priv->sgx_reg + (_offs)) +#define PSB_WSGX32(_val, _offs) iowrite32(_val, dev_priv->sgx_reg + (_offs)) #define MSVDX_REG_DUMP 0 -#if MSVDX_REG_DUMP - -#define PSB_WMSVDX32(_val, _offs) \ - printk("MSVDX: write %08x to reg 0x%08x\n", (unsigned int)(_val), (unsigned int)(_offs));\ - iowrite32(_val, dev_priv->msvdx_reg + (_offs)) -#define PSB_RMSVDX32(_offs) \ - ioread32(dev_priv->msvdx_reg + (_offs)) - -#else - -#define PSB_WMSVDX32(_val, _offs) \ - iowrite32(_val, dev_priv->msvdx_reg + (_offs)) -#define PSB_RMSVDX32(_offs) \ - ioread32(dev_priv->msvdx_reg + (_offs)) - -#endif -#define PSB_ALPL(_val, _base) \ - (((_val) >> (_base ## _ALIGNSHIFT)) << (_base ## _SHIFT)) -#define PSB_ALPLM(_val, _base) \ - ((((_val) >> (_base ## _ALIGNSHIFT)) << (_base ## _SHIFT)) & (_base ## _MASK)) +#define PSB_WMSVDX32(_val, _offs) iowrite32(_val, dev_priv->msvdx_reg + (_offs)) +#define PSB_RMSVDX32(_offs) ioread32(dev_priv->msvdx_reg + (_offs)) #endif diff --git a/drivers/staging/gma500/psb_intel_display.c b/drivers/staging/gma500/psb_intel_display.c index 09e378d..4afa671 100644 --- a/drivers/staging/gma500/psb_intel_display.c +++ b/drivers/staging/gma500/psb_intel_display.c @@ -1,5 +1,5 @@ /* - * Copyright © 2006-2007 Intel Corporation + * Copyright © 2006-2011 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -22,13 +22,14 @@ #include <linux/pm_runtime.h> #include <drm/drmP.h> -#include "psb_fb.h" +#include "framebuffer.h" #include "psb_drv.h" #include "psb_intel_drv.h" #include "psb_intel_reg.h" #include "psb_intel_display.h" -#include "psb_powermgmt.h" +#include "power.h" +#include "mdfld_output.h" struct psb_intel_clock_t { /* given values */ @@ -350,17 +351,15 @@ int psb_intel_pipe_set_base(struct drm_crtc *crtc, u32 dspcntr; int ret = 0; - PSB_DEBUG_ENTRY("\n"); + if (!gma_power_begin(dev, true)) + return 0; /* no fb bound */ if (!crtc->fb) { - DRM_DEBUG("No FB bound\n"); - return 0; + dev_dbg(dev->dev, "No FB bound\n"); + goto psb_intel_pipe_cleaner; } - if (!gma_power_begin(dev, true)) - return 0; - /* We are displaying this buffer, make sure it is actually loaded into the GTT */ ret = psb_gtt_pin(psbfb->gtt); @@ -390,7 +389,7 @@ int psb_intel_pipe_set_base(struct drm_crtc *crtc, dspcntr |= DISPPLANE_32BPP_NO_ALPHA; break; default: - DRM_ERROR("Unknown color depth\n"); + dev_err(dev->dev, "Unknown color depth\n"); ret = -EINVAL; psb_gtt_unpin(psbfb->gtt); goto psb_intel_pipe_set_base_exit; @@ -398,7 +397,6 @@ int psb_intel_pipe_set_base(struct drm_crtc *crtc, REG_WRITE(dspcntr_reg, dspcntr); - DRM_DEBUG("Writing base %08lX %08lX %d %d\n", start, offset, x, y); if (0 /* FIXMEAC - check what PSB needs */) { REG_WRITE(dspbase, offset); REG_READ(dspbase); @@ -409,6 +407,7 @@ int psb_intel_pipe_set_base(struct drm_crtc *crtc, REG_READ(dspbase); } +psb_intel_pipe_cleaner: /* If there was a previous display we can now unpin it */ if (old_fb) psb_gtt_unpin(to_psb_fb(old_fb)->gtt); @@ -588,6 +587,7 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; int pipe = psb_intel_crtc->pipe; int fp_reg = (pipe == 0) ? FPA0 : FPB0; int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; @@ -610,6 +610,12 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc, struct drm_mode_config *mode_config = &dev->mode_config; struct drm_connector *connector; + /* No scan out no play */ + if (crtc->fb == NULL) { + crtc_funcs->mode_set_base(crtc, x, y, old_fb); + return 0; + } + list_for_each_entry(connector, &mode_config->connector_list, head) { struct psb_intel_output *psb_intel_output = to_psb_intel_output(connector); @@ -642,7 +648,7 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc, ok = psb_intel_find_best_PLL(crtc, adjusted_mode->clock, refclk, &clock); if (!ok) { - DRM_ERROR("Couldn't find PLL settings for mode!\n"); + dev_err(dev->dev, "Couldn't find PLL settings for mode!\n"); return 0; } @@ -706,7 +712,6 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc, if (psb_intel_panel_fitter_pipe(dev) == pipe) REG_WRITE(PFIT_CONTROL, 0); - DRM_DEBUG("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); drm_mode_debug_printmodeline(mode); if (dpll & DPLL_VCO_ENABLE) { @@ -723,17 +728,18 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc, if (is_lvds) { u32 lvds = REG_READ(LVDS); - lvds |= - LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | - LVDS_PIPEB_SELECT; + lvds &= ~LVDS_PIPEB_SELECT; + if (pipe == 1) + lvds |= LVDS_PIPEB_SELECT; + + lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; /* Set the B0-B3 data pairs corresponding to * whether we're going to * set the DPLLs for dual-channel mode or not. */ + lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); if (clock.p2 == 7) lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; - else - lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) * appropriately here, but we need to look more @@ -785,11 +791,7 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc, REG_WRITE(dspcntr_reg, dspcntr); /* Flush the plane changes */ - { - struct drm_crtc_helper_funcs *crtc_funcs = - crtc->helper_private; - crtc_funcs->mode_set_base(crtc, x, y, old_fb); - } + crtc_funcs->mode_set_base(crtc, x, y, old_fb); psb_intel_wait_for_vblank(dev); @@ -820,7 +822,7 @@ void psb_intel_crtc_load_lut(struct drm_crtc *crtc) palreg = PALETTE_C; break; default: - DRM_ERROR("Illegal Pipe Number.\n"); + dev_err(dev->dev, "Illegal Pipe Number.\n"); return; } @@ -863,10 +865,8 @@ static void psb_intel_crtc_save(struct drm_crtc *crtc) uint32_t paletteReg; int i; - DRM_DEBUG("\n"); - if (!crtc_state) { - DRM_DEBUG("No CRTC state found\n"); + dev_err(dev->dev, "No CRTC state found\n"); return; } @@ -890,25 +890,6 @@ static void psb_intel_crtc_save(struct drm_crtc *crtc) crtc_state->saveDSPBASE = REG_READ(pipeA ? DSPABASE : DSPBBASE); - DRM_DEBUG("(%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x)\n", - crtc_state->saveDSPCNTR, - crtc_state->savePIPECONF, - crtc_state->savePIPESRC, - crtc_state->saveFP0, - crtc_state->saveFP1, - crtc_state->saveDPLL, - crtc_state->saveHTOTAL, - crtc_state->saveHBLANK, - crtc_state->saveHSYNC, - crtc_state->saveVTOTAL, - crtc_state->saveVBLANK, - crtc_state->saveVSYNC, - crtc_state->saveDSPSTRIDE, - crtc_state->saveDSPSIZE, - crtc_state->saveDSPPOS, - crtc_state->saveDSPBASE - ); - paletteReg = pipeA ? PALETTE_A : PALETTE_B; for (i = 0; i < 256; ++i) crtc_state->savePalette[i] = REG_READ(paletteReg + (i << 2)); @@ -929,60 +910,15 @@ static void psb_intel_crtc_restore(struct drm_crtc *crtc) uint32_t paletteReg; int i; - DRM_DEBUG("\n"); - if (!crtc_state) { - DRM_DEBUG("No crtc state\n"); + dev_err(dev->dev, "No crtc state\n"); return; } - DRM_DEBUG( - "current:(%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x)\n", - REG_READ(pipeA ? DSPACNTR : DSPBCNTR), - REG_READ(pipeA ? PIPEACONF : PIPEBCONF), - REG_READ(pipeA ? PIPEASRC : PIPEBSRC), - REG_READ(pipeA ? FPA0 : FPB0), - REG_READ(pipeA ? FPA1 : FPB1), - REG_READ(pipeA ? DPLL_A : DPLL_B), - REG_READ(pipeA ? HTOTAL_A : HTOTAL_B), - REG_READ(pipeA ? HBLANK_A : HBLANK_B), - REG_READ(pipeA ? HSYNC_A : HSYNC_B), - REG_READ(pipeA ? VTOTAL_A : VTOTAL_B), - REG_READ(pipeA ? VBLANK_A : VBLANK_B), - REG_READ(pipeA ? VSYNC_A : VSYNC_B), - REG_READ(pipeA ? DSPASTRIDE : DSPBSTRIDE), - REG_READ(pipeA ? DSPASIZE : DSPBSIZE), - REG_READ(pipeA ? DSPAPOS : DSPBPOS), - REG_READ(pipeA ? DSPABASE : DSPBBASE) - ); - - DRM_DEBUG( - "saved: (%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x)\n", - crtc_state->saveDSPCNTR, - crtc_state->savePIPECONF, - crtc_state->savePIPESRC, - crtc_state->saveFP0, - crtc_state->saveFP1, - crtc_state->saveDPLL, - crtc_state->saveHTOTAL, - crtc_state->saveHBLANK, - crtc_state->saveHSYNC, - crtc_state->saveVTOTAL, - crtc_state->saveVBLANK, - crtc_state->saveVSYNC, - crtc_state->saveDSPSTRIDE, - crtc_state->saveDSPSIZE, - crtc_state->saveDSPPOS, - crtc_state->saveDSPBASE - ); - - if (crtc_state->saveDPLL & DPLL_VCO_ENABLE) { REG_WRITE(pipeA ? DPLL_A : DPLL_B, crtc_state->saveDPLL & ~DPLL_VCO_ENABLE); REG_READ(pipeA ? DPLL_A : DPLL_B); - DRM_DEBUG("write dpll: %x\n", - REG_READ(pipeA ? DPLL_A : DPLL_B)); udelay(150); } @@ -1039,11 +975,8 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc, struct drm_gem_object *obj; int ret; - DRM_DEBUG("\n"); - /* if we want to turn of the cursor ignore width and height */ if (!handle) { - DRM_DEBUG("cursor off\n"); /* turn off the cursor */ temp = CURSOR_MODE_DISABLE; @@ -1067,7 +1000,7 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc, /* Currently we only support 64x64 cursors */ if (width != 64 || height != 64) { - DRM_ERROR("we currently only support 64x64 cursors\n"); + dev_dbg(dev->dev, "we currently only support 64x64 cursors\n"); return -EINVAL; } @@ -1076,7 +1009,7 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc, return -ENOENT; if (obj->size < width * height * 4) { - DRM_ERROR("buffer is to small\n"); + dev_dbg(dev->dev, "buffer is to small\n"); return -ENOMEM; } @@ -1085,7 +1018,7 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc, /* Pin the memory into the GTT */ ret = psb_gtt_pin(gt); if (ret) { - DRM_ERROR("Can not pin down handle 0x%x\n", handle); + dev_err(dev->dev, "Can not pin down handle 0x%x\n", handle); return ret; } @@ -1106,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; } @@ -1148,7 +1080,7 @@ static int psb_intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) return 0; } -static void psb_intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, +void psb_intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, uint32_t type, uint32_t size) { struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); @@ -1309,7 +1241,7 @@ struct drm_display_mode *psb_intel_crtc_mode_get(struct drm_device *dev, return mode; } -static void psb_intel_crtc_destroy(struct drm_crtc *crtc) +void psb_intel_crtc_destroy(struct drm_crtc *crtc) { struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); struct gtt_range *gt; @@ -1327,7 +1259,7 @@ static void psb_intel_crtc_destroy(struct drm_crtc *crtc) kfree(psb_intel_crtc); } -static const struct drm_crtc_helper_funcs psb_intel_helper_funcs = { +const struct drm_crtc_helper_funcs psb_intel_helper_funcs = { .dpms = psb_intel_crtc_dpms, .mode_fixup = psb_intel_crtc_mode_fixup, .mode_set = psb_intel_crtc_mode_set, @@ -1346,6 +1278,19 @@ const struct drm_crtc_funcs psb_intel_crtc_funcs = { .destroy = psb_intel_crtc_destroy, }; +/* + * Set the default value of cursor control and base register + * to zero. This is a workaround for h/w defect on Oaktrail + */ +static void psb_intel_cursor_init(struct drm_device *dev, int pipe) +{ + u32 control[3] = { CURACNTR, CURBCNTR, CURCCNTR }; + u32 base[3] = { CURABASE, CURBBASE, CURCBASE }; + + REG_WRITE(control[pipe], 0); + REG_WRITE(base[pipe], 0); +} + void psb_intel_crtc_init(struct drm_device *dev, int pipe, struct psb_intel_mode_device *mode_dev) { @@ -1354,8 +1299,6 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe, int i; uint16_t *r_base, *g_base, *b_base; - PSB_DEBUG_ENTRY("\n"); - /* We allocate a extra array of drm_connector pointers * for fbdev after the crtc */ psb_intel_crtc = @@ -1368,12 +1311,13 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe, psb_intel_crtc->crtc_state = kzalloc(sizeof(struct psb_intel_crtc_state), GFP_KERNEL); if (!psb_intel_crtc->crtc_state) { - DRM_INFO("Crtc state error: No memory\n"); + dev_err(dev->dev, "Crtc state error: No memory\n"); kfree(psb_intel_crtc); return; } - drm_crtc_init(dev, &psb_intel_crtc->base, &psb_intel_crtc_funcs); + /* Set the CRTC operations from the chip specific data */ + drm_crtc_init(dev, &psb_intel_crtc->base, dev_priv->ops->crtc_funcs); drm_mode_crtc_set_gamma_size(&psb_intel_crtc->base, 256); psb_intel_crtc->pipe = pipe; @@ -1396,12 +1340,8 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe, psb_intel_crtc->mode_dev = mode_dev; psb_intel_crtc->cursor_addr = 0; - if (IS_MRST(dev)) - drm_crtc_helper_add(&psb_intel_crtc->base, - &mrst_helper_funcs); - else - drm_crtc_helper_add(&psb_intel_crtc->base, - &psb_intel_helper_funcs); + drm_crtc_helper_add(&psb_intel_crtc->base, + dev_priv->ops->crtc_helper); /* Setup the array of drm_connector pointer array */ psb_intel_crtc->mode_set.crtc = &psb_intel_crtc->base; @@ -1414,6 +1354,7 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe, psb_intel_crtc->mode_set.connectors = (struct drm_connector **) (psb_intel_crtc + 1); psb_intel_crtc->mode_set.num_connectors = 0; + psb_intel_cursor_init(dev, pipe); } int psb_intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, @@ -1425,7 +1366,7 @@ int psb_intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, struct psb_intel_crtc *crtc; if (!dev_priv) { - DRM_ERROR("called with no initialization\n"); + dev_err(dev->dev, "called with no initialization\n"); return -EINVAL; } @@ -1433,7 +1374,7 @@ int psb_intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, DRM_MODE_OBJECT_CRTC); if (!drmmode_obj) { - DRM_ERROR("no such CRTC id\n"); + dev_err(dev->dev, "no such CRTC id\n"); return -EINVAL; } diff --git a/drivers/staging/gma500/psb_intel_display.h b/drivers/staging/gma500/psb_intel_display.h index 3724b97..535b49a 100644 --- a/drivers/staging/gma500/psb_intel_display.h +++ b/drivers/staging/gma500/psb_intel_display.h @@ -21,5 +21,8 @@ #define _INTEL_DISPLAY_H_ bool psb_intel_pipe_has_type(struct drm_crtc *crtc, int type); +void psb_intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, + u16 *green, u16 *blue, uint32_t type, uint32_t size); +void psb_intel_crtc_destroy(struct drm_crtc *crtc); #endif diff --git a/drivers/staging/gma500/psb_intel_drv.h b/drivers/staging/gma500/psb_intel_drv.h index 6006ddd..36b554b 100644 --- a/drivers/staging/gma500/psb_intel_drv.h +++ b/drivers/staging/gma500/psb_intel_drv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Intel Corporation. + * Copyright (c) 2009-2011, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -26,11 +26,6 @@ #include <linux/gpio.h> /* - * MOORESTOWN defines - */ -#define DELAY_TIME1 2000 /* 1000 = 1ms */ - -/* * Display related stuff */ @@ -61,16 +56,10 @@ #define INTEL_DVO_CHIP_TMDS 2 #define INTEL_DVO_CHIP_TVOUT 4 -enum mipi_panel_type { - NSC_800X480 = 1, - LGE_480X1024 = 2, - TPO_864X480 = 3 -}; - -/** +/* * Hold information useally put on the device driver privates here, * since it needs to be shared across multiple of devices drivers privates. -*/ + */ struct psb_intel_mode_device { /* @@ -79,7 +68,7 @@ struct psb_intel_mode_device { size_t(*bo_offset) (struct drm_device *dev, void *bo); /* - * Cursor + * Cursor (Can go ?) */ int cursor_needs_physical; @@ -116,7 +105,7 @@ struct psb_intel_output { void *dev_priv; struct psb_intel_mode_device *mode_dev; - + struct i2c_adapter *hdmi_i2c_adapter; /* for control functions */ }; struct psb_intel_crtc_state { @@ -235,4 +224,7 @@ extern int psb_intel_lvds_set_property(struct drm_connector *connector, extern void psb_intel_lvds_destroy(struct drm_connector *connector); extern const struct drm_encoder_funcs psb_intel_lvds_enc_funcs; +extern void mdfldWaitForPipeDisable(struct drm_device *dev, int pipe); +extern void mdfldWaitForPipeEnable(struct drm_device *dev, int pipe); + #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/staging/gma500/psb_intel_lvds.c b/drivers/staging/gma500/psb_intel_lvds.c index b0a225b..c6436da 100644 --- a/drivers/staging/gma500/psb_intel_lvds.c +++ b/drivers/staging/gma500/psb_intel_lvds.c @@ -21,21 +21,16 @@ */ #include <linux/i2c.h> -/* #include <drm/drm_crtc.h> */ -/* #include <drm/drm_edid.h> */ #include <drm/drmP.h> -#include "psb_intel_bios.h" +#include "intel_bios.h" #include "psb_drv.h" #include "psb_intel_drv.h" #include "psb_intel_reg.h" -#include "psb_powermgmt.h" +#include "power.h" #include <linux/pm_runtime.h> -u32 CoreClock; -u32 PWMControlRegFreq; - -/** +/* * LVDS I2C backlight control macros */ #define BRIGHTNESS_MAX_LEVEL 100 @@ -53,7 +48,7 @@ u32 PWMControlRegFreq; #define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) struct psb_intel_lvds_priv { - /** + /* * Saved LVDO output states */ uint32_t savePP_ON; @@ -66,9 +61,8 @@ struct psb_intel_lvds_priv { uint32_t saveBLC_PWM_CTL; }; -/* MRST defines end */ -/** +/* * Returns the maximum level of the backlight duty cycle field. */ static u32 psb_intel_lvds_get_max_backlight(struct drm_device *dev) @@ -126,13 +120,13 @@ static int psb_lvds_i2c_set_brightness(struct drm_device *dev, out_buf[1] = (u8)blc_i2c_brightness; if (i2c_transfer(&lvds_i2c_bus->adapter, msgs, 1) == 1) { - DRM_DEBUG("I2C set brightness.(command, value) (%d, %d)\n", + dev_dbg(dev->dev, "I2C set brightness.(command, value) (%d, %d)\n", dev_priv->lvds_bl->brightnesscmd, blc_i2c_brightness); return 0; } - DRM_ERROR("I2C transfer error\n"); + dev_err(dev->dev, "I2C transfer error\n"); return -1; } @@ -163,7 +157,7 @@ static int psb_lvds_pwm_set_brightness(struct drm_device *dev, int level) return 0; } -/** +/* * Set LVDS backlight level either by I2C or PWM */ void psb_intel_lvds_set_brightness(struct drm_device *dev, int level) @@ -172,10 +166,10 @@ void psb_intel_lvds_set_brightness(struct drm_device *dev, int level) struct drm_psb_private *dev_priv = (struct drm_psb_private *)dev->dev_private; - DRM_DEBUG("backlight level is %d\n", level); + dev_dbg(dev->dev, "backlight level is %d\n", level); if (!dev_priv->lvds_bl) { - DRM_ERROR("NO LVDS Backlight Info\n"); + dev_err(dev->dev, "NO LVDS Backlight Info\n"); return; } @@ -185,10 +179,10 @@ void psb_intel_lvds_set_brightness(struct drm_device *dev, int level) psb_lvds_pwm_set_brightness(dev, level); } -/** +/* * Sets the backlight level. * - * \param level backlight level, from 0 to psb_intel_lvds_get_max_backlight(). + * level: backlight level, from 0 to psb_intel_lvds_get_max_backlight(). */ static void psb_intel_lvds_set_backlight(struct drm_device *dev, int level) { @@ -210,7 +204,7 @@ static void psb_intel_lvds_set_backlight(struct drm_device *dev, int level) } } -/** +/* * Sets the power state for the panel. */ static void psb_intel_lvds_set_power(struct drm_device *dev, @@ -289,7 +283,7 @@ static void psb_intel_lvds_save(struct drm_connector *connector) dev_priv->backlight_duty_cycle = psb_intel_lvds_get_max_backlight(dev); - DRM_DEBUG("(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", + dev_dbg(dev->dev, "(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", lvds_priv->savePP_ON, lvds_priv->savePP_OFF, lvds_priv->saveLVDS, @@ -310,7 +304,7 @@ static void psb_intel_lvds_restore(struct drm_connector *connector) struct psb_intel_lvds_priv *lvds_priv = (struct psb_intel_lvds_priv *)psb_intel_output->dev_priv; - DRM_DEBUG("(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", + dev_dbg(dev->dev, "(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", lvds_priv->savePP_ON, lvds_priv->savePP_OFF, lvds_priv->saveLVDS, @@ -351,8 +345,6 @@ int psb_intel_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *fixed_mode = psb_intel_output->mode_dev->panel_fixed_mode; - PSB_DEBUG_ENTRY("\n"); - if (psb_intel_output->type == INTEL_OUTPUT_MIPI2) fixed_mode = psb_intel_output->mode_dev->panel_fixed_mode2; @@ -387,12 +379,10 @@ bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder, struct psb_intel_output *psb_intel_output = enc_to_psb_intel_output(encoder); - PSB_DEBUG_ENTRY("type = 0x%x, pipe = %d.\n", - psb_intel_output->type, psb_intel_crtc->pipe); - if (psb_intel_output->type == INTEL_OUTPUT_MIPI2) panel_fixed_mode = mode_dev->panel_fixed_mode2; + /* FIXME: review for Medfield */ /* PSB requires the LVDS is on pipe B, MRST has only one pipe anyway */ if (!IS_MRST(dev) && psb_intel_crtc->pipe == 0) { printk(KERN_ERR "Can't support LVDS on pipe A\n"); @@ -442,14 +432,12 @@ bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder, return true; } -void psb_intel_lvds_prepare(struct drm_encoder *encoder) +static void psb_intel_lvds_prepare(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct psb_intel_output *output = enc_to_psb_intel_output(encoder); struct psb_intel_mode_device *mode_dev = output->mode_dev; - PSB_DEBUG_ENTRY("\n"); - if (!gma_power_begin(dev, true)) return; @@ -462,14 +450,12 @@ void psb_intel_lvds_prepare(struct drm_encoder *encoder) gma_power_end(dev); } -void psb_intel_lvds_commit(struct drm_encoder *encoder) +static void psb_intel_lvds_commit(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct psb_intel_output *output = enc_to_psb_intel_output(encoder); struct psb_intel_mode_device *mode_dev = output->mode_dev; - PSB_DEBUG_ENTRY("\n"); - if (mode_dev->backlight_duty_cycle == 0) mode_dev->backlight_duty_cycle = psb_intel_lvds_get_max_backlight(dev); @@ -481,9 +467,8 @@ static void psb_intel_lvds_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct psb_intel_mode_device *mode_dev = - enc_to_psb_intel_output(encoder)->mode_dev; struct drm_device *dev = encoder->dev; + struct drm_psb_private *dev_priv = dev->dev_private; u32 pfit_control; /* @@ -505,13 +490,13 @@ static void psb_intel_lvds_mode_set(struct drm_encoder *encoder, else pfit_control = 0; - if (mode_dev->panel_wants_dither) + if (dev_priv->lvds_dither) pfit_control |= PANEL_8TO6_DITHER_ENABLE; REG_WRITE(PFIT_CONTROL, pfit_control); } -/** +/* * Detect the LVDS connection. * * This always returns CONNECTOR_STATUS_CONNECTED. @@ -524,7 +509,7 @@ static enum drm_connector_status psb_intel_lvds_detect(struct drm_connector return connector_status_connected; } -/** +/* * Return the list of DDC modes if available, or the BIOS fixed mode otherwise. */ static int psb_intel_lvds_get_modes(struct drm_connector *connector) @@ -536,7 +521,8 @@ static int psb_intel_lvds_get_modes(struct drm_connector *connector) psb_intel_output->mode_dev; int ret = 0; - ret = psb_intel_ddc_get_modes(psb_intel_output); + if (!IS_MRST(dev)) + ret = psb_intel_ddc_get_modes(psb_intel_output); if (ret) return ret; @@ -583,18 +569,17 @@ int psb_intel_lvds_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t value) { - struct drm_encoder *pEncoder = connector->encoder; + struct drm_encoder *encoder = connector->encoder; - PSB_DEBUG_ENTRY("\n"); + if (!encoder) + return -1; - if (!strcmp(property->name, "scaling mode") && pEncoder) { - struct psb_intel_crtc *pPsbCrtc = - to_psb_intel_crtc(pEncoder->crtc); - uint64_t curValue; + if (!strcmp(property->name, "scaling mode")) { + struct psb_intel_crtc *crtc = + to_psb_intel_crtc(encoder->crtc); + uint64_t curval; - PSB_DEBUG_ENTRY("scaling mode\n"); - - if (!pPsbCrtc) + if (!crtc) goto set_prop_error; switch (value) { @@ -610,10 +595,10 @@ int psb_intel_lvds_set_property(struct drm_connector *connector, if (drm_connector_property_get_value(connector, property, - &curValue)) + &curval)) goto set_prop_error; - if (curValue == value) + if (curval == value) goto set_prop_done; if (drm_connector_property_set_value(connector, @@ -621,34 +606,34 @@ int psb_intel_lvds_set_property(struct drm_connector *connector, value)) goto set_prop_error; - if (pPsbCrtc->saved_mode.hdisplay != 0 && - pPsbCrtc->saved_mode.vdisplay != 0) { - if (!drm_crtc_helper_set_mode(pEncoder->crtc, - &pPsbCrtc->saved_mode, - pEncoder->crtc->x, - pEncoder->crtc->y, - pEncoder->crtc->fb)) + if (crtc->saved_mode.hdisplay != 0 && + crtc->saved_mode.vdisplay != 0) { + if (!drm_crtc_helper_set_mode(encoder->crtc, + &crtc->saved_mode, + encoder->crtc->x, + encoder->crtc->y, + encoder->crtc->fb)) goto set_prop_error; } - } else if (!strcmp(property->name, "backlight") && pEncoder) { - PSB_DEBUG_ENTRY("backlight\n"); - + } else if (!strcmp(property->name, "backlight")) { if (drm_connector_property_set_value(connector, property, value)) goto set_prop_error; else { #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE - struct backlight_device bd; - bd.props.brightness = value; - psb_set_brightness(&bd); + struct drm_psb_private *devp = encoder->dev->dev_private; + struct backlight_device *bd = devp->backlight_device; + if (bd) { + bd->props.brightness = value; + backlight_update_status(bd); + } #endif } - } else if (!strcmp(property->name, "DPMS") && pEncoder) { - struct drm_encoder_helper_funcs *pEncHFuncs - = pEncoder->helper_private; - PSB_DEBUG_ENTRY("DPMS\n"); - pEncHFuncs->dpms(pEncoder, value); + } else if (!strcmp(property->name, "DPMS")) { + struct drm_encoder_helper_funcs *hfuncs + = encoder->helper_private; + hfuncs->dpms(encoder, value); } set_prop_done: @@ -722,7 +707,7 @@ void psb_intel_lvds_init(struct drm_device *dev, lvds_priv = kzalloc(sizeof(struct psb_intel_lvds_priv), GFP_KERNEL); if (!lvds_priv) { kfree(psb_intel_output); - DRM_DEBUG("LVDS private allocation error\n"); + dev_err(dev->dev, "LVDS private allocation error\n"); return; } @@ -758,7 +743,7 @@ void psb_intel_lvds_init(struct drm_device *dev, dev_priv->backlight_property, BRIGHTNESS_MAX_LEVEL); - /** + /* * Set up I2C bus * FIXME: distroy i2c_bus when exit */ @@ -806,7 +791,7 @@ void psb_intel_lvds_init(struct drm_device *dev, } } - /* Failed to get EDID, what about VBT? do we need this?*/ + /* Failed to get EDID, what about VBT? do we need this? */ if (mode_dev->vbt_mode) mode_dev->panel_fixed_mode = drm_mode_duplicate(dev, mode_dev->vbt_mode); @@ -838,8 +823,7 @@ void psb_intel_lvds_init(struct drm_device *dev, /* If we still don't have a mode after all that, give up. */ if (!mode_dev->panel_fixed_mode) { - DRM_DEBUG - ("Found no modes on the lvds, ignoring the LVDS\n"); + dev_err(dev->dev, "Found no modes on the lvds, ignoring the LVDS\n"); goto failed_find; } @@ -849,26 +833,6 @@ void psb_intel_lvds_init(struct drm_device *dev, */ out: drm_sysfs_connector_add(connector); - - PSB_DEBUG_ENTRY("hdisplay = %d\n", - mode_dev->panel_fixed_mode->hdisplay); - PSB_DEBUG_ENTRY(" vdisplay = %d\n", - mode_dev->panel_fixed_mode->vdisplay); - PSB_DEBUG_ENTRY(" hsync_start = %d\n", - mode_dev->panel_fixed_mode->hsync_start); - PSB_DEBUG_ENTRY(" hsync_end = %d\n", - mode_dev->panel_fixed_mode->hsync_end); - PSB_DEBUG_ENTRY(" htotal = %d\n", - mode_dev->panel_fixed_mode->htotal); - PSB_DEBUG_ENTRY(" vsync_start = %d\n", - mode_dev->panel_fixed_mode->vsync_start); - PSB_DEBUG_ENTRY(" vsync_end = %d\n", - mode_dev->panel_fixed_mode->vsync_end); - PSB_DEBUG_ENTRY(" vtotal = %d\n", - mode_dev->panel_fixed_mode->vtotal); - PSB_DEBUG_ENTRY(" clock = %d\n", - mode_dev->panel_fixed_mode->clock); - return; failed_find: diff --git a/drivers/staging/gma500/psb_intel_reg.h b/drivers/staging/gma500/psb_intel_reg.h index 1c28314..1ac16aa 100644 --- a/drivers/staging/gma500/psb_intel_reg.h +++ b/drivers/staging/gma500/psb_intel_reg.h @@ -28,8 +28,8 @@ * * The actual value is this field multiplied by two. */ -#define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17) -#define BLM_LEGACY_MODE (1 << 16) +#define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17) +#define BLM_LEGACY_MODE (1 << 16) /* * This is the number of cycles out of the backlight modulation cycle for which * the backlight is on. @@ -37,55 +37,55 @@ * This field must be no greater than the number of cycles in the complete * backlight modulation cycle. */ -#define BACKLIGHT_DUTY_CYCLE_SHIFT (0) -#define BACKLIGHT_DUTY_CYCLE_MASK (0xffff) +#define BACKLIGHT_DUTY_CYCLE_SHIFT (0) +#define BACKLIGHT_DUTY_CYCLE_MASK (0xffff) #define I915_GCFGC 0xf0 -#define I915_LOW_FREQUENCY_ENABLE (1 << 7) -#define I915_DISPLAY_CLOCK_190_200_MHZ (0 << 4) -#define I915_DISPLAY_CLOCK_333_MHZ (4 << 4) -#define I915_DISPLAY_CLOCK_MASK (7 << 4) +#define I915_LOW_FREQUENCY_ENABLE (1 << 7) +#define I915_DISPLAY_CLOCK_190_200_MHZ (0 << 4) +#define I915_DISPLAY_CLOCK_333_MHZ (4 << 4) +#define I915_DISPLAY_CLOCK_MASK (7 << 4) #define I855_HPLLCC 0xc0 -#define I855_CLOCK_CONTROL_MASK (3 << 0) -#define I855_CLOCK_133_200 (0 << 0) -#define I855_CLOCK_100_200 (1 << 0) -#define I855_CLOCK_100_133 (2 << 0) -#define I855_CLOCK_166_250 (3 << 0) +#define I855_CLOCK_CONTROL_MASK (3 << 0) +#define I855_CLOCK_133_200 (0 << 0) +#define I855_CLOCK_100_200 (1 << 0) +#define I855_CLOCK_100_133 (2 << 0) +#define I855_CLOCK_166_250 (3 << 0) /* I830 CRTC registers */ -#define HTOTAL_A 0x60000 -#define HBLANK_A 0x60004 -#define HSYNC_A 0x60008 -#define VTOTAL_A 0x6000c -#define VBLANK_A 0x60010 -#define VSYNC_A 0x60014 -#define PIPEASRC 0x6001c -#define BCLRPAT_A 0x60020 -#define VSYNCSHIFT_A 0x60028 - -#define HTOTAL_B 0x61000 -#define HBLANK_B 0x61004 -#define HSYNC_B 0x61008 -#define VTOTAL_B 0x6100c -#define VBLANK_B 0x61010 -#define VSYNC_B 0x61014 -#define PIPEBSRC 0x6101c -#define BCLRPAT_B 0x61020 -#define VSYNCSHIFT_B 0x61028 - -#define HTOTAL_C 0x62000 -#define HBLANK_C 0x62004 -#define HSYNC_C 0x62008 -#define VTOTAL_C 0x6200c -#define VBLANK_C 0x62010 -#define VSYNC_C 0x62014 -#define PIPECSRC 0x6201c -#define BCLRPAT_C 0x62020 -#define VSYNCSHIFT_C 0x62028 - -#define PP_STATUS 0x61200 -# define PP_ON (1 << 31) +#define HTOTAL_A 0x60000 +#define HBLANK_A 0x60004 +#define HSYNC_A 0x60008 +#define VTOTAL_A 0x6000c +#define VBLANK_A 0x60010 +#define VSYNC_A 0x60014 +#define PIPEASRC 0x6001c +#define BCLRPAT_A 0x60020 +#define VSYNCSHIFT_A 0x60028 + +#define HTOTAL_B 0x61000 +#define HBLANK_B 0x61004 +#define HSYNC_B 0x61008 +#define VTOTAL_B 0x6100c +#define VBLANK_B 0x61010 +#define VSYNC_B 0x61014 +#define PIPEBSRC 0x6101c +#define BCLRPAT_B 0x61020 +#define VSYNCSHIFT_B 0x61028 + +#define HTOTAL_C 0x62000 +#define HBLANK_C 0x62004 +#define HSYNC_C 0x62008 +#define VTOTAL_C 0x6200c +#define VBLANK_C 0x62010 +#define VSYNC_C 0x62014 +#define PIPECSRC 0x6201c +#define BCLRPAT_C 0x62020 +#define VSYNCSHIFT_C 0x62028 + +#define PP_STATUS 0x61200 +# define PP_ON (1 << 31) /* * Indicates that all dependencies of the panel are on: * @@ -93,56 +93,57 @@ * - pipe enabled * - LVDS/DVOB/DVOC on */ -# define PP_READY (1 << 30) -# define PP_SEQUENCE_NONE (0 << 28) -# define PP_SEQUENCE_ON (1 << 28) -# define PP_SEQUENCE_OFF (2 << 28) -# define PP_SEQUENCE_MASK 0x30000000 -#define PP_CONTROL 0x61204 -# define POWER_TARGET_ON (1 << 0) - -#define LVDSPP_ON 0x61208 -#define LVDSPP_OFF 0x6120c -#define PP_CYCLE 0x61210 - -#define PFIT_CONTROL 0x61230 -# define PFIT_ENABLE (1 << 31) -# define PFIT_PIPE_MASK (3 << 29) -# define PFIT_PIPE_SHIFT 29 -# define PFIT_SCALING_MODE_PILLARBOX (1 << 27) -# define PFIT_SCALING_MODE_LETTERBOX (3 << 26) -# define VERT_INTERP_DISABLE (0 << 10) -# define VERT_INTERP_BILINEAR (1 << 10) -# define VERT_INTERP_MASK (3 << 10) -# define VERT_AUTO_SCALE (1 << 9) -# define HORIZ_INTERP_DISABLE (0 << 6) -# define HORIZ_INTERP_BILINEAR (1 << 6) -# define HORIZ_INTERP_MASK (3 << 6) -# define HORIZ_AUTO_SCALE (1 << 5) -# define PANEL_8TO6_DITHER_ENABLE (1 << 3) - -#define PFIT_PGM_RATIOS 0x61234 -# define PFIT_VERT_SCALE_MASK 0xfff00000 -# define PFIT_HORIZ_SCALE_MASK 0x0000fff0 +#define PP_READY (1 << 30) +#define PP_SEQUENCE_NONE (0 << 28) +#define PP_SEQUENCE_ON (1 << 28) +#define PP_SEQUENCE_OFF (2 << 28) +#define PP_SEQUENCE_MASK 0x30000000 +#define PP_CONTROL 0x61204 +#define POWER_TARGET_ON (1 << 0) + +#define LVDSPP_ON 0x61208 +#define LVDSPP_OFF 0x6120c +#define PP_CYCLE 0x61210 + +#define PFIT_CONTROL 0x61230 +#define PFIT_ENABLE (1 << 31) +#define PFIT_PIPE_MASK (3 << 29) +#define PFIT_PIPE_SHIFT 29 +#define PFIT_SCALING_MODE_PILLARBOX (1 << 27) +#define PFIT_SCALING_MODE_LETTERBOX (3 << 26) +#define VERT_INTERP_DISABLE (0 << 10) +#define VERT_INTERP_BILINEAR (1 << 10) +#define VERT_INTERP_MASK (3 << 10) +#define VERT_AUTO_SCALE (1 << 9) +#define HORIZ_INTERP_DISABLE (0 << 6) +#define HORIZ_INTERP_BILINEAR (1 << 6) +#define HORIZ_INTERP_MASK (3 << 6) +#define HORIZ_AUTO_SCALE (1 << 5) +#define PANEL_8TO6_DITHER_ENABLE (1 << 3) + +#define PFIT_PGM_RATIOS 0x61234 +#define PFIT_VERT_SCALE_MASK 0xfff00000 +#define PFIT_HORIZ_SCALE_MASK 0x0000fff0 #define PFIT_AUTO_RATIOS 0x61238 +#define DPLL_A 0x06014 +#define DPLL_B 0x06018 +#define DPLL_VCO_ENABLE (1 << 31) +#define DPLL_DVO_HIGH_SPEED (1 << 30) +#define DPLL_SYNCLOCK_ENABLE (1 << 29) +#define DPLL_VGA_MODE_DIS (1 << 28) +#define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */ +#define DPLLB_MODE_LVDS (2 << 26) /* i915 */ +#define DPLL_MODE_MASK (3 << 26) +#define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */ +#define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */ +#define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24) /* i915 */ +#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 */ -#define DPLL_A 0x06014 -#define DPLL_B 0x06018 -# define DPLL_VCO_ENABLE (1 << 31) -# define DPLL_DVO_HIGH_SPEED (1 << 30) -# define DPLL_SYNCLOCK_ENABLE (1 << 29) -# define DPLL_VGA_MODE_DIS (1 << 28) -# define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */ -# define DPLLB_MODE_LVDS (2 << 26) /* i915 */ -# define DPLL_MODE_MASK (3 << 26) -# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */ -# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */ -# define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24) /* i915 */ -# 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 */ /* * 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. @@ -152,35 +153,35 @@ * The i830 generation, in LVDS mode, defines P1 as the bit number set within * this field (only one bit may be set). */ -# define DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS 0x003f0000 -# define DPLL_FPA01_P1_POST_DIV_SHIFT 16 -# define PLL_P2_DIVIDE_BY_4 (1 << 23) /* i830, required +#define DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS 0x003f0000 +#define DPLL_FPA01_P1_POST_DIV_SHIFT 16 +#define PLL_P2_DIVIDE_BY_4 (1 << 23) /* i830, required * in DVO non-gang */ -# define PLL_P1_DIVIDE_BY_TWO (1 << 21) /* i830 */ -# define PLL_REF_INPUT_DREFCLK (0 << 13) -# define PLL_REF_INPUT_TVCLKINA (1 << 13) /* i830 */ -# define PLL_REF_INPUT_TVCLKINBC (2 << 13) /* SDVO +# define PLL_P1_DIVIDE_BY_TWO (1 << 21) /* i830 */ +#define PLL_REF_INPUT_DREFCLK (0 << 13) +#define PLL_REF_INPUT_TVCLKINA (1 << 13) /* i830 */ +#define PLL_REF_INPUT_TVCLKINBC (2 << 13) /* SDVO * TVCLKIN */ -# define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13) -# define PLL_REF_INPUT_MASK (3 << 13) -# define PLL_LOAD_PULSE_PHASE_SHIFT 9 +#define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13) +#define PLL_REF_INPUT_MASK (3 << 13) +#define PLL_LOAD_PULSE_PHASE_SHIFT 9 /* * Parallel to Serial Load Pulse phase selection. * Selects the phase for the 10X DPLL clock for the PCIe * digital display port. The range is 4 to 13; 10 or more * is just a flip delay. The default is 6 */ -# define PLL_LOAD_PULSE_PHASE_MASK (0xf << PLL_LOAD_PULSE_PHASE_SHIFT) -# define DISPLAY_RATE_SELECT_FPA1 (1 << 8) +#define PLL_LOAD_PULSE_PHASE_MASK (0xf << PLL_LOAD_PULSE_PHASE_SHIFT) +#define DISPLAY_RATE_SELECT_FPA1 (1 << 8) /* * SDVO multiplier for 945G/GM. Not used on 965. * * DPLL_MD_UDI_MULTIPLIER_MASK */ -# define SDVO_MULTIPLIER_MASK 0x000000ff -# define SDVO_MULTIPLIER_SHIFT_HIRES 4 -# define SDVO_MULTIPLIER_SHIFT_VGA 0 +#define SDVO_MULTIPLIER_MASK 0x000000ff +#define SDVO_MULTIPLIER_SHIFT_HIRES 4 +#define SDVO_MULTIPLIER_SHIFT_VGA 0 /* * PLL_MD @@ -194,11 +195,11 @@ * * Value is pixels minus 1. Must be set to 1 pixel for SDVO. */ -# define DPLL_MD_UDI_DIVIDER_MASK 0x3f000000 -# define DPLL_MD_UDI_DIVIDER_SHIFT 24 +#define DPLL_MD_UDI_DIVIDER_MASK 0x3f000000 +#define DPLL_MD_UDI_DIVIDER_SHIFT 24 /* UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */ -# define DPLL_MD_VGA_UDI_DIVIDER_MASK 0x003f0000 -# define DPLL_MD_VGA_UDI_DIVIDER_SHIFT 16 +#define DPLL_MD_VGA_UDI_DIVIDER_MASK 0x003f0000 +#define DPLL_MD_VGA_UDI_DIVIDER_SHIFT 16 /* * SDVO/UDI pixel multiplier. * @@ -216,80 +217,94 @@ * This register field has values of multiplication factor minus 1, with * a maximum multiplier of 5 for SDVO. */ -# define DPLL_MD_UDI_MULTIPLIER_MASK 0x00003f00 -# define DPLL_MD_UDI_MULTIPLIER_SHIFT 8 +#define DPLL_MD_UDI_MULTIPLIER_MASK 0x00003f00 +#define DPLL_MD_UDI_MULTIPLIER_SHIFT 8 /* * SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK. * This best be set to the default value (3) or the CRT won't work. No, * I don't entirely understand what this does... */ -# define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f -# define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 +#define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f +#define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 #define DPLL_TEST 0x606c -# define DPLLB_TEST_SDVO_DIV_1 (0 << 22) -# define DPLLB_TEST_SDVO_DIV_2 (1 << 22) -# define DPLLB_TEST_SDVO_DIV_4 (2 << 22) -# define DPLLB_TEST_SDVO_DIV_MASK (3 << 22) -# define DPLLB_TEST_N_BYPASS (1 << 19) -# define DPLLB_TEST_M_BYPASS (1 << 18) -# define DPLLB_INPUT_BUFFER_ENABLE (1 << 16) -# define DPLLA_TEST_N_BYPASS (1 << 3) -# define DPLLA_TEST_M_BYPASS (1 << 2) -# define DPLLA_INPUT_BUFFER_ENABLE (1 << 0) +#define DPLLB_TEST_SDVO_DIV_1 (0 << 22) +#define DPLLB_TEST_SDVO_DIV_2 (1 << 22) +#define DPLLB_TEST_SDVO_DIV_4 (2 << 22) +#define DPLLB_TEST_SDVO_DIV_MASK (3 << 22) +#define DPLLB_TEST_N_BYPASS (1 << 19) +#define DPLLB_TEST_M_BYPASS (1 << 18) +#define DPLLB_INPUT_BUFFER_ENABLE (1 << 16) +#define DPLLA_TEST_N_BYPASS (1 << 3) +#define DPLLA_TEST_M_BYPASS (1 << 2) +#define DPLLA_INPUT_BUFFER_ENABLE (1 << 0) #define ADPA 0x61100 -#define ADPA_DAC_ENABLE (1<<31) -#define ADPA_DAC_DISABLE 0 -#define ADPA_PIPE_SELECT_MASK (1<<30) -#define ADPA_PIPE_A_SELECT 0 -#define ADPA_PIPE_B_SELECT (1<<30) -#define ADPA_USE_VGA_HVPOLARITY (1<<15) -#define ADPA_SETS_HVPOLARITY 0 -#define ADPA_VSYNC_CNTL_DISABLE (1<<11) -#define ADPA_VSYNC_CNTL_ENABLE 0 -#define ADPA_HSYNC_CNTL_DISABLE (1<<10) -#define ADPA_HSYNC_CNTL_ENABLE 0 -#define ADPA_VSYNC_ACTIVE_HIGH (1<<4) -#define ADPA_VSYNC_ACTIVE_LOW 0 -#define ADPA_HSYNC_ACTIVE_HIGH (1<<3) -#define ADPA_HSYNC_ACTIVE_LOW 0 - -#define FPA0 0x06040 -#define FPA1 0x06044 -#define FPB0 0x06048 -#define FPB1 0x0604c -# define FP_N_DIV_MASK 0x003f0000 -# define FP_N_DIV_SHIFT 16 -# define FP_M1_DIV_MASK 0x00003f00 -# define FP_M1_DIV_SHIFT 8 -# define FP_M2_DIV_MASK 0x0000003f -# define FP_M2_DIV_SHIFT 0 - +#define ADPA_DAC_ENABLE (1 << 31) +#define ADPA_DAC_DISABLE 0 +#define ADPA_PIPE_SELECT_MASK (1 << 30) +#define ADPA_PIPE_A_SELECT 0 +#define ADPA_PIPE_B_SELECT (1 << 30) +#define ADPA_USE_VGA_HVPOLARITY (1 << 15) +#define ADPA_SETS_HVPOLARITY 0 +#define ADPA_VSYNC_CNTL_DISABLE (1 << 11) +#define ADPA_VSYNC_CNTL_ENABLE 0 +#define ADPA_HSYNC_CNTL_DISABLE (1 << 10) +#define ADPA_HSYNC_CNTL_ENABLE 0 +#define ADPA_VSYNC_ACTIVE_HIGH (1 << 4) +#define ADPA_VSYNC_ACTIVE_LOW 0 +#define ADPA_HSYNC_ACTIVE_HIGH (1 << 3) +#define ADPA_HSYNC_ACTIVE_LOW 0 + +#define FPA0 0x06040 +#define FPA1 0x06044 +#define FPB0 0x06048 +#define FPB1 0x0604c +#define FP_N_DIV_MASK 0x003f0000 +#define FP_N_DIV_SHIFT 16 +#define FP_M1_DIV_MASK 0x00003f00 +#define FP_M1_DIV_SHIFT 8 +#define FP_M2_DIV_MASK 0x0000003f +#define FP_M2_DIV_SHIFT 0 #define PORT_HOTPLUG_EN 0x61110 -# define SDVOB_HOTPLUG_INT_EN (1 << 26) -# define SDVOC_HOTPLUG_INT_EN (1 << 25) -# define TV_HOTPLUG_INT_EN (1 << 18) -# define CRT_HOTPLUG_INT_EN (1 << 9) -# define CRT_HOTPLUG_FORCE_DETECT (1 << 3) +#define SDVOB_HOTPLUG_INT_EN (1 << 26) +#define SDVOC_HOTPLUG_INT_EN (1 << 25) +#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) -# define TV_HOTPLUG_INT_STATUS (1 << 10) -# define CRT_HOTPLUG_MONITOR_MASK (3 << 8) -# define CRT_HOTPLUG_MONITOR_COLOR (3 << 8) -# define CRT_HOTPLUG_MONITOR_MONO (2 << 8) -# define CRT_HOTPLUG_MONITOR_NONE (0 << 8) -# define SDVOC_HOTPLUG_INT_STATUS (1 << 7) -# define SDVOB_HOTPLUG_INT_STATUS (1 << 6) +#define CRT_HOTPLUG_INT_STATUS (1 << 11) +#define TV_HOTPLUG_INT_STATUS (1 << 10) +#define CRT_HOTPLUG_MONITOR_MASK (3 << 8) +#define CRT_HOTPLUG_MONITOR_COLOR (3 << 8) +#define CRT_HOTPLUG_MONITOR_MONO (2 << 8) +#define CRT_HOTPLUG_MONITOR_NONE (0 << 8) +#define SDVOC_HOTPLUG_INT_STATUS (1 << 7) +#define SDVOB_HOTPLUG_INT_STATUS (1 << 6) #define SDVOB 0x61140 #define SDVOC 0x61160 -#define SDVO_ENABLE (1 << 31) -#define SDVO_PIPE_B_SELECT (1 << 30) -#define SDVO_STALL_SELECT (1 << 29) -#define SDVO_INTERRUPT_ENABLE (1 << 26) +#define SDVO_ENABLE (1 << 31) +#define SDVO_PIPE_B_SELECT (1 << 30) +#define SDVO_STALL_SELECT (1 << 29) +#define SDVO_INTERRUPT_ENABLE (1 << 26) + /** * 915G/GM SDVO pixel multiplier. * @@ -297,18 +312,18 @@ * * DPLL_MD_UDI_MULTIPLIER_MASK */ -#define SDVO_PORT_MULTIPLY_MASK (7 << 23) -#define SDVO_PORT_MULTIPLY_SHIFT 23 -#define SDVO_PHASE_SELECT_MASK (15 << 19) -#define SDVO_PHASE_SELECT_DEFAULT (6 << 19) -#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18) -#define SDVOC_GANG_MODE (1 << 16) -#define SDVO_BORDER_ENABLE (1 << 7) -#define SDVOB_PCIE_CONCURRENCY (1 << 3) -#define SDVO_DETECTED (1 << 2) +#define SDVO_PORT_MULTIPLY_MASK (7 << 23) +#define SDVO_PORT_MULTIPLY_SHIFT 23 +#define SDVO_PHASE_SELECT_MASK (15 << 19) +#define SDVO_PHASE_SELECT_DEFAULT (6 << 19) +#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18) +#define SDVOC_GANG_MODE (1 << 16) +#define SDVO_BORDER_ENABLE (1 << 7) +#define SDVOB_PCIE_CONCURRENCY (1 << 3) +#define SDVO_DETECTED (1 << 2) /* Bits to be preserved when writing */ #define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14)) -#define SDVOC_PRESERVE_MASK (1 << 17) +#define SDVOC_PRESERVE_MASK (1 << 17) /* * This register controls the LVDS output enable, pipe selection, and data @@ -321,116 +336,116 @@ * Enables the LVDS port. This bit must be set before DPLLs are enabled, as * the DPLL semantics change when the LVDS is assigned to that pipe. */ -# define LVDS_PORT_EN (1 << 31) +#define LVDS_PORT_EN (1 << 31) /* Selects pipe B for LVDS data. Must be set on pre-965. */ -# define LVDS_PIPEB_SELECT (1 << 30) +#define LVDS_PIPEB_SELECT (1 << 30) /* Turns on border drawing to allow centered display. */ -# define LVDS_BORDER_EN (1 << 15) +#define LVDS_BORDER_EN (1 << 15) /* * Enables the A0-A2 data pairs and CLKA, containing 18 bits of color data per * pixel. */ -# define LVDS_A0A2_CLKA_POWER_MASK (3 << 8) -# define LVDS_A0A2_CLKA_POWER_DOWN (0 << 8) -# define LVDS_A0A2_CLKA_POWER_UP (3 << 8) +#define LVDS_A0A2_CLKA_POWER_MASK (3 << 8) +#define LVDS_A0A2_CLKA_POWER_DOWN (0 << 8) +#define LVDS_A0A2_CLKA_POWER_UP (3 << 8) /* * Controls the A3 data pair, which contains the additional LSBs for 24 bit * mode. Only enabled if LVDS_A0A2_CLKA_POWER_UP also indicates it should be * on. */ -# define LVDS_A3_POWER_MASK (3 << 6) -# define LVDS_A3_POWER_DOWN (0 << 6) -# define LVDS_A3_POWER_UP (3 << 6) +#define LVDS_A3_POWER_MASK (3 << 6) +#define LVDS_A3_POWER_DOWN (0 << 6) +#define LVDS_A3_POWER_UP (3 << 6) /* * Controls the CLKB pair. This should only be set when LVDS_B0B3_POWER_UP * is set. */ -# define LVDS_CLKB_POWER_MASK (3 << 4) -# define LVDS_CLKB_POWER_DOWN (0 << 4) -# define LVDS_CLKB_POWER_UP (3 << 4) +#define LVDS_CLKB_POWER_MASK (3 << 4) +#define LVDS_CLKB_POWER_DOWN (0 << 4) +#define LVDS_CLKB_POWER_UP (3 << 4) /* * Controls the B0-B3 data pairs. This must be set to match the DPLL p2 * setting for whether we are in dual-channel mode. The B3 pair will * additionally only be powered up when LVDS_A3_POWER_UP is set. */ -# define LVDS_B0B3_POWER_MASK (3 << 2) -# define LVDS_B0B3_POWER_DOWN (0 << 2) -# define LVDS_B0B3_POWER_UP (3 << 2) - -#define PIPEACONF 0x70008 -#define PIPEACONF_ENABLE (1<<31) -#define PIPEACONF_DISABLE 0 -#define PIPEACONF_DOUBLE_WIDE (1<<30) -#define PIPECONF_ACTIVE (1<<30) -#define I965_PIPECONF_ACTIVE (1<<30) -#define PIPECONF_DSIPLL_LOCK (1<<29) -#define PIPEACONF_SINGLE_WIDE 0 -#define PIPEACONF_PIPE_UNLOCKED 0 -#define PIPEACONF_DSR (1<<26) -#define PIPEACONF_PIPE_LOCKED (1<<25) -#define PIPEACONF_PALETTE 0 -#define PIPECONF_FORCE_BORDER (1<<25) -#define PIPEACONF_GAMMA (1<<24) -#define PIPECONF_PROGRESSIVE (0 << 21) +#define LVDS_B0B3_POWER_MASK (3 << 2) +#define LVDS_B0B3_POWER_DOWN (0 << 2) +#define LVDS_B0B3_POWER_UP (3 << 2) + +#define PIPEACONF 0x70008 +#define PIPEACONF_ENABLE (1 << 31) +#define PIPEACONF_DISABLE 0 +#define PIPEACONF_DOUBLE_WIDE (1 << 30) +#define PIPECONF_ACTIVE (1 << 30) +#define I965_PIPECONF_ACTIVE (1 << 30) +#define PIPECONF_DSIPLL_LOCK (1 << 29) +#define PIPEACONF_SINGLE_WIDE 0 +#define PIPEACONF_PIPE_UNLOCKED 0 +#define PIPEACONF_DSR (1 << 26) +#define PIPEACONF_PIPE_LOCKED (1 << 25) +#define PIPEACONF_PALETTE 0 +#define PIPECONF_FORCE_BORDER (1 << 25) +#define PIPEACONF_GAMMA (1 << 24) +#define PIPECONF_PROGRESSIVE (0 << 21) #define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21) #define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) -#define PIPECONF_PLANE_OFF (1<<19) -#define PIPECONF_CURSOR_OFF (1<<18) - +#define PIPECONF_PLANE_OFF (1 << 19) +#define PIPECONF_CURSOR_OFF (1 << 18) -#define PIPEBCONF 0x71008 -#define PIPEBCONF_ENABLE (1<<31) -#define PIPEBCONF_DISABLE 0 -#define PIPEBCONF_DOUBLE_WIDE (1<<30) -#define PIPEBCONF_DISABLE 0 -#define PIPEBCONF_GAMMA (1<<24) -#define PIPEBCONF_PALETTE 0 +#define PIPEBCONF 0x71008 +#define PIPEBCONF_ENABLE (1 << 31) +#define PIPEBCONF_DISABLE 0 +#define PIPEBCONF_DOUBLE_WIDE (1 << 30) +#define PIPEBCONF_DISABLE 0 +#define PIPEBCONF_GAMMA (1 << 24) +#define PIPEBCONF_PALETTE 0 -#define PIPECCONF 0x72008 +#define PIPECCONF 0x72008 #define PIPEBGCMAXRED 0x71010 #define PIPEBGCMAXGREEN 0x71014 #define PIPEBGCMAXBLUE 0x71018 -#define PIPEASTAT 0x70024 +#define PIPEASTAT 0x70024 #define PIPEBSTAT 0x71024 #define PIPECSTAT 0x72024 -#define PIPE_VBLANK_INTERRUPT_STATUS (1UL<<1) -#define PIPE_START_VBLANK_INTERRUPT_STATUS (1UL<<2) -#define PIPE_VBLANK_CLEAR (1 << 1) -#define PIPE_VBLANK_STATUS (1 << 1) -#define PIPE_TE_STATUS (1UL<<6) -#define PIPE_DPST_EVENT_STATUS (1UL<<7) -#define PIPE_VSYNC_CLEAR (1UL<<9) -#define PIPE_VSYNC_STATUS (1UL<<9) -#define PIPE_HDMI_AUDIO_UNDERRUN_STATUS (1UL<<10) -#define PIPE_HDMI_AUDIO_BUFFER_DONE_STATUS (1UL<<11) -#define PIPE_VBLANK_INTERRUPT_ENABLE (1UL<<17) -#define PIPE_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) -#define PIPE_TE_ENABLE (1UL<<22) -#define PIPE_DPST_EVENT_ENABLE (1UL<<23) -#define PIPE_VSYNC_ENABL (1UL<<25) -#define PIPE_HDMI_AUDIO_UNDERRUN (1UL<<26) -#define PIPE_HDMI_AUDIO_BUFFER_DONE (1UL<<27) -#define PIPE_HDMI_AUDIO_INT_MASK (PIPE_HDMI_AUDIO_UNDERRUN | PIPE_HDMI_AUDIO_BUFFER_DONE) +#define PIPE_VBLANK_INTERRUPT_STATUS (1UL << 1) +#define PIPE_START_VBLANK_INTERRUPT_STATUS (1UL << 2) +#define PIPE_VBLANK_CLEAR (1 << 1) +#define PIPE_VBLANK_STATUS (1 << 1) +#define PIPE_TE_STATUS (1UL << 6) +#define PIPE_DPST_EVENT_STATUS (1UL << 7) +#define PIPE_VSYNC_CLEAR (1UL << 9) +#define PIPE_VSYNC_STATUS (1UL << 9) +#define PIPE_HDMI_AUDIO_UNDERRUN_STATUS (1UL << 10) +#define PIPE_HDMI_AUDIO_BUFFER_DONE_STATUS (1UL << 11) +#define PIPE_VBLANK_INTERRUPT_ENABLE (1UL << 17) +#define PIPE_START_VBLANK_INTERRUPT_ENABLE (1UL << 18) +#define PIPE_TE_ENABLE (1UL << 22) +#define PIPE_DPST_EVENT_ENABLE (1UL << 23) +#define PIPE_VSYNC_ENABL (1UL << 25) +#define PIPE_HDMI_AUDIO_UNDERRUN (1UL << 26) +#define PIPE_HDMI_AUDIO_BUFFER_DONE (1UL << 27) +#define PIPE_HDMI_AUDIO_INT_MASK (PIPE_HDMI_AUDIO_UNDERRUN | \ + PIPE_HDMI_AUDIO_BUFFER_DONE) #define PIPE_EVENT_MASK ((1 << 29)|(1 << 28)|(1 << 27)|(1 << 26)|(1 << 24)|(1 << 23)|(1 << 22)|(1 << 21)|(1 << 20)|(1 << 16)) #define PIPE_VBLANK_MASK ((1 << 25)|(1 << 24)|(1 << 18)|(1 << 17)) #define HISTOGRAM_INT_CONTROL 0x61268 #define HISTOGRAM_BIN_DATA 0X61264 #define HISTOGRAM_LOGIC_CONTROL 0x61260 #define PWM_CONTROL_LOGIC 0x61250 -#define PIPE_HOTPLUG_INTERRUPT_STATUS (1UL<<10) -#define HISTOGRAM_INTERRUPT_ENABLE (1UL<<31) -#define HISTOGRAM_LOGIC_ENABLE (1UL<<31) -#define PWM_LOGIC_ENABLE (1UL<<31) -#define PWM_PHASEIN_ENABLE (1UL<<25) -#define PWM_PHASEIN_INT_ENABLE (1UL<<24) -#define PWM_PHASEIN_VB_COUNT 0x00001f00 -#define PWM_PHASEIN_INC 0x0000001f -#define HISTOGRAM_INT_CTRL_CLEAR (1UL<<30) -#define DPST_YUV_LUMA_MODE 0 +#define PIPE_HOTPLUG_INTERRUPT_STATUS (1UL << 10) +#define HISTOGRAM_INTERRUPT_ENABLE (1UL << 31) +#define HISTOGRAM_LOGIC_ENABLE (1UL << 31) +#define PWM_LOGIC_ENABLE (1UL << 31) +#define PWM_PHASEIN_ENABLE (1UL << 25) +#define PWM_PHASEIN_INT_ENABLE (1UL << 24) +#define PWM_PHASEIN_VB_COUNT 0x00001f00 +#define PWM_PHASEIN_INC 0x0000001f +#define HISTOGRAM_INT_CTRL_CLEAR (1UL << 30) +#define DPST_YUV_LUMA_MODE 0 struct dpst_ie_histogram_control { union { @@ -470,12 +485,12 @@ struct dpst_guardband { #define PIPEBFRAMEPIXEL 0x71044 #define PIPECFRAMEHIGH 0x72040 #define PIPECFRAMEPIXEL 0x72044 -#define PIPE_FRAME_HIGH_MASK 0x0000ffff -#define PIPE_FRAME_HIGH_SHIFT 0 -#define PIPE_FRAME_LOW_MASK 0xff000000 -#define PIPE_FRAME_LOW_SHIFT 24 -#define PIPE_PIXEL_MASK 0x00ffffff -#define PIPE_PIXEL_SHIFT 0 +#define PIPE_FRAME_HIGH_MASK 0x0000ffff +#define PIPE_FRAME_HIGH_SHIFT 0 +#define PIPE_FRAME_LOW_MASK 0xff000000 +#define PIPE_FRAME_LOW_SHIFT 24 +#define PIPE_PIXEL_MASK 0x00ffffff +#define PIPE_PIXEL_SHIFT 0 #define DSPARB 0x70030 #define DSPFW1 0x70034 @@ -488,30 +503,30 @@ struct dpst_guardband { #define DSPACNTR 0x70180 #define DSPBCNTR 0x71180 #define DSPCCNTR 0x72180 -#define DISPLAY_PLANE_ENABLE (1<<31) +#define DISPLAY_PLANE_ENABLE (1 << 31) #define DISPLAY_PLANE_DISABLE 0 -#define DISPPLANE_GAMMA_ENABLE (1<<30) +#define DISPPLANE_GAMMA_ENABLE (1 << 30) #define DISPPLANE_GAMMA_DISABLE 0 -#define DISPPLANE_PIXFORMAT_MASK (0xf<<26) -#define DISPPLANE_8BPP (0x2<<26) -#define DISPPLANE_15_16BPP (0x4<<26) -#define DISPPLANE_16BPP (0x5<<26) -#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26) -#define DISPPLANE_32BPP (0x7<<26) -#define DISPPLANE_STEREO_ENABLE (1<<25) +#define DISPPLANE_PIXFORMAT_MASK (0xf << 26) +#define DISPPLANE_8BPP (0x2 << 26) +#define DISPPLANE_15_16BPP (0x4 << 26) +#define DISPPLANE_16BPP (0x5 << 26) +#define DISPPLANE_32BPP_NO_ALPHA (0x6 << 26) +#define DISPPLANE_32BPP (0x7 << 26) +#define DISPPLANE_STEREO_ENABLE (1 << 25) #define DISPPLANE_STEREO_DISABLE 0 -#define DISPPLANE_SEL_PIPE_MASK (1<<24) +#define DISPPLANE_SEL_PIPE_MASK (1 << 24) #define DISPPLANE_SEL_PIPE_POS 24 #define DISPPLANE_SEL_PIPE_A 0 -#define DISPPLANE_SEL_PIPE_B (1<<24) -#define DISPPLANE_SRC_KEY_ENABLE (1<<22) +#define DISPPLANE_SEL_PIPE_B (1 << 24) +#define DISPPLANE_SRC_KEY_ENABLE (1 << 22) #define DISPPLANE_SRC_KEY_DISABLE 0 -#define DISPPLANE_LINE_DOUBLE (1<<20) +#define DISPPLANE_LINE_DOUBLE (1 << 20) #define DISPPLANE_NO_LINE_DOUBLE 0 #define DISPPLANE_STEREO_POLARITY_FIRST 0 -#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18) +#define DISPPLANE_STEREO_POLARITY_SECOND (1 << 18) /* plane B only */ -#define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15) +#define DISPPLANE_ALPHA_TRANS_ENABLE (1 << 15) #define DISPPLANE_ALPHA_TRANS_DISABLE 0 #define DISPPLANE_SPRITE_ABOVE_DISPLAYA 0 #define DISPPLANE_SPRITE_ABOVE_OVERLAY (1) @@ -548,25 +563,25 @@ struct dpst_guardband { #define DSPCSURF 0x7219C #define DSPCTILEOFF 0x721A4 -#define DSPCKEYMAXVAL 0x721A0 -#define DSPCKEYMINVAL 0x72194 -#define DSPCKEYMSK 0x72198 +#define DSPCKEYMAXVAL 0x721A0 +#define DSPCKEYMINVAL 0x72194 +#define DSPCKEYMSK 0x72198 #define VGACNTRL 0x71400 -# define VGA_DISP_DISABLE (1 << 31) -# define VGA_2X_MODE (1 << 30) -# define VGA_PIPE_B_SELECT (1 << 29) +#define VGA_DISP_DISABLE (1 << 31) +#define VGA_2X_MODE (1 << 30) +#define VGA_PIPE_B_SELECT (1 << 29) /* * Overlay registers */ #define OV_C_OFFSET 0x08000 #define OV_OVADD 0x30000 -#define OV_DOVASTA 0x30008 -# define OV_PIPE_SELECT ((1 << 6)|(1 << 7)) -# define OV_PIPE_SELECT_POS 6 -# define OV_PIPE_A 0 -# define OV_PIPE_C 1 +#define OV_DOVASTA 0x30008 +# define OV_PIPE_SELECT ((1 << 6)|(1 << 7)) +# define OV_PIPE_SELECT_POS 6 +# define OV_PIPE_A 0 +# define OV_PIPE_C 1 #define OV_OGAMC5 0x30010 #define OV_OGAMC4 0x30014 #define OV_OGAMC3 0x30018 @@ -574,7 +589,7 @@ struct dpst_guardband { #define OV_OGAMC1 0x30020 #define OV_OGAMC0 0x30024 #define OVC_OVADD 0x38000 -#define OVC_DOVCSTA 0x38008 +#define OVC_DOVCSTA 0x38008 #define OVC_OGAMC5 0x38010 #define OVC_OGAMC4 0x38014 #define OVC_OGAMC3 0x38018 @@ -627,16 +642,16 @@ struct dpst_guardband { /* Cursor A & B regs */ #define CURACNTR 0x70080 -#define CURSOR_MODE_DISABLE 0x00 -#define CURSOR_MODE_64_32B_AX 0x07 -#define CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX) -#define MCURSOR_GAMMA_ENABLE (1 << 26) +#define CURSOR_MODE_DISABLE 0x00 +#define CURSOR_MODE_64_32B_AX 0x07 +#define CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX) +#define MCURSOR_GAMMA_ENABLE (1 << 26) #define CURABASE 0x70084 #define CURAPOS 0x70088 -#define CURSOR_POS_MASK 0x007FF -#define CURSOR_POS_SIGN 0x8000 -#define CURSOR_X_SHIFT 0 -#define CURSOR_Y_SHIFT 16 +#define CURSOR_POS_MASK 0x007FF +#define CURSOR_POS_SIGN 0x8000 +#define CURSOR_X_SHIFT 0 +#define CURSOR_Y_SHIFT 16 #define CURBCNTR 0x700c0 #define CURBBASE 0x700c4 #define CURBPOS 0x700c8 @@ -647,22 +662,22 @@ struct dpst_guardband { /* * Interrupt Registers */ -#define IER 0x020a0 -#define IIR 0x020a4 -#define IMR 0x020a8 -#define ISR 0x020ac +#define IER 0x020a0 +#define IIR 0x020a4 +#define IMR 0x020a8 +#define ISR 0x020ac /* * 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 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 @@ -672,45 +687,45 @@ struct dpst_guardband { /* * MEDFIELD HDMI registers */ -#define HDMIPHYMISCCTL 0x61134 -# define HDMI_PHY_POWER_DOWN 0x7f -#define HDMIB_CONTROL 0x61140 -# define HDMIB_PORT_EN (1 << 31) -# define HDMIB_PIPE_B_SELECT (1 << 30) -# define HDMIB_NULL_PACKET (1 << 9) -#define HDMIB_HDCP_PORT (1 << 5) +#define HDMIPHYMISCCTL 0x61134 +#define HDMI_PHY_POWER_DOWN 0x7f +#define HDMIB_CONTROL 0x61140 +#define HDMIB_PORT_EN (1 << 31) +#define HDMIB_PIPE_B_SELECT (1 << 30) +#define HDMIB_NULL_PACKET (1 << 9) +#define HDMIB_HDCP_PORT (1 << 5) /* #define LVDS 0x61180 */ -# define MRST_PANEL_8TO6_DITHER_ENABLE (1 << 25) -# define MRST_PANEL_24_DOT_1_FORMAT (1 << 24) -# define LVDS_A3_POWER_UP_0_OUTPUT (1 << 6) +#define MRST_PANEL_8TO6_DITHER_ENABLE (1 << 25) +#define MRST_PANEL_24_DOT_1_FORMAT (1 << 24) +#define LVDS_A3_POWER_UP_0_OUTPUT (1 << 6) #define MIPI 0x61190 #define MIPI_C 0x62190 -# define MIPI_PORT_EN (1 << 31) +#define MIPI_PORT_EN (1 << 31) /* Turns on border drawing to allow centered display. */ -# define SEL_FLOPPED_HSTX (1 << 23) -# define PASS_FROM_SPHY_TO_AFE (1 << 16) -# define MIPI_BORDER_EN (1 << 15) -# define MIPIA_3LANE_MIPIC_1LANE 0x1 -# define MIPIA_2LANE_MIPIC_2LANE 0x2 -# define TE_TRIGGER_DSI_PROTOCOL (1 << 2) -# define TE_TRIGGER_GPIO_PIN (1 << 3) -#define MIPI_TE_COUNT 0x61194 +#define SEL_FLOPPED_HSTX (1 << 23) +#define PASS_FROM_SPHY_TO_AFE (1 << 16) +#define MIPI_BORDER_EN (1 << 15) +#define MIPIA_3LANE_MIPIC_1LANE 0x1 +#define MIPIA_2LANE_MIPIC_2LANE 0x2 +#define TE_TRIGGER_DSI_PROTOCOL (1 << 2) +#define TE_TRIGGER_GPIO_PIN (1 << 3) +#define MIPI_TE_COUNT 0x61194 /* #define PP_CONTROL 0x61204 */ -# define POWER_DOWN_ON_RESET (1 << 1) +#define POWER_DOWN_ON_RESET (1 << 1) /* #define PFIT_CONTROL 0x61230 */ -# define PFIT_PIPE_SELECT (3 << 29) -# define PFIT_PIPE_SELECT_SHIFT (29) +#define PFIT_PIPE_SELECT (3 << 29) +#define PFIT_PIPE_SELECT_SHIFT (29) /* #define BLC_PWM_CTL 0x61254 */ -#define MRST_BACKLIGHT_MODULATION_FREQ_SHIFT (16) -#define MRST_BACKLIGHT_MODULATION_FREQ_MASK (0xffff << 16) +#define MRST_BACKLIGHT_MODULATION_FREQ_SHIFT (16) +#define MRST_BACKLIGHT_MODULATION_FREQ_MASK (0xffff << 16) /* #define PIPEACONF 0x70008 */ -#define PIPEACONF_PIPE_STATE (1<<30) +#define PIPEACONF_PIPE_STATE (1 << 30) /* #define DSPACNTR 0x70180 */ #define MRST_DSPABASE 0x7019c @@ -724,281 +739,286 @@ struct dpst_guardband { /* * MIPI IP registers */ -#define MIPIC_REG_OFFSET 0x800 -#define DEVICE_READY_REG 0xb000 -#define LP_OUTPUT_HOLD (1 << 16) -#define EXIT_ULPS_DEV_READY 0x3 -#define LP_OUTPUT_HOLD_RELEASE 0x810000 -# define ENTERING_ULPS (2 << 1) -# define EXITING_ULPS (1 << 1) -# define ULPS_MASK (3 << 1) -# define BUS_POSSESSION (1 << 3) -#define INTR_STAT_REG 0xb004 -#define RX_SOT_ERROR (1 << 0) -#define RX_SOT_SYNC_ERROR (1 << 1) -#define RX_ESCAPE_MODE_ENTRY_ERROR (1 << 3) -#define RX_LP_TX_SYNC_ERROR (1 << 4) -#define RX_HS_RECEIVE_TIMEOUT_ERROR (1 << 5) -#define RX_FALSE_CONTROL_ERROR (1 << 6) -#define RX_ECC_SINGLE_BIT_ERROR (1 << 7) -#define RX_ECC_MULTI_BIT_ERROR (1 << 8) -#define RX_CHECKSUM_ERROR (1 << 9) -#define RX_DSI_DATA_TYPE_NOT_RECOGNIZED (1 << 10) -#define RX_DSI_VC_ID_INVALID (1 << 11) -#define TX_FALSE_CONTROL_ERROR (1 << 12) -#define TX_ECC_SINGLE_BIT_ERROR (1 << 13) -#define TX_ECC_MULTI_BIT_ERROR (1 << 14) -#define TX_CHECKSUM_ERROR (1 << 15) -#define TX_DSI_DATA_TYPE_NOT_RECOGNIZED (1 << 16) -#define TX_DSI_VC_ID_INVALID (1 << 17) -#define HIGH_CONTENTION (1 << 18) -#define LOW_CONTENTION (1 << 19) -#define DPI_FIFO_UNDER_RUN (1 << 20) -#define HS_TX_TIMEOUT (1 << 21) -#define LP_RX_TIMEOUT (1 << 22) -#define TURN_AROUND_ACK_TIMEOUT (1 << 23) -#define ACK_WITH_NO_ERROR (1 << 24) -#define HS_GENERIC_WR_FIFO_FULL (1 << 27) -#define LP_GENERIC_WR_FIFO_FULL (1 << 28) -#define SPL_PKT_SENT (1 << 30) -#define INTR_EN_REG 0xb008 -#define DSI_FUNC_PRG_REG 0xb00c -#define DPI_CHANNEL_NUMBER_POS 0x03 -#define DBI_CHANNEL_NUMBER_POS 0x05 -#define FMT_DPI_POS 0x07 -#define FMT_DBI_POS 0x0A -#define DBI_DATA_WIDTH_POS 0x0D +#define MIPIC_REG_OFFSET 0x800 + +#define DEVICE_READY_REG 0xb000 +#define LP_OUTPUT_HOLD (1 << 16) +#define EXIT_ULPS_DEV_READY 0x3 +#define LP_OUTPUT_HOLD_RELEASE 0x810000 +# define ENTERING_ULPS (2 << 1) +# define EXITING_ULPS (1 << 1) +# define ULPS_MASK (3 << 1) +# define BUS_POSSESSION (1 << 3) +#define INTR_STAT_REG 0xb004 +#define RX_SOT_ERROR (1 << 0) +#define RX_SOT_SYNC_ERROR (1 << 1) +#define RX_ESCAPE_MODE_ENTRY_ERROR (1 << 3) +#define RX_LP_TX_SYNC_ERROR (1 << 4) +#define RX_HS_RECEIVE_TIMEOUT_ERROR (1 << 5) +#define RX_FALSE_CONTROL_ERROR (1 << 6) +#define RX_ECC_SINGLE_BIT_ERROR (1 << 7) +#define RX_ECC_MULTI_BIT_ERROR (1 << 8) +#define RX_CHECKSUM_ERROR (1 << 9) +#define RX_DSI_DATA_TYPE_NOT_RECOGNIZED (1 << 10) +#define RX_DSI_VC_ID_INVALID (1 << 11) +#define TX_FALSE_CONTROL_ERROR (1 << 12) +#define TX_ECC_SINGLE_BIT_ERROR (1 << 13) +#define TX_ECC_MULTI_BIT_ERROR (1 << 14) +#define TX_CHECKSUM_ERROR (1 << 15) +#define TX_DSI_DATA_TYPE_NOT_RECOGNIZED (1 << 16) +#define TX_DSI_VC_ID_INVALID (1 << 17) +#define HIGH_CONTENTION (1 << 18) +#define LOW_CONTENTION (1 << 19) +#define DPI_FIFO_UNDER_RUN (1 << 20) +#define HS_TX_TIMEOUT (1 << 21) +#define LP_RX_TIMEOUT (1 << 22) +#define TURN_AROUND_ACK_TIMEOUT (1 << 23) +#define ACK_WITH_NO_ERROR (1 << 24) +#define HS_GENERIC_WR_FIFO_FULL (1 << 27) +#define LP_GENERIC_WR_FIFO_FULL (1 << 28) +#define SPL_PKT_SENT (1 << 30) +#define INTR_EN_REG 0xb008 +#define DSI_FUNC_PRG_REG 0xb00c +#define DPI_CHANNEL_NUMBER_POS 0x03 +#define DBI_CHANNEL_NUMBER_POS 0x05 +#define FMT_DPI_POS 0x07 +#define FMT_DBI_POS 0x0A +#define DBI_DATA_WIDTH_POS 0x0D + /* DPI PIXEL FORMATS */ -#define RGB_565_FMT 0x01 /* RGB 565 FORMAT */ -#define RGB_666_FMT 0x02 /* RGB 666 FORMAT */ -#define LRGB_666_FMT 0x03 /* RGB LOOSELY PACKED - * 666 FORMAT - */ -#define RGB_888_FMT 0x04 /* RGB 888 FORMAT */ -#define VIRTUAL_CHANNEL_NUMBER_0 0x00 /* Virtual channel 0 */ -#define VIRTUAL_CHANNEL_NUMBER_1 0x01 /* Virtual channel 1 */ -#define VIRTUAL_CHANNEL_NUMBER_2 0x02 /* Virtual channel 2 */ -#define VIRTUAL_CHANNEL_NUMBER_3 0x03 /* Virtual channel 3 */ -#define DBI_NOT_SUPPORTED 0x00 /* command mode - * is not supported - */ -#define DBI_DATA_WIDTH_16BIT 0x01 /* 16 bit data */ +#define RGB_565_FMT 0x01 /* RGB 565 FORMAT */ +#define RGB_666_FMT 0x02 /* RGB 666 FORMAT */ +#define LRGB_666_FMT 0x03 /* RGB LOOSELY PACKED + * 666 FORMAT + */ +#define RGB_888_FMT 0x04 /* RGB 888 FORMAT */ +#define VIRTUAL_CHANNEL_NUMBER_0 0x00 /* Virtual channel 0 */ +#define VIRTUAL_CHANNEL_NUMBER_1 0x01 /* Virtual channel 1 */ +#define VIRTUAL_CHANNEL_NUMBER_2 0x02 /* Virtual channel 2 */ +#define VIRTUAL_CHANNEL_NUMBER_3 0x03 /* Virtual channel 3 */ + +#define DBI_NOT_SUPPORTED 0x00 /* command mode + * is not supported + */ +#define DBI_DATA_WIDTH_16BIT 0x01 /* 16 bit data */ #define DBI_DATA_WIDTH_9BIT 0x02 /* 9 bit data */ #define DBI_DATA_WIDTH_8BIT 0x03 /* 8 bit data */ -#define DBI_DATA_WIDTH_OPT1 0x04 /* option 1 */ -#define DBI_DATA_WIDTH_OPT2 0x05 /* option 2 */ -#define HS_TX_TIMEOUT_REG 0xb010 -#define LP_RX_TIMEOUT_REG 0xb014 -#define TURN_AROUND_TIMEOUT_REG 0xb018 -#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 -#define HORIZ_ACTIVE_AREA_COUNT_REG 0xb034 -#define VERT_SYNC_PAD_COUNT_REG 0xb038 -#define VERT_BACK_PORCH_COUNT_REG 0xb03c -#define VERT_FRONT_PORCH_COUNT_REG 0xb040 -#define HIGH_LOW_SWITCH_COUNT_REG 0xb044 -#define DPI_CONTROL_REG 0xb048 -#define DPI_SHUT_DOWN (1 << 0) -#define DPI_TURN_ON (1 << 1) -#define DPI_COLOR_MODE_ON (1 << 2) -#define DPI_COLOR_MODE_OFF (1 << 3) -#define DPI_BACK_LIGHT_ON (1 << 4) -#define DPI_BACK_LIGHT_OFF (1 << 5) -#define DPI_LP (1 << 6) -#define DPI_DATA_REG 0xb04c -#define DPI_BACK_LIGHT_ON_DATA 0x07 -#define DPI_BACK_LIGHT_OFF_DATA 0x17 -#define INIT_COUNT_REG 0xb050 -#define MAX_RET_PAK_REG 0xb054 -#define VIDEO_FMT_REG 0xb058 -#define COMPLETE_LAST_PCKT (1 << 2) -#define EOT_DISABLE_REG 0xb05c -#define ENABLE_CLOCK_STOPPING (1 << 1) -#define LP_BYTECLK_REG 0xb060 -#define LP_GEN_DATA_REG 0xb064 -#define HS_GEN_DATA_REG 0xb068 -#define LP_GEN_CTRL_REG 0xb06C -#define HS_GEN_CTRL_REG 0xb070 -#define DCS_CHANNEL_NUMBER_POS 0x06 -#define MCS_COMMANDS_POS 0x8 -#define WORD_COUNTS_POS 0x8 -#define MCS_PARAMETER_POS 0x10 -#define GEN_FIFO_STAT_REG 0xb074 -#define HS_DATA_FIFO_FULL (1 << 0) -#define HS_DATA_FIFO_HALF_EMPTY (1 << 1) -#define HS_DATA_FIFO_EMPTY (1 << 2) -#define LP_DATA_FIFO_FULL (1 << 8) -#define LP_DATA_FIFO_HALF_EMPTY (1 << 9) -#define LP_DATA_FIFO_EMPTY (1 << 10) -#define HS_CTRL_FIFO_FULL (1 << 16) -#define HS_CTRL_FIFO_HALF_EMPTY (1 << 17) -#define HS_CTRL_FIFO_EMPTY (1 << 18) -#define LP_CTRL_FIFO_FULL (1 << 24) -#define LP_CTRL_FIFO_HALF_EMPTY (1 << 25) -#define LP_CTRL_FIFO_EMPTY (1 << 26) -#define DBI_FIFO_EMPTY (1 << 27) -#define DPI_FIFO_EMPTY (1 << 28) -#define HS_LS_DBI_ENABLE_REG 0xb078 -#define TXCLKESC_REG 0xb07c -#define DPHY_PARAM_REG 0xb080 -#define DBI_BW_CTRL_REG 0xb084 -#define CLK_LANE_SWT_REG 0xb088 +#define DBI_DATA_WIDTH_OPT1 0x04 /* option 1 */ +#define DBI_DATA_WIDTH_OPT2 0x05 /* option 2 */ + +#define HS_TX_TIMEOUT_REG 0xb010 +#define LP_RX_TIMEOUT_REG 0xb014 +#define TURN_AROUND_TIMEOUT_REG 0xb018 +#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 +#define HORIZ_ACTIVE_AREA_COUNT_REG 0xb034 +#define VERT_SYNC_PAD_COUNT_REG 0xb038 +#define VERT_BACK_PORCH_COUNT_REG 0xb03c +#define VERT_FRONT_PORCH_COUNT_REG 0xb040 +#define HIGH_LOW_SWITCH_COUNT_REG 0xb044 +#define DPI_CONTROL_REG 0xb048 +#define DPI_SHUT_DOWN (1 << 0) +#define DPI_TURN_ON (1 << 1) +#define DPI_COLOR_MODE_ON (1 << 2) +#define DPI_COLOR_MODE_OFF (1 << 3) +#define DPI_BACK_LIGHT_ON (1 << 4) +#define DPI_BACK_LIGHT_OFF (1 << 5) +#define DPI_LP (1 << 6) +#define DPI_DATA_REG 0xb04c +#define DPI_BACK_LIGHT_ON_DATA 0x07 +#define DPI_BACK_LIGHT_OFF_DATA 0x17 +#define INIT_COUNT_REG 0xb050 +#define MAX_RET_PAK_REG 0xb054 +#define VIDEO_FMT_REG 0xb058 +#define COMPLETE_LAST_PCKT (1 << 2) +#define EOT_DISABLE_REG 0xb05c +#define ENABLE_CLOCK_STOPPING (1 << 1) +#define LP_BYTECLK_REG 0xb060 +#define LP_GEN_DATA_REG 0xb064 +#define HS_GEN_DATA_REG 0xb068 +#define LP_GEN_CTRL_REG 0xb06C +#define HS_GEN_CTRL_REG 0xb070 +#define DCS_CHANNEL_NUMBER_POS 0x6 +#define MCS_COMMANDS_POS 0x8 +#define WORD_COUNTS_POS 0x8 +#define MCS_PARAMETER_POS 0x10 +#define GEN_FIFO_STAT_REG 0xb074 +#define HS_DATA_FIFO_FULL (1 << 0) +#define HS_DATA_FIFO_HALF_EMPTY (1 << 1) +#define HS_DATA_FIFO_EMPTY (1 << 2) +#define LP_DATA_FIFO_FULL (1 << 8) +#define LP_DATA_FIFO_HALF_EMPTY (1 << 9) +#define LP_DATA_FIFO_EMPTY (1 << 10) +#define HS_CTRL_FIFO_FULL (1 << 16) +#define HS_CTRL_FIFO_HALF_EMPTY (1 << 17) +#define HS_CTRL_FIFO_EMPTY (1 << 18) +#define LP_CTRL_FIFO_FULL (1 << 24) +#define LP_CTRL_FIFO_HALF_EMPTY (1 << 25) +#define LP_CTRL_FIFO_EMPTY (1 << 26) +#define DBI_FIFO_EMPTY (1 << 27) +#define DPI_FIFO_EMPTY (1 << 28) +#define HS_LS_DBI_ENABLE_REG 0xb078 +#define TXCLKESC_REG 0xb07c +#define DPHY_PARAM_REG 0xb080 +#define DBI_BW_CTRL_REG 0xb084 +#define CLK_LANE_SWT_REG 0xb088 /* * MIPI Adapter registers */ -#define MIPI_CONTROL_REG 0xb104 -#define MIPI_2X_CLOCK_BITS ((1 << 0) | (1 << 1)) -#define MIPI_DATA_ADDRESS_REG 0xb108 -#define MIPI_DATA_LENGTH_REG 0xb10C -#define MIPI_COMMAND_ADDRESS_REG 0xb110 -#define MIPI_COMMAND_LENGTH_REG 0xb114 -#define MIPI_READ_DATA_RETURN_REG0 0xb118 -#define MIPI_READ_DATA_RETURN_REG1 0xb11C -#define MIPI_READ_DATA_RETURN_REG2 0xb120 -#define MIPI_READ_DATA_RETURN_REG3 0xb124 -#define MIPI_READ_DATA_RETURN_REG4 0xb128 -#define MIPI_READ_DATA_RETURN_REG5 0xb12C -#define MIPI_READ_DATA_RETURN_REG6 0xb130 -#define MIPI_READ_DATA_RETURN_REG7 0xb134 -#define MIPI_READ_DATA_VALID_REG 0xb138 +#define MIPI_CONTROL_REG 0xb104 +#define MIPI_2X_CLOCK_BITS ((1 << 0) | (1 << 1)) +#define MIPI_DATA_ADDRESS_REG 0xb108 +#define MIPI_DATA_LENGTH_REG 0xb10C +#define MIPI_COMMAND_ADDRESS_REG 0xb110 +#define MIPI_COMMAND_LENGTH_REG 0xb114 +#define MIPI_READ_DATA_RETURN_REG0 0xb118 +#define MIPI_READ_DATA_RETURN_REG1 0xb11C +#define MIPI_READ_DATA_RETURN_REG2 0xb120 +#define MIPI_READ_DATA_RETURN_REG3 0xb124 +#define MIPI_READ_DATA_RETURN_REG4 0xb128 +#define MIPI_READ_DATA_RETURN_REG5 0xb12C +#define MIPI_READ_DATA_RETURN_REG6 0xb130 +#define MIPI_READ_DATA_RETURN_REG7 0xb134 +#define MIPI_READ_DATA_VALID_REG 0xb138 + /* DBI COMMANDS */ -#define soft_reset 0x01 +#define soft_reset 0x01 /* * The display module performs a software reset. * Registers are written with their SW Reset default values. */ -#define get_power_mode 0x0a +#define get_power_mode 0x0a /* * The display module returns the current power mode */ -#define get_address_mode 0x0b +#define get_address_mode 0x0b /* * The display module returns the current status. */ -#define get_pixel_format 0x0c +#define get_pixel_format 0x0c /* * This command gets the pixel format for the RGB image data * used by the interface. */ -#define get_display_mode 0x0d +#define get_display_mode 0x0d /* * The display module returns the Display Image Mode status. */ -#define get_signal_mode 0x0e +#define get_signal_mode 0x0e /* * The display module returns the Display Signal Mode. */ -#define get_diagnostic_result 0x0f +#define get_diagnostic_result 0x0f /* * The display module returns the self-diagnostic results following * a Sleep Out command. */ -#define enter_sleep_mode 0x10 +#define enter_sleep_mode 0x10 /* * This command causes the display module to enter the Sleep mode. * In this mode, all unnecessary blocks inside the display module are * disabled except interface communication. This is the lowest power * mode the display module supports. */ -#define exit_sleep_mode 0x11 +#define exit_sleep_mode 0x11 /* * This command causes the display module to exit Sleep mode. * All blocks inside the display module are enabled. */ -#define enter_partial_mode 0x12 +#define enter_partial_mode 0x12 /* * This command causes the display module to enter the Partial Display * Mode. The Partial Display Mode window is described by the * set_partial_area command. */ -#define enter_normal_mode 0x13 +#define enter_normal_mode 0x13 /* * This command causes the display module to enter the Normal mode. * Normal Mode is defined as Partial Display mode and Scroll mode are off */ -#define exit_invert_mode 0x20 +#define exit_invert_mode 0x20 /* * This command causes the display module to stop inverting the image * data on the display device. The frame memory contents remain unchanged. * No status bits are changed. */ -#define enter_invert_mode 0x21 +#define enter_invert_mode 0x21 /* * This command causes the display module to invert the image data only on * the display device. The frame memory contents remain unchanged. * No status bits are changed. */ -#define set_gamma_curve 0x26 +#define set_gamma_curve 0x26 /* * This command selects the desired gamma curve for the display device. * Four fixed gamma curves are defined in section DCS spec. */ -#define set_display_off 0x28 +#define set_display_off 0x28 /* ************************************************************************* *\ This command causes the display module to stop displaying the image data on the display device. The frame memory contents remain unchanged. No status bits are changed. \* ************************************************************************* */ -#define set_display_on 0x29 +#define set_display_on 0x29 /* ************************************************************************* *\ This command causes the display module to start displaying the image data on the display device. The frame memory contents remain unchanged. No status bits are changed. \* ************************************************************************* */ -#define set_column_address 0x2a +#define set_column_address 0x2a /* * This command defines the column extent of the frame memory accessed by * the hostprocessor with the read_memory_continue and * write_memory_continue commands. * No status bits are changed. */ -#define set_page_addr 0x2b +#define set_page_addr 0x2b /* * This command defines the page extent of the frame memory accessed by * the host processor with the write_memory_continue and - * read_memory_continue command. + * read_memory_continue command. * No status bits are changed. */ -#define write_mem_start 0x2c +#define write_mem_start 0x2c /* * This command transfers image data from the host processor to the - * display module s frame memory starting at the pixel location specified + * display modules frame memory starting at the pixel location specified * by preceding set_column_address and set_page_address commands. */ -#define set_partial_area 0x30 +#define set_partial_area 0x30 /* * This command defines the Partial Display mode s display area. * There are two parameters associated with this command, the first * defines the Start Row (SR) and the second the End Row (ER). SR and ER * refer to the Frame Memory Line Pointer. */ -#define set_scroll_area 0x33 +#define set_scroll_area 0x33 /* * This command defines the display modules Vertical Scrolling Area. */ -#define set_tear_off 0x34 +#define set_tear_off 0x34 /* * This command turns off the display modules Tearing Effect output * signal on the TE signal line. */ -#define set_tear_on 0x35 +#define set_tear_on 0x35 /* * This command turns on the display modules Tearing Effect output signal * on the TE signal line. */ -#define set_address_mode 0x36 +#define set_address_mode 0x36 /* * This command sets the data order for transfers from the host processor * to display modules frame memory,bits B[7:5] and B3, and from the * display modules frame memory to the display device, bits B[2:0] and B4. */ -#define set_scroll_start 0x37 +#define set_scroll_start 0x37 /* * This command sets the start of the vertical scrolling area in the frame * memory. The vertical scrolling area is fully defined when this command @@ -1007,18 +1027,18 @@ No status bits are changed. * line in the frame memory that is written to the display device as the * first line of the vertical scroll area. */ -#define exit_idle_mode 0x38 +#define exit_idle_mode 0x38 /* * This command causes the display module to exit Idle mode. */ -#define enter_idle_mode 0x39 +#define enter_idle_mode 0x39 /* * This command causes the display module to enter Idle Mode. * In Idle Mode, color expression is reduced. Colors are shown on the * display device using the MSB of each of the R, G and B color * components in the frame memory */ -#define set_pixel_format 0x3a +#define set_pixel_format 0x3a /* * This command sets the pixel format for the RGB image data used by the * interface. @@ -1026,25 +1046,27 @@ No status bits are changed. * Bits D[2:0] DBI Pixel Format Definition * Bits D7 and D3 are not used. */ - #define DCS_PIXEL_FORMAT_3bbp 0x1 - #define DCS_PIXEL_FORMAT_8bbp 0x2 - #define DCS_PIXEL_FORMAT_12bbp 0x3 - #define DCS_PIXEL_FORMAT_16bbp 0x5 - #define DCS_PIXEL_FORMAT_18bbp 0x6 - #define DCS_PIXEL_FORMAT_24bbp 0x7 -#define write_mem_cont 0x3c +#define DCS_PIXEL_FORMAT_3bpp 0x1 +#define DCS_PIXEL_FORMAT_8bpp 0x2 +#define DCS_PIXEL_FORMAT_12bpp 0x3 +#define DCS_PIXEL_FORMAT_16bpp 0x5 +#define DCS_PIXEL_FORMAT_18bpp 0x6 +#define DCS_PIXEL_FORMAT_24bpp 0x7 + +#define write_mem_cont 0x3c + /* * This command transfers image data from the host processor to the * display module's frame memory continuing from the pixel location * following the previous write_memory_continue or write_memory_start * command. */ -#define set_tear_scanline 0x44 +#define set_tear_scanline 0x44 /* * This command turns on the display modules Tearing Effect output signal * on the TE signal line when the display module reaches line N. */ -#define get_scanline 0x45 +#define get_scanline 0x45 /* * The display module returns the current scanline, N, used to update the * display device. The total number of scanlines on a display device is @@ -1094,22 +1116,22 @@ No status bits are changed. #define GAMMA_AUTO (1 << 0) /* DCS Interface Pixel Formats */ -#define DCS_PIXEL_FORMAT_3BPP 0x1 -#define DCS_PIXEL_FORMAT_8BPP 0x2 -#define DCS_PIXEL_FORMAT_12BPP 0x3 -#define DCS_PIXEL_FORMAT_16BPP 0x5 -#define DCS_PIXEL_FORMAT_18BPP 0x6 -#define DCS_PIXEL_FORMAT_24BPP 0x7 +#define DCS_PIXEL_FORMAT_3BPP 0x1 +#define DCS_PIXEL_FORMAT_8BPP 0x2 +#define DCS_PIXEL_FORMAT_12BPP 0x3 +#define DCS_PIXEL_FORMAT_16BPP 0x5 +#define DCS_PIXEL_FORMAT_18BPP 0x6 +#define DCS_PIXEL_FORMAT_24BPP 0x7 /* ONE PARAMETER READ DATA */ -#define addr_mode_data 0xfc -#define diag_res_data 0x00 -#define disp_mode_data 0x23 -#define pxl_fmt_data 0x77 -#define pwr_mode_data 0x74 -#define sig_mode_data 0x00 +#define addr_mode_data 0xfc +#define diag_res_data 0x00 +#define disp_mode_data 0x23 +#define pxl_fmt_data 0x77 +#define pwr_mode_data 0x74 +#define sig_mode_data 0x00 /* TWO PARAMETERS READ DATA */ -#define scanline_data1 0xff -#define scanline_data2 0xff +#define scanline_data1 0xff +#define scanline_data2 0xff #define NON_BURST_MODE_SYNC_PULSE 0x01 /* Non Burst Mode * with Sync Pulse */ @@ -1117,7 +1139,8 @@ No status bits are changed. * with Sync events */ #define BURST_MODE 0x03 /* Burst Mode */ -#define DBI_COMMAND_BUFFER_SIZE 0x240 /* 0x32 */ /* 0x120 */ /* Allocate at least +#define DBI_COMMAND_BUFFER_SIZE 0x240 /* 0x32 */ /* 0x120 */ + /* Allocate at least * 0x100 Byte with 32 * byte alignment */ @@ -1125,13 +1148,88 @@ No status bits are changed. * 0x100 Byte with 32 * byte alignment */ -#define DBI_CB_TIME_OUT 0xFFFF - -#define GEN_FB_TIME_OUT 2000 -#define ALIGNMENT_32BYTE_MASK (~((1 << 0)|(1 << 1)|(1 << 2)|(1 << 3)|(1 << 4))) -#define SKU_83 0x01 -#define SKU_100 0x02 -#define SKU_100L 0x04 -#define SKU_BYPASS 0x08 +#define DBI_CB_TIME_OUT 0xFFFF + +#define GEN_FB_TIME_OUT 2000 + +#define SKU_83 0x01 +#define SKU_100 0x02 +#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 diff --git a/drivers/staging/gma500/psb_intel_sdvo.c b/drivers/staging/gma500/psb_intel_sdvo.c index df1c006..a4bad1a 100644 --- a/drivers/staging/gma500/psb_intel_sdvo.c +++ b/drivers/staging/gma500/psb_intel_sdvo.c @@ -107,14 +107,10 @@ static bool psb_intel_sdvo_read_byte( ret = i2c_transfer(&sdvo_priv->i2c_bus->adapter, msgs, 2); if (ret == 2) { - /* DRM_DEBUG("got back from addr %02X = %02x\n", - * out_buf[0], buf[0]); - */ *ch = buf[0]; return true; } - DRM_DEBUG("i2c transfer returned %d\n", ret); return false; } @@ -205,24 +201,25 @@ static void psb_intel_sdvo_write_cmd(struct psb_intel_output *psb_intel_output, int i; if (0) { - DRM_DEBUG("%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd); + printk(KERN_DEBUG "%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd); for (i = 0; i < args_len; i++) - printk(KERN_INFO"%02X ", ((u8 *) args)[i]); + printk(KERN_CONT "%02X ", ((u8 *) args)[i]); for (; i < 8; i++) - printk(" "); + printk(KERN_CONT " "); for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) { if (cmd == sdvo_cmd_names[i].cmd) { - printk("(%s)", sdvo_cmd_names[i].name); + printk(KERN_CONT + "(%s)", sdvo_cmd_names[i].name); break; } } if (i == sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0])) - printk("(%02X)", cmd); - printk("\n"); + printk(KERN_CONT "(%02X)", cmd); + printk(KERN_CONT "\n"); } for (i = 0; i < args_len; i++) { @@ -267,17 +264,17 @@ static u8 psb_intel_sdvo_read_response( &status); if (0) { - DRM_DEBUG("%s: R: ", SDVO_NAME(sdvo_priv)); + pr_debug("%s: R: ", SDVO_NAME(sdvo_priv)); for (i = 0; i < response_len; i++) - printk(KERN_INFO"%02X ", ((u8 *) response)[i]); + printk(KERN_CONT "%02X ", ((u8 *) response)[i]); for (; i < 8; i++) printk(" "); if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) - printk(KERN_INFO"(%s)", + printk(KERN_CONT "(%s)", cmd_status_names[status]); else - printk(KERN_INFO"(??? %d)", status); - printk("\n"); + printk(KERN_CONT "(??? %d)", status); + printk(KERN_CONT "\n"); } if (status != SDVO_CMD_STATUS_PENDING) @@ -997,7 +994,6 @@ int psb_intel_sdvo_supports_hotplug(struct drm_connector *connector) u8 response[2]; u8 status; struct psb_intel_output *psb_intel_output; - DRM_DEBUG("\n"); if (!connector) return 0; @@ -1198,7 +1194,7 @@ void psb_intel_sdvo_init(struct drm_device *dev, int output_device) /* Read the regs to test if we can talk to the device */ for (i = 0; i < 0x40; i++) { if (!psb_intel_sdvo_read_byte(psb_intel_output, i, &ch[i])) { - DRM_DEBUG("No SDVO device found on SDVO%c\n", + dev_dbg(dev->dev, "No SDVO device found on SDVO%c\n", output_device == SDVOB ? 'B' : 'C'); goto err_i2c; } @@ -1242,8 +1238,7 @@ void psb_intel_sdvo_init(struct drm_device *dev, int output_device) unsigned char bytes[2]; memcpy(bytes, &sdvo_priv->caps.output_flags, 2); - DRM_DEBUG - ("%s: No active RGB or TMDS outputs (0x%02x%02x)\n", + dev_dbg(dev->dev, "%s: No active RGB or TMDS outputs (0x%02x%02x)\n", SDVO_NAME(sdvo_priv), bytes[0], bytes[1]); goto err_i2c; } @@ -1267,7 +1262,7 @@ void psb_intel_sdvo_init(struct drm_device *dev, int output_device) pixel_clock_max); - DRM_DEBUG("%s device VID/DID: %02X:%02X.%02X, " + dev_dbg(dev->dev, "%s device VID/DID: %02X:%02X.%02X, " "clock range %dMHz - %dMHz, " "input 1: %c, input 2: %c, " "output 1: %c, output 2: %c\n", diff --git a/drivers/staging/gma500/psb_intel_sdvo_regs.h b/drivers/staging/gma500/psb_intel_sdvo_regs.h index c7107a3..96862ea 100644 --- a/drivers/staging/gma500/psb_intel_sdvo_regs.h +++ b/drivers/staging/gma500/psb_intel_sdvo_regs.h @@ -51,7 +51,7 @@ struct psb_intel_sdvo_caps { unsigned int stall_support:1; unsigned int pad:1; u16 output_flags; -} __attribute__ ((packed)); +} __packed; /** This matches the EDID DTD structure, more or less */ struct psb_intel_sdvo_dtd { @@ -82,18 +82,18 @@ struct psb_intel_sdvo_dtd { u8 v_sync_off_high; u8 reserved; } part2; -} __attribute__ ((packed)); +} __packed; struct psb_intel_sdvo_pixel_clock_range { u16 min; /**< pixel clock, in 10kHz units */ u16 max; /**< pixel clock, in 10kHz units */ -} __attribute__ ((packed)); +} __packed; struct psb_intel_sdvo_preferred_input_timing_args { u16 clock; u16 width; u16 height; -} __attribute__ ((packed)); +} __packed; /* I2C registers for SDVO */ #define SDVO_I2C_ARG_0 0x07 @@ -147,7 +147,7 @@ struct psb_intel_sdvo_get_trained_inputs_response { unsigned int input0_trained:1; unsigned int input1_trained:1; unsigned int pad:6; -} __attribute__ ((packed)); +} __packed; /** Returns a struct psb_intel_sdvo_output_flags of active outputs. */ #define SDVO_CMD_GET_ACTIVE_OUTPUTS 0x04 @@ -201,7 +201,7 @@ struct psb_intel_sdvo_get_interrupt_event_source_response { u16 interrupt_status; unsigned int ambient_light_interrupt:1; unsigned int pad:7; -} __attribute__ ((packed)); +} __packed; /** * Selects which input is affected by future input commands. @@ -214,7 +214,7 @@ struct psb_intel_sdvo_get_interrupt_event_source_response { struct psb_intel_sdvo_set_target_input_args { unsigned int target_1:1; unsigned int pad:7; -} __attribute__ ((packed)); +} __packed; /** * Takes a struct psb_intel_sdvo_output_flags of which outputs are targeted by diff --git a/drivers/staging/gma500/psb_irq.c b/drivers/staging/gma500/psb_irq.c index 9ea37e5..4a0fa42 100644 --- a/drivers/staging/gma500/psb_irq.c +++ b/drivers/staging/gma500/psb_irq.c @@ -26,8 +26,8 @@ #include "psb_drv.h" #include "psb_reg.h" #include "psb_intel_reg.h" -#include "psb_powermgmt.h" - +#include "power.h" +#include "mdfld_output.h" /* * inline functions @@ -187,7 +187,8 @@ static void mid_pipe_event_handler(struct drm_device *dev, uint32_t pipe) } if (i == WAIT_STATUS_CLEAR_LOOP_COUNT) - DRM_ERROR("%s, can't clear the status bits in pipe_stat_reg, its value = 0x%x.\n", + dev_err(dev->dev, + "%s, can't clear the status bits in pipe_stat_reg, its value = 0x%x.\n", __func__, PSB_RVDC32(pipe_stat_reg)); if (pipe_stat_val & PIPE_VBLANK_STATUS) @@ -219,21 +220,11 @@ irqreturn_t psb_irq_handler(DRM_IRQ_ARGS) vdc_stat = PSB_RVDC32(PSB_INT_IDENTITY_R); - if (vdc_stat & _MDFLD_DISP_ALL_IRQ_FLAG) { - PSB_DEBUG_IRQ("Got DISP interrupt\n"); + if (vdc_stat & _MDFLD_DISP_ALL_IRQ_FLAG) dsp_int = 1; - } - if (vdc_stat & _PSB_IRQ_SGX_FLAG) { - PSB_DEBUG_IRQ("Got SGX interrupt\n"); + if (vdc_stat & _PSB_IRQ_SGX_FLAG) sgx_int = 1; - } - if (vdc_stat & _PSB_IRQ_MSVDX_FLAG) - PSB_DEBUG_IRQ("Got MSVDX interrupt\n"); - - if (vdc_stat & _LNC_IRQ_TOPAZ_FLAG) - PSB_DEBUG_IRQ("Got TOPAZ interrupt\n"); - vdc_stat &= dev_priv->vdc_irq_mask; spin_unlock(&dev_priv->irqmask_lock); @@ -293,8 +284,6 @@ int psb_irq_postinstall(struct drm_device *dev) (struct drm_psb_private *) dev->dev_private; unsigned long irqflags; - PSB_DEBUG_ENTRY("\n"); - spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); /* This register is safe even if display island is off */ @@ -326,8 +315,6 @@ void psb_irq_uninstall(struct drm_device *dev) (struct drm_psb_private *) dev->dev_private; unsigned long irqflags; - PSB_DEBUG_ENTRY("\n"); - spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM); @@ -395,8 +382,6 @@ int psb_irq_enable_dpst(struct drm_device *dev) (struct drm_psb_private *) dev->dev_private; unsigned long irqflags; - PSB_DEBUG_ENTRY("\n"); - spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); /* enable DPST */ @@ -435,8 +420,6 @@ int psb_irq_disable_dpst(struct drm_device *dev) (struct drm_psb_private *) dev->dev_private; unsigned long irqflags; - PSB_DEBUG_ENTRY("\n"); - spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); mid_disable_pipe_event(dev_priv, 0); @@ -472,8 +455,12 @@ int psb_enable_vblank(struct drm_device *dev, int pipe) uint32_t reg_val = 0; uint32_t pipeconf_reg = mid_pipeconf(pipe); - PSB_DEBUG_ENTRY("\n"); - +#if defined(CONFIG_DRM_PSB_MFLD) + /* Medfield is different - we should perhaps extract out vblank + and blacklight etc ops */ + if (IS_MFLD(dev) && !mdfld_panel_dpi(dev)) + return mdfld_enable_te(dev, pipe); +#endif if (gma_power_begin(dev, false)) { reg_val = REG_READ(pipeconf_reg); gma_power_end(dev); @@ -500,8 +487,10 @@ void psb_disable_vblank(struct drm_device *dev, int pipe) struct drm_psb_private *dev_priv = dev->dev_private; unsigned long irqflags; - PSB_DEBUG_ENTRY("\n"); - +#if defined(CONFIG_DRM_PSB_MFLD) + if (IS_MFLD(dev) && !mdfld_panel_dpi(dev)) + mdfld_disable_te(dev, pipe); +#endif spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); mid_disable_pipe_event(dev_priv, pipe); @@ -510,6 +499,58 @@ void psb_disable_vblank(struct drm_device *dev, int pipe) spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); } +/** + * mdfld_enable_te - enable TE events + * @dev: our DRM device + * @pipe: which pipe to work on + * + * Enable TE events on a Medfield display pipe. Medfield specific. + */ +int mdfld_enable_te(struct drm_device *dev, int pipe) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + unsigned long flags; + 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, flags); + + mid_enable_pipe_event(dev_priv, pipe); + psb_enable_pipestat(dev_priv, pipe, PIPE_TE_ENABLE); + + spin_unlock_irqrestore(&dev_priv->irqmask_lock, flags); + + return 0; +} + +/** + * mdfld_disable_te - disable TE events + * @dev: our DRM device + * @pipe: which pipe to work on + * + * Disable TE events on a Medfield display pipe. Medfield specific. + */ +void mdfld_disable_te(struct drm_device *dev, int pipe) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->irqmask_lock, flags); + + mid_disable_pipe_event(dev_priv, pipe); + psb_disable_pipestat(dev_priv, pipe, PIPE_TE_ENABLE); + + spin_unlock_irqrestore(&dev_priv->irqmask_lock, flags); +} + /* Called from drm generic code, passed a 'crtc', which * we use as a pipe index */ @@ -535,7 +576,7 @@ u32 psb_get_vblank_counter(struct drm_device *dev, int pipe) pipeconf_reg = PIPECCONF; break; default: - DRM_ERROR("%s, invalded pipe.\n", __func__); + dev_err(dev->dev, "%s, invalid pipe.\n", __func__); return 0; } @@ -545,7 +586,7 @@ u32 psb_get_vblank_counter(struct drm_device *dev, int pipe) reg_val = REG_READ(pipeconf_reg); if (!(reg_val & PIPEACONF_ENABLE)) { - DRM_ERROR("trying to get vblank count for disabled pipe %d\n", + dev_err(dev->dev, "trying to get vblank count for disabled pipe %d\n", pipe); goto psb_get_vblank_counter_exit; } diff --git a/drivers/staging/gma500/psb_irq.h b/drivers/staging/gma500/psb_irq.h index 3e56f33..216fda3 100644 --- a/drivers/staging/gma500/psb_irq.h +++ b/drivers/staging/gma500/psb_irq.h @@ -1,5 +1,5 @@ /************************************************************************** - * Copyright (c) 2009, Intel Corporation. + * Copyright (c) 2009-2011, Intel Corporation. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it @@ -34,10 +34,6 @@ int psb_irq_postinstall(struct drm_device *dev); void psb_irq_uninstall(struct drm_device *dev); irqreturn_t psb_irq_handler(DRM_IRQ_ARGS); -void psb_irq_preinstall_islands(struct drm_device *dev, int hw_islands); -int psb_irq_postinstall_islands(struct drm_device *dev, int hw_islands); -void psb_irq_uninstall_islands(struct drm_device *dev, int hw_islands); - int psb_irq_enable_dpst(struct drm_device *dev); int psb_irq_disable_dpst(struct drm_device *dev); void psb_irq_turn_on_dpst(struct drm_device *dev); @@ -46,4 +42,4 @@ int psb_enable_vblank(struct drm_device *dev, int pipe); void psb_disable_vblank(struct drm_device *dev, int pipe); u32 psb_get_vblank_counter(struct drm_device *dev, int pipe); -#endif //_SYSIRQ_H_ +#endif /* _SYSIRQ_H_ */ diff --git a/drivers/staging/gma500/psb_lid.c b/drivers/staging/gma500/psb_lid.c index 21fd202..af32851 100644 --- a/drivers/staging/gma500/psb_lid.c +++ b/drivers/staging/gma500/psb_lid.c @@ -32,10 +32,10 @@ static void psb_lid_timer_func(unsigned long data) u32 *lid_state = dev_priv->lid_state; u32 pp_status; - if (*lid_state == dev_priv->lid_last_state) + if (readl(lid_state) == dev_priv->lid_last_state) goto lid_timer_schedule; - if ((*lid_state) & 0x01) { + if ((readl(lid_state)) & 0x01) { /*lid state is open*/ REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) | POWER_TARGET_ON); do { @@ -54,7 +54,7 @@ static void psb_lid_timer_func(unsigned long data) } /* printk(KERN_INFO"%s: lid: closed\n", __FUNCTION__); */ - dev_priv->lid_last_state = *lid_state; + dev_priv->lid_last_state = readl(lid_state); lid_timer_schedule: spin_lock_irqsave(&dev_priv->lid_lock, irq_flags); diff --git a/drivers/staging/gma500/psb_reg.h b/drivers/staging/gma500/psb_reg.h index 9ad4989..b81c7c1 100644 --- a/drivers/staging/gma500/psb_reg.h +++ b/drivers/staging/gma500/psb_reg.h @@ -22,161 +22,157 @@ #ifndef _PSB_REG_H_ #define _PSB_REG_H_ -#define PSB_CR_CLKGATECTL 0x0000 -#define _PSB_C_CLKGATECTL_AUTO_MAN_REG (1 << 24) -#define _PSB_C_CLKGATECTL_USE_CLKG_SHIFT (20) -#define _PSB_C_CLKGATECTL_USE_CLKG_MASK (0x3 << 20) -#define _PSB_C_CLKGATECTL_DPM_CLKG_SHIFT (16) -#define _PSB_C_CLKGATECTL_DPM_CLKG_MASK (0x3 << 16) -#define _PSB_C_CLKGATECTL_TA_CLKG_SHIFT (12) -#define _PSB_C_CLKGATECTL_TA_CLKG_MASK (0x3 << 12) -#define _PSB_C_CLKGATECTL_TSP_CLKG_SHIFT (8) -#define _PSB_C_CLKGATECTL_TSP_CLKG_MASK (0x3 << 8) -#define _PSB_C_CLKGATECTL_ISP_CLKG_SHIFT (4) -#define _PSB_C_CLKGATECTL_ISP_CLKG_MASK (0x3 << 4) -#define _PSB_C_CLKGATECTL_2D_CLKG_SHIFT (0) -#define _PSB_C_CLKGATECTL_2D_CLKG_MASK (0x3 << 0) -#define _PSB_C_CLKGATECTL_CLKG_ENABLED (0) -#define _PSB_C_CLKGATECTL_CLKG_DISABLED (1) -#define _PSB_C_CLKGATECTL_CLKG_AUTO (2) - -#define PSB_CR_CORE_ID 0x0010 -#define _PSB_CC_ID_ID_SHIFT (16) -#define _PSB_CC_ID_ID_MASK (0xFFFF << 16) -#define _PSB_CC_ID_CONFIG_SHIFT (0) -#define _PSB_CC_ID_CONFIG_MASK (0xFFFF << 0) - -#define PSB_CR_CORE_REVISION 0x0014 -#define _PSB_CC_REVISION_DESIGNER_SHIFT (24) -#define _PSB_CC_REVISION_DESIGNER_MASK (0xFF << 24) -#define _PSB_CC_REVISION_MAJOR_SHIFT (16) -#define _PSB_CC_REVISION_MAJOR_MASK (0xFF << 16) -#define _PSB_CC_REVISION_MINOR_SHIFT (8) -#define _PSB_CC_REVISION_MINOR_MASK (0xFF << 8) -#define _PSB_CC_REVISION_MAINTENANCE_SHIFT (0) -#define _PSB_CC_REVISION_MAINTENANCE_MASK (0xFF << 0) - -#define PSB_CR_DESIGNER_REV_FIELD1 0x0018 - -#define PSB_CR_SOFT_RESET 0x0080 -#define _PSB_CS_RESET_TSP_RESET (1 << 6) -#define _PSB_CS_RESET_ISP_RESET (1 << 5) -#define _PSB_CS_RESET_USE_RESET (1 << 4) -#define _PSB_CS_RESET_TA_RESET (1 << 3) -#define _PSB_CS_RESET_DPM_RESET (1 << 2) -#define _PSB_CS_RESET_TWOD_RESET (1 << 1) -#define _PSB_CS_RESET_BIF_RESET (1 << 0) - -#define PSB_CR_DESIGNER_REV_FIELD2 0x001C - -#define PSB_CR_EVENT_HOST_ENABLE2 0x0110 - -#define PSB_CR_EVENT_STATUS2 0x0118 - -#define PSB_CR_EVENT_HOST_CLEAR2 0x0114 -#define _PSB_CE2_BIF_REQUESTER_FAULT (1 << 4) - -#define PSB_CR_EVENT_STATUS 0x012C - -#define PSB_CR_EVENT_HOST_ENABLE 0x0130 - -#define PSB_CR_EVENT_HOST_CLEAR 0x0134 -#define _PSB_CE_MASTER_INTERRUPT (1 << 31) -#define _PSB_CE_TA_DPM_FAULT (1 << 28) -#define _PSB_CE_TWOD_COMPLETE (1 << 27) -#define _PSB_CE_DPM_OUT_OF_MEMORY_ZLS (1 << 25) -#define _PSB_CE_DPM_TA_MEM_FREE (1 << 24) -#define _PSB_CE_PIXELBE_END_RENDER (1 << 18) -#define _PSB_CE_SW_EVENT (1 << 14) -#define _PSB_CE_TA_FINISHED (1 << 13) -#define _PSB_CE_TA_TERMINATE (1 << 12) -#define _PSB_CE_DPM_REACHED_MEM_THRESH (1 << 3) -#define _PSB_CE_DPM_OUT_OF_MEMORY_GBL (1 << 2) -#define _PSB_CE_DPM_OUT_OF_MEMORY_MT (1 << 1) -#define _PSB_CE_DPM_3D_MEM_FREE (1 << 0) - - -#define PSB_USE_OFFSET_MASK 0x0007FFFF -#define PSB_USE_OFFSET_SIZE (PSB_USE_OFFSET_MASK + 1) -#define PSB_CR_USE_CODE_BASE0 0x0A0C -#define PSB_CR_USE_CODE_BASE1 0x0A10 -#define PSB_CR_USE_CODE_BASE2 0x0A14 -#define PSB_CR_USE_CODE_BASE3 0x0A18 -#define PSB_CR_USE_CODE_BASE4 0x0A1C -#define PSB_CR_USE_CODE_BASE5 0x0A20 -#define PSB_CR_USE_CODE_BASE6 0x0A24 -#define PSB_CR_USE_CODE_BASE7 0x0A28 -#define PSB_CR_USE_CODE_BASE8 0x0A2C -#define PSB_CR_USE_CODE_BASE9 0x0A30 -#define PSB_CR_USE_CODE_BASE10 0x0A34 -#define PSB_CR_USE_CODE_BASE11 0x0A38 -#define PSB_CR_USE_CODE_BASE12 0x0A3C -#define PSB_CR_USE_CODE_BASE13 0x0A40 -#define PSB_CR_USE_CODE_BASE14 0x0A44 -#define PSB_CR_USE_CODE_BASE15 0x0A48 -#define PSB_CR_USE_CODE_BASE(_i) (0x0A0C + ((_i) << 2)) -#define _PSB_CUC_BASE_DM_SHIFT (25) -#define _PSB_CUC_BASE_DM_MASK (0x3 << 25) -#define _PSB_CUC_BASE_ADDR_SHIFT (0) /* 1024-bit aligned address? */ -#define _PSB_CUC_BASE_ADDR_ALIGNSHIFT (7) -#define _PSB_CUC_BASE_ADDR_MASK (0x1FFFFFF << 0) -#define _PSB_CUC_DM_VERTEX (0) -#define _PSB_CUC_DM_PIXEL (1) -#define _PSB_CUC_DM_RESERVED (2) -#define _PSB_CUC_DM_EDM (3) - -#define PSB_CR_PDS_EXEC_BASE 0x0AB8 -#define _PSB_CR_PDS_EXEC_BASE_ADDR_SHIFT (20) /* 1MB aligned address */ -#define _PSB_CR_PDS_EXEC_BASE_ADDR_ALIGNSHIFT (20) - -#define PSB_CR_EVENT_KICKER 0x0AC4 -#define _PSB_CE_KICKER_ADDRESS_SHIFT (4) /* 128-bit aligned address */ - -#define PSB_CR_EVENT_KICK 0x0AC8 -#define _PSB_CE_KICK_NOW (1 << 0) - - -#define PSB_CR_BIF_DIR_LIST_BASE1 0x0C38 - -#define PSB_CR_BIF_CTRL 0x0C00 -#define _PSB_CB_CTRL_CLEAR_FAULT (1 << 4) -#define _PSB_CB_CTRL_INVALDC (1 << 3) -#define _PSB_CB_CTRL_FLUSH (1 << 2) - -#define PSB_CR_BIF_INT_STAT 0x0C04 - -#define PSB_CR_BIF_FAULT 0x0C08 -#define _PSB_CBI_STAT_PF_N_RW (1 << 14) -#define _PSB_CBI_STAT_FAULT_SHIFT (0) -#define _PSB_CBI_STAT_FAULT_MASK (0x3FFF << 0) -#define _PSB_CBI_STAT_FAULT_CACHE (1 << 1) -#define _PSB_CBI_STAT_FAULT_TA (1 << 2) -#define _PSB_CBI_STAT_FAULT_VDM (1 << 3) -#define _PSB_CBI_STAT_FAULT_2D (1 << 4) -#define _PSB_CBI_STAT_FAULT_PBE (1 << 5) -#define _PSB_CBI_STAT_FAULT_TSP (1 << 6) -#define _PSB_CBI_STAT_FAULT_ISP (1 << 7) -#define _PSB_CBI_STAT_FAULT_USSEPDS (1 << 8) -#define _PSB_CBI_STAT_FAULT_HOST (1 << 9) - -#define PSB_CR_BIF_BANK0 0x0C78 - -#define PSB_CR_BIF_BANK1 0x0C7C - -#define PSB_CR_BIF_DIR_LIST_BASE0 0x0C84 - -#define PSB_CR_BIF_TWOD_REQ_BASE 0x0C88 -#define PSB_CR_BIF_3D_REQ_BASE 0x0CAC - -#define PSB_CR_2D_SOCIF 0x0E18 -#define _PSB_C2_SOCIF_FREESPACE_SHIFT (0) -#define _PSB_C2_SOCIF_FREESPACE_MASK (0xFF << 0) -#define _PSB_C2_SOCIF_EMPTY (0x80 << 0) - -#define PSB_CR_2D_BLIT_STATUS 0x0E04 -#define _PSB_C2B_STATUS_BUSY (1 << 24) -#define _PSB_C2B_STATUS_COMPLETE_SHIFT (0) -#define _PSB_C2B_STATUS_COMPLETE_MASK (0xFFFFFF << 0) +#define PSB_CR_CLKGATECTL 0x0000 +#define _PSB_C_CLKGATECTL_AUTO_MAN_REG (1 << 24) +#define _PSB_C_CLKGATECTL_USE_CLKG_SHIFT (20) +#define _PSB_C_CLKGATECTL_USE_CLKG_MASK (0x3 << 20) +#define _PSB_C_CLKGATECTL_DPM_CLKG_SHIFT (16) +#define _PSB_C_CLKGATECTL_DPM_CLKG_MASK (0x3 << 16) +#define _PSB_C_CLKGATECTL_TA_CLKG_SHIFT (12) +#define _PSB_C_CLKGATECTL_TA_CLKG_MASK (0x3 << 12) +#define _PSB_C_CLKGATECTL_TSP_CLKG_SHIFT (8) +#define _PSB_C_CLKGATECTL_TSP_CLKG_MASK (0x3 << 8) +#define _PSB_C_CLKGATECTL_ISP_CLKG_SHIFT (4) +#define _PSB_C_CLKGATECTL_ISP_CLKG_MASK (0x3 << 4) +#define _PSB_C_CLKGATECTL_2D_CLKG_SHIFT (0) +#define _PSB_C_CLKGATECTL_2D_CLKG_MASK (0x3 << 0) +#define _PSB_C_CLKGATECTL_CLKG_ENABLED (0) +#define _PSB_C_CLKGATECTL_CLKG_DISABLED (1) +#define _PSB_C_CLKGATECTL_CLKG_AUTO (2) + +#define PSB_CR_CORE_ID 0x0010 +#define _PSB_CC_ID_ID_SHIFT (16) +#define _PSB_CC_ID_ID_MASK (0xFFFF << 16) +#define _PSB_CC_ID_CONFIG_SHIFT (0) +#define _PSB_CC_ID_CONFIG_MASK (0xFFFF << 0) + +#define PSB_CR_CORE_REVISION 0x0014 +#define _PSB_CC_REVISION_DESIGNER_SHIFT (24) +#define _PSB_CC_REVISION_DESIGNER_MASK (0xFF << 24) +#define _PSB_CC_REVISION_MAJOR_SHIFT (16) +#define _PSB_CC_REVISION_MAJOR_MASK (0xFF << 16) +#define _PSB_CC_REVISION_MINOR_SHIFT (8) +#define _PSB_CC_REVISION_MINOR_MASK (0xFF << 8) +#define _PSB_CC_REVISION_MAINTENANCE_SHIFT (0) +#define _PSB_CC_REVISION_MAINTENANCE_MASK (0xFF << 0) + +#define PSB_CR_DESIGNER_REV_FIELD1 0x0018 + +#define PSB_CR_SOFT_RESET 0x0080 +#define _PSB_CS_RESET_TSP_RESET (1 << 6) +#define _PSB_CS_RESET_ISP_RESET (1 << 5) +#define _PSB_CS_RESET_USE_RESET (1 << 4) +#define _PSB_CS_RESET_TA_RESET (1 << 3) +#define _PSB_CS_RESET_DPM_RESET (1 << 2) +#define _PSB_CS_RESET_TWOD_RESET (1 << 1) +#define _PSB_CS_RESET_BIF_RESET (1 << 0) + +#define PSB_CR_DESIGNER_REV_FIELD2 0x001C + +#define PSB_CR_EVENT_HOST_ENABLE2 0x0110 + +#define PSB_CR_EVENT_STATUS2 0x0118 + +#define PSB_CR_EVENT_HOST_CLEAR2 0x0114 +#define _PSB_CE2_BIF_REQUESTER_FAULT (1 << 4) + +#define PSB_CR_EVENT_STATUS 0x012C + +#define PSB_CR_EVENT_HOST_ENABLE 0x0130 + +#define PSB_CR_EVENT_HOST_CLEAR 0x0134 +#define _PSB_CE_MASTER_INTERRUPT (1 << 31) +#define _PSB_CE_TA_DPM_FAULT (1 << 28) +#define _PSB_CE_TWOD_COMPLETE (1 << 27) +#define _PSB_CE_DPM_OUT_OF_MEMORY_ZLS (1 << 25) +#define _PSB_CE_DPM_TA_MEM_FREE (1 << 24) +#define _PSB_CE_PIXELBE_END_RENDER (1 << 18) +#define _PSB_CE_SW_EVENT (1 << 14) +#define _PSB_CE_TA_FINISHED (1 << 13) +#define _PSB_CE_TA_TERMINATE (1 << 12) +#define _PSB_CE_DPM_REACHED_MEM_THRESH (1 << 3) +#define _PSB_CE_DPM_OUT_OF_MEMORY_GBL (1 << 2) +#define _PSB_CE_DPM_OUT_OF_MEMORY_MT (1 << 1) +#define _PSB_CE_DPM_3D_MEM_FREE (1 << 0) + + +#define PSB_USE_OFFSET_MASK 0x0007FFFF +#define PSB_USE_OFFSET_SIZE (PSB_USE_OFFSET_MASK + 1) +#define PSB_CR_USE_CODE_BASE0 0x0A0C +#define PSB_CR_USE_CODE_BASE1 0x0A10 +#define PSB_CR_USE_CODE_BASE2 0x0A14 +#define PSB_CR_USE_CODE_BASE3 0x0A18 +#define PSB_CR_USE_CODE_BASE4 0x0A1C +#define PSB_CR_USE_CODE_BASE5 0x0A20 +#define PSB_CR_USE_CODE_BASE6 0x0A24 +#define PSB_CR_USE_CODE_BASE7 0x0A28 +#define PSB_CR_USE_CODE_BASE8 0x0A2C +#define PSB_CR_USE_CODE_BASE9 0x0A30 +#define PSB_CR_USE_CODE_BASE10 0x0A34 +#define PSB_CR_USE_CODE_BASE11 0x0A38 +#define PSB_CR_USE_CODE_BASE12 0x0A3C +#define PSB_CR_USE_CODE_BASE13 0x0A40 +#define PSB_CR_USE_CODE_BASE14 0x0A44 +#define PSB_CR_USE_CODE_BASE15 0x0A48 +#define PSB_CR_USE_CODE_BASE(_i) (0x0A0C + ((_i) << 2)) +#define _PSB_CUC_BASE_DM_SHIFT (25) +#define _PSB_CUC_BASE_DM_MASK (0x3 << 25) +#define _PSB_CUC_BASE_ADDR_SHIFT (0) /* 1024-bit aligned address? */ +#define _PSB_CUC_BASE_ADDR_ALIGNSHIFT (7) +#define _PSB_CUC_BASE_ADDR_MASK (0x1FFFFFF << 0) +#define _PSB_CUC_DM_VERTEX (0) +#define _PSB_CUC_DM_PIXEL (1) +#define _PSB_CUC_DM_RESERVED (2) +#define _PSB_CUC_DM_EDM (3) + +#define PSB_CR_PDS_EXEC_BASE 0x0AB8 +#define _PSB_CR_PDS_EXEC_BASE_ADDR_SHIFT (20) /* 1MB aligned address */ +#define _PSB_CR_PDS_EXEC_BASE_ADDR_ALIGNSHIFT (20) + +#define PSB_CR_EVENT_KICKER 0x0AC4 +#define _PSB_CE_KICKER_ADDRESS_SHIFT (4) /* 128-bit aligned address */ + +#define PSB_CR_EVENT_KICK 0x0AC8 +#define _PSB_CE_KICK_NOW (1 << 0) + +#define PSB_CR_BIF_DIR_LIST_BASE1 0x0C38 + +#define PSB_CR_BIF_CTRL 0x0C00 +#define _PSB_CB_CTRL_CLEAR_FAULT (1 << 4) +#define _PSB_CB_CTRL_INVALDC (1 << 3) +#define _PSB_CB_CTRL_FLUSH (1 << 2) + +#define PSB_CR_BIF_INT_STAT 0x0C04 + +#define PSB_CR_BIF_FAULT 0x0C08 +#define _PSB_CBI_STAT_PF_N_RW (1 << 14) +#define _PSB_CBI_STAT_FAULT_SHIFT (0) +#define _PSB_CBI_STAT_FAULT_MASK (0x3FFF << 0) +#define _PSB_CBI_STAT_FAULT_CACHE (1 << 1) +#define _PSB_CBI_STAT_FAULT_TA (1 << 2) +#define _PSB_CBI_STAT_FAULT_VDM (1 << 3) +#define _PSB_CBI_STAT_FAULT_2D (1 << 4) +#define _PSB_CBI_STAT_FAULT_PBE (1 << 5) +#define _PSB_CBI_STAT_FAULT_TSP (1 << 6) +#define _PSB_CBI_STAT_FAULT_ISP (1 << 7) +#define _PSB_CBI_STAT_FAULT_USSEPDS (1 << 8) +#define _PSB_CBI_STAT_FAULT_HOST (1 << 9) + +#define PSB_CR_BIF_BANK0 0x0C78 +#define PSB_CR_BIF_BANK1 0x0C7C +#define PSB_CR_BIF_DIR_LIST_BASE0 0x0C84 +#define PSB_CR_BIF_TWOD_REQ_BASE 0x0C88 +#define PSB_CR_BIF_3D_REQ_BASE 0x0CAC + +#define PSB_CR_2D_SOCIF 0x0E18 +#define _PSB_C2_SOCIF_FREESPACE_SHIFT (0) +#define _PSB_C2_SOCIF_FREESPACE_MASK (0xFF << 0) +#define _PSB_C2_SOCIF_EMPTY (0x80 << 0) + +#define PSB_CR_2D_BLIT_STATUS 0x0E04 +#define _PSB_C2B_STATUS_BUSY (1 << 24) +#define _PSB_C2B_STATUS_COMPLETE_SHIFT (0) +#define _PSB_C2B_STATUS_COMPLETE_MASK (0xFFFFFF << 0) /* * 2D defs. @@ -186,121 +182,121 @@ * 2D Slave Port Data : Block Header's Object Type */ -#define PSB_2D_CLIP_BH (0x00000000) -#define PSB_2D_PAT_BH (0x10000000) -#define PSB_2D_CTRL_BH (0x20000000) -#define PSB_2D_SRC_OFF_BH (0x30000000) -#define PSB_2D_MASK_OFF_BH (0x40000000) -#define PSB_2D_RESERVED1_BH (0x50000000) -#define PSB_2D_RESERVED2_BH (0x60000000) -#define PSB_2D_FENCE_BH (0x70000000) -#define PSB_2D_BLIT_BH (0x80000000) -#define PSB_2D_SRC_SURF_BH (0x90000000) -#define PSB_2D_DST_SURF_BH (0xA0000000) -#define PSB_2D_PAT_SURF_BH (0xB0000000) -#define PSB_2D_SRC_PAL_BH (0xC0000000) -#define PSB_2D_PAT_PAL_BH (0xD0000000) -#define PSB_2D_MASK_SURF_BH (0xE0000000) -#define PSB_2D_FLUSH_BH (0xF0000000) +#define PSB_2D_CLIP_BH (0x00000000) +#define PSB_2D_PAT_BH (0x10000000) +#define PSB_2D_CTRL_BH (0x20000000) +#define PSB_2D_SRC_OFF_BH (0x30000000) +#define PSB_2D_MASK_OFF_BH (0x40000000) +#define PSB_2D_RESERVED1_BH (0x50000000) +#define PSB_2D_RESERVED2_BH (0x60000000) +#define PSB_2D_FENCE_BH (0x70000000) +#define PSB_2D_BLIT_BH (0x80000000) +#define PSB_2D_SRC_SURF_BH (0x90000000) +#define PSB_2D_DST_SURF_BH (0xA0000000) +#define PSB_2D_PAT_SURF_BH (0xB0000000) +#define PSB_2D_SRC_PAL_BH (0xC0000000) +#define PSB_2D_PAT_PAL_BH (0xD0000000) +#define PSB_2D_MASK_SURF_BH (0xE0000000) +#define PSB_2D_FLUSH_BH (0xF0000000) /* * Clip Definition block (PSB_2D_CLIP_BH) */ -#define PSB_2D_CLIPCOUNT_MAX (1) -#define PSB_2D_CLIPCOUNT_MASK (0x00000000) -#define PSB_2D_CLIPCOUNT_CLRMASK (0xFFFFFFFF) -#define PSB_2D_CLIPCOUNT_SHIFT (0) +#define PSB_2D_CLIPCOUNT_MAX (1) +#define PSB_2D_CLIPCOUNT_MASK (0x00000000) +#define PSB_2D_CLIPCOUNT_CLRMASK (0xFFFFFFFF) +#define PSB_2D_CLIPCOUNT_SHIFT (0) /* clip rectangle min & max */ -#define PSB_2D_CLIP_XMAX_MASK (0x00FFF000) -#define PSB_2D_CLIP_XMAX_CLRMASK (0xFF000FFF) -#define PSB_2D_CLIP_XMAX_SHIFT (12) -#define PSB_2D_CLIP_XMIN_MASK (0x00000FFF) -#define PSB_2D_CLIP_XMIN_CLRMASK (0x00FFF000) -#define PSB_2D_CLIP_XMIN_SHIFT (0) +#define PSB_2D_CLIP_XMAX_MASK (0x00FFF000) +#define PSB_2D_CLIP_XMAX_CLRMASK (0xFF000FFF) +#define PSB_2D_CLIP_XMAX_SHIFT (12) +#define PSB_2D_CLIP_XMIN_MASK (0x00000FFF) +#define PSB_2D_CLIP_XMIN_CLRMASK (0x00FFF000) +#define PSB_2D_CLIP_XMIN_SHIFT (0) /* clip rectangle offset */ -#define PSB_2D_CLIP_YMAX_MASK (0x00FFF000) -#define PSB_2D_CLIP_YMAX_CLRMASK (0xFF000FFF) -#define PSB_2D_CLIP_YMAX_SHIFT (12) -#define PSB_2D_CLIP_YMIN_MASK (0x00000FFF) -#define PSB_2D_CLIP_YMIN_CLRMASK (0x00FFF000) -#define PSB_2D_CLIP_YMIN_SHIFT (0) +#define PSB_2D_CLIP_YMAX_MASK (0x00FFF000) +#define PSB_2D_CLIP_YMAX_CLRMASK (0xFF000FFF) +#define PSB_2D_CLIP_YMAX_SHIFT (12) +#define PSB_2D_CLIP_YMIN_MASK (0x00000FFF) +#define PSB_2D_CLIP_YMIN_CLRMASK (0x00FFF000) +#define PSB_2D_CLIP_YMIN_SHIFT (0) /* * Pattern Control (PSB_2D_PAT_BH) */ -#define PSB_2D_PAT_HEIGHT_MASK (0x0000001F) -#define PSB_2D_PAT_HEIGHT_SHIFT (0) -#define PSB_2D_PAT_WIDTH_MASK (0x000003E0) -#define PSB_2D_PAT_WIDTH_SHIFT (5) -#define PSB_2D_PAT_YSTART_MASK (0x00007C00) -#define PSB_2D_PAT_YSTART_SHIFT (10) -#define PSB_2D_PAT_XSTART_MASK (0x000F8000) -#define PSB_2D_PAT_XSTART_SHIFT (15) +#define PSB_2D_PAT_HEIGHT_MASK (0x0000001F) +#define PSB_2D_PAT_HEIGHT_SHIFT (0) +#define PSB_2D_PAT_WIDTH_MASK (0x000003E0) +#define PSB_2D_PAT_WIDTH_SHIFT (5) +#define PSB_2D_PAT_YSTART_MASK (0x00007C00) +#define PSB_2D_PAT_YSTART_SHIFT (10) +#define PSB_2D_PAT_XSTART_MASK (0x000F8000) +#define PSB_2D_PAT_XSTART_SHIFT (15) /* * 2D Control block (PSB_2D_CTRL_BH) */ /* Present Flags */ -#define PSB_2D_SRCCK_CTRL (0x00000001) -#define PSB_2D_DSTCK_CTRL (0x00000002) -#define PSB_2D_ALPHA_CTRL (0x00000004) +#define PSB_2D_SRCCK_CTRL (0x00000001) +#define PSB_2D_DSTCK_CTRL (0x00000002) +#define PSB_2D_ALPHA_CTRL (0x00000004) /* Colour Key Colour (SRC/DST)*/ -#define PSB_2D_CK_COL_MASK (0xFFFFFFFF) -#define PSB_2D_CK_COL_CLRMASK (0x00000000) -#define PSB_2D_CK_COL_SHIFT (0) +#define PSB_2D_CK_COL_MASK (0xFFFFFFFF) +#define PSB_2D_CK_COL_CLRMASK (0x00000000) +#define PSB_2D_CK_COL_SHIFT (0) /* Colour Key Mask (SRC/DST)*/ -#define PSB_2D_CK_MASK_MASK (0xFFFFFFFF) -#define PSB_2D_CK_MASK_CLRMASK (0x00000000) -#define PSB_2D_CK_MASK_SHIFT (0) +#define PSB_2D_CK_MASK_MASK (0xFFFFFFFF) +#define PSB_2D_CK_MASK_CLRMASK (0x00000000) +#define PSB_2D_CK_MASK_SHIFT (0) /* Alpha Control (Alpha/RGB)*/ -#define PSB_2D_GBLALPHA_MASK (0x000FF000) -#define PSB_2D_GBLALPHA_CLRMASK (0xFFF00FFF) -#define PSB_2D_GBLALPHA_SHIFT (12) -#define PSB_2D_SRCALPHA_OP_MASK (0x00700000) -#define PSB_2D_SRCALPHA_OP_CLRMASK (0xFF8FFFFF) -#define PSB_2D_SRCALPHA_OP_SHIFT (20) -#define PSB_2D_SRCALPHA_OP_ONE (0x00000000) -#define PSB_2D_SRCALPHA_OP_SRC (0x00100000) -#define PSB_2D_SRCALPHA_OP_DST (0x00200000) -#define PSB_2D_SRCALPHA_OP_SG (0x00300000) -#define PSB_2D_SRCALPHA_OP_DG (0x00400000) -#define PSB_2D_SRCALPHA_OP_GBL (0x00500000) -#define PSB_2D_SRCALPHA_OP_ZERO (0x00600000) -#define PSB_2D_SRCALPHA_INVERT (0x00800000) -#define PSB_2D_SRCALPHA_INVERT_CLR (0xFF7FFFFF) -#define PSB_2D_DSTALPHA_OP_MASK (0x07000000) -#define PSB_2D_DSTALPHA_OP_CLRMASK (0xF8FFFFFF) -#define PSB_2D_DSTALPHA_OP_SHIFT (24) -#define PSB_2D_DSTALPHA_OP_ONE (0x00000000) -#define PSB_2D_DSTALPHA_OP_SRC (0x01000000) -#define PSB_2D_DSTALPHA_OP_DST (0x02000000) -#define PSB_2D_DSTALPHA_OP_SG (0x03000000) -#define PSB_2D_DSTALPHA_OP_DG (0x04000000) -#define PSB_2D_DSTALPHA_OP_GBL (0x05000000) -#define PSB_2D_DSTALPHA_OP_ZERO (0x06000000) -#define PSB_2D_DSTALPHA_INVERT (0x08000000) -#define PSB_2D_DSTALPHA_INVERT_CLR (0xF7FFFFFF) - -#define PSB_2D_PRE_MULTIPLICATION_ENABLE (0x10000000) -#define PSB_2D_PRE_MULTIPLICATION_CLRMASK (0xEFFFFFFF) -#define PSB_2D_ZERO_SOURCE_ALPHA_ENABLE (0x20000000) -#define PSB_2D_ZERO_SOURCE_ALPHA_CLRMASK (0xDFFFFFFF) +#define PSB_2D_GBLALPHA_MASK (0x000FF000) +#define PSB_2D_GBLALPHA_CLRMASK (0xFFF00FFF) +#define PSB_2D_GBLALPHA_SHIFT (12) +#define PSB_2D_SRCALPHA_OP_MASK (0x00700000) +#define PSB_2D_SRCALPHA_OP_CLRMASK (0xFF8FFFFF) +#define PSB_2D_SRCALPHA_OP_SHIFT (20) +#define PSB_2D_SRCALPHA_OP_ONE (0x00000000) +#define PSB_2D_SRCALPHA_OP_SRC (0x00100000) +#define PSB_2D_SRCALPHA_OP_DST (0x00200000) +#define PSB_2D_SRCALPHA_OP_SG (0x00300000) +#define PSB_2D_SRCALPHA_OP_DG (0x00400000) +#define PSB_2D_SRCALPHA_OP_GBL (0x00500000) +#define PSB_2D_SRCALPHA_OP_ZERO (0x00600000) +#define PSB_2D_SRCALPHA_INVERT (0x00800000) +#define PSB_2D_SRCALPHA_INVERT_CLR (0xFF7FFFFF) +#define PSB_2D_DSTALPHA_OP_MASK (0x07000000) +#define PSB_2D_DSTALPHA_OP_CLRMASK (0xF8FFFFFF) +#define PSB_2D_DSTALPHA_OP_SHIFT (24) +#define PSB_2D_DSTALPHA_OP_ONE (0x00000000) +#define PSB_2D_DSTALPHA_OP_SRC (0x01000000) +#define PSB_2D_DSTALPHA_OP_DST (0x02000000) +#define PSB_2D_DSTALPHA_OP_SG (0x03000000) +#define PSB_2D_DSTALPHA_OP_DG (0x04000000) +#define PSB_2D_DSTALPHA_OP_GBL (0x05000000) +#define PSB_2D_DSTALPHA_OP_ZERO (0x06000000) +#define PSB_2D_DSTALPHA_INVERT (0x08000000) +#define PSB_2D_DSTALPHA_INVERT_CLR (0xF7FFFFFF) + +#define PSB_2D_PRE_MULTIPLICATION_ENABLE (0x10000000) +#define PSB_2D_PRE_MULTIPLICATION_CLRMASK (0xEFFFFFFF) +#define PSB_2D_ZERO_SOURCE_ALPHA_ENABLE (0x20000000) +#define PSB_2D_ZERO_SOURCE_ALPHA_CLRMASK (0xDFFFFFFF) /* *Source Offset (PSB_2D_SRC_OFF_BH) */ -#define PSB_2D_SRCOFF_XSTART_MASK ((0x00000FFF) << 12) -#define PSB_2D_SRCOFF_XSTART_SHIFT (12) -#define PSB_2D_SRCOFF_YSTART_MASK (0x00000FFF) -#define PSB_2D_SRCOFF_YSTART_SHIFT (0) +#define PSB_2D_SRCOFF_XSTART_MASK ((0x00000FFF) << 12) +#define PSB_2D_SRCOFF_XSTART_SHIFT (12) +#define PSB_2D_SRCOFF_YSTART_MASK (0x00000FFF) +#define PSB_2D_SRCOFF_YSTART_SHIFT (0) /* * Mask Offset (PSB_2D_MASK_OFF_BH) */ -#define PSB_2D_MASKOFF_XSTART_MASK ((0x00000FFF) << 12) -#define PSB_2D_MASKOFF_XSTART_SHIFT (12) -#define PSB_2D_MASKOFF_YSTART_MASK (0x00000FFF) -#define PSB_2D_MASKOFF_YSTART_SHIFT (0) +#define PSB_2D_MASKOFF_XSTART_MASK ((0x00000FFF) << 12) +#define PSB_2D_MASKOFF_XSTART_SHIFT (12) +#define PSB_2D_MASKOFF_YSTART_MASK (0x00000FFF) +#define PSB_2D_MASKOFF_YSTART_SHIFT (0) /* * 2D Fence (see PSB_2D_FENCE_BH): bits 0:27 are ignored @@ -310,118 +306,118 @@ *Blit Rectangle (PSB_2D_BLIT_BH) */ -#define PSB_2D_ROT_MASK (3<<25) -#define PSB_2D_ROT_CLRMASK (~PSB_2D_ROT_MASK) -#define PSB_2D_ROT_NONE (0<<25) -#define PSB_2D_ROT_90DEGS (1<<25) -#define PSB_2D_ROT_180DEGS (2<<25) -#define PSB_2D_ROT_270DEGS (3<<25) - -#define PSB_2D_COPYORDER_MASK (3<<23) -#define PSB_2D_COPYORDER_CLRMASK (~PSB_2D_COPYORDER_MASK) -#define PSB_2D_COPYORDER_TL2BR (0<<23) -#define PSB_2D_COPYORDER_BR2TL (1<<23) -#define PSB_2D_COPYORDER_TR2BL (2<<23) -#define PSB_2D_COPYORDER_BL2TR (3<<23) - -#define PSB_2D_DSTCK_CLRMASK (0xFF9FFFFF) -#define PSB_2D_DSTCK_DISABLE (0x00000000) -#define PSB_2D_DSTCK_PASS (0x00200000) -#define PSB_2D_DSTCK_REJECT (0x00400000) - -#define PSB_2D_SRCCK_CLRMASK (0xFFE7FFFF) -#define PSB_2D_SRCCK_DISABLE (0x00000000) -#define PSB_2D_SRCCK_PASS (0x00080000) -#define PSB_2D_SRCCK_REJECT (0x00100000) - -#define PSB_2D_CLIP_ENABLE (0x00040000) - -#define PSB_2D_ALPHA_ENABLE (0x00020000) - -#define PSB_2D_PAT_CLRMASK (0xFFFEFFFF) -#define PSB_2D_PAT_MASK (0x00010000) -#define PSB_2D_USE_PAT (0x00010000) -#define PSB_2D_USE_FILL (0x00000000) +#define PSB_2D_ROT_MASK (3 << 25) +#define PSB_2D_ROT_CLRMASK (~PSB_2D_ROT_MASK) +#define PSB_2D_ROT_NONE (0 << 25) +#define PSB_2D_ROT_90DEGS (1 << 25) +#define PSB_2D_ROT_180DEGS (2 << 25) +#define PSB_2D_ROT_270DEGS (3 << 25) + +#define PSB_2D_COPYORDER_MASK (3 << 23) +#define PSB_2D_COPYORDER_CLRMASK (~PSB_2D_COPYORDER_MASK) +#define PSB_2D_COPYORDER_TL2BR (0 << 23) +#define PSB_2D_COPYORDER_BR2TL (1 << 23) +#define PSB_2D_COPYORDER_TR2BL (2 << 23) +#define PSB_2D_COPYORDER_BL2TR (3 << 23) + +#define PSB_2D_DSTCK_CLRMASK (0xFF9FFFFF) +#define PSB_2D_DSTCK_DISABLE (0x00000000) +#define PSB_2D_DSTCK_PASS (0x00200000) +#define PSB_2D_DSTCK_REJECT (0x00400000) + +#define PSB_2D_SRCCK_CLRMASK (0xFFE7FFFF) +#define PSB_2D_SRCCK_DISABLE (0x00000000) +#define PSB_2D_SRCCK_PASS (0x00080000) +#define PSB_2D_SRCCK_REJECT (0x00100000) + +#define PSB_2D_CLIP_ENABLE (0x00040000) + +#define PSB_2D_ALPHA_ENABLE (0x00020000) + +#define PSB_2D_PAT_CLRMASK (0xFFFEFFFF) +#define PSB_2D_PAT_MASK (0x00010000) +#define PSB_2D_USE_PAT (0x00010000) +#define PSB_2D_USE_FILL (0x00000000) /* * Tungsten Graphics note on rop codes: If rop A and rop B are * identical, the mask surface will not be read and need not be * set up. */ -#define PSB_2D_ROP3B_MASK (0x0000FF00) -#define PSB_2D_ROP3B_CLRMASK (0xFFFF00FF) -#define PSB_2D_ROP3B_SHIFT (8) +#define PSB_2D_ROP3B_MASK (0x0000FF00) +#define PSB_2D_ROP3B_CLRMASK (0xFFFF00FF) +#define PSB_2D_ROP3B_SHIFT (8) /* rop code A */ -#define PSB_2D_ROP3A_MASK (0x000000FF) -#define PSB_2D_ROP3A_CLRMASK (0xFFFFFF00) -#define PSB_2D_ROP3A_SHIFT (0) +#define PSB_2D_ROP3A_MASK (0x000000FF) +#define PSB_2D_ROP3A_CLRMASK (0xFFFFFF00) +#define PSB_2D_ROP3A_SHIFT (0) -#define PSB_2D_ROP4_MASK (0x0000FFFF) +#define PSB_2D_ROP4_MASK (0x0000FFFF) /* * DWORD0: (Only pass if Pattern control == Use Fill Colour) * Fill Colour RGBA8888 */ -#define PSB_2D_FILLCOLOUR_MASK (0xFFFFFFFF) -#define PSB_2D_FILLCOLOUR_SHIFT (0) +#define PSB_2D_FILLCOLOUR_MASK (0xFFFFFFFF) +#define PSB_2D_FILLCOLOUR_SHIFT (0) /* * DWORD1: (Always Present) * X Start (Dest) * Y Start (Dest) */ -#define PSB_2D_DST_XSTART_MASK (0x00FFF000) -#define PSB_2D_DST_XSTART_CLRMASK (0xFF000FFF) -#define PSB_2D_DST_XSTART_SHIFT (12) -#define PSB_2D_DST_YSTART_MASK (0x00000FFF) -#define PSB_2D_DST_YSTART_CLRMASK (0xFFFFF000) -#define PSB_2D_DST_YSTART_SHIFT (0) +#define PSB_2D_DST_XSTART_MASK (0x00FFF000) +#define PSB_2D_DST_XSTART_CLRMASK (0xFF000FFF) +#define PSB_2D_DST_XSTART_SHIFT (12) +#define PSB_2D_DST_YSTART_MASK (0x00000FFF) +#define PSB_2D_DST_YSTART_CLRMASK (0xFFFFF000) +#define PSB_2D_DST_YSTART_SHIFT (0) /* * DWORD2: (Always Present) * X Size (Dest) * Y Size (Dest) */ -#define PSB_2D_DST_XSIZE_MASK (0x00FFF000) -#define PSB_2D_DST_XSIZE_CLRMASK (0xFF000FFF) -#define PSB_2D_DST_XSIZE_SHIFT (12) -#define PSB_2D_DST_YSIZE_MASK (0x00000FFF) -#define PSB_2D_DST_YSIZE_CLRMASK (0xFFFFF000) -#define PSB_2D_DST_YSIZE_SHIFT (0) +#define PSB_2D_DST_XSIZE_MASK (0x00FFF000) +#define PSB_2D_DST_XSIZE_CLRMASK (0xFF000FFF) +#define PSB_2D_DST_XSIZE_SHIFT (12) +#define PSB_2D_DST_YSIZE_MASK (0x00000FFF) +#define PSB_2D_DST_YSIZE_CLRMASK (0xFFFFF000) +#define PSB_2D_DST_YSIZE_SHIFT (0) /* * Source Surface (PSB_2D_SRC_SURF_BH) */ /* - * WORD 0 + * WORD 0 */ -#define PSB_2D_SRC_FORMAT_MASK (0x00078000) -#define PSB_2D_SRC_1_PAL (0x00000000) -#define PSB_2D_SRC_2_PAL (0x00008000) -#define PSB_2D_SRC_4_PAL (0x00010000) -#define PSB_2D_SRC_8_PAL (0x00018000) -#define PSB_2D_SRC_8_ALPHA (0x00020000) -#define PSB_2D_SRC_4_ALPHA (0x00028000) -#define PSB_2D_SRC_332RGB (0x00030000) -#define PSB_2D_SRC_4444ARGB (0x00038000) -#define PSB_2D_SRC_555RGB (0x00040000) -#define PSB_2D_SRC_1555ARGB (0x00048000) -#define PSB_2D_SRC_565RGB (0x00050000) -#define PSB_2D_SRC_0888ARGB (0x00058000) -#define PSB_2D_SRC_8888ARGB (0x00060000) -#define PSB_2D_SRC_8888UYVY (0x00068000) -#define PSB_2D_SRC_RESERVED (0x00070000) -#define PSB_2D_SRC_1555ARGB_LOOKUP (0x00078000) - - -#define PSB_2D_SRC_STRIDE_MASK (0x00007FFF) -#define PSB_2D_SRC_STRIDE_CLRMASK (0xFFFF8000) -#define PSB_2D_SRC_STRIDE_SHIFT (0) +#define PSB_2D_SRC_FORMAT_MASK (0x00078000) +#define PSB_2D_SRC_1_PAL (0x00000000) +#define PSB_2D_SRC_2_PAL (0x00008000) +#define PSB_2D_SRC_4_PAL (0x00010000) +#define PSB_2D_SRC_8_PAL (0x00018000) +#define PSB_2D_SRC_8_ALPHA (0x00020000) +#define PSB_2D_SRC_4_ALPHA (0x00028000) +#define PSB_2D_SRC_332RGB (0x00030000) +#define PSB_2D_SRC_4444ARGB (0x00038000) +#define PSB_2D_SRC_555RGB (0x00040000) +#define PSB_2D_SRC_1555ARGB (0x00048000) +#define PSB_2D_SRC_565RGB (0x00050000) +#define PSB_2D_SRC_0888ARGB (0x00058000) +#define PSB_2D_SRC_8888ARGB (0x00060000) +#define PSB_2D_SRC_8888UYVY (0x00068000) +#define PSB_2D_SRC_RESERVED (0x00070000) +#define PSB_2D_SRC_1555ARGB_LOOKUP (0x00078000) + + +#define PSB_2D_SRC_STRIDE_MASK (0x00007FFF) +#define PSB_2D_SRC_STRIDE_CLRMASK (0xFFFF8000) +#define PSB_2D_SRC_STRIDE_SHIFT (0) /* * WORD 1 - Base Address */ -#define PSB_2D_SRC_ADDR_MASK (0x0FFFFFFC) -#define PSB_2D_SRC_ADDR_CLRMASK (0x00000003) -#define PSB_2D_SRC_ADDR_SHIFT (2) -#define PSB_2D_SRC_ADDR_ALIGNSHIFT (2) +#define PSB_2D_SRC_ADDR_MASK (0x0FFFFFFC) +#define PSB_2D_SRC_ADDR_CLRMASK (0x00000003) +#define PSB_2D_SRC_ADDR_SHIFT (2) +#define PSB_2D_SRC_ADDR_ALIGNSHIFT (2) /* * Pattern Surface (PSB_2D_PAT_SURF_BH) @@ -430,31 +426,31 @@ * WORD 0 */ -#define PSB_2D_PAT_FORMAT_MASK (0x00078000) -#define PSB_2D_PAT_1_PAL (0x00000000) -#define PSB_2D_PAT_2_PAL (0x00008000) -#define PSB_2D_PAT_4_PAL (0x00010000) -#define PSB_2D_PAT_8_PAL (0x00018000) -#define PSB_2D_PAT_8_ALPHA (0x00020000) -#define PSB_2D_PAT_4_ALPHA (0x00028000) -#define PSB_2D_PAT_332RGB (0x00030000) -#define PSB_2D_PAT_4444ARGB (0x00038000) -#define PSB_2D_PAT_555RGB (0x00040000) -#define PSB_2D_PAT_1555ARGB (0x00048000) -#define PSB_2D_PAT_565RGB (0x00050000) -#define PSB_2D_PAT_0888ARGB (0x00058000) -#define PSB_2D_PAT_8888ARGB (0x00060000) - -#define PSB_2D_PAT_STRIDE_MASK (0x00007FFF) -#define PSB_2D_PAT_STRIDE_CLRMASK (0xFFFF8000) -#define PSB_2D_PAT_STRIDE_SHIFT (0) +#define PSB_2D_PAT_FORMAT_MASK (0x00078000) +#define PSB_2D_PAT_1_PAL (0x00000000) +#define PSB_2D_PAT_2_PAL (0x00008000) +#define PSB_2D_PAT_4_PAL (0x00010000) +#define PSB_2D_PAT_8_PAL (0x00018000) +#define PSB_2D_PAT_8_ALPHA (0x00020000) +#define PSB_2D_PAT_4_ALPHA (0x00028000) +#define PSB_2D_PAT_332RGB (0x00030000) +#define PSB_2D_PAT_4444ARGB (0x00038000) +#define PSB_2D_PAT_555RGB (0x00040000) +#define PSB_2D_PAT_1555ARGB (0x00048000) +#define PSB_2D_PAT_565RGB (0x00050000) +#define PSB_2D_PAT_0888ARGB (0x00058000) +#define PSB_2D_PAT_8888ARGB (0x00060000) + +#define PSB_2D_PAT_STRIDE_MASK (0x00007FFF) +#define PSB_2D_PAT_STRIDE_CLRMASK (0xFFFF8000) +#define PSB_2D_PAT_STRIDE_SHIFT (0) /* * WORD 1 - Base Address */ -#define PSB_2D_PAT_ADDR_MASK (0x0FFFFFFC) -#define PSB_2D_PAT_ADDR_CLRMASK (0x00000003) -#define PSB_2D_PAT_ADDR_SHIFT (2) -#define PSB_2D_PAT_ADDR_ALIGNSHIFT (2) +#define PSB_2D_PAT_ADDR_MASK (0x0FFFFFFC) +#define PSB_2D_PAT_ADDR_CLRMASK (0x00000003) +#define PSB_2D_PAT_ADDR_SHIFT (2) +#define PSB_2D_PAT_ADDR_ALIGNSHIFT (2) /* * Destination Surface (PSB_2D_DST_SURF_BH) @@ -463,26 +459,26 @@ * WORD 0 */ -#define PSB_2D_DST_FORMAT_MASK (0x00078000) -#define PSB_2D_DST_332RGB (0x00030000) -#define PSB_2D_DST_4444ARGB (0x00038000) -#define PSB_2D_DST_555RGB (0x00040000) -#define PSB_2D_DST_1555ARGB (0x00048000) -#define PSB_2D_DST_565RGB (0x00050000) -#define PSB_2D_DST_0888ARGB (0x00058000) -#define PSB_2D_DST_8888ARGB (0x00060000) -#define PSB_2D_DST_8888AYUV (0x00070000) - -#define PSB_2D_DST_STRIDE_MASK (0x00007FFF) -#define PSB_2D_DST_STRIDE_CLRMASK (0xFFFF8000) -#define PSB_2D_DST_STRIDE_SHIFT (0) +#define PSB_2D_DST_FORMAT_MASK (0x00078000) +#define PSB_2D_DST_332RGB (0x00030000) +#define PSB_2D_DST_4444ARGB (0x00038000) +#define PSB_2D_DST_555RGB (0x00040000) +#define PSB_2D_DST_1555ARGB (0x00048000) +#define PSB_2D_DST_565RGB (0x00050000) +#define PSB_2D_DST_0888ARGB (0x00058000) +#define PSB_2D_DST_8888ARGB (0x00060000) +#define PSB_2D_DST_8888AYUV (0x00070000) + +#define PSB_2D_DST_STRIDE_MASK (0x00007FFF) +#define PSB_2D_DST_STRIDE_CLRMASK (0xFFFF8000) +#define PSB_2D_DST_STRIDE_SHIFT (0) /* * WORD 1 - Base Address */ -#define PSB_2D_DST_ADDR_MASK (0x0FFFFFFC) -#define PSB_2D_DST_ADDR_CLRMASK (0x00000003) -#define PSB_2D_DST_ADDR_SHIFT (2) -#define PSB_2D_DST_ADDR_ALIGNSHIFT (2) +#define PSB_2D_DST_ADDR_MASK (0x0FFFFFFC) +#define PSB_2D_DST_ADDR_CLRMASK (0x00000003) +#define PSB_2D_DST_ADDR_SHIFT (2) +#define PSB_2D_DST_ADDR_ALIGNSHIFT (2) /* * Mask Surface (PSB_2D_MASK_SURF_BH) @@ -490,99 +486,97 @@ /* * WORD 0 */ -#define PSB_2D_MASK_STRIDE_MASK (0x00007FFF) -#define PSB_2D_MASK_STRIDE_CLRMASK (0xFFFF8000) -#define PSB_2D_MASK_STRIDE_SHIFT (0) +#define PSB_2D_MASK_STRIDE_MASK (0x00007FFF) +#define PSB_2D_MASK_STRIDE_CLRMASK (0xFFFF8000) +#define PSB_2D_MASK_STRIDE_SHIFT (0) /* * WORD 1 - Base Address */ -#define PSB_2D_MASK_ADDR_MASK (0x0FFFFFFC) -#define PSB_2D_MASK_ADDR_CLRMASK (0x00000003) -#define PSB_2D_MASK_ADDR_SHIFT (2) -#define PSB_2D_MASK_ADDR_ALIGNSHIFT (2) +#define PSB_2D_MASK_ADDR_MASK (0x0FFFFFFC) +#define PSB_2D_MASK_ADDR_CLRMASK (0x00000003) +#define PSB_2D_MASK_ADDR_SHIFT (2) +#define PSB_2D_MASK_ADDR_ALIGNSHIFT (2) /* * Source Palette (PSB_2D_SRC_PAL_BH) */ -#define PSB_2D_SRCPAL_ADDR_SHIFT (0) -#define PSB_2D_SRCPAL_ADDR_CLRMASK (0xF0000007) -#define PSB_2D_SRCPAL_ADDR_MASK (0x0FFFFFF8) -#define PSB_2D_SRCPAL_BYTEALIGN (1024) +#define PSB_2D_SRCPAL_ADDR_SHIFT (0) +#define PSB_2D_SRCPAL_ADDR_CLRMASK (0xF0000007) +#define PSB_2D_SRCPAL_ADDR_MASK (0x0FFFFFF8) +#define PSB_2D_SRCPAL_BYTEALIGN (1024) /* * Pattern Palette (PSB_2D_PAT_PAL_BH) */ -#define PSB_2D_PATPAL_ADDR_SHIFT (0) -#define PSB_2D_PATPAL_ADDR_CLRMASK (0xF0000007) -#define PSB_2D_PATPAL_ADDR_MASK (0x0FFFFFF8) -#define PSB_2D_PATPAL_BYTEALIGN (1024) +#define PSB_2D_PATPAL_ADDR_SHIFT (0) +#define PSB_2D_PATPAL_ADDR_CLRMASK (0xF0000007) +#define PSB_2D_PATPAL_ADDR_MASK (0x0FFFFFF8) +#define PSB_2D_PATPAL_BYTEALIGN (1024) /* * Rop3 Codes (2 LS bytes) */ -#define PSB_2D_ROP3_SRCCOPY (0xCCCC) -#define PSB_2D_ROP3_PATCOPY (0xF0F0) -#define PSB_2D_ROP3_WHITENESS (0xFFFF) -#define PSB_2D_ROP3_BLACKNESS (0x0000) -#define PSB_2D_ROP3_SRC (0xCC) -#define PSB_2D_ROP3_PAT (0xF0) -#define PSB_2D_ROP3_DST (0xAA) - +#define PSB_2D_ROP3_SRCCOPY (0xCCCC) +#define PSB_2D_ROP3_PATCOPY (0xF0F0) +#define PSB_2D_ROP3_WHITENESS (0xFFFF) +#define PSB_2D_ROP3_BLACKNESS (0x0000) +#define PSB_2D_ROP3_SRC (0xCC) +#define PSB_2D_ROP3_PAT (0xF0) +#define PSB_2D_ROP3_DST (0xAA) /* * Sizes. */ -#define PSB_SCENE_HW_COOKIE_SIZE 16 -#define PSB_TA_MEM_HW_COOKIE_SIZE 16 +#define PSB_SCENE_HW_COOKIE_SIZE 16 +#define PSB_TA_MEM_HW_COOKIE_SIZE 16 /* * Scene stuff. */ -#define PSB_NUM_HW_SCENES 2 +#define PSB_NUM_HW_SCENES 2 /* * Scheduler completion actions. */ -#define PSB_RASTER_BLOCK 0 -#define PSB_RASTER 1 -#define PSB_RETURN 2 -#define PSB_TA 3 - - -/*Power management*/ -#define PSB_PUNIT_PORT 0x04 -#define PSB_OSPMBA 0x78 -#define PSB_APMBA 0x7a -#define PSB_APM_CMD 0x0 -#define PSB_APM_STS 0x04 -#define PSB_PWRGT_VID_ENC_MASK 0x30 -#define PSB_PWRGT_VID_DEC_MASK 0xc -#define PSB_PWRGT_GL3_MASK 0xc0 - -#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 PSB_RASTER_BLOCK 0 +#define PSB_RASTER 1 +#define PSB_RETURN 2 +#define PSB_TA 3 + +/* Power management */ +#define PSB_PUNIT_PORT 0x04 +#define PSB_OSPMBA 0x78 +#define PSB_APMBA 0x7a +#define PSB_APM_CMD 0x0 +#define PSB_APM_STS 0x04 +#define PSB_PWRGT_VID_ENC_MASK 0x30 +#define PSB_PWRGT_VID_DEC_MASK 0xc +#define PSB_PWRGT_GL3_MASK 0xc0 + +#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 +#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 |