diff options
Diffstat (limited to 'drivers/gpu/drm/gma500')
69 files changed, 5051 insertions, 13649 deletions
diff --git a/drivers/gpu/drm/gma500/Kconfig b/drivers/gpu/drm/gma500/Kconfig index 1f6e2dfaaeae..a2acaa699dd5 100644 --- a/drivers/gpu/drm/gma500/Kconfig +++ b/drivers/gpu/drm/gma500/Kconfig @@ -1,38 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-only config DRM_GMA500 - tristate "Intel GMA5/600 KMS Framebuffer" - depends on DRM && PCI && X86 - select FB_CFB_COPYAREA - select FB_CFB_FILLRECT - select FB_CFB_IMAGEBLIT + tristate "Intel GMA500/600/3600/3650 KMS Framebuffer" + depends on DRM && PCI && X86 && HAS_IOPORT + select DRM_CLIENT_SELECTION select DRM_KMS_HELPER - select DRM_TTM + select FB_IOMEM_HELPERS if DRM_FBDEV_EMULATION + select I2C + select I2C_ALGOBIT # GMA500 depends on ACPI_VIDEO when ACPI is enabled, just like i915 select ACPI_VIDEO if ACPI select BACKLIGHT_CLASS_DEVICE if ACPI - select VIDEO_OUTPUT_CONTROL if ACPI select INPUT if ACPI + select X86_PLATFORM_DEVICES if ACPI + select ACPI_WMI if ACPI help Say yes for an experimental 2D KMS framebuffer driver for the - Intel GMA500 ('Poulsbo') and other Intel IMG based graphics - devices. - -config DRM_GMA600 - bool "Intel GMA600 support (Experimental)" - depends on DRM_GMA500 - help - Say yes to include support for GMA600 (Intel Moorestown/Oaktrail) - platforms with LVDS ports. MIPI is not currently supported. - -config DRM_GMA3600 - bool "Intel GMA3600/3650 support (Experimental)" - depends on DRM_GMA500 - help - Say yes to include basic support for Intel GMA3600/3650 (Intel - Cedar Trail) platforms. - -config DRM_MEDFIELD - bool "Intel Medfield support (Experimental)" - depends on DRM_GMA500 && X86_INTEL_MID - help - Say yes to include support for the Intel Medfield platform. - + Intel GMA500 (Poulsbo), Intel GMA600 (Moorestown/Oak Trail) and + Intel GMA3600/3650 (Cedar Trail). diff --git a/drivers/gpu/drm/gma500/Makefile b/drivers/gpu/drm/gma500/Makefile index 7a2d40a5c1e1..58fed80c7392 100644 --- a/drivers/gpu/drm/gma500/Makefile +++ b/drivers/gpu/drm/gma500/Makefile @@ -1,52 +1,42 @@ +# SPDX-License-Identifier: GPL-2.0 # # KMS driver for the GMA500 # -ccflags-y += -I$(srctree)/include/drm gma500_gfx-y += \ - accel_2d.o \ backlight.o \ + cdv_device.o \ + cdv_intel_crt.o \ + cdv_intel_display.o \ + cdv_intel_dp.o \ + cdv_intel_hdmi.o \ + cdv_intel_lvds.o \ framebuffer.o \ gem.o \ + gma_device.o \ + gma_display.o \ gtt.o \ intel_bios.o \ - intel_i2c.o \ intel_gmbus.o \ + intel_i2c.o \ + mid_bios.o \ mmu.o \ + oaktrail_device.o \ + oaktrail_crtc.o \ + oaktrail_hdmi.o \ + oaktrail_hdmi_i2c.o \ + oaktrail_lvds.o \ + oaktrail_lvds_i2c.o \ power.o \ + psb_device.o \ psb_drv.o \ psb_intel_display.o \ psb_intel_lvds.o \ psb_intel_modes.o \ psb_intel_sdvo.o \ - psb_lid.o \ - psb_irq.o \ - psb_device.o \ - mid_bios.o - -gma500_gfx-$(CONFIG_ACPI) += opregion.o \ - -gma500_gfx-$(CONFIG_DRM_GMA3600) += cdv_device.o \ - cdv_intel_crt.o \ - cdv_intel_display.o \ - cdv_intel_hdmi.o \ - cdv_intel_lvds.o \ - cdv_intel_dp.o - -gma500_gfx-$(CONFIG_DRM_GMA600) += oaktrail_device.o \ - oaktrail_crtc.o \ - oaktrail_lvds.o \ - oaktrail_hdmi.o \ - oaktrail_hdmi_i2c.o + psb_irq.o -gma500_gfx-$(CONFIG_DRM_MEDFIELD) += mdfld_device.o \ - mdfld_output.o \ - mdfld_intel_display.o \ - mdfld_dsi_output.o \ - mdfld_dsi_dpi.o \ - mdfld_dsi_pkg_sender.o \ - mdfld_tpo_vid.o \ - mdfld_tmd_vid.o \ - tc35876x-dsi-lvds.o +gma500_gfx-$(CONFIG_ACPI) += opregion.o +gma500_gfx-$(CONFIG_DRM_FBDEV_EMULATION) += fbdev.o obj-$(CONFIG_DRM_GMA500) += gma500_gfx.o diff --git a/drivers/gpu/drm/gma500/accel_2d.c b/drivers/gpu/drm/gma500/accel_2d.c deleted file mode 100644 index d5ef1a5793c8..000000000000 --- a/drivers/gpu/drm/gma500/accel_2d.c +++ /dev/null @@ -1,364 +0,0 @@ -/************************************************************************** - * Copyright (c) 2007-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. - * - * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to - * develop this driver. - * - **************************************************************************/ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/tty.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/fb.h> -#include <linux/init.h> -#include <linux/console.h> - -#include <drm/drmP.h> -#include <drm/drm.h> -#include <drm/drm_crtc.h> - -#include "psb_drv.h" -#include "psb_reg.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_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); - PSB_RSGX32(PSB_CR_SOFT_RESET); - - msleep(1); - - PSB_WSGX32(0, PSB_CR_SOFT_RESET); - wmb(); - PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) | _PSB_CB_CTRL_CLEAR_FAULT, - PSB_CR_BIF_CTRL); - wmb(); - (void) PSB_RSGX32(PSB_CR_BIF_CTRL); - - msleep(1); - 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->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) { - avail = PSB_RSGX32(PSB_CR_2D_SOCIF); - if (time_after(jiffies, t)) { - psb_spank(dev_priv); - return -EIO; - } - } - return 0; -} - -/** - * 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; - unsigned long flags; - - spin_lock_irqsave(&dev_priv->lock_2d, flags); - while (size > 0) { - submit_size = (size < 0x60) ? size : 0x60; - size -= submit_size; - ret = psb_2d_wait_available(dev_priv, submit_size); - if (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); - } - spin_unlock_irqrestore(&dev_priv->lock_2d, flags); - return ret; -} - - -/** - * 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; - else - return (ydir < 0) ? PSB_2D_COPYORDER_BL2TR : - PSB_2D_COPYORDER_TL2BR; -} - -/** - * 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, - uint32_t src_format, uint32_t dst_offset, - uint32_t dst_stride, uint32_t dst_format, - uint16_t src_x, uint16_t src_y, - uint16_t dst_x, uint16_t dst_y, - uint16_t size_x, uint16_t size_y) -{ - uint32_t blit_cmd; - uint32_t buffer[10]; - uint32_t *buf; - uint32_t direction; - - buf = buffer; - - direction = - psb_accel_2d_copy_direction(src_x - dst_x, src_y - dst_y); - - if (direction == PSB_2D_COPYORDER_BR2TL || - direction == PSB_2D_COPYORDER_TR2BL) { - src_x += size_x - 1; - dst_x += size_x - 1; - } - if (direction == PSB_2D_COPYORDER_BR2TL || - direction == PSB_2D_COPYORDER_BL2TR) { - src_y += size_y - 1; - dst_y += size_y - 1; - } - - blit_cmd = - PSB_2D_BLIT_BH | - PSB_2D_ROT_NONE | - PSB_2D_DSTCK_DISABLE | - PSB_2D_SRCCK_DISABLE | - PSB_2D_USE_PAT | PSB_2D_ROP3_SRCCOPY | direction; - - *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_SRC_SURF_BH | src_format | (src_stride << - PSB_2D_SRC_STRIDE_SHIFT); - *buf++ = src_offset; - *buf++ = - PSB_2D_SRC_OFF_BH | (src_x << PSB_2D_SRCOFF_XSTART_SHIFT) | - (src_y << PSB_2D_SRCOFF_YSTART_SHIFT); - *buf++ = blit_cmd; - *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); -} - -/** - * 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 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 src_format; - uint32_t dst_format; - - if (!fb) - return; - - offset = psbfb->gtt->offset; - stride = fb->pitches[0]; - - switch (fb->depth) { - case 8: - src_format = PSB_2D_SRC_332RGB; - dst_format = PSB_2D_DST_332RGB; - break; - case 15: - src_format = PSB_2D_SRC_555RGB; - dst_format = PSB_2D_DST_555RGB; - break; - case 16: - src_format = PSB_2D_SRC_565RGB; - dst_format = PSB_2D_DST_565RGB; - break; - case 24: - case 32: - /* this is wrong but since we don't do blending its okay */ - src_format = PSB_2D_SRC_8888ARGB; - dst_format = PSB_2D_DST_8888ARGB; - break; - default: - /* software fallback */ - cfb_copyarea(info, a); - 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; - - /* Avoid the 8 pixel erratum */ - if (region->width == 8 || region->height == 8 || - (info->flags & FBINFO_HWACCEL_DISABLED)) - return cfb_copyarea(info, region); - - psbfb_copyarea_accel(info, region); -} - -/** - * 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 drm_device *dev = psbfb->base.dev; - struct drm_psb_private *dev_priv = dev->dev_private; - unsigned long _end = jiffies + DRM_HZ; - int busy = 0; - unsigned long flags; - - spin_lock_irqsave(&dev_priv->lock_2d, flags); - /* - * First idle the 2D engine. - */ - - if ((PSB_RSGX32(PSB_CR_2D_SOCIF) == _PSB_C2_SOCIF_EMPTY) && - ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & _PSB_C2B_STATUS_BUSY) == 0)) - goto out; - - do { - busy = (PSB_RSGX32(PSB_CR_2D_SOCIF) != _PSB_C2_SOCIF_EMPTY); - cpu_relax(); - } while (busy && !time_after_eq(jiffies, _end)); - - if (busy) - busy = (PSB_RSGX32(PSB_CR_2D_SOCIF) != _PSB_C2_SOCIF_EMPTY); - if (busy) - goto out; - - do { - busy = ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & - _PSB_C2B_STATUS_BUSY) != 0); - cpu_relax(); - } while (busy && !time_after_eq(jiffies, _end)); - if (busy) - busy = ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & - _PSB_C2B_STATUS_BUSY) != 0); - -out: - spin_unlock_irqrestore(&dev_priv->lock_2d, flags); - return (busy) ? -EBUSY : 0; -} diff --git a/drivers/gpu/drm/gma500/backlight.c b/drivers/gpu/drm/gma500/backlight.c index 143eba3309c5..c8f1716a12d5 100644 --- a/drivers/gpu/drm/gma500/backlight.c +++ b/drivers/gpu/drm/gma500/backlight.c @@ -1,94 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * 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 <linux/backlight.h> + +#include <acpi/video.h> + +#include <drm/drm_print.h> + #include "psb_drv.h" #include "psb_intel_reg.h" #include "psb_intel_drv.h" #include "intel_bios.h" #include "power.h" -static void do_gma_backlight_set(struct drm_device *dev) -{ -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE - struct drm_psb_private *dev_priv = dev->dev_private; - backlight_update_status(dev_priv->backlight_device); -#endif -} - void gma_backlight_enable(struct drm_device *dev) { -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + dev_priv->backlight_enabled = true; - if (dev_priv->backlight_device) { - dev_priv->backlight_device->props.brightness = dev_priv->backlight_level; - do_gma_backlight_set(dev); - } -#endif + dev_priv->ops->backlight_set(dev, dev_priv->backlight_level); } void gma_backlight_disable(struct drm_device *dev) { -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + dev_priv->backlight_enabled = false; - if (dev_priv->backlight_device) { - dev_priv->backlight_device->props.brightness = 0; - do_gma_backlight_set(dev); - } -#endif + dev_priv->ops->backlight_set(dev, 0); } void gma_backlight_set(struct drm_device *dev, int v) { -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + dev_priv->backlight_level = v; - if (dev_priv->backlight_device && dev_priv->backlight_enabled) { - dev_priv->backlight_device->props.brightness = v; - do_gma_backlight_set(dev); - } -#endif + if (dev_priv->backlight_enabled) + dev_priv->ops->backlight_set(dev, v); } +static int gma_backlight_get_brightness(struct backlight_device *bd) +{ + struct drm_device *dev = bl_get_data(bd); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + + if (dev_priv->ops->backlight_get) + return dev_priv->ops->backlight_get(dev); + + return dev_priv->backlight_level; +} + +static int gma_backlight_update_status(struct backlight_device *bd) +{ + struct drm_device *dev = bl_get_data(bd); + int level = backlight_get_brightness(bd); + + /* Percentage 1-100% being valid */ + if (level < 1) + level = 1; + + gma_backlight_set(dev, level); + return 0; +} + +static const struct backlight_ops gma_backlight_ops __maybe_unused = { + .get_brightness = gma_backlight_get_brightness, + .update_status = gma_backlight_update_status, +}; + int gma_backlight_init(struct drm_device *dev) { -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct backlight_properties props __maybe_unused = {}; + int ret; + dev_priv->backlight_enabled = true; - return dev_priv->ops->backlight_init(dev); -#else - return 0; + dev_priv->backlight_level = 100; + + ret = dev_priv->ops->backlight_init(dev); + if (ret) + return ret; + + if (!acpi_video_backlight_use_native()) { + drm_info(dev, "Skipping %s backlight registration\n", + dev_priv->ops->backlight_name); + return 0; + } + +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + props.brightness = dev_priv->backlight_level; + props.max_brightness = PSB_MAX_BRIGHTNESS; + props.type = BACKLIGHT_RAW; + + dev_priv->backlight_device = + backlight_device_register(dev_priv->ops->backlight_name, + dev->dev, dev, + &gma_backlight_ops, &props); + if (IS_ERR(dev_priv->backlight_device)) + return PTR_ERR(dev_priv->backlight_device); #endif + + return 0; } 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); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + + if (dev_priv->backlight_device) backlight_device_unregister(dev_priv->backlight_device); - } #endif } diff --git a/drivers/gpu/drm/gma500/cdv_device.c b/drivers/gpu/drm/gma500/cdv_device.c index 23e14e93991f..fd6ea8998dbe 100644 --- a/drivers/gpu/drm/gma500/cdv_device.c +++ b/drivers/gpu/drm/gma500/cdv_device.c @@ -1,31 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-only /************************************************************************** * 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 <linux/delay.h> + #include <drm/drm.h> -#include <drm/gma_drm.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_print.h> + +#include "cdv_device.h" +#include "gma_device.h" +#include "intel_bios.h" #include "psb_drv.h" -#include "psb_reg.h" #include "psb_intel_reg.h" -#include "intel_bios.h" -#include "cdv_device.h" +#include "psb_reg.h" #define VGA_SR_INDEX 0x3c4 #define VGA_SR_DATA 0x3c5 @@ -48,7 +39,7 @@ static void cdv_disable_vga(struct drm_device *dev) static int cdv_output_init(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); drm_mode_create_scaling_mode_property(dev); @@ -72,14 +63,10 @@ static int cdv_output_init(struct drm_device *dev) return 0; } -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE - /* * Cedartrail Backlght Interfaces */ -static struct backlight_device *cdv_backlight_device; - static int cdv_backlight_combination_mode(struct drm_device *dev) { return REG_READ(BLC_PWM_CTL2) & PWM_LEGACY_MODE; @@ -102,32 +89,26 @@ static u32 cdv_get_max_backlight(struct drm_device *dev) return max; } -static int cdv_get_brightness(struct backlight_device *bd) +static int cdv_get_brightness(struct drm_device *dev) { - struct drm_device *dev = bl_get_data(bd); + struct pci_dev *pdev = to_pci_dev(dev->dev); u32 val = REG_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; if (cdv_backlight_combination_mode(dev)) { u8 lbpc; val &= ~1; - pci_read_config_byte(dev->pdev, 0xF4, &lbpc); + pci_read_config_byte(pdev, 0xF4, &lbpc); val *= lbpc; } return (val * 100)/cdv_get_max_backlight(dev); - } -static int cdv_set_brightness(struct backlight_device *bd) +static void cdv_set_brightness(struct drm_device *dev, int level) { - struct drm_device *dev = bl_get_data(bd); - int level = bd->props.brightness; + struct pci_dev *pdev = to_pci_dev(dev->dev); u32 blc_pwm_ctl; - /* Percentage 1-100% being valid */ - if (level < 1) - level = 1; - level *= cdv_get_max_backlight(dev); level /= 100; @@ -138,44 +119,24 @@ static int cdv_set_brightness(struct backlight_device *bd) lbpc = level * 0xfe / max + 1; level /= lbpc; - pci_write_config_byte(dev->pdev, 0xF4, lbpc); + pci_write_config_byte(pdev, 0xF4, lbpc); } 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))); - 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; - 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); - - cdv_backlight_device->props.brightness = - cdv_get_brightness(cdv_backlight_device); - backlight_update_status(cdv_backlight_device); - dev_priv->backlight_device = cdv_backlight_device; - dev_priv->backlight_enabled = true; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + + dev_priv->backlight_level = cdv_get_brightness(dev); + cdv_set_brightness(dev, dev_priv->backlight_level); + return 0; } -#endif - /* * Provide the Cedarview specific chip logic and low level methods * for power management @@ -184,21 +145,22 @@ static int cdv_backlight_init(struct drm_device *dev) * for this and the MID devices. */ -static inline u32 CDV_MSG_READ32(uint port, uint offset) +static inline u32 CDV_MSG_READ32(int domain, uint port, uint offset) { int mcr = (0x10<<24) | (port << 16) | (offset << 8); uint32_t ret_val = 0; - struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0); + struct pci_dev *pci_root = pci_get_domain_bus_and_slot(domain, 0, 0); pci_write_config_dword(pci_root, 0xD0, mcr); pci_read_config_dword(pci_root, 0xD4, &ret_val); pci_dev_put(pci_root); return ret_val; } -static inline void CDV_MSG_WRITE32(uint port, uint offset, u32 value) +static inline void CDV_MSG_WRITE32(int domain, uint port, uint offset, + u32 value) { int mcr = (0x11<<24) | (port << 16) | (offset << 8) | 0xF0; - struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0); + struct pci_dev *pci_root = pci_get_domain_bus_and_slot(domain, 0, 0); pci_write_config_dword(pci_root, 0xD4, value); pci_write_config_dword(pci_root, 0xD0, mcr); pci_dev_put(pci_root); @@ -213,13 +175,15 @@ static inline void CDV_MSG_WRITE32(uint port, uint offset, u32 value) static void cdv_init_pm(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct pci_dev *pdev = to_pci_dev(dev->dev); u32 pwr_cnt; + int domain = pci_domain_nr(pdev->bus); int i; - dev_priv->apm_base = CDV_MSG_READ32(PSB_PUNIT_PORT, + dev_priv->apm_base = CDV_MSG_READ32(domain, PSB_PUNIT_PORT, PSB_APMBA) & 0xFFFF; - dev_priv->ospm_base = CDV_MSG_READ32(PSB_PUNIT_PORT, + dev_priv->ospm_base = CDV_MSG_READ32(domain, PSB_PUNIT_PORT, PSB_OSPMBA) & 0xFFFF; /* Power status */ @@ -242,6 +206,8 @@ static void cdv_init_pm(struct drm_device *dev) static void cdv_errata(struct drm_device *dev) { + struct pci_dev *pdev = to_pci_dev(dev->dev); + /* Disable bonus launch. * CPU and GPU competes for memory and display misses updates and * flickers. Worst with dual core, dual displays. @@ -250,7 +216,7 @@ static void cdv_errata(struct drm_device *dev) * Bonus Launch to work around the issue, by degrading * performance. */ - CDV_MSG_WRITE32(3, 0x30, 0x08027108); + CDV_MSG_WRITE32(pci_domain_nr(pdev->bus), 3, 0x30, 0x08027108); } /** @@ -262,13 +228,15 @@ static void cdv_errata(struct drm_device *dev) */ static int cdv_save_display_registers(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct pci_dev *pdev = to_pci_dev(dev->dev); struct psb_save_area *regs = &dev_priv->regs; + struct drm_connector_list_iter conn_iter; struct drm_connector *connector; dev_dbg(dev->dev, "Saving GPU registers.\n"); - pci_read_config_byte(dev->pdev, 0xF4, ®s->cdv.saveLBB); + pci_read_config_byte(pdev, 0xF4, ®s->cdv.saveLBB); regs->cdv.saveDSPCLK_GATE_D = REG_READ(DSPCLK_GATE_D); regs->cdv.saveRAMCLK_GATE_D = REG_READ(RAMCLK_GATE_D); @@ -300,8 +268,10 @@ static int cdv_save_display_registers(struct drm_device *dev) regs->cdv.saveIER = REG_READ(PSB_INT_ENABLE_R); regs->cdv.saveIMR = REG_READ(PSB_INT_MASK_R); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF); + drm_connector_list_iter_end(&conn_iter); return 0; } @@ -316,12 +286,14 @@ static int cdv_save_display_registers(struct drm_device *dev) */ static int cdv_restore_display_registers(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct pci_dev *pdev = to_pci_dev(dev->dev); struct psb_save_area *regs = &dev_priv->regs; + struct drm_connector_list_iter conn_iter; struct drm_connector *connector; u32 temp; - pci_write_config_byte(dev->pdev, 0xF4, regs->cdv.saveLBB); + pci_write_config_byte(pdev, 0xF4, regs->cdv.saveLBB); REG_WRITE(DSPCLK_GATE_D, regs->cdv.saveDSPCLK_GATE_D); REG_WRITE(RAMCLK_GATE_D, regs->cdv.saveRAMCLK_GATE_D); @@ -374,8 +346,10 @@ static int cdv_restore_display_registers(struct drm_device *dev) drm_mode_config_reset(dev); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) connector->funcs->dpms(connector, DRM_MODE_DPMS_ON); + drm_connector_list_iter_end(&conn_iter); /* Resume the modeset for every activated CRTC */ drm_helper_resume_force_mode(dev); @@ -384,7 +358,7 @@ static int cdv_restore_display_registers(struct drm_device *dev) static int cdv_power_down(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); u32 pwr_cnt, pwr_mask, pwr_sts; int tries = 5; @@ -406,7 +380,7 @@ static int cdv_power_down(struct drm_device *dev) static int cdv_power_up(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); u32 pwr_cnt, pwr_mask, pwr_sts; int tries = 5; @@ -426,59 +400,22 @@ 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; - break; - default: - dev_priv->core_freq = 0; - } -} - static void cdv_hotplug_work_func(struct work_struct *work) { struct drm_psb_private *dev_priv = container_of(work, struct drm_psb_private, - hotplug_work); - struct drm_device *dev = dev_priv->dev; + hotplug_work); + struct drm_device *dev = &dev_priv->dev; /* Just fire off a uevent and let userspace tell us what to do */ drm_helper_hpd_irq_event(dev); -} +} /* The core driver has received a hotplug IRQ. We are in IRQ context so extract the needed information and kick off queued processing */ - + static int cdv_hotplug_event(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); schedule_work(&dev_priv->hotplug_work); REG_WRITE(PORT_HOTPLUG_STAT, REG_READ(PORT_HOTPLUG_STAT)); return 1; @@ -494,7 +431,7 @@ static void cdv_hotplug_enable(struct drm_device *dev, bool on) } else { REG_WRITE(PORT_HOTPLUG_EN, 0); REG_WRITE(PORT_HOTPLUG_STAT, REG_READ(PORT_HOTPLUG_STAT)); - } + } } static const char *force_audio_names[] = { @@ -506,7 +443,7 @@ static const char *force_audio_names[] = { void cdv_intel_attach_force_audio_property(struct drm_connector *connector) { struct drm_device *dev = connector->dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct drm_property *prop; int i; @@ -519,7 +456,7 @@ void cdv_intel_attach_force_audio_property(struct drm_connector *connector) return; for (i = 0; i < ARRAY_SIZE(force_audio_names); i++) - drm_property_add_enum(prop, i, i-1, force_audio_names[i]); + drm_property_add_enum(prop, i-1, force_audio_names[i]); dev_priv->force_audio_property = prop; } @@ -535,7 +472,7 @@ static const char *broadcast_rgb_names[] = { void cdv_intel_attach_broadcast_rgb_property(struct drm_connector *connector) { struct drm_device *dev = connector->dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct drm_property *prop; int i; @@ -548,7 +485,7 @@ void cdv_intel_attach_broadcast_rgb_property(struct drm_connector *connector) return; for (i = 0; i < ARRAY_SIZE(broadcast_rgb_names); i++) - drm_property_add_enum(prop, i, i, broadcast_rgb_names[i]); + drm_property_add_enum(prop, i, broadcast_rgb_names[i]); dev_priv->broadcast_rgb_property = prop; } @@ -612,13 +549,12 @@ static const struct psb_offset cdv_regmap[2] = { static int cdv_chip_setup(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); INIT_WORK(&dev_priv->hotplug_work, cdv_hotplug_work_func); - if (pci_enable_msi(dev->pdev)) - dev_warn(dev->dev, "Enabling MSI failed!\n"); + dev_priv->use_msi = true; dev_priv->regmap = cdv_regmap; - cdv_get_core_freq(dev); + gma_get_core_freq(dev); psb_intel_opregion_init(dev); psb_intel_init_bios(dev); cdv_hotplug_enable(dev, false); @@ -629,30 +565,35 @@ static int cdv_chip_setup(struct drm_device *dev) const struct psb_ops cdv_chip_ops = { .name = "GMA3600/3650", - .accel_2d = 0, .pipes = 2, .crtcs = 2, .hdmi_mask = (1 << 0) | (1 << 1), .lvds_mask = (1 << 1), + .sdvo_mask = (1 << 0), .cursor_needs_phys = 0, .sgx_offset = MRST_SGX_OFFSET, .chip_setup = cdv_chip_setup, .errata = cdv_errata, .crtc_helper = &cdv_intel_helper_funcs, - .crtc_funcs = &cdv_intel_crtc_funcs, + .clock_funcs = &cdv_clock_funcs, .output_init = cdv_output_init, .hotplug = cdv_hotplug_event, .hotplug_enable = cdv_hotplug_enable, -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE .backlight_init = cdv_backlight_init, -#endif + .backlight_get = cdv_get_brightness, + .backlight_set = cdv_set_brightness, + .backlight_name = "psb-bl", .init_pm = cdv_init_pm, .save_regs = cdv_save_display_registers, .restore_regs = cdv_restore_display_registers, + .save_crtc = gma_crtc_save, + .restore_crtc = gma_crtc_restore, .power_down = cdv_power_down, .power_up = cdv_power_up, + .update_wm = cdv_update_wm, + .disable_sr = cdv_disable_sr, }; diff --git a/drivers/gpu/drm/gma500/cdv_device.h b/drivers/gpu/drm/gma500/cdv_device.h index 9561e17621b3..504d717385cd 100644 --- a/drivers/gpu/drm/gma500/cdv_device.h +++ b/drivers/gpu/drm/gma500/cdv_device.h @@ -1,22 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * 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. */ +struct drm_crtc; +struct drm_device; +struct psb_intel_mode_device; + extern const struct drm_crtc_helper_funcs cdv_intel_helper_funcs; -extern const struct drm_crtc_funcs cdv_intel_crtc_funcs; +extern const struct gma_clock_funcs cdv_clock_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, @@ -25,12 +17,5 @@ extern void cdv_hdmi_init(struct drm_device *dev, struct psb_intel_mode_device * int reg); extern struct drm_display_mode *cdv_intel_crtc_mode_get(struct drm_device *dev, struct drm_crtc *crtc); - -static inline void cdv_intel_wait_for_vblank(struct drm_device *dev) -{ - /* Wait for 20ms, i.e. one cycle at 50hz. */ - /* FIXME: msleep ?? */ - mdelay(20); -} - - +extern void cdv_update_wm(struct drm_device *dev, struct drm_crtc *crtc); +extern void cdv_disable_sr(struct drm_device *dev); diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c index 7b8386fc3024..06fe7480e7af 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_crt.c +++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c @@ -24,16 +24,20 @@ * Eric Anholt <eric@anholt.net> */ +#include <linux/delay.h> #include <linux/i2c.h> -#include <drm/drmP.h> +#include <linux/pm_runtime.h> + +#include <drm/drm_crtc_helper.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_simple_kms_helper.h> +#include "cdv_device.h" #include "intel_bios.h" +#include "power.h" #include "psb_drv.h" #include "psb_intel_drv.h" #include "psb_intel_reg.h" -#include "power.h" -#include "cdv_device.h" -#include <linux/pm_runtime.h> static void cdv_intel_crt_dpms(struct drm_encoder *encoder, int mode) @@ -64,8 +68,8 @@ static void cdv_intel_crt_dpms(struct drm_encoder *encoder, int mode) REG_WRITE(reg, temp); } -static int cdv_intel_crt_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status cdv_intel_crt_mode_valid(struct drm_connector *connector, + const struct drm_display_mode *mode) { if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; @@ -81,13 +85,6 @@ static int cdv_intel_crt_mode_valid(struct drm_connector *connector, return MODE_OK; } -static bool cdv_intel_crt_mode_fixup(struct drm_encoder *encoder, - const 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) @@ -95,13 +92,12 @@ static void cdv_intel_crt_mode_set(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct drm_crtc *crtc = encoder->crtc; - struct psb_intel_crtc *psb_intel_crtc = - to_psb_intel_crtc(crtc); + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); int dpll_md_reg; u32 adpa, dpll_md; u32 adpa_reg; - if (psb_intel_crtc->pipe == 0) + if (gma_crtc->pipe == 0) dpll_md_reg = DPLL_A_MD; else dpll_md_reg = DPLL_B_MD; @@ -124,7 +120,7 @@ static void cdv_intel_crt_mode_set(struct drm_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) adpa |= ADPA_VSYNC_ACTIVE_HIGH; - if (psb_intel_crtc->pipe == 0) + if (gma_crtc->pipe == 0) adpa |= ADPA_PIPE_A_SELECT; else adpa |= ADPA_PIPE_B_SELECT; @@ -133,7 +129,7 @@ static void cdv_intel_crt_mode_set(struct drm_encoder *encoder, } -/** +/* * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence. * * \return true if CRT is connected. @@ -197,20 +193,17 @@ static enum drm_connector_status cdv_intel_crt_detect( static void cdv_intel_crt_destroy(struct drm_connector *connector) { - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); + struct gma_connector *gma_connector = to_gma_connector(connector); + struct gma_i2c_chan *ddc_bus = to_gma_i2c_chan(connector->ddc); - psb_intel_i2c_destroy(psb_intel_encoder->ddc_bus); - drm_sysfs_connector_remove(connector); + gma_i2c_destroy(ddc_bus); drm_connector_cleanup(connector); - kfree(connector); + kfree(gma_connector); } static int cdv_intel_crt_get_modes(struct drm_connector *connector) { - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); - return psb_intel_ddc_get_modes(connector, &psb_intel_encoder->ddc_bus->adapter); + return psb_intel_ddc_get_modes(connector, connector->ddc); } static int cdv_intel_crt_set_property(struct drm_connector *connector, @@ -226,9 +219,8 @@ static int cdv_intel_crt_set_property(struct drm_connector *connector, 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, + .prepare = gma_encoder_prepare, + .commit = gma_encoder_commit, .mode_set = cdv_intel_crt_mode_set, }; @@ -244,69 +236,52 @@ 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, + .best_encoder = gma_best_encoder, }; void cdv_intel_crt_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev) { - struct psb_intel_connector *psb_intel_connector; - struct psb_intel_encoder *psb_intel_encoder; + struct gma_connector *gma_connector; + struct gma_encoder *gma_encoder; + struct gma_i2c_chan *ddc_bus; struct drm_connector *connector; struct drm_encoder *encoder; + int ret; - u32 i2c_reg; - - psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder), GFP_KERNEL); - if (!psb_intel_encoder) + gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL); + if (!gma_encoder) return; - psb_intel_connector = kzalloc(sizeof(struct psb_intel_connector), GFP_KERNEL); - if (!psb_intel_connector) - goto failed_connector; + gma_connector = kzalloc(sizeof(struct gma_connector), GFP_KERNEL); + if (!gma_connector) + goto err_free_encoder; - connector = &psb_intel_connector->base; + /* Set up the DDC bus. */ + ddc_bus = gma_i2c_create(dev, GPIOA, "CRTDDC_A"); + if (!ddc_bus) { + dev_printk(KERN_ERR, dev->dev, "DDC bus registration failed.\n"); + goto err_free_connector; + } + + connector = &gma_connector->base; connector->polled = DRM_CONNECTOR_POLL_HPD; - drm_connector_init(dev, connector, - &cdv_intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); + ret = drm_connector_init_with_ddc(dev, connector, + &cdv_intel_crt_connector_funcs, + DRM_MODE_CONNECTOR_VGA, + &ddc_bus->base); + if (ret) + goto err_ddc_destroy; - encoder = &psb_intel_encoder->base; - drm_encoder_init(dev, encoder, - &cdv_intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC); + encoder = &gma_encoder->base; + ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_DAC); + if (ret) + goto err_connector_cleanup; - psb_intel_connector_attach_encoder(psb_intel_connector, - psb_intel_encoder); + gma_connector_attach_encoder(gma_connector, gma_encoder); - /* 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_encoder->ddc_bus = psb_intel_i2c_create(dev, - i2c_reg, "CRTDDC_A"); - if (!psb_intel_encoder->ddc_bus) { - dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " - "failed.\n"); - goto failed_ddc; - } - - psb_intel_encoder->type = INTEL_OUTPUT_ANALOG; - /* - psb_intel_output->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT); - psb_intel_output->crtc_mask = (1 << 0) | (1 << 1); - */ + gma_encoder->type = INTEL_OUTPUT_ANALOG; connector->interlace_allowed = 0; connector->doublescan_allowed = 0; @@ -314,14 +289,15 @@ void cdv_intel_crt_init(struct drm_device *dev, drm_connector_helper_add(connector, &cdv_intel_crt_connector_helper_funcs); - drm_sysfs_connector_add(connector); - return; -failed_ddc: - drm_encoder_cleanup(&psb_intel_encoder->base); - drm_connector_cleanup(&psb_intel_connector->base); - kfree(psb_intel_connector); -failed_connector: - kfree(psb_intel_encoder); + +err_connector_cleanup: + drm_connector_cleanup(&gma_connector->base); +err_ddc_destroy: + gma_i2c_destroy(ddc_bus); +err_free_connector: + kfree(gma_connector); +err_free_encoder: + kfree(gma_encoder); return; } diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c index 82430ad8ba62..5942a9d46b02 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_display.c +++ b/drivers/gpu/drm/gma500/cdv_intel_display.c @@ -1,72 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * 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/delay.h> #include <linux/i2c.h> -#include <linux/pm_runtime.h> -#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_print.h> + +#include "cdv_device.h" #include "framebuffer.h" +#include "gma_display.h" +#include "power.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; -}; +static bool cdv_intel_find_dp_pll(const struct gma_limit_t *limit, + struct drm_crtc *crtc, int target, + int refclk, struct gma_clock_t *best_clock); -#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; - bool (*find_pll)(const struct cdv_intel_limit_t *, struct drm_crtc *, - int, int, struct cdv_intel_clock_t *); -}; - -static bool cdv_intel_find_best_PLL(const struct cdv_intel_limit_t *limit, - struct drm_crtc *crtc, int target, int refclk, - struct cdv_intel_clock_t *best_clock); -static bool cdv_intel_find_dp_pll(const struct cdv_intel_limit_t *limit, struct drm_crtc *crtc, int target, - int refclk, - struct cdv_intel_clock_t *best_clock); #define CDV_LIMIT_SINGLE_LVDS_96 0 #define CDV_LIMIT_SINGLE_LVDS_100 1 @@ -75,7 +33,7 @@ static bool cdv_intel_find_dp_pll(const struct cdv_intel_limit_t *limit, struct #define CDV_LIMIT_DP_27 4 #define CDV_LIMIT_DP_100 5 -static const struct cdv_intel_limit_t cdv_intel_limits[] = { +static const struct gma_limit_t cdv_intel_limits[] = { { /* CDV_SINGLE_LVDS_96MHz */ .dot = {.min = 20000, .max = 115500}, .vco = {.min = 1800000, .max = 3600000}, @@ -85,9 +43,8 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = { .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}, - .find_pll = cdv_intel_find_best_PLL, + .p2 = {.dot_limit = 200000, .p2_slow = 14, .p2_fast = 14}, + .find_pll = gma_find_best_pll, }, { /* CDV_SINGLE_LVDS_100MHz */ .dot = {.min = 20000, .max = 115500}, @@ -102,7 +59,7 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = { * is 80-224Mhz. Prefer single channel as much as possible. */ .p2 = {.dot_limit = 200000, .p2_slow = 14, .p2_fast = 14}, - .find_pll = cdv_intel_find_best_PLL, + .find_pll = gma_find_best_pll, }, { /* CDV_DAC_HDMI_27MHz */ .dot = {.min = 20000, .max = 400000}, @@ -114,7 +71,7 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = { .p = {.min = 5, .max = 90}, .p1 = {.min = 1, .max = 9}, .p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 5}, - .find_pll = cdv_intel_find_best_PLL, + .find_pll = gma_find_best_pll, }, { /* CDV_DAC_HDMI_96MHz */ .dot = {.min = 20000, .max = 400000}, @@ -126,7 +83,7 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = { .p = {.min = 5, .max = 100}, .p1 = {.min = 1, .max = 10}, .p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 5}, - .find_pll = cdv_intel_find_best_PLL, + .find_pll = gma_find_best_pll, }, { /* CDV_DP_27MHz */ .dot = {.min = 160000, .max = 272000}, @@ -151,7 +108,7 @@ static const struct cdv_intel_limit_t cdv_intel_limits[] = { .p1 = {.min = 1, .max = 10}, .p2 = {.dot_limit = 225000, .p2_slow = 10, .p2_fast = 10}, .find_pll = cdv_intel_find_dp_pll, - } + } }; #define _wait_for(COND, MS, W) ({ \ @@ -255,10 +212,10 @@ void cdv_sb_reset(struct drm_device *dev) */ static int cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc, - struct cdv_intel_clock_t *clock, bool is_lvds, u32 ddi_select) + struct gma_clock_t *clock, bool is_lvds, u32 ddi_select) { - struct psb_intel_crtc *psb_crtc = to_psb_intel_crtc(crtc); - int pipe = psb_crtc->pipe; + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + int pipe = gma_crtc->pipe; u32 m, n_vco, p; int ret = 0; int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; @@ -280,7 +237,7 @@ cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc, /* We don't know what the other fields of these regs are, so * leave them in place. */ - /* + /* * The BIT 14:13 of 0x8010/0x8030 is used to select the ref clk * for the pipe A/B. Display spec 1.06 has wrong definition. * Correct definition is like below: @@ -291,7 +248,7 @@ cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc, * * if DPLLA sets 01 and DPLLB sets 02, both use clk from DPLLA * - */ + */ ret = cdv_sb_read(dev, ref_sfr, &ref_value); if (ret) return ret; @@ -405,31 +362,11 @@ cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc, return 0; } -/* - * Returns whether any encoder on the specified pipe is of the specified type - */ -static 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_encoder *psb_intel_encoder = - psb_intel_attached_encoder(l_entry); - if (psb_intel_encoder->type == type) - return true; - } - } - return false; -} - -static const struct cdv_intel_limit_t *cdv_intel_limit(struct drm_crtc *crtc, - int refclk) +static const struct gma_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)) { + const struct gma_limit_t *limit; + if (gma_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. @@ -438,8 +375,8 @@ static const struct cdv_intel_limit_t *cdv_intel_limit(struct drm_crtc *crtc, limit = &cdv_intel_limits[CDV_LIMIT_SINGLE_LVDS_96]; else limit = &cdv_intel_limits[CDV_LIMIT_SINGLE_LVDS_100]; - } else if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) || - psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) { + } else if (gma_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) || + gma_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) { if (refclk == 27000) limit = &cdv_intel_limits[CDV_LIMIT_DP_27]; else @@ -454,8 +391,7 @@ static const struct cdv_intel_limit_t *cdv_intel_limit(struct drm_crtc *crtc, } /* 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) +static void cdv_intel_clock(int refclk, struct gma_clock_t *clock) { clock->m = clock->m2 + 2; clock->p = clock->p1 * clock->p2; @@ -463,94 +399,18 @@ static void cdv_intel_clock(struct drm_device *dev, 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) +static bool cdv_intel_find_dp_pll(const struct gma_limit_t *limit, + struct drm_crtc *crtc, int target, + int refclk, + struct gma_clock_t *best_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(const struct cdv_intel_limit_t *limit, - 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; - int err = target; + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + struct gma_clock_t clock; + memset(&clock, 0, sizeof(clock)); - 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; -} - -static bool cdv_intel_find_dp_pll(const struct cdv_intel_limit_t *limit, struct drm_crtc *crtc, int target, - int refclk, - struct cdv_intel_clock_t *best_clock) -{ - struct cdv_intel_clock_t clock; - if (refclk == 27000) { + switch (refclk) { + case 27000: if (target < 200000) { clock.p1 = 2; clock.p2 = 10; @@ -564,7 +424,9 @@ static bool cdv_intel_find_dp_pll(const struct cdv_intel_limit_t *limit, struct clock.m1 = 0; clock.m2 = 98; } - } else if (refclk == 100000) { + break; + + case 100000: if (target < 200000) { clock.p1 = 2; clock.p2 = 10; @@ -578,89 +440,15 @@ static bool cdv_intel_find_dp_pll(const struct cdv_intel_limit_t *limit, struct clock.m1 = 0; clock.m2 = 133; } - } else - return false; - clock.m = clock.m2 + 2; - clock.p = clock.p1 * clock.p2; - clock.vco = (refclk * clock.m) / clock.n; - clock.dot = clock.vco / clock.p; - memcpy(best_clock, &clock, sizeof(struct cdv_intel_clock_t)); - return true; -} - -static 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 drm_psb_private *dev_priv = dev->dev_private; - 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; - const struct psb_offset *map = &dev_priv->regmap[pipe]; - unsigned long start, offset; - 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->pitches[0] + x * (crtc->fb->bits_per_pixel / 8); - - REG_WRITE(map->stride, crtc->fb->pitches[0]); - - dspcntr = REG_READ(map->cntr); - 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; + return false; } - REG_WRITE(map->cntr, dspcntr); - - dev_dbg(dev->dev, - "Writing base %08lX %08lX %d %d\n", start, offset, x, y); - REG_WRITE(map->base, offset); - REG_READ(map->base); - REG_WRITE(map->surf, start); - REG_READ(map->surf); - -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; + gma_crtc->clock_funcs->clock(refclk, &clock); + memcpy(best_clock, &clock, sizeof(struct gma_clock_t)); + return true; } #define FIFO_PIPEA (1 << 0) @@ -669,61 +457,18 @@ psb_intel_pipe_set_base_exit: static bool cdv_intel_pipe_enabled(struct drm_device *dev, int pipe) { struct drm_crtc *crtc; - struct drm_psb_private *dev_priv = dev->dev_private; - struct psb_intel_crtc *psb_intel_crtc = NULL; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_crtc *gma_crtc = NULL; crtc = dev_priv->pipe_to_crtc_mapping[pipe]; - psb_intel_crtc = to_psb_intel_crtc(crtc); + gma_crtc = to_gma_crtc(crtc); - if (crtc->fb == NULL || !psb_intel_crtc->active) + if (crtc->primary->fb == NULL || !gma_crtc->active) return false; return true; } -static bool cdv_intel_single_pipe_active (struct drm_device *dev) -{ - uint32_t pipe_enabled = 0; - - if (cdv_intel_pipe_enabled(dev, 0)) - pipe_enabled |= FIFO_PIPEA; - - if (cdv_intel_pipe_enabled(dev, 1)) - pipe_enabled |= FIFO_PIPEB; - - - DRM_DEBUG_KMS("pipe enabled %x\n", pipe_enabled); - - if (pipe_enabled == FIFO_PIPEA || pipe_enabled == FIFO_PIPEB) - return true; - else - return false; -} - -static bool is_pipeb_lvds(struct drm_device *dev, struct drm_crtc *crtc) -{ - struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); - struct drm_mode_config *mode_config = &dev->mode_config; - struct drm_connector *connector; - - if (psb_intel_crtc->pipe != 1) - return false; - - list_for_each_entry(connector, &mode_config->connector_list, head) { - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); - - if (!connector->encoder - || connector->encoder->crtc != crtc) - continue; - - if (psb_intel_encoder->type == INTEL_OUTPUT_LVDS) - return true; - } - - return false; -} - -static void cdv_intel_disable_self_refresh (struct drm_device *dev) +void cdv_disable_sr(struct drm_device *dev) { if (REG_READ(FW_BLC_SELF) & FW_BLC_SELF_EN) { @@ -731,7 +476,7 @@ static void cdv_intel_disable_self_refresh (struct drm_device *dev) REG_WRITE(FW_BLC_SELF, (REG_READ(FW_BLC_SELF) & ~FW_BLC_SELF_EN)); REG_READ(FW_BLC_SELF); - cdv_intel_wait_for_vblank(dev); + gma_wait_for_vblank(dev); /* Cedarview workaround to write ovelay plane, which force to leave * MAX_FIFO state. @@ -739,15 +484,18 @@ static void cdv_intel_disable_self_refresh (struct drm_device *dev) REG_WRITE(OV_OVADD, 0/*dev_priv->ovl_offset*/); REG_READ(OV_OVADD); - cdv_intel_wait_for_vblank(dev); + gma_wait_for_vblank(dev); } } -static void cdv_intel_update_watermark (struct drm_device *dev, struct drm_crtc *crtc) +void cdv_update_wm(struct drm_device *dev, struct drm_crtc *crtc) { + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); - if (cdv_intel_single_pipe_active(dev)) { + /* Is only one pipe enabled? */ + if (cdv_intel_pipe_enabled(dev, 0) ^ cdv_intel_pipe_enabled(dev, 1)) { u32 fw; fw = REG_READ(DSPFW1); @@ -768,7 +516,9 @@ static void cdv_intel_update_watermark (struct drm_device *dev, struct drm_crtc /* ignore FW4 */ - if (is_pipeb_lvds(dev, crtc)) { + /* Is pipe b lvds ? */ + if (gma_crtc->pipe == 1 && + gma_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { REG_WRITE(DSPFW5, 0x00040330); } else { fw = (3 << DSP_PLANE_B_FIFO_WM1_SHIFT) | @@ -780,12 +530,12 @@ static void cdv_intel_update_watermark (struct drm_device *dev, struct drm_crtc REG_WRITE(DSPFW6, 0x10); - cdv_intel_wait_for_vblank(dev); + gma_wait_for_vblank(dev); /* enable self-refresh for single pipe active */ REG_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); REG_READ(FW_BLC_SELF); - cdv_intel_wait_for_vblank(dev); + gma_wait_for_vblank(dev); } else { @@ -797,217 +547,13 @@ static void cdv_intel_update_watermark (struct drm_device *dev, struct drm_crtc REG_WRITE(DSPFW5, 0x01010101); REG_WRITE(DSPFW6, 0x1d0); - cdv_intel_wait_for_vblank(dev); - - cdv_intel_disable_self_refresh(dev); - - } -} - -/** Loads the palette/gamma unit for the CRTC with the prepared values */ -static void cdv_intel_crtc_load_lut(struct drm_crtc *crtc) -{ - 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 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->regs.pipe[0].palette[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]); - } - - } -} - -/** - * 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 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; - const struct psb_offset *map = &dev_priv->regmap[pipe]; - u32 temp; - - /* 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. - */ - cdv_intel_disable_self_refresh(dev); - - switch (mode) { - case DRM_MODE_DPMS_ON: - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - if (psb_intel_crtc->active) - break; - - psb_intel_crtc->active = true; - - /* Enable the DPLL */ - temp = REG_READ(map->dpll); - if ((temp & DPLL_VCO_ENABLE) == 0) { - REG_WRITE(map->dpll, temp); - REG_READ(map->dpll); - /* Wait for the clocks to stabilize. */ - udelay(150); - REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE); - REG_READ(map->dpll); - /* Wait for the clocks to stabilize. */ - udelay(150); - REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE); - REG_READ(map->dpll); - /* Wait for the clocks to stabilize. */ - udelay(150); - } - - /* Jim Bish - switch plan and pipe per scott */ - /* Enable the plane */ - temp = REG_READ(map->cntr); - if ((temp & DISPLAY_PLANE_ENABLE) == 0) { - REG_WRITE(map->cntr, - temp | DISPLAY_PLANE_ENABLE); - /* Flush the plane changes */ - REG_WRITE(map->base, REG_READ(map->base)); - } - - udelay(150); + gma_wait_for_vblank(dev); - /* Enable the pipe */ - temp = REG_READ(map->conf); - if ((temp & PIPEACONF_ENABLE) == 0) - REG_WRITE(map->conf, temp | PIPEACONF_ENABLE); - - temp = REG_READ(map->status); - temp &= ~(0xFFFF); - temp |= PIPE_FIFO_UNDERRUN; - REG_WRITE(map->status, temp); - REG_READ(map->status); - - cdv_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: - if (!psb_intel_crtc->active) - break; - - psb_intel_crtc->active = false; - - /* 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. */ - - drm_vblank_off(dev, pipe); - /* Wait for vblank for the disable to take effect */ - cdv_intel_wait_for_vblank(dev); - - /* Next, disable display pipes */ - temp = REG_READ(map->conf); - if ((temp & PIPEACONF_ENABLE) != 0) { - REG_WRITE(map->conf, temp & ~PIPEACONF_ENABLE); - REG_READ(map->conf); - } - - /* Wait for vblank for the disable to take effect. */ - cdv_intel_wait_for_vblank(dev); - - udelay(150); - - /* Disable display plane */ - temp = REG_READ(map->cntr); - if ((temp & DISPLAY_PLANE_ENABLE) != 0) { - REG_WRITE(map->cntr, - temp & ~DISPLAY_PLANE_ENABLE); - /* Flush the plane changes */ - REG_WRITE(map->base, REG_READ(map->base)); - REG_READ(map->base); - } - - temp = REG_READ(map->dpll); - if ((temp & DPLL_VCO_ENABLE) != 0) { - REG_WRITE(map->dpll, temp & ~DPLL_VCO_ENABLE); - REG_READ(map->dpll); - } - - /* Wait for the clocks to turn off. */ - udelay(150); - break; + dev_priv->ops->disable_sr(dev); } - cdv_intel_update_watermark(dev, crtc); - /*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); -} - -static bool cdv_intel_crtc_mode_fixup(struct drm_crtc *crtc, - const 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 */ @@ -1030,43 +576,38 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) { 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; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + int pipe = gma_crtc->pipe; const struct psb_offset *map = &dev_priv->regmap[pipe]; int refclk; - struct cdv_intel_clock_t clock; + struct gma_clock_t clock; u32 dpll = 0, dspcntr, pipeconf; bool ok; - bool is_crt = false, is_lvds = false, is_tv = false; - bool is_hdmi = false, is_dp = false; - struct drm_mode_config *mode_config = &dev->mode_config; + bool is_lvds = false; + bool is_dp = false; + struct drm_connector_list_iter conn_iter; struct drm_connector *connector; - const struct cdv_intel_limit_t *limit; + const struct gma_limit_t *limit; u32 ddi_select = 0; bool is_edp = false; - list_for_each_entry(connector, &mode_config->connector_list, head) { - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + struct gma_encoder *gma_encoder = + gma_attached_encoder(connector); if (!connector->encoder || connector->encoder->crtc != crtc) continue; - ddi_select = psb_intel_encoder->ddi_select; - switch (psb_intel_encoder->type) { + ddi_select = gma_encoder->ddi_select; + switch (gma_encoder->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_HDMI: - is_hdmi = true; break; case INTEL_OUTPUT_DISPLAYPORT: is_dp = true; @@ -1075,10 +616,14 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc, is_edp = true; break; default: + drm_connector_list_iter_end(&conn_iter); DRM_ERROR("invalid output type.\n"); return 0; } + + break; } + drm_connector_list_iter_end(&conn_iter); if (dev_priv->dplla_96mhz) /* low-end sku, 96/100 mhz */ @@ -1094,7 +639,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc, * for DP/eDP. When using SSC clock, the ref clk is 100MHz.Otherwise * it will be 27MHz. From the VBIOS code it seems that the pipe A choose * 27MHz for DP/eDP while the Pipe B chooses the 100MHz. - */ + */ if (pipe == 0) refclk = 27000; else @@ -1107,23 +652,18 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc, } drm_mode_debug_printmodeline(adjusted_mode); - - limit = cdv_intel_limit(crtc, refclk); + + limit = gma_crtc->clock_funcs->limit(crtc, refclk); ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock); if (!ok) { - dev_err(dev->dev, "Couldn't find PLL settings for mode!\n"); + DRM_ERROR("Couldn't find PLL settings for mode! target: %d, actual: %d", + adjusted_mode->clock, clock.dot); 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; */ if (is_dp || is_edp) { cdv_intel_dp_set_m_n(crtc, mode, adjusted_mode); @@ -1168,7 +708,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc, pipeconf |= PIPE_6BPC; } else pipeconf |= PIPE_8BPC; - + /* Set up the display plane register */ dspcntr = DISPPLANE_GAMMA_ENABLE; @@ -1264,355 +804,27 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc, REG_WRITE(map->conf, pipeconf); REG_READ(map->conf); - cdv_intel_wait_for_vblank(dev); + gma_wait_for_vblank(dev); REG_WRITE(map->cntr, dspcntr); /* Flush the plane changes */ { - struct drm_crtc_helper_funcs *crtc_funcs = + const 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); + gma_wait_for_vblank(dev); return 0; } - -/** - * 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 = 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; - const struct psb_offset *map = &dev_priv->regmap[psb_intel_crtc->pipe]; - uint32_t paletteReg; - int i; - - if (!crtc_state) { - dev_dbg(dev->dev, "No CRTC state found\n"); - return; - } - - crtc_state->saveDSPCNTR = REG_READ(map->cntr); - crtc_state->savePIPECONF = REG_READ(map->conf); - crtc_state->savePIPESRC = REG_READ(map->src); - crtc_state->saveFP0 = REG_READ(map->fp0); - crtc_state->saveFP1 = REG_READ(map->fp1); - crtc_state->saveDPLL = REG_READ(map->dpll); - crtc_state->saveHTOTAL = REG_READ(map->htotal); - crtc_state->saveHBLANK = REG_READ(map->hblank); - crtc_state->saveHSYNC = REG_READ(map->hsync); - crtc_state->saveVTOTAL = REG_READ(map->vtotal); - crtc_state->saveVBLANK = REG_READ(map->vblank); - crtc_state->saveVSYNC = REG_READ(map->vsync); - crtc_state->saveDSPSTRIDE = REG_READ(map->stride); - - /*NOTE: DSPSIZE DSPPOS only for psb*/ - crtc_state->saveDSPSIZE = REG_READ(map->size); - crtc_state->saveDSPPOS = REG_READ(map->pos); - - crtc_state->saveDSPBASE = REG_READ(map->base); - - 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 = map->palette; - 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 = 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; - const struct psb_offset *map = &dev_priv->regmap[psb_intel_crtc->pipe]; - 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(map->cntr), - REG_READ(map->conf), - REG_READ(map->src), - REG_READ(map->fp0), - REG_READ(map->fp1), - REG_READ(map->dpll), - REG_READ(map->htotal), - REG_READ(map->hblank), - REG_READ(map->hsync), - REG_READ(map->vtotal), - REG_READ(map->vblank), - REG_READ(map->vsync), - REG_READ(map->stride), - REG_READ(map->size), - REG_READ(map->pos), - REG_READ(map->base) - ); - - 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(map->dpll, - crtc_state->saveDPLL & ~DPLL_VCO_ENABLE); - REG_READ(map->dpll); - DRM_DEBUG("write dpll: %x\n", - REG_READ(map->dpll)); - udelay(150); - } - - REG_WRITE(map->fp0, crtc_state->saveFP0); - REG_READ(map->fp0); - - REG_WRITE(map->fp1, crtc_state->saveFP1); - REG_READ(map->fp1); - - REG_WRITE(map->dpll, crtc_state->saveDPLL); - REG_READ(map->dpll); - udelay(150); - - REG_WRITE(map->htotal, crtc_state->saveHTOTAL); - REG_WRITE(map->hblank, crtc_state->saveHBLANK); - REG_WRITE(map->hsync, crtc_state->saveHSYNC); - REG_WRITE(map->vtotal, crtc_state->saveVTOTAL); - REG_WRITE(map->vblank, crtc_state->saveVBLANK); - REG_WRITE(map->vsync, crtc_state->saveVSYNC); - REG_WRITE(map->stride, crtc_state->saveDSPSTRIDE); - - REG_WRITE(map->size, crtc_state->saveDSPSIZE); - REG_WRITE(map->pos, crtc_state->saveDSPPOS); - - REG_WRITE(map->src, crtc_state->savePIPESRC); - REG_WRITE(map->base, crtc_state->saveDSPBASE); - REG_WRITE(map->conf, crtc_state->savePIPECONF); - - cdv_intel_wait_for_vblank(dev); - - REG_WRITE(map->cntr, crtc_state->saveDSPCNTR); - REG_WRITE(map->base, crtc_state->saveDSPBASE); - - cdv_intel_wait_for_vblank(dev); - - paletteReg = map->palette; - 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 = 0; - - /* 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"); - ret = -ENOMEM; - goto unref_cursor; - } - - 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); - goto unref_cursor; - } - - 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 ret; - -unref_cursor: - drm_gem_object_unreference(obj); - return ret; -} - -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) +static void i8xx_clock(int refclk, struct gma_clock_t *clock) { clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); clock->p = clock->p1 * clock->p2; @@ -1624,13 +836,13 @@ static void i8xx_clock(int refclk, struct cdv_intel_clock_t *clock) static int cdv_intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) { - 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; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + int pipe = gma_crtc->pipe; const struct psb_offset *map = &dev_priv->regmap[pipe]; u32 dpll; u32 fp; - struct cdv_intel_clock_t clock; + struct gma_clock_t clock; bool is_lvds; struct psb_pipe *p = &dev_priv->regs.pipe[pipe]; @@ -1703,9 +915,9 @@ static int cdv_intel_crtc_clock_get(struct drm_device *dev, 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_psb_private *dev_priv = dev->dev_private; + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + int pipe = gma_crtc->pipe; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_pipe *p = &dev_priv->regs.pipe[pipe]; const struct psb_offset *map = &dev_priv->regmap[pipe]; struct drm_display_mode *mode; @@ -1747,44 +959,17 @@ struct drm_display_mode *cdv_intel_crtc_mode_get(struct drm_device *dev, 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); -} - -static void cdv_intel_crtc_disable(struct drm_crtc *crtc) -{ - struct gtt_range *gt; - struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - - crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); - - if (crtc->fb) { - gt = to_psb_fb(crtc->fb)->gtt; - psb_gtt_unpin(gt); - } -} - const struct drm_crtc_helper_funcs cdv_intel_helper_funcs = { - .dpms = cdv_intel_crtc_dpms, - .mode_fixup = cdv_intel_crtc_mode_fixup, + .dpms = gma_crtc_dpms, .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, - .disable = cdv_intel_crtc_disable, + .mode_set_base = gma_pipe_set_base, + .prepare = gma_crtc_prepare, + .commit = gma_crtc_commit, + .disable = gma_crtc_disable, }; -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, +const struct gma_clock_funcs cdv_clock_funcs = { + .clock = cdv_intel_clock, + .limit = cdv_intel_limit, + .pll_is_valid = gma_pll_is_valid, }; diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c index 88d9ef6b5b4a..54bf626f0524 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_dp.c +++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c @@ -26,15 +26,210 @@ */ #include <linux/i2c.h> -#include <linux/slab.h> #include <linux/module.h> -#include <drm/drmP.h> +#include <linux/slab.h> + +#include <drm/display/drm_dp_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_edid.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_print.h> +#include <drm/drm_simple_kms_helper.h> + +#include "gma_display.h" #include "psb_drv.h" #include "psb_intel_drv.h" #include "psb_intel_reg.h" -#include <drm/drm_dp_helper.h> + +/** + * struct i2c_algo_dp_aux_data - driver interface structure for i2c over dp + * aux algorithm + * @running: set by the algo indicating whether an i2c is ongoing or whether + * the i2c bus is quiescent + * @address: i2c target address for the currently ongoing transfer + * @aux_ch: driver callback to transfer a single byte of the i2c payload + */ +struct i2c_algo_dp_aux_data { + bool running; + u16 address; + int (*aux_ch) (struct i2c_adapter *adapter, + int mode, uint8_t write_byte, + uint8_t *read_byte); +}; + +/* Run a single AUX_CH I2C transaction, writing/reading data as necessary */ +static int +i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode, + uint8_t write_byte, uint8_t *read_byte) +{ + struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; + int ret; + + ret = (*algo_data->aux_ch)(adapter, mode, + write_byte, read_byte); + return ret; +} + +/* + * I2C over AUX CH + */ + +/* + * Send the address. If the I2C link is running, this 'restarts' + * the connection with the new address, this is used for doing + * a write followed by a read (as needed for DDC) + */ +static int +i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool reading) +{ + struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; + int mode = MODE_I2C_START; + + if (reading) + mode |= MODE_I2C_READ; + else + mode |= MODE_I2C_WRITE; + algo_data->address = address; + algo_data->running = true; + return i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL); +} + +/* + * Stop the I2C transaction. This closes out the link, sending + * a bare address packet with the MOT bit turned off + */ +static void +i2c_algo_dp_aux_stop(struct i2c_adapter *adapter, bool reading) +{ + struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; + int mode = MODE_I2C_STOP; + + if (reading) + mode |= MODE_I2C_READ; + else + mode |= MODE_I2C_WRITE; + if (algo_data->running) { + (void) i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL); + algo_data->running = false; + } +} + +/* + * Write a single byte to the current I2C address, the + * I2C link must be running or this returns -EIO + */ +static int +i2c_algo_dp_aux_put_byte(struct i2c_adapter *adapter, u8 byte) +{ + struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; + + if (!algo_data->running) + return -EIO; + + return i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, NULL); +} + +/* + * Read a single byte from the current I2C address, the + * I2C link must be running or this returns -EIO + */ +static int +i2c_algo_dp_aux_get_byte(struct i2c_adapter *adapter, u8 *byte_ret) +{ + struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; + + if (!algo_data->running) + return -EIO; + + return i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, byte_ret); +} + +static int +i2c_algo_dp_aux_xfer(struct i2c_adapter *adapter, + struct i2c_msg *msgs, + int num) +{ + int ret = 0; + bool reading = false; + int m; + int b; + + for (m = 0; m < num; m++) { + u16 len = msgs[m].len; + u8 *buf = msgs[m].buf; + reading = (msgs[m].flags & I2C_M_RD) != 0; + ret = i2c_algo_dp_aux_address(adapter, msgs[m].addr, reading); + if (ret < 0) + break; + if (reading) { + for (b = 0; b < len; b++) { + ret = i2c_algo_dp_aux_get_byte(adapter, &buf[b]); + if (ret < 0) + break; + } + } else { + for (b = 0; b < len; b++) { + ret = i2c_algo_dp_aux_put_byte(adapter, buf[b]); + if (ret < 0) + break; + } + } + if (ret < 0) + break; + } + if (ret >= 0) + ret = num; + i2c_algo_dp_aux_stop(adapter, reading); + DRM_DEBUG_KMS("dp_aux_xfer return %d\n", ret); + return ret; +} + +static u32 +i2c_algo_dp_aux_functionality(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | + I2C_FUNC_SMBUS_READ_BLOCK_DATA | + I2C_FUNC_SMBUS_BLOCK_PROC_CALL | + I2C_FUNC_10BIT_ADDR; +} + +static const struct i2c_algorithm i2c_dp_aux_algo = { + .master_xfer = i2c_algo_dp_aux_xfer, + .functionality = i2c_algo_dp_aux_functionality, +}; + +static void +i2c_dp_aux_reset_bus(struct i2c_adapter *adapter) +{ + (void) i2c_algo_dp_aux_address(adapter, 0, false); + (void) i2c_algo_dp_aux_stop(adapter, false); +} + +static int +i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter) +{ + adapter->algo = &i2c_dp_aux_algo; + adapter->retries = 3; + i2c_dp_aux_reset_bus(adapter); + return 0; +} + +/* + * FIXME: This is the old dp aux helper, gma500 is the last driver that needs to + * be ported over to the new helper code in drm_dp_helper.c like i915 or radeon. + */ +static int +i2c_dp_aux_add_bus(struct i2c_adapter *adapter) +{ + int error; + + error = i2c_dp_aux_prepare_bus(adapter); + if (error) + return error; + error = i2c_add_adapter(adapter); + return error; +} #define _wait_for(COND, MS, W) ({ \ unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \ @@ -47,11 +242,10 @@ if (W && !in_dbg_master()) msleep(W); \ } \ ret__; \ -}) +}) #define wait_for(COND, MS) _wait_for(COND, MS, 1) -#define DP_LINK_STATUS_SIZE 6 #define DP_LINK_CHECK_TIMEOUT (10 * 1000) #define DP_LINK_CONFIGURATION_SIZE 9 @@ -68,7 +262,7 @@ struct cdv_intel_dp { uint8_t link_bw; uint8_t lane_count; uint8_t dpcd[4]; - struct psb_intel_encoder *encoder; + struct gma_encoder *encoder; struct i2c_adapter adapter; struct i2c_algo_dp_aux_data algo; uint8_t train_set[4]; @@ -109,23 +303,23 @@ static uint32_t dp_vswing_premph_table[] = { }; /** * is_edp - is the given port attached to an eDP panel (either CPU or PCH) - * @intel_dp: DP struct + * @encoder: GMA encoder struct * * If a CPU or PCH DP output is attached to an eDP panel, this function * will return true, and false otherwise. */ -static bool is_edp(struct psb_intel_encoder *encoder) +static bool is_edp(struct gma_encoder *encoder) { return encoder->type == INTEL_OUTPUT_EDP; } -static void cdv_intel_dp_start_link_train(struct psb_intel_encoder *encoder); -static void cdv_intel_dp_complete_link_train(struct psb_intel_encoder *encoder); -static void cdv_intel_dp_link_down(struct psb_intel_encoder *encoder); +static void cdv_intel_dp_start_link_train(struct gma_encoder *encoder); +static void cdv_intel_dp_complete_link_train(struct gma_encoder *encoder); +static void cdv_intel_dp_link_down(struct gma_encoder *encoder); static int -cdv_intel_dp_max_lane_count(struct psb_intel_encoder *encoder) +cdv_intel_dp_max_lane_count(struct gma_encoder *encoder) { struct cdv_intel_dp *intel_dp = encoder->dev_priv; int max_lane_count = 4; @@ -143,7 +337,7 @@ cdv_intel_dp_max_lane_count(struct psb_intel_encoder *encoder) } static int -cdv_intel_dp_max_link_bw(struct psb_intel_encoder *encoder) +cdv_intel_dp_max_link_bw(struct gma_encoder *encoder) { struct cdv_intel_dp *intel_dp = encoder->dev_priv; int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE]; @@ -180,7 +374,7 @@ cdv_intel_dp_max_data_rate(int max_link_clock, int max_lanes) return (max_link_clock * max_lanes * 19) / 20; } -static void cdv_intel_edp_panel_vdd_on(struct psb_intel_encoder *intel_encoder) +static void cdv_intel_edp_panel_vdd_on(struct gma_encoder *intel_encoder) { struct drm_device *dev = intel_encoder->base.dev; struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv; @@ -189,7 +383,7 @@ static void cdv_intel_edp_panel_vdd_on(struct psb_intel_encoder *intel_encoder) if (intel_dp->panel_on) { DRM_DEBUG_KMS("Skip VDD on because of panel on\n"); return; - } + } DRM_DEBUG_KMS("\n"); pp = REG_READ(PP_CONTROL); @@ -200,7 +394,7 @@ static void cdv_intel_edp_panel_vdd_on(struct psb_intel_encoder *intel_encoder) msleep(intel_dp->panel_power_up_delay); } -static void cdv_intel_edp_panel_vdd_off(struct psb_intel_encoder *intel_encoder) +static void cdv_intel_edp_panel_vdd_off(struct gma_encoder *intel_encoder) { struct drm_device *dev = intel_encoder->base.dev; u32 pp; @@ -215,7 +409,7 @@ static void cdv_intel_edp_panel_vdd_off(struct psb_intel_encoder *intel_encoder) } /* Returns true if the panel was already on when called */ -static bool cdv_intel_edp_panel_on(struct psb_intel_encoder *intel_encoder) +static bool cdv_intel_edp_panel_on(struct gma_encoder *intel_encoder) { struct drm_device *dev = intel_encoder->base.dev; struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv; @@ -236,13 +430,13 @@ static bool cdv_intel_edp_panel_on(struct psb_intel_encoder *intel_encoder) DRM_DEBUG_KMS("Error in Powering up eDP panel, status %x\n", REG_READ(PP_STATUS)); intel_dp->panel_on = false; } else - intel_dp->panel_on = true; + intel_dp->panel_on = true; msleep(intel_dp->panel_power_up_delay); return false; } -static void cdv_intel_edp_panel_off (struct psb_intel_encoder *intel_encoder) +static void cdv_intel_edp_panel_off (struct gma_encoder *intel_encoder) { struct drm_device *dev = intel_encoder->base.dev; u32 pp, idle_off_mask = PP_ON ; @@ -252,7 +446,7 @@ static void cdv_intel_edp_panel_off (struct psb_intel_encoder *intel_encoder) pp = REG_READ(PP_CONTROL); - if ((pp & POWER_TARGET_ON) == 0) + if ((pp & POWER_TARGET_ON) == 0) return; intel_dp->panel_on = false; @@ -267,14 +461,14 @@ static void cdv_intel_edp_panel_off (struct psb_intel_encoder *intel_encoder) DRM_DEBUG_KMS("PP_STATUS %x\n", REG_READ(PP_STATUS)); if (wait_for((REG_READ(PP_STATUS) & idle_off_mask) == 0, 1000)) { - DRM_DEBUG_KMS("Error in turning off Panel\n"); + DRM_DEBUG_KMS("Error in turning off Panel\n"); } msleep(intel_dp->panel_power_cycle_delay); DRM_DEBUG_KMS("Over\n"); } -static void cdv_intel_edp_backlight_on (struct psb_intel_encoder *intel_encoder) +static void cdv_intel_edp_backlight_on (struct gma_encoder *intel_encoder) { struct drm_device *dev = intel_encoder->base.dev; u32 pp; @@ -294,7 +488,7 @@ static void cdv_intel_edp_backlight_on (struct psb_intel_encoder *intel_encoder) gma_backlight_enable(dev); } -static void cdv_intel_edp_backlight_off (struct psb_intel_encoder *intel_encoder) +static void cdv_intel_edp_backlight_off (struct gma_encoder *intel_encoder) { struct drm_device *dev = intel_encoder->base.dev; struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv; @@ -310,15 +504,15 @@ static void cdv_intel_edp_backlight_off (struct psb_intel_encoder *intel_encoder msleep(intel_dp->backlight_off_delay); } -static int +static enum drm_mode_status cdv_intel_dp_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { - struct psb_intel_encoder *encoder = psb_intel_attached_encoder(connector); + struct gma_encoder *encoder = gma_attached_encoder(connector); struct cdv_intel_dp *intel_dp = encoder->dev_priv; int max_link_clock = cdv_intel_dp_link_clock(cdv_intel_dp_max_link_bw(encoder)); int max_lanes = cdv_intel_dp_max_lane_count(encoder); - struct drm_psb_private *dev_priv = connector->dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(connector->dev); if (is_edp(encoder) && intel_dp->panel_fixed_mode) { if (mode->hdisplay > intel_dp->panel_fixed_mode->hdisplay) @@ -338,7 +532,7 @@ cdv_intel_dp_mode_valid(struct drm_connector *connector, if (cdv_intel_dp_link_required(mode->clock, 24) > cdv_intel_dp_max_data_rate(max_link_clock, max_lanes)) return MODE_CLOCK_HIGH; - + } if (mode->clock < 10000) return MODE_CLOCK_LOW; @@ -370,7 +564,7 @@ unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes) } static int -cdv_intel_dp_aux_ch(struct psb_intel_encoder *encoder, +cdv_intel_dp_aux_ch(struct gma_encoder *encoder, uint8_t *send, int send_bytes, uint8_t *recv, int recv_size) { @@ -409,7 +603,7 @@ cdv_intel_dp_aux_ch(struct psb_intel_encoder *encoder, for (i = 0; i < send_bytes; i += 4) REG_WRITE(ch_data + i, pack_aux(send + i, send_bytes - i)); - + /* Send the command and wait for it to complete */ REG_WRITE(ch_ctl, DP_AUX_CH_CTL_SEND_BUSY | @@ -426,7 +620,7 @@ cdv_intel_dp_aux_ch(struct psb_intel_encoder *encoder, break; udelay(100); } - + /* Clear done status and any errors */ REG_WRITE(ch_ctl, status | @@ -462,7 +656,7 @@ cdv_intel_dp_aux_ch(struct psb_intel_encoder *encoder, DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT); if (recv_bytes > recv_size) recv_bytes = recv_size; - + for (i = 0; i < recv_bytes; i += 4) unpack_aux(REG_READ(ch_data + i), recv + i, recv_bytes - i); @@ -472,7 +666,7 @@ cdv_intel_dp_aux_ch(struct psb_intel_encoder *encoder, /* Write data to the aux channel in native mode */ static int -cdv_intel_dp_aux_native_write(struct psb_intel_encoder *encoder, +cdv_intel_dp_aux_native_write(struct gma_encoder *encoder, uint16_t address, uint8_t *send, int send_bytes) { int ret; @@ -482,7 +676,7 @@ cdv_intel_dp_aux_native_write(struct psb_intel_encoder *encoder, if (send_bytes > 16) return -1; - msg[0] = AUX_NATIVE_WRITE << 4; + msg[0] = DP_AUX_NATIVE_WRITE << 4; msg[1] = address >> 8; msg[2] = address & 0xff; msg[3] = send_bytes - 1; @@ -492,9 +686,10 @@ cdv_intel_dp_aux_native_write(struct psb_intel_encoder *encoder, ret = cdv_intel_dp_aux_ch(encoder, msg, msg_bytes, &ack, 1); if (ret < 0) return ret; - if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) + ack >>= 4; + if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK) break; - else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER) + else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER) udelay(100); else return -EIO; @@ -504,7 +699,7 @@ cdv_intel_dp_aux_native_write(struct psb_intel_encoder *encoder, /* Write a single byte to the aux channel in native mode */ static int -cdv_intel_dp_aux_native_write_1(struct psb_intel_encoder *encoder, +cdv_intel_dp_aux_native_write_1(struct gma_encoder *encoder, uint16_t address, uint8_t byte) { return cdv_intel_dp_aux_native_write(encoder, address, &byte, 1); @@ -512,7 +707,7 @@ cdv_intel_dp_aux_native_write_1(struct psb_intel_encoder *encoder, /* read bytes from a native aux channel */ static int -cdv_intel_dp_aux_native_read(struct psb_intel_encoder *encoder, +cdv_intel_dp_aux_native_read(struct gma_encoder *encoder, uint16_t address, uint8_t *recv, int recv_bytes) { uint8_t msg[4]; @@ -522,7 +717,7 @@ cdv_intel_dp_aux_native_read(struct psb_intel_encoder *encoder, uint8_t ack; int ret; - msg[0] = AUX_NATIVE_READ << 4; + msg[0] = DP_AUX_NATIVE_READ << 4; msg[1] = address >> 8; msg[2] = address & 0xff; msg[3] = recv_bytes - 1; @@ -537,12 +732,12 @@ cdv_intel_dp_aux_native_read(struct psb_intel_encoder *encoder, return -EPROTO; if (ret < 0) return ret; - ack = reply[0]; - if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) { + ack = reply[0] >> 4; + if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK) { memcpy(recv, reply + 1, ret - 1); return ret - 1; } - else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER) + else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER) udelay(100); else return -EIO; @@ -557,7 +752,7 @@ cdv_intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, struct cdv_intel_dp *intel_dp = container_of(adapter, struct cdv_intel_dp, adapter); - struct psb_intel_encoder *encoder = intel_dp->encoder; + struct gma_encoder *encoder = intel_dp->encoder; uint16_t address = algo_data->address; uint8_t msg[5]; uint8_t reply[2]; @@ -568,12 +763,12 @@ cdv_intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, /* Set up the command byte */ if (mode & MODE_I2C_READ) - msg[0] = AUX_I2C_READ << 4; + msg[0] = DP_AUX_I2C_READ << 4; else - msg[0] = AUX_I2C_WRITE << 4; + msg[0] = DP_AUX_I2C_WRITE << 4; if (!(mode & MODE_I2C_STOP)) - msg[0] |= AUX_I2C_MOT << 4; + msg[0] |= DP_AUX_I2C_MOT << 4; msg[1] = address >> 8; msg[2] = address; @@ -605,16 +800,16 @@ cdv_intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, return ret; } - switch (reply[0] & AUX_NATIVE_REPLY_MASK) { - case AUX_NATIVE_REPLY_ACK: + switch ((reply[0] >> 4) & DP_AUX_NATIVE_REPLY_MASK) { + case DP_AUX_NATIVE_REPLY_ACK: /* I2C-over-AUX Reply field is only valid * when paired with AUX ACK. */ break; - case AUX_NATIVE_REPLY_NACK: + case DP_AUX_NATIVE_REPLY_NACK: DRM_DEBUG_KMS("aux_ch native nack\n"); return -EREMOTEIO; - case AUX_NATIVE_REPLY_DEFER: + case DP_AUX_NATIVE_REPLY_DEFER: udelay(100); continue; default: @@ -623,16 +818,16 @@ cdv_intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, return -EREMOTEIO; } - switch (reply[0] & AUX_I2C_REPLY_MASK) { - case AUX_I2C_REPLY_ACK: + switch ((reply[0] >> 4) & DP_AUX_I2C_REPLY_MASK) { + case DP_AUX_I2C_REPLY_ACK: if (mode == MODE_I2C_READ) { *read_byte = reply[1]; } return reply_bytes - 1; - case AUX_I2C_REPLY_NACK: + case DP_AUX_I2C_REPLY_NACK: DRM_DEBUG_KMS("aux_i2c nack\n"); return -EREMOTEIO; - case AUX_I2C_REPLY_DEFER: + case DP_AUX_I2C_REPLY_DEFER: DRM_DEBUG_KMS("aux_i2c defer\n"); udelay(100); break; @@ -647,7 +842,8 @@ cdv_intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, } static int -cdv_intel_dp_i2c_init(struct psb_intel_connector *connector, struct psb_intel_encoder *encoder, const char *name) +cdv_intel_dp_i2c_init(struct gma_connector *connector, + struct gma_encoder *encoder, const char *name) { struct cdv_intel_dp *intel_dp = encoder->dev_priv; int ret; @@ -660,22 +856,20 @@ cdv_intel_dp_i2c_init(struct psb_intel_connector *connector, struct psb_intel_en memset(&intel_dp->adapter, '\0', sizeof (intel_dp->adapter)); intel_dp->adapter.owner = THIS_MODULE; - intel_dp->adapter.class = I2C_CLASS_DDC; - strncpy (intel_dp->adapter.name, name, sizeof(intel_dp->adapter.name) - 1); - intel_dp->adapter.name[sizeof(intel_dp->adapter.name) - 1] = '\0'; + strscpy(intel_dp->adapter.name, name); intel_dp->adapter.algo_data = &intel_dp->algo; - intel_dp->adapter.dev.parent = &connector->base.kdev; + intel_dp->adapter.dev.parent = connector->base.kdev; if (is_edp(encoder)) cdv_intel_edp_panel_vdd_on(encoder); ret = i2c_dp_aux_add_bus(&intel_dp->adapter); if (is_edp(encoder)) cdv_intel_edp_panel_vdd_off(encoder); - + return ret; } -void cdv_intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, +static void cdv_intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, struct drm_display_mode *adjusted_mode) { adjusted_mode->hdisplay = fixed_mode->hdisplay; @@ -697,8 +891,8 @@ static bool cdv_intel_dp_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_psb_private *dev_priv = encoder->dev->dev_private; - struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder); + struct drm_psb_private *dev_priv = to_drm_psb_private(encoder->dev); + struct gma_encoder *intel_encoder = to_gma_encoder(encoder); struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv; int lane_count, clock; int max_lane_count = cdv_intel_dp_max_lane_count(intel_encoder); @@ -789,25 +983,25 @@ cdv_intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = crtc->dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct drm_mode_config *mode_config = &dev->mode_config; struct drm_encoder *encoder; - struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc); + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); int lane_count = 4, bpp = 24; struct cdv_intel_dp_m_n m_n; - int pipe = intel_crtc->pipe; + int pipe = gma_crtc->pipe; /* * Find the lane count in the intel_encoder private */ list_for_each_entry(encoder, &mode_config->encoder_list, head) { - struct psb_intel_encoder *intel_encoder; + struct gma_encoder *intel_encoder; struct cdv_intel_dp *intel_dp; if (encoder->crtc != crtc) continue; - intel_encoder = to_psb_intel_encoder(encoder); + intel_encoder = to_gma_encoder(encoder); intel_dp = intel_encoder->dev_priv; if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) { lane_count = intel_dp->lane_count; @@ -841,9 +1035,9 @@ static void cdv_intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder); + struct gma_encoder *intel_encoder = to_gma_encoder(encoder); struct drm_crtc *crtc = encoder->crtc; - struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc); + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv; struct drm_device *dev = encoder->dev; @@ -885,7 +1079,7 @@ cdv_intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode } /* CPT DP's pipe select is decided in TRANS_DP_CTL */ - if (intel_crtc->pipe == 1) + if (gma_crtc->pipe == 1) intel_dp->DP |= DP_PIPEB_SELECT; REG_WRITE(intel_dp->output_reg, (intel_dp->DP | DP_PORT_EN)); @@ -900,7 +1094,7 @@ cdv_intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode else pfit_control = 0; - pfit_control |= intel_crtc->pipe << PFIT_PIPE_SHIFT; + pfit_control |= gma_crtc->pipe << PFIT_PIPE_SHIFT; REG_WRITE(PFIT_CONTROL, pfit_control); } @@ -908,7 +1102,7 @@ cdv_intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode /* If the sink supports it, try to set the power state appropriately */ -static void cdv_intel_dp_sink_dpms(struct psb_intel_encoder *encoder, int mode) +static void cdv_intel_dp_sink_dpms(struct gma_encoder *encoder, int mode) { struct cdv_intel_dp *intel_dp = encoder->dev_priv; int ret, i; @@ -940,7 +1134,7 @@ static void cdv_intel_dp_sink_dpms(struct psb_intel_encoder *encoder, int mode) static void cdv_intel_dp_prepare(struct drm_encoder *encoder) { - struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder); + struct gma_encoder *intel_encoder = to_gma_encoder(encoder); int edp = is_edp(intel_encoder); if (edp) { @@ -957,7 +1151,7 @@ static void cdv_intel_dp_prepare(struct drm_encoder *encoder) static void cdv_intel_dp_commit(struct drm_encoder *encoder) { - struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder); + struct gma_encoder *intel_encoder = to_gma_encoder(encoder); int edp = is_edp(intel_encoder); if (edp) @@ -971,7 +1165,7 @@ static void cdv_intel_dp_commit(struct drm_encoder *encoder) static void cdv_intel_dp_dpms(struct drm_encoder *encoder, int mode) { - struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder); + struct gma_encoder *intel_encoder = to_gma_encoder(encoder); struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv; struct drm_device *dev = encoder->dev; uint32_t dp_reg = REG_READ(intel_dp->output_reg); @@ -1006,7 +1200,7 @@ cdv_intel_dp_dpms(struct drm_encoder *encoder, int mode) * cases where the sink may still be asleep. */ static bool -cdv_intel_dp_aux_native_read_retry(struct psb_intel_encoder *encoder, uint16_t address, +cdv_intel_dp_aux_native_read_retry(struct gma_encoder *encoder, uint16_t address, uint8_t *recv, int recv_bytes) { int ret, i; @@ -1031,7 +1225,7 @@ cdv_intel_dp_aux_native_read_retry(struct psb_intel_encoder *encoder, uint16_t a * link status information */ static bool -cdv_intel_dp_get_link_status(struct psb_intel_encoder *encoder) +cdv_intel_dp_get_link_status(struct gma_encoder *encoder) { struct cdv_intel_dp *intel_dp = encoder->dev_priv; return cdv_intel_dp_aux_native_read_retry(encoder, @@ -1073,39 +1267,10 @@ cdv_intel_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZ return ((l >> s) & 3) << DP_TRAIN_PRE_EMPHASIS_SHIFT; } +#define CDV_DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_LEVEL_3 -#if 0 -static char *voltage_names[] = { - "0.4V", "0.6V", "0.8V", "1.2V" -}; -static char *pre_emph_names[] = { - "0dB", "3.5dB", "6dB", "9.5dB" -}; -static char *link_train_names[] = { - "pattern 1", "pattern 2", "idle", "off" -}; -#endif - -#define CDV_DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_1200 -/* -static uint8_t -cdv_intel_dp_pre_emphasis_max(uint8_t voltage_swing) -{ - switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { - case DP_TRAIN_VOLTAGE_SWING_400: - return DP_TRAIN_PRE_EMPHASIS_6; - case DP_TRAIN_VOLTAGE_SWING_600: - return DP_TRAIN_PRE_EMPHASIS_6; - case DP_TRAIN_VOLTAGE_SWING_800: - return DP_TRAIN_PRE_EMPHASIS_3_5; - case DP_TRAIN_VOLTAGE_SWING_1200: - default: - return DP_TRAIN_PRE_EMPHASIS_0; - } -} -*/ static void -cdv_intel_get_adjust_train(struct psb_intel_encoder *encoder) +cdv_intel_get_adjust_train(struct gma_encoder *encoder) { struct cdv_intel_dp *intel_dp = encoder->dev_priv; uint8_t v = 0; @@ -1121,13 +1286,13 @@ cdv_intel_get_adjust_train(struct psb_intel_encoder *encoder) if (this_p > p) p = this_p; } - + if (v >= CDV_DP_VOLTAGE_MAX) v = CDV_DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED; if (p == DP_TRAIN_PRE_EMPHASIS_MASK) p |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; - + for (lane = 0; lane < 4; lane++) intel_dp->train_set[lane] = v | p; } @@ -1164,7 +1329,7 @@ cdv_intel_clock_recovery_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_c DP_LANE_CHANNEL_EQ_DONE|\ DP_LANE_SYMBOL_LOCKED) static bool -cdv_intel_channel_eq_ok(struct psb_intel_encoder *encoder) +cdv_intel_channel_eq_ok(struct gma_encoder *encoder) { struct cdv_intel_dp *intel_dp = encoder->dev_priv; uint8_t lane_align; @@ -1184,11 +1349,10 @@ cdv_intel_channel_eq_ok(struct psb_intel_encoder *encoder) } static bool -cdv_intel_dp_set_link_train(struct psb_intel_encoder *encoder, +cdv_intel_dp_set_link_train(struct gma_encoder *encoder, uint32_t dp_reg_value, uint8_t dp_train_pat) { - struct drm_device *dev = encoder->base.dev; int ret; struct cdv_intel_dp *intel_dp = encoder->dev_priv; @@ -1211,10 +1375,9 @@ cdv_intel_dp_set_link_train(struct psb_intel_encoder *encoder, static bool -cdv_intel_dplink_set_level(struct psb_intel_encoder *encoder, +cdv_intel_dplink_set_level(struct gma_encoder *encoder, uint8_t dp_train_pat) { - int ret; struct cdv_intel_dp *intel_dp = encoder->dev_priv; @@ -1232,7 +1395,7 @@ cdv_intel_dplink_set_level(struct psb_intel_encoder *encoder, } static void -cdv_intel_dp_set_vswing_premph(struct psb_intel_encoder *encoder, uint8_t signal_level) +cdv_intel_dp_set_vswing_premph(struct gma_encoder *encoder, uint8_t signal_level) { struct drm_device *dev = encoder->base.dev; struct cdv_intel_dp *intel_dp = encoder->dev_priv; @@ -1273,7 +1436,7 @@ cdv_intel_dp_set_vswing_premph(struct psb_intel_encoder *encoder, uint8_t signal cdv_sb_write(dev, ddi_reg->VSwing2, dp_vswing_premph_table[index]); /* ;gfx_dpio_set_reg(0x814c, 0x40802040) */ - if ((vswing + premph) == DP_TRAIN_VOLTAGE_SWING_1200) + if ((vswing + premph) == DP_TRAIN_VOLTAGE_SWING_LEVEL_3) cdv_sb_write(dev, ddi_reg->VSwing3, 0x70802040); else cdv_sb_write(dev, ddi_reg->VSwing3, 0x40802040); @@ -1292,13 +1455,13 @@ cdv_intel_dp_set_vswing_premph(struct psb_intel_encoder *encoder, uint8_t signal /* ;gfx_dpio_set_reg(0x8124, 0x00004000) */ index = 2 * premph + 1; cdv_sb_write(dev, ddi_reg->PreEmph2, dp_vswing_premph_table[index]); - return; + return; } /* Enable corresponding port and start training pattern 1 */ static void -cdv_intel_dp_start_link_train(struct psb_intel_encoder *encoder) +cdv_intel_dp_start_link_train(struct gma_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct cdv_intel_dp *intel_dp = encoder->dev_priv; @@ -1311,13 +1474,13 @@ cdv_intel_dp_start_link_train(struct psb_intel_encoder *encoder) DP |= DP_PORT_EN; DP &= ~DP_LINK_TRAIN_MASK; - - reg = DP; + + reg = DP; reg |= DP_LINK_TRAIN_PAT_1; /* Enable output, wait for it to become active */ REG_WRITE(intel_dp->output_reg, reg); REG_READ(intel_dp->output_reg); - psb_intel_wait_for_vblank(dev); + gma_wait_for_vblank(dev); DRM_DEBUG_KMS("Link config\n"); /* Write the link configuration data */ @@ -1331,8 +1494,7 @@ cdv_intel_dp_start_link_train(struct psb_intel_encoder *encoder) clock_recovery = false; DRM_DEBUG_KMS("Start train\n"); - reg = DP | DP_LINK_TRAIN_PAT_1; - + reg = DP | DP_LINK_TRAIN_PAT_1; for (;;) { /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */ @@ -1385,18 +1547,17 @@ cdv_intel_dp_start_link_train(struct psb_intel_encoder *encoder) } if (!clock_recovery) { - DRM_DEBUG_KMS("failure in DP patter 1 training, train set %x\n", intel_dp->train_set[0]); + DRM_DEBUG_KMS("failure in DP pattern 1 training, train set %x\n", intel_dp->train_set[0]); } - + intel_dp->DP = DP; } static void -cdv_intel_dp_complete_link_train(struct psb_intel_encoder *encoder) +cdv_intel_dp_complete_link_train(struct gma_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct cdv_intel_dp *intel_dp = encoder->dev_priv; - bool channel_eq = false; int tries, cr_tries; u32 reg; uint32_t DP = intel_dp->DP; @@ -1404,10 +1565,9 @@ cdv_intel_dp_complete_link_train(struct psb_intel_encoder *encoder) /* channel equalization */ tries = 0; cr_tries = 0; - channel_eq = false; DRM_DEBUG_KMS("\n"); - reg = DP | DP_LINK_TRAIN_PAT_2; + reg = DP | DP_LINK_TRAIN_PAT_2; for (;;) { @@ -1450,7 +1610,6 @@ cdv_intel_dp_complete_link_train(struct psb_intel_encoder *encoder) if (cdv_intel_channel_eq_ok(encoder)) { DRM_DEBUG_KMS("PT2 train is done\n"); - channel_eq = true; break; } @@ -1478,7 +1637,7 @@ cdv_intel_dp_complete_link_train(struct psb_intel_encoder *encoder) } static void -cdv_intel_dp_link_down(struct psb_intel_encoder *encoder) +cdv_intel_dp_link_down(struct gma_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct cdv_intel_dp *intel_dp = encoder->dev_priv; @@ -1502,8 +1661,7 @@ cdv_intel_dp_link_down(struct psb_intel_encoder *encoder) REG_READ(intel_dp->output_reg); } -static enum drm_connector_status -cdv_dp_detect(struct psb_intel_encoder *encoder) +static enum drm_connector_status cdv_dp_detect(struct gma_encoder *encoder) { struct cdv_intel_dp *intel_dp = encoder->dev_priv; enum drm_connector_status status; @@ -1522,7 +1680,7 @@ cdv_dp_detect(struct psb_intel_encoder *encoder) return status; } -/** +/* * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection. * * \return true if DP port is connected. @@ -1531,7 +1689,7 @@ cdv_dp_detect(struct psb_intel_encoder *encoder) static enum drm_connector_status cdv_intel_dp_detect(struct drm_connector *connector, bool force) { - struct psb_intel_encoder *encoder = psb_intel_attached_encoder(connector); + struct gma_encoder *encoder = gma_attached_encoder(connector); struct cdv_intel_dp *intel_dp = encoder->dev_priv; enum drm_connector_status status; struct edid *edid = NULL; @@ -1565,7 +1723,7 @@ cdv_intel_dp_detect(struct drm_connector *connector, bool force) static int cdv_intel_dp_get_modes(struct drm_connector *connector) { - struct psb_intel_encoder *intel_encoder = psb_intel_attached_encoder(connector); + struct gma_encoder *intel_encoder = gma_attached_encoder(connector); struct cdv_intel_dp *intel_dp = intel_encoder->dev_priv; struct edid *edid = NULL; int ret = 0; @@ -1574,15 +1732,15 @@ static int cdv_intel_dp_get_modes(struct drm_connector *connector) edid = drm_get_edid(connector, &intel_dp->adapter); if (edid) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); } if (is_edp(intel_encoder)) { struct drm_device *dev = connector->dev; - struct drm_psb_private *dev_priv = dev->dev_private; - + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + cdv_intel_edp_panel_vdd_off(intel_encoder); if (ret) { if (edp && !intel_dp->panel_fixed_mode) { @@ -1621,7 +1779,7 @@ static int cdv_intel_dp_get_modes(struct drm_connector *connector) static bool cdv_intel_dp_detect_audio(struct drm_connector *connector) { - struct psb_intel_encoder *encoder = psb_intel_attached_encoder(connector); + struct gma_encoder *encoder = gma_attached_encoder(connector); struct cdv_intel_dp *intel_dp = encoder->dev_priv; struct edid *edid; bool has_audio = false; @@ -1646,8 +1804,8 @@ cdv_intel_dp_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t val) { - struct drm_psb_private *dev_priv = connector->dev->dev_private; - struct psb_intel_encoder *encoder = psb_intel_attached_encoder(connector); + struct drm_psb_private *dev_priv = to_drm_psb_private(connector->dev); + struct gma_encoder *encoder = gma_attached_encoder(connector); struct cdv_intel_dp *intel_dp = encoder->dev_priv; int ret; @@ -1691,7 +1849,7 @@ done: struct drm_crtc *crtc = encoder->base.crtc; drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, - crtc->fb); + crtc->primary->fb); } return 0; @@ -1700,26 +1858,18 @@ done: static void cdv_intel_dp_destroy(struct drm_connector *connector) { - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); - struct cdv_intel_dp *intel_dp = psb_intel_encoder->dev_priv; + struct gma_connector *gma_connector = to_gma_connector(connector); + struct gma_encoder *gma_encoder = gma_attached_encoder(connector); + struct cdv_intel_dp *intel_dp = gma_encoder->dev_priv; - if (is_edp(psb_intel_encoder)) { + if (is_edp(gma_encoder)) { /* cdv_intel_panel_destroy_backlight(connector->dev); */ - if (intel_dp->panel_fixed_mode) { - kfree(intel_dp->panel_fixed_mode); - intel_dp->panel_fixed_mode = NULL; - } + kfree(intel_dp->panel_fixed_mode); + intel_dp->panel_fixed_mode = NULL; } i2c_del_adapter(&intel_dp->adapter); - drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); - kfree(connector); -} - -static void cdv_intel_dp_encoder_destroy(struct drm_encoder *encoder) -{ - drm_encoder_cleanup(encoder); + kfree(gma_connector); } static const struct drm_encoder_helper_funcs cdv_intel_dp_helper_funcs = { @@ -1741,14 +1891,9 @@ static const struct drm_connector_funcs cdv_intel_dp_connector_funcs = { static const struct drm_connector_helper_funcs cdv_intel_dp_connector_helper_funcs = { .get_modes = cdv_intel_dp_get_modes, .mode_valid = cdv_intel_dp_mode_valid, - .best_encoder = psb_intel_best_encoder, + .best_encoder = gma_best_encoder, }; -static const struct drm_encoder_funcs cdv_intel_dp_enc_funcs = { - .destroy = cdv_intel_dp_encoder_destroy, -}; - - static void cdv_intel_dp_add_properties(struct drm_connector *connector) { cdv_intel_attach_force_audio_property(connector); @@ -1758,7 +1903,7 @@ static void cdv_intel_dp_add_properties(struct drm_connector *connector) /* check the VBT to see whether the eDP is on DP-D port */ static bool cdv_intel_dpc_is_edp(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct child_device_config *p_child; int i; @@ -1790,29 +1935,29 @@ static void cdv_disable_intel_clock_gating(struct drm_device *dev) DPCUNIT_CLOCK_GATE_DISABLE | DPLSUNIT_CLOCK_GATE_DISABLE | DPOUNIT_CLOCK_GATE_DISABLE | - DPIOUNIT_CLOCK_GATE_DISABLE); + DPIOUNIT_CLOCK_GATE_DISABLE); REG_WRITE(DSPCLK_GATE_D, reg_value); - udelay(500); + udelay(500); } void cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev, int output_reg) { - struct psb_intel_encoder *psb_intel_encoder; - struct psb_intel_connector *psb_intel_connector; + struct gma_encoder *gma_encoder; + struct gma_connector *gma_connector; struct drm_connector *connector; struct drm_encoder *encoder; struct cdv_intel_dp *intel_dp; const char *name = NULL; int type = DRM_MODE_CONNECTOR_DisplayPort; - psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder), GFP_KERNEL); - if (!psb_intel_encoder) + gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL); + if (!gma_encoder) return; - psb_intel_connector = kzalloc(sizeof(struct psb_intel_connector), GFP_KERNEL); - if (!psb_intel_connector) + gma_connector = kzalloc(sizeof(struct gma_connector), GFP_KERNEL); + if (!gma_connector) goto err_connector; intel_dp = kzalloc(sizeof(struct cdv_intel_dp), GFP_KERNEL); if (!intel_dp) @@ -1821,24 +1966,24 @@ cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev if ((output_reg == DP_C) && cdv_intel_dpc_is_edp(dev)) type = DRM_MODE_CONNECTOR_eDP; - connector = &psb_intel_connector->base; - encoder = &psb_intel_encoder->base; + connector = &gma_connector->base; + encoder = &gma_encoder->base; drm_connector_init(dev, connector, &cdv_intel_dp_connector_funcs, type); - drm_encoder_init(dev, encoder, &cdv_intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS); + drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_TMDS); - psb_intel_connector_attach_encoder(psb_intel_connector, psb_intel_encoder); + gma_connector_attach_encoder(gma_connector, gma_encoder); if (type == DRM_MODE_CONNECTOR_DisplayPort) - psb_intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT; + gma_encoder->type = INTEL_OUTPUT_DISPLAYPORT; else - psb_intel_encoder->type = INTEL_OUTPUT_EDP; + gma_encoder->type = INTEL_OUTPUT_EDP; - psb_intel_encoder->dev_priv=intel_dp; - intel_dp->encoder = psb_intel_encoder; + gma_encoder->dev_priv=intel_dp; + intel_dp->encoder = gma_encoder; intel_dp->output_reg = output_reg; - + drm_encoder_helper_add(encoder, &cdv_intel_dp_helper_funcs); drm_connector_helper_add(connector, &cdv_intel_dp_connector_helper_funcs); @@ -1846,27 +1991,25 @@ cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev connector->interlace_allowed = false; connector->doublescan_allowed = false; - drm_sysfs_connector_add(connector); - /* Set up the DDC bus. */ switch (output_reg) { case DP_B: name = "DPDDC-B"; - psb_intel_encoder->ddi_select = (DP_MASK | DDI0_SELECT); + gma_encoder->ddi_select = (DP_MASK | DDI0_SELECT); break; case DP_C: name = "DPDDC-C"; - psb_intel_encoder->ddi_select = (DP_MASK | DDI1_SELECT); + gma_encoder->ddi_select = (DP_MASK | DDI1_SELECT); break; } cdv_disable_intel_clock_gating(dev); - cdv_intel_dp_i2c_init(psb_intel_connector, psb_intel_encoder, name); + cdv_intel_dp_i2c_init(gma_connector, gma_encoder, name); /* FIXME:fail check */ cdv_intel_dp_add_properties(connector); - if (is_edp(psb_intel_encoder)) { + if (is_edp(gma_encoder)) { int ret; struct edp_power_seq cur; u32 pp_on, pp_off, pp_div; @@ -1875,7 +2018,7 @@ cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev pp_on = REG_READ(PP_CONTROL); pp_on &= ~PANEL_UNLOCK_MASK; pp_on |= PANEL_UNLOCK_REGS; - + REG_WRITE(PP_CONTROL, pp_on); pwm_ctrl = REG_READ(BLC_PWM_CTL2); @@ -1885,7 +2028,7 @@ cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev pp_on = REG_READ(PP_ON_DELAYS); pp_off = REG_READ(PP_OFF_DELAYS); pp_div = REG_READ(PP_DIVISOR); - + /* Pull timing values out of registers */ cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >> PANEL_POWER_UP_DELAY_SHIFT; @@ -1920,22 +2063,22 @@ cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev intel_dp->backlight_on_delay, intel_dp->backlight_off_delay); - cdv_intel_edp_panel_vdd_on(psb_intel_encoder); - ret = cdv_intel_dp_aux_native_read(psb_intel_encoder, DP_DPCD_REV, + cdv_intel_edp_panel_vdd_on(gma_encoder); + ret = cdv_intel_dp_aux_native_read(gma_encoder, DP_DPCD_REV, intel_dp->dpcd, sizeof(intel_dp->dpcd)); - cdv_intel_edp_panel_vdd_off(psb_intel_encoder); - if (ret == 0) { + cdv_intel_edp_panel_vdd_off(gma_encoder); + if (ret <= 0) { /* if this fails, presume the device is a ghost */ DRM_INFO("failed to retrieve link info, disabling eDP\n"); - cdv_intel_dp_encoder_destroy(encoder); + drm_encoder_cleanup(encoder); cdv_intel_dp_destroy(connector); - goto err_priv; + goto err_connector; } else { DRM_DEBUG_KMS("DPCD: Rev=%x LN_Rate=%x LN_CNT=%x LN_DOWNSP=%x\n", - intel_dp->dpcd[0], intel_dp->dpcd[1], + intel_dp->dpcd[0], intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]); - + } /* The CDV reference driver moves pnale backlight setup into the displays that have a backlight: this is a good idea and one we should probably adopt, however @@ -1945,7 +2088,7 @@ cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev return; err_priv: - kfree(psb_intel_connector); + kfree(gma_connector); err_connector: - kfree(psb_intel_encoder); + kfree(gma_encoder); } diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c index 464153d9d2df..8e93ee0d0ccd 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c +++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c @@ -22,20 +22,22 @@ * * Authors: * jim liu <jim.liu@intel.com> - * - * FIXME: - * We should probably make this generic and share it with Medfield */ -#include <drm/drmP.h> +#include <linux/pm_runtime.h> + #include <drm/drm.h> #include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> #include <drm/drm_edid.h> -#include "psb_intel_drv.h" +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_print.h> +#include <drm/drm_simple_kms_helper.h> + +#include "cdv_device.h" #include "psb_drv.h" +#include "psb_intel_drv.h" #include "psb_intel_reg.h" -#include "cdv_device.h" -#include <linux/pm_runtime.h> /* hdmi control bits */ #define HDMI_NULL_PACKETS_DURING_VSYNC (1 << 9) @@ -54,8 +56,6 @@ struct mid_intel_hdmi_priv { bool has_hdmi_audio; /* Should set this when detect hotplug */ bool hdmi_device_connected; - struct mdfld_hdmi_i2c *i2c_bus; - struct i2c_adapter *hdmi_i2c_adapter; /* for control functions */ struct drm_device *dev; }; @@ -64,11 +64,11 @@ static void cdv_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; - struct psb_intel_encoder *psb_intel_encoder = to_psb_intel_encoder(encoder); - struct mid_intel_hdmi_priv *hdmi_priv = psb_intel_encoder->dev_priv; + struct gma_encoder *gma_encoder = to_gma_encoder(encoder); + struct mid_intel_hdmi_priv *hdmi_priv = gma_encoder->dev_priv; u32 hdmib; struct drm_crtc *crtc = encoder->crtc; - struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc); + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); hdmib = (2 << 10); @@ -77,7 +77,7 @@ static void cdv_hdmi_mode_set(struct drm_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) hdmib |= HDMI_HSYNC_ACTIVE_HIGH; - if (intel_crtc->pipe == 1) + if (gma_crtc->pipe == 1) hdmib |= HDMIB_PIPE_B_SELECT; if (hdmi_priv->has_hdmi_audio) { @@ -89,19 +89,11 @@ static void cdv_hdmi_mode_set(struct drm_encoder *encoder, REG_READ(hdmi_priv->hdmi_reg); } -static bool cdv_hdmi_mode_fixup(struct drm_encoder *encoder, - const 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_encoder *psb_intel_encoder = - to_psb_intel_encoder(encoder); - struct mid_intel_hdmi_priv *hdmi_priv = psb_intel_encoder->dev_priv; + struct gma_encoder *gma_encoder = to_gma_encoder(encoder); + struct mid_intel_hdmi_priv *hdmi_priv = gma_encoder->dev_priv; u32 hdmib; hdmib = REG_READ(hdmi_priv->hdmi_reg); @@ -116,9 +108,8 @@ static void cdv_hdmi_dpms(struct drm_encoder *encoder, int mode) static void cdv_hdmi_save(struct drm_connector *connector) { struct drm_device *dev = connector->dev; - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); - struct mid_intel_hdmi_priv *hdmi_priv = psb_intel_encoder->dev_priv; + struct gma_encoder *gma_encoder = gma_attached_encoder(connector); + struct mid_intel_hdmi_priv *hdmi_priv = gma_encoder->dev_priv; hdmi_priv->save_HDMIB = REG_READ(hdmi_priv->hdmi_reg); } @@ -126,9 +117,8 @@ static void cdv_hdmi_save(struct drm_connector *connector) static void cdv_hdmi_restore(struct drm_connector *connector) { struct drm_device *dev = connector->dev; - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); - struct mid_intel_hdmi_priv *hdmi_priv = psb_intel_encoder->dev_priv; + struct gma_encoder *gma_encoder = gma_attached_encoder(connector); + struct mid_intel_hdmi_priv *hdmi_priv = gma_encoder->dev_priv; REG_WRITE(hdmi_priv->hdmi_reg, hdmi_priv->save_HDMIB); REG_READ(hdmi_priv->hdmi_reg); @@ -137,13 +127,12 @@ static void cdv_hdmi_restore(struct drm_connector *connector) static enum drm_connector_status cdv_hdmi_detect( struct drm_connector *connector, bool force) { - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); - struct mid_intel_hdmi_priv *hdmi_priv = psb_intel_encoder->dev_priv; + struct gma_encoder *gma_encoder = gma_attached_encoder(connector); + struct mid_intel_hdmi_priv *hdmi_priv = gma_encoder->dev_priv; struct edid *edid = NULL; enum drm_connector_status status = connector_status_disconnected; - edid = drm_get_edid(connector, &psb_intel_encoder->i2c_bus->adapter); + edid = drm_get_edid(connector, connector->ddc); hdmi_priv->has_hdmi_sink = false; hdmi_priv->has_hdmi_audio = false; @@ -167,7 +156,7 @@ static int cdv_hdmi_set_property(struct drm_connector *connector, struct drm_encoder *encoder = connector->encoder; if (!strcmp(property->name, "scaling mode") && encoder) { - struct psb_intel_crtc *crtc = to_psb_intel_crtc(encoder->crtc); + struct gma_crtc *crtc = to_gma_crtc(encoder->crtc); bool centre; uint64_t curValue; @@ -203,10 +192,10 @@ static int cdv_hdmi_set_property(struct drm_connector *connector, 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)) + encoder->crtc->x, encoder->crtc->y, encoder->crtc->primary->fb)) return -1; } else { - struct drm_encoder_helper_funcs *helpers + const struct drm_encoder_helper_funcs *helpers = encoder->helper_private; helpers->mode_set(encoder, &crtc->saved_mode, &crtc->saved_adjusted_mode); @@ -221,22 +210,20 @@ static int cdv_hdmi_set_property(struct drm_connector *connector, */ static int cdv_hdmi_get_modes(struct drm_connector *connector) { - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); struct edid *edid = NULL; int ret = 0; - edid = drm_get_edid(connector, &psb_intel_encoder->i2c_bus->adapter); + edid = drm_get_edid(connector, connector->ddc); if (edid) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); } return ret; } -static int cdv_hdmi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status cdv_hdmi_mode_valid(struct drm_connector *connector, + const struct drm_display_mode *mode) { if (mode->clock > 165000) return MODE_CLOCK_HIGH; @@ -256,35 +243,30 @@ static int cdv_hdmi_mode_valid(struct drm_connector *connector, static void cdv_hdmi_destroy(struct drm_connector *connector) { - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); + struct gma_connector *gma_connector = to_gma_connector(connector); + struct gma_i2c_chan *ddc_bus = to_gma_i2c_chan(connector->ddc); - if (psb_intel_encoder->i2c_bus) - psb_intel_i2c_destroy(psb_intel_encoder->i2c_bus); - drm_sysfs_connector_remove(connector); + gma_i2c_destroy(ddc_bus); drm_connector_cleanup(connector); - kfree(connector); + kfree(gma_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, + .prepare = gma_encoder_prepare, .mode_set = cdv_hdmi_mode_set, - .commit = psb_intel_encoder_commit, + .commit = gma_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, + .best_encoder = gma_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, @@ -294,48 +276,71 @@ static const struct drm_connector_funcs cdv_hdmi_connector_funcs = { void cdv_hdmi_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev, int reg) { - struct psb_intel_encoder *psb_intel_encoder; - struct psb_intel_connector *psb_intel_connector; + struct gma_encoder *gma_encoder; + struct gma_connector *gma_connector; struct drm_connector *connector; - struct drm_encoder *encoder; struct mid_intel_hdmi_priv *hdmi_priv; - int ddc_bus; - - psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder), - GFP_KERNEL); + struct gma_i2c_chan *ddc_bus; + int ddc_reg; + int ret; - if (!psb_intel_encoder) + gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL); + if (!gma_encoder) return; - psb_intel_connector = kzalloc(sizeof(struct psb_intel_connector), - GFP_KERNEL); - - if (!psb_intel_connector) - goto err_connector; + gma_connector = kzalloc(sizeof(struct gma_connector), GFP_KERNEL); + if (!gma_connector) + goto err_free_encoder; hdmi_priv = kzalloc(sizeof(struct mid_intel_hdmi_priv), GFP_KERNEL); - if (!hdmi_priv) - goto err_priv; + goto err_free_connector; - connector = &psb_intel_connector->base; + connector = &gma_connector->base; connector->polled = DRM_CONNECTOR_POLL_HPD; - encoder = &psb_intel_encoder->base; - drm_connector_init(dev, connector, - &cdv_hdmi_connector_funcs, - DRM_MODE_CONNECTOR_DVID); + gma_connector->save = cdv_hdmi_save; + gma_connector->restore = cdv_hdmi_restore; + + switch (reg) { + case SDVOB: + ddc_reg = GPIOE; + gma_encoder->ddi_select = DDI0_SELECT; + break; + case SDVOC: + ddc_reg = GPIOD; + gma_encoder->ddi_select = DDI1_SELECT; + break; + default: + DRM_ERROR("unknown reg 0x%x for HDMI\n", reg); + goto err_free_hdmi_priv; + } + + ddc_bus = gma_i2c_create(dev, ddc_reg, + (reg == SDVOB) ? "HDMIB" : "HDMIC"); + if (!ddc_bus) { + dev_err(dev->dev, "No ddc adapter available!\n"); + goto err_free_hdmi_priv; + } - drm_encoder_init(dev, encoder, &psb_intel_lvds_enc_funcs, - DRM_MODE_ENCODER_TMDS); + ret = drm_connector_init_with_ddc(dev, connector, + &cdv_hdmi_connector_funcs, + DRM_MODE_CONNECTOR_DVID, + &ddc_bus->base); + if (ret) + goto err_ddc_destroy; - psb_intel_connector_attach_encoder(psb_intel_connector, - psb_intel_encoder); - psb_intel_encoder->type = INTEL_OUTPUT_HDMI; + ret = drm_simple_encoder_init(dev, &gma_encoder->base, + DRM_MODE_ENCODER_TMDS); + if (ret) + goto err_connector_cleanup; + + gma_connector_attach_encoder(gma_connector, gma_encoder); + gma_encoder->type = INTEL_OUTPUT_HDMI; hdmi_priv->hdmi_reg = reg; hdmi_priv->has_hdmi_sink = false; - psb_intel_encoder->dev_priv = hdmi_priv; + gma_encoder->dev_priv = hdmi_priv; - drm_encoder_helper_add(encoder, &cdv_hdmi_helper_funcs); + drm_encoder_helper_add(&gma_encoder->base, &cdv_hdmi_helper_funcs); drm_connector_helper_add(connector, &cdv_hdmi_connector_helper_funcs); connector->display_info.subpixel_order = SubPixelHorizontalRGB; @@ -346,40 +351,17 @@ void cdv_hdmi_init(struct drm_device *dev, dev->mode_config.scaling_mode_property, DRM_MODE_SCALE_FULLSCREEN); - switch (reg) { - case SDVOB: - ddc_bus = GPIOE; - psb_intel_encoder->ddi_select = DDI0_SELECT; - break; - case SDVOC: - ddc_bus = GPIOD; - psb_intel_encoder->ddi_select = DDI1_SELECT; - break; - default: - DRM_ERROR("unknown reg 0x%x for HDMI\n", reg); - goto failed_ddc; - break; - } - - psb_intel_encoder->i2c_bus = psb_intel_i2c_create(dev, - ddc_bus, (reg == SDVOB) ? "HDMIB" : "HDMIC"); - - if (!psb_intel_encoder->i2c_bus) { - dev_err(dev->dev, "No ddc adapter available!\n"); - goto failed_ddc; - } - - hdmi_priv->hdmi_i2c_adapter = - &(psb_intel_encoder->i2c_bus->adapter); hdmi_priv->dev = dev; - drm_sysfs_connector_add(connector); return; -failed_ddc: - drm_encoder_cleanup(encoder); +err_connector_cleanup: drm_connector_cleanup(connector); -err_priv: - kfree(psb_intel_connector); -err_connector: - kfree(psb_intel_encoder); +err_ddc_destroy: + gma_i2c_destroy(ddc_bus); +err_free_hdmi_priv: + kfree(hdmi_priv); +err_free_connector: + kfree(gma_connector); +err_free_encoder: + kfree(gma_encoder); } diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c index d81dbc3368f0..fbe7fe317393 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c +++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c @@ -1,38 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * 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 <linux/i2c.h> +#include <linux/pm_runtime.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_print.h> +#include <drm/drm_simple_kms_helper.h> + +#include "cdv_device.h" #include "intel_bios.h" +#include "power.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 @@ -68,7 +60,7 @@ struct cdv_intel_lvds_priv { */ static u32 cdv_intel_lvds_get_max_backlight(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); u32 retval; if (gma_power_begin(dev, false)) { @@ -85,97 +77,14 @@ static u32 cdv_intel_lvds_get_max_backlight(struct drm_device *dev) return retval; } -#if 0 -/* - * 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); -} -#endif - -/** * 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; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); u32 blc_pwm_ctl; if (gma_power_begin(dev, false)) { @@ -193,13 +102,13 @@ static void cdv_intel_lvds_set_backlight(struct drm_device *dev, int level) } } -/** +/* * Sets the power state for the panel. */ static void cdv_intel_lvds_set_power(struct drm_device *dev, struct drm_encoder *encoder, bool on) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); u32 pp_status; if (!gma_power_begin(dev, true)) @@ -244,11 +153,11 @@ static void cdv_intel_lvds_restore(struct drm_connector *connector) { } -static int cdv_intel_lvds_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status cdv_intel_lvds_mode_valid(struct drm_connector *connector, + const struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct drm_display_mode *fixed_mode = dev_priv->mode_dev.panel_fixed_mode; @@ -274,7 +183,7 @@ static bool cdv_intel_lvds_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; struct drm_encoder *tmp_encoder; struct drm_display_mode *panel_fixed_mode = mode_dev->panel_fixed_mode; @@ -284,8 +193,7 @@ static bool cdv_intel_lvds_mode_fixup(struct drm_encoder *encoder, 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"); + pr_err("Can't enable LVDS and another encoder on the same pipe\n"); return false; } } @@ -322,7 +230,7 @@ static bool cdv_intel_lvds_mode_fixup(struct drm_encoder *encoder, static void cdv_intel_lvds_prepare(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; if (!gma_power_begin(dev, true)) @@ -340,7 +248,7 @@ static void cdv_intel_lvds_prepare(struct drm_encoder *encoder) static void cdv_intel_lvds_commit(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; if (mode_dev->backlight_duty_cycle == 0) @@ -355,9 +263,8 @@ static void cdv_intel_lvds_mode_set(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; - struct drm_psb_private *dev_priv = dev->dev_private; - struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc( - encoder->crtc); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_crtc *gma_crtc = to_gma_crtc(encoder->crtc); u32 pfit_control; /* @@ -379,7 +286,7 @@ static void cdv_intel_lvds_mode_set(struct drm_encoder *encoder, else pfit_control = 0; - pfit_control |= psb_intel_crtc->pipe << PFIT_PIPE_SHIFT; + pfit_control |= gma_crtc->pipe << PFIT_PIPE_SHIFT; if (dev_priv->lvds_dither) pfit_control |= PANEL_8TO6_DITHER_ENABLE; @@ -387,47 +294,27 @@ static void cdv_intel_lvds_mode_set(struct drm_encoder *encoder, 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 drm_psb_private *dev_priv = dev->dev_private; - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; int ret; - ret = psb_intel_ddc_get_modes(connector, &psb_intel_encoder->i2c_bus->adapter); + ret = psb_intel_ddc_get_modes(connector, connector->ddc); 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); + if (!mode) + return 0; + drm_mode_probed_add(connector, mode); return 1; } @@ -435,23 +322,15 @@ static int cdv_intel_lvds_get_modes(struct drm_connector *connector) 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. - */ static void cdv_intel_lvds_destroy(struct drm_connector *connector) { - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); + struct gma_connector *gma_connector = to_gma_connector(connector); + struct gma_encoder *gma_encoder = gma_attached_encoder(connector); - if (psb_intel_encoder->i2c_bus) - psb_intel_i2c_destroy(psb_intel_encoder->i2c_bus); - drm_sysfs_connector_remove(connector); + gma_i2c_destroy(to_gma_i2c_chan(connector->ddc)); + gma_i2c_destroy(gma_encoder->i2c_bus); drm_connector_cleanup(connector); - kfree(connector); + kfree(gma_connector); } static int cdv_intel_lvds_set_property(struct drm_connector *connector, @@ -461,8 +340,7 @@ static int cdv_intel_lvds_set_property(struct drm_connector *connector, struct drm_encoder *encoder = connector->encoder; if (!strcmp(property->name, "scaling mode") && encoder) { - struct psb_intel_crtc *crtc = - to_psb_intel_crtc(encoder->crtc); + struct gma_crtc *crtc = to_gma_crtc(encoder->crtc); uint64_t curValue; if (!crtc) @@ -498,7 +376,7 @@ static int cdv_intel_lvds_set_property(struct drm_connector *connector, &crtc->saved_mode, encoder->crtc->x, encoder->crtc->y, - encoder->crtc->fb)) + encoder->crtc->primary->fb)) return -1; } } else if (!strcmp(property->name, "backlight") && encoder) { @@ -509,7 +387,7 @@ static int cdv_intel_lvds_set_property(struct drm_connector *connector, else gma_backlight_set(encoder->dev, value); } else if (!strcmp(property->name, "DPMS") && encoder) { - struct drm_encoder_helper_funcs *helpers = + const struct drm_encoder_helper_funcs *helpers = encoder->helper_private; helpers->dpms(encoder, value); } @@ -529,29 +407,16 @@ 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, + .best_encoder = gma_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); -} - -static const struct drm_encoder_funcs cdv_intel_lvds_enc_funcs = { - .destroy = cdv_intel_lvds_enc_destroy, -}; - /* * Enumerate the child dev array parsed from VBT to check whether * the LVDS is present. @@ -562,7 +427,7 @@ static const struct drm_encoder_funcs cdv_intel_lvds_enc_funcs = { static bool lvds_is_present_in_vbt(struct drm_device *dev, u8 *i2c_pin) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); int i; if (!dev_priv->child_dev_num) @@ -605,6 +470,7 @@ static bool lvds_is_present_in_vbt(struct drm_device *dev, /** * cdv_intel_lvds_init - setup LVDS connectors on this device * @dev: drm device + * @mode_dev: PSB mode 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). @@ -612,56 +478,71 @@ static bool lvds_is_present_in_vbt(struct drm_device *dev, void cdv_intel_lvds_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev) { - struct psb_intel_encoder *psb_intel_encoder; - struct psb_intel_connector *psb_intel_connector; + struct gma_encoder *gma_encoder; + struct gma_connector *gma_connector; 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; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_i2c_chan *ddc_bus; u32 lvds; int pipe; + int ret; u8 pin; + if (!dev_priv->lvds_enabled_in_vbt) + return; + pin = GMBUS_PORT_PANEL; if (!lvds_is_present_in_vbt(dev, &pin)) { DRM_DEBUG_KMS("LVDS is not present in VBT\n"); return; } - psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder), + gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL); - if (!psb_intel_encoder) + if (!gma_encoder) return; - psb_intel_connector = kzalloc(sizeof(struct psb_intel_connector), + gma_connector = kzalloc(sizeof(struct gma_connector), GFP_KERNEL); - if (!psb_intel_connector) - goto failed_connector; + if (!gma_connector) + goto err_free_encoder; lvds_priv = kzalloc(sizeof(struct cdv_intel_lvds_priv), GFP_KERNEL); if (!lvds_priv) - goto failed_lvds_priv; - - psb_intel_encoder->dev_priv = lvds_priv; + goto err_free_connector; - connector = &psb_intel_connector->base; - encoder = &psb_intel_encoder->base; + gma_encoder->dev_priv = lvds_priv; + connector = &gma_connector->base; + gma_connector->save = cdv_intel_lvds_save; + gma_connector->restore = cdv_intel_lvds_restore; + encoder = &gma_encoder->base; - drm_connector_init(dev, connector, - &cdv_intel_lvds_connector_funcs, - DRM_MODE_CONNECTOR_LVDS); + /* Set up the DDC bus. */ + ddc_bus = gma_i2c_create(dev, GPIOC, "LVDSDDC_C"); + if (!ddc_bus) { + dev_printk(KERN_ERR, dev->dev, + "DDC bus registration " "failed.\n"); + goto err_free_lvds_priv; + } - drm_encoder_init(dev, encoder, - &cdv_intel_lvds_enc_funcs, - DRM_MODE_ENCODER_LVDS); + ret = drm_connector_init_with_ddc(dev, connector, + &cdv_intel_lvds_connector_funcs, + DRM_MODE_CONNECTOR_LVDS, + &ddc_bus->base); + if (ret) + goto err_destroy_ddc; + ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_LVDS); + if (ret) + goto err_connector_cleanup; - psb_intel_connector_attach_encoder(psb_intel_connector, - psb_intel_encoder); - psb_intel_encoder->type = INTEL_OUTPUT_LVDS; + gma_connector_attach_encoder(gma_connector, gma_encoder); + gma_encoder->type = INTEL_OUTPUT_LVDS; drm_encoder_helper_add(encoder, &cdv_intel_lvds_helper_funcs); drm_connector_helper_add(connector, @@ -682,16 +563,14 @@ void cdv_intel_lvds_init(struct drm_device *dev, * Set up I2C bus * FIXME: distroy i2c_bus when exit */ - psb_intel_encoder->i2c_bus = psb_intel_i2c_create(dev, - GPIOB, - "LVDSBLC_B"); - if (!psb_intel_encoder->i2c_bus) { + gma_encoder->i2c_bus = gma_i2c_create(dev, GPIOB, "LVDSBLC_B"); + if (!gma_encoder->i2c_bus) { dev_printk(KERN_ERR, - &dev->pdev->dev, "I2C bus registration failed.\n"); - goto failed_blc_i2c; + dev->dev, "I2C bus registration failed.\n"); + goto err_encoder_cleanup; } - psb_intel_encoder->i2c_bus->slave_addr = 0x2C; - dev_priv->lvds_i2c_bus = psb_intel_encoder->i2c_bus; + gma_encoder->i2c_bus->target_addr = 0x2C; + dev_priv->lvds_i2c_bus = gma_encoder->i2c_bus; /* * LVDS discovery: @@ -703,22 +582,13 @@ void cdv_intel_lvds_init(struct drm_device *dev, * if closed, act like it's not there for now */ - /* Set up the DDC bus. */ - psb_intel_encoder->ddc_bus = psb_intel_i2c_create(dev, - GPIOC, - "LVDSDDC_C"); - if (!psb_intel_encoder->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(connector, - &psb_intel_encoder->ddc_bus->adapter); + mutex_lock(&dev->mode_config.mutex); + psb_intel_ddc_get_modes(connector, &ddc_bus->base); + list_for_each_entry(scan, &connector->probed_modes, head) { if (scan->type & DRM_MODE_TYPE_PREFERRED) { mode_dev->panel_fixed_mode = @@ -760,7 +630,7 @@ void cdv_intel_lvds_init(struct drm_device *dev, if (!mode_dev->panel_fixed_mode) { DRM_DEBUG ("Found no modes on the lvds, ignoring the LVDS\n"); - goto failed_find; + goto err_unlock; } /* setup PWM */ @@ -777,24 +647,22 @@ void cdv_intel_lvds_init(struct drm_device *dev, } out: - drm_sysfs_connector_add(connector); + mutex_unlock(&dev->mode_config.mutex); return; -failed_find: - printk(KERN_ERR "Failed find\n"); - if (psb_intel_encoder->ddc_bus) - psb_intel_i2c_destroy(psb_intel_encoder->ddc_bus); -failed_ddc: - printk(KERN_ERR "Failed DDC\n"); - if (psb_intel_encoder->i2c_bus) - psb_intel_i2c_destroy(psb_intel_encoder->i2c_bus); -failed_blc_i2c: - printk(KERN_ERR "Failed BLC\n"); +err_unlock: + mutex_unlock(&dev->mode_config.mutex); + gma_i2c_destroy(gma_encoder->i2c_bus); +err_encoder_cleanup: drm_encoder_cleanup(encoder); +err_connector_cleanup: drm_connector_cleanup(connector); +err_destroy_ddc: + gma_i2c_destroy(ddc_bus); +err_free_lvds_priv: kfree(lvds_priv); -failed_lvds_priv: - kfree(psb_intel_connector); -failed_connector: - kfree(psb_intel_encoder); +err_free_connector: + kfree(gma_connector); +err_free_encoder: + kfree(gma_encoder); } diff --git a/drivers/gpu/drm/gma500/fbdev.c b/drivers/gpu/drm/gma500/fbdev.c new file mode 100644 index 000000000000..c26926babc2a --- /dev/null +++ b/drivers/gpu/drm/gma500/fbdev.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0-only +/************************************************************************** + * Copyright (c) 2007-2011, Intel Corporation. + * All Rights Reserved. + * + **************************************************************************/ + +#include <linux/fb.h> + +#include <drm/drm_crtc_helper.h> +#include <drm/drm_drv.h> +#include <drm/drm_fb_helper.h> +#include <drm/drm_framebuffer.h> + +#include "gem.h" +#include "psb_drv.h" + +/* + * VM area struct + */ + +static vm_fault_t psb_fbdev_vm_fault(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; + struct fb_info *info = vma->vm_private_data; + unsigned long address = vmf->address - (vmf->pgoff << PAGE_SHIFT); + unsigned long pfn = info->fix.smem_start >> PAGE_SHIFT; + vm_fault_t err = VM_FAULT_SIGBUS; + unsigned long page_num = vma_pages(vma); + unsigned long i; + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + for (i = 0; i < page_num; ++i) { + err = vmf_insert_mixed(vma, address, pfn); + if (unlikely(err & VM_FAULT_ERROR)) + break; + address += PAGE_SIZE; + ++pfn; + } + + return err; +} + +static const struct vm_operations_struct psb_fbdev_vm_ops = { + .fault = psb_fbdev_vm_fault, +}; + +/* + * struct fb_ops + */ + +static int psb_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + if (vma->vm_pgoff != 0) + return -EINVAL; + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) + return -EINVAL; + + /* + * 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 = &psb_fbdev_vm_ops; + vma->vm_private_data = info; + vm_flags_set(vma, VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP); + + return 0; +} + +static void psb_fbdev_fb_destroy(struct fb_info *info) +{ + struct drm_fb_helper *fb_helper = info->par; + struct drm_framebuffer *fb = fb_helper->fb; + struct drm_gem_object *obj = fb->obj[0]; + + drm_fb_helper_fini(fb_helper); + + drm_framebuffer_unregister_private(fb); + drm_framebuffer_cleanup(fb); + kfree(fb); + + drm_gem_object_put(obj); + + drm_client_release(&fb_helper->client); +} + +static const struct fb_ops psb_fbdev_fb_ops = { + .owner = THIS_MODULE, + __FB_DEFAULT_IOMEM_OPS_RDWR, + DRM_FB_HELPER_DEFAULT_OPS, + __FB_DEFAULT_IOMEM_OPS_DRAW, + .fb_mmap = psb_fbdev_fb_mmap, + .fb_destroy = psb_fbdev_fb_destroy, +}; + +static const struct drm_fb_helper_funcs psb_fbdev_fb_helper_funcs = { +}; + +/* + * struct drm_driver + */ + +int psb_fbdev_driver_fbdev_probe(struct drm_fb_helper *fb_helper, + struct drm_fb_helper_surface_size *sizes) +{ + struct drm_device *dev = fb_helper->dev; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct pci_dev *pdev = to_pci_dev(dev->dev); + struct fb_info *info = fb_helper->info; + struct drm_framebuffer *fb; + struct drm_mode_fb_cmd2 mode_cmd = { }; + int size; + int ret; + struct psb_gem_object *backing; + struct drm_gem_object *obj; + u32 bpp, depth; + + /* No 24-bit packed mode */ + if (sizes->surface_bpp == 24) { + sizes->surface_bpp = 32; + sizes->surface_depth = 24; + } + bpp = sizes->surface_bpp; + depth = sizes->surface_depth; + + /* + * If the mode does not fit in 32 bit then switch to 16 bit to get + * a console on full resolution. The X mode setting server will + * allocate its own 32-bit GEM framebuffer. + */ + size = ALIGN(sizes->surface_width * DIV_ROUND_UP(bpp, 8), 64) * + sizes->surface_height; + size = ALIGN(size, PAGE_SIZE); + + if (size > dev_priv->vram_stolen_size) { + sizes->surface_bpp = 16; + sizes->surface_depth = 16; + } + bpp = sizes->surface_bpp; + depth = sizes->surface_depth; + + mode_cmd.width = sizes->surface_width; + mode_cmd.height = sizes->surface_height; + mode_cmd.pitches[0] = ALIGN(mode_cmd.width * DIV_ROUND_UP(bpp, 8), 64); + mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth); + + size = mode_cmd.pitches[0] * mode_cmd.height; + size = ALIGN(size, PAGE_SIZE); + + /* Allocate the framebuffer in the GTT with stolen page backing */ + backing = psb_gem_create(dev, size, "fb", true, PAGE_SIZE); + if (IS_ERR(backing)) + return PTR_ERR(backing); + obj = &backing->base; + + fb = psb_framebuffer_create(dev, + drm_get_format_info(dev, mode_cmd.pixel_format, + mode_cmd.modifier[0]), + &mode_cmd, obj); + if (IS_ERR(fb)) { + ret = PTR_ERR(fb); + goto err_drm_gem_object_put; + } + + fb_helper->funcs = &psb_fbdev_fb_helper_funcs; + fb_helper->fb = fb; + + info->fbops = &psb_fbdev_fb_ops; + + /* Accessed stolen memory directly */ + info->screen_base = dev_priv->vram_addr + backing->offset; + info->screen_size = size; + + drm_fb_helper_fill_info(info, fb_helper, sizes); + + info->fix.smem_start = dev_priv->stolen_base + backing->offset; + info->fix.smem_len = size; + info->fix.ywrapstep = 0; + info->fix.ypanstep = 0; + info->fix.mmio_start = pci_resource_start(pdev, 0); + info->fix.mmio_len = pci_resource_len(pdev, 0); + + fb_memset_io(info->screen_base, 0, info->screen_size); + + /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ + + dev_dbg(dev->dev, "allocated %dx%d fb\n", fb->width, fb->height); + + return 0; + +err_drm_gem_object_put: + drm_gem_object_put(obj); + return ret; +} diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index 8b1b6d923abe..e69b537ded6b 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -1,232 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-only /************************************************************************** * Copyright (c) 2007-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/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/tty.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/fb.h> -#include <linux/init.h> -#include <linux/console.h> - -#include <drm/drmP.h> -#include <drm/drm.h> -#include <drm/drm_crtc.h> -#include <drm/drm_fb_helper.h> +#include <drm/drm_framebuffer.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_modeset_helper.h> -#include "psb_drv.h" -#include "psb_intel_reg.h" -#include "psb_intel_drv.h" #include "framebuffer.h" -#include "gtt.h" - -static void psb_user_framebuffer_destroy(struct drm_framebuffer *fb); -static int psb_user_framebuffer_create_handle(struct drm_framebuffer *fb, - struct drm_file *file_priv, - unsigned int *handle); +#include "psb_drv.h" static const struct drm_framebuffer_funcs psb_fb_funcs = { - .destroy = psb_user_framebuffer_destroy, - .create_handle = psb_user_framebuffer_create_handle, -}; - -#define CMAP_TOHW(_val, _width) ((((_val) << (_width)) + 0x7FFF - (_val)) >> 16) - -static int psbfb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info) -{ - struct psb_fbdev *fbdev = info->par; - struct drm_framebuffer *fb = fbdev->psb_fb_helper.fb; - uint32_t v; - - if (!fb) - return -ENOMEM; - - if (regno > 255) - return 1; - - red = CMAP_TOHW(red, info->var.red.length); - blue = CMAP_TOHW(blue, info->var.blue.length); - green = CMAP_TOHW(green, info->var.green.length); - transp = CMAP_TOHW(transp, info->var.transp.length); - - v = (red << info->var.red.offset) | - (green << info->var.green.offset) | - (blue << info->var.blue.offset) | - (transp << info->var.transp.offset); - - if (regno < 16) { - switch (fb->bits_per_pixel) { - case 16: - ((uint32_t *) info->pseudo_palette)[regno] = v; - break; - case 24: - case 32: - ((uint32_t *) info->pseudo_palette)[regno] = v; - break; - } - } - - return 0; -} - -static int psbfb_pan(struct fb_var_screeninfo *var, struct fb_info *info) -{ - struct psb_fbdev *fbdev = info->par; - struct psb_framebuffer *psbfb = &fbdev->pfb; - struct drm_device *dev = psbfb->base.dev; - - /* - * We have to poke our nose in here. The core fb code assumes - * panning is part of the hardware that can be invoked before - * the actual fb is mapped. In our case that isn't quite true. - */ - if (psbfb->gtt->npage) { - /* GTT roll shifts in 4K pages, we need to shift the right - number of pages */ - int pages = info->fix.line_length >> 12; - psb_gtt_roll(dev, psbfb->gtt, var->yoffset * pages); - } - return 0; -} - -static int psbfb_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - 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; - unsigned long phys_addr = (unsigned long)dev_priv->stolen_base + - psbfb->gtt->offset; - - page_num = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; - address = (unsigned long)vmf->virtual_address - (vmf->pgoff << PAGE_SHIFT); - - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - - for (i = 0; i < page_num; i++) { - pfn = (phys_addr >> PAGE_SHIFT); - - ret = vm_insert_mixed(vma, address, pfn); - if (unlikely((ret == -EBUSY) || (ret != 0 && i > 0))) - break; - else if (unlikely(ret != 0)) { - 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) -{ -} - -static void psbfb_vm_close(struct vm_area_struct *vma) -{ -} - -static const struct vm_operations_struct psbfb_vm_ops = { - .fault = psbfb_vm_fault, - .open = psbfb_vm_open, - .close = psbfb_vm_close -}; - -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; - - if (vma->vm_pgoff != 0) - return -EINVAL; - if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) - return -EINVAL; - - if (!psbfb->addr_space) - psbfb->addr_space = vma->vm_file->f_mapping; - /* - * 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_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP; - return 0; -} - -static int psbfb_ioctl(struct fb_info *info, unsigned int cmd, - unsigned long arg) -{ - return -ENOTTY; -} - -static struct fb_ops psbfb_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 = psbfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_mmap = psbfb_mmap, - .fb_sync = psbfb_sync, - .fb_ioctl = psbfb_ioctl, -}; - -static struct fb_ops psbfb_roll_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_pan_display = psbfb_pan, - .fb_mmap = psbfb_mmap, - .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, + .destroy = drm_gem_fb_destroy, + .create_handle = drm_gem_fb_create_handle, }; /** @@ -234,35 +22,32 @@ static struct fb_ops psbfb_unaccel_ops = { * @dev: our DRM device * @fb: framebuffer to set up * @mode_cmd: mode description - * @gt: backing object + * @obj: 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_cmd2 *mode_cmd, - struct gtt_range *gt) + struct drm_framebuffer *fb, + const struct drm_format_info *info, + const struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_gem_object *obj) { - u32 bpp, depth; int ret; - drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp); + /* + * Reject unknown formats, YUV formats, and formats with more than + * 4 bytes per pixel. + */ + if (!info->depth || info->cpp[0] > 4) + return -EINVAL; if (mode_cmd->pitches[0] & 63) return -EINVAL; - switch (bpp) { - case 8: - case 16: - case 24: - case 32: - break; - default: - return -EINVAL; - } - drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd); - fb->gtt = gt; - ret = drm_framebuffer_init(dev, &fb->base, &psb_fb_funcs); + + drm_helper_mode_fill_fb_struct(dev, fb, info, mode_cmd); + fb->obj[0] = obj; + ret = drm_framebuffer_init(dev, fb, &psb_fb_funcs); if (ret) { dev_err(dev->dev, "framebuffer init failed: %d\n", ret); return ret; @@ -273,222 +58,33 @@ static int psb_framebuffer_init(struct drm_device *dev, /** * psb_framebuffer_create - create a framebuffer backed by gt * @dev: our DRM device + * @info: pixel format information * @mode_cmd: the description of the requested mode - * @gt: the backing object + * @obj: 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_cmd2 *mode_cmd, - struct gtt_range *gt) +struct drm_framebuffer *psb_framebuffer_create(struct drm_device *dev, + const struct drm_format_info *info, + const struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_gem_object *obj) { - struct psb_framebuffer *fb; + struct drm_framebuffer *fb; int ret; fb = kzalloc(sizeof(*fb), GFP_KERNEL); if (!fb) return ERR_PTR(-ENOMEM); - ret = psb_framebuffer_init(dev, fb, mode_cmd, gt); + ret = psb_framebuffer_init(dev, fb, info, mode_cmd, obj); if (ret) { kfree(fb); return ERR_PTR(ret); } - return &fb->base; -} - -/** - * psbfb_alloc - allocate frame buffer memory - * @dev: the DRM device - * @aligned_size: space needed - * @force: fall back to GEM buffers if need be - * - * Allocate the frame buffer. In the usual case we get a GTT range that - * is stolen memory backed and life is simple. If there isn't sufficient - * we fail as we don't have the virtual mapping space to really vmap it - * and the kernel console code can't handle non linear framebuffers. - * - * Re-address this as and if the framebuffer layer grows this ability. - */ -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) { - if (drm_gem_private_object_init(dev, - &backing->gem, aligned_size) == 0) - return backing; - psb_gtt_free_range(dev, backing); - } - return NULL; -} - -/** - * psbfb_create - create a framebuffer - * @fbdev: the framebuffer device - * @sizes: specification of the layout - * - * Create a framebuffer to the specifications provided - */ -static int psbfb_create(struct psb_fbdev *fbdev, - struct drm_fb_helper_surface_size *sizes) -{ - struct drm_device *dev = fbdev->psb_fb_helper.dev; - struct drm_psb_private *dev_priv = dev->dev_private; - struct fb_info *info; - struct drm_framebuffer *fb; - struct psb_framebuffer *psbfb = &fbdev->pfb; - struct drm_mode_fb_cmd2 mode_cmd; - struct device *device = &dev->pdev->dev; - int size; - int ret; - struct gtt_range *backing; - u32 bpp, depth; - int gtt_roll = 0; - int pitch_lines = 0; - - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - bpp = sizes->surface_bpp; - depth = sizes->surface_depth; - - /* No 24bit packed */ - if (bpp == 24) - bpp = 32; - - do { - /* - * Acceleration via the GTT requires pitch to be - * power of two aligned. Preferably page but less - * is ok with some fonts - */ - mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((bpp + 7) / 8), 4096 >> pitch_lines); - - size = mode_cmd.pitches[0] * mode_cmd.height; - size = ALIGN(size, PAGE_SIZE); - - /* Allocate the fb in the GTT with stolen page backing */ - backing = psbfb_alloc(dev, size); - - if (pitch_lines) - pitch_lines *= 2; - else - pitch_lines = 1; - gtt_roll++; - } while (backing == NULL && pitch_lines <= 16); - - /* The final pitch we accepted if we succeeded */ - pitch_lines /= 2; - - if (backing == NULL) { - /* - * We couldn't get the space we wanted, fall back to the - * display engine requirement instead. The HW requires - * the pitch to be 64 byte aligned - */ - - gtt_roll = 0; /* Don't use GTT accelerated scrolling */ - pitch_lines = 64; - - mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((bpp + 7) / 8), 64); - - size = mode_cmd.pitches[0] * mode_cmd.height; - size = ALIGN(size, PAGE_SIZE); - - /* Allocate the framebuffer in the GTT with stolen page backing */ - backing = psbfb_alloc(dev, size); - if (backing == NULL) - return -ENOMEM; - } - - memset(dev_priv->vram_addr + backing->offset, 0, size); - - mutex_lock(&dev->struct_mutex); - - info = framebuffer_alloc(0, device); - if (!info) { - ret = -ENOMEM; - goto out_err1; - } - info->par = fbdev; - - mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth); - - 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; - - drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); - strcpy(info->fix.id, "psbdrmfb"); - - info->flags = FBINFO_DEFAULT; - if (dev_priv->ops->accel_2d && pitch_lines > 8) /* 2D engine */ - info->fbops = &psbfb_ops; - else if (gtt_roll) { /* GTT rolling seems best */ - info->fbops = &psbfb_roll_ops; - info->flags |= FBINFO_HWACCEL_YPAN; - } else /* Software */ - info->fbops = &psbfb_unaccel_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; - info->fix.ywrapstep = gtt_roll; - info->fix.ypanstep = 0; - - /* Accessed stolen memory directly */ - info->screen_base = dev_priv->vram_addr + backing->offset; - info->screen_size = size; - - if (dev_priv->gtt.stolen_size) { - info->apertures = alloc_apertures(1); - if (!info->apertures) { - ret = -ENOMEM; - goto out_unref; - } - info->apertures->ranges[0].base = dev->mode_config.fb_base; - info->apertures->ranges[0].size = dev_priv->gtt.stolen_size; - } - - drm_fb_helper_fill_var(info, &fbdev->psb_fb_helper, - sizes->fb_width, sizes->fb_height); - - info->fix.mmio_start = pci_resource_start(dev->pdev, 0); - info->fix.mmio_len = pci_resource_len(dev->pdev, 0); - - /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ - - dev_dbg(dev->dev, "allocated %dx%d fb\n", - psbfb->base.width, psbfb->base.height); - - mutex_unlock(&dev->struct_mutex); - return 0; -out_unref: - if (backing->stolen) - psb_gtt_free_range(dev, backing); - else - drm_gem_object_unreference(&backing->gem); -out_err1: - mutex_unlock(&dev->struct_mutex); - psb_gtt_free_range(dev, backing); - return ret; + return fb; } /** @@ -501,273 +97,107 @@ out_err1: */ static struct drm_framebuffer *psb_user_framebuffer_create (struct drm_device *dev, struct drm_file *filp, - struct drm_mode_fb_cmd2 *cmd) + const struct drm_format_info *info, + const struct drm_mode_fb_cmd2 *cmd) { - struct gtt_range *r; struct drm_gem_object *obj; + struct drm_framebuffer *fb; /* * Find the GEM object and thus the gtt range object that is * to back this space */ - obj = drm_gem_object_lookup(dev, filp, cmd->handles[0]); + obj = drm_gem_object_lookup(filp, cmd->handles[0]); if (obj == NULL) 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) -{ - struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc); + fb = psb_framebuffer_create(dev, info, cmd, obj); + if (IS_ERR(fb)) + drm_gem_object_put(obj); - intel_crtc->lut_r[regno] = red >> 8; - intel_crtc->lut_g[regno] = green >> 8; - intel_crtc->lut_b[regno] = blue >> 8; -} - -static void psbfb_gamma_get(struct drm_crtc *crtc, u16 *red, - u16 *green, u16 *blue, int regno) -{ - struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc); - - *red = intel_crtc->lut_r[regno] << 8; - *green = intel_crtc->lut_g[regno] << 8; - *blue = intel_crtc->lut_b[regno] << 8; -} - -static int psbfb_probe(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) -{ - struct psb_fbdev *psb_fbdev = (struct psb_fbdev *)helper; - struct drm_device *dev = psb_fbdev->psb_fb_helper.dev; - struct drm_psb_private *dev_priv = dev->dev_private; - int bytespp; - - bytespp = sizes->surface_bpp / 8; - if (bytespp == 3) /* no 24bit packed */ - bytespp = 4; - - /* If the mode will not fit in 32bit then switch to 16bit to get - a console on full resolution. The X mode setting server will - allocate its own 32bit GEM framebuffer */ - if (ALIGN(sizes->fb_width * bytespp, 64) * sizes->fb_height > - dev_priv->vram_stolen_size) { - sizes->surface_bpp = 16; - sizes->surface_depth = 16; - } - - return psbfb_create(psb_fbdev, sizes); -} - -static struct drm_fb_helper_funcs psb_fb_helper_funcs = { - .gamma_set = psbfb_gamma_set, - .gamma_get = psbfb_gamma_get, - .fb_probe = psbfb_probe, -}; - -static int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev) -{ - struct fb_info *info; - struct psb_framebuffer *psbfb = &fbdev->pfb; - - if (fbdev->psb_fb_helper.fbdev) { - info = fbdev->psb_fb_helper.fbdev; - unregister_framebuffer(info); - if (info->cmap.len) - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); - } - drm_fb_helper_fini(&fbdev->psb_fb_helper); - drm_framebuffer_unregister_private(&psbfb->base); - drm_framebuffer_cleanup(&psbfb->base); - - if (psbfb->gtt) - drm_gem_object_unreference(&psbfb->gtt->gem); - return 0; -} - -int psb_fbdev_init(struct drm_device *dev) -{ - struct psb_fbdev *fbdev; - struct drm_psb_private *dev_priv = dev->dev_private; - - fbdev = kzalloc(sizeof(struct psb_fbdev), GFP_KERNEL); - if (!fbdev) { - dev_err(dev->dev, "no memory\n"); - return -ENOMEM; - } - - dev_priv->fbdev = fbdev; - fbdev->psb_fb_helper.funcs = &psb_fb_helper_funcs; - - 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); - - /* disable all the possible outputs/crtcs before entering KMS mode */ - drm_helper_disable_unused_functions(dev); - - drm_fb_helper_initial_config(&fbdev->psb_fb_helper, 32); - return 0; -} - -static void psb_fbdev_fini(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - - if (!dev_priv->fbdev) - return; - - psb_fbdev_destroy(dev, dev_priv->fbdev); - kfree(dev_priv->fbdev); - dev_priv->fbdev = NULL; -} - -static void psbfb_output_poll_changed(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - struct psb_fbdev *fbdev = (struct psb_fbdev *)dev_priv->fbdev; - drm_fb_helper_hotplug_event(&fbdev->psb_fb_helper); -} - -/** - * psb_user_framebuffer_create_handle - add hamdle to a framebuffer - * @fb: framebuffer - * @file_priv: our DRM file - * @handle: returned handle - * - * Our framebuffer object is a GTT range which also contains a GEM - * object. We need to turn it into a handle for userspace. GEM will do - * the work for us - */ -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; - return drm_gem_handle_create(file_priv, &r->gem, handle); -} - -/** - * psb_user_framebuffer_destroy - destruct user created fb - * @fb: framebuffer - * - * User framebuffers are backed by GEM objects so all we have to do is - * clean up a bit and drop the reference, GEM will handle the fallout - */ -static void psb_user_framebuffer_destroy(struct drm_framebuffer *fb) -{ - struct psb_framebuffer *psbfb = to_psb_fb(fb); - struct gtt_range *r = psbfb->gtt; - - /* 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); + return fb; } static const struct drm_mode_config_funcs psb_mode_funcs = { .fb_create = psb_user_framebuffer_create, - .output_poll_changed = psbfb_output_poll_changed, }; -static int psb_create_backlight_property(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - struct drm_property *backlight; - - if (dev_priv->backlight_property) - return 0; - - backlight = drm_property_create_range(dev, 0, "backlight", 0, 100); - - dev_priv->backlight_property = backlight; - - return 0; -} - static void psb_setup_outputs(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct drm_connector_list_iter conn_iter; struct drm_connector *connector; drm_mode_create_scaling_mode_property(dev); - psb_create_backlight_property(dev); + /* It is ok for this to fail - we just don't get backlight control */ + if (!dev_priv->backlight_property) + dev_priv->backlight_property = drm_property_create_range(dev, 0, + "backlight", 0, 100); dev_priv->ops->output_init(dev); - list_for_each_entry(connector, &dev->mode_config.connector_list, - head) { - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); - struct drm_encoder *encoder = &psb_intel_encoder->base; + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + struct gma_encoder *gma_encoder = gma_attached_encoder(connector); + struct drm_encoder *encoder = &gma_encoder->base; int crtc_mask = 0, clone_mask = 0; /* valid crtcs */ - switch (psb_intel_encoder->type) { + switch (gma_encoder->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); + crtc_mask = dev_priv->ops->sdvo_mask; + clone_mask = 0; break; case INTEL_OUTPUT_LVDS: - crtc_mask = dev_priv->ops->lvds_mask; - clone_mask = (1 << INTEL_OUTPUT_LVDS); + crtc_mask = dev_priv->ops->lvds_mask; + clone_mask = 0; break; case INTEL_OUTPUT_MIPI: crtc_mask = (1 << 0); - clone_mask = (1 << INTEL_OUTPUT_MIPI); + clone_mask = 0; break; case INTEL_OUTPUT_MIPI2: crtc_mask = (1 << 2); - clone_mask = (1 << INTEL_OUTPUT_MIPI2); + clone_mask = 0; break; case INTEL_OUTPUT_HDMI: - crtc_mask = dev_priv->ops->hdmi_mask; + crtc_mask = dev_priv->ops->hdmi_mask; clone_mask = (1 << INTEL_OUTPUT_HDMI); break; case INTEL_OUTPUT_DISPLAYPORT: crtc_mask = (1 << 0) | (1 << 1); - clone_mask = (1 << INTEL_OUTPUT_DISPLAYPORT); + clone_mask = 0; break; case INTEL_OUTPUT_EDP: crtc_mask = (1 << 1); - clone_mask = (1 << INTEL_OUTPUT_EDP); + clone_mask = 0; } encoder->possible_crtcs = crtc_mask; encoder->possible_clones = - psb_intel_connector_clones(dev, clone_mask); + gma_connector_clones(dev, clone_mask); } + drm_connector_list_iter_end(&conn_iter); } void psb_modeset_init(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; int i; - drm_mode_config_init(dev); + if (drmm_mode_config_init(dev)) + return; dev->mode_config.min_width = 0; dev->mode_config.min_height = 0; dev->mode_config.funcs = &psb_mode_funcs; - /* set memory base */ - /* Oaktrail and Poulsbo should use BAR 2*/ - pci_read_config_dword(dev->pdev, PSB_BSM, (u32 *) - &(dev->mode_config.fb_base)); - /* num pipes is 2 for PSB but 1 for Mrst */ for (i = 0; i < dev_priv->num_pipe; i++) psb_intel_crtc_init(dev, i, mode_dev); @@ -785,14 +215,8 @@ void psb_modeset_init(struct drm_device *dev) void psb_modeset_cleanup(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); if (dev_priv->modeset) { - mutex_lock(&dev->struct_mutex); - drm_kms_helper_poll_fini(dev); - psb_fbdev_fini(dev); - drm_mode_config_cleanup(dev); - - mutex_unlock(&dev->struct_mutex); } } diff --git a/drivers/gpu/drm/gma500/framebuffer.h b/drivers/gpu/drm/gma500/framebuffer.h index 989558a9e6ee..2fbba4b48841 100644 --- a/drivers/gpu/drm/gma500/framebuffer.h +++ b/drivers/gpu/drm/gma500/framebuffer.h @@ -1,47 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * 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, - * 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> - * */ #ifndef _FRAMEBUFFER_H_ #define _FRAMEBUFFER_H_ -#include <drm/drmP.h> -#include <drm/drm_fb_helper.h> - #include "psb_drv.h" -struct psb_framebuffer { - struct drm_framebuffer base; - struct address_space *addr_space; - struct fb_info *fbdev; - struct gtt_range *gtt; -}; - -struct psb_fbdev { - struct drm_fb_helper psb_fb_helper; - 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); +extern int gma_connector_clones(struct drm_device *dev, int type_mask); #endif diff --git a/drivers/gpu/drm/gma500/gem.c b/drivers/gpu/drm/gma500/gem.c index eefd6cc5b80d..2e44a2ac2742 100644 --- a/drivers/gpu/drm/gma500/gem.c +++ b/drivers/gpu/drm/gma500/gem.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * psb GEM interface * * Copyright (c) 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: Alan Cox * * TODO: @@ -23,132 +11,185 @@ * accelerated operations on a GEM object) */ -#include <drm/drmP.h> +#include <linux/pagemap.h> + +#include <asm/set_memory.h> + #include <drm/drm.h> -#include <drm/gma_drm.h> +#include <drm/drm_print.h> +#include <drm/drm_vma_manager.h> + +#include "gem.h" #include "psb_drv.h" -int psb_gem_init_object(struct drm_gem_object *obj) -{ - return -EINVAL; -} +/* + * PSB GEM object + */ -void psb_gem_free_object(struct drm_gem_object *obj) +int psb_gem_pin(struct psb_gem_object *pobj) { - struct gtt_range *gtt = container_of(obj, struct gtt_range, gem); + struct drm_gem_object *obj = &pobj->base; + struct drm_device *dev = obj->dev; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + u32 gpu_base = dev_priv->gtt.gatt_start; + struct page **pages; + unsigned int npages; + int ret; - /* Remove the list map if one is present */ - if (obj->map_list.map) - drm_gem_free_mmap_offset(obj); - drm_gem_object_release(obj); + ret = dma_resv_lock(obj->resv, NULL); + if (drm_WARN_ONCE(dev, ret, "dma_resv_lock() failed, ret=%d\n", ret)) + return ret; + + if (pobj->in_gart || pobj->stolen) + goto out; /* already mapped */ + + pages = drm_gem_get_pages(obj); + if (IS_ERR(pages)) { + ret = PTR_ERR(pages); + goto err_dma_resv_unlock; + } + + npages = obj->size / PAGE_SIZE; - /* This must occur last as it frees up the memory of the GEM object */ - psb_gtt_free_range(obj->dev, gtt); + set_pages_array_wc(pages, npages); + + psb_gtt_insert_pages(dev_priv, &pobj->resource, pages); + psb_mmu_insert_pages(psb_mmu_get_default_pd(dev_priv->mmu), pages, + (gpu_base + pobj->offset), npages, 0, 0, + PSB_MMU_CACHED_MEMORY); + + pobj->pages = pages; + +out: + ++pobj->in_gart; + dma_resv_unlock(obj->resv); + + return 0; + +err_dma_resv_unlock: + dma_resv_unlock(obj->resv); + return ret; } -int psb_gem_get_aperture(struct drm_device *dev, void *data, - struct drm_file *file) +void psb_gem_unpin(struct psb_gem_object *pobj) { - return -EINVAL; + struct drm_gem_object *obj = &pobj->base; + struct drm_device *dev = obj->dev; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + u32 gpu_base = dev_priv->gtt.gatt_start; + unsigned long npages; + int ret; + + ret = dma_resv_lock(obj->resv, NULL); + if (drm_WARN_ONCE(dev, ret, "dma_resv_lock() failed, ret=%d\n", ret)) + return; + + WARN_ON(!pobj->in_gart); + + --pobj->in_gart; + + if (pobj->in_gart || pobj->stolen) + goto out; + + npages = obj->size / PAGE_SIZE; + + psb_mmu_remove_pages(psb_mmu_get_default_pd(dev_priv->mmu), + (gpu_base + pobj->offset), npages, 0, 0); + psb_gtt_remove_pages(dev_priv, &pobj->resource); + + /* Reset caching flags */ + set_pages_array_wb(pobj->pages, npages); + + drm_gem_put_pages(obj, pobj->pages, true, false); + pobj->pages = NULL; + +out: + dma_resv_unlock(obj->resv); } -/** - * psb_gem_dumb_map_gtt - buffer mapping for dumb interface - * @file: our drm client file - * @dev: drm device - * @handle: GEM handle to the object (from dumb_create) - * - * Do the necessary setup to allow the mapping of the frame buffer - * into user memory. We don't have to do much here at the moment. - */ -int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev, - uint32_t handle, uint64_t *offset) +static vm_fault_t psb_gem_fault(struct vm_fault *vmf); + +static void psb_gem_free_object(struct drm_gem_object *obj) { - int ret = 0; - struct drm_gem_object *obj; + struct psb_gem_object *pobj = to_psb_gem_object(obj); - if (!(dev->driver->driver_features & DRIVER_GEM)) - return -ENODEV; + /* Undo the mmap pin if we are destroying the object */ + if (pobj->mmapping) + psb_gem_unpin(pobj); - mutex_lock(&dev->struct_mutex); + drm_gem_object_release(obj); - /* GEM does all our handle to object mapping */ - obj = drm_gem_object_lookup(dev, file, handle); - if (obj == NULL) { - ret = -ENOENT; - goto unlock; - } - /* What validation is needed here ? */ + WARN_ON(pobj->in_gart && !pobj->stolen); - /* Make it mmapable */ - if (!obj->map_list.map) { - ret = drm_gem_create_mmap_offset(obj); - if (ret) - goto out; - } - /* GEM should really work out the hash offsets for us */ - *offset = (u64)obj->map_list.hash.key << PAGE_SHIFT; -out: - drm_gem_object_unreference(obj); -unlock: - mutex_unlock(&dev->struct_mutex); - return ret; + release_resource(&pobj->resource); + kfree(pobj); } -/** - * psb_gem_create - create a mappable object - * @file: the DRM file of the client - * @dev: our device - * @size: the size requested - * @handlep: returned handle (opaque number) - * - * Create a GEM object, fill in the boilerplate and attach a handle to - * it so that userspace can speak about it. This does the core work - * for the various methods that do/will create GEM objects for things - */ -static int psb_gem_create(struct drm_file *file, - struct drm_device *dev, uint64_t size, uint32_t *handlep) +static const struct vm_operations_struct psb_gem_vm_ops = { + .fault = psb_gem_fault, + .open = drm_gem_vm_open, + .close = drm_gem_vm_close, +}; + +static const struct drm_gem_object_funcs psb_gem_object_funcs = { + .free = psb_gem_free_object, + .vm_ops = &psb_gem_vm_ops, +}; + +struct psb_gem_object * +psb_gem_create(struct drm_device *dev, u64 size, const char *name, bool stolen, u32 align) { - struct gtt_range *r; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct psb_gem_object *pobj; + struct drm_gem_object *obj; int ret; - u32 handle; size = roundup(size, PAGE_SIZE); - /* 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) { - 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 so use -ENOMEM */ - dev_err(dev->dev, "GEM init failed for %lld\n", size); - return -ENOMEM; + pobj = kzalloc(sizeof(*pobj), GFP_KERNEL); + if (!pobj) + return ERR_PTR(-ENOMEM); + obj = &pobj->base; + + /* GTT resource */ + + ret = psb_gtt_allocate_resource(dev_priv, &pobj->resource, name, size, align, stolen, + &pobj->offset); + if (ret) + goto err_kfree; + + if (stolen) { + pobj->stolen = true; + pobj->in_gart = 1; } - /* Limit the object to 32bit mappings */ - mapping_set_gfp_mask(r->gem.filp->f_mapping, GFP_KERNEL | __GFP_DMA32); - /* 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; + + /* GEM object */ + + obj->funcs = &psb_gem_object_funcs; + + if (stolen) { + drm_gem_private_object_init(dev, obj, size); + } else { + ret = drm_gem_object_init(dev, obj, size); + if (ret) + goto err_release_resource; + + /* Limit the object to 32-bit mappings */ + mapping_set_gfp_mask(obj->filp->f_mapping, GFP_KERNEL | __GFP_DMA32); } - /* We have the initial and handle reference but need only one now */ - drm_gem_object_unreference(&r->gem); - *handlep = handle; - return 0; + + return pobj; + +err_release_resource: + release_resource(&pobj->resource); +err_kfree: + kfree(pobj); + return ERR_PTR(ret); } /** * psb_gem_dumb_create - create a dumb buffer - * @drm_file: our client file + * @file: our client file * @dev: our device * @args: the requested arguments copied from userspace * @@ -159,31 +200,44 @@ static int psb_gem_create(struct drm_file *file, int psb_gem_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args) { - args->pitch = ALIGN(args->width * ((args->bpp + 7) / 8), 64); - args->size = args->pitch * args->height; - return psb_gem_create(file, dev, args->size, &args->handle); -} + size_t pitch, size; + struct psb_gem_object *pobj; + struct drm_gem_object *obj; + u32 handle; + int ret; -/** - * psb_gem_dumb_destroy - destroy a dumb buffer - * @file: client file - * @dev: our DRM device - * @handle: the object handle - * - * Destroy a handle that was created via psb_gem_dumb_create, at least - * we hope it was created that way. i915 seems to assume the caller - * does the checking but that might be worth review ! FIXME - */ -int psb_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev, - uint32_t handle) -{ - /* No special work needed, drop the reference and see what falls out */ - return drm_gem_handle_delete(file, handle); + pitch = args->width * DIV_ROUND_UP(args->bpp, 8); + pitch = ALIGN(pitch, 64); + + size = pitch * args->height; + size = roundup(size, PAGE_SIZE); + if (!size) + return -EINVAL; + + pobj = psb_gem_create(dev, size, "gem", false, PAGE_SIZE); + if (IS_ERR(pobj)) + return PTR_ERR(pobj); + obj = &pobj->base; + + ret = drm_gem_handle_create(file, obj, &handle); + if (ret) + goto err_drm_gem_object_put; + + drm_gem_object_put(obj); + + args->pitch = pitch; + args->size = size; + args->handle = handle; + + return 0; + +err_drm_gem_object_put: + drm_gem_object_put(obj); + return ret; } /** * psb_gem_fault - pagefault handler for GEM objects - * @vma: the VMA of the GEM object * @vmf: fault detail * * Invoked when a fault occurs on an mmap of a GEM managed area. GEM @@ -198,11 +252,13 @@ int psb_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev, * vma->vm_private_data points to the GEM object that is backing this * mapping. */ -int psb_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +static vm_fault_t psb_gem_fault(struct vm_fault *vmf) { + struct vm_area_struct *vma = vmf->vma; struct drm_gem_object *obj; - struct gtt_range *r; - int ret; + struct psb_gem_object *pobj; + int err; + vm_fault_t ret; unsigned long pfn; pgoff_t page_offset; struct drm_device *dev; @@ -210,90 +266,167 @@ int psb_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) obj = vma->vm_private_data; /* GEM object */ dev = obj->dev; - dev_priv = dev->dev_private; + dev_priv = to_drm_psb_private(dev); - r = container_of(obj, struct gtt_range, gem); /* Get the gtt range */ + pobj = to_psb_gem_object(obj); /* Make sure we don't parallel update on a fault, nor move or remove something from beneath our feet */ - mutex_lock(&dev->struct_mutex); + mutex_lock(&dev_priv->mmap_mutex); /* For now the mmap pins the object and it stays pinned. As things stand that will do us no harm */ - if (r->mmapping == 0) { - ret = psb_gtt_pin(r); - if (ret < 0) { - dev_err(dev->dev, "gma500: pin failed: %d\n", ret); + if (pobj->mmapping == 0) { + err = psb_gem_pin(pobj); + if (err < 0) { + dev_err(dev->dev, "gma500: pin failed: %d\n", err); + ret = vmf_error(err); goto fail; } - r->mmapping = 1; + pobj->mmapping = 1; } /* 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; + page_offset = (vmf->address - vma->vm_start) >> 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; + if (pobj->stolen) + pfn = (dev_priv->stolen_base + pobj->offset) >> PAGE_SHIFT; else - pfn = page_to_pfn(r->pages[page_offset]); - ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); - + pfn = page_to_pfn(pobj->pages[page_offset]); + ret = vmf_insert_pfn(vma, vmf->address, pfn); fail: - mutex_unlock(&dev->struct_mutex); - switch (ret) { - case 0: - case -ERESTARTSYS: - case -EINTR: - return VM_FAULT_NOPAGE; - case -ENOMEM: - return VM_FAULT_OOM; - default: - return VM_FAULT_SIGBUS; - } -} + mutex_unlock(&dev_priv->mmap_mutex); -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; + return ret; } /* - * GEM interfaces for our specific client + * Memory management */ -int psb_gem_create_ioctl(struct drm_device *dev, void *data, - struct drm_file *file) + +/* Insert vram stolen pages into the GTT. */ +static void psb_gem_mm_populate_stolen(struct drm_psb_private *pdev) +{ + struct drm_device *dev = &pdev->dev; + unsigned int pfn_base; + unsigned int i, num_pages; + uint32_t pte; + + pfn_base = pdev->stolen_base >> PAGE_SHIFT; + num_pages = pdev->vram_stolen_size >> PAGE_SHIFT; + + drm_dbg(dev, "Set up %u stolen pages starting at 0x%08x, GTT offset %dK\n", + num_pages, pfn_base << PAGE_SHIFT, 0); + + for (i = 0; i < num_pages; ++i) { + pte = psb_gtt_mask_pte(pfn_base + i, PSB_MMU_CACHED_MEMORY); + iowrite32(pte, pdev->gtt_map + i); + } + + (void)ioread32(pdev->gtt_map + i - 1); +} + +int psb_gem_mm_init(struct drm_device *dev) { - struct drm_psb_gem_create *args = data; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct pci_dev *pdev = to_pci_dev(dev->dev); + unsigned long stolen_size, vram_stolen_size; + struct psb_gtt *pg; int ret; - if (args->flags & GMA_GEM_CREATE_STOLEN) { - ret = psb_gem_create_stolen(file, dev, args->size, - &args->handle); - if (ret == 0) - return 0; - /* Fall throguh */ - args->flags &= ~GMA_GEM_CREATE_STOLEN; + + mutex_init(&dev_priv->mmap_mutex); + + pg = &dev_priv->gtt; + + pci_read_config_dword(pdev, PSB_BSM, &dev_priv->stolen_base); + vram_stolen_size = pg->gtt_phys_start - dev_priv->stolen_base - PAGE_SIZE; + + stolen_size = vram_stolen_size; + + dev_dbg(dev->dev, "Stolen memory base 0x%x, size %luK\n", + dev_priv->stolen_base, vram_stolen_size / 1024); + + pg->stolen_size = stolen_size; + dev_priv->vram_stolen_size = vram_stolen_size; + + dev_priv->vram_addr = ioremap_wc(dev_priv->stolen_base, stolen_size); + if (!dev_priv->vram_addr) { + dev_err(dev->dev, "Failure to map stolen base.\n"); + ret = -ENOMEM; + goto err_mutex_destroy; } - return psb_gem_create(file, dev, args->size, &args->handle); + + psb_gem_mm_populate_stolen(dev_priv); + + return 0; + +err_mutex_destroy: + mutex_destroy(&dev_priv->mmap_mutex); + return ret; } -int psb_gem_mmap_ioctl(struct drm_device *dev, void *data, - struct drm_file *file) +void psb_gem_mm_fini(struct drm_device *dev) { - struct drm_psb_gem_mmap *args = data; - return dev->driver->dumb_map_offset(file, dev, - args->handle, &args->offset); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + + iounmap(dev_priv->vram_addr); + + mutex_destroy(&dev_priv->mmap_mutex); } +/* Re-insert all pinned GEM objects into GTT. */ +static void psb_gem_mm_populate_resources(struct drm_psb_private *pdev) +{ + unsigned int restored = 0, total = 0, size = 0; + struct resource *r = pdev->gtt_mem->child; + struct drm_device *dev = &pdev->dev; + struct psb_gem_object *pobj; + + while (r) { + /* + * TODO: GTT restoration needs a refactoring, so that we don't have to touch + * struct psb_gem_object here. The type represents a GEM object and is + * not related to the GTT itself. + */ + pobj = container_of(r, struct psb_gem_object, resource); + if (pobj->pages) { + psb_gtt_insert_pages(pdev, &pobj->resource, pobj->pages); + size += resource_size(&pobj->resource); + ++restored; + } + r = r->sibling; + ++total; + } + + drm_dbg(dev, "Restored %u of %u gtt ranges (%u KB)", restored, total, (size / 1024)); +} + +int psb_gem_mm_resume(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct pci_dev *pdev = to_pci_dev(dev->dev); + unsigned long stolen_size, vram_stolen_size; + struct psb_gtt *pg; + + pg = &dev_priv->gtt; + + pci_read_config_dword(pdev, PSB_BSM, &dev_priv->stolen_base); + vram_stolen_size = pg->gtt_phys_start - dev_priv->stolen_base - PAGE_SIZE; + + stolen_size = vram_stolen_size; + + dev_dbg(dev->dev, "Stolen memory base 0x%x, size %luK\n", dev_priv->stolen_base, + vram_stolen_size / 1024); + + if (stolen_size != pg->stolen_size) { + dev_err(dev->dev, "GTT resume error.\n"); + return -EINVAL; + } + + psb_gem_mm_populate_stolen(dev_priv); + psb_gem_mm_populate_resources(dev_priv); + + return 0; +} diff --git a/drivers/gpu/drm/gma500/gem.h b/drivers/gpu/drm/gma500/gem.h new file mode 100644 index 000000000000..27df6ff4ed37 --- /dev/null +++ b/drivers/gpu/drm/gma500/gem.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/************************************************************************** + * Copyright (c) 2014 Patrik Jakobsson + * All Rights Reserved. + * + **************************************************************************/ + +#ifndef _GEM_H +#define _GEM_H + +#include <linux/kernel.h> + +#include <drm/drm_gem.h> + +struct drm_device; + +/* + * PSB GEM object + */ + +struct psb_gem_object { + struct drm_gem_object base; + + struct resource resource; /* GTT resource for our allocation */ + u32 offset; /* GTT offset of our object */ + int in_gart; /* Currently in the GART (ref ct) */ + bool stolen; /* Backed from stolen RAM */ + bool mmapping; /* Is mmappable */ + struct page **pages; /* Backing pages if present */ +}; + +static inline struct psb_gem_object *to_psb_gem_object(struct drm_gem_object *obj) +{ + return container_of(obj, struct psb_gem_object, base); +} + +struct psb_gem_object * +psb_gem_create(struct drm_device *dev, u64 size, const char *name, bool stolen, u32 align); + +int psb_gem_pin(struct psb_gem_object *pobj); +void psb_gem_unpin(struct psb_gem_object *pobj); + +/* + * Memory management + */ + +int psb_gem_mm_init(struct drm_device *dev); +void psb_gem_mm_fini(struct drm_device *dev); +int psb_gem_mm_resume(struct drm_device *dev); + +#endif diff --git a/drivers/gpu/drm/gma500/gma_device.c b/drivers/gpu/drm/gma500/gma_device.c new file mode 100644 index 000000000000..954f3a275d81 --- /dev/null +++ b/drivers/gpu/drm/gma500/gma_device.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0-only +/************************************************************************** + * Copyright (c) 2011, Intel Corporation. + * All Rights Reserved. + * + **************************************************************************/ + +#include "psb_drv.h" +#include "gma_device.h" + +void gma_get_core_freq(struct drm_device *dev) +{ + uint32_t clock; + struct pci_dev *pdev = to_pci_dev(dev->dev); + struct pci_dev *pci_root = + pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus), + 0, 0); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + + /*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; + break; + default: + dev_priv->core_freq = 0; + } +} diff --git a/drivers/gpu/drm/gma500/gma_device.h b/drivers/gpu/drm/gma500/gma_device.h new file mode 100644 index 000000000000..a8cf31d4b814 --- /dev/null +++ b/drivers/gpu/drm/gma500/gma_device.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/************************************************************************** + * Copyright (c) 2011, Intel Corporation. + * All Rights Reserved. + * + **************************************************************************/ + +#ifndef _GMA_DEVICE_H +#define _GMA_DEVICE_H +struct drm_device; + +extern void gma_get_core_freq(struct drm_device *dev); + +#endif diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c new file mode 100644 index 000000000000..f65e90d890f4 --- /dev/null +++ b/drivers/gpu/drm/gma500/gma_display.c @@ -0,0 +1,811 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright © 2006-2011 Intel Corporation + * + * Authors: + * Eric Anholt <eric@anholt.net> + * Patrik Jakobsson <patrik.r.jakobsson@gmail.com> + */ + +#include <linux/delay.h> +#include <linux/highmem.h> + +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_framebuffer.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_vblank.h> + +#include "framebuffer.h" +#include "gem.h" +#include "gma_display.h" +#include "psb_irq.h" +#include "psb_intel_drv.h" +#include "psb_intel_reg.h" + +/* + * Returns whether any output on the specified pipe is of the specified type + */ +bool gma_pipe_has_type(struct drm_crtc *crtc, int type) +{ + struct drm_device *dev = crtc->dev; + struct drm_connector_list_iter conn_iter; + struct drm_connector *connector; + + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + if (connector->encoder && connector->encoder->crtc == crtc) { + struct gma_encoder *gma_encoder = + gma_attached_encoder(connector); + if (gma_encoder->type == type) { + drm_connector_list_iter_end(&conn_iter); + return true; + } + } + } + drm_connector_list_iter_end(&conn_iter); + + return false; +} + +void gma_wait_for_vblank(struct drm_device *dev) +{ + /* Wait for 20ms, i.e. one cycle at 50hz. */ + mdelay(20); +} + +int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb) +{ + struct drm_device *dev = crtc->dev; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + struct drm_framebuffer *fb = crtc->primary->fb; + struct psb_gem_object *pobj; + int pipe = gma_crtc->pipe; + const struct psb_offset *map = &dev_priv->regmap[pipe]; + unsigned long start, offset; + u32 dspcntr; + int ret = 0; + + if (!gma_power_begin(dev, true)) + return 0; + + /* no fb bound */ + if (!fb) { + dev_err(dev->dev, "No FB bound\n"); + goto gma_pipe_cleaner; + } + + pobj = to_psb_gem_object(fb->obj[0]); + + /* We are displaying this buffer, make sure it is actually loaded + into the GTT */ + ret = psb_gem_pin(pobj); + if (ret < 0) + goto gma_pipe_set_base_exit; + start = pobj->offset; + offset = y * fb->pitches[0] + x * fb->format->cpp[0]; + + REG_WRITE(map->stride, fb->pitches[0]); + + dspcntr = REG_READ(map->cntr); + dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; + + switch (fb->format->cpp[0] * 8) { + case 8: + dspcntr |= DISPPLANE_8BPP; + break; + case 16: + if (fb->format->depth == 15) + dspcntr |= DISPPLANE_15_16BPP; + else + dspcntr |= DISPPLANE_16BPP; + break; + case 24: + case 32: + dspcntr |= DISPPLANE_32BPP_NO_ALPHA; + break; + default: + dev_err(dev->dev, "Unknown color depth\n"); + ret = -EINVAL; + goto gma_pipe_set_base_exit; + } + REG_WRITE(map->cntr, dspcntr); + + dev_dbg(dev->dev, + "Writing base %08lX %08lX %d %d\n", start, offset, x, y); + + /* FIXME: Investigate whether this really is the base for psb and why + the linear offset is named base for the other chips. map->surf + should be the base and map->linoff the offset for all chips */ + if (IS_PSB(dev)) { + REG_WRITE(map->base, offset + start); + REG_READ(map->base); + } else { + REG_WRITE(map->base, offset); + REG_READ(map->base); + REG_WRITE(map->surf, start); + REG_READ(map->surf); + } + +gma_pipe_cleaner: + /* If there was a previous display we can now unpin it */ + if (old_fb) + psb_gem_unpin(to_psb_gem_object(old_fb->obj[0])); + +gma_pipe_set_base_exit: + gma_power_end(dev); + return ret; +} + +/* Loads the palette/gamma unit for the CRTC with the prepared values */ +void gma_crtc_load_lut(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + const struct psb_offset *map = &dev_priv->regmap[gma_crtc->pipe]; + int palreg = map->palette; + u16 *r, *g, *b; + int i; + + /* The clocks have to be on to load the palette. */ + if (!crtc->enabled) + return; + + r = crtc->gamma_store; + g = r + crtc->gamma_size; + b = g + crtc->gamma_size; + + if (gma_power_begin(dev, false)) { + for (i = 0; i < 256; i++) { + REG_WRITE(palreg + 4 * i, + (((*r++ >> 8) + gma_crtc->lut_adj[i]) << 16) | + (((*g++ >> 8) + gma_crtc->lut_adj[i]) << 8) | + ((*b++ >> 8) + gma_crtc->lut_adj[i])); + } + gma_power_end(dev); + } else { + for (i = 0; i < 256; i++) { + /* FIXME: Why pipe[0] and not pipe[..._crtc->pipe]? */ + dev_priv->regs.pipe[0].palette[i] = + (((*r++ >> 8) + gma_crtc->lut_adj[i]) << 16) | + (((*g++ >> 8) + gma_crtc->lut_adj[i]) << 8) | + ((*b++ >> 8) + gma_crtc->lut_adj[i]); + } + + } +} + +static int gma_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, + u16 *blue, u32 size, + struct drm_modeset_acquire_ctx *ctx) +{ + gma_crtc_load_lut(crtc); + + return 0; +} + +/* + * 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. + */ +void gma_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + struct drm_device *dev = crtc->dev; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + int pipe = gma_crtc->pipe; + const struct psb_offset *map = &dev_priv->regmap[pipe]; + u32 temp; + + /* 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. + */ + + if (IS_CDV(dev)) + dev_priv->ops->disable_sr(dev); + + switch (mode) { + case DRM_MODE_DPMS_ON: + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + if (gma_crtc->active) + break; + + gma_crtc->active = true; + + /* Enable the DPLL */ + temp = REG_READ(map->dpll); + if ((temp & DPLL_VCO_ENABLE) == 0) { + REG_WRITE(map->dpll, temp); + REG_READ(map->dpll); + /* Wait for the clocks to stabilize. */ + udelay(150); + REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE); + REG_READ(map->dpll); + /* Wait for the clocks to stabilize. */ + udelay(150); + REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE); + REG_READ(map->dpll); + /* Wait for the clocks to stabilize. */ + udelay(150); + } + + /* Enable the plane */ + temp = REG_READ(map->cntr); + if ((temp & DISPLAY_PLANE_ENABLE) == 0) { + REG_WRITE(map->cntr, + temp | DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + REG_WRITE(map->base, REG_READ(map->base)); + } + + udelay(150); + + /* Enable the pipe */ + temp = REG_READ(map->conf); + if ((temp & PIPEACONF_ENABLE) == 0) + REG_WRITE(map->conf, temp | PIPEACONF_ENABLE); + + temp = REG_READ(map->status); + temp &= ~(0xFFFF); + temp |= PIPE_FIFO_UNDERRUN; + REG_WRITE(map->status, temp); + REG_READ(map->status); + + gma_crtc_load_lut(crtc); + + /* Give the overlay scaler a chance to enable + * if it's on this pipe */ + /* psb_intel_crtc_dpms_video(crtc, true); TODO */ + + drm_crtc_vblank_on(crtc); + break; + case DRM_MODE_DPMS_OFF: + if (!gma_crtc->active) + break; + + gma_crtc->active = false; + + /* 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); + + /* Turn off vblank interrupts */ + drm_crtc_vblank_off(crtc); + + /* Wait for vblank for the disable to take effect */ + gma_wait_for_vblank(dev); + + /* Disable plane */ + temp = REG_READ(map->cntr); + if ((temp & DISPLAY_PLANE_ENABLE) != 0) { + REG_WRITE(map->cntr, + temp & ~DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + REG_WRITE(map->base, REG_READ(map->base)); + REG_READ(map->base); + } + + /* Disable pipe */ + temp = REG_READ(map->conf); + if ((temp & PIPEACONF_ENABLE) != 0) { + REG_WRITE(map->conf, temp & ~PIPEACONF_ENABLE); + REG_READ(map->conf); + } + + /* Wait for vblank for the disable to take effect. */ + gma_wait_for_vblank(dev); + + udelay(150); + + /* Disable DPLL */ + temp = REG_READ(map->dpll); + if ((temp & DPLL_VCO_ENABLE) != 0) { + REG_WRITE(map->dpll, temp & ~DPLL_VCO_ENABLE); + REG_READ(map->dpll); + } + + /* Wait for the clocks to turn off. */ + udelay(150); + break; + } + + if (IS_CDV(dev)) + dev_priv->ops->update_wm(dev, crtc); + + /* Set FIFO watermarks */ + REG_WRITE(DSPARB, 0x3F3E); +} + +static int gma_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 drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + int pipe = gma_crtc->pipe; + uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR; + uint32_t base = (pipe == 0) ? CURABASE : CURBBASE; + uint32_t temp; + size_t addr = 0; + struct psb_gem_object *pobj; + struct psb_gem_object *cursor_pobj = gma_crtc->cursor_pobj; + struct drm_gem_object *obj; + void *tmp_dst; + int ret = 0, i, cursor_pages; + + /* If we didn't get a handle then turn the cursor off */ + if (!handle) { + 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 (gma_crtc->cursor_obj) { + pobj = to_psb_gem_object(gma_crtc->cursor_obj); + psb_gem_unpin(pobj); + drm_gem_object_put(gma_crtc->cursor_obj); + gma_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(file_priv, handle); + if (!obj) { + ret = -ENOENT; + goto unlock; + } + + if (obj->size < width * height * 4) { + dev_dbg(dev->dev, "Buffer is too small\n"); + ret = -ENOMEM; + goto unref_cursor; + } + + pobj = to_psb_gem_object(obj); + + /* Pin the memory into the GTT */ + ret = psb_gem_pin(pobj); + if (ret) { + dev_err(dev->dev, "Can not pin down handle 0x%x\n", handle); + goto unref_cursor; + } + + if (dev_priv->ops->cursor_needs_phys) { + if (!cursor_pobj) { + dev_err(dev->dev, "No hardware cursor mem available"); + ret = -ENOMEM; + goto unref_cursor; + } + + cursor_pages = obj->size / PAGE_SIZE; + if (cursor_pages > 4) + cursor_pages = 4; /* Prevent overflow */ + + /* Copy the cursor to cursor mem */ + tmp_dst = dev_priv->vram_addr + cursor_pobj->offset; + for (i = 0; i < cursor_pages; i++) { + memcpy_from_page(tmp_dst, pobj->pages[i], 0, PAGE_SIZE); + tmp_dst += PAGE_SIZE; + } + + addr = gma_crtc->cursor_addr; + } else { + addr = pobj->offset; + gma_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 bo */ + if (gma_crtc->cursor_obj) { + pobj = to_psb_gem_object(gma_crtc->cursor_obj); + psb_gem_unpin(pobj); + drm_gem_object_put(gma_crtc->cursor_obj); + } + + gma_crtc->cursor_obj = obj; +unlock: + return ret; + +unref_cursor: + drm_gem_object_put(obj); + return ret; +} + +static int gma_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) +{ + struct drm_device *dev = crtc->dev; + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + int pipe = gma_crtc->pipe; + uint32_t temp = 0; + uint32_t addr; + + 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 = gma_crtc->cursor_addr; + + if (gma_power_begin(dev, false)) { + REG_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp); + REG_WRITE((pipe == 0) ? CURABASE : CURBBASE, addr); + gma_power_end(dev); + } + return 0; +} + +void gma_crtc_prepare(struct drm_crtc *crtc) +{ + const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); +} + +void gma_crtc_commit(struct drm_crtc *crtc) +{ + const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); +} + +void gma_crtc_disable(struct drm_crtc *crtc) +{ + struct psb_gem_object *pobj; + const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); + + if (crtc->primary->fb) { + pobj = to_psb_gem_object(crtc->primary->fb->obj[0]); + psb_gem_unpin(pobj); + } +} + +void gma_crtc_destroy(struct drm_crtc *crtc) +{ + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + + if (gma_crtc->cursor_pobj) + drm_gem_object_put(&gma_crtc->cursor_pobj->base); + + kfree(gma_crtc->crtc_state); + drm_crtc_cleanup(crtc); + kfree(gma_crtc); +} + +int gma_crtc_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, + uint32_t page_flip_flags, + struct drm_modeset_acquire_ctx *ctx) +{ + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + struct drm_framebuffer *current_fb = crtc->primary->fb; + struct drm_framebuffer *old_fb = crtc->primary->old_fb; + const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + struct drm_device *dev = crtc->dev; + unsigned long flags; + int ret; + + if (!crtc_funcs->mode_set_base) + return -EINVAL; + + /* Using mode_set_base requires the new fb to be set already. */ + crtc->primary->fb = fb; + + if (event) { + spin_lock_irqsave(&dev->event_lock, flags); + + WARN_ON(drm_crtc_vblank_get(crtc) != 0); + + gma_crtc->page_flip_event = event; + spin_unlock_irqrestore(&dev->event_lock, flags); + + /* Call this locked if we want an event at vblank interrupt. */ + ret = crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y, old_fb); + if (ret) { + spin_lock_irqsave(&dev->event_lock, flags); + if (gma_crtc->page_flip_event) { + gma_crtc->page_flip_event = NULL; + drm_crtc_vblank_put(crtc); + } + spin_unlock_irqrestore(&dev->event_lock, flags); + } + } else { + ret = crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y, old_fb); + } + + /* Restore previous fb in case of failure. */ + if (ret) + crtc->primary->fb = current_fb; + + return ret; +} + +const struct drm_crtc_funcs gma_crtc_funcs = { + .cursor_set = gma_crtc_cursor_set, + .cursor_move = gma_crtc_cursor_move, + .gamma_set = gma_crtc_gamma_set, + .set_config = drm_crtc_helper_set_config, + .destroy = gma_crtc_destroy, + .page_flip = gma_crtc_page_flip, + .enable_vblank = gma_crtc_enable_vblank, + .disable_vblank = gma_crtc_disable_vblank, + .get_vblank_counter = gma_crtc_get_vblank_counter, +}; + +/* + * Save HW states of given crtc + */ +void gma_crtc_save(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + struct psb_intel_crtc_state *crtc_state = gma_crtc->crtc_state; + const struct psb_offset *map = &dev_priv->regmap[gma_crtc->pipe]; + uint32_t palette_reg; + int i; + + if (!crtc_state) { + dev_err(dev->dev, "No CRTC state found\n"); + return; + } + + crtc_state->saveDSPCNTR = REG_READ(map->cntr); + crtc_state->savePIPECONF = REG_READ(map->conf); + crtc_state->savePIPESRC = REG_READ(map->src); + crtc_state->saveFP0 = REG_READ(map->fp0); + crtc_state->saveFP1 = REG_READ(map->fp1); + crtc_state->saveDPLL = REG_READ(map->dpll); + crtc_state->saveHTOTAL = REG_READ(map->htotal); + crtc_state->saveHBLANK = REG_READ(map->hblank); + crtc_state->saveHSYNC = REG_READ(map->hsync); + crtc_state->saveVTOTAL = REG_READ(map->vtotal); + crtc_state->saveVBLANK = REG_READ(map->vblank); + crtc_state->saveVSYNC = REG_READ(map->vsync); + crtc_state->saveDSPSTRIDE = REG_READ(map->stride); + + /* NOTE: DSPSIZE DSPPOS only for psb */ + crtc_state->saveDSPSIZE = REG_READ(map->size); + crtc_state->saveDSPPOS = REG_READ(map->pos); + + crtc_state->saveDSPBASE = REG_READ(map->base); + + palette_reg = map->palette; + for (i = 0; i < 256; ++i) + crtc_state->savePalette[i] = REG_READ(palette_reg + (i << 2)); +} + +/* + * Restore HW states of given crtc + */ +void gma_crtc_restore(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + struct psb_intel_crtc_state *crtc_state = gma_crtc->crtc_state; + const struct psb_offset *map = &dev_priv->regmap[gma_crtc->pipe]; + uint32_t palette_reg; + int i; + + if (!crtc_state) { + dev_err(dev->dev, "No crtc state\n"); + return; + } + + if (crtc_state->saveDPLL & DPLL_VCO_ENABLE) { + REG_WRITE(map->dpll, + crtc_state->saveDPLL & ~DPLL_VCO_ENABLE); + REG_READ(map->dpll); + udelay(150); + } + + REG_WRITE(map->fp0, crtc_state->saveFP0); + REG_READ(map->fp0); + + REG_WRITE(map->fp1, crtc_state->saveFP1); + REG_READ(map->fp1); + + REG_WRITE(map->dpll, crtc_state->saveDPLL); + REG_READ(map->dpll); + udelay(150); + + REG_WRITE(map->htotal, crtc_state->saveHTOTAL); + REG_WRITE(map->hblank, crtc_state->saveHBLANK); + REG_WRITE(map->hsync, crtc_state->saveHSYNC); + REG_WRITE(map->vtotal, crtc_state->saveVTOTAL); + REG_WRITE(map->vblank, crtc_state->saveVBLANK); + REG_WRITE(map->vsync, crtc_state->saveVSYNC); + REG_WRITE(map->stride, crtc_state->saveDSPSTRIDE); + + REG_WRITE(map->size, crtc_state->saveDSPSIZE); + REG_WRITE(map->pos, crtc_state->saveDSPPOS); + + REG_WRITE(map->src, crtc_state->savePIPESRC); + REG_WRITE(map->base, crtc_state->saveDSPBASE); + REG_WRITE(map->conf, crtc_state->savePIPECONF); + + gma_wait_for_vblank(dev); + + REG_WRITE(map->cntr, crtc_state->saveDSPCNTR); + REG_WRITE(map->base, crtc_state->saveDSPBASE); + + gma_wait_for_vblank(dev); + + palette_reg = map->palette; + for (i = 0; i < 256; ++i) + REG_WRITE(palette_reg + (i << 2), crtc_state->savePalette[i]); +} + +void gma_encoder_prepare(struct drm_encoder *encoder) +{ + const struct drm_encoder_helper_funcs *encoder_funcs = + encoder->helper_private; + /* lvds has its own version of prepare see psb_intel_lvds_prepare */ + encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF); +} + +void gma_encoder_commit(struct drm_encoder *encoder) +{ + const struct drm_encoder_helper_funcs *encoder_funcs = + encoder->helper_private; + /* lvds has its own version of commit see psb_intel_lvds_commit */ + encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); +} + +void gma_encoder_destroy(struct drm_encoder *encoder) +{ + struct gma_encoder *intel_encoder = to_gma_encoder(encoder); + + drm_encoder_cleanup(encoder); + kfree(intel_encoder); +} + +/* Currently there is only a 1:1 mapping of encoders and connectors */ +struct drm_encoder *gma_best_encoder(struct drm_connector *connector) +{ + struct gma_encoder *gma_encoder = gma_attached_encoder(connector); + + return &gma_encoder->base; +} + +void gma_connector_attach_encoder(struct gma_connector *connector, + struct gma_encoder *encoder) +{ + connector->encoder = encoder; + drm_connector_attach_encoder(&connector->base, + &encoder->base); +} + +#define GMA_PLL_INVALID(s) { /* DRM_ERROR(s); */ return false; } + +bool gma_pll_is_valid(struct drm_crtc *crtc, + const struct gma_limit_t *limit, + struct gma_clock_t *clock) +{ + if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1) + GMA_PLL_INVALID("p1 out of range"); + if (clock->p < limit->p.min || limit->p.max < clock->p) + GMA_PLL_INVALID("p out of range"); + if (clock->m2 < limit->m2.min || limit->m2.max < clock->m2) + GMA_PLL_INVALID("m2 out of range"); + if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1) + GMA_PLL_INVALID("m1 out of range"); + /* On CDV m1 is always 0 */ + if (clock->m1 <= clock->m2 && clock->m1 != 0) + GMA_PLL_INVALID("m1 <= m2 && m1 != 0"); + if (clock->m < limit->m.min || limit->m.max < clock->m) + GMA_PLL_INVALID("m out of range"); + if (clock->n < limit->n.min || limit->n.max < clock->n) + GMA_PLL_INVALID("n out of range"); + if (clock->vco < limit->vco.min || limit->vco.max < clock->vco) + GMA_PLL_INVALID("vco out of range"); + /* 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) + GMA_PLL_INVALID("dot out of range"); + + return true; +} + +bool gma_find_best_pll(const struct gma_limit_t *limit, + struct drm_crtc *crtc, int target, int refclk, + struct gma_clock_t *best_clock) +{ + struct drm_device *dev = crtc->dev; + const struct gma_clock_funcs *clock_funcs = + to_gma_crtc(crtc)->clock_funcs; + struct gma_clock_t clock; + int err = target; + + if (gma_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)); + + /* m1 is always 0 on CDV so the outmost loop will run just once */ + for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) { + for (clock.m2 = limit->m2.min; + (clock.m2 < clock.m1 || clock.m1 == 0) && + clock.m2 <= limit->m2.max; clock.m2++) { + for (clock.n = limit->n.min; + clock.n <= limit->n.max; clock.n++) { + for (clock.p1 = limit->p1.min; + clock.p1 <= limit->p1.max; + clock.p1++) { + int this_err; + + clock_funcs->clock(refclk, &clock); + + if (!clock_funcs->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; +} diff --git a/drivers/gpu/drm/gma500/gma_display.h b/drivers/gpu/drm/gma500/gma_display.h new file mode 100644 index 000000000000..1188a8d61caf --- /dev/null +++ b/drivers/gpu/drm/gma500/gma_display.h @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright © 2006-2011 Intel Corporation + * + * Authors: + * Eric Anholt <eric@anholt.net> + * Patrik Jakobsson <patrik.r.jakobsson@gmail.com> + */ + +#ifndef _GMA_DISPLAY_H_ +#define _GMA_DISPLAY_H_ + +#include <linux/pm_runtime.h> +#include <drm/drm_vblank.h> + +struct drm_encoder; +struct drm_mode_set; + +struct gma_clock_t { + /* given values */ + int n; + int m1, m2; + int p1, p2; + /* derived values */ + int dot; + int vco; + int m; + int p; +}; + +struct gma_range_t { + int min, max; +}; + +struct gma_p2_t { + int dot_limit; + int p2_slow, p2_fast; +}; + +struct gma_limit_t { + struct gma_range_t dot, vco, n, m, m1, m2, p, p1; + struct gma_p2_t p2; + bool (*find_pll)(const struct gma_limit_t *, struct drm_crtc *, + int target, int refclk, + struct gma_clock_t *best_clock); +}; + +struct gma_clock_funcs { + void (*clock)(int refclk, struct gma_clock_t *clock); + const struct gma_limit_t *(*limit)(struct drm_crtc *crtc, int refclk); + bool (*pll_is_valid)(struct drm_crtc *crtc, + const struct gma_limit_t *limit, + struct gma_clock_t *clock); +}; + +/* Common pipe related functions */ +extern bool gma_pipe_has_type(struct drm_crtc *crtc, int type); +extern void gma_wait_for_vblank(struct drm_device *dev); +extern int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb); +extern void gma_crtc_load_lut(struct drm_crtc *crtc); +extern void gma_crtc_dpms(struct drm_crtc *crtc, int mode); +extern void gma_crtc_prepare(struct drm_crtc *crtc); +extern void gma_crtc_commit(struct drm_crtc *crtc); +extern void gma_crtc_disable(struct drm_crtc *crtc); +extern void gma_crtc_destroy(struct drm_crtc *crtc); +extern int gma_crtc_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, + uint32_t page_flip_flags, + struct drm_modeset_acquire_ctx *ctx); + +extern void gma_crtc_save(struct drm_crtc *crtc); +extern void gma_crtc_restore(struct drm_crtc *crtc); + +extern const struct drm_crtc_funcs gma_crtc_funcs; + +extern void gma_encoder_prepare(struct drm_encoder *encoder); +extern void gma_encoder_commit(struct drm_encoder *encoder); +extern void gma_encoder_destroy(struct drm_encoder *encoder); + +/* Common clock related functions */ +extern const struct gma_limit_t *gma_limit(struct drm_crtc *crtc, int refclk); +extern bool gma_pll_is_valid(struct drm_crtc *crtc, + const struct gma_limit_t *limit, + struct gma_clock_t *clock); +extern bool gma_find_best_pll(const struct gma_limit_t *limit, + struct drm_crtc *crtc, int target, int refclk, + struct gma_clock_t *best_clock); +#endif diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c index 1f82183536a3..379bc218aa6b 100644 --- a/drivers/gpu/drm/gma500/gtt.c +++ b/drivers/gpu/drm/gma500/gtt.c @@ -1,26 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2007, 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. - * * Authors: Thomas Hellstrom <thomas-at-tungstengraphics.com> * Alan Cox <alan@linux.intel.com> */ -#include <drm/drmP.h> -#include <linux/shmem_fs.h> +#include "gem.h" /* TODO: for struct psb_gem_object, see psb_gtt_restore() */ #include "psb_drv.h" @@ -28,6 +15,33 @@ * GTT resource allocator - manage page mappings in GTT space */ +int psb_gtt_allocate_resource(struct drm_psb_private *pdev, struct resource *res, + const char *name, resource_size_t size, resource_size_t align, + bool stolen, u32 *offset) +{ + struct resource *root = pdev->gtt_mem; + resource_size_t start, end; + int ret; + + if (stolen) { + /* The start of the GTT is backed by stolen pages. */ + start = root->start; + end = root->start + pdev->gtt.stolen_size - 1; + } else { + /* The rest is backed by system pages. */ + start = root->start + pdev->gtt.stolen_size; + end = root->end; + } + + res->name = name; + ret = allocate_resource(root, res, size, start, end, align, NULL, NULL); + if (ret) + return ret; + *offset = res->start - root->start; + + return 0; +} + /** * psb_gtt_mask_pte - generate GTT pte entry * @pfn: page number to encode @@ -35,7 +49,7 @@ * * Set the GTT entry for the appropriate memory type. */ -static inline uint32_t psb_gtt_mask_pte(uint32_t pfn, int type) +uint32_t psb_gtt_mask_pte(uint32_t pfn, int type) { uint32_t mask = PSB_PTE_VALID; @@ -53,535 +67,246 @@ static inline uint32_t psb_gtt_mask_pte(uint32_t pfn, int type) return (pfn << PAGE_SHIFT) | mask; } -/** - * 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 GTT offset of the page table - * entries for this gtt_range - */ -static u32 __iomem *psb_gtt_entry(struct drm_device *dev, struct gtt_range *r) +static u32 __iomem *psb_gtt_entry(struct drm_psb_private *pdev, const struct resource *res) { - struct drm_psb_private *dev_priv = dev->dev_private; - unsigned long offset; + unsigned long offset = res->start - pdev->gtt_mem->start; - offset = r->resource.start - dev_priv->gtt_mem->start; - - return dev_priv->gtt_map + (offset >> PAGE_SHIFT); + return pdev->gtt_map + (offset >> PAGE_SHIFT); } -/** - * 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 GTT. This is protected via the gtt mutex which the caller - * must hold. - */ -static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r, - int resume) +/* Acquires GTT mutex internally. */ +void psb_gtt_insert_pages(struct drm_psb_private *pdev, const struct resource *res, + struct page **pages) { + resource_size_t npages, i; u32 __iomem *gtt_slot; u32 pte; - struct page **pages; - int i; - if (r->pages == NULL) { - WARN_ON(1); - return -EINVAL; - } + mutex_lock(&pdev->gtt_mutex); - WARN_ON(r->stolen); /* refcount these maybe ? */ + /* Write our page entries into the GTT itself */ - gtt_slot = psb_gtt_entry(dev, r); - pages = r->pages; + npages = resource_size(res) >> PAGE_SHIFT; + gtt_slot = psb_gtt_entry(pdev, res); - if (!resume) { - /* Make sure changes are visible to the GPU */ - set_pages_array_wc(pages, r->npage); + for (i = 0; i < npages; ++i, ++gtt_slot) { + pte = psb_gtt_mask_pte(page_to_pfn(pages[i]), PSB_MMU_CACHED_MEMORY); + iowrite32(pte, gtt_slot); } - /* Write our page entries into the GTT itself */ - for (i = r->roll; i < r->npage; i++) { - pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0); - iowrite32(pte, gtt_slot++); - } - for (i = 0; i < r->roll; i++) { - pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0); - iowrite32(pte, gtt_slot++); - } /* Make sure all the entries are set before we return */ ioread32(gtt_slot - 1); - return 0; + mutex_unlock(&pdev->gtt_mutex); } -/** - * psb_gtt_remove - remove an object from the GTT - * @dev: our DRM device - * @r: our GTT range - * - * Remove a preallocated GTT range from the GTT. Overwrite all the - * page table entries with the dummy page. This is protected via the gtt - * mutex which the caller must hold. - */ -static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r) +/* Acquires GTT mutex internally. */ +void psb_gtt_remove_pages(struct drm_psb_private *pdev, const struct resource *res) { - struct drm_psb_private *dev_priv = dev->dev_private; + resource_size_t npages, i; u32 __iomem *gtt_slot; u32 pte; - 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); - for (i = 0; i < r->npage; i++) - iowrite32(pte, gtt_slot++); - ioread32(gtt_slot - 1); - set_pages_array_wb(r->pages, r->npage); -} - -/** - * psb_gtt_roll - set scrolling position - * @dev: our DRM device - * @r: the gtt mapping we are using - * @roll: roll offset - * - * Roll an existing pinned mapping by moving the pages through the GTT. - * This allows us to implement hardware scrolling on the consoles without - * a 2D engine - */ -void psb_gtt_roll(struct drm_device *dev, struct gtt_range *r, int roll) -{ - u32 __iomem *gtt_slot; - u32 pte; - int i; + mutex_lock(&pdev->gtt_mutex); - if (roll >= r->npage) { - WARN_ON(1); - return; - } + /* Install scratch page for the resource */ - r->roll = roll; + pte = psb_gtt_mask_pte(page_to_pfn(pdev->scratch_page), PSB_MMU_CACHED_MEMORY); - /* Not currently in the GTT - no worry we will write the mapping at - the right position when it gets pinned */ - if (!r->stolen && !r->in_gart) - return; + npages = resource_size(res) >> PAGE_SHIFT; + gtt_slot = psb_gtt_entry(pdev, res); - gtt_slot = psb_gtt_entry(dev, r); + for (i = 0; i < npages; ++i, ++gtt_slot) + iowrite32(pte, gtt_slot); - for (i = r->roll; i < r->npage; i++) { - pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0); - iowrite32(pte, gtt_slot++); - } - for (i = 0; i < r->roll; i++) { - pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0); - iowrite32(pte, gtt_slot++); - } + /* Make sure all the entries are set before we return */ ioread32(gtt_slot - 1); -} -/** - * psb_gtt_attach_pages - attach and pin GEM pages - * @gt: the gtt range - * - * 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. This is protected - * via the gtt mutex which the caller must hold. - */ -static int psb_gtt_attach_pages(struct gtt_range *gt) -{ - struct inode *inode; - struct address_space *mapping; - int i; - struct page *p; - int pages = gt->gem.size / PAGE_SIZE; - - WARN_ON(gt->pages); - - /* This is the shared memory object that backs the GEM resource */ - inode = file_inode(gt->gem.filp); - mapping = inode->i_mapping; - - gt->pages = kmalloc(pages * sizeof(struct page *), GFP_KERNEL); - if (gt->pages == NULL) - return -ENOMEM; - gt->npage = pages; - - for (i = 0; i < pages; i++) { - p = shmem_read_mapping_page(mapping, i); - if (IS_ERR(p)) - goto err; - gt->pages[i] = p; - } - return 0; - -err: - while (i--) - page_cache_release(gt->pages[i]); - kfree(gt->pages); - gt->pages = NULL; - return PTR_ERR(p); + mutex_unlock(&pdev->gtt_mutex); } -/** - * psb_gtt_detach_pages - attach and pin GEM pages - * @gt: the gtt range - * - * Undo the effect of psb_gtt_attach_pages. At this point the pages - * must have been removed from the GTT as they could now be paged out - * and move bus address. This is protected via the gtt mutex which the - * caller must hold. - */ -static void psb_gtt_detach_pages(struct gtt_range *gt) +static int psb_gtt_enable(struct drm_psb_private *dev_priv) { - int i; - for (i = 0; i < gt->npage; i++) { - /* FIXME: do we need to force dirty */ - set_page_dirty(gt->pages[i]); - page_cache_release(gt->pages[i]); - } - kfree(gt->pages); - gt->pages = NULL; -} + struct drm_device *dev = &dev_priv->dev; + struct pci_dev *pdev = to_pci_dev(dev->dev); + int ret; -/** - * psb_gtt_pin - pin pages into the GTT - * @gt: range to pin - * - * Pin a set of pages into the GTT. The pins are refcounted so that - * multiple pins need multiple unpins to undo. - * - * Non GEM backed objects treat this as a no-op as they are always GTT - * backed objects. - */ -int psb_gtt_pin(struct gtt_range *gt) -{ - int ret = 0; - struct drm_device *dev = gt->gem.dev; - struct drm_psb_private *dev_priv = dev->dev_private; - - mutex_lock(&dev_priv->gtt_mutex); - - if (gt->in_gart == 0 && gt->stolen == 0) { - ret = psb_gtt_attach_pages(gt); - if (ret < 0) - goto out; - ret = psb_gtt_insert(dev, gt, 0); - if (ret < 0) { - psb_gtt_detach_pages(gt); - goto out; - } - } - gt->in_gart++; -out: - mutex_unlock(&dev_priv->gtt_mutex); - return ret; -} + ret = pci_read_config_word(pdev, PSB_GMCH_CTRL, &dev_priv->gmch_ctrl); + if (ret) + return pcibios_err_to_errno(ret); + ret = pci_write_config_word(pdev, PSB_GMCH_CTRL, dev_priv->gmch_ctrl | _PSB_GMCH_ENABLED); + if (ret) + return pcibios_err_to_errno(ret); -/** - * psb_gtt_unpin - Drop a GTT pin requirement - * @gt: range to pin - * - * Undoes the effect of psb_gtt_pin. On the last drop the GEM object - * will be removed from the GTT which will also drop the page references - * and allow the VM to clean up or page stuff. - * - * Non GEM backed objects treat this as a no-op as they are always GTT - * backed objects. - */ -void psb_gtt_unpin(struct gtt_range *gt) -{ - struct drm_device *dev = gt->gem.dev; - struct drm_psb_private *dev_priv = dev->dev_private; - - mutex_lock(&dev_priv->gtt_mutex); + dev_priv->pge_ctl = PSB_RVDC32(PSB_PGETBL_CTL); + PSB_WVDC32(dev_priv->pge_ctl | _PSB_PGETBL_ENABLED, PSB_PGETBL_CTL); - WARN_ON(!gt->in_gart); + (void)PSB_RVDC32(PSB_PGETBL_CTL); - gt->in_gart--; - if (gt->in_gart == 0 && gt->stolen == 0) { - psb_gtt_remove(dev, gt); - psb_gtt_detach_pages(gt); - } - mutex_unlock(&dev_priv->gtt_mutex); + return 0; } -/* - * GTT resource allocator - allocate and manage GTT address space - */ - -/** - * psb_gtt_alloc_range - allocate GTT address space - * @dev: Our DRM device - * @len: length (bytes) of address space required - * @name: resource name - * @backed: resource should be backed by stolen pages - * - * Ask the kernel core to find us a suitable range of addresses - * to use for a GTT mapping. - * - * Returns a gtt_range structure describing the object, or NULL on - * error. On successful return the resource is both allocated and marked - * as in use. - */ -struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len, - const char *name, int backed) +static void psb_gtt_disable(struct drm_psb_private *dev_priv) { - struct drm_psb_private *dev_priv = dev->dev_private; - struct gtt_range *gt; - struct resource *r = dev_priv->gtt_mem; - int ret; - unsigned long start, end; + struct drm_device *dev = &dev_priv->dev; + struct pci_dev *pdev = to_pci_dev(dev->dev); - if (backed) { - /* 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; - } + pci_write_config_word(pdev, PSB_GMCH_CTRL, dev_priv->gmch_ctrl); + PSB_WVDC32(dev_priv->pge_ctl, PSB_PGETBL_CTL); - gt = kzalloc(sizeof(struct gtt_range), GFP_KERNEL); - if (gt == NULL) - return NULL; - gt->resource.name = name; - gt->stolen = backed; - gt->in_gart = backed; - gt->roll = 0; - /* 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; - return gt; - } - kfree(gt); - return NULL; + (void)PSB_RVDC32(PSB_PGETBL_CTL); } -/** - * 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. If the - * object has been pinned by mmap users we clean this up here currently. - */ -void psb_gtt_free_range(struct drm_device *dev, struct gtt_range *gt) +void psb_gtt_fini(struct drm_device *dev) { - /* Undo the mmap pin if we are destroying the object */ - if (gt->mmapping) { - psb_gtt_unpin(gt); - gt->mmapping = 0; - } - WARN_ON(gt->in_gart && !gt->stolen); - release_resource(>->resource); - kfree(gt); -} + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); -static void psb_gtt_alloc(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - init_rwsem(&dev_priv->gtt.sem); + iounmap(dev_priv->gtt_map); + psb_gtt_disable(dev_priv); + mutex_destroy(&dev_priv->gtt_mutex); } -void psb_gtt_takedown(struct drm_device *dev) +/* Clear GTT. Use a scratch page to avoid accidents or scribbles. */ +static void psb_gtt_clear(struct drm_psb_private *pdev) { - struct drm_psb_private *dev_priv = dev->dev_private; - - if (dev_priv->gtt_map) { - iounmap(dev_priv->gtt_map); - dev_priv->gtt_map = NULL; - } - if (dev_priv->gtt_initialized) { - pci_write_config_word(dev->pdev, PSB_GMCH_CTRL, - dev_priv->gmch_ctrl); - PSB_WVDC32(dev_priv->pge_ctl, PSB_PGETBL_CTL); - (void) PSB_RVDC32(PSB_PGETBL_CTL); - } - if (dev_priv->vram_addr) - iounmap(dev_priv->gtt_map); -} - -int psb_gtt_init(struct drm_device *dev, int resume) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - unsigned gtt_pages; - unsigned long stolen_size, vram_stolen_size; - unsigned i, num_pages; - unsigned pfn_base; - struct psb_gtt *pg; - - int ret = 0; + resource_size_t pfn_base; + unsigned long i; uint32_t pte; - if (!resume) { - mutex_init(&dev_priv->gtt_mutex); - psb_gtt_alloc(dev); - } + pfn_base = page_to_pfn(pdev->scratch_page); + pte = psb_gtt_mask_pte(pfn_base, PSB_MMU_CACHED_MEMORY); - pg = &dev_priv->gtt; + for (i = 0; i < pdev->gtt.gtt_pages; ++i) + iowrite32(pte, pdev->gtt_map + i); - /* 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); + (void)ioread32(pdev->gtt_map + i - 1); +} - dev_priv->pge_ctl = PSB_RVDC32(PSB_PGETBL_CTL); - PSB_WVDC32(dev_priv->pge_ctl | _PSB_PGETBL_ENABLED, PSB_PGETBL_CTL); - (void) PSB_RVDC32(PSB_PGETBL_CTL); +static void psb_gtt_init_ranges(struct drm_psb_private *dev_priv) +{ + struct drm_device *dev = &dev_priv->dev; + struct pci_dev *pdev = to_pci_dev(dev->dev); + struct psb_gtt *pg = &dev_priv->gtt; + resource_size_t gtt_phys_start, mmu_gatt_start, gtt_start, gtt_pages, + gatt_start, gatt_pages; + struct resource *gtt_mem; /* The root resource we allocate address space from */ - dev_priv->gtt_initialized = 1; - - pg->gtt_phys_start = dev_priv->pge_ctl & PAGE_MASK; + gtt_phys_start = dev_priv->pge_ctl & PAGE_MASK; /* - * The video mmu has a hw bug when accessing 0x0D0000000. - * Make gatt start at 0x0e000,0000. This doesn't actually - * matter for us but may do if the video acceleration ever - * gets opened up. + * The video MMU has a HW bug when accessing 0x0d0000000. Make + * GATT start at 0x0e0000000. This doesn't actually matter for + * us now, but maybe will if the video acceleration ever gets + * opened up. */ - pg->mmu_gatt_start = 0xE0000000; + mmu_gatt_start = 0xe0000000; + + gtt_start = pci_resource_start(pdev, PSB_GTT_RESOURCE); + gtt_pages = pci_resource_len(pdev, PSB_GTT_RESOURCE) >> PAGE_SHIFT; - pg->gtt_start = pci_resource_start(dev->pdev, PSB_GTT_RESOURCE); - gtt_pages = pci_resource_len(dev->pdev, PSB_GTT_RESOURCE) - >> PAGE_SHIFT; /* CDV doesn't report this. In which case the system has 64 gtt pages */ - if (pg->gtt_start == 0 || gtt_pages == 0) { + if (!gtt_start || !gtt_pages) { dev_dbg(dev->dev, "GTT PCI BAR not initialized.\n"); gtt_pages = 64; - pg->gtt_start = dev_priv->pge_ctl; + gtt_start = dev_priv->pge_ctl; } - pg->gatt_start = pci_resource_start(dev->pdev, PSB_GATT_RESOURCE); - pg->gatt_pages = pci_resource_len(dev->pdev, PSB_GATT_RESOURCE) - >> PAGE_SHIFT; - dev_priv->gtt_mem = &dev->pdev->resource[PSB_GATT_RESOURCE]; + gatt_start = pci_resource_start(pdev, PSB_GATT_RESOURCE); + gatt_pages = pci_resource_len(pdev, PSB_GATT_RESOURCE) >> PAGE_SHIFT; - if (pg->gatt_pages == 0 || pg->gatt_start == 0) { + if (!gatt_pages || !gatt_start) { static struct resource fudge; /* Preferably peppermint */ - /* This can occur on CDV systems. Fudge it in this case. - We really don't care what imaginary space is being allocated - at this point */ + + /* + * This can occur on CDV systems. Fudge it in this case. We + * really don't care what imaginary space is being allocated + * at this point. + */ dev_dbg(dev->dev, "GATT PCI BAR not initialized.\n"); - pg->gatt_start = 0x40000000; - pg->gatt_pages = (128 * 1024 * 1024) >> PAGE_SHIFT; - /* This is a little confusing but in fact the GTT is providing - a view from the GPU into memory and not vice versa. As such - this is really allocating space that is not the same as the - CPU address space on CDV */ + gatt_start = 0x40000000; + gatt_pages = (128 * 1024 * 1024) >> PAGE_SHIFT; + + /* + * This is a little confusing but in fact the GTT is providing + * a view from the GPU into memory and not vice versa. As such + * this is really allocating space that is not the same as the + * CPU address space on CDV. + */ fudge.start = 0x40000000; fudge.end = 0x40000000 + 128 * 1024 * 1024 - 1; fudge.name = "fudge"; fudge.flags = IORESOURCE_MEM; - dev_priv->gtt_mem = &fudge; + + gtt_mem = &fudge; + } else { + gtt_mem = &pdev->resource[PSB_GATT_RESOURCE]; } - 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; + pg->gtt_phys_start = gtt_phys_start; + pg->mmu_gatt_start = mmu_gatt_start; + pg->gtt_start = gtt_start; + pg->gtt_pages = gtt_pages; + pg->gatt_start = gatt_start; + pg->gatt_pages = gatt_pages; + dev_priv->gtt_mem = gtt_mem; +} - stolen_size = vram_stolen_size; +int psb_gtt_init(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct psb_gtt *pg = &dev_priv->gtt; + int ret; - dev_dbg(dev->dev, "Stolen memory base 0x%x, size %luK\n", - dev_priv->stolen_base, vram_stolen_size / 1024); + mutex_init(&dev_priv->gtt_mutex); - if (resume && (gtt_pages != pg->gtt_pages) && - (stolen_size != pg->stolen_size)) { - dev_err(dev->dev, "GTT resume error.\n"); - ret = -EINVAL; - goto out_err; - } + ret = psb_gtt_enable(dev_priv); + if (ret) + goto err_mutex_destroy; - pg->gtt_pages = gtt_pages; - pg->stolen_size = stolen_size; - dev_priv->vram_stolen_size = vram_stolen_size; + psb_gtt_init_ranges(dev_priv); - /* - * Map the GTT and the stolen memory area - */ - if (!resume) - dev_priv->gtt_map = ioremap_nocache(pg->gtt_phys_start, - gtt_pages << PAGE_SHIFT); + dev_priv->gtt_map = ioremap(pg->gtt_phys_start, pg->gtt_pages << PAGE_SHIFT); if (!dev_priv->gtt_map) { dev_err(dev->dev, "Failure to map gtt.\n"); ret = -ENOMEM; - goto out_err; - } - - if (!resume) - dev_priv->vram_addr = ioremap_wc(dev_priv->stolen_base, - stolen_size); - if (!dev_priv->vram_addr) { - dev_err(dev->dev, "Failure to map stolen base.\n"); - ret = -ENOMEM; - goto out_err; + goto err_psb_gtt_disable; } - /* - * Insert vram stolen pages into the GTT - */ + psb_gtt_clear(dev_priv); - pfn_base = dev_priv->stolen_base >> PAGE_SHIFT; - num_pages = vram_stolen_size >> PAGE_SHIFT; - dev_dbg(dev->dev, "Set up %d stolen pages starting at 0x%08x, GTT offset %dK\n", - 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 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); - for (; i < gtt_pages; ++i) - iowrite32(pte, dev_priv->gtt_map + i); - - (void) ioread32(dev_priv->gtt_map + i - 1); return 0; -out_err: - psb_gtt_takedown(dev); +err_psb_gtt_disable: + psb_gtt_disable(dev_priv); +err_mutex_destroy: + mutex_destroy(&dev_priv->gtt_mutex); return ret; } -int psb_gtt_restore(struct drm_device *dev) +int psb_gtt_resume(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; - struct resource *r = dev_priv->gtt_mem->child; - struct gtt_range *range; - unsigned int restored = 0, total = 0, size = 0; - - /* On resume, the gtt_mutex is already initialized */ - mutex_lock(&dev_priv->gtt_mutex); - psb_gtt_init(dev, 1); - - while (r != NULL) { - range = container_of(r, struct gtt_range, resource); - if (range->pages) { - psb_gtt_insert(dev, range, 1); - size += range->resource.end - range->resource.start; - restored++; - } - r = r->sibling; - total++; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct psb_gtt *pg = &dev_priv->gtt; + unsigned int old_gtt_pages = pg->gtt_pages; + int ret; + + /* Enable the GTT */ + ret = psb_gtt_enable(dev_priv); + if (ret) + return ret; + + psb_gtt_init_ranges(dev_priv); + + if (old_gtt_pages != pg->gtt_pages) { + dev_err(dev->dev, "GTT resume error.\n"); + ret = -ENODEV; + goto err_psb_gtt_disable; } - mutex_unlock(&dev_priv->gtt_mutex); - DRM_DEBUG_DRIVER("Restored %u of %u gtt ranges (%u KB)", restored, - total, (size / 1024)); - return 0; + psb_gtt_clear(dev_priv); + +err_psb_gtt_disable: + psb_gtt_disable(dev_priv); + return ret; } diff --git a/drivers/gpu/drm/gma500/gtt.h b/drivers/gpu/drm/gma500/gtt.h index 6191d10acf33..d5a5fd4466c1 100644 --- a/drivers/gpu/drm/gma500/gtt.h +++ b/drivers/gpu/drm/gma500/gtt.h @@ -1,26 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /************************************************************************** * Copyright (c) 2007-2008, 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. - * **************************************************************************/ #ifndef _PSB_GTT_H_ #define _PSB_GTT_H_ -#include <drm/drmP.h> +#include <drm/drm_gem.h> + +struct drm_psb_private; /* This wants cleaning up with respect to the psb_dev and un-needed stuff */ struct psb_gtt { @@ -32,33 +22,20 @@ struct psb_gtt { unsigned gatt_pages; unsigned long stolen_size; unsigned long vram_stolen_size; - struct rw_semaphore sem; }; /* Exported functions */ -extern int psb_gtt_init(struct drm_device *dev, int resume); -extern void psb_gtt_takedown(struct drm_device *dev); +int psb_gtt_init(struct drm_device *dev); +void psb_gtt_fini(struct drm_device *dev); +int psb_gtt_resume(struct drm_device *dev); -/* Each gtt_range describes an allocation in the GTT area */ -struct gtt_range { - 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 */ - struct page **pages; /* Backing pages if present */ - int npage; /* Number of backing pages */ - int roll; /* Roll applied to the GTT entries */ -}; +int psb_gtt_allocate_resource(struct drm_psb_private *pdev, struct resource *res, + const char *name, resource_size_t size, resource_size_t align, + bool stolen, u32 *offset); + +uint32_t psb_gtt_mask_pte(uint32_t pfn, int type); +void psb_gtt_insert_pages(struct drm_psb_private *pdev, const struct resource *res, + struct page **pages); +void psb_gtt_remove_pages(struct drm_psb_private *pdev, const struct resource *res); -extern struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len, - const char *name, int backed); -extern void psb_gtt_kref_put(struct gtt_range *gt); -extern void psb_gtt_free_range(struct drm_device *dev, struct gtt_range *gt); -extern int psb_gtt_pin(struct gtt_range *gt); -extern void psb_gtt_unpin(struct gtt_range *gt); -extern void psb_gtt_roll(struct drm_device *dev, - struct gtt_range *gt, int roll); -extern int psb_gtt_restore(struct drm_device *dev); #endif diff --git a/drivers/gpu/drm/gma500/intel_bios.c b/drivers/gpu/drm/gma500/intel_bios.c index d3497348c4d5..b60720560830 100644 --- a/drivers/gpu/drm/gma500/intel_bios.c +++ b/drivers/gpu/drm/gma500/intel_bios.c @@ -1,33 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2006 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 <drm/drmP.h> + +#include <drm/display/drm_dp_helper.h> #include <drm/drm.h> -#include <drm/gma_drm.h> +#include <drm/drm_print.h> + +#include "intel_bios.h" #include "psb_drv.h" #include "psb_intel_drv.h" #include "psb_intel_reg.h" -#include "intel_bios.h" -#define SLAVE_ADDR1 0x70 -#define SLAVE_ADDR2 0x72 +#define TARGET_ADDR1 0x70 +#define TARGET_ADDR2 0x72 static void *find_section(struct bdb_header *bdb, int section_id) { @@ -63,7 +52,7 @@ parse_edp(struct drm_psb_private *dev_priv, struct bdb_header *bdb) uint8_t panel_type; edp = find_section(bdb, BDB_EDP); - + dev_priv->edp.bpp = 18; if (!edp) { if (dev_priv->edp.support) { @@ -93,7 +82,7 @@ parse_edp(struct drm_psb_private *dev_priv, struct bdb_header *bdb) dev_priv->edp.pps = *edp_pps; DRM_DEBUG_KMS("EDP timing in vbt t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n", - dev_priv->edp.pps.t1_t3, dev_priv->edp.pps.t8, + dev_priv->edp.pps.t1_t3, dev_priv->edp.pps.t8, dev_priv->edp.pps.t9, dev_priv->edp.pps.t10, dev_priv->edp.pps.t11_t12); @@ -116,30 +105,30 @@ parse_edp(struct drm_psb_private *dev_priv, struct bdb_header *bdb) switch (edp_link_params->preemphasis) { case 0: - dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_0; + dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_0; break; case 1: - dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5; + dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_1; break; case 2: - dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_6; + dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_2; break; case 3: - dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5; + dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_3; break; } switch (edp_link_params->vswing) { case 0: - dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_400; + dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_0; break; case 1: - dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_600; + dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_1; break; case 2: - dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_800; + dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_2; break; case 3: - dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_1200; + dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_3; break; } DRM_DEBUG_KMS("VBT reports EDP: VSwing %d, Preemph %d\n", @@ -220,7 +209,7 @@ static void parse_backlight_data(struct drm_psb_private *dev_priv, lvds_bl = kmemdup(vbt_lvds_bl, sizeof(*vbt_lvds_bl), GFP_KERNEL); if (!lvds_bl) { - dev_err(dev_priv->dev->dev, "out of memory for backlight data\n"); + dev_err(dev_priv->dev.dev, "out of memory for backlight data\n"); return; } dev_priv->lvds_bl = lvds_bl; @@ -261,7 +250,7 @@ static void parse_lfp_panel_data(struct drm_psb_private *dev_priv, 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"); + dev_err(dev_priv->dev.dev, "out of memory for fixed panel mode\n"); return; } @@ -272,7 +261,7 @@ static void parse_lfp_panel_data(struct drm_psb_private *dev_priv, dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode; drm_mode_debug_printmodeline(panel_fixed_mode); } else { - dev_dbg(dev_priv->dev->dev, "ignoring invalid LVDS VBT\n"); + dev_dbg(dev_priv->dev.dev, "ignoring invalid LVDS VBT\n"); dev_priv->lvds_vbt = 0; kfree(panel_fixed_mode); } @@ -369,10 +358,10 @@ parse_sdvo_device_mapping(struct drm_psb_private *dev_priv, /* skip the device block if device type is invalid */ continue; } - if (p_child->slave_addr != SLAVE_ADDR1 && - p_child->slave_addr != SLAVE_ADDR2) { + if (p_child->target_addr != TARGET_ADDR1 && + p_child->target_addr != TARGET_ADDR2) { /* - * If the slave address is neither 0x70 nor 0x72, + * If the target address is neither 0x70 nor 0x72, * it is not a SDVO device. Skip it. */ continue; @@ -383,22 +372,22 @@ parse_sdvo_device_mapping(struct drm_psb_private *dev_priv, DRM_DEBUG_KMS("Incorrect SDVO port. Skip it\n"); continue; } - DRM_DEBUG_KMS("the SDVO device with slave addr %2x is found on" + DRM_DEBUG_KMS("the SDVO device with target addr %2x is found on" " %s port\n", - p_child->slave_addr, + p_child->target_addr, (p_child->dvo_port == DEVICE_PORT_DVOB) ? "SDVOB" : "SDVOC"); p_mapping = &(dev_priv->sdvo_mappings[p_child->dvo_port - 1]); if (!p_mapping->initialized) { p_mapping->dvo_port = p_child->dvo_port; - p_mapping->slave_addr = p_child->slave_addr; + p_mapping->target_addr = p_child->target_addr; p_mapping->dvo_wiring = p_child->dvo_wiring; p_mapping->ddc_pin = p_child->ddc_pin; p_mapping->i2c_pin = p_child->i2c_pin; p_mapping->initialized = 1; DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d\n", p_mapping->dvo_port, - p_mapping->slave_addr, + p_mapping->target_addr, p_mapping->dvo_wiring, p_mapping->ddc_pin, p_mapping->i2c_pin); @@ -406,10 +395,10 @@ parse_sdvo_device_mapping(struct drm_psb_private *dev_priv, DRM_DEBUG_KMS("Maybe one SDVO port is shared by " "two SDVO device.\n"); } - if (p_child->slave2_addr) { + if (p_child->target2_addr) { /* Maybe this is a SDVO device with multiple inputs */ /* And the mapping info is not added */ - DRM_DEBUG_KMS("there exists the slave2_addr. Maybe this" + DRM_DEBUG_KMS("there exists the target2_addr. Maybe this" " is a SDVO device with multiple inputs.\n"); } count++; @@ -436,6 +425,9 @@ parse_driver_features(struct drm_psb_private *dev_priv, if (driver->lvds_config == BDB_DRIVER_FEATURE_EDP) dev_priv->edp.support = 1; + dev_priv->lvds_enabled_in_vbt = driver->lvds_config != 0; + DRM_DEBUG_KMS("LVDS VBT config bits: 0x%x\n", driver->lvds_config); + /* This bit means to use 96Mhz for DPLL_A or not */ if (driver->primary_lfp_id) dev_priv->dplla_96mhz = true; @@ -525,8 +517,8 @@ parse_device_mapping(struct drm_psb_private *dev_priv, */ int psb_intel_init_bios(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; - struct pci_dev *pdev = dev->pdev; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct pci_dev *pdev = to_pci_dev(dev->dev); struct vbt_header *vbt = NULL; struct bdb_header *bdb = NULL; u8 __iomem *bios = NULL; @@ -584,12 +576,12 @@ int psb_intel_init_bios(struct drm_device *dev) return 0; } -/** +/* * Destroy and free VBT data */ void psb_intel_destroy_bios(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); kfree(dev_priv->sdvo_lvds_vbt_mode); kfree(dev_priv->lfp_lvds_vbt_mode); diff --git a/drivers/gpu/drm/gma500/intel_bios.h b/drivers/gpu/drm/gma500/intel_bios.h index 978ae4b25e82..b5adea2a20c3 100644 --- a/drivers/gpu/drm/gma500/intel_bios.h +++ b/drivers/gpu/drm/gma500/intel_bios.h @@ -1,29 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2006 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> - * */ #ifndef _INTEL_BIOS_H_ #define _INTEL_BIOS_H_ -#include <drm/drmP.h> -#include <drm/drm_dp_helper.h> +struct drm_device; struct vbt_header { u8 signature[20]; /**< Always starts with 'VBT$' */ @@ -34,7 +20,7 @@ struct vbt_header { u8 reserved0; u32 bdb_offset; /**< from beginning of VBT */ u32 aim_offset[4]; /**< from beginning of VBT */ -} __attribute__((packed)); +} __packed; struct bdb_header { @@ -61,7 +47,7 @@ struct vbios_data { u8 rsvd4; /* popup memory size */ u8 resize_pci_bios; u8 rsvd5; /* is crt already on ddc2 */ -} __attribute__((packed)); +} __packed; /* * There are several types of BIOS data blocks (BDBs), each block has @@ -133,7 +119,7 @@ struct bdb_general_features { u8 dp_ssc_enb:1; /* PCH attached eDP supports SSC */ u8 dp_ssc_freq:1; /* SSC freq for PCH attached eDP */ u8 rsvd11:3; /* finish byte */ -} __attribute__((packed)); +} __packed; /* pre-915 */ #define GPIO_PIN_DVI_LVDS 0x03 /* "DVI/LVDS DDC GPIO pins" */ @@ -200,20 +186,20 @@ struct child_device_config { u16 addin_offset; u8 dvo_port; /* See Device_PORT_* above */ u8 i2c_pin; - u8 slave_addr; + u8 target_addr; u8 ddc_pin; u16 edid_ptr; u8 dvo_cfg; /* See DEVICE_CFG_* above */ u8 dvo2_port; u8 i2c2_pin; - u8 slave2_addr; + u8 target2_addr; u8 ddc2_pin; u8 capabilities; u8 dvo_wiring;/* See DEVICE_WIRE_* above */ u8 dvo2_wiring; u16 extended_type; u8 dvo_function; -} __attribute__((packed)); +} __packed; struct bdb_general_definitions { @@ -241,7 +227,7 @@ struct bdb_general_definitions { * number = (block_size - sizeof(bdb_general_definitions))/ * sizeof(child_device_config); */ - struct child_device_config devices[0]; + struct child_device_config devices[]; }; struct bdb_lvds_options { @@ -256,7 +242,7 @@ struct bdb_lvds_options { u8 lvds_edid:1; u8 rsvd2:1; u8 rsvd4; -} __attribute__((packed)); +} __packed; struct bdb_lvds_backlight { u8 type:2; @@ -268,7 +254,7 @@ struct bdb_lvds_backlight { u8 i2caddr; u8 brightnesscmd; /*FIXME: more...*/ -} __attribute__((packed)); +} __packed; /* LFP pointer table contains entries to the struct below */ struct bdb_lvds_lfp_data_ptr { @@ -278,12 +264,12 @@ struct bdb_lvds_lfp_data_ptr { u8 dvo_table_size; u16 panel_pnp_id_offset; u8 pnp_table_size; -} __attribute__((packed)); +} __packed; struct bdb_lvds_lfp_data_ptrs { u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */ struct bdb_lvds_lfp_data_ptr ptr[16]; -} __attribute__((packed)); +} __packed; /* LFP data has 3 blocks per entry */ struct lvds_fp_timing { @@ -300,7 +286,7 @@ struct lvds_fp_timing { u32 pfit_reg; u32 pfit_reg_val; u16 terminator; -} __attribute__((packed)); +} __packed; struct lvds_dvo_timing { u16 clock; /**< In 10khz */ @@ -328,7 +314,7 @@ struct lvds_dvo_timing { u8 vsync_positive:1; u8 hsync_positive:1; u8 rsvd2:1; -} __attribute__((packed)); +} __packed; struct lvds_pnp_id { u16 mfg_name; @@ -336,17 +322,17 @@ struct lvds_pnp_id { u32 serial; u8 mfg_week; u8 mfg_year; -} __attribute__((packed)); +} __packed; struct bdb_lvds_lfp_data_entry { struct lvds_fp_timing fp_timing; struct lvds_dvo_timing dvo_timing; struct lvds_pnp_id pnp_id; -} __attribute__((packed)); +} __packed; struct bdb_lvds_lfp_data { struct bdb_lvds_lfp_data_entry data[16]; -} __attribute__((packed)); +} __packed; struct aimdb_header { char signature[16]; @@ -354,12 +340,12 @@ struct aimdb_header { u16 aimdb_version; u16 aimdb_header_size; u16 aimdb_size; -} __attribute__((packed)); +} __packed; struct aimdb_block { u8 aimdb_id; u16 aimdb_size; -} __attribute__((packed)); +} __packed; struct vch_panel_data { u16 fp_timing_offset; @@ -370,12 +356,12 @@ struct vch_panel_data { u8 text_fitting_size; u16 graphics_fitting_offset; u8 graphics_fitting_size; -} __attribute__((packed)); +} __packed; struct vch_bdb_22 { struct aimdb_block aimdb_block; struct vch_panel_data panels[16]; -} __attribute__((packed)); +} __packed; struct bdb_sdvo_lvds_options { u8 panel_backlight; @@ -391,7 +377,7 @@ struct bdb_sdvo_lvds_options { u8 panel_misc_bits_2; u8 panel_misc_bits_3; u8 panel_misc_bits_4; -} __attribute__((packed)); +} __packed; #define BDB_DRIVER_FEATURE_NO_LVDS 0 #define BDB_DRIVER_FEATURE_INT_LVDS 1 @@ -436,7 +422,7 @@ struct bdb_driver_features { u8 hdmi_termination; u8 custom_vbt_version; -} __attribute__((packed)); +} __packed; #define EDP_18BPP 0 #define EDP_24BPP 1 diff --git a/drivers/gpu/drm/gma500/intel_gmbus.c b/drivers/gpu/drm/gma500/intel_gmbus.c index 62cd42e88f28..2b06ba22f9c6 100644 --- a/drivers/gpu/drm/gma500/intel_gmbus.c +++ b/drivers/gpu/drm/gma500/intel_gmbus.c @@ -26,13 +26,16 @@ * Eric Anholt <eric@anholt.net> * Chris Wilson <chris@chris-wilson.co.uk> */ -#include <linux/module.h> -#include <linux/i2c.h> + +#include <linux/delay.h> #include <linux/i2c-algo-bit.h> -#include <drm/drmP.h> -#include "psb_intel_drv.h" -#include <drm/gma_drm.h> +#include <linux/i2c.h> +#include <linux/module.h> + +#include <drm/drm_print.h> + #include "psb_drv.h" +#include "psb_intel_drv.h" #include "psb_intel_reg.h" #define _wait_for(COND, MS, W) ({ \ @@ -43,13 +46,16 @@ ret__ = -ETIMEDOUT; \ break; \ } \ - if (W && !(in_atomic() || in_dbg_master())) msleep(W); \ + if (W && !(in_dbg_master())) \ + msleep(W); \ } \ ret__; \ }) #define wait_for(COND, MS) _wait_for(COND, MS, 1) -#define wait_for_atomic(COND, MS) _wait_for(COND, MS, 0) + +#define GMBUS_REG_READ(reg) ioread32(dev_priv->gmbus_reg + (reg)) +#define GMBUS_REG_WRITE(reg, val) iowrite32((val), dev_priv->gmbus_reg + (reg)) /* Intel GPIO access functions */ @@ -71,7 +77,8 @@ struct intel_gpio { void gma_intel_i2c_reset(struct drm_device *dev) { - REG_WRITE(GMBUS0, 0); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + GMBUS_REG_WRITE(GMBUS0, 0); } static void intel_i2c_quirk_set(struct drm_psb_private *dev_priv, bool enable) @@ -98,11 +105,10 @@ static void intel_i2c_quirk_set(struct drm_psb_private *dev_priv, bool enable) static u32 get_reserved(struct intel_gpio *gpio) { struct drm_psb_private *dev_priv = gpio->dev_priv; - struct drm_device *dev = dev_priv->dev; u32 reserved = 0; /* On most chips, these bits must be preserved in software. */ - reserved = REG_READ(gpio->reg) & + reserved = GMBUS_REG_READ(gpio->reg) & (GPIO_DATA_PULLUP_DISABLE | GPIO_CLOCK_PULLUP_DISABLE); @@ -113,29 +119,26 @@ static int get_clock(void *data) { struct intel_gpio *gpio = data; struct drm_psb_private *dev_priv = gpio->dev_priv; - struct drm_device *dev = dev_priv->dev; u32 reserved = get_reserved(gpio); - REG_WRITE(gpio->reg, reserved | GPIO_CLOCK_DIR_MASK); - REG_WRITE(gpio->reg, reserved); - return (REG_READ(gpio->reg) & GPIO_CLOCK_VAL_IN) != 0; + GMBUS_REG_WRITE(gpio->reg, reserved | GPIO_CLOCK_DIR_MASK); + GMBUS_REG_WRITE(gpio->reg, reserved); + return (GMBUS_REG_READ(gpio->reg) & GPIO_CLOCK_VAL_IN) != 0; } static int get_data(void *data) { struct intel_gpio *gpio = data; struct drm_psb_private *dev_priv = gpio->dev_priv; - struct drm_device *dev = dev_priv->dev; u32 reserved = get_reserved(gpio); - REG_WRITE(gpio->reg, reserved | GPIO_DATA_DIR_MASK); - REG_WRITE(gpio->reg, reserved); - return (REG_READ(gpio->reg) & GPIO_DATA_VAL_IN) != 0; + GMBUS_REG_WRITE(gpio->reg, reserved | GPIO_DATA_DIR_MASK); + GMBUS_REG_WRITE(gpio->reg, reserved); + return (GMBUS_REG_READ(gpio->reg) & GPIO_DATA_VAL_IN) != 0; } static void set_clock(void *data, int state_high) { struct intel_gpio *gpio = data; struct drm_psb_private *dev_priv = gpio->dev_priv; - struct drm_device *dev = dev_priv->dev; u32 reserved = get_reserved(gpio); u32 clock_bits; @@ -145,15 +148,14 @@ static void set_clock(void *data, int state_high) clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK | GPIO_CLOCK_VAL_MASK; - REG_WRITE(gpio->reg, reserved | clock_bits); - REG_READ(gpio->reg); /* Posting */ + GMBUS_REG_WRITE(gpio->reg, reserved | clock_bits); + GMBUS_REG_READ(gpio->reg); /* Posting */ } static void set_data(void *data, int state_high) { struct intel_gpio *gpio = data; struct drm_psb_private *dev_priv = gpio->dev_priv; - struct drm_device *dev = dev_priv->dev; u32 reserved = get_reserved(gpio); u32 data_bits; @@ -163,8 +165,8 @@ static void set_data(void *data, int state_high) data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK | GPIO_DATA_VAL_MASK; - REG_WRITE(gpio->reg, reserved | data_bits); - REG_READ(gpio->reg); + GMBUS_REG_WRITE(gpio->reg, reserved | data_bits); + GMBUS_REG_READ(gpio->reg); } static struct i2c_adapter * @@ -196,7 +198,7 @@ intel_gpio_create(struct drm_psb_private *dev_priv, u32 pin) "gma500 GPIO%c", "?BACDE?F"[pin]); gpio->adapter.owner = THIS_MODULE; gpio->adapter.algo_data = &gpio->algo; - gpio->adapter.dev.parent = &dev_priv->dev->pdev->dev; + gpio->adapter.dev.parent = dev_priv->dev.dev; gpio->algo.setsda = set_data; gpio->algo.setscl = set_clock; gpio->algo.getsda = get_data; @@ -226,7 +228,7 @@ intel_i2c_quirk_xfer(struct drm_psb_private *dev_priv, adapter); int ret; - gma_intel_i2c_reset(dev_priv->dev); + gma_intel_i2c_reset(&dev_priv->dev); intel_i2c_quirk_set(dev_priv, true); set_data(gpio, 1); @@ -251,7 +253,6 @@ gmbus_xfer(struct i2c_adapter *adapter, struct intel_gmbus, adapter); struct drm_psb_private *dev_priv = adapter->algo_data; - struct drm_device *dev = dev_priv->dev; int i, reg_offset; if (bus->force_bit) @@ -260,28 +261,30 @@ gmbus_xfer(struct i2c_adapter *adapter, reg_offset = 0; - REG_WRITE(GMBUS0 + reg_offset, bus->reg0); + GMBUS_REG_WRITE(GMBUS0 + reg_offset, bus->reg0); for (i = 0; i < num; i++) { u16 len = msgs[i].len; u8 *buf = msgs[i].buf; if (msgs[i].flags & I2C_M_RD) { - REG_WRITE(GMBUS1 + reg_offset, - GMBUS_CYCLE_WAIT | (i + 1 == num ? GMBUS_CYCLE_STOP : 0) | - (len << GMBUS_BYTE_COUNT_SHIFT) | - (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) | - GMBUS_SLAVE_READ | GMBUS_SW_RDY); - REG_READ(GMBUS2+reg_offset); + GMBUS_REG_WRITE(GMBUS1 + reg_offset, + GMBUS_CYCLE_WAIT | + (i + 1 == num ? GMBUS_CYCLE_STOP : 0) | + (len << GMBUS_BYTE_COUNT_SHIFT) | + (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) | + GMBUS_SLAVE_READ | GMBUS_SW_RDY); + GMBUS_REG_READ(GMBUS2+reg_offset); do { u32 val, loop = 0; - if (wait_for(REG_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50)) + if (wait_for(GMBUS_REG_READ(GMBUS2 + reg_offset) & + (GMBUS_SATOER | GMBUS_HW_RDY), 50)) goto timeout; - if (REG_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) + if (GMBUS_REG_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) goto clear_err; - val = REG_READ(GMBUS3 + reg_offset); + val = GMBUS_REG_READ(GMBUS3 + reg_offset); do { *buf++ = val & 0xff; val >>= 8; @@ -295,18 +298,20 @@ gmbus_xfer(struct i2c_adapter *adapter, val |= *buf++ << (8 * loop); } while (--len && ++loop < 4); - REG_WRITE(GMBUS3 + reg_offset, val); - REG_WRITE(GMBUS1 + reg_offset, + GMBUS_REG_WRITE(GMBUS3 + reg_offset, val); + GMBUS_REG_WRITE(GMBUS1 + reg_offset, (i + 1 == num ? GMBUS_CYCLE_STOP : GMBUS_CYCLE_WAIT) | (msgs[i].len << GMBUS_BYTE_COUNT_SHIFT) | (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) | GMBUS_SLAVE_WRITE | GMBUS_SW_RDY); - REG_READ(GMBUS2+reg_offset); + GMBUS_REG_READ(GMBUS2+reg_offset); while (len) { - if (wait_for(REG_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50)) + if (wait_for(GMBUS_REG_READ(GMBUS2 + reg_offset) & + (GMBUS_SATOER | GMBUS_HW_RDY), 50)) goto timeout; - if (REG_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) + if (GMBUS_REG_READ(GMBUS2 + reg_offset) & + GMBUS_SATOER) goto clear_err; val = loop = 0; @@ -314,14 +319,14 @@ gmbus_xfer(struct i2c_adapter *adapter, val |= *buf++ << (8 * loop); } while (--len && ++loop < 4); - REG_WRITE(GMBUS3 + reg_offset, val); - REG_READ(GMBUS2+reg_offset); + GMBUS_REG_WRITE(GMBUS3 + reg_offset, val); + GMBUS_REG_READ(GMBUS2+reg_offset); } } - if (i + 1 < num && wait_for(REG_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), 50)) + if (i + 1 < num && wait_for(GMBUS_REG_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), 50)) goto timeout; - if (REG_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) + if (GMBUS_REG_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) goto clear_err; } @@ -330,22 +335,22 @@ gmbus_xfer(struct i2c_adapter *adapter, clear_err: /* Toggle the Software Clear Interrupt bit. This has the effect * of resetting the GMBUS controller and so clearing the - * BUS_ERROR raised by the slave's NAK. + * BUS_ERROR raised by the target's NAK. */ - REG_WRITE(GMBUS1 + reg_offset, GMBUS_SW_CLR_INT); - REG_WRITE(GMBUS1 + reg_offset, 0); + GMBUS_REG_WRITE(GMBUS1 + reg_offset, GMBUS_SW_CLR_INT); + GMBUS_REG_WRITE(GMBUS1 + reg_offset, 0); done: /* Mark the GMBUS interface as disabled. We will re-enable it at the * start of the next xfer, till then let it sleep. */ - REG_WRITE(GMBUS0 + reg_offset, 0); + GMBUS_REG_WRITE(GMBUS0 + reg_offset, 0); return i; timeout: DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n", bus->reg0 & 0xff, bus->adapter.name); - REG_WRITE(GMBUS0 + reg_offset, 0); + GMBUS_REG_WRITE(GMBUS0 + reg_offset, 0); /* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */ bus->force_bit = intel_gpio_create(dev_priv, bus->reg0 & 0xff); @@ -376,7 +381,7 @@ static const struct i2c_algorithm gmbus_algorithm = { }; /** - * intel_gmbus_setup - instantiate all Intel i2c GMBuses + * gma_intel_setup_gmbus() - instantiate all Intel i2c GMBuses * @dev: DRM device */ int gma_intel_setup_gmbus(struct drm_device *dev) @@ -391,7 +396,7 @@ int gma_intel_setup_gmbus(struct drm_device *dev) "reserved", "dpd", }; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); int ret, i; dev_priv->gmbus = kcalloc(GMBUS_NUM_PORTS, sizeof(struct intel_gmbus), @@ -399,17 +404,21 @@ int gma_intel_setup_gmbus(struct drm_device *dev) if (dev_priv->gmbus == NULL) return -ENOMEM; + if (IS_MRST(dev)) + dev_priv->gmbus_reg = dev_priv->aux_reg; + else + dev_priv->gmbus_reg = dev_priv->vdc_reg; + for (i = 0; i < GMBUS_NUM_PORTS; i++) { struct intel_gmbus *bus = &dev_priv->gmbus[i]; bus->adapter.owner = THIS_MODULE; - bus->adapter.class = I2C_CLASS_DDC; snprintf(bus->adapter.name, sizeof(bus->adapter.name), "gma500 gmbus %s", names[i]); - bus->adapter.dev.parent = &dev->pdev->dev; + bus->adapter.dev.parent = dev->dev; bus->adapter.algo_data = dev_priv; bus->adapter.algo = &gmbus_algorithm; @@ -424,12 +433,12 @@ int gma_intel_setup_gmbus(struct drm_device *dev) bus->force_bit = intel_gpio_create(dev_priv, i); } - gma_intel_i2c_reset(dev_priv->dev); + gma_intel_i2c_reset(&dev_priv->dev); return 0; err: - while (--i) { + while (i--) { struct intel_gmbus *bus = &dev_priv->gmbus[i]; i2c_del_adapter(&bus->adapter); } @@ -472,7 +481,7 @@ void gma_intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit) void gma_intel_teardown_gmbus(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); int i; if (dev_priv->gmbus == NULL) @@ -487,6 +496,7 @@ void gma_intel_teardown_gmbus(struct drm_device *dev) i2c_del_adapter(&bus->adapter); } + dev_priv->gmbus_reg = NULL; /* iounmap is done in driver_unload */ kfree(dev_priv->gmbus); dev_priv->gmbus = NULL; } diff --git a/drivers/gpu/drm/gma500/intel_i2c.c b/drivers/gpu/drm/gma500/intel_i2c.c index 98a28c209555..9d02a7b6d9a3 100644 --- a/drivers/gpu/drm/gma500/intel_i2c.c +++ b/drivers/gpu/drm/gma500/intel_i2c.c @@ -1,25 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright © 2006-2007 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/delay.h> #include <linux/export.h> -#include <linux/i2c.h> #include <linux/i2c-algo-bit.h> +#include <linux/i2c.h> #include "psb_drv.h" #include "psb_intel_reg.h" @@ -32,7 +22,7 @@ static int get_clock(void *data) { - struct psb_intel_i2c_chan *chan = data; + struct gma_i2c_chan *chan = data; struct drm_device *dev = chan->drm_dev; u32 val; @@ -42,7 +32,7 @@ static int get_clock(void *data) static int get_data(void *data) { - struct psb_intel_i2c_chan *chan = data; + struct gma_i2c_chan *chan = data; struct drm_device *dev = chan->drm_dev; u32 val; @@ -52,7 +42,7 @@ static int get_data(void *data) static void set_clock(void *data, int state_high) { - struct psb_intel_i2c_chan *chan = data; + struct gma_i2c_chan *chan = data; struct drm_device *dev = chan->drm_dev; u32 reserved = 0, clock_bits; @@ -72,7 +62,7 @@ static void set_clock(void *data, int state_high) static void set_data(void *data, int state_high) { - struct psb_intel_i2c_chan *chan = data; + struct gma_i2c_chan *chan = data; struct drm_device *dev = chan->drm_dev; u32 reserved = 0, data_bits; @@ -93,9 +83,8 @@ static void set_data(void *data, int state_high) } /** - * psb_intel_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg + * gma_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg * @dev: DRM device - * @output: driver specific output device * @reg: GPIO reg to use * @name: name for this bus * @@ -113,21 +102,21 @@ static void set_data(void *data, int state_high) * %GPIOH * see PRM for details on how these different busses are used. */ -struct psb_intel_i2c_chan *psb_intel_i2c_create(struct drm_device *dev, - const u32 reg, const char *name) +struct gma_i2c_chan *gma_i2c_create(struct drm_device *dev, const u32 reg, + const char *name) { - struct psb_intel_i2c_chan *chan; + struct gma_i2c_chan *chan; - chan = kzalloc(sizeof(struct psb_intel_i2c_chan), GFP_KERNEL); + chan = kzalloc(sizeof(struct gma_i2c_chan), GFP_KERNEL); if (!chan) goto out_free; chan->drm_dev = dev; chan->reg = reg; - snprintf(chan->adapter.name, I2C_NAME_SIZE, "intel drm %s", name); - chan->adapter.owner = THIS_MODULE; - chan->adapter.algo_data = &chan->algo; - chan->adapter.dev.parent = &dev->pdev->dev; + snprintf(chan->base.name, I2C_NAME_SIZE, "intel drm %s", name); + chan->base.owner = THIS_MODULE; + chan->base.algo_data = &chan->algo; + chan->base.dev.parent = dev->dev; chan->algo.setsda = set_data; chan->algo.setscl = set_clock; chan->algo.getsda = get_data; @@ -136,9 +125,9 @@ struct psb_intel_i2c_chan *psb_intel_i2c_create(struct drm_device *dev, chan->algo.timeout = usecs_to_jiffies(2200); chan->algo.data = chan; - i2c_set_adapdata(&chan->adapter, chan); + i2c_set_adapdata(&chan->base, chan); - if (i2c_bit_add_bus(&chan->adapter)) + if (i2c_bit_add_bus(&chan->base)) goto out_free; /* JJJ: raise SCL and SDA? */ @@ -154,16 +143,16 @@ out_free: } /** - * psb_intel_i2c_destroy - unregister and free i2c bus resources - * @output: channel to free + * gma_i2c_destroy - unregister and free i2c bus resources + * @chan: channel to free * * Unregister the adapter from the i2c layer, then free the structure. */ -void psb_intel_i2c_destroy(struct psb_intel_i2c_chan *chan) +void gma_i2c_destroy(struct gma_i2c_chan *chan) { if (!chan) return; - i2c_del_adapter(&chan->adapter); + i2c_del_adapter(&chan->base); kfree(chan); } diff --git a/drivers/gpu/drm/gma500/mdfld_device.c b/drivers/gpu/drm/gma500/mdfld_device.c deleted file mode 100644 index 265ad0de44a6..000000000000 --- a/drivers/gpu/drm/gma500/mdfld_device.c +++ /dev/null @@ -1,551 +0,0 @@ -/************************************************************************** - * Copyright (c) 2011, Intel Corporation. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - **************************************************************************/ - -#include "psb_drv.h" -#include "mid_bios.h" -#include "mdfld_output.h" -#include "mdfld_dsi_output.h" -#include "tc35876x-dsi-lvds.h" - -#include <asm/intel_scu_ipc.h> - -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE - -#define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF -#define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */ -#define BLC_PWM_FREQ_CALC_CONSTANT 32 -#define MHz 1000000 -#define BRIGHTNESS_MIN_LEVEL 1 -#define BRIGHTNESS_MAX_LEVEL 100 -#define BRIGHTNESS_MASK 0xFF -#define BLC_POLARITY_NORMAL 0 -#define BLC_POLARITY_INVERSE 1 -#define BLC_ADJUSTMENT_MAX 100 - -#define MDFLD_BLC_PWM_PRECISION_FACTOR 10 -#define MDFLD_BLC_MAX_PWM_REG_FREQ 0xFFFE -#define MDFLD_BLC_MIN_PWM_REG_FREQ 0x2 - -#define MDFLD_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) -#define MDFLD_BACKLIGHT_PWM_CTL_SHIFT (16) - -static struct backlight_device *mdfld_backlight_device; - -int mdfld_set_brightness(struct backlight_device *bd) -{ - struct drm_device *dev = - (struct drm_device *)bl_get_data(mdfld_backlight_device); - struct drm_psb_private *dev_priv = dev->dev_private; - int level = bd->props.brightness; - - DRM_DEBUG_DRIVER("backlight level set to %d\n", level); - - /* Perform value bounds checking */ - if (level < BRIGHTNESS_MIN_LEVEL) - level = BRIGHTNESS_MIN_LEVEL; - - if (gma_power_begin(dev, false)) { - u32 adjusted_level = 0; - - /* - * Adjust the backlight level with the percent in - * dev_priv->blc_adj2 - */ - adjusted_level = level * dev_priv->blc_adj2; - adjusted_level = adjusted_level / BLC_ADJUSTMENT_MAX; - dev_priv->brightness_adjusted = adjusted_level; - - if (mdfld_get_panel_type(dev, 0) == TC35876X) { - if (dev_priv->dpi_panel_on[0] || - dev_priv->dpi_panel_on[2]) - tc35876x_brightness_control(dev, - dev_priv->brightness_adjusted); - } else { - if (dev_priv->dpi_panel_on[0]) - mdfld_dsi_brightness_control(dev, 0, - dev_priv->brightness_adjusted); - } - - if (dev_priv->dpi_panel_on[2]) - mdfld_dsi_brightness_control(dev, 2, - dev_priv->brightness_adjusted); - gma_power_end(dev); - } - - /* cache the brightness for later use */ - dev_priv->brightness = level; - return 0; -} - -static int mdfld_get_brightness(struct backlight_device *bd) -{ - struct drm_device *dev = - (struct drm_device *)bl_get_data(mdfld_backlight_device); - struct drm_psb_private *dev_priv = dev->dev_private; - - DRM_DEBUG_DRIVER("brightness = 0x%x \n", dev_priv->brightness); - - /* return locally cached var instead of HW read (due to DPST etc.) */ - return dev_priv->brightness; -} - -static const struct backlight_ops mdfld_ops = { - .get_brightness = mdfld_get_brightness, - .update_status = mdfld_set_brightness, -}; - -static int device_backlight_init(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv = (struct drm_psb_private *) - dev->dev_private; - - dev_priv->blc_adj1 = BLC_ADJUSTMENT_MAX; - dev_priv->blc_adj2 = BLC_ADJUSTMENT_MAX; - - return 0; -} - -static int mdfld_backlight_init(struct drm_device *dev) -{ - struct backlight_properties props; - int ret = 0; - - memset(&props, 0, sizeof(struct backlight_properties)); - props.max_brightness = BRIGHTNESS_MAX_LEVEL; - props.type = BACKLIGHT_PLATFORM; - mdfld_backlight_device = backlight_device_register("mdfld-bl", - NULL, (void *)dev, &mdfld_ops, &props); - - if (IS_ERR(mdfld_backlight_device)) - return PTR_ERR(mdfld_backlight_device); - - ret = device_backlight_init(dev); - if (ret) - return ret; - - mdfld_backlight_device->props.brightness = BRIGHTNESS_MAX_LEVEL; - mdfld_backlight_device->props.max_brightness = BRIGHTNESS_MAX_LEVEL; - backlight_update_status(mdfld_backlight_device); - return 0; -} -#endif - -struct backlight_device *mdfld_get_backlight_device(void) -{ -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE - return mdfld_backlight_device; -#else - return NULL; -#endif -} - -/* - * mdfld_save_display_registers - * - * Description: We are going to suspend so save current display - * register state. - * - * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio - */ -static int mdfld_save_display_registers(struct drm_device *dev, int pipenum) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - struct medfield_state *regs = &dev_priv->regs.mdfld; - struct psb_pipe *pipe = &dev_priv->regs.pipe[pipenum]; - const struct psb_offset *map = &dev_priv->regmap[pipenum]; - int i; - u32 *mipi_val; - - /* register */ - u32 mipi_reg = MIPI; - - switch (pipenum) { - case 0: - mipi_val = ®s->saveMIPI; - break; - case 1: - mipi_val = ®s->saveMIPI; - break; - case 2: - /* register */ - mipi_reg = MIPI_C; - /* pointer to values */ - mipi_val = ®s->saveMIPI_C; - break; - default: - DRM_ERROR("%s, invalid pipe number.\n", __func__); - return -EINVAL; - } - - /* Pipe & plane A info */ - pipe->dpll = PSB_RVDC32(map->dpll); - pipe->fp0 = PSB_RVDC32(map->fp0); - pipe->conf = PSB_RVDC32(map->conf); - pipe->htotal = PSB_RVDC32(map->htotal); - pipe->hblank = PSB_RVDC32(map->hblank); - pipe->hsync = PSB_RVDC32(map->hsync); - pipe->vtotal = PSB_RVDC32(map->vtotal); - pipe->vblank = PSB_RVDC32(map->vblank); - pipe->vsync = PSB_RVDC32(map->vsync); - pipe->src = PSB_RVDC32(map->src); - pipe->stride = PSB_RVDC32(map->stride); - pipe->linoff = PSB_RVDC32(map->linoff); - pipe->tileoff = PSB_RVDC32(map->tileoff); - pipe->size = PSB_RVDC32(map->size); - pipe->pos = PSB_RVDC32(map->pos); - pipe->surf = PSB_RVDC32(map->surf); - pipe->cntr = PSB_RVDC32(map->cntr); - pipe->status = PSB_RVDC32(map->status); - - /*save palette (gamma) */ - for (i = 0; i < 256; i++) - pipe->palette[i] = PSB_RVDC32(map->palette + (i << 2)); - - if (pipenum == 1) { - regs->savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL); - regs->savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS); - - regs->saveHDMIPHYMISCCTL = PSB_RVDC32(HDMIPHYMISCCTL); - regs->saveHDMIB_CONTROL = PSB_RVDC32(HDMIB_CONTROL); - return 0; - } - - *mipi_val = PSB_RVDC32(mipi_reg); - return 0; -} - -/* - * mdfld_restore_display_registers - * - * Description: We are going to resume so restore display register state. - * - * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio - */ -static int mdfld_restore_display_registers(struct drm_device *dev, int pipenum) -{ - /* To get panel out of ULPS mode. */ - u32 temp = 0; - u32 device_ready_reg = DEVICE_READY_REG; - struct drm_psb_private *dev_priv = dev->dev_private; - struct mdfld_dsi_config *dsi_config = NULL; - struct medfield_state *regs = &dev_priv->regs.mdfld; - struct psb_pipe *pipe = &dev_priv->regs.pipe[pipenum]; - const struct psb_offset *map = &dev_priv->regmap[pipenum]; - u32 i; - u32 dpll; - u32 timeout = 0; - - /* register */ - u32 mipi_reg = MIPI; - - /* values */ - u32 dpll_val = pipe->dpll; - u32 mipi_val = regs->saveMIPI; - - switch (pipenum) { - case 0: - dpll_val &= ~DPLL_VCO_ENABLE; - dsi_config = dev_priv->dsi_configs[0]; - break; - case 1: - dpll_val &= ~DPLL_VCO_ENABLE; - break; - case 2: - mipi_reg = MIPI_C; - mipi_val = regs->saveMIPI_C; - dsi_config = dev_priv->dsi_configs[1]; - break; - default: - DRM_ERROR("%s, invalid pipe number.\n", __func__); - return -EINVAL; - } - - /*make sure VGA plane is off. it initializes to on after reset!*/ - PSB_WVDC32(0x80000000, VGACNTRL); - - if (pipenum == 1) { - PSB_WVDC32(dpll_val & ~DPLL_VCO_ENABLE, map->dpll); - PSB_RVDC32(map->dpll); - - PSB_WVDC32(pipe->fp0, map->fp0); - } else { - - dpll = PSB_RVDC32(map->dpll); - - if (!(dpll & DPLL_VCO_ENABLE)) { - - /* When ungating power of DPLL, needs to wait 0.5us - before enable the VCO */ - if (dpll & MDFLD_PWR_GATE_EN) { - dpll &= ~MDFLD_PWR_GATE_EN; - PSB_WVDC32(dpll, map->dpll); - /* FIXME_MDFLD PO - change 500 to 1 after PO */ - udelay(500); - } - - PSB_WVDC32(pipe->fp0, map->fp0); - PSB_WVDC32(dpll_val, map->dpll); - /* FIXME_MDFLD PO - change 500 to 1 after PO */ - udelay(500); - - dpll_val |= DPLL_VCO_ENABLE; - PSB_WVDC32(dpll_val, map->dpll); - PSB_RVDC32(map->dpll); - - /* wait for DSI PLL to lock */ - while (timeout < 20000 && - !(PSB_RVDC32(map->conf) & PIPECONF_DSIPLL_LOCK)) { - udelay(150); - timeout++; - } - - if (timeout == 20000) { - DRM_ERROR("%s, can't lock DSIPLL.\n", - __func__); - return -EINVAL; - } - } - } - /* Restore mode */ - PSB_WVDC32(pipe->htotal, map->htotal); - PSB_WVDC32(pipe->hblank, map->hblank); - PSB_WVDC32(pipe->hsync, map->hsync); - PSB_WVDC32(pipe->vtotal, map->vtotal); - PSB_WVDC32(pipe->vblank, map->vblank); - PSB_WVDC32(pipe->vsync, map->vsync); - PSB_WVDC32(pipe->src, map->src); - PSB_WVDC32(pipe->status, map->status); - - /*set up the plane*/ - PSB_WVDC32(pipe->stride, map->stride); - PSB_WVDC32(pipe->linoff, map->linoff); - PSB_WVDC32(pipe->tileoff, map->tileoff); - PSB_WVDC32(pipe->size, map->size); - PSB_WVDC32(pipe->pos, map->pos); - PSB_WVDC32(pipe->surf, map->surf); - - if (pipenum == 1) { - /* restore palette (gamma) */ - /*DRM_UDELAY(50000); */ - for (i = 0; i < 256; i++) - PSB_WVDC32(pipe->palette[i], map->palette + (i << 2)); - - PSB_WVDC32(regs->savePFIT_CONTROL, PFIT_CONTROL); - PSB_WVDC32(regs->savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS); - - /*TODO: resume HDMI port */ - - /*TODO: resume pipe*/ - - /*enable the plane*/ - PSB_WVDC32(pipe->cntr & ~DISPLAY_PLANE_ENABLE, map->cntr); - - return 0; - } - - /*set up pipe related registers*/ - PSB_WVDC32(mipi_val, mipi_reg); - - /*setup MIPI adapter + MIPI IP registers*/ - if (dsi_config) - mdfld_dsi_controller_init(dsi_config, pipenum); - - if (in_atomic() || in_interrupt()) - mdelay(20); - else - msleep(20); - - /*enable the plane*/ - PSB_WVDC32(pipe->cntr, map->cntr); - - if (in_atomic() || in_interrupt()) - mdelay(20); - else - msleep(20); - - /* LP Hold Release */ - temp = REG_READ(mipi_reg); - temp |= LP_OUTPUT_HOLD_RELEASE; - REG_WRITE(mipi_reg, temp); - mdelay(1); - - - /* Set DSI host to exit from Utra Low Power State */ - temp = REG_READ(device_ready_reg); - temp &= ~ULPS_MASK; - temp |= 0x3; - temp |= EXIT_ULPS_DEV_READY; - REG_WRITE(device_ready_reg, temp); - mdelay(1); - - temp = REG_READ(device_ready_reg); - temp &= ~ULPS_MASK; - temp |= EXITING_ULPS; - REG_WRITE(device_ready_reg, temp); - mdelay(1); - - /*enable the pipe*/ - PSB_WVDC32(pipe->conf, map->conf); - - /* restore palette (gamma) */ - /*DRM_UDELAY(50000); */ - for (i = 0; i < 256; i++) - PSB_WVDC32(pipe->palette[i], map->palette + (i << 2)); - - return 0; -} - -static int mdfld_save_registers(struct drm_device *dev) -{ - /* mdfld_save_cursor_overlay_registers(dev); */ - mdfld_save_display_registers(dev, 0); - mdfld_save_display_registers(dev, 2); - mdfld_disable_crtc(dev, 0); - mdfld_disable_crtc(dev, 2); - - return 0; -} - -static int mdfld_restore_registers(struct drm_device *dev) -{ - mdfld_restore_display_registers(dev, 2); - mdfld_restore_display_registers(dev, 0); - /* mdfld_restore_cursor_overlay_registers(dev); */ - - return 0; -} - -static int mdfld_power_down(struct drm_device *dev) -{ - /* FIXME */ - return 0; -} - -static int mdfld_power_up(struct drm_device *dev) -{ - /* FIXME */ - return 0; -} - -/* Medfield */ -static const struct psb_offset mdfld_regmap[3] = { - { - .fp0 = MRST_FPA0, - .fp1 = MRST_FPA1, - .cntr = DSPACNTR, - .conf = PIPEACONF, - .src = PIPEASRC, - .dpll = MRST_DPLL_A, - .htotal = HTOTAL_A, - .hblank = HBLANK_A, - .hsync = HSYNC_A, - .vtotal = VTOTAL_A, - .vblank = VBLANK_A, - .vsync = VSYNC_A, - .stride = DSPASTRIDE, - .size = DSPASIZE, - .pos = DSPAPOS, - .surf = DSPASURF, - .addr = MRST_DSPABASE, - .status = PIPEASTAT, - .linoff = DSPALINOFF, - .tileoff = DSPATILEOFF, - .palette = PALETTE_A, - }, - { - .fp0 = MDFLD_DPLL_DIV0, - .cntr = DSPBCNTR, - .conf = PIPEBCONF, - .src = PIPEBSRC, - .dpll = MDFLD_DPLL_B, - .htotal = HTOTAL_B, - .hblank = HBLANK_B, - .hsync = HSYNC_B, - .vtotal = VTOTAL_B, - .vblank = VBLANK_B, - .vsync = VSYNC_B, - .stride = DSPBSTRIDE, - .size = DSPBSIZE, - .pos = DSPBPOS, - .surf = DSPBSURF, - .addr = MRST_DSPBBASE, - .status = PIPEBSTAT, - .linoff = DSPBLINOFF, - .tileoff = DSPBTILEOFF, - .palette = PALETTE_B, - }, - { - .fp0 = MRST_FPA0, /* This is what the old code did ?? */ - .cntr = DSPCCNTR, - .conf = PIPECCONF, - .src = PIPECSRC, - /* No DPLL_C */ - .dpll = MRST_DPLL_A, - .htotal = HTOTAL_C, - .hblank = HBLANK_C, - .hsync = HSYNC_C, - .vtotal = VTOTAL_C, - .vblank = VBLANK_C, - .vsync = VSYNC_C, - .stride = DSPCSTRIDE, - .size = DSPBSIZE, - .pos = DSPCPOS, - .surf = DSPCSURF, - .addr = MDFLD_DSPCBASE, - .status = PIPECSTAT, - .linoff = DSPCLINOFF, - .tileoff = DSPCTILEOFF, - .palette = PALETTE_C, - }, -}; - -static int mdfld_chip_setup(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - if (pci_enable_msi(dev->pdev)) - dev_warn(dev->dev, "Enabling MSI failed!\n"); - dev_priv->regmap = mdfld_regmap; - return mid_chip_setup(dev); -} - -const struct psb_ops mdfld_chip_ops = { - .name = "mdfld", - .accel_2d = 0, - .pipes = 3, - .crtcs = 3, - .lvds_mask = (1 << 1), - .hdmi_mask = (1 << 1), - .cursor_needs_phys = 0, - .sgx_offset = MRST_SGX_OFFSET, - - .chip_setup = mdfld_chip_setup, - .crtc_helper = &mdfld_helper_funcs, - .crtc_funcs = &psb_intel_crtc_funcs, - - .output_init = mdfld_output_init, - -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE - .backlight_init = mdfld_backlight_init, -#endif - - .save_regs = mdfld_save_registers, - .restore_regs = mdfld_restore_registers, - .power_down = mdfld_power_down, - .power_up = mdfld_power_up, -}; diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c deleted file mode 100644 index d4813e03f5ee..000000000000 --- a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c +++ /dev/null @@ -1,1016 +0,0 @@ -/* - * Copyright © 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: - * jim liu <jim.liu@intel.com> - * Jackie Li<yaodong.li@intel.com> - */ - -#include "mdfld_dsi_dpi.h" -#include "mdfld_output.h" -#include "mdfld_dsi_pkg_sender.h" -#include "psb_drv.h" -#include "tc35876x-dsi-lvds.h" - -static void mdfld_dsi_dpi_shut_down(struct mdfld_dsi_dpi_output *output, - int pipe); - -static void mdfld_wait_for_HS_DATA_FIFO(struct drm_device *dev, u32 pipe) -{ - u32 gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe); - int timeout = 0; - - 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) - DRM_INFO("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 = MIPI_GEN_FIFO_STAT_REG(pipe); - int timeout = 0; - - 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) - DRM_INFO("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 = MIPI_GEN_FIFO_STAT_REG(pipe); - int timeout = 0; - - 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) - DRM_ERROR("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 = MIPI_INTR_STAT_REG(pipe); - int timeout = 0; - - 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) - DRM_ERROR("MIPI: SPL_PKT_SENT_INTERRUPT was not sent successfully!\n"); -} - -/* For TC35876X */ - -static void dsi_set_device_ready_state(struct drm_device *dev, int state, - int pipe) -{ - REG_FLD_MOD(MIPI_DEVICE_READY_REG(pipe), !!state, 0, 0); -} - -static void dsi_set_pipe_plane_enable_state(struct drm_device *dev, - int state, int pipe) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - u32 pipeconf_reg = PIPEACONF; - u32 dspcntr_reg = DSPACNTR; - - u32 dspcntr = dev_priv->dspcntr[pipe]; - u32 mipi = MIPI_PORT_EN | PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX; - - if (pipe) { - pipeconf_reg = PIPECCONF; - dspcntr_reg = DSPCCNTR; - } else - mipi &= (~0x03); - - if (state) { - /*Set up pipe */ - REG_WRITE(pipeconf_reg, BIT(31)); - - if (REG_BIT_WAIT(pipeconf_reg, 1, 30)) - dev_err(&dev->pdev->dev, "%s: Pipe enable timeout\n", - __func__); - - /*Set up display plane */ - REG_WRITE(dspcntr_reg, dspcntr); - } else { - u32 dspbase_reg = pipe ? MDFLD_DSPCBASE : MRST_DSPABASE; - - /* Put DSI lanes to ULPS to disable pipe */ - REG_FLD_MOD(MIPI_DEVICE_READY_REG(pipe), 2, 2, 1); - REG_READ(MIPI_DEVICE_READY_REG(pipe)); /* posted write? */ - - /* LP Hold */ - REG_FLD_MOD(MIPI_PORT_CONTROL(pipe), 0, 16, 16); - REG_READ(MIPI_PORT_CONTROL(pipe)); /* posted write? */ - - /* Disable display plane */ - REG_FLD_MOD(dspcntr_reg, 0, 31, 31); - - /* Flush the plane changes ??? posted write? */ - REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); - REG_READ(dspbase_reg); - - /* Disable PIPE */ - REG_FLD_MOD(pipeconf_reg, 0, 31, 31); - - if (REG_BIT_WAIT(pipeconf_reg, 0, 30)) - dev_err(&dev->pdev->dev, "%s: Pipe disable timeout\n", - __func__); - - if (REG_BIT_WAIT(MIPI_GEN_FIFO_STAT_REG(pipe), 1, 28)) - dev_err(&dev->pdev->dev, "%s: FIFO not empty\n", - __func__); - } -} - -static void mdfld_dsi_configure_down(struct mdfld_dsi_encoder *dsi_encoder, - int pipe) -{ - 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; - - if (!dev_priv->dpi_panel_on[pipe]) { - dev_err(dev->dev, "DPI panel is already off\n"); - return; - } - tc35876x_toshiba_bridge_panel_off(dev); - tc35876x_set_bridge_reset_state(dev, 1); - dsi_set_pipe_plane_enable_state(dev, 0, pipe); - mdfld_dsi_dpi_shut_down(dpi_output, pipe); - dsi_set_device_ready_state(dev, 0, pipe); -} - -static void mdfld_dsi_configure_up(struct mdfld_dsi_encoder *dsi_encoder, - int pipe) -{ - 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; - - if (dev_priv->dpi_panel_on[pipe]) { - dev_err(dev->dev, "DPI panel is already on\n"); - return; - } - - /* For resume path sequence */ - mdfld_dsi_dpi_shut_down(dpi_output, pipe); - dsi_set_device_ready_state(dev, 0, pipe); - - dsi_set_device_ready_state(dev, 1, pipe); - tc35876x_set_bridge_reset_state(dev, 0); - tc35876x_configure_lvds_bridge(dev); - mdfld_dsi_dpi_turn_on(dpi_output, pipe); /* Send turn on command */ - dsi_set_pipe_plane_enable_state(dev, 1, pipe); -} -/* End for TC35876X */ - -/* ************************************************************************* *\ - * 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! -\* ************************************************************************* */ -static 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 = MIPI_HS_GEN_DATA_REG(pipe); - u32 gen_ctrl_reg = MIPI_HS_GEN_CTRL_REG(pipe); - u32 gen_ctrl_val = GEN_LONG_WRITE; - - DRM_INFO("Enter mrst init TPO MIPI display.\n"); - - 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_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_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; - int lane_count = dsi_config->lane_count; - struct mdfld_dsi_dpi_timing dpi_timing; - struct drm_display_mode *mode = dsi_config->mode; - u32 val; - - /*un-ready device*/ - REG_FLD_MOD(MIPI_DEVICE_READY_REG(pipe), 0, 0, 0); - - /*init dsi adapter before kicking off*/ - REG_WRITE(MIPI_CTRL_REG(pipe), 0x00000018); - - /*enable all interrupts*/ - REG_WRITE(MIPI_INTR_EN_REG(pipe), 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(MIPI_DSI_FUNC_PRG_REG(pipe), val); - - REG_WRITE(MIPI_HS_TX_TIMEOUT_REG(pipe), - (mode->vtotal * mode->htotal * dsi_config->bpp / - (8 * lane_count)) & DSI_HS_TX_TIMEOUT_MASK); - REG_WRITE(MIPI_LP_RX_TIMEOUT_REG(pipe), - 0xffff & DSI_LP_RX_TIMEOUT_MASK); - - /*max value: 20 clock cycles of txclkesc*/ - REG_WRITE(MIPI_TURN_AROUND_TIMEOUT_REG(pipe), - 0x14 & DSI_TURN_AROUND_TIMEOUT_MASK); - - /*min 21 txclkesc, max: ffffh*/ - REG_WRITE(MIPI_DEVICE_RESET_TIMER_REG(pipe), - 0xffff & DSI_RESET_TIMER_MASK); - - REG_WRITE(MIPI_DPI_RESOLUTION_REG(pipe), - 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(MIPI_HSYNC_COUNT_REG(pipe), - dpi_timing.hsync_count & DSI_DPI_TIMING_MASK); - REG_WRITE(MIPI_HBP_COUNT_REG(pipe), - dpi_timing.hbp_count & DSI_DPI_TIMING_MASK); - REG_WRITE(MIPI_HFP_COUNT_REG(pipe), - dpi_timing.hfp_count & DSI_DPI_TIMING_MASK); - REG_WRITE(MIPI_HACTIVE_COUNT_REG(pipe), - dpi_timing.hactive_count & DSI_DPI_TIMING_MASK); - REG_WRITE(MIPI_VSYNC_COUNT_REG(pipe), - dpi_timing.vsync_count & DSI_DPI_TIMING_MASK); - REG_WRITE(MIPI_VBP_COUNT_REG(pipe), - dpi_timing.vbp_count & DSI_DPI_TIMING_MASK); - REG_WRITE(MIPI_VFP_COUNT_REG(pipe), - dpi_timing.vfp_count & DSI_DPI_TIMING_MASK); - - REG_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT_REG(pipe), 0x46); - - /*min: 7d0 max: 4e20*/ - REG_WRITE(MIPI_INIT_COUNT_REG(pipe), 0x000007d0); - - /*set up video mode*/ - val = dsi_config->video_mode | DSI_DPI_COMPLETE_LAST_LINE; - REG_WRITE(MIPI_VIDEO_MODE_FORMAT_REG(pipe), val); - - REG_WRITE(MIPI_EOT_DISABLE_REG(pipe), 0x00000000); - - REG_WRITE(MIPI_LP_BYTECLK_REG(pipe), 0x00000004); - - /*TODO: figure out how to setup these registers*/ - if (mdfld_get_panel_type(dev, pipe) == TC35876X) - REG_WRITE(MIPI_DPHY_PARAM_REG(pipe), 0x2A0c6008); - else - REG_WRITE(MIPI_DPHY_PARAM_REG(pipe), 0x150c3408); - - REG_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT_REG(pipe), (0xa << 16) | 0x14); - - if (mdfld_get_panel_type(dev, pipe) == TC35876X) - tc35876x_set_bridge_reset_state(dev, 0); /*Pull High Reset */ - - /*set device ready*/ - REG_FLD_MOD(MIPI_DEVICE_READY_REG(pipe), 1, 0, 0); -} - -void mdfld_dsi_dpi_turn_on(struct mdfld_dsi_dpi_output *output, int pipe) -{ - struct drm_device *dev = output->dev; - - /* clear special packet sent bit */ - if (REG_READ(MIPI_INTR_STAT_REG(pipe)) & DSI_INTR_STATE_SPL_PKG_SENT) - REG_WRITE(MIPI_INTR_STAT_REG(pipe), - DSI_INTR_STATE_SPL_PKG_SENT); - - /*send turn on package*/ - REG_WRITE(MIPI_DPI_CONTROL_REG(pipe), DSI_DPI_CTRL_HS_TURN_ON); - - /*wait for SPL_PKG_SENT interrupt*/ - mdfld_wait_for_SPL_PKG_SENT(dev, pipe); - - if (REG_READ(MIPI_INTR_STAT_REG(pipe)) & DSI_INTR_STATE_SPL_PKG_SENT) - REG_WRITE(MIPI_INTR_STAT_REG(pipe), - 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; - - /*if output is on, or mode setting didn't happen, ignore this*/ - if ((!output->panel_on) || output->first_boot) { - output->first_boot = 0; - return; - } - - /* 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(MIPI_INTR_STAT_REG(pipe)) & DSI_INTR_STATE_SPL_PKG_SENT) - REG_WRITE(MIPI_INTR_STAT_REG(pipe), - DSI_INTR_STATE_SPL_PKG_SENT); - - if (REG_READ(MIPI_DPI_CONTROL_REG(pipe)) == DSI_DPI_CTRL_HS_SHUTDOWN) - goto shutdown_out; - - REG_WRITE(MIPI_DPI_CONTROL_REG(pipe), 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; */ -} - -static 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; - - /*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 if (mdfld_get_panel_type(dev, pipe) == TC35876X) - mdfld_dsi_configure_up(dsi_encoder, pipe); - else { - /*enable mipi port*/ - REG_WRITE(MIPI_PORT_CONTROL(pipe), - REG_READ(MIPI_PORT_CONTROL(pipe)) | BIT(31)); - REG_READ(MIPI_PORT_CONTROL(pipe)); - - mdfld_dsi_dpi_turn_on(dpi_output, pipe); - mdfld_dsi_tpo_ic_init(dsi_config, pipe); - } - dev_priv->dpi_panel_on[pipe] = true; - } else { - if (mdfld_get_panel_type(dev, pipe) == TMD_VID) - mdfld_dsi_dpi_shut_down(dpi_output, pipe); - else if (mdfld_get_panel_type(dev, pipe) == TC35876X) - mdfld_dsi_configure_down(dsi_encoder, pipe); - else { - mdfld_dsi_dpi_shut_down(dpi_output, pipe); - - /*disable mipi port*/ - REG_WRITE(MIPI_PORT_CONTROL(pipe), - REG_READ(MIPI_PORT_CONTROL(pipe)) & ~BIT(31)); - REG_READ(MIPI_PORT_CONTROL(pipe)); - } - dev_priv->dpi_panel_on[pipe] = false; - } - gma_power_end(dev); -} - -void mdfld_dsi_dpi_dpms(struct drm_encoder *encoder, int mode) -{ - mdfld_dsi_dpi_set_power(encoder, mode == DRM_MODE_DPMS_ON); -} - -bool mdfld_dsi_dpi_mode_fixup(struct drm_encoder *encoder, - const 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); -} - -/* For TC35876X */ -/* This functionality was implemented in FW in iCDK */ -/* But removed in DV0 and later. So need to add here. */ -static void mipi_set_properties(struct mdfld_dsi_config *dsi_config, int pipe) -{ - struct drm_device *dev = dsi_config->dev; - - REG_WRITE(MIPI_CTRL_REG(pipe), 0x00000018); - REG_WRITE(MIPI_INTR_EN_REG(pipe), 0xffffffff); - REG_WRITE(MIPI_HS_TX_TIMEOUT_REG(pipe), 0xffffff); - REG_WRITE(MIPI_LP_RX_TIMEOUT_REG(pipe), 0xffffff); - REG_WRITE(MIPI_TURN_AROUND_TIMEOUT_REG(pipe), 0x14); - REG_WRITE(MIPI_DEVICE_RESET_TIMER_REG(pipe), 0xff); - REG_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT_REG(pipe), 0x25); - REG_WRITE(MIPI_INIT_COUNT_REG(pipe), 0xf0); - REG_WRITE(MIPI_EOT_DISABLE_REG(pipe), 0x00000000); - REG_WRITE(MIPI_LP_BYTECLK_REG(pipe), 0x00000004); - REG_WRITE(MIPI_DBI_BW_CTRL_REG(pipe), 0x00000820); - REG_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT_REG(pipe), (0xa << 16) | 0x14); -} - -static void mdfld_mipi_set_video_timing(struct mdfld_dsi_config *dsi_config, - int pipe) -{ - struct drm_device *dev = dsi_config->dev; - struct mdfld_dsi_dpi_timing dpi_timing; - struct drm_display_mode *mode = dsi_config->mode; - - mdfld_dsi_dpi_timing_calculation(mode, &dpi_timing, - dsi_config->lane_count, - dsi_config->bpp); - - REG_WRITE(MIPI_DPI_RESOLUTION_REG(pipe), - mode->vdisplay << 16 | mode->hdisplay); - REG_WRITE(MIPI_HSYNC_COUNT_REG(pipe), - dpi_timing.hsync_count & DSI_DPI_TIMING_MASK); - REG_WRITE(MIPI_HBP_COUNT_REG(pipe), - dpi_timing.hbp_count & DSI_DPI_TIMING_MASK); - REG_WRITE(MIPI_HFP_COUNT_REG(pipe), - dpi_timing.hfp_count & DSI_DPI_TIMING_MASK); - REG_WRITE(MIPI_HACTIVE_COUNT_REG(pipe), - dpi_timing.hactive_count & DSI_DPI_TIMING_MASK); - REG_WRITE(MIPI_VSYNC_COUNT_REG(pipe), - dpi_timing.vsync_count & DSI_DPI_TIMING_MASK); - REG_WRITE(MIPI_VBP_COUNT_REG(pipe), - dpi_timing.vbp_count & DSI_DPI_TIMING_MASK); - REG_WRITE(MIPI_VFP_COUNT_REG(pipe), - dpi_timing.vfp_count & DSI_DPI_TIMING_MASK); -} - -static void mdfld_mipi_config(struct mdfld_dsi_config *dsi_config, int pipe) -{ - struct drm_device *dev = dsi_config->dev; - int lane_count = dsi_config->lane_count; - - if (pipe) { - REG_WRITE(MIPI_PORT_CONTROL(0), 0x00000002); - REG_WRITE(MIPI_PORT_CONTROL(2), 0x80000000); - } else { - REG_WRITE(MIPI_PORT_CONTROL(0), 0x80010000); - REG_WRITE(MIPI_PORT_CONTROL(2), 0x00); - } - - REG_WRITE(MIPI_DPHY_PARAM_REG(pipe), 0x150A600F); - REG_WRITE(MIPI_VIDEO_MODE_FORMAT_REG(pipe), 0x0000000F); - - /* lane_count = 3 */ - REG_WRITE(MIPI_DSI_FUNC_PRG_REG(pipe), 0x00000200 | lane_count); - - mdfld_mipi_set_video_timing(dsi_config, pipe); -} - -static void mdfld_set_pipe_timing(struct mdfld_dsi_config *dsi_config, int pipe) -{ - struct drm_device *dev = dsi_config->dev; - struct drm_display_mode *mode = dsi_config->mode; - - REG_WRITE(HTOTAL_A, ((mode->htotal - 1) << 16) | (mode->hdisplay - 1)); - REG_WRITE(HBLANK_A, ((mode->htotal - 1) << 16) | (mode->hdisplay - 1)); - REG_WRITE(HSYNC_A, - ((mode->hsync_end - 1) << 16) | (mode->hsync_start - 1)); - - REG_WRITE(VTOTAL_A, ((mode->vtotal - 1) << 16) | (mode->vdisplay - 1)); - REG_WRITE(VBLANK_A, ((mode->vtotal - 1) << 16) | (mode->vdisplay - 1)); - REG_WRITE(VSYNC_A, - ((mode->vsync_end - 1) << 16) | (mode->vsync_start - 1)); - - REG_WRITE(PIPEASRC, - ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); -} -/* End for TC35876X */ - -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 pipeconf = dev_priv->pipeconf[pipe]; - u32 dspcntr = dev_priv->dspcntr[pipe]; - u32 mipi = MIPI_PORT_EN | PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX; - - if (pipe) { - pipeconf_reg = PIPECCONF; - dspcntr_reg = DSPCCNTR; - } else { - if (mdfld_get_panel_type(dev, pipe) == TC35876X) - mipi &= (~0x03); /* Use all four lanes */ - else - mipi |= 2; - } - - /*start up display island if it was shutdown*/ - if (!gma_power_begin(dev, true)) - return; - - if (mdfld_get_panel_type(dev, pipe) == TC35876X) { - /* - * The following logic is required to reset the bridge and - * configure. This also starts the DSI clock at 200MHz. - */ - tc35876x_set_bridge_reset_state(dev, 0); /*Pull High Reset */ - tc35876x_toshiba_bridge_panel_on(dev); - udelay(100); - /* Now start the DSI clock */ - REG_WRITE(MRST_DPLL_A, 0x00); - REG_WRITE(MRST_FPA0, 0xC1); - REG_WRITE(MRST_DPLL_A, 0x00800000); - udelay(500); - REG_WRITE(MRST_DPLL_A, 0x80800000); - - if (REG_BIT_WAIT(pipeconf_reg, 1, 29)) - dev_err(&dev->pdev->dev, "%s: DSI PLL lock timeout\n", - __func__); - - REG_WRITE(MIPI_DPHY_PARAM_REG(pipe), 0x2A0c6008); - - mipi_set_properties(dsi_config, pipe); - mdfld_mipi_config(dsi_config, pipe); - mdfld_set_pipe_timing(dsi_config, pipe); - - REG_WRITE(DSPABASE, 0x00); - REG_WRITE(DSPASIZE, - ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); - - REG_WRITE(DSPACNTR, 0x98000000); - REG_WRITE(DSPASURF, 0x00); - - REG_WRITE(VGACNTRL, 0x80000000); - REG_WRITE(DEVICE_READY_REG, 0x00000001); - - REG_WRITE(MIPI_PORT_CONTROL(pipe), 0x80810000); - } else { - /*set up mipi port FIXME: do at init time */ - REG_WRITE(MIPI_PORT_CONTROL(pipe), mipi); - } - REG_READ(MIPI_PORT_CONTROL(pipe)); - - if (mdfld_get_panel_type(dev, pipe) == TMD_VID) { - /* NOP */ - } else if (mdfld_get_panel_type(dev, pipe) == TC35876X) { - /* set up DSI controller DPI interface */ - mdfld_dsi_dpi_controller_init(dsi_config, pipe); - - /* Configure MIPI Bridge and Panel */ - tc35876x_configure_lvds_bridge(dev); - dev_priv->dpi_panel_on[pipe] = true; - } else { - /*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 */ - - if (mdfld_get_panel_type(dev, pipe) == TMD_VID) { - /* NOP */ - } else if (mdfld_get_panel_type(dev, pipe) == TC35876X) { - mdfld_dsi_dpi_turn_on(dpi_output, pipe); - } else { - /* 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, - const 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; - int pipe; - u32 data; - int ret; - - pipe = dsi_connector->pipe; - - if (mdfld_get_panel_type(dev, pipe) != TC35876X) { - dsi_config = mdfld_dsi_get_config(dsi_connector); - - /* 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, false); - 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) { - DRM_ERROR("No memory\n"); - return NULL; - } - - if (dsi_connector->pipe) - dpi_output->panel_on = 0; - else - dpi_output->panel_on = 0; - - dpi_output->dev = dev; - if (mdfld_get_panel_type(dev, pipe) != TC35876X) - dpi_output->p_funcs = p_funcs; - dpi_output->first_boot = 1; - - /*get fixed mode*/ - dsi_config = mdfld_dsi_get_config(dsi_connector); - - /*create drm encoder object*/ - connector = &dsi_connector->base.base; - encoder = &dpi_output->base.base.base; - drm_encoder_init(dev, - encoder, - p_funcs->encoder_funcs, - DRM_MODE_ENCODER_LVDS); - 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); - } - - dsi_connector->base.encoder = &dpi_output->base.base; - - return &dpi_output->base; -} diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.h b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.h deleted file mode 100644 index 2b40663e1696..000000000000 --- a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright © 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: - * jim liu <jim.liu@intel.com> - * Jackie Li<yaodong.li@intel.com> - */ - -#ifndef __MDFLD_DSI_DPI_H__ -#define __MDFLD_DSI_DPI_H__ - -#include "mdfld_dsi_output.h" -#include "mdfld_output.h" - -struct mdfld_dsi_dpi_timing { - u16 hsync_count; - u16 hbp_count; - u16 hfp_count; - u16 hactive_count; - u16 vsync_count; - u16 vbp_count; - u16 vfp_count; -}; - -struct mdfld_dsi_dpi_output { - struct mdfld_dsi_encoder base; - struct drm_device *dev; - - int panel_on; - int first_boot; - - const struct panel_funcs *p_funcs; -}; - -#define MDFLD_DSI_DPI_OUTPUT(dsi_encoder)\ - container_of(dsi_encoder, struct mdfld_dsi_dpi_output, base) - -/* Export functions */ -extern int mdfld_dsi_dpi_timing_calculation(struct drm_display_mode *mode, - struct mdfld_dsi_dpi_timing *dpi_timing, - int num_lane, int bpp); -extern struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev, - struct mdfld_dsi_connector *dsi_connector, - const struct panel_funcs *p_funcs); - -/* MDFLD DPI helper functions */ -extern void mdfld_dsi_dpi_dpms(struct drm_encoder *encoder, int mode); -extern bool mdfld_dsi_dpi_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); -extern void mdfld_dsi_dpi_prepare(struct drm_encoder *encoder); -extern void mdfld_dsi_dpi_commit(struct drm_encoder *encoder); -extern void mdfld_dsi_dpi_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); -extern void mdfld_dsi_dpi_turn_on(struct mdfld_dsi_dpi_output *output, - int pipe); -extern void mdfld_dsi_dpi_controller_init(struct mdfld_dsi_config *dsi_config, - int pipe); -#endif /*__MDFLD_DSI_DPI_H__*/ diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/drivers/gpu/drm/gma500/mdfld_dsi_output.c deleted file mode 100644 index 3abf8315f57c..000000000000 --- a/drivers/gpu/drm/gma500/mdfld_dsi_output.c +++ /dev/null @@ -1,615 +0,0 @@ -/* - * Copyright © 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: - * jim liu <jim.liu@intel.com> - * Jackie Li<yaodong.li@intel.com> - */ - -#include <linux/module.h> - -#include "mdfld_dsi_output.h" -#include "mdfld_dsi_dpi.h" -#include "mdfld_output.h" -#include "mdfld_dsi_pkg_sender.h" -#include "tc35876x-dsi-lvds.h" -#include <linux/pm_runtime.h> -#include <asm/intel_scu_ipc.h> - -/* get the LABC from command line. */ -static int LABC_control = 1; - -#ifdef MODULE -module_param(LABC_control, int, 0644); -#else - -static int __init parse_LABC_control(char *arg) -{ - /* LABC control can be passed in as a cmdline parameter */ - /* to enable this feature add LABC=1 to cmdline */ - /* to disable this feature add LABC=0 to cmdline */ - if (!arg) - return -EINVAL; - - if (!strcasecmp(arg, "0")) - LABC_control = 0; - else if (!strcasecmp(arg, "1")) - LABC_control = 1; - - return 0; -} -early_param("LABC", parse_LABC_control); -#endif - -/** - * Check and see if the generic control or data buffer is empty and ready. - */ -void mdfld_dsi_gen_fifo_ready(struct drm_device *dev, u32 gen_fifo_stat_reg, - u32 fifo_stat) -{ - u32 GEN_BF_time_out_count; - - /* Check MIPI Adatper command registers */ - for (GEN_BF_time_out_count = 0; - GEN_BF_time_out_count < GEN_FB_TIME_OUT; - GEN_BF_time_out_count++) { - if ((REG_READ(gen_fifo_stat_reg) & fifo_stat) == fifo_stat) - break; - udelay(100); - } - - if (GEN_BF_time_out_count == GEN_FB_TIME_OUT) - DRM_ERROR("mdfld_dsi_gen_fifo_ready, Timeout. gen_fifo_stat_reg = 0x%x.\n", - gen_fifo_stat_reg); -} - -/** - * Manage the DSI MIPI keyboard and display brightness. - * FIXME: this is exported to OSPM code. should work out an specific - * display interface to OSPM. - */ - -void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config, int pipe) -{ - struct mdfld_dsi_pkg_sender *sender = - mdfld_dsi_get_pkg_sender(dsi_config); - struct drm_device *dev; - struct drm_psb_private *dev_priv; - u32 gen_ctrl_val; - - if (!sender) { - DRM_ERROR("No sender found\n"); - return; - } - - dev = sender->dev; - dev_priv = dev->dev_private; - - /* Set default display backlight value to 85% (0xd8)*/ - mdfld_dsi_send_mcs_short(sender, write_display_brightness, 0xd8, 1, - true); - - /* Set minimum brightness setting of CABC function to 20% (0x33)*/ - mdfld_dsi_send_mcs_short(sender, write_cabc_min_bright, 0x33, 1, true); - - /* Enable backlight or/and LABC */ - gen_ctrl_val = BRIGHT_CNTL_BLOCK_ON | DISPLAY_DIMMING_ON | - BACKLIGHT_ON; - if (LABC_control == 1) - gen_ctrl_val |= DISPLAY_DIMMING_ON | DISPLAY_BRIGHTNESS_AUTO - | GAMMA_AUTO; - - if (LABC_control == 1) - gen_ctrl_val |= AMBIENT_LIGHT_SENSE_ON; - - dev_priv->mipi_ctrl_display = gen_ctrl_val; - - mdfld_dsi_send_mcs_short(sender, write_ctrl_display, (u8)gen_ctrl_val, - 1, true); - - mdfld_dsi_send_mcs_short(sender, write_ctrl_cabc, UI_IMAGE, 1, true); -} - -void mdfld_dsi_brightness_control(struct drm_device *dev, int pipe, int level) -{ - struct mdfld_dsi_pkg_sender *sender; - struct drm_psb_private *dev_priv; - struct mdfld_dsi_config *dsi_config; - u32 gen_ctrl_val = 0; - int p_type = TMD_VID; - - if (!dev || (pipe != 0 && pipe != 2)) { - DRM_ERROR("Invalid parameter\n"); - return; - } - - p_type = mdfld_get_panel_type(dev, 0); - - dev_priv = dev->dev_private; - - if (pipe) - dsi_config = dev_priv->dsi_configs[1]; - else - dsi_config = dev_priv->dsi_configs[0]; - - sender = mdfld_dsi_get_pkg_sender(dsi_config); - - if (!sender) { - DRM_ERROR("No sender found\n"); - return; - } - - gen_ctrl_val = (level * 0xff / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL) & 0xff; - - dev_dbg(sender->dev->dev, "pipe = %d, gen_ctrl_val = %d.\n", - pipe, gen_ctrl_val); - - if (p_type == TMD_VID) { - /* Set display backlight value */ - mdfld_dsi_send_mcs_short(sender, tmd_write_display_brightness, - (u8)gen_ctrl_val, 1, true); - } else { - /* Set display backlight value */ - mdfld_dsi_send_mcs_short(sender, write_display_brightness, - (u8)gen_ctrl_val, 1, true); - - /* Enable backlight control */ - if (level == 0) - gen_ctrl_val = 0; - else - gen_ctrl_val = dev_priv->mipi_ctrl_display; - - mdfld_dsi_send_mcs_short(sender, write_ctrl_display, - (u8)gen_ctrl_val, 1, true); - } -} - -static int mdfld_dsi_get_panel_status(struct mdfld_dsi_config *dsi_config, - u8 dcs, u32 *data, bool hs) -{ - struct mdfld_dsi_pkg_sender *sender - = mdfld_dsi_get_pkg_sender(dsi_config); - - if (!sender || !data) { - DRM_ERROR("Invalid parameter\n"); - return -EINVAL; - } - - return mdfld_dsi_read_mcs(sender, dcs, data, 1, hs); -} - -int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config, u32 *mode, - bool hs) -{ - if (!dsi_config || !mode) { - DRM_ERROR("Invalid parameter\n"); - return -EINVAL; - } - - return mdfld_dsi_get_panel_status(dsi_config, 0x0a, mode, hs); -} - -/* - * NOTE: this function was used by OSPM. - * TODO: will be removed later, should work out display interfaces for OSPM - */ -void mdfld_dsi_controller_init(struct mdfld_dsi_config *dsi_config, int pipe) -{ - if (!dsi_config || ((pipe != 0) && (pipe != 2))) { - DRM_ERROR("Invalid parameters\n"); - return; - } - - mdfld_dsi_dpi_controller_init(dsi_config, pipe); -} - -static void mdfld_dsi_connector_save(struct drm_connector *connector) -{ -} - -static void mdfld_dsi_connector_restore(struct drm_connector *connector) -{ -} - -/* FIXME: start using the force parameter */ -static enum drm_connector_status -mdfld_dsi_connector_detect(struct drm_connector *connector, bool force) -{ - struct mdfld_dsi_connector *dsi_connector - = mdfld_dsi_connector(connector); - - dsi_connector->status = connector_status_connected; - - return dsi_connector->status; -} - -static int mdfld_dsi_connector_set_property(struct drm_connector *connector, - struct drm_property *property, - uint64_t value) -{ - struct drm_encoder *encoder = connector->encoder; - - if (!strcmp(property->name, "scaling mode") && encoder) { - struct psb_intel_crtc *psb_crtc = - to_psb_intel_crtc(encoder->crtc); - bool centerechange; - uint64_t val; - - if (!psb_crtc) - goto set_prop_error; - - switch (value) { - case DRM_MODE_SCALE_FULLSCREEN: - break; - case DRM_MODE_SCALE_NO_SCALE: - break; - case DRM_MODE_SCALE_ASPECT: - break; - default: - goto set_prop_error; - } - - if (drm_object_property_get_value(&connector->base, property, &val)) - goto set_prop_error; - - if (val == value) - goto set_prop_done; - - if (drm_object_property_set_value(&connector->base, - property, value)) - goto set_prop_error; - - centerechange = (val == DRM_MODE_SCALE_NO_SCALE) || - (value == DRM_MODE_SCALE_NO_SCALE); - - if (psb_crtc->saved_mode.hdisplay != 0 && - psb_crtc->saved_mode.vdisplay != 0) { - if (centerechange) { - if (!drm_crtc_helper_set_mode(encoder->crtc, - &psb_crtc->saved_mode, - encoder->crtc->x, - encoder->crtc->y, - encoder->crtc->fb)) - goto set_prop_error; - } else { - struct drm_encoder_helper_funcs *funcs = - encoder->helper_private; - funcs->mode_set(encoder, - &psb_crtc->saved_mode, - &psb_crtc->saved_adjusted_mode); - } - } - } else if (!strcmp(property->name, "backlight") && encoder) { - if (drm_object_property_set_value(&connector->base, property, - value)) - goto set_prop_error; - else - gma_backlight_set(encoder->dev, value); - } -set_prop_done: - return 0; -set_prop_error: - return -1; -} - -static void mdfld_dsi_connector_destroy(struct drm_connector *connector) -{ - struct mdfld_dsi_connector *dsi_connector = - mdfld_dsi_connector(connector); - struct mdfld_dsi_pkg_sender *sender; - - if (!dsi_connector) - return; - drm_sysfs_connector_remove(connector); - drm_connector_cleanup(connector); - sender = dsi_connector->pkg_sender; - mdfld_dsi_pkg_sender_destroy(sender); - kfree(dsi_connector); -} - -static int mdfld_dsi_connector_get_modes(struct drm_connector *connector) -{ - struct mdfld_dsi_connector *dsi_connector = - mdfld_dsi_connector(connector); - struct mdfld_dsi_config *dsi_config = - mdfld_dsi_get_config(dsi_connector); - struct drm_display_mode *fixed_mode = dsi_config->fixed_mode; - struct drm_display_mode *dup_mode = NULL; - struct drm_device *dev = connector->dev; - - connector->display_info.min_vfreq = 0; - connector->display_info.max_vfreq = 200; - connector->display_info.min_hfreq = 0; - connector->display_info.max_hfreq = 200; - - if (fixed_mode) { - dev_dbg(dev->dev, "fixed_mode %dx%d\n", - fixed_mode->hdisplay, fixed_mode->vdisplay); - dup_mode = drm_mode_duplicate(dev, fixed_mode); - drm_mode_probed_add(connector, dup_mode); - return 1; - } - DRM_ERROR("Didn't get any modes!\n"); - return 0; -} - -static int mdfld_dsi_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - struct mdfld_dsi_connector *dsi_connector = - mdfld_dsi_connector(connector); - struct mdfld_dsi_config *dsi_config = - mdfld_dsi_get_config(dsi_connector); - struct drm_display_mode *fixed_mode = dsi_config->fixed_mode; - - if (mode->flags & DRM_MODE_FLAG_DBLSCAN) - return MODE_NO_DBLESCAN; - - if (mode->flags & DRM_MODE_FLAG_INTERLACE) - return MODE_NO_INTERLACE; - - /** - * FIXME: current DC has no fitting unit, reject any mode setting - * request - * Will figure out a way to do up-scaling(pannel fitting) later. - **/ - if (fixed_mode) { - if (mode->hdisplay != fixed_mode->hdisplay) - return MODE_PANEL; - - if (mode->vdisplay != fixed_mode->vdisplay) - return MODE_PANEL; - } - - return MODE_OK; -} - -static void mdfld_dsi_connector_dpms(struct drm_connector *connector, int mode) -{ - if (mode == connector->dpms) - return; - - /*first, execute dpms*/ - - drm_helper_connector_dpms(connector, mode); -} - -static struct drm_encoder *mdfld_dsi_connector_best_encoder( - struct drm_connector *connector) -{ - struct mdfld_dsi_connector *dsi_connector = - mdfld_dsi_connector(connector); - struct mdfld_dsi_config *dsi_config = - mdfld_dsi_get_config(dsi_connector); - return &dsi_config->encoder->base.base; -} - -/*DSI connector funcs*/ -static const struct drm_connector_funcs mdfld_dsi_connector_funcs = { - .dpms = /*drm_helper_connector_dpms*/mdfld_dsi_connector_dpms, - .save = mdfld_dsi_connector_save, - .restore = mdfld_dsi_connector_restore, - .detect = mdfld_dsi_connector_detect, - .fill_modes = drm_helper_probe_single_connector_modes, - .set_property = mdfld_dsi_connector_set_property, - .destroy = mdfld_dsi_connector_destroy, -}; - -/*DSI connector helper funcs*/ -static const struct drm_connector_helper_funcs - mdfld_dsi_connector_helper_funcs = { - .get_modes = mdfld_dsi_connector_get_modes, - .mode_valid = mdfld_dsi_connector_mode_valid, - .best_encoder = mdfld_dsi_connector_best_encoder, -}; - -static int mdfld_dsi_get_default_config(struct drm_device *dev, - struct mdfld_dsi_config *config, int pipe) -{ - if (!dev || !config) { - DRM_ERROR("Invalid parameters"); - return -EINVAL; - } - - config->bpp = 24; - if (mdfld_get_panel_type(dev, pipe) == TC35876X) - config->lane_count = 4; - else - config->lane_count = 2; - config->channel_num = 0; - - if (mdfld_get_panel_type(dev, pipe) == TMD_VID) - config->video_mode = MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE; - else if (mdfld_get_panel_type(dev, pipe) == TC35876X) - config->video_mode = - MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS; - else - config->video_mode = MDFLD_DSI_VIDEO_BURST_MODE; - - return 0; -} - -int mdfld_dsi_panel_reset(int pipe) -{ - unsigned gpio; - int ret = 0; - - switch (pipe) { - case 0: - gpio = 128; - break; - case 2: - gpio = 34; - break; - default: - DRM_ERROR("Invalid output\n"); - return -EINVAL; - } - - ret = gpio_request(gpio, "gfx"); - if (ret) { - DRM_ERROR("gpio_rqueset failed\n"); - return ret; - } - - ret = gpio_direction_output(gpio, 1); - if (ret) { - DRM_ERROR("gpio_direction_output failed\n"); - goto gpio_error; - } - - gpio_get_value(128); - -gpio_error: - if (gpio_is_valid(gpio)) - gpio_free(gpio); - - return ret; -} - -/* - * MIPI output init - * @dev drm device - * @pipe pipe number. 0 or 2 - * @config - * - * Do the initialization of a MIPI output, including create DRM mode objects - * initialization of DSI output on @pipe - */ -void mdfld_dsi_output_init(struct drm_device *dev, - int pipe, - const struct panel_funcs *p_vid_funcs) -{ - struct mdfld_dsi_config *dsi_config; - struct mdfld_dsi_connector *dsi_connector; - struct drm_connector *connector; - struct mdfld_dsi_encoder *encoder; - struct drm_psb_private *dev_priv = dev->dev_private; - struct panel_info dsi_panel_info; - u32 width_mm, height_mm; - - dev_dbg(dev->dev, "init DSI output on pipe %d\n", pipe); - - if (pipe != 0 && pipe != 2) { - DRM_ERROR("Invalid parameter\n"); - return; - } - - /*create a new connetor*/ - dsi_connector = kzalloc(sizeof(struct mdfld_dsi_connector), GFP_KERNEL); - if (!dsi_connector) { - DRM_ERROR("No memory"); - return; - } - - dsi_connector->pipe = pipe; - - dsi_config = kzalloc(sizeof(struct mdfld_dsi_config), - GFP_KERNEL); - if (!dsi_config) { - DRM_ERROR("cannot allocate memory for DSI config\n"); - goto dsi_init_err0; - } - mdfld_dsi_get_default_config(dev, dsi_config, pipe); - - dsi_connector->private = dsi_config; - - dsi_config->changed = 1; - dsi_config->dev = dev; - - dsi_config->fixed_mode = p_vid_funcs->get_config_mode(dev); - if (p_vid_funcs->get_panel_info(dev, pipe, &dsi_panel_info)) - goto dsi_init_err0; - - width_mm = dsi_panel_info.width_mm; - height_mm = dsi_panel_info.height_mm; - - dsi_config->mode = dsi_config->fixed_mode; - dsi_config->connector = dsi_connector; - - if (!dsi_config->fixed_mode) { - DRM_ERROR("No pannel fixed mode was found\n"); - goto dsi_init_err0; - } - - if (pipe && dev_priv->dsi_configs[0]) { - dsi_config->dvr_ic_inited = 0; - dev_priv->dsi_configs[1] = dsi_config; - } else if (pipe == 0) { - dsi_config->dvr_ic_inited = 1; - dev_priv->dsi_configs[0] = dsi_config; - } else { - DRM_ERROR("Trying to init MIPI1 before MIPI0\n"); - goto dsi_init_err0; - } - - - connector = &dsi_connector->base.base; - drm_connector_init(dev, connector, &mdfld_dsi_connector_funcs, - DRM_MODE_CONNECTOR_LVDS); - drm_connector_helper_add(connector, &mdfld_dsi_connector_helper_funcs); - - connector->display_info.subpixel_order = SubPixelHorizontalRGB; - connector->display_info.width_mm = width_mm; - connector->display_info.height_mm = height_mm; - connector->interlace_allowed = false; - connector->doublescan_allowed = false; - - /*attach properties*/ - drm_object_attach_property(&connector->base, - dev->mode_config.scaling_mode_property, - DRM_MODE_SCALE_FULLSCREEN); - drm_object_attach_property(&connector->base, - dev_priv->backlight_property, - MDFLD_DSI_BRIGHTNESS_MAX_LEVEL); - - /*init DSI package sender on this output*/ - if (mdfld_dsi_pkg_sender_init(dsi_connector, pipe)) { - DRM_ERROR("Package Sender initialization failed on pipe %d\n", - pipe); - goto dsi_init_err0; - } - - encoder = mdfld_dsi_dpi_init(dev, dsi_connector, p_vid_funcs); - if (!encoder) { - DRM_ERROR("Create DPI encoder failed\n"); - goto dsi_init_err1; - } - encoder->private = dsi_config; - dsi_config->encoder = encoder; - encoder->base.type = (pipe == 0) ? INTEL_OUTPUT_MIPI : - INTEL_OUTPUT_MIPI2; - drm_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/gpu/drm/gma500/mdfld_dsi_output.h b/drivers/gpu/drm/gma500/mdfld_dsi_output.h deleted file mode 100644 index 36eb0744841c..000000000000 --- a/drivers/gpu/drm/gma500/mdfld_dsi_output.h +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright © 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: - * jim liu <jim.liu@intel.com> - * Jackie Li<yaodong.li@intel.com> - */ - -#ifndef __MDFLD_DSI_OUTPUT_H__ -#define __MDFLD_DSI_OUTPUT_H__ - -#include <linux/backlight.h> -#include <drm/drmP.h> -#include <drm/drm.h> -#include <drm/drm_crtc.h> -#include <drm/drm_edid.h> - -#include "psb_drv.h" -#include "psb_intel_drv.h" -#include "psb_intel_reg.h" -#include "mdfld_output.h" - -#include <asm/mrst.h> - -#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end)) -#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end)) -#define FLD_GET(val, start, end) (((val) & FLD_MASK(start, end)) >> (end)) -#define FLD_MOD(orig, val, start, end) \ - (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end)) - -#define REG_FLD_MOD(reg, val, start, end) \ - REG_WRITE(reg, FLD_MOD(REG_READ(reg), val, start, end)) - -static inline int REGISTER_FLD_WAIT(struct drm_device *dev, u32 reg, - u32 val, int start, int end) -{ - int t = 100000; - - while (FLD_GET(REG_READ(reg), start, end) != val) { - if (--t == 0) - return 1; - } - - return 0; -} - -#define REG_FLD_WAIT(reg, val, start, end) \ - REGISTER_FLD_WAIT(dev, reg, val, start, end) - -#define REG_BIT_WAIT(reg, val, bitnum) \ - REGISTER_FLD_WAIT(dev, reg, val, bitnum, bitnum) - -#define MDFLD_DSI_BRIGHTNESS_MAX_LEVEL 100 - -#ifdef DEBUG -#define CHECK_PIPE(pipe) ({ \ - const typeof(pipe) __pipe = (pipe); \ - BUG_ON(__pipe != 0 && __pipe != 2); \ - __pipe; }) -#else -#define CHECK_PIPE(pipe) (pipe) -#endif - -/* - * Actual MIPIA->MIPIC reg offset is 0x800, value 0x400 is valid for 0 and 2 - */ -#define REG_OFFSET(pipe) (CHECK_PIPE(pipe) * 0x400) - -/* mdfld DSI controller registers */ -#define MIPI_DEVICE_READY_REG(pipe) (0xb000 + REG_OFFSET(pipe)) -#define MIPI_INTR_STAT_REG(pipe) (0xb004 + REG_OFFSET(pipe)) -#define MIPI_INTR_EN_REG(pipe) (0xb008 + REG_OFFSET(pipe)) -#define MIPI_DSI_FUNC_PRG_REG(pipe) (0xb00c + REG_OFFSET(pipe)) -#define MIPI_HS_TX_TIMEOUT_REG(pipe) (0xb010 + REG_OFFSET(pipe)) -#define MIPI_LP_RX_TIMEOUT_REG(pipe) (0xb014 + REG_OFFSET(pipe)) -#define MIPI_TURN_AROUND_TIMEOUT_REG(pipe) (0xb018 + REG_OFFSET(pipe)) -#define MIPI_DEVICE_RESET_TIMER_REG(pipe) (0xb01c + REG_OFFSET(pipe)) -#define MIPI_DPI_RESOLUTION_REG(pipe) (0xb020 + REG_OFFSET(pipe)) -#define MIPI_DBI_FIFO_THROTTLE_REG(pipe) (0xb024 + REG_OFFSET(pipe)) -#define MIPI_HSYNC_COUNT_REG(pipe) (0xb028 + REG_OFFSET(pipe)) -#define MIPI_HBP_COUNT_REG(pipe) (0xb02c + REG_OFFSET(pipe)) -#define MIPI_HFP_COUNT_REG(pipe) (0xb030 + REG_OFFSET(pipe)) -#define MIPI_HACTIVE_COUNT_REG(pipe) (0xb034 + REG_OFFSET(pipe)) -#define MIPI_VSYNC_COUNT_REG(pipe) (0xb038 + REG_OFFSET(pipe)) -#define MIPI_VBP_COUNT_REG(pipe) (0xb03c + REG_OFFSET(pipe)) -#define MIPI_VFP_COUNT_REG(pipe) (0xb040 + REG_OFFSET(pipe)) -#define MIPI_HIGH_LOW_SWITCH_COUNT_REG(pipe) (0xb044 + REG_OFFSET(pipe)) -#define MIPI_DPI_CONTROL_REG(pipe) (0xb048 + REG_OFFSET(pipe)) -#define MIPI_DPI_DATA_REG(pipe) (0xb04c + REG_OFFSET(pipe)) -#define MIPI_INIT_COUNT_REG(pipe) (0xb050 + REG_OFFSET(pipe)) -#define MIPI_MAX_RETURN_PACK_SIZE_REG(pipe) (0xb054 + REG_OFFSET(pipe)) -#define MIPI_VIDEO_MODE_FORMAT_REG(pipe) (0xb058 + REG_OFFSET(pipe)) -#define MIPI_EOT_DISABLE_REG(pipe) (0xb05c + REG_OFFSET(pipe)) -#define MIPI_LP_BYTECLK_REG(pipe) (0xb060 + REG_OFFSET(pipe)) -#define MIPI_LP_GEN_DATA_REG(pipe) (0xb064 + REG_OFFSET(pipe)) -#define MIPI_HS_GEN_DATA_REG(pipe) (0xb068 + REG_OFFSET(pipe)) -#define MIPI_LP_GEN_CTRL_REG(pipe) (0xb06c + REG_OFFSET(pipe)) -#define MIPI_HS_GEN_CTRL_REG(pipe) (0xb070 + REG_OFFSET(pipe)) -#define MIPI_GEN_FIFO_STAT_REG(pipe) (0xb074 + REG_OFFSET(pipe)) -#define MIPI_HS_LS_DBI_ENABLE_REG(pipe) (0xb078 + REG_OFFSET(pipe)) -#define MIPI_DPHY_PARAM_REG(pipe) (0xb080 + REG_OFFSET(pipe)) -#define MIPI_DBI_BW_CTRL_REG(pipe) (0xb084 + REG_OFFSET(pipe)) -#define MIPI_CLK_LANE_SWITCH_TIME_CNT_REG(pipe) (0xb088 + REG_OFFSET(pipe)) - -#define MIPI_CTRL_REG(pipe) (0xb104 + REG_OFFSET(pipe)) -#define MIPI_DATA_ADD_REG(pipe) (0xb108 + REG_OFFSET(pipe)) -#define MIPI_DATA_LEN_REG(pipe) (0xb10c + REG_OFFSET(pipe)) -#define MIPI_CMD_ADD_REG(pipe) (0xb110 + REG_OFFSET(pipe)) -#define MIPI_CMD_LEN_REG(pipe) (0xb114 + REG_OFFSET(pipe)) - -/* non-uniform reg offset */ -#define MIPI_PORT_CONTROL(pipe) (CHECK_PIPE(pipe) ? MIPI_C : MIPI) - -#define DSI_DEVICE_READY (0x1) -#define DSI_POWER_STATE_ULPS_ENTER (0x2 << 1) -#define DSI_POWER_STATE_ULPS_EXIT (0x1 << 1) -#define DSI_POWER_STATE_ULPS_OFFSET (0x1) - - -#define DSI_ONE_DATA_LANE (0x1) -#define DSI_TWO_DATA_LANE (0x2) -#define DSI_THREE_DATA_LANE (0X3) -#define DSI_FOUR_DATA_LANE (0x4) -#define DSI_DPI_VIRT_CHANNEL_OFFSET (0x3) -#define DSI_DBI_VIRT_CHANNEL_OFFSET (0x5) -#define DSI_DPI_COLOR_FORMAT_RGB565 (0x01 << 7) -#define DSI_DPI_COLOR_FORMAT_RGB666 (0x02 << 7) -#define DSI_DPI_COLOR_FORMAT_RGB666_UNPACK (0x03 << 7) -#define DSI_DPI_COLOR_FORMAT_RGB888 (0x04 << 7) -#define DSI_DBI_COLOR_FORMAT_OPTION2 (0x05 << 13) - -#define DSI_INTR_STATE_RXSOTERROR BIT(0) - -#define DSI_INTR_STATE_SPL_PKG_SENT BIT(30) -#define DSI_INTR_STATE_TE BIT(31) - -#define DSI_HS_TX_TIMEOUT_MASK (0xffffff) - -#define DSI_LP_RX_TIMEOUT_MASK (0xffffff) - -#define DSI_TURN_AROUND_TIMEOUT_MASK (0x3f) - -#define DSI_RESET_TIMER_MASK (0xffff) - -#define DSI_DBI_FIFO_WM_HALF (0x0) -#define DSI_DBI_FIFO_WM_QUARTER (0x1) -#define DSI_DBI_FIFO_WM_LOW (0x2) - -#define DSI_DPI_TIMING_MASK (0xffff) - -#define DSI_INIT_TIMER_MASK (0xffff) - -#define DSI_DBI_RETURN_PACK_SIZE_MASK (0x3ff) - -#define DSI_LP_BYTECLK_MASK (0x0ffff) - -#define DSI_HS_CTRL_GEN_SHORT_W0 (0x03) -#define DSI_HS_CTRL_GEN_SHORT_W1 (0x13) -#define DSI_HS_CTRL_GEN_SHORT_W2 (0x23) -#define DSI_HS_CTRL_GEN_R0 (0x04) -#define DSI_HS_CTRL_GEN_R1 (0x14) -#define DSI_HS_CTRL_GEN_R2 (0x24) -#define DSI_HS_CTRL_GEN_LONG_W (0x29) -#define DSI_HS_CTRL_MCS_SHORT_W0 (0x05) -#define DSI_HS_CTRL_MCS_SHORT_W1 (0x15) -#define DSI_HS_CTRL_MCS_R0 (0x06) -#define DSI_HS_CTRL_MCS_LONG_W (0x39) -#define DSI_HS_CTRL_VC_OFFSET (0x06) -#define DSI_HS_CTRL_WC_OFFSET (0x08) - -#define DSI_FIFO_GEN_HS_DATA_FULL BIT(0) -#define DSI_FIFO_GEN_HS_DATA_HALF_EMPTY BIT(1) -#define DSI_FIFO_GEN_HS_DATA_EMPTY BIT(2) -#define DSI_FIFO_GEN_LP_DATA_FULL BIT(8) -#define DSI_FIFO_GEN_LP_DATA_HALF_EMPTY BIT(9) -#define DSI_FIFO_GEN_LP_DATA_EMPTY BIT(10) -#define DSI_FIFO_GEN_HS_CTRL_FULL BIT(16) -#define DSI_FIFO_GEN_HS_CTRL_HALF_EMPTY BIT(17) -#define DSI_FIFO_GEN_HS_CTRL_EMPTY BIT(18) -#define DSI_FIFO_GEN_LP_CTRL_FULL BIT(24) -#define DSI_FIFO_GEN_LP_CTRL_HALF_EMPTY BIT(25) -#define DSI_FIFO_GEN_LP_CTRL_EMPTY BIT(26) -#define DSI_FIFO_DBI_EMPTY BIT(27) -#define DSI_FIFO_DPI_EMPTY BIT(28) - -#define DSI_DBI_HS_LP_SWITCH_MASK (0x1) - -#define DSI_HS_LP_SWITCH_COUNTER_OFFSET (0x0) -#define DSI_LP_HS_SWITCH_COUNTER_OFFSET (0x16) - -#define DSI_DPI_CTRL_HS_SHUTDOWN (0x00000001) -#define DSI_DPI_CTRL_HS_TURN_ON (0x00000002) - -/*dsi power modes*/ -#define DSI_POWER_MODE_DISPLAY_ON BIT(2) -#define DSI_POWER_MODE_NORMAL_ON BIT(3) -#define DSI_POWER_MODE_SLEEP_OUT BIT(4) -#define DSI_POWER_MODE_PARTIAL_ON BIT(5) -#define DSI_POWER_MODE_IDLE_ON BIT(6) - -enum { - MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE = 1, - MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS = 2, - MDFLD_DSI_VIDEO_BURST_MODE = 3, -}; - -#define DSI_DPI_COMPLETE_LAST_LINE BIT(2) -#define DSI_DPI_DISABLE_BTA BIT(3) - -struct mdfld_dsi_connector { - struct psb_intel_connector base; - - int pipe; - void *private; - void *pkg_sender; - - /* Connection status */ - enum drm_connector_status status; -}; - -struct mdfld_dsi_encoder { - struct psb_intel_encoder base; - void *private; -}; - -/* - * DSI config, consists of one DSI connector, two DSI encoders. - * DRM will pick up on DSI encoder basing on differents configs. - */ -struct mdfld_dsi_config { - struct drm_device *dev; - struct drm_display_mode *fixed_mode; - struct drm_display_mode *mode; - - struct mdfld_dsi_connector *connector; - struct mdfld_dsi_encoder *encoder; - - int changed; - - int bpp; - int lane_count; - /*Virtual channel number for this encoder*/ - int channel_num; - /*video mode configure*/ - int video_mode; - - int dvr_ic_inited; -}; - -static inline struct mdfld_dsi_connector *mdfld_dsi_connector( - struct drm_connector *connector) -{ - struct psb_intel_connector *psb_connector; - - psb_connector = to_psb_intel_connector(connector); - - return container_of(psb_connector, struct mdfld_dsi_connector, base); -} - -static inline struct mdfld_dsi_encoder *mdfld_dsi_encoder( - struct drm_encoder *encoder) -{ - struct psb_intel_encoder *psb_encoder; - - psb_encoder = to_psb_intel_encoder(encoder); - - return container_of(psb_encoder, struct mdfld_dsi_encoder, base); -} - -static inline struct mdfld_dsi_config * - mdfld_dsi_get_config(struct mdfld_dsi_connector *connector) -{ - if (!connector) - return NULL; - return (struct mdfld_dsi_config *)connector->private; -} - -static inline void *mdfld_dsi_get_pkg_sender(struct mdfld_dsi_config *config) -{ - struct mdfld_dsi_connector *dsi_connector; - - if (!config) - return NULL; - - dsi_connector = config->connector; - - if (!dsi_connector) - return NULL; - - return dsi_connector->pkg_sender; -} - -static inline struct mdfld_dsi_config * - mdfld_dsi_encoder_get_config(struct mdfld_dsi_encoder *encoder) -{ - if (!encoder) - return NULL; - return (struct mdfld_dsi_config *)encoder->private; -} - -static inline struct mdfld_dsi_connector * - mdfld_dsi_encoder_get_connector(struct mdfld_dsi_encoder *encoder) -{ - struct mdfld_dsi_config *config; - - if (!encoder) - return NULL; - - config = mdfld_dsi_encoder_get_config(encoder); - if (!config) - return NULL; - - return config->connector; -} - -static inline void *mdfld_dsi_encoder_get_pkg_sender( - struct mdfld_dsi_encoder *encoder) -{ - struct mdfld_dsi_config *dsi_config; - - dsi_config = mdfld_dsi_encoder_get_config(encoder); - if (!dsi_config) - return NULL; - - return mdfld_dsi_get_pkg_sender(dsi_config); -} - -static inline int mdfld_dsi_encoder_get_pipe(struct mdfld_dsi_encoder *encoder) -{ - struct mdfld_dsi_connector *connector; - - if (!encoder) - return -1; - - connector = mdfld_dsi_encoder_get_connector(encoder); - if (!connector) - return -1; - return connector->pipe; -} - -/* Export functions */ -extern void mdfld_dsi_gen_fifo_ready(struct drm_device *dev, - u32 gen_fifo_stat_reg, u32 fifo_stat); -extern void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config, - int pipe); -extern void mdfld_dsi_brightness_control(struct drm_device *dev, int pipe, - int level); -extern void mdfld_dsi_output_init(struct drm_device *dev, - int pipe, - const struct panel_funcs *p_vid_funcs); -extern void mdfld_dsi_controller_init(struct mdfld_dsi_config *dsi_config, - int pipe); - -extern int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config, - u32 *mode, bool hs); -extern int mdfld_dsi_panel_reset(int pipe); - -#endif /*__MDFLD_DSI_OUTPUT_H__*/ diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c b/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c deleted file mode 100644 index 489ffd2c66e5..000000000000 --- a/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c +++ /dev/null @@ -1,688 +0,0 @@ -/* - * Copyright © 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: - * Jackie Li<yaodong.li@intel.com> - */ - -#include <linux/freezer.h> - -#include "mdfld_dsi_output.h" -#include "mdfld_dsi_pkg_sender.h" -#include "mdfld_dsi_dpi.h" - -#define MDFLD_DSI_READ_MAX_COUNT 5000 - -enum data_type { - DSI_DT_GENERIC_SHORT_WRITE_0 = 0x03, - DSI_DT_GENERIC_SHORT_WRITE_1 = 0x13, - DSI_DT_GENERIC_SHORT_WRITE_2 = 0x23, - DSI_DT_GENERIC_READ_0 = 0x04, - DSI_DT_GENERIC_READ_1 = 0x14, - DSI_DT_GENERIC_READ_2 = 0x24, - DSI_DT_GENERIC_LONG_WRITE = 0x29, - DSI_DT_DCS_SHORT_WRITE_0 = 0x05, - DSI_DT_DCS_SHORT_WRITE_1 = 0x15, - DSI_DT_DCS_READ = 0x06, - DSI_DT_DCS_LONG_WRITE = 0x39, -}; - -enum { - MDFLD_DSI_PANEL_MODE_SLEEP = 0x1, -}; - -enum { - MDFLD_DSI_PKG_SENDER_FREE = 0x0, - MDFLD_DSI_PKG_SENDER_BUSY = 0x1, -}; - -static const char *const dsi_errors[] = { - "RX SOT Error", - "RX SOT Sync Error", - "RX EOT Sync Error", - "RX Escape Mode Entry Error", - "RX LP TX Sync Error", - "RX HS Receive Timeout Error", - "RX False Control Error", - "RX ECC Single Bit Error", - "RX ECC Multibit Error", - "RX Checksum Error", - "RX DSI Data Type Not Recognised", - "RX DSI VC ID Invalid", - "TX False Control Error", - "TX ECC Single Bit Error", - "TX ECC Multibit Error", - "TX Checksum Error", - "TX DSI Data Type Not Recognised", - "TX DSI VC ID invalid", - "High Contention", - "Low contention", - "DPI FIFO Under run", - "HS TX Timeout", - "LP RX Timeout", - "Turn Around ACK Timeout", - "ACK With No Error", - "RX Invalid TX Length", - "RX Prot Violation", - "HS Generic Write FIFO Full", - "LP Generic Write FIFO Full", - "Generic Read Data Avail" - "Special Packet Sent", - "Tearing Effect", -}; - -static inline int wait_for_gen_fifo_empty(struct mdfld_dsi_pkg_sender *sender, - u32 mask) -{ - struct drm_device *dev = sender->dev; - u32 gen_fifo_stat_reg = sender->mipi_gen_fifo_stat_reg; - int retry = 0xffff; - - while (retry--) { - if ((mask & REG_READ(gen_fifo_stat_reg)) == mask) - return 0; - udelay(100); - } - DRM_ERROR("fifo is NOT empty 0x%08x\n", REG_READ(gen_fifo_stat_reg)); - return -EIO; -} - -static int wait_for_all_fifos_empty(struct mdfld_dsi_pkg_sender *sender) -{ - return wait_for_gen_fifo_empty(sender, (BIT(2) | BIT(10) | BIT(18) | - BIT(26) | BIT(27) | BIT(28))); -} - -static int wait_for_lp_fifos_empty(struct mdfld_dsi_pkg_sender *sender) -{ - return wait_for_gen_fifo_empty(sender, (BIT(10) | BIT(26))); -} - -static int wait_for_hs_fifos_empty(struct mdfld_dsi_pkg_sender *sender) -{ - return wait_for_gen_fifo_empty(sender, (BIT(2) | BIT(18))); -} - -static int handle_dsi_error(struct mdfld_dsi_pkg_sender *sender, u32 mask) -{ - u32 intr_stat_reg = sender->mipi_intr_stat_reg; - struct drm_device *dev = sender->dev; - - dev_dbg(sender->dev->dev, "Handling error 0x%08x\n", mask); - - switch (mask) { - case BIT(0): - case BIT(1): - case BIT(2): - case BIT(3): - case BIT(4): - case BIT(5): - case BIT(6): - case BIT(7): - case BIT(8): - case BIT(9): - case BIT(10): - case BIT(11): - case BIT(12): - case BIT(13): - dev_dbg(sender->dev->dev, "No Action required\n"); - break; - case BIT(14): - /*wait for all fifo empty*/ - /*wait_for_all_fifos_empty(sender)*/; - break; - case BIT(15): - dev_dbg(sender->dev->dev, "No Action required\n"); - break; - case BIT(16): - break; - case BIT(17): - break; - case BIT(18): - case BIT(19): - dev_dbg(sender->dev->dev, "High/Low contention detected\n"); - /*wait for contention recovery time*/ - /*mdelay(10);*/ - /*wait for all fifo empty*/ - if (0) - wait_for_all_fifos_empty(sender); - break; - case BIT(20): - dev_dbg(sender->dev->dev, "No Action required\n"); - break; - case BIT(21): - /*wait for all fifo empty*/ - /*wait_for_all_fifos_empty(sender);*/ - break; - case BIT(22): - break; - case BIT(23): - case BIT(24): - case BIT(25): - case BIT(26): - case BIT(27): - dev_dbg(sender->dev->dev, "HS Gen fifo full\n"); - REG_WRITE(intr_stat_reg, mask); - wait_for_hs_fifos_empty(sender); - break; - case BIT(28): - dev_dbg(sender->dev->dev, "LP Gen fifo full\n"); - REG_WRITE(intr_stat_reg, mask); - wait_for_lp_fifos_empty(sender); - break; - case BIT(29): - case BIT(30): - case BIT(31): - dev_dbg(sender->dev->dev, "No Action required\n"); - break; - } - - if (mask & REG_READ(intr_stat_reg)) - dev_dbg(sender->dev->dev, - "Cannot clean interrupt 0x%08x\n", mask); - return 0; -} - -static int dsi_error_handler(struct mdfld_dsi_pkg_sender *sender) -{ - struct drm_device *dev = sender->dev; - u32 intr_stat_reg = sender->mipi_intr_stat_reg; - u32 mask; - u32 intr_stat; - int i; - int err = 0; - - intr_stat = REG_READ(intr_stat_reg); - - for (i = 0; i < 32; i++) { - mask = (0x00000001UL) << i; - if (intr_stat & mask) { - dev_dbg(sender->dev->dev, "[DSI]: %s\n", dsi_errors[i]); - err = handle_dsi_error(sender, mask); - if (err) - DRM_ERROR("Cannot handle error\n"); - } - } - return err; -} - -static int send_short_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type, - u8 cmd, u8 param, bool hs) -{ - struct drm_device *dev = sender->dev; - u32 ctrl_reg; - u32 val; - u8 virtual_channel = 0; - - if (hs) { - ctrl_reg = sender->mipi_hs_gen_ctrl_reg; - - /* FIXME: wait_for_hs_fifos_empty(sender); */ - } else { - ctrl_reg = sender->mipi_lp_gen_ctrl_reg; - - /* FIXME: wait_for_lp_fifos_empty(sender); */ - } - - val = FLD_VAL(param, 23, 16) | FLD_VAL(cmd, 15, 8) | - FLD_VAL(virtual_channel, 7, 6) | FLD_VAL(data_type, 5, 0); - - REG_WRITE(ctrl_reg, val); - - return 0; -} - -static int send_long_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type, - u8 *data, int len, bool hs) -{ - struct drm_device *dev = sender->dev; - u32 ctrl_reg; - u32 data_reg; - u32 val; - u8 *p; - u8 b1, b2, b3, b4; - u8 virtual_channel = 0; - int i; - - if (hs) { - ctrl_reg = sender->mipi_hs_gen_ctrl_reg; - data_reg = sender->mipi_hs_gen_data_reg; - - /* FIXME: wait_for_hs_fifos_empty(sender); */ - } else { - ctrl_reg = sender->mipi_lp_gen_ctrl_reg; - data_reg = sender->mipi_lp_gen_data_reg; - - /* FIXME: wait_for_lp_fifos_empty(sender); */ - } - - p = data; - for (i = 0; i < len / 4; i++) { - b1 = *p++; - b2 = *p++; - b3 = *p++; - b4 = *p++; - - REG_WRITE(data_reg, b4 << 24 | b3 << 16 | b2 << 8 | b1); - } - - i = len % 4; - if (i) { - b1 = 0; b2 = 0; b3 = 0; - - switch (i) { - case 3: - b1 = *p++; - b2 = *p++; - b3 = *p++; - break; - case 2: - b1 = *p++; - b2 = *p++; - break; - case 1: - b1 = *p++; - break; - } - - REG_WRITE(data_reg, b3 << 16 | b2 << 8 | b1); - } - - val = FLD_VAL(len, 23, 8) | FLD_VAL(virtual_channel, 7, 6) | - FLD_VAL(data_type, 5, 0); - - REG_WRITE(ctrl_reg, val); - - return 0; -} - -static int send_pkg_prepare(struct mdfld_dsi_pkg_sender *sender, u8 data_type, - u8 *data, u16 len) -{ - u8 cmd; - - switch (data_type) { - case DSI_DT_DCS_SHORT_WRITE_0: - case DSI_DT_DCS_SHORT_WRITE_1: - case DSI_DT_DCS_LONG_WRITE: - cmd = *data; - break; - default: - return 0; - } - - /*this prevents other package sending while doing msleep*/ - sender->status = MDFLD_DSI_PKG_SENDER_BUSY; - - /*wait for 120 milliseconds in case exit_sleep_mode just be sent*/ - if (unlikely(cmd == DCS_ENTER_SLEEP_MODE)) { - /*TODO: replace it with msleep later*/ - mdelay(120); - } - - if (unlikely(cmd == DCS_EXIT_SLEEP_MODE)) { - /*TODO: replace it with msleep later*/ - mdelay(120); - } - return 0; -} - -static int send_pkg_done(struct mdfld_dsi_pkg_sender *sender, u8 data_type, - u8 *data, u16 len) -{ - u8 cmd; - - switch (data_type) { - case DSI_DT_DCS_SHORT_WRITE_0: - case DSI_DT_DCS_SHORT_WRITE_1: - case DSI_DT_DCS_LONG_WRITE: - cmd = *data; - break; - default: - return 0; - } - - /*update panel status*/ - if (unlikely(cmd == DCS_ENTER_SLEEP_MODE)) { - sender->panel_mode |= MDFLD_DSI_PANEL_MODE_SLEEP; - /*TODO: replace it with msleep later*/ - mdelay(120); - } else if (unlikely(cmd == DCS_EXIT_SLEEP_MODE)) { - sender->panel_mode &= ~MDFLD_DSI_PANEL_MODE_SLEEP; - /*TODO: replace it with msleep later*/ - mdelay(120); - } else if (unlikely(cmd == DCS_SOFT_RESET)) { - /*TODO: replace it with msleep later*/ - mdelay(5); - } - - sender->status = MDFLD_DSI_PKG_SENDER_FREE; - - return 0; -} - -static int send_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type, - u8 *data, u16 len, bool hs) -{ - int ret; - - /*handle DSI error*/ - ret = dsi_error_handler(sender); - if (ret) { - DRM_ERROR("Error handling failed\n"); - return -EAGAIN; - } - - /* send pkg */ - if (sender->status == MDFLD_DSI_PKG_SENDER_BUSY) { - DRM_ERROR("sender is busy\n"); - return -EAGAIN; - } - - ret = send_pkg_prepare(sender, data_type, data, len); - if (ret) { - DRM_ERROR("send_pkg_prepare error\n"); - return ret; - } - - switch (data_type) { - case DSI_DT_GENERIC_SHORT_WRITE_0: - case DSI_DT_GENERIC_SHORT_WRITE_1: - case DSI_DT_GENERIC_SHORT_WRITE_2: - case DSI_DT_GENERIC_READ_0: - case DSI_DT_GENERIC_READ_1: - case DSI_DT_GENERIC_READ_2: - case DSI_DT_DCS_SHORT_WRITE_0: - case DSI_DT_DCS_SHORT_WRITE_1: - case DSI_DT_DCS_READ: - ret = send_short_pkg(sender, data_type, data[0], data[1], hs); - break; - case DSI_DT_GENERIC_LONG_WRITE: - case DSI_DT_DCS_LONG_WRITE: - ret = send_long_pkg(sender, data_type, data, len, hs); - break; - } - - send_pkg_done(sender, data_type, data, len); - - /*FIXME: should I query complete and fifo empty here?*/ - - return ret; -} - -int mdfld_dsi_send_mcs_long(struct mdfld_dsi_pkg_sender *sender, u8 *data, - u32 len, bool hs) -{ - unsigned long flags; - - if (!sender || !data || !len) { - DRM_ERROR("Invalid parameters\n"); - return -EINVAL; - } - - spin_lock_irqsave(&sender->lock, flags); - send_pkg(sender, DSI_DT_DCS_LONG_WRITE, data, len, hs); - spin_unlock_irqrestore(&sender->lock, flags); - - return 0; -} - -int mdfld_dsi_send_mcs_short(struct mdfld_dsi_pkg_sender *sender, u8 cmd, - u8 param, u8 param_num, bool hs) -{ - u8 data[2]; - unsigned long flags; - u8 data_type; - - if (!sender) { - DRM_ERROR("Invalid parameter\n"); - return -EINVAL; - } - - data[0] = cmd; - - if (param_num) { - data_type = DSI_DT_DCS_SHORT_WRITE_1; - data[1] = param; - } else { - data_type = DSI_DT_DCS_SHORT_WRITE_0; - data[1] = 0; - } - - spin_lock_irqsave(&sender->lock, flags); - send_pkg(sender, data_type, data, sizeof(data), hs); - spin_unlock_irqrestore(&sender->lock, flags); - - return 0; -} - -int mdfld_dsi_send_gen_short(struct mdfld_dsi_pkg_sender *sender, u8 param0, - u8 param1, u8 param_num, bool hs) -{ - u8 data[2]; - unsigned long flags; - u8 data_type; - - if (!sender || param_num > 2) { - DRM_ERROR("Invalid parameter\n"); - return -EINVAL; - } - - switch (param_num) { - case 0: - data_type = DSI_DT_GENERIC_SHORT_WRITE_0; - data[0] = 0; - data[1] = 0; - break; - case 1: - data_type = DSI_DT_GENERIC_SHORT_WRITE_1; - data[0] = param0; - data[1] = 0; - break; - case 2: - data_type = DSI_DT_GENERIC_SHORT_WRITE_2; - data[0] = param0; - data[1] = param1; - break; - } - - spin_lock_irqsave(&sender->lock, flags); - send_pkg(sender, data_type, data, sizeof(data), hs); - spin_unlock_irqrestore(&sender->lock, flags); - - return 0; -} - -int mdfld_dsi_send_gen_long(struct mdfld_dsi_pkg_sender *sender, u8 *data, - u32 len, bool hs) -{ - unsigned long flags; - - if (!sender || !data || !len) { - DRM_ERROR("Invalid parameters\n"); - return -EINVAL; - } - - spin_lock_irqsave(&sender->lock, flags); - send_pkg(sender, DSI_DT_GENERIC_LONG_WRITE, data, len, hs); - spin_unlock_irqrestore(&sender->lock, flags); - - return 0; -} - -static int __read_panel_data(struct mdfld_dsi_pkg_sender *sender, u8 data_type, - u8 *data, u16 len, u32 *data_out, u16 len_out, bool hs) -{ - unsigned long flags; - struct drm_device *dev = sender->dev; - int i; - u32 gen_data_reg; - int retry = MDFLD_DSI_READ_MAX_COUNT; - - if (!sender || !data_out || !len_out) { - DRM_ERROR("Invalid parameters\n"); - return -EINVAL; - } - - /** - * do reading. - * 0) send out generic read request - * 1) polling read data avail interrupt - * 2) read data - */ - spin_lock_irqsave(&sender->lock, flags); - - REG_WRITE(sender->mipi_intr_stat_reg, BIT(29)); - - if ((REG_READ(sender->mipi_intr_stat_reg) & BIT(29))) - DRM_ERROR("Can NOT clean read data valid interrupt\n"); - - /*send out read request*/ - send_pkg(sender, data_type, data, len, hs); - - /*polling read data avail interrupt*/ - while (retry && !(REG_READ(sender->mipi_intr_stat_reg) & BIT(29))) { - udelay(100); - retry--; - } - - if (!retry) { - spin_unlock_irqrestore(&sender->lock, flags); - return -ETIMEDOUT; - } - - REG_WRITE(sender->mipi_intr_stat_reg, BIT(29)); - - /*read data*/ - if (hs) - gen_data_reg = sender->mipi_hs_gen_data_reg; - else - gen_data_reg = sender->mipi_lp_gen_data_reg; - - for (i = 0; i < len_out; i++) - *(data_out + i) = REG_READ(gen_data_reg); - - spin_unlock_irqrestore(&sender->lock, flags); - - return 0; -} - -int mdfld_dsi_read_mcs(struct mdfld_dsi_pkg_sender *sender, u8 cmd, - u32 *data, u16 len, bool hs) -{ - if (!sender || !data || !len) { - DRM_ERROR("Invalid parameters\n"); - return -EINVAL; - } - - return __read_panel_data(sender, DSI_DT_DCS_READ, &cmd, 1, - data, len, hs); -} - -int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector, - int pipe) -{ - struct mdfld_dsi_pkg_sender *pkg_sender; - struct mdfld_dsi_config *dsi_config = - mdfld_dsi_get_config(dsi_connector); - struct drm_device *dev = dsi_config->dev; - struct drm_psb_private *dev_priv = dev->dev_private; - const struct psb_offset *map = &dev_priv->regmap[pipe]; - u32 mipi_val = 0; - - if (!dsi_connector) { - DRM_ERROR("Invalid parameter\n"); - return -EINVAL; - } - - pkg_sender = dsi_connector->pkg_sender; - - if (!pkg_sender || IS_ERR(pkg_sender)) { - pkg_sender = kzalloc(sizeof(struct mdfld_dsi_pkg_sender), - GFP_KERNEL); - if (!pkg_sender) { - DRM_ERROR("Create DSI pkg sender failed\n"); - return -ENOMEM; - } - dsi_connector->pkg_sender = (void *)pkg_sender; - } - - pkg_sender->dev = dev; - pkg_sender->dsi_connector = dsi_connector; - pkg_sender->pipe = pipe; - pkg_sender->pkg_num = 0; - pkg_sender->panel_mode = 0; - pkg_sender->status = MDFLD_DSI_PKG_SENDER_FREE; - - /*init regs*/ - /* FIXME: should just copy the regmap ptr ? */ - pkg_sender->dpll_reg = map->dpll; - pkg_sender->dspcntr_reg = map->cntr; - pkg_sender->pipeconf_reg = map->conf; - pkg_sender->dsplinoff_reg = map->linoff; - pkg_sender->dspsurf_reg = map->surf; - pkg_sender->pipestat_reg = map->status; - - pkg_sender->mipi_intr_stat_reg = MIPI_INTR_STAT_REG(pipe); - pkg_sender->mipi_lp_gen_data_reg = MIPI_LP_GEN_DATA_REG(pipe); - pkg_sender->mipi_hs_gen_data_reg = MIPI_HS_GEN_DATA_REG(pipe); - pkg_sender->mipi_lp_gen_ctrl_reg = MIPI_LP_GEN_CTRL_REG(pipe); - pkg_sender->mipi_hs_gen_ctrl_reg = MIPI_HS_GEN_CTRL_REG(pipe); - pkg_sender->mipi_gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe); - pkg_sender->mipi_data_addr_reg = MIPI_DATA_ADD_REG(pipe); - pkg_sender->mipi_data_len_reg = MIPI_DATA_LEN_REG(pipe); - pkg_sender->mipi_cmd_addr_reg = MIPI_CMD_ADD_REG(pipe); - pkg_sender->mipi_cmd_len_reg = MIPI_CMD_LEN_REG(pipe); - - /*init lock*/ - spin_lock_init(&pkg_sender->lock); - - if (mdfld_get_panel_type(dev, pipe) != TC35876X) { - /** - * For video mode, don't enable DPI timing output here, - * will init the DPI timing output during mode setting. - */ - mipi_val = PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX; - - if (pipe == 0) - mipi_val |= 0x2; - - REG_WRITE(MIPI_PORT_CONTROL(pipe), mipi_val); - REG_READ(MIPI_PORT_CONTROL(pipe)); - - /* do dsi controller init */ - mdfld_dsi_controller_init(dsi_config, pipe); - } - - return 0; -} - -void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender) -{ - if (!sender || IS_ERR(sender)) - return; - - /*free*/ - kfree(sender); -} - - diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.h b/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.h deleted file mode 100644 index 459cd7ea8b81..000000000000 --- a/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright © 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: - * Jackie Li<yaodong.li@intel.com> - */ -#ifndef __MDFLD_DSI_PKG_SENDER_H__ -#define __MDFLD_DSI_PKG_SENDER_H__ - -#include <linux/kthread.h> - -#define MDFLD_MAX_DCS_PARAM 8 - -struct mdfld_dsi_pkg_sender { - struct drm_device *dev; - struct mdfld_dsi_connector *dsi_connector; - u32 status; - u32 panel_mode; - - int pipe; - - spinlock_t lock; - - u32 pkg_num; - - /* Registers */ - u32 dpll_reg; - u32 dspcntr_reg; - u32 pipeconf_reg; - u32 pipestat_reg; - u32 dsplinoff_reg; - u32 dspsurf_reg; - - u32 mipi_intr_stat_reg; - u32 mipi_lp_gen_data_reg; - u32 mipi_hs_gen_data_reg; - u32 mipi_lp_gen_ctrl_reg; - u32 mipi_hs_gen_ctrl_reg; - u32 mipi_gen_fifo_stat_reg; - u32 mipi_data_addr_reg; - u32 mipi_data_len_reg; - u32 mipi_cmd_addr_reg; - u32 mipi_cmd_len_reg; -}; - -/* DCS definitions */ -#define DCS_SOFT_RESET 0x01 -#define DCS_ENTER_SLEEP_MODE 0x10 -#define DCS_EXIT_SLEEP_MODE 0x11 -#define DCS_SET_DISPLAY_OFF 0x28 -#define DCS_SET_DISPLAY_ON 0x29 -#define DCS_SET_COLUMN_ADDRESS 0x2a -#define DCS_SET_PAGE_ADDRESS 0x2b -#define DCS_WRITE_MEM_START 0x2c -#define DCS_SET_TEAR_OFF 0x34 -#define DCS_SET_TEAR_ON 0x35 - -extern int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector, - int pipe); -extern void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender); -int mdfld_dsi_send_mcs_short(struct mdfld_dsi_pkg_sender *sender, u8 cmd, - u8 param, u8 param_num, bool hs); -int mdfld_dsi_send_mcs_long(struct mdfld_dsi_pkg_sender *sender, u8 *data, - u32 len, bool hs); -int mdfld_dsi_send_gen_short(struct mdfld_dsi_pkg_sender *sender, u8 param0, - u8 param1, u8 param_num, bool hs); -int mdfld_dsi_send_gen_long(struct mdfld_dsi_pkg_sender *sender, u8 *data, - u32 len, bool hs); -/* Read interfaces */ -int mdfld_dsi_read_mcs(struct mdfld_dsi_pkg_sender *sender, u8 cmd, - u32 *data, u16 len, bool hs); - -#endif diff --git a/drivers/gpu/drm/gma500/mdfld_intel_display.c b/drivers/gpu/drm/gma500/mdfld_intel_display.c deleted file mode 100644 index 74485dc43945..000000000000 --- a/drivers/gpu/drm/gma500/mdfld_intel_display.c +++ /dev/null @@ -1,1054 +0,0 @@ -/* - * Copyright © 2006-2007 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 "psb_intel_reg.h" -#include "psb_intel_display.h" -#include "framebuffer.h" -#include "mdfld_output.h" -#include "mdfld_dsi_output.h" - -/* Hardcoded currently */ -static int ksel = KSEL_CRYSTAL_19; - -struct psb_intel_range_t { - int min, max; -}; - -struct mrst_limit_t { - struct psb_intel_range_t dot, m, p1; -}; - -struct mrst_clock_t { - /* derived values */ - int dot; - int m; - int p1; -}; - -#define COUNT_MAX 0x10000000 - -void mdfldWaitForPipeDisable(struct drm_device *dev, int pipe) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - const struct psb_offset *map = &dev_priv->regmap[pipe]; - int count, temp; - - switch (pipe) { - case 0: - case 1: - case 2: - break; - default: - DRM_ERROR("Illegal Pipe Number.\n"); - return; - } - - /* FIXME JLIU7_PO */ - 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(map->conf); - if ((temp & PIPEACONF_PIPE_STATE) == 0) - break; - } -} - -void mdfldWaitForPipeEnable(struct drm_device *dev, int pipe) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - const struct psb_offset *map = &dev_priv->regmap[pipe]; - int count, temp; - - switch (pipe) { - case 0: - case 1: - case 2: - break; - default: - DRM_ERROR("Illegal Pipe Number.\n"); - return; - } - - /* FIXME JLIU7_PO */ - 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(map->conf); - if ((temp & PIPEACONF_PIPE_STATE) == 1) - break; - } -} - -static void psb_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 psb_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); -} - -static bool psb_intel_crtc_mode_fixup(struct drm_crtc *crtc, - const 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 psb_intel_panel_fitter_pipe(struct drm_device *dev) -{ - u32 pfit_control; - - pfit_control = REG_READ(PFIT_CONTROL); - - /* See if the panel fitter is in use */ - if ((pfit_control & PFIT_ENABLE) == 0) - return -1; - - /* 965 can place panel fitter on either pipe */ - return (pfit_control >> 29) & 0x3; -} - -static 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); -} - -static int check_fb(struct drm_framebuffer *fb) -{ - if (!fb) - return 0; - - switch (fb->bits_per_pixel) { - case 8: - case 16: - case 24: - case 32: - return 0; - default: - DRM_ERROR("Unknown color depth\n"); - return -EINVAL; - } -} - -static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, - struct drm_framebuffer *old_fb) -{ - struct drm_device *dev = crtc->dev; - struct drm_psb_private *dev_priv = dev->dev_private; - struct 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; - const struct psb_offset *map = &dev_priv->regmap[pipe]; - unsigned long start, offset; - u32 dspcntr; - int ret; - - memcpy(&globle_dev, dev, sizeof(struct drm_device)); - - dev_dbg(dev->dev, "pipe = 0x%x.\n", pipe); - - /* no fb bound */ - if (!crtc->fb) { - dev_dbg(dev->dev, "No FB bound\n"); - return 0; - } - - ret = check_fb(crtc->fb); - if (ret) - return ret; - - if (pipe > 2) { - DRM_ERROR("Illegal Pipe Number.\n"); - return -EINVAL; - } - - if (!gma_power_begin(dev, true)) - return 0; - - start = psbfb->gtt->offset; - offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8); - - REG_WRITE(map->stride, crtc->fb->pitches[0]); - dspcntr = REG_READ(map->cntr); - 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; - } - REG_WRITE(map->cntr, dspcntr); - - dev_dbg(dev->dev, "Writing base %08lX %08lX %d %d\n", - start, offset, x, y); - REG_WRITE(map->linoff, offset); - REG_READ(map->linoff); - REG_WRITE(map->surf, start); - REG_READ(map->surf); - - gma_power_end(dev); - - return 0; -} - -/* - * Disable the pipe, plane and pll. - * - */ -void mdfld_disable_crtc(struct drm_device *dev, int pipe) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - const struct psb_offset *map = &dev_priv->regmap[pipe]; - u32 temp; - - dev_dbg(dev->dev, "pipe = %d\n", pipe); - - - if (pipe != 1) - mdfld_dsi_gen_fifo_ready(dev, MIPI_GEN_FIFO_STAT_REG(pipe), - HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY); - - /* Disable display plane */ - temp = REG_READ(map->cntr); - if ((temp & DISPLAY_PLANE_ENABLE) != 0) { - REG_WRITE(map->cntr, - temp & ~DISPLAY_PLANE_ENABLE); - /* Flush the plane changes */ - REG_WRITE(map->base, REG_READ(map->base)); - REG_READ(map->base); - } - - /* FIXME_JLIU7 MDFLD_PO revisit */ - - /* Next, disable display pipes */ - temp = REG_READ(map->conf); - if ((temp & PIPEACONF_ENABLE) != 0) { - temp &= ~PIPEACONF_ENABLE; - temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF; - REG_WRITE(map->conf, temp); - REG_READ(map->conf); - - /* Wait for for the pipe disable to take effect. */ - mdfldWaitForPipeDisable(dev, pipe); - } - - temp = REG_READ(map->dpll); - if (temp & DPLL_VCO_ENABLE) { - if ((pipe != 1 && - !((REG_READ(PIPEACONF) | REG_READ(PIPECCONF)) - & PIPEACONF_ENABLE)) || pipe == 1) { - temp &= ~(DPLL_VCO_ENABLE); - REG_WRITE(map->dpll, temp); - REG_READ(map->dpll); - /* Wait for the clocks to turn off. */ - /* FIXME_MDFLD PO may need more delay */ - udelay(500); - - if (!(temp & MDFLD_PWR_GATE_EN)) { - /* gating power of DPLL */ - REG_WRITE(map->dpll, temp | MDFLD_PWR_GATE_EN); - /* FIXME_MDFLD PO - change 500 to 1 after PO */ - udelay(5000); - } - } - } - -} - -/** - * Sets the power management mode of the pipe and plane. - * - * This code should probably grow support for turning the cursor off and back - * on appropriately at the same time as we're turning the pipe off/on. - */ -static void mdfld_crtc_dpms(struct drm_crtc *crtc, int mode) -{ - struct drm_device *dev = crtc->dev; - struct drm_psb_private *dev_priv = dev->dev_private; - struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); - int pipe = psb_intel_crtc->pipe; - const struct psb_offset *map = &dev_priv->regmap[pipe]; - u32 pipeconf = dev_priv->pipeconf[pipe]; - u32 temp; - int timeout = 0; - - dev_dbg(dev->dev, "mode = %d, pipe = %d\n", mode, pipe); - - /* Note: Old code uses pipe a stat for pipe b but that appears - to be a bug */ - - if (!gma_power_begin(dev, true)) - return; - - /* XXX: When our outputs are all unaware of DPMS modes other than off - * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. - */ - switch (mode) { - case DRM_MODE_DPMS_ON: - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - /* Enable the DPLL */ - temp = REG_READ(map->dpll); - - if ((temp & DPLL_VCO_ENABLE) == 0) { - /* When ungating power of DPLL, needs to wait 0.5us - before enable the VCO */ - if (temp & MDFLD_PWR_GATE_EN) { - temp &= ~MDFLD_PWR_GATE_EN; - REG_WRITE(map->dpll, temp); - /* FIXME_MDFLD PO - change 500 to 1 after PO */ - udelay(500); - } - - REG_WRITE(map->dpll, temp); - REG_READ(map->dpll); - /* FIXME_MDFLD PO - change 500 to 1 after PO */ - udelay(500); - - REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE); - REG_READ(map->dpll); - - /** - * wait for DSI PLL to lock - * NOTE: only need to poll status of pipe 0 and pipe 1, - * since both MIPI pipes share the same PLL. - */ - while ((pipe != 2) && (timeout < 20000) && - !(REG_READ(map->conf) & PIPECONF_DSIPLL_LOCK)) { - udelay(150); - timeout++; - } - } - - /* Enable the plane */ - temp = REG_READ(map->cntr); - if ((temp & DISPLAY_PLANE_ENABLE) == 0) { - REG_WRITE(map->cntr, - temp | DISPLAY_PLANE_ENABLE); - /* Flush the plane changes */ - REG_WRITE(map->base, REG_READ(map->base)); - } - - /* Enable the pipe */ - temp = REG_READ(map->conf); - if ((temp & PIPEACONF_ENABLE) == 0) { - REG_WRITE(map->conf, pipeconf); - - /* Wait for for the pipe enable to take effect. */ - mdfldWaitForPipeEnable(dev, pipe); - } - - /*workaround for sighting 3741701 Random X blank display*/ - /*perform w/a in video mode only on pipe A or C*/ - if (pipe == 0 || pipe == 2) { - REG_WRITE(map->status, REG_READ(map->status)); - msleep(100); - if (PIPE_VBLANK_STATUS & REG_READ(map->status)) - dev_dbg(dev->dev, "OK"); - else { - dev_dbg(dev->dev, "STUCK!!!!"); - /*shutdown controller*/ - temp = REG_READ(map->cntr); - REG_WRITE(map->cntr, - temp & ~DISPLAY_PLANE_ENABLE); - REG_WRITE(map->base, REG_READ(map->base)); - /*mdfld_dsi_dpi_shut_down(dev, pipe);*/ - REG_WRITE(0xb048, 1); - msleep(100); - temp = REG_READ(map->conf); - temp &= ~PIPEACONF_ENABLE; - REG_WRITE(map->conf, temp); - msleep(100); /*wait for pipe disable*/ - REG_WRITE(MIPI_DEVICE_READY_REG(pipe), 0); - msleep(100); - REG_WRITE(0xb004, REG_READ(0xb004)); - /* try to bring the controller back up again*/ - REG_WRITE(MIPI_DEVICE_READY_REG(pipe), 1); - temp = REG_READ(map->cntr); - REG_WRITE(map->cntr, - temp | DISPLAY_PLANE_ENABLE); - REG_WRITE(map->base, REG_READ(map->base)); - /*mdfld_dsi_dpi_turn_on(dev, pipe);*/ - REG_WRITE(0xb048, 2); - msleep(100); - temp = REG_READ(map->conf); - temp |= PIPEACONF_ENABLE; - REG_WRITE(map->conf, temp); - } - } - - 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, - MIPI_GEN_FIFO_STAT_REG(pipe), - HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY); - - /* Disable the VGA plane that we never use */ - REG_WRITE(VGACNTRL, VGA_DISP_DISABLE); - - /* Disable display plane */ - temp = REG_READ(map->cntr); - if ((temp & DISPLAY_PLANE_ENABLE) != 0) { - REG_WRITE(map->cntr, - temp & ~DISPLAY_PLANE_ENABLE); - /* Flush the plane changes */ - REG_WRITE(map->base, REG_READ(map->base)); - REG_READ(map->base); - } - - /* Next, disable display pipes */ - temp = REG_READ(map->conf); - if ((temp & PIPEACONF_ENABLE) != 0) { - temp &= ~PIPEACONF_ENABLE; - temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF; - REG_WRITE(map->conf, temp); - REG_READ(map->conf); - - /* Wait for for the pipe disable to take effect. */ - mdfldWaitForPipeDisable(dev, pipe); - } - - temp = REG_READ(map->dpll); - if (temp & DPLL_VCO_ENABLE) { - if ((pipe != 1 && !((REG_READ(PIPEACONF) - | REG_READ(PIPECCONF)) & PIPEACONF_ENABLE)) - || pipe == 1) { - temp &= ~(DPLL_VCO_ENABLE); - REG_WRITE(map->dpll, temp); - REG_READ(map->dpll); - /* Wait for the clocks to turn off. */ - /* FIXME_MDFLD PO may need more delay */ - udelay(500); - } - } - break; - } - gma_power_end(dev); -} - - -#define MDFLD_LIMT_DPLL_19 0 -#define MDFLD_LIMT_DPLL_25 1 -#define MDFLD_LIMT_DPLL_83 2 -#define MDFLD_LIMT_DPLL_100 3 -#define MDFLD_LIMT_DSIPLL_19 4 -#define MDFLD_LIMT_DSIPLL_25 5 -#define MDFLD_LIMT_DSIPLL_83 6 -#define MDFLD_LIMT_DSIPLL_100 7 - -#define MDFLD_DOT_MIN 19750 -#define MDFLD_DOT_MAX 120000 -#define MDFLD_DPLL_M_MIN_19 113 -#define MDFLD_DPLL_M_MAX_19 155 -#define MDFLD_DPLL_P1_MIN_19 2 -#define MDFLD_DPLL_P1_MAX_19 10 -#define MDFLD_DPLL_M_MIN_25 101 -#define MDFLD_DPLL_M_MAX_25 130 -#define MDFLD_DPLL_P1_MIN_25 2 -#define MDFLD_DPLL_P1_MAX_25 10 -#define MDFLD_DPLL_M_MIN_83 64 -#define MDFLD_DPLL_M_MAX_83 64 -#define MDFLD_DPLL_P1_MIN_83 2 -#define MDFLD_DPLL_P1_MAX_83 2 -#define MDFLD_DPLL_M_MIN_100 64 -#define MDFLD_DPLL_M_MAX_100 64 -#define MDFLD_DPLL_P1_MIN_100 2 -#define MDFLD_DPLL_P1_MAX_100 2 -#define MDFLD_DSIPLL_M_MIN_19 131 -#define MDFLD_DSIPLL_M_MAX_19 175 -#define MDFLD_DSIPLL_P1_MIN_19 3 -#define MDFLD_DSIPLL_P1_MAX_19 8 -#define MDFLD_DSIPLL_M_MIN_25 97 -#define MDFLD_DSIPLL_M_MAX_25 140 -#define MDFLD_DSIPLL_P1_MIN_25 3 -#define MDFLD_DSIPLL_P1_MAX_25 9 -#define MDFLD_DSIPLL_M_MIN_83 33 -#define MDFLD_DSIPLL_M_MAX_83 92 -#define MDFLD_DSIPLL_P1_MIN_83 2 -#define MDFLD_DSIPLL_P1_MAX_83 3 -#define MDFLD_DSIPLL_M_MIN_100 97 -#define MDFLD_DSIPLL_M_MAX_100 140 -#define MDFLD_DSIPLL_P1_MIN_100 3 -#define MDFLD_DSIPLL_P1_MAX_100 9 - -static const struct mrst_limit_t mdfld_limits[] = { - { /* MDFLD_LIMT_DPLL_19 */ - .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, - .m = {.min = MDFLD_DPLL_M_MIN_19, .max = MDFLD_DPLL_M_MAX_19}, - .p1 = {.min = MDFLD_DPLL_P1_MIN_19, .max = MDFLD_DPLL_P1_MAX_19}, - }, - { /* MDFLD_LIMT_DPLL_25 */ - .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, - .m = {.min = MDFLD_DPLL_M_MIN_25, .max = MDFLD_DPLL_M_MAX_25}, - .p1 = {.min = MDFLD_DPLL_P1_MIN_25, .max = MDFLD_DPLL_P1_MAX_25}, - }, - { /* MDFLD_LIMT_DPLL_83 */ - .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, - .m = {.min = MDFLD_DPLL_M_MIN_83, .max = MDFLD_DPLL_M_MAX_83}, - .p1 = {.min = MDFLD_DPLL_P1_MIN_83, .max = MDFLD_DPLL_P1_MAX_83}, - }, - { /* MDFLD_LIMT_DPLL_100 */ - .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, - .m = {.min = MDFLD_DPLL_M_MIN_100, .max = MDFLD_DPLL_M_MAX_100}, - .p1 = {.min = MDFLD_DPLL_P1_MIN_100, .max = MDFLD_DPLL_P1_MAX_100}, - }, - { /* MDFLD_LIMT_DSIPLL_19 */ - .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, - .m = {.min = MDFLD_DSIPLL_M_MIN_19, .max = MDFLD_DSIPLL_M_MAX_19}, - .p1 = {.min = MDFLD_DSIPLL_P1_MIN_19, .max = MDFLD_DSIPLL_P1_MAX_19}, - }, - { /* MDFLD_LIMT_DSIPLL_25 */ - .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, - .m = {.min = MDFLD_DSIPLL_M_MIN_25, .max = MDFLD_DSIPLL_M_MAX_25}, - .p1 = {.min = MDFLD_DSIPLL_P1_MIN_25, .max = MDFLD_DSIPLL_P1_MAX_25}, - }, - { /* MDFLD_LIMT_DSIPLL_83 */ - .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, - .m = {.min = MDFLD_DSIPLL_M_MIN_83, .max = MDFLD_DSIPLL_M_MAX_83}, - .p1 = {.min = MDFLD_DSIPLL_P1_MIN_83, .max = MDFLD_DSIPLL_P1_MAX_83}, - }, - { /* MDFLD_LIMT_DSIPLL_100 */ - .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, - .m = {.min = MDFLD_DSIPLL_M_MIN_100, .max = MDFLD_DSIPLL_M_MAX_100}, - .p1 = {.min = MDFLD_DSIPLL_P1_MIN_100, .max = MDFLD_DSIPLL_P1_MAX_100}, - }, -}; - -#define MDFLD_M_MIN 21 -#define MDFLD_M_MAX 180 -static const u32 mdfld_m_converts[] = { -/* M configuration table from 9-bit LFSR table */ - 224, 368, 440, 220, 366, 439, 219, 365, 182, 347, /* 21 - 30 */ - 173, 342, 171, 85, 298, 149, 74, 37, 18, 265, /* 31 - 40 */ - 388, 194, 353, 432, 216, 108, 310, 155, 333, 166, /* 41 - 50 */ - 83, 41, 276, 138, 325, 162, 337, 168, 340, 170, /* 51 - 60 */ - 341, 426, 469, 234, 373, 442, 221, 110, 311, 411, /* 61 - 70 */ - 461, 486, 243, 377, 188, 350, 175, 343, 427, 213, /* 71 - 80 */ - 106, 53, 282, 397, 354, 227, 113, 56, 284, 142, /* 81 - 90 */ - 71, 35, 273, 136, 324, 418, 465, 488, 500, 506, /* 91 - 100 */ - 253, 126, 63, 287, 399, 455, 483, 241, 376, 444, /* 101 - 110 */ - 478, 495, 503, 251, 381, 446, 479, 239, 375, 443, /* 111 - 120 */ - 477, 238, 119, 315, 157, 78, 295, 147, 329, 420, /* 121 - 130 */ - 210, 105, 308, 154, 77, 38, 275, 137, 68, 290, /* 131 - 140 */ - 145, 328, 164, 82, 297, 404, 458, 485, 498, 249, /* 141 - 150 */ - 380, 190, 351, 431, 471, 235, 117, 314, 413, 206, /* 151 - 160 */ - 103, 51, 25, 12, 262, 387, 193, 96, 48, 280, /* 161 - 170 */ - 396, 198, 99, 305, 152, 76, 294, 403, 457, 228, /* 171 - 180 */ -}; - -static const struct mrst_limit_t *mdfld_limit(struct drm_crtc *crtc) -{ - const struct mrst_limit_t *limit = NULL; - struct drm_device *dev = crtc->dev; - struct drm_psb_private *dev_priv = dev->dev_private; - - if (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_dbg(dev->dev, "mdfld_limit Wrong display type.\n"); - } - - return limit; -} - -/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ -static void mdfld_clock(int refclk, struct mrst_clock_t *clock) -{ - clock->dot = (refclk * clock->m) / clock->p1; -} - -/** - * Returns a set of divisors for the desired target clock with the given refclk, - * or FALSE. Divisor values are the actual divisors for - */ -static bool -mdfldFindBestPLL(struct drm_crtc *crtc, int target, int refclk, - struct mrst_clock_t *best_clock) -{ - struct mrst_clock_t clock; - const struct mrst_limit_t *limit = mdfld_limit(crtc); - int err = target; - - memset(best_clock, 0, sizeof(*best_clock)); - - for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) { - for (clock.p1 = limit->p1.min; clock.p1 <= limit->p1.max; - clock.p1++) { - int this_err; - - mdfld_clock(refclk, &clock); - - this_err = abs(clock.dot - target); - if (this_err < err) { - *best_clock = clock; - err = this_err; - } - } - } - return err != target; -} - -static int mdfld_crtc_mode_set(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, - int x, int y, - struct drm_framebuffer *old_fb) -{ - struct drm_device *dev = crtc->dev; - struct 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; - const struct psb_offset *map = &dev_priv->regmap[pipe]; - int refclk = 0; - int clk_n = 0, clk_p2 = 0, clk_byte = 1, clk = 0, m_conv = 0, - clk_tmp = 0; - struct mrst_clock_t clock; - bool ok; - u32 dpll = 0, fp = 0; - bool is_mipi = false, is_mipi2 = false, is_hdmi = false; - struct drm_mode_config *mode_config = &dev->mode_config; - struct psb_intel_encoder *psb_intel_encoder = NULL; - uint64_t scalingType = DRM_MODE_SCALE_FULLSCREEN; - struct drm_encoder *encoder; - struct drm_connector *connector; - int timeout = 0; - int ret; - - dev_dbg(dev->dev, "pipe = 0x%x\n", pipe); - -#if 0 - if (pipe == 1) { - if (!gma_power_begin(dev, true)) - return 0; - android_hdmi_crtc_mode_set(crtc, mode, adjusted_mode, - x, y, old_fb); - goto mrst_crtc_mode_set_exit; - } -#endif - - ret = check_fb(crtc->fb); - if (ret) - return ret; - - dev_dbg(dev->dev, "adjusted_hdisplay = %d\n", - adjusted_mode->hdisplay); - dev_dbg(dev->dev, "adjusted_vdisplay = %d\n", - adjusted_mode->vdisplay); - dev_dbg(dev->dev, "adjusted_hsync_start = %d\n", - adjusted_mode->hsync_start); - dev_dbg(dev->dev, "adjusted_hsync_end = %d\n", - adjusted_mode->hsync_end); - dev_dbg(dev->dev, "adjusted_htotal = %d\n", - adjusted_mode->htotal); - dev_dbg(dev->dev, "adjusted_vsync_start = %d\n", - adjusted_mode->vsync_start); - dev_dbg(dev->dev, "adjusted_vsync_end = %d\n", - adjusted_mode->vsync_end); - dev_dbg(dev->dev, "adjusted_vtotal = %d\n", - adjusted_mode->vtotal); - dev_dbg(dev->dev, "adjusted_clock = %d\n", - adjusted_mode->clock); - dev_dbg(dev->dev, "hdisplay = %d\n", - mode->hdisplay); - dev_dbg(dev->dev, "vdisplay = %d\n", - mode->vdisplay); - - if (!gma_power_begin(dev, true)) - return 0; - - memcpy(&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) { - if (!connector) - continue; - - encoder = connector->encoder; - - if (!encoder) - continue; - - if (encoder->crtc != crtc) - continue; - - psb_intel_encoder = psb_intel_attached_encoder(connector); - - switch (psb_intel_encoder->type) { - case INTEL_OUTPUT_MIPI: - is_mipi = true; - break; - case INTEL_OUTPUT_MIPI2: - is_mipi2 = true; - break; - case INTEL_OUTPUT_HDMI: - is_hdmi = true; - break; - } - } - - /* Disable the VGA plane that we never use */ - REG_WRITE(VGACNTRL, VGA_DISP_DISABLE); - - /* Disable the panel fitter if it was on our pipe */ - if (psb_intel_panel_fitter_pipe(dev) == pipe) - REG_WRITE(PFIT_CONTROL, 0); - - /* pipesrc and dspsize control the size that is scaled from, - * which should always be the user's requested size. - */ - if (pipe == 1) { - /* FIXME: To make HDMI display with 864x480 (TPO), 480x864 - * (PYR) or 480x854 (TMD), set the sprite width/height and - * souce image size registers with the adjusted mode for - * pipe B. - */ - - /* - * The defined sprite rectangle must always be completely - * contained within the displayable area of the screen image - * (frame buffer). - */ - REG_WRITE(map->size, ((min(mode->crtc_vdisplay, adjusted_mode->crtc_vdisplay) - 1) << 16) - | (min(mode->crtc_hdisplay, adjusted_mode->crtc_hdisplay) - 1)); - /* Set the CRTC with encoder mode. */ - REG_WRITE(map->src, ((mode->crtc_hdisplay - 1) << 16) - | (mode->crtc_vdisplay - 1)); - } else { - REG_WRITE(map->size, - ((mode->crtc_vdisplay - 1) << 16) | - (mode->crtc_hdisplay - 1)); - REG_WRITE(map->src, - ((mode->crtc_hdisplay - 1) << 16) | - (mode->crtc_vdisplay - 1)); - } - - REG_WRITE(map->pos, 0); - - if (psb_intel_encoder) - drm_object_property_get_value(&connector->base, - dev->mode_config.scaling_mode_property, &scalingType); - - if (scalingType == DRM_MODE_SCALE_NO_SCALE) { - /* Medfield doesn't have register support for centering so we - * need to mess with the h/vblank and h/vsync start and ends - * to get centering - */ - int offsetX = 0, offsetY = 0; - - offsetX = (adjusted_mode->crtc_hdisplay - - mode->crtc_hdisplay) / 2; - offsetY = (adjusted_mode->crtc_vdisplay - - mode->crtc_vdisplay) / 2; - - REG_WRITE(map->htotal, (mode->crtc_hdisplay - 1) | - ((adjusted_mode->crtc_htotal - 1) << 16)); - REG_WRITE(map->vtotal, (mode->crtc_vdisplay - 1) | - ((adjusted_mode->crtc_vtotal - 1) << 16)); - REG_WRITE(map->hblank, (adjusted_mode->crtc_hblank_start - - offsetX - 1) | - ((adjusted_mode->crtc_hblank_end - offsetX - 1) << 16)); - REG_WRITE(map->hsync, (adjusted_mode->crtc_hsync_start - - offsetX - 1) | - ((adjusted_mode->crtc_hsync_end - offsetX - 1) << 16)); - REG_WRITE(map->vblank, (adjusted_mode->crtc_vblank_start - - offsetY - 1) | - ((adjusted_mode->crtc_vblank_end - offsetY - 1) << 16)); - REG_WRITE(map->vsync, (adjusted_mode->crtc_vsync_start - - offsetY - 1) | - ((adjusted_mode->crtc_vsync_end - offsetY - 1) << 16)); - } else { - REG_WRITE(map->htotal, (adjusted_mode->crtc_hdisplay - 1) | - ((adjusted_mode->crtc_htotal - 1) << 16)); - REG_WRITE(map->vtotal, (adjusted_mode->crtc_vdisplay - 1) | - ((adjusted_mode->crtc_vtotal - 1) << 16)); - REG_WRITE(map->hblank, (adjusted_mode->crtc_hblank_start - 1) | - ((adjusted_mode->crtc_hblank_end - 1) << 16)); - REG_WRITE(map->hsync, (adjusted_mode->crtc_hsync_start - 1) | - ((adjusted_mode->crtc_hsync_end - 1) << 16)); - REG_WRITE(map->vblank, (adjusted_mode->crtc_vblank_start - 1) | - ((adjusted_mode->crtc_vblank_end - 1) << 16)); - REG_WRITE(map->vsync, (adjusted_mode->crtc_vsync_start - 1) | - ((adjusted_mode->crtc_vsync_end - 1) << 16)); - } - - /* Flush the plane changes */ - { - struct drm_crtc_helper_funcs *crtc_funcs = - crtc->helper_private; - crtc_funcs->mode_set_base(crtc, x, y, old_fb); - } - - /* setup pipeconf */ - dev_priv->pipeconf[pipe] = PIPEACONF_ENABLE; /* FIXME_JLIU7 REG_READ(pipeconf_reg); */ - - /* Set up the display plane register */ - dev_priv->dspcntr[pipe] = REG_READ(map->cntr); - dev_priv->dspcntr[pipe] |= pipe << DISPPLANE_SEL_PIPE_POS; - dev_priv->dspcntr[pipe] |= DISPLAY_PLANE_ENABLE; - - if (is_mipi2) - goto mrst_crtc_mode_set_exit; - clk = adjusted_mode->clock; - - if (is_hdmi) { - if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19)) { - refclk = 19200; - - if (is_mipi || is_mipi2) - clk_n = 1, clk_p2 = 8; - else if (is_hdmi) - clk_n = 1, clk_p2 = 10; - } else if (ksel == KSEL_BYPASS_25) { - refclk = 25000; - - if (is_mipi || is_mipi2) - clk_n = 1, clk_p2 = 8; - else if (is_hdmi) - clk_n = 1, clk_p2 = 10; - } else if ((ksel == KSEL_BYPASS_83_100) && - dev_priv->core_freq == 166) { - refclk = 83000; - - if (is_mipi || is_mipi2) - clk_n = 4, clk_p2 = 8; - else if (is_hdmi) - clk_n = 4, clk_p2 = 10; - } else if ((ksel == KSEL_BYPASS_83_100) && - (dev_priv->core_freq == 100 || - dev_priv->core_freq == 200)) { - refclk = 100000; - if (is_mipi || is_mipi2) - clk_n = 4, clk_p2 = 8; - else if (is_hdmi) - clk_n = 4, clk_p2 = 10; - } - - if (is_mipi) - clk_byte = dev_priv->bpp / 8; - else if (is_mipi2) - clk_byte = dev_priv->bpp2 / 8; - - clk_tmp = clk * clk_n * clk_p2 * clk_byte; - - dev_dbg(dev->dev, "clk = %d, clk_n = %d, clk_p2 = %d.\n", - clk, clk_n, clk_p2); - dev_dbg(dev->dev, "adjusted_mode->clock = %d, clk_tmp = %d.\n", - adjusted_mode->clock, clk_tmp); - - ok = mdfldFindBestPLL(crtc, clk_tmp, refclk, &clock); - - if (!ok) { - DRM_ERROR - ("mdfldFindBestPLL fail in mdfld_crtc_mode_set.\n"); - } else { - m_conv = mdfld_m_converts[(clock.m - MDFLD_M_MIN)]; - - dev_dbg(dev->dev, "dot clock = %d," - "m = %d, p1 = %d, m_conv = %d.\n", - clock.dot, clock.m, - clock.p1, m_conv); - } - - dpll = REG_READ(map->dpll); - - if (dpll & DPLL_VCO_ENABLE) { - dpll &= ~DPLL_VCO_ENABLE; - REG_WRITE(map->dpll, dpll); - REG_READ(map->dpll); - - /* FIXME jliu7 check the DPLL lock bit PIPEACONF[29] */ - /* FIXME_MDFLD PO - change 500 to 1 after PO */ - udelay(500); - - /* reset M1, N1 & P1 */ - REG_WRITE(map->fp0, 0); - dpll &= ~MDFLD_P1_MASK; - REG_WRITE(map->dpll, dpll); - /* FIXME_MDFLD PO - change 500 to 1 after PO */ - udelay(500); - } - - /* When ungating power of DPLL, needs to wait 0.5us before - * enable the VCO */ - if (dpll & MDFLD_PWR_GATE_EN) { - dpll &= ~MDFLD_PWR_GATE_EN; - REG_WRITE(map->dpll, dpll); - /* FIXME_MDFLD PO - change 500 to 1 after PO */ - udelay(500); - } - dpll = 0; - -#if 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(map->fp0, fp); - REG_WRITE(map->dpll, dpll); - /* FIXME_MDFLD PO - change 500 to 1 after PO */ - udelay(500); - - dpll |= DPLL_VCO_ENABLE; - REG_WRITE(map->dpll, dpll); - REG_READ(map->dpll); - - /* wait for DSI PLL to lock */ - while (timeout < 20000 && - !(REG_READ(map->conf) & PIPECONF_DSIPLL_LOCK)) { - udelay(150); - timeout++; - } - - if (is_mipi) - goto mrst_crtc_mode_set_exit; - - dev_dbg(dev->dev, "is_mipi = 0x%x\n", is_mipi); - - REG_WRITE(map->conf, dev_priv->pipeconf[pipe]); - REG_READ(map->conf); - - /* Wait for for the pipe enable to take effect. */ - REG_WRITE(map->cntr, dev_priv->dspcntr[pipe]); - psb_intel_wait_for_vblank(dev); - -mrst_crtc_mode_set_exit: - - gma_power_end(dev); - - return 0; -} - -const struct drm_crtc_helper_funcs mdfld_helper_funcs = { - .dpms = mdfld_crtc_dpms, - .mode_fixup = psb_intel_crtc_mode_fixup, - .mode_set = mdfld_crtc_mode_set, - .mode_set_base = mdfld__intel_pipe_set_base, - .prepare = psb_intel_crtc_prepare, - .commit = psb_intel_crtc_commit, -}; - diff --git a/drivers/gpu/drm/gma500/mdfld_output.c b/drivers/gpu/drm/gma500/mdfld_output.c deleted file mode 100644 index c95966bb0c96..000000000000 --- a/drivers/gpu/drm/gma500/mdfld_output.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicensen - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: - * Thomas Eaton <thomas.g.eaton@intel.com> - * Scott Rowe <scott.m.rowe@intel.com> -*/ - -#include "mdfld_output.h" -#include "mdfld_dsi_dpi.h" -#include "mdfld_dsi_output.h" - -#include "tc35876x-dsi-lvds.h" - -int mdfld_get_panel_type(struct drm_device *dev, int pipe) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - return dev_priv->mdfld_panel_id; -} - -static void mdfld_init_panel(struct drm_device *dev, int mipi_pipe, - int p_type) -{ - switch (p_type) { - case TPO_VID: - mdfld_dsi_output_init(dev, mipi_pipe, &mdfld_tpo_vid_funcs); - break; - case TC35876X: - tc35876x_init(dev); - mdfld_dsi_output_init(dev, mipi_pipe, &mdfld_tc35876x_funcs); - break; - case TMD_VID: - mdfld_dsi_output_init(dev, mipi_pipe, &mdfld_tmd_vid_funcs); - break; - case HDMI: -/* if (dev_priv->mdfld_hdmi_present) - mdfld_hdmi_init(dev, &dev_priv->mode_dev); */ - break; - } -} - - -int mdfld_output_init(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - - /* FIXME: hardcoded for now */ - dev_priv->mdfld_panel_id = TC35876X; - /* MIPI panel 1 */ - mdfld_init_panel(dev, 0, dev_priv->mdfld_panel_id); - /* HDMI panel */ - mdfld_init_panel(dev, 1, HDMI); - return 0; -} - diff --git a/drivers/gpu/drm/gma500/mdfld_output.h b/drivers/gpu/drm/gma500/mdfld_output.h deleted file mode 100644 index ab2b27c0f037..000000000000 --- a/drivers/gpu/drm/gma500/mdfld_output.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicensen - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: - * Thomas Eaton <thomas.g.eaton@intel.com> - * Scott Rowe <scott.m.rowe@intel.com> -*/ - -#ifndef MDFLD_OUTPUT_H -#define MDFLD_OUTPUT_H - -#include "psb_drv.h" - -#define TPO_PANEL_WIDTH 84 -#define TPO_PANEL_HEIGHT 46 -#define TMD_PANEL_WIDTH 39 -#define TMD_PANEL_HEIGHT 71 - -struct mdfld_dsi_config; - -enum panel_type { - TPO_VID, - TMD_VID, - HDMI, - TC35876X, -}; - -struct panel_info { - u32 width_mm; - u32 height_mm; - /* Other info */ -}; - -struct panel_funcs { - const struct drm_encoder_funcs *encoder_funcs; - const struct drm_encoder_helper_funcs *encoder_helper_funcs; - struct drm_display_mode * (*get_config_mode)(struct drm_device *); - int (*get_panel_info)(struct drm_device *, int, struct panel_info *); - int (*reset)(int pipe); - void (*drv_ic_init)(struct mdfld_dsi_config *dsi_config, int pipe); -}; - -int mdfld_output_init(struct drm_device *dev); - -struct backlight_device *mdfld_get_backlight_device(void); -int mdfld_set_brightness(struct backlight_device *bd); - -int mdfld_get_panel_type(struct drm_device *dev, int pipe); - -extern const struct drm_crtc_helper_funcs mdfld_helper_funcs; - -extern const struct panel_funcs mdfld_tmd_vid_funcs; -extern const struct panel_funcs mdfld_tpo_vid_funcs; - -extern void mdfld_disable_crtc(struct drm_device *dev, int pipe); -extern void mdfldWaitForPipeEnable(struct drm_device *dev, int pipe); -extern void mdfldWaitForPipeDisable(struct drm_device *dev, int pipe); -#endif diff --git a/drivers/gpu/drm/gma500/mdfld_tmd_vid.c b/drivers/gpu/drm/gma500/mdfld_tmd_vid.c deleted file mode 100644 index dc0c6c3d3d29..000000000000 --- a/drivers/gpu/drm/gma500/mdfld_tmd_vid.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright © 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: - * Jim Liu <jim.liu@intel.com> - * Jackie Li<yaodong.li@intel.com> - * Gideon Eaton <eaton. - * Scott Rowe <scott.m.rowe@intel.com> - */ - -#include "mdfld_dsi_dpi.h" -#include "mdfld_dsi_pkg_sender.h" - -static struct drm_display_mode *tmd_vid_get_config_mode(struct drm_device *dev) -{ - struct drm_display_mode *mode; - struct drm_psb_private *dev_priv = dev->dev_private; - struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD; - bool use_gct = false; /*Disable GCT for now*/ - - mode = kzalloc(sizeof(*mode), GFP_KERNEL); - if (!mode) - return NULL; - - if (use_gct) { - mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo; - mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo; - mode->hsync_start = mode->hdisplay + \ - ((ti->hsync_offset_hi << 8) | \ - ti->hsync_offset_lo); - mode->hsync_end = mode->hsync_start + \ - ((ti->hsync_pulse_width_hi << 8) | \ - ti->hsync_pulse_width_lo); - mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) | \ - ti->hblank_lo); - mode->vsync_start = \ - mode->vdisplay + ((ti->vsync_offset_hi << 8) | \ - ti->vsync_offset_lo); - mode->vsync_end = \ - mode->vsync_start + ((ti->vsync_pulse_width_hi << 8) | \ - ti->vsync_pulse_width_lo); - mode->vtotal = mode->vdisplay + \ - ((ti->vblank_hi << 8) | ti->vblank_lo); - mode->clock = ti->pixel_clock * 10; - - dev_dbg(dev->dev, "hdisplay is %d\n", mode->hdisplay); - dev_dbg(dev->dev, "vdisplay is %d\n", mode->vdisplay); - dev_dbg(dev->dev, "HSS is %d\n", mode->hsync_start); - dev_dbg(dev->dev, "HSE is %d\n", mode->hsync_end); - dev_dbg(dev->dev, "htotal is %d\n", mode->htotal); - dev_dbg(dev->dev, "VSS is %d\n", mode->vsync_start); - dev_dbg(dev->dev, "VSE is %d\n", mode->vsync_end); - dev_dbg(dev->dev, "vtotal is %d\n", mode->vtotal); - dev_dbg(dev->dev, "clock is %d\n", mode->clock); - } else { - mode->hdisplay = 480; - mode->vdisplay = 854; - mode->hsync_start = 487; - mode->hsync_end = 490; - mode->htotal = 499; - mode->vsync_start = 861; - mode->vsync_end = 865; - mode->vtotal = 873; - mode->clock = 33264; - } - - drm_mode_set_name(mode); - drm_mode_set_crtcinfo(mode, 0); - - mode->type |= DRM_MODE_TYPE_PREFERRED; - - return mode; -} - -static int tmd_vid_get_panel_info(struct drm_device *dev, - int pipe, - struct panel_info *pi) -{ - if (!dev || !pi) - return -EINVAL; - - pi->width_mm = TMD_PANEL_WIDTH; - pi->height_mm = TMD_PANEL_HEIGHT; - - return 0; -} - -/* ************************************************************************* *\ - * FUNCTION: mdfld_init_TMD_MIPI - * - * DESCRIPTION: This function is called only by mrst_dsi_mode_set and - * restore_display_registers. since this function does not - * acquire the mutex, it is important that the calling function - * does! -\* ************************************************************************* */ - -/* FIXME: make the below data u8 instead of u32; note byte order! */ -static u32 tmd_cmd_mcap_off[] = {0x000000b2}; -static u32 tmd_cmd_enable_lane_switch[] = {0x000101ef}; -static u32 tmd_cmd_set_lane_num[] = {0x006360ef}; -static u32 tmd_cmd_pushing_clock0[] = {0x00cc2fef}; -static u32 tmd_cmd_pushing_clock1[] = {0x00dd6eef}; -static u32 tmd_cmd_set_mode[] = {0x000000b3}; -static u32 tmd_cmd_set_sync_pulse_mode[] = {0x000961ef}; -static u32 tmd_cmd_set_column[] = {0x0100002a, 0x000000df}; -static u32 tmd_cmd_set_page[] = {0x0300002b, 0x00000055}; -static u32 tmd_cmd_set_video_mode[] = {0x00000153}; -/*no auto_bl,need add in furture*/ -static u32 tmd_cmd_enable_backlight[] = {0x00005ab4}; -static u32 tmd_cmd_set_backlight_dimming[] = {0x00000ebd}; - -static void mdfld_dsi_tmd_drv_ic_init(struct mdfld_dsi_config *dsi_config, - int pipe) -{ - struct mdfld_dsi_pkg_sender *sender - = mdfld_dsi_get_pkg_sender(dsi_config); - - DRM_INFO("Enter mdfld init TMD MIPI display.\n"); - - if (!sender) { - DRM_ERROR("Cannot get sender\n"); - return; - } - - if (dsi_config->dvr_ic_inited) - return; - - msleep(3); - - /* FIXME: make the below data u8 instead of u32; note byte order! */ - - mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_mcap_off, - sizeof(tmd_cmd_mcap_off), false); - mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_enable_lane_switch, - sizeof(tmd_cmd_enable_lane_switch), false); - mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_lane_num, - sizeof(tmd_cmd_set_lane_num), false); - mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_pushing_clock0, - sizeof(tmd_cmd_pushing_clock0), false); - mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_pushing_clock1, - sizeof(tmd_cmd_pushing_clock1), false); - mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_mode, - sizeof(tmd_cmd_set_mode), false); - mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_sync_pulse_mode, - sizeof(tmd_cmd_set_sync_pulse_mode), false); - mdfld_dsi_send_mcs_long(sender, (u8 *) tmd_cmd_set_column, - sizeof(tmd_cmd_set_column), false); - mdfld_dsi_send_mcs_long(sender, (u8 *) tmd_cmd_set_page, - sizeof(tmd_cmd_set_page), false); - mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_video_mode, - sizeof(tmd_cmd_set_video_mode), false); - mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_enable_backlight, - sizeof(tmd_cmd_enable_backlight), false); - mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_backlight_dimming, - sizeof(tmd_cmd_set_backlight_dimming), false); - - dsi_config->dvr_ic_inited = 1; -} - -/*TPO DPI encoder helper funcs*/ -static const struct drm_encoder_helper_funcs - mdfld_tpo_dpi_encoder_helper_funcs = { - .dpms = mdfld_dsi_dpi_dpms, - .mode_fixup = mdfld_dsi_dpi_mode_fixup, - .prepare = mdfld_dsi_dpi_prepare, - .mode_set = mdfld_dsi_dpi_mode_set, - .commit = mdfld_dsi_dpi_commit, -}; - -/*TPO DPI encoder funcs*/ -static const struct drm_encoder_funcs mdfld_tpo_dpi_encoder_funcs = { - .destroy = drm_encoder_cleanup, -}; - -const struct panel_funcs mdfld_tmd_vid_funcs = { - .encoder_funcs = &mdfld_tpo_dpi_encoder_funcs, - .encoder_helper_funcs = &mdfld_tpo_dpi_encoder_helper_funcs, - .get_config_mode = &tmd_vid_get_config_mode, - .get_panel_info = tmd_vid_get_panel_info, - .reset = mdfld_dsi_panel_reset, - .drv_ic_init = mdfld_dsi_tmd_drv_ic_init, -}; diff --git a/drivers/gpu/drm/gma500/mdfld_tpo_vid.c b/drivers/gpu/drm/gma500/mdfld_tpo_vid.c deleted file mode 100644 index d8d4170725b2..000000000000 --- a/drivers/gpu/drm/gma500/mdfld_tpo_vid.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright © 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: - * jim liu <jim.liu@intel.com> - * Jackie Li<yaodong.li@intel.com> - */ - -#include "mdfld_dsi_dpi.h" - -static struct drm_display_mode *tpo_vid_get_config_mode(struct drm_device *dev) -{ - struct drm_display_mode *mode; - struct drm_psb_private *dev_priv = dev->dev_private; - struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD; - bool use_gct = false; - - mode = kzalloc(sizeof(*mode), GFP_KERNEL); - if (!mode) - return NULL; - - if (use_gct) { - mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo; - mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo; - mode->hsync_start = mode->hdisplay + - ((ti->hsync_offset_hi << 8) | - ti->hsync_offset_lo); - mode->hsync_end = mode->hsync_start + - ((ti->hsync_pulse_width_hi << 8) | - ti->hsync_pulse_width_lo); - mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) | - ti->hblank_lo); - mode->vsync_start = - mode->vdisplay + ((ti->vsync_offset_hi << 8) | - ti->vsync_offset_lo); - mode->vsync_end = - mode->vsync_start + ((ti->vsync_pulse_width_hi << 8) | - ti->vsync_pulse_width_lo); - mode->vtotal = mode->vdisplay + - ((ti->vblank_hi << 8) | ti->vblank_lo); - mode->clock = ti->pixel_clock * 10; - - dev_dbg(dev->dev, "hdisplay is %d\n", mode->hdisplay); - dev_dbg(dev->dev, "vdisplay is %d\n", mode->vdisplay); - dev_dbg(dev->dev, "HSS is %d\n", mode->hsync_start); - dev_dbg(dev->dev, "HSE is %d\n", mode->hsync_end); - dev_dbg(dev->dev, "htotal is %d\n", mode->htotal); - dev_dbg(dev->dev, "VSS is %d\n", mode->vsync_start); - dev_dbg(dev->dev, "VSE is %d\n", mode->vsync_end); - dev_dbg(dev->dev, "vtotal is %d\n", mode->vtotal); - dev_dbg(dev->dev, "clock is %d\n", mode->clock); - } else { - mode->hdisplay = 864; - mode->vdisplay = 480; - mode->hsync_start = 873; - mode->hsync_end = 876; - mode->htotal = 887; - mode->vsync_start = 487; - mode->vsync_end = 490; - mode->vtotal = 499; - mode->clock = 33264; - } - - drm_mode_set_name(mode); - drm_mode_set_crtcinfo(mode, 0); - - mode->type |= DRM_MODE_TYPE_PREFERRED; - - return mode; -} - -static int tpo_vid_get_panel_info(struct drm_device *dev, - int pipe, - struct panel_info *pi) -{ - if (!dev || !pi) - return -EINVAL; - - pi->width_mm = TPO_PANEL_WIDTH; - pi->height_mm = TPO_PANEL_HEIGHT; - - return 0; -} - -/*TPO DPI encoder helper funcs*/ -static const struct drm_encoder_helper_funcs - mdfld_tpo_dpi_encoder_helper_funcs = { - .dpms = mdfld_dsi_dpi_dpms, - .mode_fixup = mdfld_dsi_dpi_mode_fixup, - .prepare = mdfld_dsi_dpi_prepare, - .mode_set = mdfld_dsi_dpi_mode_set, - .commit = mdfld_dsi_dpi_commit, -}; - -/*TPO DPI encoder funcs*/ -static const struct drm_encoder_funcs mdfld_tpo_dpi_encoder_funcs = { - .destroy = drm_encoder_cleanup, -}; - -const struct panel_funcs mdfld_tpo_vid_funcs = { - .encoder_funcs = &mdfld_tpo_dpi_encoder_funcs, - .encoder_helper_funcs = &mdfld_tpo_dpi_encoder_helper_funcs, - .get_config_mode = &tpo_vid_get_config_mode, - .get_panel_info = tpo_vid_get_panel_info, -}; diff --git a/drivers/gpu/drm/gma500/mid_bios.c b/drivers/gpu/drm/gma500/mid_bios.c index a97e38e284fa..0326f3ddc621 100644 --- a/drivers/gpu/drm/gma500/mid_bios.c +++ b/drivers/gpu/drm/gma500/mid_bios.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /************************************************************************** * 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 @@ -23,23 +11,25 @@ * - Check ioremap failures */ -#include <drm/drmP.h> #include <drm/drm.h> -#include <drm/gma_drm.h> -#include "psb_drv.h" +#include <drm/drm_print.h> + #include "mid_bios.h" +#include "psb_drv.h" 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); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct pci_dev *pdev = to_pci_dev(dev->dev); + struct pci_dev *pci_root = + pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus), + 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 @@ -105,7 +95,10 @@ static void mid_get_fuse_settings(struct drm_device *dev) 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)); + struct pci_dev *pdev = to_pci_dev(dev_priv->dev.dev); + int domain = pci_domain_nr(pdev->bus); + struct pci_dev *pci_gfx_root = + pci_get_domain_bus_and_slot(domain, 0, PCI_DEVFN(2, 0)); if (pci_gfx_root == NULL) { WARN_ON(1); @@ -114,8 +107,7 @@ static void mid_get_pci_revID(struct drm_psb_private *dev_priv) 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); + dev_dbg(dev_priv->dev.dev, "platform_rev_id is %x\n", dev_priv->platform_rev_id); } struct mid_vbt_header { @@ -236,9 +228,9 @@ static int mid_get_vbt_data_r10(struct drm_psb_private *dev_priv, u32 addr) if (read_vbt_r10(addr, &vbt)) return -1; - gct = kmalloc(sizeof(*gct) * vbt.panel_count, GFP_KERNEL); + gct = kmalloc_array(vbt.panel_count, sizeof(*gct), GFP_KERNEL); if (!gct) - return -1; + return -ENOMEM; gct_virtual = ioremap(addr + sizeof(vbt), sizeof(*gct) * vbt.panel_count); @@ -278,13 +270,21 @@ out: static void mid_get_vbt_data(struct drm_psb_private *dev_priv) { - struct drm_device *dev = dev_priv->dev; + struct drm_device *dev = &dev_priv->dev; + struct pci_dev *pdev = to_pci_dev(dev->dev); u32 addr; u8 __iomem *vbt_virtual; struct mid_vbt_header vbt_header; - struct pci_dev *pci_gfx_root = pci_get_bus_and_slot(0, PCI_DEVFN(2, 0)); + struct pci_dev *pci_gfx_root = + pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus), + 0, PCI_DEVFN(2, 0)); int ret = -1; + if (pci_gfx_root == NULL) { + WARN_ON(1); + return; + } + /* Get the address of the platform config vbt */ pci_read_config_dword(pci_gfx_root, 0xFC, &addr); pci_dev_put(pci_gfx_root); @@ -330,7 +330,7 @@ out: int mid_chip_setup(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); mid_get_fuse_settings(dev); mid_get_vbt_data(dev_priv); mid_get_pci_revID(dev_priv); diff --git a/drivers/gpu/drm/gma500/mid_bios.h b/drivers/gpu/drm/gma500/mid_bios.h index 00e7d564b7eb..8707f7c893a7 100644 --- a/drivers/gpu/drm/gma500/mid_bios.h +++ b/drivers/gpu/drm/gma500/mid_bios.h @@ -1,21 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /************************************************************************** * 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. - * **************************************************************************/ +struct drm_device; extern int mid_chip_setup(struct drm_device *dev); diff --git a/drivers/gpu/drm/gma500/mmu.c b/drivers/gpu/drm/gma500/mmu.c index 49bac41beefb..e6753282e70e 100644 --- a/drivers/gpu/drm/gma500/mmu.c +++ b/drivers/gpu/drm/gma500/mmu.c @@ -1,21 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-only /************************************************************************** * Copyright (c) 2007, 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. - * **************************************************************************/ -#include <drm/drmP.h> + +#include <linux/highmem.h> +#include <linux/vmalloc.h> + +#include "mmu.h" #include "psb_drv.h" #include "psb_reg.h" @@ -47,51 +39,6 @@ * but on average it should be fast. */ -struct psb_mmu_driver { - /* protects driver- and pd structures. Always take in read mode - * before taking the page table spinlock. - */ - struct rw_semaphore sem; - - /* protects page tables, directory tables and pt tables. - * and pt structures. - */ - spinlock_t lock; - - atomic_t needs_tlbflush; - - uint8_t __iomem *register_map; - struct psb_mmu_pd *default_pd; - /*uint32_t bif_ctrl;*/ - int has_clflush; - int clflush_add; - unsigned long clflush_mask; - - struct drm_psb_private *dev_priv; -}; - -struct psb_mmu_pd; - -struct psb_mmu_pt { - struct psb_mmu_pd *pd; - uint32_t index; - uint32_t count; - struct page *p; - uint32_t *v; -}; - -struct psb_mmu_pd { - struct psb_mmu_driver *driver; - int hw_context; - struct psb_mmu_pt **tables; - struct page *p; - struct page *dummy_pt; - struct page *dummy_page; - uint32_t pd_mask; - uint32_t invalid_pde; - uint32_t invalid_pte; -}; - static inline uint32_t psb_mmu_pt_index(uint32_t offset) { return (offset >> PSB_PTE_SHIFT) & 0x3FF; @@ -107,8 +54,7 @@ static inline void psb_clflush(void *addr) __asm__ __volatile__("clflush (%0)\n" : : "r"(addr) : "memory"); } -static inline void psb_mmu_clflush(struct psb_mmu_driver *driver, - void *addr) +static inline void psb_mmu_clflush(struct psb_mmu_driver *driver, void *addr) { if (!driver->has_clflush) return; @@ -118,61 +64,69 @@ static inline void psb_mmu_clflush(struct psb_mmu_driver *driver, mb(); } -static void psb_page_clflush(struct psb_mmu_driver *driver, struct page* page) +static void psb_mmu_flush_pd_locked(struct psb_mmu_driver *driver, int force) { - uint32_t clflush_add = driver->clflush_add >> PAGE_SHIFT; - uint32_t clflush_count = PAGE_SIZE / clflush_add; - int i; - uint8_t *clf; - - clf = kmap_atomic(page); - mb(); - for (i = 0; i < clflush_count; ++i) { - psb_clflush(clf); - clf += clflush_add; + struct drm_device *dev = driver->dev; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + + if (atomic_read(&driver->needs_tlbflush) || force) { + uint32_t val = PSB_RSGX32(PSB_CR_BIF_CTRL); + PSB_WSGX32(val | _PSB_CB_CTRL_INVALDC, PSB_CR_BIF_CTRL); + + /* Make sure data cache is turned off before enabling it */ + wmb(); + PSB_WSGX32(val & ~_PSB_CB_CTRL_INVALDC, PSB_CR_BIF_CTRL); + (void)PSB_RSGX32(PSB_CR_BIF_CTRL); + if (driver->msvdx_mmu_invaldc) + atomic_set(driver->msvdx_mmu_invaldc, 1); } - mb(); - kunmap_atomic(clf); -} - -static void psb_pages_clflush(struct psb_mmu_driver *driver, - struct page *page[], unsigned long num_pages) -{ - int i; - - if (!driver->has_clflush) - return ; - - for (i = 0; i < num_pages; i++) - psb_page_clflush(driver, *page++); -} - -static void psb_mmu_flush_pd_locked(struct psb_mmu_driver *driver, - int force) -{ atomic_set(&driver->needs_tlbflush, 0); } +#if 0 static void psb_mmu_flush_pd(struct psb_mmu_driver *driver, int force) { down_write(&driver->sem); psb_mmu_flush_pd_locked(driver, force); up_write(&driver->sem); } +#endif -void psb_mmu_flush(struct psb_mmu_driver *driver, int rc_prot) +void psb_mmu_flush(struct psb_mmu_driver *driver) { - if (rc_prot) - down_write(&driver->sem); - if (rc_prot) - up_write(&driver->sem); + struct drm_device *dev = driver->dev; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + uint32_t val; + + down_write(&driver->sem); + val = PSB_RSGX32(PSB_CR_BIF_CTRL); + if (atomic_read(&driver->needs_tlbflush)) + PSB_WSGX32(val | _PSB_CB_CTRL_INVALDC, PSB_CR_BIF_CTRL); + else + PSB_WSGX32(val | _PSB_CB_CTRL_FLUSH, PSB_CR_BIF_CTRL); + + /* Make sure data cache is turned off and MMU is flushed before + restoring bank interface control register */ + wmb(); + PSB_WSGX32(val & ~(_PSB_CB_CTRL_FLUSH | _PSB_CB_CTRL_INVALDC), + PSB_CR_BIF_CTRL); + (void)PSB_RSGX32(PSB_CR_BIF_CTRL); + + atomic_set(&driver->needs_tlbflush, 0); + if (driver->msvdx_mmu_invaldc) + atomic_set(driver->msvdx_mmu_invaldc, 1); + up_write(&driver->sem); } void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context) { - /*ttm_tt_cache_flush(&pd->p, 1);*/ - psb_pages_clflush(pd->driver, &pd->p, 1); + struct drm_device *dev = pd->driver->dev; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + uint32_t offset = (hw_context == 0) ? PSB_CR_BIF_DIR_LIST_BASE0 : + PSB_CR_BIF_DIR_LIST_BASE1 + hw_context * 4; + down_write(&pd->driver->sem); + PSB_WSGX32(page_to_pfn(pd->p) << PAGE_SHIFT, offset); wmb(); psb_mmu_flush_pd_locked(pd->driver, 1); pd->hw_context = hw_context; @@ -183,7 +137,6 @@ void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context) static inline unsigned long psb_pd_addr_end(unsigned long addr, unsigned long end) { - addr = (addr + PSB_PDE_MASK + 1) & ~PSB_PDE_MASK; return (addr < end) ? addr : end; } @@ -223,28 +176,26 @@ struct psb_mmu_pd *psb_mmu_alloc_pd(struct psb_mmu_driver *driver, goto out_err3; if (!trap_pagefaults) { - pd->invalid_pde = - psb_mmu_mask_pte(page_to_pfn(pd->dummy_pt), - invalid_type); - pd->invalid_pte = - psb_mmu_mask_pte(page_to_pfn(pd->dummy_page), - invalid_type); + pd->invalid_pde = psb_mmu_mask_pte(page_to_pfn(pd->dummy_pt), + invalid_type); + pd->invalid_pte = psb_mmu_mask_pte(page_to_pfn(pd->dummy_page), + invalid_type); } else { pd->invalid_pde = 0; pd->invalid_pte = 0; } - v = kmap(pd->dummy_pt); + v = kmap_local_page(pd->dummy_pt); for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i) v[i] = pd->invalid_pte; - kunmap(pd->dummy_pt); + kunmap_local(v); - v = kmap(pd->p); + v = kmap_local_page(pd->p); for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i) v[i] = pd->invalid_pde; - kunmap(pd->p); + kunmap_local(v); clear_page(kmap(pd->dummy_page)); kunmap(pd->dummy_page); @@ -279,12 +230,16 @@ static void psb_mmu_free_pt(struct psb_mmu_pt *pt) void psb_mmu_free_pagedir(struct psb_mmu_pd *pd) { struct psb_mmu_driver *driver = pd->driver; + struct drm_device *dev = driver->dev; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_mmu_pt *pt; int i; down_write(&driver->sem); - if (pd->hw_context != -1) + if (pd->hw_context != -1) { + PSB_WSGX32(0, PSB_CR_BIF_DIR_LIST_BASE0 + pd->hw_context * 4); psb_mmu_flush_pd_locked(driver, 1); + } /* Should take the spinlock here, but we don't need to do that since we have the semaphore in write mode. */ @@ -331,7 +286,6 @@ static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd) for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i) *ptes++ = pd->invalid_pte; - if (pd->driver->has_clflush && pd->hw_context != -1) { mb(); for (i = 0; i < clflush_count; ++i) { @@ -340,7 +294,6 @@ static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd) } mb(); } - kunmap_atomic(v); spin_unlock(lock); @@ -352,7 +305,7 @@ static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd) } static struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd, - unsigned long addr) + unsigned long addr) { uint32_t index = psb_mmu_pd_index(addr); struct psb_mmu_pt *pt; @@ -383,7 +336,7 @@ static struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd, kunmap_atomic((void *) v); if (pd->hw_context != -1) { - psb_mmu_clflush(pd->driver, (void *) &v[index]); + psb_mmu_clflush(pd->driver, (void *)&v[index]); atomic_set(&pd->driver->needs_tlbflush, 1); } } @@ -420,11 +373,10 @@ static void psb_mmu_pt_unmap_unlock(struct psb_mmu_pt *pt) pd->tables[pt->index] = NULL; if (pd->hw_context != -1) { - psb_mmu_clflush(pd->driver, - (void *) &v[pt->index]); + psb_mmu_clflush(pd->driver, (void *)&v[pt->index]); atomic_set(&pd->driver->needs_tlbflush, 1); } - kunmap_atomic(pt->v); + kunmap_atomic(v); spin_unlock(&pd->driver->lock); psb_mmu_free_pt(pt); return; @@ -432,8 +384,8 @@ static void psb_mmu_pt_unmap_unlock(struct psb_mmu_pt *pt) spin_unlock(&pd->driver->lock); } -static inline void psb_mmu_set_pte(struct psb_mmu_pt *pt, - unsigned long addr, uint32_t pte) +static inline void psb_mmu_set_pte(struct psb_mmu_pt *pt, unsigned long addr, + uint32_t pte) { pt->v[psb_mmu_pt_index(addr)] = pte; } @@ -444,69 +396,41 @@ static inline void psb_mmu_invalidate_pte(struct psb_mmu_pt *pt, pt->v[psb_mmu_pt_index(addr)] = pt->pd->invalid_pte; } - -void psb_mmu_mirror_gtt(struct psb_mmu_pd *pd, - uint32_t mmu_offset, uint32_t gtt_start, - uint32_t gtt_pages) -{ - uint32_t *v; - uint32_t start = psb_mmu_pd_index(mmu_offset); - struct psb_mmu_driver *driver = pd->driver; - int num_pages = gtt_pages; - - down_read(&driver->sem); - spin_lock(&driver->lock); - - v = kmap_atomic(pd->p); - v += start; - - while (gtt_pages--) { - *v++ = gtt_start | pd->pd_mask; - gtt_start += PAGE_SIZE; - } - - /*ttm_tt_cache_flush(&pd->p, num_pages);*/ - psb_pages_clflush(pd->driver, &pd->p, num_pages); - kunmap_atomic(v); - spin_unlock(&driver->lock); - - if (pd->hw_context != -1) - atomic_set(&pd->driver->needs_tlbflush, 1); - - up_read(&pd->driver->sem); - psb_mmu_flush_pd(pd->driver, 0); -} - struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver *driver) { struct psb_mmu_pd *pd; - /* down_read(&driver->sem); */ + down_read(&driver->sem); pd = driver->default_pd; - /* up_read(&driver->sem); */ + up_read(&driver->sem); return pd; } void psb_mmu_driver_takedown(struct psb_mmu_driver *driver) { + struct drm_device *dev = driver->dev; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + + PSB_WSGX32(driver->bif_ctrl, PSB_CR_BIF_CTRL); psb_mmu_free_pagedir(driver->default_pd); kfree(driver); } -struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers, - int trap_pagefaults, - int invalid_type, - struct drm_psb_private *dev_priv) +struct psb_mmu_driver *psb_mmu_driver_init(struct drm_device *dev, + int trap_pagefaults, + int invalid_type, + atomic_t *msvdx_mmu_invaldc) { struct psb_mmu_driver *driver; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); driver = kmalloc(sizeof(*driver), GFP_KERNEL); if (!driver) return NULL; - driver->dev_priv = dev_priv; + driver->dev = dev; driver->default_pd = psb_mmu_alloc_pd(driver, trap_pagefaults, invalid_type); if (!driver->default_pd) @@ -515,17 +439,23 @@ struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers, spin_lock_init(&driver->lock); init_rwsem(&driver->sem); down_write(&driver->sem); - driver->register_map = registers; atomic_set(&driver->needs_tlbflush, 1); + driver->msvdx_mmu_invaldc = msvdx_mmu_invaldc; + + driver->bif_ctrl = PSB_RSGX32(PSB_CR_BIF_CTRL); + PSB_WSGX32(driver->bif_ctrl | _PSB_CB_CTRL_CLEAR_FAULT, + PSB_CR_BIF_CTRL); + PSB_WSGX32(driver->bif_ctrl & ~_PSB_CB_CTRL_CLEAR_FAULT, + PSB_CR_BIF_CTRL); driver->has_clflush = 0; - if (boot_cpu_has(X86_FEATURE_CLFLSH)) { + if (boot_cpu_has(X86_FEATURE_CLFLUSH)) { uint32_t tfms, misc, cap0, cap4, clflush_size; /* - * clflush size is determined at kernel setup for x86_64 - * but not for i386. We have to do it here. + * clflush size is determined at kernel setup for x86_64 but not + * for i386. We have to do it here. */ cpuid(0x00000001, &tfms, &misc, &cap0, &cap4); @@ -545,9 +475,8 @@ out_err1: return NULL; } -static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, - unsigned long address, uint32_t num_pages, - uint32_t desired_tile_stride, +static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, unsigned long address, + uint32_t num_pages, uint32_t desired_tile_stride, uint32_t hw_tile_stride) { struct psb_mmu_pt *pt; @@ -561,11 +490,8 @@ static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, unsigned long clflush_add = pd->driver->clflush_add; unsigned long clflush_mask = pd->driver->clflush_mask; - if (!pd->driver->has_clflush) { - /*ttm_tt_cache_flush(&pd->p, num_pages);*/ - psb_pages_clflush(pd->driver, &pd->p, num_pages); + if (!pd->driver->has_clflush) return; - } if (hw_tile_stride) rows = num_pages / desired_tile_stride; @@ -586,10 +512,8 @@ static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, if (!pt) continue; do { - psb_clflush(&pt->v - [psb_mmu_pt_index(addr)]); - } while (addr += - clflush_add, + psb_clflush(&pt->v[psb_mmu_pt_index(addr)]); + } while (addr += clflush_add, (addr & clflush_mask) < next); psb_mmu_pt_unmap_unlock(pt); @@ -633,7 +557,7 @@ out: up_read(&pd->driver->sem); if (pd->hw_context != -1) - psb_mmu_flush(pd->driver, 0); + psb_mmu_flush(pd->driver); return; } @@ -660,7 +584,7 @@ void psb_mmu_remove_pages(struct psb_mmu_pd *pd, unsigned long address, add = desired_tile_stride << PAGE_SHIFT; row_add = hw_tile_stride << PAGE_SHIFT; - /* down_read(&pd->driver->sem); */ + down_read(&pd->driver->sem); /* Make sure we only need to flush this processor's cache */ @@ -688,10 +612,10 @@ void psb_mmu_remove_pages(struct psb_mmu_pd *pd, unsigned long address, psb_mmu_flush_ptes(pd, f_address, num_pages, desired_tile_stride, hw_tile_stride); - /* up_read(&pd->driver->sem); */ + up_read(&pd->driver->sem); if (pd->hw_context != -1) - psb_mmu_flush(pd->driver, 0); + psb_mmu_flush(pd->driver); } int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, uint32_t start_pfn, @@ -704,7 +628,7 @@ int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, uint32_t start_pfn, unsigned long end; unsigned long next; unsigned long f_address = address; - int ret = 0; + int ret = -ENOMEM; down_read(&pd->driver->sem); @@ -726,6 +650,7 @@ int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, uint32_t start_pfn, psb_mmu_pt_unmap_unlock(pt); } while (addr = next, next != end); + ret = 0; out: if (pd->hw_context != -1) @@ -734,15 +659,15 @@ out: up_read(&pd->driver->sem); if (pd->hw_context != -1) - psb_mmu_flush(pd->driver, 1); + psb_mmu_flush(pd->driver); return ret; } int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, unsigned long address, uint32_t num_pages, - uint32_t desired_tile_stride, - uint32_t hw_tile_stride, int type) + uint32_t desired_tile_stride, uint32_t hw_tile_stride, + int type) { struct psb_mmu_pt *pt; uint32_t rows = 1; @@ -754,7 +679,7 @@ int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, unsigned long add; unsigned long row_add; unsigned long f_address = address; - int ret = 0; + int ret = -ENOMEM; if (hw_tile_stride) { if (num_pages % desired_tile_stride != 0) @@ -777,14 +702,11 @@ int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, do { next = psb_pd_addr_end(addr, end); pt = psb_mmu_pt_alloc_map_lock(pd, addr); - if (!pt) { - ret = -ENOMEM; + if (!pt) goto out; - } do { - pte = - psb_mmu_mask_pte(page_to_pfn(*pages++), - type); + pte = psb_mmu_mask_pte(page_to_pfn(*pages++), + type); psb_mmu_set_pte(pt, addr, pte); pt->count++; } while (addr += PAGE_SIZE, addr < next); @@ -794,6 +716,8 @@ int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, address += row_add; } + + ret = 0; out: if (pd->hw_context != -1) psb_mmu_flush_ptes(pd, f_address, num_pages, @@ -802,48 +726,7 @@ out: up_read(&pd->driver->sem); if (pd->hw_context != -1) - psb_mmu_flush(pd->driver, 1); - - return ret; -} - -int psb_mmu_virtual_to_pfn(struct psb_mmu_pd *pd, uint32_t virtual, - unsigned long *pfn) -{ - int ret; - struct psb_mmu_pt *pt; - uint32_t tmp; - spinlock_t *lock = &pd->driver->lock; - - down_read(&pd->driver->sem); - pt = psb_mmu_pt_map_lock(pd, virtual); - if (!pt) { - uint32_t *v; + psb_mmu_flush(pd->driver); - spin_lock(lock); - v = kmap_atomic(pd->p); - tmp = v[psb_mmu_pd_index(virtual)]; - kunmap_atomic(v); - spin_unlock(lock); - - if (tmp != pd->invalid_pde || !(tmp & PSB_PTE_VALID) || - !(pd->invalid_pte & PSB_PTE_VALID)) { - ret = -EINVAL; - goto out; - } - ret = 0; - *pfn = pd->invalid_pte >> PAGE_SHIFT; - goto out; - } - tmp = pt->v[psb_mmu_pt_index(virtual)]; - if (!(tmp & PSB_PTE_VALID)) { - ret = -EINVAL; - } else { - ret = 0; - *pfn = tmp >> PAGE_SHIFT; - } - psb_mmu_pt_unmap_unlock(pt); -out: - up_read(&pd->driver->sem); return ret; } diff --git a/drivers/gpu/drm/gma500/mmu.h b/drivers/gpu/drm/gma500/mmu.h new file mode 100644 index 000000000000..e6d39703718c --- /dev/null +++ b/drivers/gpu/drm/gma500/mmu.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/************************************************************************** + * Copyright (c) 2007-2011, Intel Corporation. + * All Rights Reserved. + * + **************************************************************************/ + +#ifndef __MMU_H +#define __MMU_H + +struct psb_mmu_driver { + /* protects driver- and pd structures. Always take in read mode + * before taking the page table spinlock. + */ + struct rw_semaphore sem; + + /* protects page tables, directory tables and pt tables. + * and pt structures. + */ + spinlock_t lock; + + atomic_t needs_tlbflush; + atomic_t *msvdx_mmu_invaldc; + struct psb_mmu_pd *default_pd; + uint32_t bif_ctrl; + int has_clflush; + int clflush_add; + unsigned long clflush_mask; + + struct drm_device *dev; +}; + +struct psb_mmu_pd; + +struct psb_mmu_pt { + struct psb_mmu_pd *pd; + uint32_t index; + uint32_t count; + struct page *p; + uint32_t *v; +}; + +struct psb_mmu_pd { + struct psb_mmu_driver *driver; + int hw_context; + struct psb_mmu_pt **tables; + struct page *p; + struct page *dummy_pt; + struct page *dummy_page; + uint32_t pd_mask; + uint32_t invalid_pde; + uint32_t invalid_pte; +}; + +extern struct psb_mmu_driver *psb_mmu_driver_init(struct drm_device *dev, + int trap_pagefaults, + int invalid_type, + atomic_t *msvdx_mmu_invaldc); +extern void psb_mmu_driver_takedown(struct psb_mmu_driver *driver); +extern struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver + *driver); +extern struct psb_mmu_pd *psb_mmu_alloc_pd(struct psb_mmu_driver *driver, + int trap_pagefaults, + int invalid_type); +extern void psb_mmu_free_pagedir(struct psb_mmu_pd *pd); +extern void psb_mmu_flush(struct psb_mmu_driver *driver); +extern void psb_mmu_remove_pfn_sequence(struct psb_mmu_pd *pd, + unsigned long address, + uint32_t num_pages); +extern int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, + uint32_t start_pfn, + unsigned long address, + uint32_t num_pages, int type); +extern void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context); +extern int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, + unsigned long address, uint32_t num_pages, + uint32_t desired_tile_stride, + uint32_t hw_tile_stride, int type); +extern void psb_mmu_remove_pages(struct psb_mmu_pd *pd, + unsigned long address, uint32_t num_pages, + uint32_t desired_tile_stride, + uint32_t hw_tile_stride); + +#endif diff --git a/drivers/gpu/drm/gma500/oaktrail.h b/drivers/gpu/drm/gma500/oaktrail.h index 30adbbe23024..8d20fa2ee286 100644 --- a/drivers/gpu/drm/gma500/oaktrail.h +++ b/drivers/gpu/drm/gma500/oaktrail.h @@ -1,22 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /************************************************************************** * Copyright (c) 2007-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. - * **************************************************************************/ +struct psb_intel_mode_device; + /* MID device specific descriptors */ struct oaktrail_timing_info { diff --git a/drivers/gpu/drm/gma500/oaktrail_crtc.c b/drivers/gpu/drm/gma500/oaktrail_crtc.c index 3071526bc3c1..086d14678a8e 100644 --- a/drivers/gpu/drm/gma500/oaktrail_crtc.c +++ b/drivers/gpu/drm/gma500/oaktrail_crtc.c @@ -1,49 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright © 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. */ +#include <linux/delay.h> #include <linux/i2c.h> #include <linux/pm_runtime.h> -#include <drm/drmP.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_framebuffer.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_print.h> + #include "framebuffer.h" +#include "gem.h" +#include "gma_display.h" +#include "power.h" #include "psb_drv.h" #include "psb_intel_drv.h" #include "psb_intel_reg.h" -#include "psb_intel_display.h" -#include "power.h" - -struct psb_intel_range_t { - int min, max; -}; - -struct oaktrail_limit_t { - struct psb_intel_range_t dot, m, p1; -}; - -struct oaktrail_clock_t { - /* derived values */ - int dot; - int m; - int p1; -}; -#define MRST_LIMIT_LVDS_100L 0 -#define MRST_LIMIT_LVDS_83 1 -#define MRST_LIMIT_LVDS_100 2 +#define MRST_LIMIT_LVDS_100L 0 +#define MRST_LIMIT_LVDS_83 1 +#define MRST_LIMIT_LVDS_100 2 +#define MRST_LIMIT_SDVO 3 #define MRST_DOT_MIN 19750 #define MRST_DOT_MAX 120000 @@ -57,21 +37,40 @@ struct oaktrail_clock_t { #define MRST_P1_MAX_0 7 #define MRST_P1_MAX_1 8 -static const struct oaktrail_limit_t oaktrail_limits[] = { +static bool mrst_lvds_find_best_pll(const struct gma_limit_t *limit, + struct drm_crtc *crtc, int target, + int refclk, struct gma_clock_t *best_clock); + +static bool mrst_sdvo_find_best_pll(const struct gma_limit_t *limit, + struct drm_crtc *crtc, int target, + int refclk, struct gma_clock_t *best_clock); + +static const struct gma_limit_t mrst_limits[] = { { /* MRST_LIMIT_LVDS_100L */ .dot = {.min = MRST_DOT_MIN, .max = MRST_DOT_MAX}, .m = {.min = MRST_M_MIN_100L, .max = MRST_M_MAX_100L}, .p1 = {.min = MRST_P1_MIN, .max = MRST_P1_MAX_1}, + .find_pll = mrst_lvds_find_best_pll, }, { /* MRST_LIMIT_LVDS_83L */ .dot = {.min = MRST_DOT_MIN, .max = MRST_DOT_MAX}, .m = {.min = MRST_M_MIN_83, .max = MRST_M_MAX_83}, .p1 = {.min = MRST_P1_MIN, .max = MRST_P1_MAX_0}, + .find_pll = mrst_lvds_find_best_pll, }, { /* MRST_LIMIT_LVDS_100 */ .dot = {.min = MRST_DOT_MIN, .max = MRST_DOT_MAX}, .m = {.min = MRST_M_MIN_100, .max = MRST_M_MAX_100}, .p1 = {.min = MRST_P1_MIN, .max = MRST_P1_MAX_1}, + .find_pll = mrst_lvds_find_best_pll, + }, + { /* MRST_LIMIT_SDVO */ + .vco = {.min = 1400000, .max = 2800000}, + .n = {.min = 3, .max = 7}, + .m = {.min = 80, .max = 137}, + .p1 = {.min = 1, .max = 2}, + .p2 = {.dot_limit = 200000, .p2_slow = 10, .p2_fast = 10}, + .find_pll = mrst_sdvo_find_best_pll, }, }; @@ -82,65 +81,123 @@ static const u32 oaktrail_m_converts[] = { 0x12, 0x09, 0x24, 0x32, 0x39, 0x1c, }; -static const struct oaktrail_limit_t *oaktrail_limit(struct drm_crtc *crtc) +static const struct gma_limit_t *mrst_limit(struct drm_crtc *crtc, + int refclk) { - const struct oaktrail_limit_t *limit = NULL; + const struct gma_limit_t *limit = NULL; struct drm_device *dev = crtc->dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) - || psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_MIPI)) { + if (gma_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) + || gma_pipe_has_type(crtc, INTEL_OUTPUT_MIPI)) { switch (dev_priv->core_freq) { case 100: - limit = &oaktrail_limits[MRST_LIMIT_LVDS_100L]; + limit = &mrst_limits[MRST_LIMIT_LVDS_100L]; break; case 166: - limit = &oaktrail_limits[MRST_LIMIT_LVDS_83]; + limit = &mrst_limits[MRST_LIMIT_LVDS_83]; break; case 200: - limit = &oaktrail_limits[MRST_LIMIT_LVDS_100]; + limit = &mrst_limits[MRST_LIMIT_LVDS_100]; break; } + } else if (gma_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) { + limit = &mrst_limits[MRST_LIMIT_SDVO]; } else { limit = NULL; - dev_err(dev->dev, "oaktrail_limit Wrong display type.\n"); + dev_err(dev->dev, "mrst_limit Wrong display type.\n"); } return limit; } /** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ -static void oaktrail_clock(int refclk, struct oaktrail_clock_t *clock) +static void mrst_lvds_clock(int refclk, struct gma_clock_t *clock) { clock->dot = (refclk * clock->m) / (14 * clock->p1); } -static void mrstPrintPll(char *prefix, struct oaktrail_clock_t *clock) +static void mrst_print_pll(struct gma_clock_t *clock) { - pr_debug("%s: dotclock = %d, m = %d, p1 = %d.\n", - prefix, clock->dot, clock->m, clock->p1); + DRM_DEBUG_DRIVER("dotclock=%d, m=%d, m1=%d, m2=%d, n=%d, p1=%d, p2=%d\n", + clock->dot, clock->m, clock->m1, clock->m2, clock->n, + clock->p1, clock->p2); } -/** +static bool mrst_sdvo_find_best_pll(const struct gma_limit_t *limit, + struct drm_crtc *crtc, int target, + int refclk, struct gma_clock_t *best_clock) +{ + struct gma_clock_t clock; + u32 target_vco, actual_freq; + s32 freq_error, min_error = 100000; + + memset(best_clock, 0, sizeof(*best_clock)); + memset(&clock, 0, sizeof(clock)); + + for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) { + for (clock.n = limit->n.min; clock.n <= limit->n.max; + clock.n++) { + for (clock.p1 = limit->p1.min; + clock.p1 <= limit->p1.max; clock.p1++) { + /* p2 value always stored in p2_slow on SDVO */ + clock.p = clock.p1 * limit->p2.p2_slow; + target_vco = target * clock.p; + + /* VCO will increase at this point so break */ + if (target_vco > limit->vco.max) + break; + + if (target_vco < limit->vco.min) + continue; + + actual_freq = (refclk * clock.m) / + (clock.n * clock.p); + freq_error = 10000 - + ((target * 10000) / actual_freq); + + if (freq_error < -min_error) { + /* freq_error will start to decrease at + this point so break */ + break; + } + + if (freq_error < 0) + freq_error = -freq_error; + + if (freq_error < min_error) { + min_error = freq_error; + *best_clock = clock; + } + } + } + if (min_error == 0) + break; + } + + return min_error == 0; +} + +/* * 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 -mrstFindBestPLL(struct drm_crtc *crtc, int target, int refclk, - struct oaktrail_clock_t *best_clock) +static bool mrst_lvds_find_best_pll(const struct gma_limit_t *limit, + struct drm_crtc *crtc, int target, + int refclk, struct gma_clock_t *best_clock) { - struct oaktrail_clock_t clock; - const struct oaktrail_limit_t *limit = oaktrail_limit(crtc); + struct gma_clock_t clock; int err = target; memset(best_clock, 0, sizeof(*best_clock)); + memset(&clock, 0, sizeof(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; - oaktrail_clock(refclk, &clock); + mrst_lvds_clock(refclk, &clock); this_err = abs(clock.dot - target); if (this_err < err) { @@ -149,11 +206,10 @@ mrstFindBestPLL(struct drm_crtc *crtc, int target, int refclk, } } } - dev_dbg(crtc->dev->dev, "mrstFindBestPLL err = %d.\n", err); return err != target; } -/** +/* * Sets the power management mode of the pipe and plane. * * This code should probably grow support for turning the cursor off and back @@ -162,13 +218,15 @@ mrstFindBestPLL(struct drm_crtc *crtc, int target, int refclk, static void oaktrail_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; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + int pipe = gma_crtc->pipe; const struct psb_offset *map = &dev_priv->regmap[pipe]; u32 temp; + int i; + int need_aux = gma_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) ? 1 : 0; - if (pipe == 1) { + if (gma_pipe_has_type(crtc, INTEL_OUTPUT_HDMI)) { oaktrail_crtc_hdmi_dpms(crtc, mode); return; } @@ -183,36 +241,46 @@ static void oaktrail_crtc_dpms(struct drm_crtc *crtc, int mode) case DRM_MODE_DPMS_ON: case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: - /* Enable the DPLL */ - temp = REG_READ(map->dpll); - if ((temp & DPLL_VCO_ENABLE) == 0) { - REG_WRITE(map->dpll, temp); - REG_READ(map->dpll); - /* Wait for the clocks to stabilize. */ - udelay(150); - REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE); - REG_READ(map->dpll); - /* Wait for the clocks to stabilize. */ - udelay(150); - REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE); - REG_READ(map->dpll); - /* Wait for the clocks to stabilize. */ - udelay(150); - } - /* Enable the pipe */ - temp = REG_READ(map->conf); - if ((temp & PIPEACONF_ENABLE) == 0) - REG_WRITE(map->conf, temp | PIPEACONF_ENABLE); - /* Enable the plane */ - temp = REG_READ(map->cntr); - if ((temp & DISPLAY_PLANE_ENABLE) == 0) { - REG_WRITE(map->cntr, - temp | DISPLAY_PLANE_ENABLE); - /* Flush the plane changes */ - REG_WRITE(map->base, REG_READ(map->base)); - } + for (i = 0; i <= need_aux; i++) { + /* Enable the DPLL */ + temp = REG_READ_WITH_AUX(map->dpll, i); + if ((temp & DPLL_VCO_ENABLE) == 0) { + REG_WRITE_WITH_AUX(map->dpll, temp, i); + REG_READ_WITH_AUX(map->dpll, i); + /* Wait for the clocks to stabilize. */ + udelay(150); + REG_WRITE_WITH_AUX(map->dpll, + temp | DPLL_VCO_ENABLE, i); + REG_READ_WITH_AUX(map->dpll, i); + /* Wait for the clocks to stabilize. */ + udelay(150); + REG_WRITE_WITH_AUX(map->dpll, + temp | DPLL_VCO_ENABLE, i); + REG_READ_WITH_AUX(map->dpll, i); + /* Wait for the clocks to stabilize. */ + udelay(150); + } + + /* Enable the pipe */ + temp = REG_READ_WITH_AUX(map->conf, i); + if ((temp & PIPEACONF_ENABLE) == 0) { + REG_WRITE_WITH_AUX(map->conf, + temp | PIPEACONF_ENABLE, i); + } + + /* Enable the plane */ + temp = REG_READ_WITH_AUX(map->cntr, i); + if ((temp & DISPLAY_PLANE_ENABLE) == 0) { + REG_WRITE_WITH_AUX(map->cntr, + temp | DISPLAY_PLANE_ENABLE, + i); + /* Flush the plane changes */ + REG_WRITE_WITH_AUX(map->base, + REG_READ_WITH_AUX(map->base, i), i); + } - psb_intel_crtc_load_lut(crtc); + } + gma_crtc_load_lut(crtc); /* Give the overlay scaler a chance to enable if it's on this pipe */ @@ -223,53 +291,57 @@ static void oaktrail_crtc_dpms(struct drm_crtc *crtc, int mode) * 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); - /* Disable display plane */ - temp = REG_READ(map->cntr); - if ((temp & DISPLAY_PLANE_ENABLE) != 0) { - REG_WRITE(map->cntr, - temp & ~DISPLAY_PLANE_ENABLE); - /* Flush the plane changes */ - REG_WRITE(map->base, REG_READ(map->base)); - REG_READ(map->base); - } + for (i = 0; i <= need_aux; i++) { + /* Disable the VGA plane that we never use */ + REG_WRITE_WITH_AUX(VGACNTRL, VGA_DISP_DISABLE, i); + /* Disable display plane */ + temp = REG_READ_WITH_AUX(map->cntr, i); + if ((temp & DISPLAY_PLANE_ENABLE) != 0) { + REG_WRITE_WITH_AUX(map->cntr, + temp & ~DISPLAY_PLANE_ENABLE, i); + /* Flush the plane changes */ + REG_WRITE_WITH_AUX(map->base, + REG_READ(map->base), i); + REG_READ_WITH_AUX(map->base, i); + } - /* Next, disable display pipes */ - temp = REG_READ(map->conf); - if ((temp & PIPEACONF_ENABLE) != 0) { - REG_WRITE(map->conf, temp & ~PIPEACONF_ENABLE); - REG_READ(map->conf); - } - /* Wait for for the pipe disable to take effect. */ - psb_intel_wait_for_vblank(dev); + /* Next, disable display pipes */ + temp = REG_READ_WITH_AUX(map->conf, i); + if ((temp & PIPEACONF_ENABLE) != 0) { + REG_WRITE_WITH_AUX(map->conf, + temp & ~PIPEACONF_ENABLE, i); + REG_READ_WITH_AUX(map->conf, i); + } + /* Wait for the pipe disable to take effect. */ + gma_wait_for_vblank(dev); + + temp = REG_READ_WITH_AUX(map->dpll, i); + if ((temp & DPLL_VCO_ENABLE) != 0) { + REG_WRITE_WITH_AUX(map->dpll, + temp & ~DPLL_VCO_ENABLE, i); + REG_READ_WITH_AUX(map->dpll, i); + } - temp = REG_READ(map->dpll); - if ((temp & DPLL_VCO_ENABLE) != 0) { - REG_WRITE(map->dpll, temp & ~DPLL_VCO_ENABLE); - REG_READ(map->dpll); + /* Wait for the clocks to turn off. */ + udelay(150); } - - /* Wait for the clocks to turn off. */ - udelay(150); break; } - /*Set FIFO Watermarks*/ - REG_WRITE(DSPARB, 0x3FFF); - REG_WRITE(DSPFW1, 0x3F88080A); - REG_WRITE(DSPFW2, 0x0b060808); + /* Set FIFO Watermarks (values taken from EMGD) */ + REG_WRITE(DSPARB, 0x3f80); + REG_WRITE(DSPFW1, 0x3f8f0404); + REG_WRITE(DSPFW2, 0x04040f04); REG_WRITE(DSPFW3, 0x0); - REG_WRITE(DSPFW4, 0x08030404); + REG_WRITE(DSPFW4, 0x04040404); REG_WRITE(DSPFW5, 0x04040404); REG_WRITE(DSPFW6, 0x78); - REG_WRITE(0x70400, REG_READ(0x70400) | 0x4000); - /* Must write Bit 14 of the Chicken Bit Register */ + REG_WRITE(DSPCHICKENBIT, REG_READ(DSPCHICKENBIT) | 0xc040); gma_power_end(dev); } -/** +/* * Return the pipe currently connected to the panel fitter, * or -1 if the panel fitter is not present or not in use */ @@ -292,41 +364,41 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc, 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; + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + int pipe = gma_crtc->pipe; const struct psb_offset *map = &dev_priv->regmap[pipe]; int refclk = 0; - struct oaktrail_clock_t clock; + struct gma_clock_t clock; + const struct gma_limit_t *limit; u32 dpll = 0, fp = 0, dspcntr, pipeconf; bool ok, is_sdvo = false; bool is_lvds = false; bool is_mipi = false; - struct drm_mode_config *mode_config = &dev->mode_config; - struct psb_intel_encoder *psb_intel_encoder = NULL; + struct gma_encoder *gma_encoder = NULL; uint64_t scalingType = DRM_MODE_SCALE_FULLSCREEN; + struct drm_connector_list_iter conn_iter; struct drm_connector *connector; + int i; + int need_aux = gma_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) ? 1 : 0; - if (pipe == 1) + if (gma_pipe_has_type(crtc, INTEL_OUTPUT_HDMI)) return oaktrail_crtc_hdmi_mode_set(crtc, mode, adjusted_mode, x, y, old_fb); 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)); + drm_mode_copy(&gma_crtc->saved_mode, mode); + drm_mode_copy(&gma_crtc->saved_adjusted_mode, adjusted_mode); - list_for_each_entry(connector, &mode_config->connector_list, head) { + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { if (!connector->encoder || connector->encoder->crtc != crtc) continue; - psb_intel_encoder = psb_intel_attached_encoder(connector); + gma_encoder = gma_attached_encoder(connector); - switch (psb_intel_encoder->type) { + switch (gma_encoder->type) { case INTEL_OUTPUT_LVDS: is_lvds = true; break; @@ -337,22 +409,28 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc, is_mipi = true; break; } + + break; } + if (gma_encoder) + drm_object_property_get_value(&connector->base, + dev->mode_config.scaling_mode_property, &scalingType); + + drm_connector_list_iter_end(&conn_iter); + /* Disable the VGA plane that we never use */ - REG_WRITE(VGACNTRL, VGA_DISP_DISABLE); + for (i = 0; i <= need_aux; i++) + REG_WRITE_WITH_AUX(VGACNTRL, VGA_DISP_DISABLE, i); /* Disable the panel fitter if it was on our pipe */ if (oaktrail_panel_fitter_pipe(dev) == pipe) REG_WRITE(PFIT_CONTROL, 0); - REG_WRITE(map->src, - ((mode->crtc_hdisplay - 1) << 16) | - (mode->crtc_vdisplay - 1)); - - if (psb_intel_encoder) - drm_object_property_get_value(&connector->base, - dev->mode_config.scaling_mode_property, &scalingType); + for (i = 0; i <= need_aux; i++) { + REG_WRITE_WITH_AUX(map->src, ((mode->crtc_hdisplay - 1) << 16) | + (mode->crtc_vdisplay - 1), i); + } if (scalingType == DRM_MODE_SCALE_NO_SCALE) { /* Moorestown doesn't have register support for centering so @@ -365,40 +443,44 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc, offsetY = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2; - REG_WRITE(map->htotal, (mode->crtc_hdisplay - 1) | - ((adjusted_mode->crtc_htotal - 1) << 16)); - REG_WRITE(map->vtotal, (mode->crtc_vdisplay - 1) | - ((adjusted_mode->crtc_vtotal - 1) << 16)); - REG_WRITE(map->hblank, - (adjusted_mode->crtc_hblank_start - offsetX - 1) | - ((adjusted_mode->crtc_hblank_end - offsetX - 1) << 16)); - REG_WRITE(map->hsync, - (adjusted_mode->crtc_hsync_start - offsetX - 1) | - ((adjusted_mode->crtc_hsync_end - offsetX - 1) << 16)); - REG_WRITE(map->vblank, - (adjusted_mode->crtc_vblank_start - offsetY - 1) | - ((adjusted_mode->crtc_vblank_end - offsetY - 1) << 16)); - REG_WRITE(map->vsync, - (adjusted_mode->crtc_vsync_start - offsetY - 1) | - ((adjusted_mode->crtc_vsync_end - offsetY - 1) << 16)); + for (i = 0; i <= need_aux; i++) { + REG_WRITE_WITH_AUX(map->htotal, (mode->crtc_hdisplay - 1) | + ((adjusted_mode->crtc_htotal - 1) << 16), i); + REG_WRITE_WITH_AUX(map->vtotal, (mode->crtc_vdisplay - 1) | + ((adjusted_mode->crtc_vtotal - 1) << 16), i); + REG_WRITE_WITH_AUX(map->hblank, + (adjusted_mode->crtc_hblank_start - offsetX - 1) | + ((adjusted_mode->crtc_hblank_end - offsetX - 1) << 16), i); + REG_WRITE_WITH_AUX(map->hsync, + (adjusted_mode->crtc_hsync_start - offsetX - 1) | + ((adjusted_mode->crtc_hsync_end - offsetX - 1) << 16), i); + REG_WRITE_WITH_AUX(map->vblank, + (adjusted_mode->crtc_vblank_start - offsetY - 1) | + ((adjusted_mode->crtc_vblank_end - offsetY - 1) << 16), i); + REG_WRITE_WITH_AUX(map->vsync, + (adjusted_mode->crtc_vsync_start - offsetY - 1) | + ((adjusted_mode->crtc_vsync_end - offsetY - 1) << 16), i); + } } else { - REG_WRITE(map->htotal, (adjusted_mode->crtc_hdisplay - 1) | - ((adjusted_mode->crtc_htotal - 1) << 16)); - REG_WRITE(map->vtotal, (adjusted_mode->crtc_vdisplay - 1) | - ((adjusted_mode->crtc_vtotal - 1) << 16)); - REG_WRITE(map->hblank, (adjusted_mode->crtc_hblank_start - 1) | - ((adjusted_mode->crtc_hblank_end - 1) << 16)); - REG_WRITE(map->hsync, (adjusted_mode->crtc_hsync_start - 1) | - ((adjusted_mode->crtc_hsync_end - 1) << 16)); - REG_WRITE(map->vblank, (adjusted_mode->crtc_vblank_start - 1) | - ((adjusted_mode->crtc_vblank_end - 1) << 16)); - REG_WRITE(map->vsync, (adjusted_mode->crtc_vsync_start - 1) | - ((adjusted_mode->crtc_vsync_end - 1) << 16)); + for (i = 0; i <= need_aux; i++) { + REG_WRITE_WITH_AUX(map->htotal, (adjusted_mode->crtc_hdisplay - 1) | + ((adjusted_mode->crtc_htotal - 1) << 16), i); + REG_WRITE_WITH_AUX(map->vtotal, (adjusted_mode->crtc_vdisplay - 1) | + ((adjusted_mode->crtc_vtotal - 1) << 16), i); + REG_WRITE_WITH_AUX(map->hblank, (adjusted_mode->crtc_hblank_start - 1) | + ((adjusted_mode->crtc_hblank_end - 1) << 16), i); + REG_WRITE_WITH_AUX(map->hsync, (adjusted_mode->crtc_hsync_start - 1) | + ((adjusted_mode->crtc_hsync_end - 1) << 16), i); + REG_WRITE_WITH_AUX(map->vblank, (adjusted_mode->crtc_vblank_start - 1) | + ((adjusted_mode->crtc_vblank_end - 1) << 16), i); + REG_WRITE_WITH_AUX(map->vsync, (adjusted_mode->crtc_vsync_start - 1) | + ((adjusted_mode->crtc_vsync_end - 1) << 16), i); + } } /* Flush the plane changes */ { - struct drm_crtc_helper_funcs *crtc_funcs = + const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; crtc_funcs->mode_set_base(crtc, x, y, old_fb); } @@ -418,21 +500,30 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc, if (is_mipi) goto oaktrail_crtc_mode_set_exit; - refclk = dev_priv->core_freq * 1000; dpll = 0; /*BIT16 = 0 for 100MHz reference */ - ok = mrstFindBestPLL(crtc, adjusted_mode->clock, refclk, &clock); + refclk = is_sdvo ? 96000 : dev_priv->core_freq * 1000; + limit = mrst_limit(crtc, refclk); + ok = limit->find_pll(limit, crtc, adjusted_mode->clock, + refclk, &clock); - if (!ok) { - dev_dbg(dev->dev, "mrstFindBestPLL fail in oaktrail_crtc_mode_set.\n"); - } else { - dev_dbg(dev->dev, "oaktrail_crtc_mode_set pixel clock = %d," - "m = %x, p1 = %x.\n", clock.dot, clock.m, - clock.p1); + if (is_sdvo) { + /* Convert calculated values to register values */ + clock.p1 = (1L << (clock.p1 - 1)); + clock.m -= 2; + clock.n = (1L << (clock.n - 1)); } - fp = oaktrail_m_converts[(clock.m - MRST_M_MIN)] << 8; + if (!ok) + DRM_ERROR("Failed to find proper PLL settings"); + + mrst_print_pll(&clock); + + if (is_sdvo) + fp = clock.n << 16 | clock.m; + else + fp = oaktrail_m_converts[(clock.m - MRST_M_MIN)] << 8; dpll |= DPLL_VGA_MODE_DIS; @@ -456,59 +547,57 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc, /* compute bitmask from p1 value */ - dpll |= (1 << (clock.p1 - 2)) << 17; + if (is_sdvo) + dpll |= clock.p1 << 16; // dpll |= (1 << (clock.p1 - 1)) << 16; + else + dpll |= (1 << (clock.p1 - 2)) << 17; dpll |= DPLL_VCO_ENABLE; - mrstPrintPll("chosen", &clock); - if (dpll & DPLL_VCO_ENABLE) { - REG_WRITE(map->fp0, fp); - REG_WRITE(map->dpll, dpll & ~DPLL_VCO_ENABLE); - REG_READ(map->dpll); - /* Check the DPLLA lock bit PIPEACONF[29] */ - udelay(150); + for (i = 0; i <= need_aux; i++) { + REG_WRITE_WITH_AUX(map->fp0, fp, i); + REG_WRITE_WITH_AUX(map->dpll, dpll & ~DPLL_VCO_ENABLE, i); + REG_READ_WITH_AUX(map->dpll, i); + /* Check the DPLLA lock bit PIPEACONF[29] */ + udelay(150); + } } - REG_WRITE(map->fp0, fp); - REG_WRITE(map->dpll, dpll); - REG_READ(map->dpll); - /* Wait for the clocks to stabilize. */ - udelay(150); + for (i = 0; i <= need_aux; i++) { + REG_WRITE_WITH_AUX(map->fp0, fp, i); + REG_WRITE_WITH_AUX(map->dpll, dpll, i); + REG_READ_WITH_AUX(map->dpll, i); + /* Wait for the clocks to stabilize. */ + udelay(150); - /* write it again -- the BIOS does, after all */ - REG_WRITE(map->dpll, dpll); - REG_READ(map->dpll); - /* Wait for the clocks to stabilize. */ - udelay(150); + /* write it again -- the BIOS does, after all */ + REG_WRITE_WITH_AUX(map->dpll, dpll, i); + REG_READ_WITH_AUX(map->dpll, i); + /* Wait for the clocks to stabilize. */ + udelay(150); - REG_WRITE(map->conf, pipeconf); - REG_READ(map->conf); - psb_intel_wait_for_vblank(dev); + REG_WRITE_WITH_AUX(map->conf, pipeconf, i); + REG_READ_WITH_AUX(map->conf, i); + gma_wait_for_vblank(dev); - REG_WRITE(map->cntr, dspcntr); - psb_intel_wait_for_vblank(dev); + REG_WRITE_WITH_AUX(map->cntr, dspcntr, i); + gma_wait_for_vblank(dev); + } oaktrail_crtc_mode_set_exit: gma_power_end(dev); return 0; } -static bool oaktrail_crtc_mode_fixup(struct drm_crtc *crtc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - return true; -} - static int oaktrail_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) { struct drm_device *dev = crtc->dev; - struct drm_psb_private *dev_priv = dev->dev_private; - struct 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; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + struct drm_framebuffer *fb = crtc->primary->fb; + int pipe = gma_crtc->pipe; const struct psb_offset *map = &dev_priv->regmap[pipe]; unsigned long start, offset; @@ -516,7 +605,7 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc, int ret = 0; /* no fb bound */ - if (!crtc->fb) { + if (!fb) { dev_dbg(dev->dev, "No FB bound\n"); return 0; } @@ -524,20 +613,20 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc, if (!gma_power_begin(dev, true)) return 0; - start = psbfb->gtt->offset; - offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8); + start = to_psb_gem_object(fb->obj[0])->offset; + offset = y * fb->pitches[0] + x * fb->format->cpp[0]; - REG_WRITE(map->stride, crtc->fb->pitches[0]); + REG_WRITE(map->stride, fb->pitches[0]); dspcntr = REG_READ(map->cntr); dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; - switch (crtc->fb->bits_per_pixel) { + switch (fb->format->cpp[0] * 8) { case 8: dspcntr |= DISPPLANE_8BPP; break; case 16: - if (crtc->fb->depth == 15) + if (fb->format->depth == 15) dspcntr |= DISPPLANE_15_16BPP; else dspcntr |= DISPPLANE_16BPP; @@ -563,24 +652,10 @@ pipe_set_base_exit: return ret; } -static void oaktrail_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 oaktrail_crtc_commit(struct drm_crtc *crtc) -{ - struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); -} - const struct drm_crtc_helper_funcs oaktrail_helper_funcs = { .dpms = oaktrail_crtc_dpms, - .mode_fixup = oaktrail_crtc_mode_fixup, .mode_set = oaktrail_crtc_mode_set, .mode_set_base = oaktrail_pipe_set_base, - .prepare = oaktrail_crtc_prepare, - .commit = oaktrail_crtc_commit, + .prepare = gma_crtc_prepare, + .commit = gma_crtc_commit, }; - diff --git a/drivers/gpu/drm/gma500/oaktrail_device.c b/drivers/gpu/drm/gma500/oaktrail_device.c index 08747fd7105c..2531959d3d77 100644 --- a/drivers/gpu/drm/gma500/oaktrail_device.c +++ b/drivers/gpu/drm/gma500/oaktrail_device.c @@ -1,45 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-only /************************************************************************** * 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/delay.h> #include <linux/dmi.h> -#include <drm/drmP.h> +#include <linux/module.h> + #include <drm/drm.h> -#include <drm/gma_drm.h> + +#include "intel_bios.h" +#include "mid_bios.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" -#include "intel_bios.h" +#include "psb_reg.h" static int oaktrail_output_init(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); if (dev_priv->iLVDS_enable) oaktrail_lvds_init(dev, &dev_priv->mode_dev); else dev_err(dev->dev, "DSI is not supported\n"); if (dev_priv->hdmi_priv) oaktrail_hdmi_init(dev, &dev_priv->mode_dev); + + psb_intel_sdvo_init(dev, SDVOB); + return 0; } @@ -47,29 +36,18 @@ static int oaktrail_output_init(struct drm_device *dev) * 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 *oaktrail_backlight_device; -static int oaktrail_brightness; - -static int oaktrail_set_brightness(struct backlight_device *bd) +static void oaktrail_set_brightness(struct drm_device *dev, int level) { - struct drm_device *dev = bl_get_data(oaktrail_backlight_device); - struct drm_psb_private *dev_priv = dev->dev_private; - int level = bd->props.brightness; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); 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; @@ -92,21 +70,11 @@ static int oaktrail_set_brightness(struct backlight_device *bd) REG_WRITE(BLC_PWM_CTL, (max_pwm_blc << 16) | blc_pwm_ctl); gma_power_end(dev); } - oaktrail_brightness = level; - return 0; } -static int oaktrail_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 oaktrail_brightness; -} - -static int device_backlight_init(struct drm_device *dev) +static int oaktrail_backlight_init(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); unsigned long core_clock; u16 bl_max_freq; uint32_t value; @@ -133,44 +101,11 @@ static int device_backlight_init(struct drm_device *dev) REG_WRITE(BLC_PWM_CTL, value | (value << 16)); gma_power_end(dev); } - return 0; -} - -static const struct backlight_ops oaktrail_ops = { - .get_brightness = oaktrail_get_brightness, - .update_status = oaktrail_set_brightness, -}; - -static int oaktrail_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; - - oaktrail_backlight_device = backlight_device_register("oaktrail-bl", - NULL, (void *)dev, &oaktrail_ops, &props); - if (IS_ERR(oaktrail_backlight_device)) - return PTR_ERR(oaktrail_backlight_device); - - ret = device_backlight_init(dev); - if (ret < 0) { - backlight_device_unregister(oaktrail_backlight_device); - return ret; - } - oaktrail_backlight_device->props.brightness = 100; - oaktrail_backlight_device->props.max_brightness = 100; - backlight_update_status(oaktrail_backlight_device); - dev_priv->backlight_device = oaktrail_backlight_device; + oaktrail_set_brightness(dev, PSB_MAX_BRIGHTNESS); return 0; } -#endif - /* * Provide the Moorestown specific chip logic and low level methods * for power management @@ -185,7 +120,7 @@ static int oaktrail_backlight_init(struct drm_device *dev) */ static int oaktrail_save_display_registers(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_save_area *regs = &dev_priv->regs; struct psb_pipe *p = ®s->pipe[0]; int i; @@ -299,7 +234,7 @@ static int oaktrail_save_display_registers(struct drm_device *dev) */ static int oaktrail_restore_display_registers(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_save_area *regs = &dev_priv->regs; struct psb_pipe *p = ®s->pipe[0]; u32 pp_stat; @@ -324,7 +259,7 @@ static int oaktrail_restore_display_registers(struct drm_device *dev) /* Actually enable it */ PSB_WVDC32(p->dpll, MRST_DPLL_A); - DRM_UDELAY(150); + udelay(150); /* Restore mode */ PSB_WVDC32(p->htotal, HTOTAL_A); @@ -414,7 +349,7 @@ static int oaktrail_restore_display_registers(struct drm_device *dev) */ static int oaktrail_power_down(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); u32 pwr_mask ; u32 pwr_sts; @@ -438,7 +373,7 @@ static int oaktrail_power_down(struct drm_device *dev) */ static int oaktrail_power_up(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); u32 pwr_mask = PSB_PWRGT_DISPLAY_MASK; u32 pwr_sts, pwr_cnt; @@ -510,12 +445,10 @@ static const struct psb_offset oaktrail_regmap[2] = { static int oaktrail_chip_setup(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); int ret; - - if (pci_enable_msi(dev->pdev)) - dev_warn(dev->dev, "Enabling MSI failed!\n"); + dev_priv->use_msi = true; dev_priv->regmap = oaktrail_regmap; ret = mid_chip_setup(dev); @@ -526,14 +459,16 @@ static int oaktrail_chip_setup(struct drm_device *dev) psb_intel_opregion_init(dev); psb_intel_init_bios(dev); } + gma_intel_setup_gmbus(dev); oaktrail_hdmi_setup(dev); return 0; } static void oaktrail_teardown(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + gma_intel_teardown_gmbus(dev); oaktrail_hdmi_teardown(dev); if (!dev_priv->has_gct) psb_intel_destroy_bios(dev); @@ -541,27 +476,28 @@ static void oaktrail_teardown(struct drm_device *dev) const struct psb_ops oaktrail_chip_ops = { .name = "Oaktrail", - .accel_2d = 1, .pipes = 2, .crtcs = 2, .hdmi_mask = (1 << 1), .lvds_mask = (1 << 0), + .sdvo_mask = (1 << 1), .cursor_needs_phys = 0, .sgx_offset = MRST_SGX_OFFSET, .chip_setup = oaktrail_chip_setup, .chip_teardown = oaktrail_teardown, .crtc_helper = &oaktrail_helper_funcs, - .crtc_funcs = &psb_intel_crtc_funcs, .output_init = oaktrail_output_init, -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE .backlight_init = oaktrail_backlight_init, -#endif + .backlight_set = oaktrail_set_brightness, + .backlight_name = "oaktrail-bl", .save_regs = oaktrail_save_display_registers, .restore_regs = oaktrail_restore_display_registers, + .save_crtc = gma_crtc_save, + .restore_crtc = gma_crtc_restore, .power_down = oaktrail_power_down, .power_up = oaktrail_power_up, diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c index f036f1fc161e..20d027d552c7 100644 --- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c +++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c @@ -24,11 +24,18 @@ * Li Peng <peng.li@intel.com> */ -#include <drm/drmP.h> +#include <linux/delay.h> + #include <drm/drm.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_edid.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_print.h> +#include <drm/drm_simple_kms_helper.h> + +#include "psb_drv.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)) @@ -127,7 +134,7 @@ static const struct oaktrail_hdmi_limit oaktrail_hdmi_limit = { static void oaktrail_hdmi_audio_enable(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; HDMI_WRITE(HDMI_HCR, 0x67); @@ -142,7 +149,7 @@ static void oaktrail_hdmi_audio_enable(struct drm_device *dev) static void oaktrail_hdmi_audio_disable(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; HDMI_WRITE(0x51a8, 0x0); @@ -155,17 +162,9 @@ static void oaktrail_hdmi_audio_disable(struct drm_device *dev) HDMI_READ(HDMI_HCR); } -static void wait_for_vblank(struct drm_device *dev) -{ - /* Wait for 20ms, i.e. one cycle at 50hz. */ - mdelay(20); -} - 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); + u32 new_crtc_htotal; /* * 1024 x 768 new_crtc_htotal = 0x1024; @@ -269,7 +268,7 @@ int oaktrail_crtc_hdmi_mode_set(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) { struct drm_device *dev = crtc->dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; int pipe = 1; int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; @@ -353,7 +352,7 @@ int oaktrail_crtc_hdmi_mode_set(struct drm_crtc *crtc, /* Flush the plane changes */ { - struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; crtc_funcs->mode_set_base(crtc, x, y, old_fb); } @@ -372,10 +371,10 @@ int oaktrail_crtc_hdmi_mode_set(struct drm_crtc *crtc, REG_WRITE(PCH_PIPEBCONF, pipeconf); REG_READ(PCH_PIPEBCONF); - wait_for_vblank(dev); + gma_wait_for_vblank(dev); REG_WRITE(dspcntr_reg, dspcntr); - wait_for_vblank(dev); + gma_wait_for_vblank(dev); gma_power_end(dev); @@ -459,7 +458,7 @@ void oaktrail_crtc_hdmi_dpms(struct drm_crtc *crtc, int mode) REG_READ(PCH_PIPEBCONF); } - wait_for_vblank(dev); + gma_wait_for_vblank(dev); /* Enable plane */ temp = REG_READ(DSPBCNTR); @@ -470,7 +469,7 @@ void oaktrail_crtc_hdmi_dpms(struct drm_crtc *crtc, int mode) REG_READ(DSPBSURF); } - psb_intel_crtc_load_lut(crtc); + gma_crtc_load_lut(crtc); } /* DSPARB */ @@ -499,7 +498,7 @@ static void oaktrail_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 drm_psb_private *dev_priv = to_drm_psb_private(dev); struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; u32 temp; @@ -515,8 +514,8 @@ static void oaktrail_hdmi_dpms(struct drm_encoder *encoder, int mode) HDMI_WRITE(HDMI_VIDEO_REG, temp); } -static int oaktrail_hdmi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status oaktrail_hdmi_mode_valid(struct drm_connector *connector, + const struct drm_display_mode *mode) { if (mode->clock > 165000) return MODE_CLOCK_HIGH; @@ -529,19 +528,12 @@ static int oaktrail_hdmi_mode_valid(struct drm_connector *connector, return MODE_OK; } -static bool oaktrail_hdmi_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - return true; -} - static enum drm_connector_status oaktrail_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 drm_psb_private *dev_priv = to_drm_psb_private(dev); struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; u32 temp; @@ -591,7 +583,7 @@ static int oaktrail_hdmi_get_modes(struct drm_connector *connector) } if (edid) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); } return ret; @@ -614,17 +606,16 @@ static void oaktrail_hdmi_destroy(struct drm_connector *connector) static const struct drm_encoder_helper_funcs oaktrail_hdmi_helper_funcs = { .dpms = oaktrail_hdmi_dpms, - .mode_fixup = oaktrail_hdmi_mode_fixup, - .prepare = psb_intel_encoder_prepare, + .prepare = gma_encoder_prepare, .mode_set = oaktrail_hdmi_mode_set, - .commit = psb_intel_encoder_commit, + .commit = gma_encoder_commit, }; static const struct drm_connector_helper_funcs oaktrail_hdmi_connector_helper_funcs = { .get_modes = oaktrail_hdmi_get_modes, .mode_valid = oaktrail_hdmi_mode_valid, - .best_encoder = psb_intel_best_encoder, + .best_encoder = gma_best_encoder, }; static const struct drm_connector_funcs oaktrail_hdmi_connector_funcs = { @@ -634,68 +625,50 @@ static const struct drm_connector_funcs oaktrail_hdmi_connector_funcs = { .destroy = oaktrail_hdmi_destroy, }; -static void oaktrail_hdmi_enc_destroy(struct drm_encoder *encoder) -{ - drm_encoder_cleanup(encoder); -} - -static const struct drm_encoder_funcs oaktrail_hdmi_enc_funcs = { - .destroy = oaktrail_hdmi_enc_destroy, -}; - void oaktrail_hdmi_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev) { - struct psb_intel_encoder *psb_intel_encoder; - struct psb_intel_connector *psb_intel_connector; + struct gma_encoder *gma_encoder; + struct gma_connector *gma_connector; struct drm_connector *connector; struct drm_encoder *encoder; - psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder), GFP_KERNEL); - if (!psb_intel_encoder) + gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL); + if (!gma_encoder) return; - psb_intel_connector = kzalloc(sizeof(struct psb_intel_connector), GFP_KERNEL); - if (!psb_intel_connector) + gma_connector = kzalloc(sizeof(struct gma_connector), GFP_KERNEL); + if (!gma_connector) goto failed_connector; - connector = &psb_intel_connector->base; - encoder = &psb_intel_encoder->base; + connector = &gma_connector->base; + encoder = &gma_encoder->base; drm_connector_init(dev, connector, &oaktrail_hdmi_connector_funcs, DRM_MODE_CONNECTOR_DVID); - drm_encoder_init(dev, encoder, - &oaktrail_hdmi_enc_funcs, - DRM_MODE_ENCODER_TMDS); + drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_TMDS); - psb_intel_connector_attach_encoder(psb_intel_connector, - psb_intel_encoder); + gma_connector_attach_encoder(gma_connector, gma_encoder); - psb_intel_encoder->type = INTEL_OUTPUT_HDMI; + gma_encoder->type = INTEL_OUTPUT_HDMI; drm_encoder_helper_add(encoder, &oaktrail_hdmi_helper_funcs); drm_connector_helper_add(connector, &oaktrail_hdmi_connector_helper_funcs); connector->display_info.subpixel_order = SubPixelHorizontalRGB; connector->interlace_allowed = false; connector->doublescan_allowed = false; - drm_sysfs_connector_add(connector); dev_info(dev->dev, "HDMI initialised.\n"); return; failed_connector: - kfree(psb_intel_encoder); + kfree(gma_encoder); } -static DEFINE_PCI_DEVICE_TABLE(hdmi_ids) = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080d) }, - { 0 } -}; - void oaktrail_hdmi_setup(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct pci_dev *pdev; struct oaktrail_hdmi_dev *hdmi_dev; int ret; @@ -748,14 +721,14 @@ out: void oaktrail_hdmi_teardown(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; struct pci_dev *pdev; if (hdmi_dev) { pdev = hdmi_dev->dev; - pci_set_drvdata(pdev, NULL); oaktrail_hdmi_i2c_exit(pdev); + pci_set_drvdata(pdev, NULL); iounmap(hdmi_dev->regs); kfree(hdmi_dev); pci_dev_put(pdev); @@ -765,7 +738,7 @@ void oaktrail_hdmi_teardown(struct drm_device *dev) /* save HDMI register state */ void oaktrail_hdmi_save(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; struct psb_state *regs = &dev_priv->regs.psb; struct psb_pipe *pipeb = &dev_priv->regs.pipe[1]; @@ -818,7 +791,7 @@ void oaktrail_hdmi_save(struct drm_device *dev) /* restore HDMI register state */ void oaktrail_hdmi_restore(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv; struct psb_state *regs = &dev_priv->regs.psb; struct psb_pipe *pipeb = &dev_priv->regs.pipe[1]; @@ -830,7 +803,7 @@ void oaktrail_hdmi_restore(struct drm_device *dev) 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); + udelay(150); /* pipe */ PSB_WVDC32(pipeb->src, PIPEBSRC); diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c b/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c index 1eb86c79523e..48e8ac560a2a 100644 --- a/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c +++ b/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c @@ -30,6 +30,9 @@ #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/delay.h> + +#include <drm/drm_print.h> + #include "psb_drv.h" #define HDMI_READ(reg) readl(hdmi_dev->regs + (reg)) @@ -99,7 +102,7 @@ static int xfer_read(struct i2c_adapter *adap, struct i2c_msg *pmsg) i2c_dev->status = I2C_STAT_INIT; i2c_dev->msg = pmsg; i2c_dev->buf_offset = 0; - INIT_COMPLETION(i2c_dev->complete); + reinit_completion(&i2c_dev->complete); /* Enable I2C transaction */ temp = ((pmsg->len) << 20) | HI2C_EDID_READ | HI2C_ENABLE_TRANSACTION; @@ -168,7 +171,6 @@ static struct i2c_adapter oaktrail_hdmi_i2c_adapter = { .name = "oaktrail_hdmi_i2c", .nr = 3, .owner = THIS_MODULE, - .class = I2C_CLASS_DDC, .algo = &oaktrail_hdmi_i2c_algorithm, }; @@ -279,11 +281,8 @@ int oaktrail_hdmi_i2c_init(struct pci_dev *dev) 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; - } + if (!i2c_dev) + return -ENOMEM; i2c_dev->adap = &oaktrail_hdmi_i2c_adapter; i2c_dev->status = I2C_STAT_INIT; @@ -300,16 +299,23 @@ int oaktrail_hdmi_i2c_init(struct pci_dev *dev) oaktrail_hdmi_i2c_adapter.name, hdmi_dev); if (ret) { DRM_ERROR("Failed to request IRQ for I2C controller\n"); - goto err; + goto free_dev; } /* Adapter registration */ ret = i2c_add_numbered_adapter(&oaktrail_hdmi_i2c_adapter); - return ret; + if (ret) { + DRM_ERROR("Failed to add I2C adapter\n"); + goto free_irq; + } + + return 0; -err: +free_irq: + free_irq(dev->irq, hdmi_dev); +free_dev: kfree(i2c_dev); -exit: + return ret; } diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c index 325013a9c48c..0705ba3813e6 100644 --- a/drivers/gpu/drm/gma500/oaktrail_lvds.c +++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright © 2006-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 Anholt <eric@anholt.net> * Dave Airlie <airlied@linux.ie> @@ -21,15 +9,18 @@ */ #include <linux/i2c.h> -#include <drm/drmP.h> -#include <asm/mrst.h> +#include <linux/pm_runtime.h> + +#include <drm/drm_edid.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_print.h> +#include <drm/drm_simple_kms_helper.h> #include "intel_bios.h" +#include "power.h" #include "psb_drv.h" #include "psb_intel_drv.h" #include "psb_intel_reg.h" -#include "power.h" -#include <linux/pm_runtime.h> /* The max/min PWM frequency in BPCR[31:17] - */ /* The smallest number is 1 (not 0) that can fit in the @@ -39,15 +30,15 @@ #define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF #define BRIGHTNESS_MAX_LEVEL 100 -/** +/* * Sets the power state for the panel. */ static void oaktrail_lvds_set_power(struct drm_device *dev, - struct psb_intel_encoder *psb_intel_encoder, + struct gma_encoder *gma_encoder, bool on) { u32 pp_status; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); if (!gma_power_begin(dev, true)) return; @@ -70,7 +61,6 @@ static void oaktrail_lvds_set_power(struct drm_device *dev, pp_status = REG_READ(PP_STATUS); } while (pp_status & PP_ON); dev_priv->is_lvds_on = false; - pm_request_idle(&dev->pdev->dev); } gma_power_end(dev); } @@ -78,13 +68,12 @@ static void oaktrail_lvds_set_power(struct drm_device *dev, static void oaktrail_lvds_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; - struct psb_intel_encoder *psb_intel_encoder = - to_psb_intel_encoder(encoder); + struct gma_encoder *gma_encoder = to_gma_encoder(encoder); if (mode == DRM_MODE_DPMS_ON) - oaktrail_lvds_set_power(dev, psb_intel_encoder, true); + oaktrail_lvds_set_power(dev, gma_encoder, true); else - oaktrail_lvds_set_power(dev, psb_intel_encoder, false); + oaktrail_lvds_set_power(dev, gma_encoder, false); /* XXX: We never power down the LVDS pairs. */ } @@ -94,9 +83,9 @@ static void oaktrail_lvds_mode_set(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; - struct drm_mode_config *mode_config = &dev->mode_config; + struct drm_connector_list_iter conn_iter; struct drm_connector *connector = NULL; struct drm_crtc *crtc = encoder->crtc; u32 lvds_port; @@ -123,20 +112,22 @@ static void oaktrail_lvds_mode_set(struct drm_encoder *encoder, REG_WRITE(LVDS, lvds_port); /* Find the connector we're trying to set up */ - list_for_each_entry(connector, &mode_config->connector_list, head) { - if (!connector->encoder || connector->encoder->crtc != crtc) - continue; + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + if (connector->encoder && connector->encoder->crtc == crtc) + break; } if (!connector) { + drm_connector_list_iter_end(&conn_iter); DRM_ERROR("Couldn't find connector when setting mode"); + gma_power_end(dev); return; } - drm_object_property_get_value( - &connector->base, - dev->mode_config.scaling_mode_property, - &v); + drm_object_property_get_value( &connector->base, + dev->mode_config.scaling_mode_property, &v); + drm_connector_list_iter_end(&conn_iter); if (v == DRM_MODE_SCALE_NO_SCALE) REG_WRITE(PFIT_CONTROL, 0); @@ -165,9 +156,8 @@ static void oaktrail_lvds_mode_set(struct drm_encoder *encoder, static void oaktrail_lvds_prepare(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct drm_psb_private *dev_priv = dev->dev_private; - struct psb_intel_encoder *psb_intel_encoder = - to_psb_intel_encoder(encoder); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_encoder *gma_encoder = to_gma_encoder(encoder); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; if (!gma_power_begin(dev, true)) @@ -176,13 +166,13 @@ static void oaktrail_lvds_prepare(struct drm_encoder *encoder) mode_dev->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL); mode_dev->backlight_duty_cycle = (mode_dev->saveBLC_PWM_CTL & BACKLIGHT_DUTY_CYCLE_MASK); - oaktrail_lvds_set_power(dev, psb_intel_encoder, false); + oaktrail_lvds_set_power(dev, gma_encoder, false); gma_power_end(dev); } static u32 oaktrail_lvds_get_max_backlight(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); u32 ret; if (gma_power_begin(dev, false)) { @@ -202,15 +192,14 @@ static u32 oaktrail_lvds_get_max_backlight(struct drm_device *dev) static void oaktrail_lvds_commit(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct drm_psb_private *dev_priv = dev->dev_private; - struct psb_intel_encoder *psb_intel_encoder = - to_psb_intel_encoder(encoder); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_encoder *gma_encoder = to_gma_encoder(encoder); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; if (mode_dev->backlight_duty_cycle == 0) mode_dev->backlight_duty_cycle = oaktrail_lvds_get_max_backlight(dev); - oaktrail_lvds_set_power(dev, psb_intel_encoder, true); + oaktrail_lvds_set_power(dev, gma_encoder, true); } static const struct drm_encoder_helper_funcs oaktrail_lvds_helper_funcs = { @@ -221,37 +210,13 @@ static const struct drm_encoder_helper_funcs oaktrail_lvds_helper_funcs = { .commit = oaktrail_lvds_commit, }; -static struct drm_display_mode lvds_configuration_modes[] = { - /* hard coded fixed mode for TPO LTPS LPJ040K001A */ - { DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER, 33264, 800, 836, - 846, 1056, 0, 480, 489, 491, 525, 0, 0) }, - /* hard coded fixed mode for LVDS 800x480 */ - { DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER, 30994, 800, 801, - 802, 1024, 0, 480, 481, 482, 525, 0, 0) }, - /* hard coded fixed mode for Samsung 480wsvga LVDS 1024x600@75 */ - { DRM_MODE("1024x600", DRM_MODE_TYPE_DRIVER, 53990, 1024, 1072, - 1104, 1184, 0, 600, 603, 604, 608, 0, 0) }, - /* hard coded fixed mode for Samsung 480wsvga LVDS 1024x600@75 */ - { DRM_MODE("1024x600", DRM_MODE_TYPE_DRIVER, 53990, 1024, 1104, - 1136, 1184, 0, 600, 603, 604, 608, 0, 0) }, - /* hard coded fixed mode for Sharp wsvga LVDS 1024x600 */ - { DRM_MODE("1024x600", DRM_MODE_TYPE_DRIVER, 48885, 1024, 1124, - 1204, 1312, 0, 600, 607, 610, 621, 0, 0) }, - /* hard coded fixed mode for LVDS 1024x768 */ - { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048, - 1184, 1344, 0, 768, 771, 777, 806, 0, 0) }, - /* hard coded fixed mode for LVDS 1366x768 */ - { DRM_MODE("1366x768", DRM_MODE_TYPE_DRIVER, 77500, 1366, 1430, - 1558, 1664, 0, 768, 769, 770, 776, 0, 0) }, -}; - /* Returns the panel fixed mode from configuration. */ static void oaktrail_lvds_get_configuration_mode(struct drm_device *dev, struct psb_intel_mode_device *mode_dev) { struct drm_display_mode *mode = NULL; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD; mode_dev->panel_fixed_mode = NULL; @@ -282,15 +247,15 @@ static void oaktrail_lvds_get_configuration_mode(struct drm_device *dev, ((ti->vblank_hi << 8) | ti->vblank_lo); mode->clock = ti->pixel_clock * 10; #if 0 - printk(KERN_INFO "hdisplay is %d\n", mode->hdisplay); - printk(KERN_INFO "vdisplay is %d\n", mode->vdisplay); - printk(KERN_INFO "HSS is %d\n", mode->hsync_start); - printk(KERN_INFO "HSE is %d\n", mode->hsync_end); - printk(KERN_INFO "htotal is %d\n", mode->htotal); - printk(KERN_INFO "VSS is %d\n", mode->vsync_start); - printk(KERN_INFO "VSE is %d\n", mode->vsync_end); - printk(KERN_INFO "vtotal is %d\n", mode->vtotal); - printk(KERN_INFO "clock is %d\n", mode->clock); + pr_info("hdisplay is %d\n", mode->hdisplay); + pr_info("vdisplay is %d\n", mode->vdisplay); + pr_info("HSS is %d\n", mode->hsync_start); + pr_info("HSE is %d\n", mode->hsync_end); + pr_info("htotal is %d\n", mode->htotal); + pr_info("VSS is %d\n", mode->vsync_start); + pr_info("VSE is %d\n", mode->vsync_end); + pr_info("vtotal is %d\n", mode->vtotal); + pr_info("clock is %d\n", mode->clock); #endif mode_dev->panel_fixed_mode = mode; } @@ -306,10 +271,10 @@ static void oaktrail_lvds_get_configuration_mode(struct drm_device *dev, mode_dev->panel_fixed_mode = drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); - /* Then guess */ + + /* If we still got no mode then bail */ if (mode_dev->panel_fixed_mode == NULL) - mode_dev->panel_fixed_mode - = drm_mode_duplicate(dev, &lvds_configuration_modes[2]); + return; drm_mode_set_name(mode_dev->panel_fixed_mode); drm_mode_set_crtcinfo(mode_dev->panel_fixed_mode, 0); @@ -318,6 +283,7 @@ static void oaktrail_lvds_get_configuration_mode(struct drm_device *dev, /** * oaktrail_lvds_init - setup LVDS connectors on this device * @dev: drm device + * @mode_dev: PSB mode 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). @@ -325,36 +291,40 @@ static void oaktrail_lvds_get_configuration_mode(struct drm_device *dev, void oaktrail_lvds_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev) { - struct psb_intel_encoder *psb_intel_encoder; - struct psb_intel_connector *psb_intel_connector; + struct gma_encoder *gma_encoder; + struct gma_connector *gma_connector; + struct gma_i2c_chan *ddc_bus; struct drm_connector *connector; struct drm_encoder *encoder; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct edid *edid; struct i2c_adapter *i2c_adap; struct drm_display_mode *scan; /* *modes, *bios_mode; */ + int ret; - psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder), GFP_KERNEL); - if (!psb_intel_encoder) + gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL); + if (!gma_encoder) return; - psb_intel_connector = kzalloc(sizeof(struct psb_intel_connector), GFP_KERNEL); - if (!psb_intel_connector) - goto failed_connector; + gma_connector = kzalloc(sizeof(struct gma_connector), GFP_KERNEL); + if (!gma_connector) + goto err_free_encoder; - connector = &psb_intel_connector->base; - encoder = &psb_intel_encoder->base; + connector = &gma_connector->base; + encoder = &gma_encoder->base; dev_priv->is_lvds_on = true; - drm_connector_init(dev, connector, - &psb_intel_lvds_connector_funcs, - DRM_MODE_CONNECTOR_LVDS); + ret = drm_connector_init(dev, connector, + &psb_intel_lvds_connector_funcs, + DRM_MODE_CONNECTOR_LVDS); + if (ret) + goto err_free_connector; - drm_encoder_init(dev, encoder, &psb_intel_lvds_enc_funcs, - DRM_MODE_ENCODER_LVDS); + ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_LVDS); + if (ret) + goto err_connector_cleanup; - psb_intel_connector_attach_encoder(psb_intel_connector, - psb_intel_encoder); - psb_intel_encoder->type = INTEL_OUTPUT_LVDS; + gma_connector_attach_encoder(gma_connector, gma_encoder); + gma_encoder->type = INTEL_OUTPUT_LVDS; drm_encoder_helper_add(encoder, &oaktrail_lvds_helper_funcs); drm_connector_helper_add(connector, @@ -387,21 +357,36 @@ void oaktrail_lvds_init(struct drm_device *dev, * if closed, act like it's not there for now */ + edid = NULL; + mutex_lock(&dev->mode_config.mutex); + i2c_adap = i2c_get_adapter(dev_priv->ops->i2c_bus); - if (i2c_adap == NULL) - dev_err(dev->dev, "No ddc adapter available!\n"); + if (i2c_adap) + edid = drm_get_edid(connector, i2c_adap); + + if (edid == NULL && dev_priv->lpc_gpio_base) { + ddc_bus = oaktrail_lvds_i2c_init(dev); + if (!IS_ERR(ddc_bus)) { + i2c_adap = &ddc_bus->base; + edid = drm_get_edid(connector, i2c_adap); + } + } + + /* + * Due to the logic in probing for i2c buses above we do not know the + * i2c_adap until now. Hence we cannot use drm_connector_init_with_ddc() + * but must instead set connector->ddc manually here. + */ + connector->ddc = i2c_adap; + /* * Attempt to get the fixed panel mode from DDC. Assume that the * preferred mode is the right one. */ - if (i2c_adap) { - edid = drm_get_edid(connector, i2c_adap); - if (edid) { - drm_mode_connector_update_edid_property(connector, - edid); - drm_add_edid_modes(connector, edid); - kfree(edid); - } + if (edid) { + drm_connector_update_edid_property(connector, edid); + drm_add_edid_modes(connector, edid); + kfree(edid); list_for_each_entry(scan, &connector->probed_modes, head) { if (scan->type & DRM_MODE_TYPE_PREFERRED) { @@ -410,7 +395,8 @@ void oaktrail_lvds_init(struct drm_device *dev, goto out; /* FIXME: check for quirks */ } } - } + } else + dev_err(dev->dev, "No ddc adapter available!\n"); /* * If we didn't get EDID, try geting panel timing * from configuration data @@ -425,24 +411,23 @@ void oaktrail_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) { dev_err(dev->dev, "Found no modes on the lvds, ignoring the LVDS\n"); - goto failed_find; + goto err_unlock; } out: - drm_sysfs_connector_add(connector); - return; + mutex_unlock(&dev->mode_config.mutex); -failed_find: - dev_dbg(dev->dev, "No LVDS modes found, disabling.\n"); - if (psb_intel_encoder->ddc_bus) - psb_intel_i2c_destroy(psb_intel_encoder->ddc_bus); - -/* failed_ddc: */ + return; +err_unlock: + mutex_unlock(&dev->mode_config.mutex); + gma_i2c_destroy(to_gma_i2c_chan(connector->ddc)); drm_encoder_cleanup(encoder); +err_connector_cleanup: drm_connector_cleanup(connector); - kfree(psb_intel_connector); -failed_connector: - kfree(psb_intel_encoder); +err_free_connector: + kfree(gma_connector); +err_free_encoder: + kfree(gma_encoder); } diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c b/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c new file mode 100644 index 000000000000..939c53fd09e8 --- /dev/null +++ b/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2002-2010, Intel Corporation. + * Copyright (c) 2014 ATRON electronic GmbH + * Author: Jan Safrata <jan.nikitenko@gmail.com> + * + * 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 shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include <linux/delay.h> +#include <linux/i2c-algo-bit.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/types.h> + +#include "psb_drv.h" +#include "psb_intel_reg.h" + + +/* + * LPC GPIO based I2C bus for LVDS of Atom E6xx + */ + +/*----------------------------------------------------------------------------- + * LPC Register Offsets. Used for LVDS GPIO Bit Bashing. Registers are part + * Atom E6xx [D31:F0] + ----------------------------------------------------------------------------*/ +#define RGEN 0x20 +#define RGIO 0x24 +#define RGLVL 0x28 +#define RGTPE 0x2C +#define RGTNE 0x30 +#define RGGPE 0x34 +#define RGSMI 0x38 +#define RGTS 0x3C + +/* The LVDS GPIO clock lines are GPIOSUS[3] + * The LVDS GPIO data lines are GPIOSUS[4] + */ +#define GPIO_CLOCK 0x08 +#define GPIO_DATA 0x10 + +#define LPC_READ_REG(chan, r) inl((chan)->reg + (r)) +#define LPC_WRITE_REG(chan, r, val) outl((val), (chan)->reg + (r)) + +static int get_clock(void *data) +{ + struct gma_i2c_chan *chan = data; + u32 val; + + val = LPC_READ_REG(chan, RGIO); + val |= GPIO_CLOCK; + LPC_WRITE_REG(chan, RGIO, val); + LPC_READ_REG(chan, RGLVL); + val = (LPC_READ_REG(chan, RGLVL) & GPIO_CLOCK) ? 1 : 0; + + return val; +} + +static int get_data(void *data) +{ + struct gma_i2c_chan *chan = data; + u32 val; + + val = LPC_READ_REG(chan, RGIO); + val |= GPIO_DATA; + LPC_WRITE_REG(chan, RGIO, val); + LPC_READ_REG(chan, RGLVL); + val = (LPC_READ_REG(chan, RGLVL) & GPIO_DATA) ? 1 : 0; + + return val; +} + +static void set_clock(void *data, int state_high) +{ + struct gma_i2c_chan *chan = data; + u32 val; + + if (state_high) { + val = LPC_READ_REG(chan, RGIO); + val |= GPIO_CLOCK; + LPC_WRITE_REG(chan, RGIO, val); + } else { + val = LPC_READ_REG(chan, RGIO); + val &= ~GPIO_CLOCK; + LPC_WRITE_REG(chan, RGIO, val); + val = LPC_READ_REG(chan, RGLVL); + val &= ~GPIO_CLOCK; + LPC_WRITE_REG(chan, RGLVL, val); + } +} + +static void set_data(void *data, int state_high) +{ + struct gma_i2c_chan *chan = data; + u32 val; + + if (state_high) { + val = LPC_READ_REG(chan, RGIO); + val |= GPIO_DATA; + LPC_WRITE_REG(chan, RGIO, val); + } else { + val = LPC_READ_REG(chan, RGIO); + val &= ~GPIO_DATA; + LPC_WRITE_REG(chan, RGIO, val); + val = LPC_READ_REG(chan, RGLVL); + val &= ~GPIO_DATA; + LPC_WRITE_REG(chan, RGLVL, val); + } +} + +struct gma_i2c_chan *oaktrail_lvds_i2c_init(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_i2c_chan *chan; + int ret; + + chan = kzalloc(sizeof(struct gma_i2c_chan), GFP_KERNEL); + if (!chan) + return ERR_PTR(-ENOMEM); + + chan->drm_dev = dev; + chan->reg = dev_priv->lpc_gpio_base; + strscpy(chan->base.name, "gma500 LPC", sizeof(chan->base.name)); + chan->base.owner = THIS_MODULE; + chan->base.algo_data = &chan->algo; + chan->base.dev.parent = dev->dev; + chan->algo.setsda = set_data; + chan->algo.setscl = set_clock; + chan->algo.getsda = get_data; + chan->algo.getscl = get_clock; + chan->algo.udelay = 100; + chan->algo.timeout = usecs_to_jiffies(2200); + chan->algo.data = chan; + + i2c_set_adapdata(&chan->base, chan); + + set_data(chan, 1); + set_clock(chan, 1); + udelay(50); + + ret = i2c_bit_add_bus(&chan->base); + if (ret < 0) { + kfree(chan); + return ERR_PTR(ret); + } + + return chan; +} diff --git a/drivers/gpu/drm/gma500/opregion.c b/drivers/gpu/drm/gma500/opregion.c index ad0d6de938f3..5f0daa25b86d 100644 --- a/drivers/gpu/drm/gma500/opregion.c +++ b/drivers/gpu/drm/gma500/opregion.c @@ -22,8 +22,11 @@ * */ #include <linux/acpi.h> -#include <linux/acpi_io.h> + +#include <drm/drm_print.h> + #include "psb_drv.h" +#include "psb_irq.h" #include "psb_intel_reg.h" #define PCI_ASLE 0xe4 @@ -148,36 +151,32 @@ static struct psb_intel_opregion *system_opregion; static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct opregion_asle *asle = dev_priv->opregion.asle; - struct backlight_device *bd = dev_priv->backlight_device; DRM_DEBUG_DRIVER("asle set backlight %x\n", bclp); if (!(bclp & ASLE_BCLP_VALID)) return ASLE_BACKLIGHT_FAILED; - if (bd == NULL) - return ASLE_BACKLIGHT_FAILED; - bclp &= ASLE_BCLP_MSK; if (bclp > 255) return ASLE_BACKLIGHT_FAILED; - if (config_enabled(CONFIG_BACKLIGHT_CLASS_DEVICE)) { - int max = bd->props.max_brightness; - gma_backlight_set(dev, bclp * max / 255); - } + gma_backlight_set(dev, bclp * PSB_MAX_BRIGHTNESS / 255); asle->cblv = (bclp * 0x64) / 0xff | ASLE_CBLV_VALID; return 0; } -void psb_intel_opregion_asle_intr(struct drm_device *dev) +static void psb_intel_opregion_asle_work(struct work_struct *work) { - struct drm_psb_private *dev_priv = dev->dev_private; - struct opregion_asle *asle = dev_priv->opregion.asle; + struct psb_intel_opregion *opregion = + container_of(work, struct psb_intel_opregion, asle_work); + struct drm_psb_private *dev_priv = + container_of(opregion, struct drm_psb_private, opregion); + struct opregion_asle *asle = opregion->asle; u32 asle_stat = 0; u32 asle_req; @@ -191,9 +190,18 @@ void psb_intel_opregion_asle_intr(struct drm_device *dev) } if (asle_req & ASLE_SET_BACKLIGHT) - asle_stat |= asle_set_backlight(dev, asle->bclp); + asle_stat |= asle_set_backlight(&dev_priv->dev, asle->bclp); asle->aslc = asle_stat; + +} + +void psb_intel_opregion_asle_intr(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + + if (dev_priv->opregion.asle) + schedule_work(&dev_priv->opregion.asle_work); } #define ASLE_ALS_EN (1<<0) @@ -203,14 +211,14 @@ void psb_intel_opregion_asle_intr(struct drm_device *dev) void psb_intel_opregion_enable_asle(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct opregion_asle *asle = dev_priv->opregion.asle; if (asle && system_opregion ) { /* Don't do this on Medfield or other non PC like devices, they use the bit for something different altogether */ - psb_enable_pipestat(dev_priv, 0, PIPE_LEGACY_BLC_EVENT_ENABLE); - psb_enable_pipestat(dev_priv, 1, PIPE_LEGACY_BLC_EVENT_ENABLE); + gma_enable_pipestat(dev_priv, 0, PIPE_LEGACY_BLC_EVENT_ENABLE); + gma_enable_pipestat(dev_priv, 1, PIPE_LEGACY_BLC_EVENT_ENABLE); asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN | ASLE_PFMB_EN; @@ -250,7 +258,7 @@ static struct notifier_block psb_intel_opregion_notifier = { void psb_intel_opregion_init(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_intel_opregion *opregion = &dev_priv->opregion; if (!opregion->header) @@ -270,7 +278,7 @@ void psb_intel_opregion_init(struct drm_device *dev) void psb_intel_opregion_fini(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_intel_opregion *opregion = &dev_priv->opregion; if (!opregion->header) @@ -283,6 +291,8 @@ void psb_intel_opregion_fini(struct drm_device *dev) unregister_acpi_notifier(&psb_intel_opregion_notifier); } + cancel_work_sync(&opregion->asle_work); + /* just clear all opregion memory pointers now */ iounmap(opregion->header); opregion->header = NULL; @@ -294,17 +304,21 @@ void psb_intel_opregion_fini(struct drm_device *dev) int psb_intel_opregion_setup(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct pci_dev *pdev = to_pci_dev(dev->dev); struct psb_intel_opregion *opregion = &dev_priv->opregion; u32 opregion_phy, mboxes; void __iomem *base; int err = 0; - pci_read_config_dword(dev->pdev, PCI_ASLS, &opregion_phy); + pci_read_config_dword(pdev, PCI_ASLS, &opregion_phy); if (opregion_phy == 0) { DRM_DEBUG_DRIVER("ACPI Opregion not supported\n"); return -ENOTSUPP; } + + INIT_WORK(&opregion->asle_work, psb_intel_opregion_asle_work); + DRM_DEBUG("OpRegion detected at 0x%8x\n", opregion_phy); base = acpi_os_ioremap(opregion_phy, 8*1024); if (!base) diff --git a/drivers/gpu/drm/gma500/power.c b/drivers/gpu/drm/gma500/power.c index b6b135fcd59c..186af29bea6f 100644 --- a/drivers/gpu/drm/gma500/power.c +++ b/drivers/gpu/drm/gma500/power.c @@ -28,16 +28,15 @@ * Alan Cox <alan@linux.intel.com> */ +#include "gem.h" #include "power.h" #include "psb_drv.h" #include "psb_reg.h" #include "psb_intel_reg.h" +#include "psb_irq.h" #include <linux/mutex.h> #include <linux/pm_runtime.h> -static struct mutex power_mutex; /* Serialize power ops */ -static spinlock_t power_ctrl_lock; /* Serialize power claim */ - /** * gma_power_init - initialise power manager * @dev: our device @@ -46,20 +45,29 @@ static spinlock_t power_ctrl_lock; /* Serialize power claim */ */ void gma_power_init(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); /* 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 (dev_priv->ops->init_pm) dev_priv->ops->init_pm(dev); + + /* + * Runtime pm support is broken atm. So for now unconditionally + * call pm_runtime_get() here and put it again in psb_driver_unload() + * + * To fix this we need to call pm_runtime_get() once for each active + * pipe at boot and then put() / get() for each pipe disable / enable + * so that the device gets runtime suspended when no pipes are active. + * Once this is in place the pm_runtime_get() below should be replaced + * by a pm_runtime_allow() call to undo the pm_runtime_forbid() from + * pci_pm_init(). + */ + pm_runtime_get(dev->dev); + + dev_priv->pm_initialized = true; } /** @@ -70,8 +78,12 @@ void gma_power_init(struct drm_device *dev) */ void gma_power_uninit(struct drm_device *dev) { - pm_runtime_disable(&dev->pdev->dev); - pm_runtime_set_suspended(&dev->pdev->dev); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + + if (!dev_priv->pm_initialized) + return; + + pm_runtime_put_noidle(dev->dev); } /** @@ -82,17 +94,15 @@ void gma_power_uninit(struct drm_device *dev) */ static void gma_suspend_display(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - if (dev_priv->suspended) - return; dev_priv->ops->save_regs(dev); dev_priv->ops->power_down(dev); - dev_priv->display_power = false; } /** * gma_resume_display - resume display side logic + * @pdev: PCI device * * Resume the display hardware restoring state and enabling * as necessary. @@ -100,18 +110,18 @@ static void gma_suspend_display(struct drm_device *dev) static void gma_resume_display(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); /* turn on the display power island */ 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); - psb_gtt_restore(dev); /* Rebuild our GTT mappings */ + /* Rebuild our GTT mappings */ + psb_gtt_resume(dev); + psb_gem_mm_resume(dev); dev_priv->ops->restore_regs(dev); } @@ -124,62 +134,42 @@ static void gma_resume_display(struct pci_dev *pdev) static void gma_suspend_pci(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); int bsm, vbt; - if (dev_priv->suspended) - return; - pci_save_state(pdev); pci_read_config_dword(pdev, 0x5C, &bsm); dev_priv->regs.saveBSM = bsm; pci_read_config_dword(pdev, 0xFC, &vbt); dev_priv->regs.saveVBT = vbt; - pci_read_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, &dev_priv->msi_addr); - pci_read_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, &dev_priv->msi_data); pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); - - dev_priv->suspended = true; } /** * gma_resume_pci - resume helper - * @dev: our PCI device + * @pdev: our PCI device * * Perform the resume processing on our PCI device state - rewrite * register state and re-enable the PCI device */ -static bool gma_resume_pci(struct pci_dev *pdev) +static int gma_resume_pci(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); - struct drm_psb_private *dev_priv = dev->dev_private; - int ret; - - if (!dev_priv->suspended) - return true; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); pci_write_config_dword(pdev, 0x5c, dev_priv->regs.saveBSM); pci_write_config_dword(pdev, 0xFC, dev_priv->regs.saveVBT); - /* 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); - if (ret != 0) - dev_err(&pdev->dev, "pci_enable failed: %d\n", ret); - else - dev_priv->suspended = false; - return !dev_priv->suspended; + return pci_enable_device(pdev); } /** * gma_power_suspend - bus callback for suspend - * @pdev: our PCI device - * @state: suspend type + * @_dev: our device * * Called back by the PCI layer during a suspend of the system. We * perform the necessary shut down steps and save enough state that @@ -187,58 +177,33 @@ static bool gma_resume_pci(struct pci_dev *pdev) */ int gma_power_suspend(struct device *_dev) { - struct pci_dev *pdev = container_of(_dev, struct pci_dev, dev); + struct pci_dev *pdev = to_pci_dev(_dev); struct drm_device *dev = pci_get_drvdata(pdev); - struct drm_psb_private *dev_priv = dev->dev_private; - mutex_lock(&power_mutex); - if (!dev_priv->suspended) { - if (dev_priv->display_count) { - mutex_unlock(&power_mutex); - dev_err(dev->dev, "GPU hardware busy, cannot suspend\n"); - return -EBUSY; - } - psb_irq_uninstall(dev); - gma_suspend_display(dev); - gma_suspend_pci(pdev); - } - mutex_unlock(&power_mutex); + gma_irq_uninstall(dev); + gma_suspend_display(dev); + gma_suspend_pci(pdev); return 0; } /** * gma_power_resume - resume power - * @pdev: PCI device + * @_dev: our device * * Resume the PCI side of the graphics and then the displays */ int gma_power_resume(struct device *_dev) { - struct pci_dev *pdev = container_of(_dev, struct pci_dev, dev); + struct pci_dev *pdev = to_pci_dev(_dev); struct drm_device *dev = pci_get_drvdata(pdev); - mutex_lock(&power_mutex); gma_resume_pci(pdev); gma_resume_display(pdev); - psb_irq_preinstall(dev); - psb_irq_postinstall(dev); - mutex_unlock(&power_mutex); + gma_irq_install(dev); return 0; } /** - * gma_power_is_on - returne true if power is on - * @dev: our DRM device - * - * Returns true if the display island power is on at this moment - */ -bool gma_power_is_on(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - return dev_priv->display_power; -} - -/** * gma_power_begin - begin requiring power * @dev: our DRM device * @force_on: true to force power on @@ -248,34 +213,10 @@ bool gma_power_is_on(struct drm_device *dev) */ 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) - goto out_false; - - /* Ok power up needed */ - ret = gma_resume_pci(dev->pdev); - if (ret == 0) { - psb_irq_preinstall(dev); - 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; + if (force_on) + return pm_runtime_resume_and_get(dev->dev) == 0; + else + return pm_runtime_get_if_in_use(dev->dev) == 1; } /** @@ -287,46 +228,5 @@ out_false: */ 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) -{ - return gma_power_suspend(dev); -} - -int psb_runtime_resume(struct device *dev) -{ - return gma_power_resume(dev); -} - -int psb_runtime_idle(struct device *dev) -{ - struct drm_device *drmdev = pci_get_drvdata(to_pci_dev(dev)); - struct drm_psb_private *dev_priv = drmdev->dev_private; - if (dev_priv->display_count) - return 0; - else - return 1; -} - -int gma_power_thaw(struct device *_dev) -{ - return gma_power_resume(_dev); -} - -int gma_power_freeze(struct device *_dev) -{ - return gma_power_suspend(_dev); -} - -int gma_power_restore(struct device *_dev) -{ - return gma_power_resume(_dev); + pm_runtime_put(dev->dev); } diff --git a/drivers/gpu/drm/gma500/power.h b/drivers/gpu/drm/gma500/power.h index 56d8708bd41c..063328d66652 100644 --- a/drivers/gpu/drm/gma500/power.h +++ b/drivers/gpu/drm/gma500/power.h @@ -31,7 +31,9 @@ #define _PSB_POWERMGMT_H_ #include <linux/pci.h> -#include <drm/drmP.h> + +struct device; +struct drm_device; void gma_power_init(struct drm_device *dev); void gma_power_uninit(struct drm_device *dev); @@ -41,9 +43,6 @@ void gma_power_uninit(struct drm_device *dev); */ int gma_power_suspend(struct device *dev); int gma_power_resume(struct device *dev); -int gma_power_thaw(struct device *dev); -int gma_power_freeze(struct device *dev); -int gma_power_restore(struct device *_dev); /* * These are the functions the driver should use to wrap all hw access @@ -52,19 +51,4 @@ int gma_power_restore(struct device *_dev); bool gma_power_begin(struct drm_device *dev, bool force); void gma_power_end(struct drm_device *dev); -/* - * Use this function to do an instantaneous check for if the hw is on. - * Only use this in cases where you know the mutex is already held such - * as in irq install/uninstall and you need to - * prevent a deadlock situation. Otherwise use gma_power_begin(). - */ -bool gma_power_is_on(struct drm_device *dev); - -/* - * GFX-Runtime PM callbacks - */ -int psb_runtime_suspend(struct device *dev); -int psb_runtime_resume(struct device *dev); -int psb_runtime_idle(struct device *dev); - #endif /*_PSB_POWERMGMT_H_*/ diff --git a/drivers/gpu/drm/gma500/psb_device.c b/drivers/gpu/drm/gma500/psb_device.c index f6f534b4197e..6dece8f0e380 100644 --- a/drivers/gpu/drm/gma500/psb_device.c +++ b/drivers/gpu/drm/gma500/psb_device.c @@ -1,42 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-only /************************************************************************** * 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 <drm/gma_drm.h> +#include <drm/drm_crtc_helper.h> + +#include "gma_device.h" +#include "intel_bios.h" +#include "psb_device.h" #include "psb_drv.h" -#include "psb_reg.h" #include "psb_intel_reg.h" -#include "intel_bios.h" - +#include "psb_reg.h" static int psb_output_init(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); 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 */ @@ -52,21 +38,9 @@ static int psb_output_init(struct drm_device *dev) #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; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); unsigned long core_clock; /* u32 bl_max_freq; */ /* unsigned long value; */ @@ -97,62 +71,12 @@ static int psb_backlight_setup(struct drm_device *dev) 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; + psb_intel_lvds_set_brightness(dev, PSB_MAX_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; - - /* This must occur after the backlight is properly initialised */ - psb_lid_timer_init(dev_priv); - - return 0; -} - -#endif - /* * Provide the Poulsbo specific chip logic and low level methods * for power management @@ -160,7 +84,7 @@ static int psb_backlight_init(struct drm_device *dev) static void psb_init_pm(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); u32 gating = PSB_RSGX32(PSB_CR_CLKGATECTL); gating &= ~3; /* Disable 2D clock gating */ @@ -178,8 +102,10 @@ static void psb_init_pm(struct drm_device *dev) */ static int psb_save_display_registers(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_connector *gma_connector; struct drm_crtc *crtc; + struct drm_connector_list_iter conn_iter; struct drm_connector *connector; struct psb_state *regs = &dev_priv->regs.psb; @@ -197,12 +123,16 @@ static int psb_save_display_registers(struct drm_device *dev) drm_modeset_lock_all(dev); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (drm_helper_crtc_in_use(crtc)) - crtc->funcs->save(crtc); + dev_priv->ops->save_crtc(crtc); } - list_for_each_entry(connector, &dev->mode_config.connector_list, head) - if (connector->funcs->save) - connector->funcs->save(connector); + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + gma_connector = to_gma_connector(connector); + if (gma_connector->save) + gma_connector->save(connector); + } + drm_connector_list_iter_end(&conn_iter); drm_modeset_unlock_all(dev); return 0; @@ -216,8 +146,10 @@ static int psb_save_display_registers(struct drm_device *dev) */ static int psb_restore_display_registers(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_connector *gma_connector; struct drm_crtc *crtc; + struct drm_connector_list_iter conn_iter; struct drm_connector *connector; struct psb_state *regs = &dev_priv->regs.psb; @@ -237,11 +169,15 @@ static int psb_restore_display_registers(struct drm_device *dev) drm_modeset_lock_all(dev); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) if (drm_helper_crtc_in_use(crtc)) - crtc->funcs->restore(crtc); + dev_priv->ops->restore_crtc(crtc); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) - if (connector->funcs->restore) - connector->funcs->restore(connector); + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + gma_connector = to_gma_connector(connector); + if (gma_connector->restore) + gma_connector->restore(connector); + } + drm_connector_list_iter_end(&conn_iter); drm_modeset_unlock_all(dev); return 0; @@ -257,45 +193,6 @@ 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; - break; - default: - dev_priv->core_freq = 0; - } -} - /* Poulsbo */ static const struct psb_offset psb_regmap[2] = { { @@ -350,9 +247,9 @@ static const struct psb_offset psb_regmap[2] = { static int psb_chip_setup(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); dev_priv->regmap = psb_regmap; - psb_get_core_freq(dev); + gma_get_core_freq(dev); gma_intel_setup_gmbus(dev); psb_intel_opregion_init(dev); psb_intel_init_bios(dev); @@ -361,35 +258,35 @@ static int psb_chip_setup(struct drm_device *dev) static void psb_chip_teardown(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; - psb_lid_timer_takedown(dev_priv); gma_intel_teardown_gmbus(dev); } const struct psb_ops psb_chip_ops = { .name = "Poulsbo", - .accel_2d = 1, .pipes = 2, .crtcs = 2, .hdmi_mask = (1 << 0), .lvds_mask = (1 << 1), + .sdvo_mask = (1 << 0), .cursor_needs_phys = 1, .sgx_offset = PSB_SGX_OFFSET, .chip_setup = psb_chip_setup, .chip_teardown = psb_chip_teardown, .crtc_helper = &psb_intel_helper_funcs, - .crtc_funcs = &psb_intel_crtc_funcs, + .clock_funcs = &psb_clock_funcs, .output_init = psb_output_init, -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE - .backlight_init = psb_backlight_init, -#endif + .backlight_init = psb_backlight_setup, + .backlight_set = psb_intel_lvds_set_brightness, + .backlight_name = "psb-bl", .init_pm = psb_init_pm, .save_regs = psb_save_display_registers, .restore_regs = psb_restore_display_registers, + .save_crtc = gma_crtc_save, + .restore_crtc = gma_crtc_restore, .power_down = psb_power_down, .power_up = psb_power_up, }; diff --git a/drivers/gpu/drm/gma500/psb_device.h b/drivers/gpu/drm/gma500/psb_device.h new file mode 100644 index 000000000000..3f11179562c9 --- /dev/null +++ b/drivers/gpu/drm/gma500/psb_device.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright © 2013 Patrik Jakobsson + * Copyright © 2011 Intel Corporation + */ + +#ifndef _PSB_DEVICE_H_ +#define _PSB_DEVICE_H_ + +extern const struct gma_clock_funcs psb_clock_funcs; + +#endif diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index bddea5807442..005ab7f5355f 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -1,93 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0-only /************************************************************************** * Copyright (c) 2007-2011, Intel Corporation. * All Rights Reserved. * Copyright (c) 2008, Tungsten Graphics, Inc. Cedar Park, TX., USA. * 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> -#include <drm/gma_drm.h> -#include "psb_drv.h" -#include "framebuffer.h" -#include "psb_reg.h" -#include "psb_intel_reg.h" -#include "intel_bios.h" -#include "mid_bios.h" -#include <drm/drm_pciids.h> -#include "power.h" +#include <linux/aperture.h> #include <linux/cpu.h> +#include <linux/module.h> #include <linux/notifier.h> -#include <linux/spinlock.h> #include <linux/pm_runtime.h> -#include <acpi/video.h> -#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/delay.h> -static int drm_psb_trap_pagefaults; +#include <asm/set_memory.h> -static int psb_probe(struct pci_dev *pdev, const struct pci_device_id *ent); +#include <acpi/video.h> -MODULE_PARM_DESC(trap_pagefaults, "Error and reset on MMU pagefaults"); -module_param_named(trap_pagefaults, drm_psb_trap_pagefaults, int, 0600); +#include <drm/clients/drm_client_setup.h> +#include <drm/drm.h> +#include <drm/drm_drv.h> +#include <drm/drm_file.h> +#include <drm/drm_ioctl.h> +#include <drm/drm_pciids.h> +#include <drm/drm_print.h> +#include <drm/drm_vblank.h> + +#include "framebuffer.h" +#include "gem.h" +#include "intel_bios.h" +#include "mid_bios.h" +#include "power.h" +#include "psb_drv.h" +#include "psb_intel_reg.h" +#include "psb_irq.h" +#include "psb_reg.h" +static const struct drm_driver driver; +static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); -static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { +/* + * The table below contains a mapping of the PCI vendor ID and the PCI Device ID + * to the different groups of PowerVR 5-series chip designs + * + * 0x8086 = Intel Corporation + * + * PowerVR SGX535 - Poulsbo - Intel GMA 500, Intel Atom Z5xx + * PowerVR SGX535 - Moorestown - Intel GMA 600 + * PowerVR SGX535 - Oaktrail - Intel GMA 600, Intel Atom Z6xx, E6xx + * PowerVR SGX545 - Cedartrail - Intel GMA 3600, Intel Atom D2500, N2600 + * PowerVR SGX545 - Cedartrail - Intel GMA 3650, Intel Atom D2550, D2700, + * N2800 + */ +static const struct pci_device_id pciidlist[] = { + /* Poulsbo */ { 0x8086, 0x8108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &psb_chip_ops }, { 0x8086, 0x8109, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &psb_chip_ops }, -#if defined(CONFIG_DRM_GMA600) - { 0x8086, 0x4100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4103, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4107, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - /* Atom E620 */ - { 0x8086, 0x4108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, -#endif -#if defined(CONFIG_DRM_MEDFIELD) - {0x8086, 0x0130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0133, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0134, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0135, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, -#endif -#if defined(CONFIG_DRM_GMA3600) - { 0x8086, 0x0be0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0be1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 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}, - { 0x8086, 0x0be8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0be9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0bea, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0beb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0bec, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0bed, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0bee, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0bef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, -#endif + /* Oak Trail */ + { 0x8086, 0x4100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4103, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4107, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + /* Cedar Trail */ + { 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 }, + { 0x8086, 0x0be8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0be9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0bea, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0beb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0bec, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0bed, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0bee, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0bef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, { 0, } }; MODULE_DEVICE_TABLE(pci, pciidlist); @@ -95,196 +92,167 @@ MODULE_DEVICE_TABLE(pci, pciidlist); /* * Standard IOCTLs. */ - -#define DRM_IOCTL_GMA_ADB \ - DRM_IOWR(DRM_GMA_ADB + DRM_COMMAND_BASE, uint32_t) -#define DRM_IOCTL_GMA_MODE_OPERATION \ - DRM_IOWR(DRM_GMA_MODE_OPERATION + DRM_COMMAND_BASE, \ - struct drm_psb_mode_operation_arg) -#define DRM_IOCTL_GMA_STOLEN_MEMORY \ - DRM_IOWR(DRM_GMA_STOLEN_MEMORY + DRM_COMMAND_BASE, \ - struct drm_psb_stolen_memory_arg) -#define DRM_IOCTL_GMA_GAMMA \ - DRM_IOWR(DRM_GMA_GAMMA + DRM_COMMAND_BASE, \ - struct drm_psb_dpst_lut_arg) -#define DRM_IOCTL_GMA_DPST_BL \ - DRM_IOWR(DRM_GMA_DPST_BL + DRM_COMMAND_BASE, \ - uint32_t) -#define DRM_IOCTL_GMA_GET_PIPE_FROM_CRTC_ID \ - DRM_IOWR(DRM_GMA_GET_PIPE_FROM_CRTC_ID + DRM_COMMAND_BASE, \ - struct drm_psb_get_pipe_from_crtc_id_arg) -#define DRM_IOCTL_GMA_GEM_CREATE \ - DRM_IOWR(DRM_GMA_GEM_CREATE + DRM_COMMAND_BASE, \ - struct drm_psb_gem_create) -#define DRM_IOCTL_GMA_GEM_MMAP \ - DRM_IOWR(DRM_GMA_GEM_MMAP + DRM_COMMAND_BASE, \ - struct drm_psb_gem_mmap) - -static int psb_adb_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -static int psb_mode_operation_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -static int psb_stolen_memory_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -static int psb_gamma_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -static int psb_dpst_bl_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); - -static struct drm_ioctl_desc psb_ioctls[] = { - DRM_IOCTL_DEF_DRV(GMA_ADB, psb_adb_ioctl, DRM_AUTH), - DRM_IOCTL_DEF_DRV(GMA_MODE_OPERATION, psb_mode_operation_ioctl, - DRM_AUTH), - DRM_IOCTL_DEF_DRV(GMA_STOLEN_MEMORY, psb_stolen_memory_ioctl, - DRM_AUTH), - DRM_IOCTL_DEF_DRV(GMA_GAMMA, psb_gamma_ioctl, DRM_AUTH), - DRM_IOCTL_DEF_DRV(GMA_DPST_BL, psb_dpst_bl_ioctl, DRM_AUTH), - DRM_IOCTL_DEF_DRV(GMA_GET_PIPE_FROM_CRTC_ID, - psb_intel_get_pipe_from_crtc_id, 0), - DRM_IOCTL_DEF_DRV(GMA_GEM_CREATE, psb_gem_create_ioctl, - DRM_UNLOCKED | DRM_AUTH), - DRM_IOCTL_DEF_DRV(GMA_GEM_MMAP, psb_gem_mmap_ioctl, - DRM_UNLOCKED | DRM_AUTH), +static const struct drm_ioctl_desc psb_ioctls[] = { }; -static void psb_lastclose(struct drm_device *dev) +/** + * psb_spank - reset the 2D engine + * @dev_priv: our PSB DRM device + * + * Soft reset the graphics engine and then reload the necessary registers. + */ +static void psb_spank(struct drm_psb_private *dev_priv) { - int ret; - struct drm_psb_private *dev_priv = dev->dev_private; - struct psb_fbdev *fbdev = dev_priv->fbdev; - - drm_modeset_lock_all(dev); - ret = drm_fb_helper_restore_fbdev_mode(&fbdev->psb_fb_helper); - if (ret) - DRM_DEBUG("failed to restore crtc mode\n"); - drm_modeset_unlock_all(dev); - - return; + 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); + PSB_RSGX32(PSB_CR_SOFT_RESET); + + msleep(1); + + PSB_WSGX32(0, PSB_CR_SOFT_RESET); + wmb(); + PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) | _PSB_CB_CTRL_CLEAR_FAULT, + PSB_CR_BIF_CTRL); + wmb(); + (void) PSB_RSGX32(PSB_CR_BIF_CTRL); + + msleep(1); + 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->gtt.gatt_start, PSB_CR_BIF_TWOD_REQ_BASE); } static int psb_do_init(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_gtt *pg = &dev_priv->gtt; uint32_t stolen_gtt; - int ret = -ENOMEM; - if (pg->mmu_gatt_start & 0x0FFFFFFF) { dev_err(dev->dev, "Gatt must be 256M aligned. This is a bug.\n"); - ret = -EINVAL; - goto out_err; + return -EINVAL; } - stolen_gtt = (pg->stolen_size >> PAGE_SHIFT) * 4; stolen_gtt = (stolen_gtt + PAGE_SIZE - 1) >> PAGE_SHIFT; - stolen_gtt = - (stolen_gtt < pg->gtt_pages) ? stolen_gtt : pg->gtt_pages; + stolen_gtt = (stolen_gtt < pg->gtt_pages) ? stolen_gtt : pg->gtt_pages; dev_priv->gatt_free_offset = pg->mmu_gatt_start + (stolen_gtt << PAGE_SHIFT) * 1024; spin_lock_init(&dev_priv->irqmask_lock); - spin_lock_init(&dev_priv->lock_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_CR_BIF_CTRL); + + /* Do not bypass any MMU access, let them pagefault instead */ + PSB_WSGX32((PSB_RSGX32(PSB_CR_BIF_CTRL) & ~_PSB_MMU_ER_MASK), + PSB_CR_BIF_CTRL); + PSB_RSGX32(PSB_CR_BIF_CTRL); + psb_spank(dev_priv); /* mmu_gatt ?? */ PSB_WSGX32(pg->gatt_start, PSB_CR_BIF_TWOD_REQ_BASE); + PSB_RSGX32(PSB_CR_BIF_TWOD_REQ_BASE); /* Post */ + return 0; -out_err: - return ret; } -static int psb_driver_unload(struct drm_device *dev) +static void psb_driver_unload(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - /* Kill vblank etc here */ + /* TODO: Kill vblank etc here */ + gma_backlight_exit(dev); + psb_modeset_cleanup(dev); - if (dev_priv) { - if (dev_priv->backlight_device) - gma_backlight_exit(dev); - psb_modeset_cleanup(dev); + gma_irq_uninstall(dev); - if (dev_priv->ops->chip_teardown) - dev_priv->ops->chip_teardown(dev); + if (dev_priv->ops->chip_teardown) + dev_priv->ops->chip_teardown(dev); - psb_intel_opregion_fini(dev); + psb_intel_opregion_fini(dev); - if (dev_priv->pf_pd) { - psb_mmu_free_pagedir(dev_priv->pf_pd); - dev_priv->pf_pd = NULL; - } - if (dev_priv->mmu) { - struct psb_gtt *pg = &dev_priv->gtt; - - down_read(&pg->sem); - psb_mmu_remove_pfn_sequence( - psb_mmu_get_default_pd - (dev_priv->mmu), - pg->mmu_gatt_start, - dev_priv->vram_stolen_size >> PAGE_SHIFT); - up_read(&pg->sem); - psb_mmu_driver_takedown(dev_priv->mmu); - dev_priv->mmu = NULL; - } - psb_gtt_takedown(dev); - if (dev_priv->scratch_page) { - set_pages_wb(dev_priv->scratch_page, 1); - __free_page(dev_priv->scratch_page); - dev_priv->scratch_page = NULL; - } - if (dev_priv->vdc_reg) { - iounmap(dev_priv->vdc_reg); - dev_priv->vdc_reg = NULL; - } - if (dev_priv->sgx_reg) { - iounmap(dev_priv->sgx_reg); - dev_priv->sgx_reg = NULL; - } + if (dev_priv->pf_pd) { + psb_mmu_free_pagedir(dev_priv->pf_pd); + dev_priv->pf_pd = NULL; + } + if (dev_priv->mmu) { + struct psb_gtt *pg = &dev_priv->gtt; + + psb_mmu_remove_pfn_sequence( + psb_mmu_get_default_pd + (dev_priv->mmu), + pg->mmu_gatt_start, + dev_priv->vram_stolen_size >> PAGE_SHIFT); + psb_mmu_driver_takedown(dev_priv->mmu); + dev_priv->mmu = NULL; + } + psb_gem_mm_fini(dev); + psb_gtt_fini(dev); + if (dev_priv->scratch_page) { + set_pages_wb(dev_priv->scratch_page, 1); + __free_page(dev_priv->scratch_page); + dev_priv->scratch_page = NULL; + } + if (dev_priv->vdc_reg) { + iounmap(dev_priv->vdc_reg); + dev_priv->vdc_reg = NULL; + } + if (dev_priv->sgx_reg) { + iounmap(dev_priv->sgx_reg); + dev_priv->sgx_reg = NULL; + } + if (dev_priv->aux_reg) { + iounmap(dev_priv->aux_reg); + dev_priv->aux_reg = NULL; + } + pci_dev_put(dev_priv->aux_pdev); + pci_dev_put(dev_priv->lpc_pdev); - /* Destroy VBT data */ - psb_intel_destroy_bios(dev); + /* Destroy VBT data */ + psb_intel_destroy_bios(dev); - kfree(dev_priv); - dev->dev_private = NULL; - } gma_power_uninit(dev); - return 0; } +static void psb_device_release(void *data) +{ + struct drm_device *dev = data; + + psb_driver_unload(dev); +} -static int psb_driver_load(struct drm_device *dev, unsigned long chipset) +static int psb_driver_load(struct drm_device *dev, unsigned long flags) { - struct drm_psb_private *dev_priv; - unsigned long resource_start; + struct pci_dev *pdev = to_pci_dev(dev->dev); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + unsigned long resource_start, resource_len; unsigned long irqflags; - int ret = -ENOMEM; + struct drm_connector_list_iter conn_iter; struct drm_connector *connector; - struct psb_intel_encoder *psb_intel_encoder; + struct gma_encoder *gma_encoder; + struct psb_gtt *pg; + int ret = -ENOMEM; - dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); - if (dev_priv == NULL) - return -ENOMEM; + /* initializing driver private data */ - dev_priv->ops = (struct psb_ops *)chipset; - dev_priv->dev = dev; - dev->dev_private = (void *) dev_priv; + dev_priv->ops = (struct psb_ops *)flags; - pci_set_master(dev->pdev); + pg = &dev_priv->gtt; + + pci_set_master(pdev); dev_priv->num_pipe = dev_priv->ops->pipes; - resource_start = pci_resource_start(dev->pdev, PSB_MMIO_RESOURCE); + resource_start = pci_resource_start(pdev, PSB_MMIO_RESOURCE); dev_priv->vdc_reg = ioremap(resource_start + PSB_VDC_OFFSET, PSB_VDC_SIZE); @@ -296,6 +264,54 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) if (!dev_priv->sgx_reg) goto out_err; + if (IS_MRST(dev)) { + int domain = pci_domain_nr(pdev->bus); + + dev_priv->aux_pdev = + pci_get_domain_bus_and_slot(domain, 0, + PCI_DEVFN(3, 0)); + + if (dev_priv->aux_pdev) { + resource_start = pci_resource_start(dev_priv->aux_pdev, + PSB_AUX_RESOURCE); + resource_len = pci_resource_len(dev_priv->aux_pdev, + PSB_AUX_RESOURCE); + dev_priv->aux_reg = ioremap(resource_start, + resource_len); + if (!dev_priv->aux_reg) + goto out_err; + + DRM_DEBUG_KMS("Found aux vdc"); + } else { + /* Couldn't find the aux vdc so map to primary vdc */ + dev_priv->aux_reg = dev_priv->vdc_reg; + DRM_DEBUG_KMS("Couldn't find aux pci device"); + } + dev_priv->gmbus_reg = dev_priv->aux_reg; + + dev_priv->lpc_pdev = + pci_get_domain_bus_and_slot(domain, 0, + PCI_DEVFN(31, 0)); + if (dev_priv->lpc_pdev) { + pci_read_config_word(dev_priv->lpc_pdev, PSB_LPC_GBA, + &dev_priv->lpc_gpio_base); + pci_write_config_dword(dev_priv->lpc_pdev, PSB_LPC_GBA, + (u32)dev_priv->lpc_gpio_base | (1L<<31)); + pci_read_config_word(dev_priv->lpc_pdev, PSB_LPC_GBA, + &dev_priv->lpc_gpio_base); + dev_priv->lpc_gpio_base &= 0xffc0; + if (dev_priv->lpc_gpio_base) + DRM_DEBUG_KMS("Found LPC GPIO at 0x%04x\n", + dev_priv->lpc_gpio_base); + else { + pci_dev_put(dev_priv->lpc_pdev); + dev_priv->lpc_pdev = NULL; + } + } + } else { + dev_priv->gmbus_reg = dev_priv->vdc_reg; + } + psb_intel_opregion_setup(dev); ret = dev_priv->ops->chip_setup(dev); @@ -313,13 +329,16 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) set_pages_uc(dev_priv->scratch_page, 1); - ret = psb_gtt_init(dev, 0); + ret = psb_gtt_init(dev); + if (ret) + goto out_err; + ret = psb_gem_mm_init(dev); if (ret) goto out_err; - dev_priv->mmu = psb_mmu_driver_init((void *)0, - drm_psb_trap_pagefaults, 0, - dev_priv); + ret = -ENOMEM; + + dev_priv->mmu = psb_mmu_driver_init(dev, 1, 0, NULL); if (!dev_priv->mmu) goto out_err; @@ -327,18 +346,25 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) if (!dev_priv->pf_pd) goto out_err; - psb_mmu_set_pd_context(psb_mmu_get_default_pd(dev_priv->mmu), 0); - psb_mmu_set_pd_context(dev_priv->pf_pd, 1); - ret = psb_do_init(dev); if (ret) return ret; + /* Add stolen memory to SGX MMU */ + ret = psb_mmu_insert_pfn_sequence(psb_mmu_get_default_pd(dev_priv->mmu), + dev_priv->stolen_base >> PAGE_SHIFT, + pg->gatt_start, + pg->stolen_size >> PAGE_SHIFT, 0); + + psb_mmu_set_pd_context(psb_mmu_get_default_pd(dev_priv->mmu), 0); + psb_mmu_set_pd_context(dev_priv->pf_pd, 1); + PSB_WSGX32(0x20000000, PSB_CR_PDS_EXEC_BASE); PSB_WSGX32(0x30000000, PSB_CR_BIF_3D_REQ_BASE); acpi_video_register(); + /* Setup vertical blanking handling */ ret = drm_vblank_init(dev, dev_priv->num_pipe); if (ret) goto out_err; @@ -357,339 +383,166 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) PSB_WVDC32(0xFFFFFFFF, PSB_INT_MASK_R); spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); - drm_irq_install(dev); - - dev->vblank_disable_allowed = 1; + gma_irq_install(dev); dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ - dev->driver->get_vblank_counter = psb_get_vblank_counter; - psb_modeset_init(dev); - psb_fbdev_init(dev); drm_kms_helper_poll_init(dev); - /* Only add backlight support if we have LVDS output */ - list_for_each_entry(connector, &dev->mode_config.connector_list, - head) { - psb_intel_encoder = psb_intel_attached_encoder(connector); + /* Only add backlight support if we have LVDS or MIPI output */ + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + gma_encoder = gma_attached_encoder(connector); - switch (psb_intel_encoder->type) { - case INTEL_OUTPUT_LVDS: - case INTEL_OUTPUT_MIPI: + if (gma_encoder->type == INTEL_OUTPUT_LVDS || + gma_encoder->type == INTEL_OUTPUT_MIPI) { ret = gma_backlight_init(dev); + if (ret == 0) + acpi_video_register_backlight(); break; } } + drm_connector_list_iter_end(&conn_iter); if (ret) return ret; psb_intel_opregion_enable_asle(dev); -#if 0 - /*enable runtime pm at last*/ - pm_runtime_enable(&dev->pdev->dev); - pm_runtime_set_active(&dev->pdev->dev); -#endif - /*Intel drm driver load is done, continue doing pvr load*/ - return 0; + + return devm_add_action_or_reset(dev->dev, psb_device_release, dev); + out_err: psb_driver_unload(dev); return ret; } -static int psb_driver_device_is_agp(struct drm_device *dev) -{ - return 0; -} - -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; - - dev_priv->blc_adj2 = *arg; - get_brightness(dev_priv->backlight_device); - return 0; -} - -static int psb_adb_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; - - dev_priv->blc_adj1 = *arg; - get_brightness(dev_priv->backlight_device); - return 0; -} - -static int psb_gamma_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +/* + * Hardware for gma500 is a hybrid device, which both acts as a PCI + * device (for legacy vga functionality) but also more like an + * integrated display on a SoC where the framebuffer simply + * resides in main memory and not in a special PCI bar (that + * internally redirects to a stolen range of main memory) like all + * other integrated PCI display devices implement it. + * + * To catch all cases we need to remove conflicting firmware devices + * for the stolen system memory and for the VGA functionality. As we + * currently cannot easily find the framebuffer's location in stolen + * memory, we remove all framebuffers here. + * + * TODO: Refactor psb_driver_load() to map vdc_reg earlier. Then + * we might be able to read the framebuffer range from the + * device. + */ +static int gma_remove_conflicting_framebuffers(struct pci_dev *pdev, + const struct drm_driver *req_driver) { - struct drm_psb_dpst_lut_arg *lut_arg = data; - struct drm_mode_object *obj; - struct drm_crtc *crtc; - struct drm_connector *connector; - struct psb_intel_crtc *psb_intel_crtc; - int i = 0; - int32_t obj_id; - - obj_id = lut_arg->output_id; - obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_CONNECTOR); - if (!obj) { - dev_dbg(dev->dev, "Invalid Connector object.\n"); - return -EINVAL; - } - - connector = obj_to_connector(obj); - crtc = connector->encoder->crtc; - psb_intel_crtc = to_psb_intel_crtc(crtc); - - for (i = 0; i < 256; i++) - psb_intel_crtc->lut_adj[i] = lut_arg->lut[i]; + resource_size_t base = 0; + resource_size_t size = U32_MAX; /* 4 GiB HW limit */ + const char *name = req_driver->name; + int ret; - psb_intel_crtc_load_lut(crtc); + ret = aperture_remove_conflicting_devices(base, size, name); + if (ret) + return ret; - return 0; + return __aperture_remove_legacy_vga_devices(pdev); } -static int psb_mode_operation_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - uint32_t obj_id; - uint16_t op; - struct drm_mode_modeinfo *umode; - struct drm_display_mode *mode = NULL; - struct drm_psb_mode_operation_arg *arg; - struct drm_mode_object *obj; - struct drm_connector *connector; - struct drm_connector_helper_funcs *connector_funcs; - int ret = 0; - int resp = MODE_OK; - - arg = (struct drm_psb_mode_operation_arg *)data; - obj_id = arg->obj_id; - op = arg->operation; - - switch (op) { - case PSB_MODE_OPERATION_MODE_VALID: - umode = &arg->mode; - - drm_modeset_lock_all(dev); - - obj = drm_mode_object_find(dev, obj_id, - DRM_MODE_OBJECT_CONNECTOR); - if (!obj) { - ret = -EINVAL; - goto mode_op_out; - } - - connector = obj_to_connector(obj); - - mode = drm_mode_create(dev); - if (!mode) { - ret = -ENOMEM; - goto mode_op_out; - } - - /* drm_crtc_convert_umode(mode, umode); */ - { - mode->clock = umode->clock; - mode->hdisplay = umode->hdisplay; - mode->hsync_start = umode->hsync_start; - mode->hsync_end = umode->hsync_end; - mode->htotal = umode->htotal; - mode->hskew = umode->hskew; - mode->vdisplay = umode->vdisplay; - mode->vsync_start = umode->vsync_start; - mode->vsync_end = umode->vsync_end; - mode->vtotal = umode->vtotal; - mode->vscan = umode->vscan; - mode->vrefresh = umode->vrefresh; - mode->flags = umode->flags; - mode->type = umode->type; - strncpy(mode->name, umode->name, DRM_DISPLAY_MODE_LEN); - mode->name[DRM_DISPLAY_MODE_LEN-1] = 0; - } - - connector_funcs = (struct drm_connector_helper_funcs *) - connector->helper_private; + struct drm_psb_private *dev_priv; + struct drm_device *dev; + int ret; - if (connector_funcs->mode_valid) { - resp = connector_funcs->mode_valid(connector, mode); - arg->data = resp; - } + ret = gma_remove_conflicting_framebuffers(pdev, &driver); + if (ret) + return ret; - /*do some clean up work*/ - if (mode) - drm_mode_destroy(dev, mode); -mode_op_out: - drm_modeset_unlock_all(dev); + ret = pcim_enable_device(pdev); + if (ret) return ret; - default: - dev_dbg(dev->dev, "Unsupported psb mode operation\n"); - return -EOPNOTSUPP; - } + dev_priv = devm_drm_dev_alloc(&pdev->dev, &driver, struct drm_psb_private, dev); + if (IS_ERR(dev_priv)) + return PTR_ERR(dev_priv); + dev = &dev_priv->dev; - return 0; -} + pci_set_drvdata(pdev, dev); -static int psb_stolen_memory_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_psb_private *dev_priv = psb_priv(dev); - struct drm_psb_stolen_memory_arg *arg = data; + ret = psb_driver_load(dev, ent->driver_data); + if (ret) + return ret; - arg->base = dev_priv->stolen_base; - arg->size = dev_priv->vram_stolen_size; + ret = drm_dev_register(dev, ent->driver_data); + if (ret) + return ret; - return 0; -} + drm_client_setup(dev, NULL); -static int psb_driver_open(struct drm_device *dev, struct drm_file *priv) -{ return 0; } -static void psb_driver_close(struct drm_device *dev, struct drm_file *priv) -{ -} - -static long psb_unlocked_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - struct drm_file *file_priv = filp->private_data; - struct drm_device *dev = file_priv->minor->dev; - struct drm_psb_private *dev_priv = dev->dev_private; - static unsigned int runtime_allowed; - - if (runtime_allowed == 1 && dev_priv->is_lvds_on) { - runtime_allowed++; - pm_runtime_allow(&dev->pdev->dev); - dev_priv->rpm_enabled = 1; - } - return drm_ioctl(filp, cmd, arg); - /* FIXME: do we need to wrap the other side of this */ -} - - -/* When a client dies: - * - Check for and clean up flipped page state - */ -static void psb_driver_preclose(struct drm_device *dev, struct drm_file *priv) -{ -} - -static void psb_remove(struct pci_dev *pdev) +static void psb_pci_remove(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); - drm_put_dev(dev); -} -static const struct dev_pm_ops psb_pm_ops = { - .resume = gma_power_resume, - .suspend = gma_power_suspend, - .thaw = gma_power_thaw, - .freeze = gma_power_freeze, - .restore = gma_power_restore, - .runtime_suspend = psb_runtime_suspend, - .runtime_resume = psb_runtime_resume, - .runtime_idle = psb_runtime_idle, -}; + drm_dev_unregister(dev); +} -static const struct vm_operations_struct psb_gem_vm_ops = { - .fault = psb_gem_fault, - .open = drm_gem_vm_open, - .close = drm_gem_vm_close, -}; +static DEFINE_RUNTIME_DEV_PM_OPS(psb_pm_ops, gma_power_suspend, gma_power_resume, NULL); static const struct file_operations psb_gem_fops = { .owner = THIS_MODULE, .open = drm_open, .release = drm_release, - .unlocked_ioctl = psb_unlocked_ioctl, + .unlocked_ioctl = drm_ioctl, + .compat_ioctl = drm_compat_ioctl, .mmap = drm_gem_mmap, .poll = drm_poll, - .fasync = drm_fasync, .read = drm_read, + .fop_flags = FOP_UNSIGNED_OFFSET, }; -static struct drm_driver driver = { - .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | \ - DRIVER_IRQ_VBL | DRIVER_MODESET | DRIVER_GEM , - .load = psb_driver_load, - .unload = psb_driver_unload, +static const struct drm_driver driver = { + .driver_features = DRIVER_MODESET | DRIVER_GEM, + + .num_ioctls = ARRAY_SIZE(psb_ioctls), - .ioctls = psb_ioctls, - .num_ioctls = DRM_ARRAY_SIZE(psb_ioctls), - .device_is_agp = psb_driver_device_is_agp, - .irq_preinstall = psb_irq_preinstall, - .irq_postinstall = psb_irq_postinstall, - .irq_uninstall = psb_irq_uninstall, - .irq_handler = psb_irq_handler, - .enable_vblank = psb_enable_vblank, - .disable_vblank = psb_disable_vblank, - .get_vblank_counter = psb_get_vblank_counter, - .lastclose = psb_lastclose, - .open = psb_driver_open, - .preclose = psb_driver_preclose, - .postclose = psb_driver_close, - - .gem_init_object = psb_gem_init_object, - .gem_free_object = psb_gem_free_object, - .gem_vm_ops = &psb_gem_vm_ops, .dumb_create = psb_gem_dumb_create, - .dumb_map_offset = psb_gem_dumb_map_gtt, - .dumb_destroy = psb_gem_dumb_destroy, + PSB_FBDEV_DRIVER_OPS, + .ioctls = psb_ioctls, .fops = &psb_gem_fops, .name = DRIVER_NAME, .desc = DRIVER_DESC, - .date = PSB_DRM_DRIVER_DATE, - .major = PSB_DRM_DRIVER_MAJOR, - .minor = PSB_DRM_DRIVER_MINOR, - .patchlevel = PSB_DRM_DRIVER_PATCHLEVEL + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL }; static struct pci_driver psb_pci_driver = { .name = DRIVER_NAME, .id_table = pciidlist, - .probe = psb_probe, - .remove = psb_remove, - .driver = { - .pm = &psb_pm_ops, - } + .probe = psb_pci_probe, + .remove = psb_pci_remove, + .driver.pm = &psb_pm_ops, }; -static int psb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - return drm_get_pci_dev(pdev, ent, &driver); -} - static int __init psb_init(void) { - return drm_pci_init(&driver, &psb_pci_driver); + if (drm_firmware_drivers_only()) + return -ENODEV; + + return pci_register_driver(&psb_pci_driver); } static void __exit psb_exit(void) { - drm_pci_exit(&driver, &psb_pci_driver); + pci_unregister_driver(&psb_pci_driver); } late_initcall(psb_init); module_exit(psb_exit); -MODULE_AUTHOR("Alan Cox <alan@linux.intel.com> and others"); +MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index 6053b8abcd12..0b27112ec46f 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -1,121 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /************************************************************************** * Copyright (c) 2007-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. - * **************************************************************************/ #ifndef _PSB_DRV_H_ #define _PSB_DRV_H_ #include <linux/kref.h> +#include <linux/mm_types.h> + +#include <drm/drm_device.h> -#include <drm/drmP.h> -#include <drm/drm_global.h> -#include <drm/gma_drm.h> -#include "psb_reg.h" -#include "psb_intel_drv.h" -#include "intel_bios.h" #include "gtt.h" -#include "power.h" -#include "opregion.h" +#include "intel_bios.h" +#include "mmu.h" #include "oaktrail.h" +#include "opregion.h" +#include "power.h" +#include "psb_intel_drv.h" +#include "psb_reg.h" -/* Append new drm mode definition here, align with libdrm definition */ -#define DRM_MODE_SCALE_NO_SCALE 2 - -enum { - CHIP_PSB_8108 = 0, /* Poulsbo */ - CHIP_PSB_8109 = 1, /* Poulsbo */ - CHIP_MRST_4100 = 2, /* Moorestown/Oaktrail */ - CHIP_MFLD_0130 = 3, /* Medfield */ -}; +#define DRIVER_AUTHOR "Alan Cox <alan@linux.intel.com> and others" -#define IS_PSB(dev) (((dev)->pci_device & 0xfffe) == 0x8108) -#define IS_MRST(dev) (((dev)->pci_device & 0xfffc) == 0x4100) -#define IS_MFLD(dev) (((dev)->pci_device & 0xfff8) == 0x0130) +#define DRIVER_NAME "gma500" +#define DRIVER_DESC "DRM driver for the Intel GMA500, GMA600, GMA3600, GMA3650" -/* - * Driver definitions - */ +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 +#define DRIVER_PATCHLEVEL 0 -#define DRIVER_NAME "gma500" -#define DRIVER_DESC "DRM driver for the Intel GMA500" +/* Append new drm mode definition here, align with libdrm definition */ +#define DRM_MODE_SCALE_NO_SCALE 2 -#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 +#define IS_PSB(drm) ((to_pci_dev((drm)->dev)->device & 0xfffe) == 0x8108) +#define IS_MRST(drm) ((to_pci_dev((drm)->dev)->device & 0xfff0) == 0x4100) +#define IS_CDV(drm) ((to_pci_dev((drm)->dev)->device & 0xfff0) == 0x0be0) -/* - * Hardware offsets - */ +/* Hardware offsets */ #define PSB_VDC_OFFSET 0x00000000 #define PSB_VDC_SIZE 0x000080000 #define MRST_MMIO_SIZE 0x0000C0000 -#define MDFLD_MMIO_SIZE 0x000100000 #define PSB_SGX_SIZE 0x8000 #define PSB_SGX_OFFSET 0x00040000 #define MRST_SGX_OFFSET 0x00080000 -/* - * PCI resource identifiers - */ + +/* PCI resource identifiers */ #define PSB_MMIO_RESOURCE 0 +#define PSB_AUX_RESOURCE 0 #define PSB_GATT_RESOURCE 2 #define PSB_GTT_RESOURCE 3 -/* - * PCI configuration - */ + +/* 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 +#define PSB_LPC_GBA 0x44 -/* To get rid of */ +/* TODO: To get rid of */ #define PSB_TT_PRIV0_LIMIT (256*1024*1024) #define PSB_TT_PRIV0_PLIMIT (PSB_TT_PRIV0_LIMIT >> PAGE_SHIFT) -/* - * SGX side MMU definitions (these can probably go) - */ +/* SGX side MMU definitions (these can probably go) */ -/* - * Flags for external memory type field. - */ +/* 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 - */ + +/* 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 #define PSB_HWSTAM 0x2098 @@ -130,8 +98,6 @@ enum { #define _PSB_DPST_PIPEA_FLAG (1<<6) #define _PSB_PIPEA_EVENT_FLAG (1<<6) #define _PSB_VSYNC_PIPEA_FLAG (1<<7) -#define _MDFLD_MIPIA_FLAG (1<<16) -#define _MDFLD_MIPIC_FLAG (1<<17) #define _PSB_IRQ_DISP_HOTSYNC (1<<17) #define _PSB_IRQ_SGX_FLAG (1<<18) #define _PSB_IRQ_MSVDX_FLAG (1<<19) @@ -140,13 +106,6 @@ enum { #define _PSB_PIPE_EVENT_FLAG (_PSB_VSYNC_PIPEA_FLAG | \ _PSB_VSYNC_PIPEB_FLAG) -/* This flag includes all the display IRQ bits excepts the vblank irqs. */ -#define _MDFLD_DISP_ALL_IRQ_FLAG (_MDFLD_PIPEC_EVENT_FLAG | \ - _MDFLD_PIPEB_EVENT_FLAG | \ - _PSB_PIPEA_EVENT_FLAG | \ - _PSB_VSYNC_PIPEA_FLAG | \ - _MDFLD_MIPIA_FLAG | \ - _MDFLD_MIPIC_FLAG) #define PSB_INT_IDENTITY_R 0x20A4 #define PSB_INT_MASK_R 0x20A8 #define PSB_INT_ENABLE_R 0x20A0 @@ -201,35 +160,9 @@ enum { #define PSB_NUM_VBLANKS 2 +#define PSB_WATCHDOG_DELAY (HZ * 2) -#define PSB_2D_SIZE (256*1024*1024) -#define PSB_MAX_RELOC_PAGES 1024 - -#define PSB_LOW_REG_OFFS 0x0204 -#define PSB_HIGH_REG_OFFS 0x0600 - -#define PSB_NUM_VBLANKS 2 -#define PSB_WATCHDOG_DELAY (DRM_HZ * 2) -#define PSB_LID_DELAY (DRM_HZ / 10) - -#define MDFLD_PNW_B0 0x04 -#define MDFLD_PNW_C0 0x08 - -#define MDFLD_DSR_2D_3D_0 (1 << 0) -#define MDFLD_DSR_2D_3D_2 (1 << 1) -#define MDFLD_DSR_CURSOR_0 (1 << 2) -#define MDFLD_DSR_CURSOR_2 (1 << 3) -#define MDFLD_DSR_OVERLAY_0 (1 << 4) -#define MDFLD_DSR_OVERLAY_2 (1 << 5) -#define MDFLD_DSR_MIPI_CONTROL (1 << 6) -#define MDFLD_DSR_DAMAGE_MASK_0 ((1 << 0) | (1 << 2) | (1 << 4)) -#define MDFLD_DSR_DAMAGE_MASK_2 ((1 << 1) | (1 << 3) | (1 << 5)) -#define MDFLD_DSR_2D_3D (MDFLD_DSR_2D_3D_0 | MDFLD_DSR_2D_3D_2) - -#define MDFLD_DSR_RR 45 -#define MDFLD_DPU_ENABLE (1 << 31) -#define MDFLD_DSR_FULLSCREEN (1 << 30) -#define MDFLD_DSR_DELAY (DRM_HZ / MDFLD_DSR_RR) +#define PSB_MAX_BRIGHTNESS 100 #define PSB_PWR_STATE_ON 1 #define PSB_PWR_STATE_OFF 2 @@ -250,6 +183,9 @@ enum { #define KSEL_BYPASS_25 6 #define KSEL_BYPASS_83_100 7 +struct drm_fb_helper; +struct drm_fb_helper_surface_size; + struct opregion_header; struct opregion_acpi; struct opregion_swsci; @@ -262,12 +198,13 @@ struct psb_intel_opregion { struct opregion_asle *asle; void *vbt; u32 __iomem *lid_state; + struct work_struct asle_work; }; struct sdvo_device_mapping { u8 initialized; u8 dvo_port; - u8 slave_addr; + u8 target_addr; u8 dvo_wiring; u8 i2c_pin; u8 i2c_speed; @@ -280,10 +217,7 @@ struct intel_gmbus { u32 reg0; }; -/* - * Register offset maps - */ - +/* Register offset maps */ struct psb_offset { u32 fp0; u32 fp1; @@ -317,9 +251,7 @@ struct psb_offset { * update the register cache instead. */ -/* - * Common status for pipes. - */ +/* Common status for pipes */ struct psb_pipe { u32 fp0; u32 fp1; @@ -405,16 +337,6 @@ struct psb_state { uint32_t savePWM_CONTROL_LOGIC; }; -struct medfield_state { - uint32_t saveMIPI; - uint32_t saveMIPI_C; - - uint32_t savePFIT_CONTROL; - uint32_t savePFIT_PGM_RATIOS; - uint32_t saveHDMIPHYMISCCTL; - uint32_t saveHDMIB_CONTROL; -}; - struct cdv_state { uint32_t saveDSPCLK_GATE_D; uint32_t saveRAMCLK_GATE_D; @@ -440,7 +362,6 @@ struct psb_save_area { uint32_t saveVBT; union { struct psb_state psb; - struct medfield_state mdfld; struct cdv_state cdv; }; uint32_t saveBLC_PWM_CTL2; @@ -451,11 +372,16 @@ struct psb_ops; #define PSB_NUM_PIPE 3 +struct intel_scu_ipc_dev; + struct drm_psb_private { - struct drm_device *dev; + struct drm_device dev; + + struct pci_dev *aux_pdev; /* Currently only used by mrst */ + struct pci_dev *lpc_pdev; /* Currently only used by mrst */ const struct psb_ops *ops; const struct psb_offset *regmap; - + struct child_device_config *child_dev; int child_dev_num; @@ -468,44 +394,35 @@ struct drm_psb_private { uint32_t stolen_base; u8 __iomem *vram_addr; unsigned long vram_stolen_size; - int gtt_initialized; u16 gmch_ctrl; /* Saved GTT setup */ u32 pge_ctl; struct mutex gtt_mutex; struct resource *gtt_mem; /* Our PCI resource */ + struct mutex mmap_mutex; + struct psb_mmu_driver *mmu; struct psb_mmu_pd *pf_pd; - /* - * Register base - */ - + /* Register base */ uint8_t __iomem *sgx_reg; uint8_t __iomem *vdc_reg; + uint8_t __iomem *aux_reg; /* Auxillary vdc pipe regs */ + uint16_t lpc_gpio_base; uint32_t gatt_free_offset; - /* - * Fencing / irq. - */ - + /* Fencing / irq */ uint32_t vdc_irq_mask; uint32_t pipestat[PSB_NUM_PIPE]; spinlock_t irqmask_lock; + bool irq_enabled; - /* - * Power - */ - - bool suspended; - bool display_power; - int display_count; + /* Power */ + bool pm_initialized; - /* - * Modesetting - */ + /* Modesetting */ struct psb_intel_mode_device mode_dev; bool modeset; /* true if we have done the mode_device setup */ @@ -513,15 +430,10 @@ struct drm_psb_private { struct drm_crtc *pipe_to_crtc_mapping[PSB_NUM_PIPE]; uint32_t num_pipe; - /* - * OSPM info (Power management base) (can go ?) - */ + /* OSPM info (Power management base) (TODO: can go ?) */ uint32_t ospm_base; - /* - * Sizes info - */ - + /* Sizes info */ u32 fuse_reg_value; u32 video_device_fuse; @@ -530,6 +442,7 @@ struct drm_psb_private { /* gmbus */ struct intel_gmbus *gmbus; + uint8_t __iomem *gmbus_reg; /* Used by SDVO */ int crt_ddc_pin; @@ -540,9 +453,7 @@ struct drm_psb_private { struct drm_property *broadcast_rgb_property; struct drm_property *force_audio_property; - /* - * LVDS info - */ + /* LVDS info */ int backlight_duty_cycle; /* restore backlight to this value */ bool panel_wants_dither; struct drm_display_mode *panel_fixed_mode; @@ -550,7 +461,7 @@ struct drm_psb_private { struct drm_display_mode *sdvo_lvds_vbt_mode; struct bdb_lvds_backlight *lvds_bl; /* LVDS backlight info from VBT */ - struct psb_intel_i2c_chan *lvds_i2c_bus; /* FIXME: Remove this? */ + struct gma_i2c_chan *lvds_i2c_bus; /* FIXME: Remove this? */ /* Feature bits from the VBIOS */ unsigned int int_tv_support:1; @@ -561,49 +472,29 @@ struct drm_psb_private { int lvds_ssc_freq; bool is_lvds_on; bool is_mipi_on; + bool lvds_enabled_in_vbt; u32 mipi_ctrl_display; unsigned int core_freq; uint32_t iLVDS_enable; - /* Runtime PM state */ - int rpm_enabled; - /* MID specific */ + bool use_msi; bool has_gct; struct oaktrail_gct_data gct_data; /* Oaktrail HDMI state */ struct oaktrail_hdmi_dev *hdmi_priv; - - /* - * Register state - */ + /* Register state */ struct psb_save_area regs; - /* MSI reg save */ - uint32_t msi_addr; - uint32_t msi_data; - - /* - * Hotplug handling - */ - + /* Hotplug handling */ struct work_struct hotplug_work; - /* - * LID-Switch - */ - spinlock_t lid_lock; - struct timer_list lid_timer; struct psb_intel_opregion opregion; - u32 lid_last_state; - - /* - * Watchdog - */ + /* Watchdog */ uint32_t apm_reg; uint16_t apm_base; @@ -611,6 +502,7 @@ struct drm_psb_private { * Used for modifying backlight from * xrandr -- consider removing and using HAL instead */ + struct intel_scu_ipc_dev *scu; struct backlight_device *backlight_device; struct drm_property *backlight_property; bool backlight_enabled; @@ -618,17 +510,6 @@ struct drm_psb_private { uint32_t blc_adj1; uint32_t blc_adj2; - void *fbdev; - - /* 2D acceleration */ - spinlock_t lock_2d; - - /* - * Panel brightness - */ - int brightness; - int brightness_adjusted; - bool dsr_enable; u32 dsr_fb_update; bool dpi_panel_on[3]; @@ -639,8 +520,6 @@ struct drm_psb_private { u32 pipeconf[3]; u32 dspcntr[3]; - int mdfld_panel_id; - bool dplla_96mhz; /* DPLL data from the VBT */ struct { @@ -657,24 +536,25 @@ struct drm_psb_private { uint8_t panel_type; }; +static inline struct drm_psb_private *to_drm_psb_private(struct drm_device *dev) +{ + return container_of(dev, struct drm_psb_private, dev); +} -/* - * Operations for each board type - */ - +/* 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 */ int hdmi_mask; /* Mask of HDMI CRTCs */ int lvds_mask; /* Mask of LVDS CRTCs */ + int sdvo_mask; /* Mask of SDVO CRTCs */ int cursor_needs_phys; /* If cursor base reg need physical address */ /* Sub functions */ struct drm_crtc_helper_funcs const *crtc_helper; - struct drm_crtc_funcs const *crtc_funcs; + const struct gma_clock_funcs *clock_funcs; /* Setup hooks */ int (*chip_setup)(struct drm_device *dev); @@ -690,123 +570,44 @@ struct psb_ops { void (*init_pm)(struct drm_device *dev); int (*save_regs)(struct drm_device *dev); int (*restore_regs)(struct drm_device *dev); + void (*save_crtc)(struct drm_crtc *crtc); + void (*restore_crtc)(struct drm_crtc *crtc); int (*power_up)(struct drm_device *dev); int (*power_down)(struct drm_device *dev); + void (*update_wm)(struct drm_device *dev, struct drm_crtc *crtc); + void (*disable_sr)(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 + void (*backlight_set)(struct drm_device *dev, int level); + int (*backlight_get)(struct drm_device *dev); + const char *backlight_name; + 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); -extern int drm_pick_crtcs(struct drm_device *dev); - -static inline struct drm_psb_private *psb_priv(struct drm_device *dev) -{ - return (struct drm_psb_private *) dev->dev_private; -} - -/* - * MMU stuff. - */ - -extern struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers, - int trap_pagefaults, - int invalid_type, - struct drm_psb_private *dev_priv); -extern void psb_mmu_driver_takedown(struct psb_mmu_driver *driver); -extern struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver - *driver); -extern void psb_mmu_mirror_gtt(struct psb_mmu_pd *pd, uint32_t mmu_offset, - uint32_t gtt_start, uint32_t gtt_pages); -extern struct psb_mmu_pd *psb_mmu_alloc_pd(struct psb_mmu_driver *driver, - int trap_pagefaults, - int invalid_type); -extern void psb_mmu_free_pagedir(struct psb_mmu_pd *pd); -extern void psb_mmu_flush(struct psb_mmu_driver *driver, int rc_prot); -extern void psb_mmu_remove_pfn_sequence(struct psb_mmu_pd *pd, - unsigned long address, - uint32_t num_pages); -extern int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, - uint32_t start_pfn, - unsigned long address, - uint32_t num_pages, int type); -extern int psb_mmu_virtual_to_pfn(struct psb_mmu_pd *pd, uint32_t virtual, - unsigned long *pfn); - -/* - * Enable / disable MMU for different requestors. - */ - - -extern void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context); -extern int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, - unsigned long address, uint32_t num_pages, - uint32_t desired_tile_stride, - uint32_t hw_tile_stride, int type); -extern void psb_mmu_remove_pages(struct psb_mmu_pd *pd, - unsigned long address, uint32_t num_pages, - uint32_t desired_tile_stride, - uint32_t hw_tile_stride); -/* - *psb_irq.c - */ - -extern irqreturn_t psb_irq_handler(DRM_IRQ_ARGS); -extern int psb_irq_enable_dpst(struct drm_device *dev); -extern int psb_irq_disable_dpst(struct drm_device *dev); -extern void psb_irq_preinstall(struct drm_device *dev); -extern int psb_irq_postinstall(struct drm_device *dev); -extern void psb_irq_uninstall(struct drm_device *dev); -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_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); -void -psb_enable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask); - -void -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); - -/* - * framebuffer.c - */ -extern int psbfb_probed(struct drm_device *dev); -extern int psbfb_remove(struct drm_device *dev, - struct drm_framebuffer *fb); -/* - * accel_2d.c - */ -extern void psbfb_copyarea(struct fb_info *info, - const struct fb_copyarea *region); -extern int psbfb_sync(struct fb_info *info); -extern void psb_spank(struct drm_psb_private *dev_priv); - -/* - * psb_reset.c - */ - -extern void psb_lid_timer_init(struct drm_psb_private *dev_priv); -extern void psb_lid_timer_takedown(struct drm_psb_private *dev_priv); -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); + +/* framebuffer */ +struct drm_framebuffer *psb_framebuffer_create(struct drm_device *dev, + const struct drm_format_info *info, + const struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_gem_object *obj); + +/* fbdev */ +#if defined(CONFIG_DRM_FBDEV_EMULATION) +int psb_fbdev_driver_fbdev_probe(struct drm_fb_helper *fb_helper, + struct drm_fb_helper_surface_size *sizes); +#define PSB_FBDEV_DRIVER_OPS \ + .fbdev_probe = psb_fbdev_driver_fbdev_probe +#else +#define PSB_FBDEV_DRIVER_OPS \ + .fbdev_probe = NULL +#endif /* backlight.c */ int gma_backlight_init(struct drm_device *dev); @@ -824,7 +625,6 @@ extern void oaktrail_lvds_init(struct drm_device *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 const struct drm_connector_helper_funcs @@ -832,21 +632,8 @@ extern const struct drm_connector_helper_funcs extern const struct drm_connector_funcs psb_intel_lvds_connector_funcs; /* 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); 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); -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; @@ -854,92 +641,73 @@ extern const struct psb_ops psb_chip_ops; /* oaktrail_device.c */ extern const struct psb_ops oaktrail_chip_ops; -/* mdlfd_device.c */ -extern const struct psb_ops mdfld_chip_ops; - /* cdv_device.c */ extern const struct psb_ops cdv_chip_ops; -/* - * Debug print bits setting - */ -#define PSB_D_GENERAL (1 << 0) -#define PSB_D_INIT (1 << 1) -#define PSB_D_IRQ (1 << 2) -#define PSB_D_ENTRY (1 << 3) -/* debug the get H/V BP/FP count */ -#define PSB_D_HV (1 << 4) -#define PSB_D_DBI_BF (1 << 5) -#define PSB_D_PM (1 << 6) -#define PSB_D_RENDER (1 << 7) -#define PSB_D_REG (1 << 8) -#define PSB_D_MSVDX (1 << 9) -#define PSB_D_TOPAZ (1 << 10) - -extern int drm_idle_check_interval; - -/* - * Utilities - */ - -static inline u32 MRST_MSG_READ32(uint port, uint offset) +/* Utilities */ +static inline uint32_t REGISTER_READ(struct drm_device *dev, uint32_t reg) { - 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); - pci_dev_put(pci_root); - return ret_val; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + return ioread32(dev_priv->vdc_reg + reg); } -static inline void MRST_MSG_WRITE32(uint port, uint offset, u32 value) + +static inline uint32_t REGISTER_READ_AUX(struct drm_device *dev, uint32_t reg) { - 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); - pci_dev_put(pci_root); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + return ioread32(dev_priv->aux_reg + reg); } -static inline u32 MDFLD_MSG_READ32(uint port, uint offset) + +#define REG_READ(reg) REGISTER_READ(dev, (reg)) +#define REG_READ_AUX(reg) REGISTER_READ_AUX(dev, (reg)) + +/* Useful for post reads */ +static inline uint32_t REGISTER_READ_WITH_AUX(struct drm_device *dev, + uint32_t reg, int aux) { - 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; + uint32_t val; + + if (aux) + val = REG_READ_AUX(reg); + else + val = REG_READ(reg); + + return val; } -static inline void MDFLD_MSG_WRITE32(uint port, uint offset, u32 value) + +#define REG_READ_WITH_AUX(reg, aux) REGISTER_READ_WITH_AUX(dev, (reg), (aux)) + +static inline void REGISTER_WRITE(struct drm_device *dev, uint32_t reg, + uint32_t val) { - 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); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + iowrite32((val), dev_priv->vdc_reg + (reg)); } -static inline uint32_t REGISTER_READ(struct drm_device *dev, uint32_t reg) +static inline void REGISTER_WRITE_AUX(struct drm_device *dev, uint32_t reg, + uint32_t val) { - struct drm_psb_private *dev_priv = dev->dev_private; - return ioread32(dev_priv->vdc_reg + reg); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + iowrite32((val), dev_priv->aux_reg + (reg)); } -#define REG_READ(reg) REGISTER_READ(dev, (reg)) +#define REG_WRITE(reg, val) REGISTER_WRITE(dev, (reg), (val)) +#define REG_WRITE_AUX(reg, val) REGISTER_WRITE_AUX(dev, (reg), (val)) -static inline void REGISTER_WRITE(struct drm_device *dev, uint32_t reg, - uint32_t val) +static inline void REGISTER_WRITE_WITH_AUX(struct drm_device *dev, uint32_t reg, + uint32_t val, int aux) { - struct drm_psb_private *dev_priv = dev->dev_private; - iowrite32((val), dev_priv->vdc_reg + (reg)); + if (aux) + REG_WRITE_AUX(reg, val); + else + REG_WRITE(reg, val); } -#define REG_WRITE(reg, val) REGISTER_WRITE(dev, (reg), (val)) +#define REG_WRITE_WITH_AUX(reg, val, aux) REGISTER_WRITE_WITH_AUX(dev, (reg), (val), (aux)) static inline void REGISTER_WRITE16(struct drm_device *dev, uint32_t reg, uint32_t val) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); iowrite16((val), dev_priv->vdc_reg + (reg)); } @@ -948,7 +716,7 @@ static inline void REGISTER_WRITE16(struct drm_device *dev, static inline void REGISTER_WRITE8(struct drm_device *dev, uint32_t reg, uint32_t val) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); iowrite8((val), dev_priv->vdc_reg + (reg)); } @@ -957,25 +725,9 @@ static inline void REGISTER_WRITE8(struct drm_device *dev, #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__); \ - melay(1000); \ - } \ - ioread32(dev_priv->sgx_reg + (_offs)); \ -}) -#else #define PSB_RSGX32(_offs) ioread32(dev_priv->sgx_reg + (_offs)) -#endif #define PSB_WSGX32(_val, _offs) iowrite32(_val, dev_priv->sgx_reg + (_offs)) -#define MSVDX_REG_DUMP 0 - #define PSB_WMSVDX32(_val, _offs) iowrite32(_val, dev_priv->msvdx_reg + (_offs)) #define PSB_RMSVDX32(_offs) ioread32(dev_priv->msvdx_reg + (_offs)) diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c index 6666493789d1..1ff2bd23db74 100644 --- a/drivers/gpu/drm/gma500/psb_intel_display.c +++ b/drivers/gpu/drm/gma500/psb_intel_display.c @@ -1,64 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * 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/delay.h> #include <linux/i2c.h> -#include <linux/pm_runtime.h> -#include <drm/drmP.h> +#include <drm/drm_modeset_helper.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_print.h> + #include "framebuffer.h" +#include "gem.h" +#include "gma_display.h" +#include "power.h" #include "psb_drv.h" #include "psb_intel_drv.h" #include "psb_intel_reg.h" -#include "psb_intel_display.h" -#include "power.h" - -struct psb_intel_clock_t { - /* given values */ - int n; - int m1, m2; - int p1, p2; - /* derived values */ - int dot; - int vco; - int m; - int p; -}; - -struct psb_intel_range_t { - int min, max; -}; - -struct psb_intel_p2_t { - int dot_limit; - int p2_slow, p2_fast; -}; - -struct psb_intel_limit_t { - struct psb_intel_range_t dot, vco, n, m, m1, m2, p, p1; - struct psb_intel_p2_t p2; -}; #define INTEL_LIMIT_I9XX_SDVO_DAC 0 #define INTEL_LIMIT_I9XX_LVDS 1 -static const struct psb_intel_limit_t psb_intel_limits[] = { +static const struct gma_limit_t psb_intel_limits[] = { { /* INTEL_LIMIT_I9XX_SDVO_DAC */ .dot = {.min = 20000, .max = 400000}, .vco = {.min = 1400000, .max = 2800000}, @@ -68,8 +34,8 @@ static const struct psb_intel_limit_t psb_intel_limits[] = { .m2 = {.min = 3, .max = 7}, .p = {.min = 5, .max = 80}, .p1 = {.min = 1, .max = 8}, - .p2 = {.dot_limit = 200000, - .p2_slow = 10, .p2_fast = 5}, + .p2 = {.dot_limit = 200000, .p2_slow = 10, .p2_fast = 5}, + .find_pll = gma_find_best_pll, }, { /* INTEL_LIMIT_I9XX_LVDS */ .dot = {.min = 20000, .max = 400000}, @@ -83,23 +49,24 @@ static const struct psb_intel_limit_t psb_intel_limits[] = { /* The single-channel range is 25-112Mhz, and dual-channel * is 80-224Mhz. Prefer single channel as much as possible. */ - .p2 = {.dot_limit = 112000, - .p2_slow = 14, .p2_fast = 7}, + .p2 = {.dot_limit = 112000, .p2_slow = 14, .p2_fast = 7}, + .find_pll = gma_find_best_pll, }, }; -static const struct psb_intel_limit_t *psb_intel_limit(struct drm_crtc *crtc) +static const struct gma_limit_t *psb_intel_limit(struct drm_crtc *crtc, + int refclk) { - const struct psb_intel_limit_t *limit; + const struct gma_limit_t *limit; - if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) + if (gma_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) limit = &psb_intel_limits[INTEL_LIMIT_I9XX_LVDS]; else limit = &psb_intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC]; return limit; } -static void psb_intel_clock(int refclk, struct psb_intel_clock_t *clock) +static void psb_intel_clock(int refclk, struct gma_clock_t *clock) { clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); clock->p = clock->p1 * clock->p2; @@ -107,354 +74,7 @@ static void psb_intel_clock(int refclk, struct psb_intel_clock_t *clock) clock->dot = clock->vco / clock->p; } -/** - * Returns whether any output on the specified pipe is of the specified type - */ -bool psb_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_encoder *psb_intel_encoder = - psb_intel_attached_encoder(l_entry); - if (psb_intel_encoder->type == type) - return true; - } - } - return false; -} - -#define INTELPllInvalid(s) { /* ErrorF (s) */; return false; } -/** - * Returns whether the given set of divisors are valid for a given refclk with - * the given connectors. - */ - -static bool psb_intel_PLL_is_valid(struct drm_crtc *crtc, - struct psb_intel_clock_t *clock) -{ - const struct psb_intel_limit_t *limit = psb_intel_limit(crtc); - - 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"); - if (clock->m2 < limit->m2.min || limit->m2.max < clock->m2) - INTELPllInvalid("m2 out of range\n"); - if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1) - INTELPllInvalid("m1 out of range\n"); - if (clock->m1 <= clock->m2) - INTELPllInvalid("m1 <= m2\n"); - if (clock->m < limit->m.min || limit->m.max < clock->m) - INTELPllInvalid("m out of range\n"); - if (clock->n < limit->n.min || limit->n.max < clock->n) - INTELPllInvalid("n out of range\n"); - 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; -} - -/** - * Returns a set of divisors for the desired target clock with the given - * refclk, or FALSE. The returned values represent the clock equation: - * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. - */ -static bool psb_intel_find_best_PLL(struct drm_crtc *crtc, int target, - int refclk, - struct psb_intel_clock_t *best_clock) -{ - struct drm_device *dev = crtc->dev; - struct psb_intel_clock_t clock; - const struct psb_intel_limit_t *limit = psb_intel_limit(crtc); - int err = target; - - if (psb_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)); - - for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; - clock.m1++) { - for (clock.m2 = limit->m2.min; - clock.m2 < clock.m1 && clock.m2 <= limit->m2.max; - clock.m2++) { - for (clock.n = limit->n.min; - clock.n <= limit->n.max; clock.n++) { - for (clock.p1 = limit->p1.min; - clock.p1 <= limit->p1.max; - clock.p1++) { - int this_err; - - psb_intel_clock(refclk, &clock); - - if (!psb_intel_PLL_is_valid - (crtc, &clock)) - continue; - - this_err = abs(clock.dot - target); - if (this_err < err) { - *best_clock = clock; - err = this_err; - } - } - } - } - } - - return err != target; -} - -void psb_intel_wait_for_vblank(struct drm_device *dev) -{ - /* Wait for 20ms, i.e. one cycle at 50hz. */ - mdelay(20); -} - -static int psb_intel_pipe_set_base(struct drm_crtc *crtc, - int x, int y, struct drm_framebuffer *old_fb) -{ - struct drm_device *dev = crtc->dev; - struct drm_psb_private *dev_priv = dev->dev_private; - struct 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; - const struct psb_offset *map = &dev_priv->regmap[pipe]; - unsigned long start, offset; - u32 dspcntr; - int ret = 0; - - if (!gma_power_begin(dev, true)) - return 0; - - /* no fb bound */ - if (!crtc->fb) { - dev_dbg(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->pitches[0] + x * (crtc->fb->bits_per_pixel / 8); - - REG_WRITE(map->stride, crtc->fb->pitches[0]); - - dspcntr = REG_READ(map->cntr); - 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; - psb_gtt_unpin(psbfb->gtt); - goto psb_intel_pipe_set_base_exit; - } - REG_WRITE(map->cntr, dspcntr); - - REG_WRITE(map->base, start + offset); - REG_READ(map->base); - -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 psb_intel_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; - const struct psb_offset *map = &dev_priv->regmap[pipe]; - u32 temp; - - /* XXX: When our outputs are all unaware of DPMS modes other than off - * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. - */ - switch (mode) { - case DRM_MODE_DPMS_ON: - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - /* Enable the DPLL */ - temp = REG_READ(map->dpll); - if ((temp & DPLL_VCO_ENABLE) == 0) { - REG_WRITE(map->dpll, temp); - REG_READ(map->dpll); - /* Wait for the clocks to stabilize. */ - udelay(150); - REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE); - REG_READ(map->dpll); - /* Wait for the clocks to stabilize. */ - udelay(150); - REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE); - REG_READ(map->dpll); - /* Wait for the clocks to stabilize. */ - udelay(150); - } - - /* Enable the pipe */ - temp = REG_READ(map->conf); - if ((temp & PIPEACONF_ENABLE) == 0) - REG_WRITE(map->conf, temp | PIPEACONF_ENABLE); - - /* Enable the plane */ - temp = REG_READ(map->cntr); - if ((temp & DISPLAY_PLANE_ENABLE) == 0) { - REG_WRITE(map->cntr, - temp | DISPLAY_PLANE_ENABLE); - /* Flush the plane changes */ - REG_WRITE(map->base, REG_READ(map->base)); - } - - 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); - - /* Disable display plane */ - temp = REG_READ(map->cntr); - if ((temp & DISPLAY_PLANE_ENABLE) != 0) { - REG_WRITE(map->cntr, - temp & ~DISPLAY_PLANE_ENABLE); - /* Flush the plane changes */ - REG_WRITE(map->base, REG_READ(map->base)); - REG_READ(map->base); - } - - /* Next, disable display pipes */ - temp = REG_READ(map->conf); - if ((temp & PIPEACONF_ENABLE) != 0) { - REG_WRITE(map->conf, temp & ~PIPEACONF_ENABLE); - REG_READ(map->conf); - } - - /* Wait for vblank for the disable to take effect. */ - psb_intel_wait_for_vblank(dev); - - temp = REG_READ(map->dpll); - if ((temp & DPLL_VCO_ENABLE) != 0) { - REG_WRITE(map->dpll, temp & ~DPLL_VCO_ENABLE); - REG_READ(map->dpll); - } - - /* Wait for the clocks to turn off. */ - udelay(150); - break; - } - - /*Set FIFO Watermarks*/ - REG_WRITE(DSPARB, 0x3F3E); -} - -static void psb_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 psb_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 psb_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 psb_intel_lvds_prepare */ - encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF); -} - -void psb_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 psb_intel_lvds_commit */ - encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); -} - -void psb_intel_encoder_destroy(struct drm_encoder *encoder) -{ - struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder); - - drm_encoder_cleanup(encoder); - kfree(intel_encoder); -} - -static bool psb_intel_crtc_mode_fixup(struct drm_crtc *crtc, - const 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 */ @@ -478,34 +98,35 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) { 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); - struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - int pipe = psb_intel_crtc->pipe; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + int pipe = gma_crtc->pipe; const struct psb_offset *map = &dev_priv->regmap[pipe]; int refclk; - struct psb_intel_clock_t clock; + struct gma_clock_t clock; u32 dpll = 0, fp = 0, dspcntr, pipeconf; bool ok, is_sdvo = false; bool is_lvds = false, is_tv = false; - struct drm_mode_config *mode_config = &dev->mode_config; + struct drm_connector_list_iter conn_iter; struct drm_connector *connector; + const struct gma_limit_t *limit; /* No scan out no play */ - if (crtc->fb == NULL) { + if (crtc->primary->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_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + struct gma_encoder *gma_encoder = gma_attached_encoder(connector); if (!connector->encoder || connector->encoder->crtc != crtc) continue; - switch (psb_intel_encoder->type) { + switch (gma_encoder->type) { case INTEL_OUTPUT_LVDS: is_lvds = true; break; @@ -516,14 +137,20 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc, is_tv = true; break; } + + break; } + drm_connector_list_iter_end(&conn_iter); refclk = 96000; - ok = psb_intel_find_best_PLL(crtc, adjusted_mode->clock, refclk, + limit = gma_crtc->clock_funcs->limit(crtc, refclk); + + ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock); if (!ok) { - dev_err(dev->dev, "Couldn't find PLL settings for mode!\n"); + DRM_ERROR("Couldn't find PLL settings for mode! target: %d, actual: %d", + adjusted_mode->clock, clock.dot); return 0; } @@ -661,368 +288,29 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc, REG_WRITE(map->conf, pipeconf); REG_READ(map->conf); - psb_intel_wait_for_vblank(dev); + gma_wait_for_vblank(dev); REG_WRITE(map->cntr, dspcntr); /* Flush the plane changes */ crtc_funcs->mode_set_base(crtc, x, y, old_fb); - psb_intel_wait_for_vblank(dev); - - return 0; -} - -/** Loads the palette/gamma unit for the CRTC with the prepared values */ -void psb_intel_crtc_load_lut(struct drm_crtc *crtc) -{ - 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); - const struct psb_offset *map = &dev_priv->regmap[psb_intel_crtc->pipe]; - int palreg = map->palette; - int i; - - /* The clocks have to be on to load the palette. */ - if (!crtc->enabled) - return; - - switch (psb_intel_crtc->pipe) { - case 0: - case 1: - 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->regs.pipe[0].palette[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 psb_intel_crtc_save(struct drm_crtc *crtc) -{ - 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); - struct psb_intel_crtc_state *crtc_state = psb_intel_crtc->crtc_state; - const struct psb_offset *map = &dev_priv->regmap[psb_intel_crtc->pipe]; - uint32_t paletteReg; - int i; - - if (!crtc_state) { - dev_err(dev->dev, "No CRTC state found\n"); - return; - } - - crtc_state->saveDSPCNTR = REG_READ(map->cntr); - crtc_state->savePIPECONF = REG_READ(map->conf); - crtc_state->savePIPESRC = REG_READ(map->src); - crtc_state->saveFP0 = REG_READ(map->fp0); - crtc_state->saveFP1 = REG_READ(map->fp1); - crtc_state->saveDPLL = REG_READ(map->dpll); - crtc_state->saveHTOTAL = REG_READ(map->htotal); - crtc_state->saveHBLANK = REG_READ(map->hblank); - crtc_state->saveHSYNC = REG_READ(map->hsync); - crtc_state->saveVTOTAL = REG_READ(map->vtotal); - crtc_state->saveVBLANK = REG_READ(map->vblank); - crtc_state->saveVSYNC = REG_READ(map->vsync); - crtc_state->saveDSPSTRIDE = REG_READ(map->stride); - - /*NOTE: DSPSIZE DSPPOS only for psb*/ - crtc_state->saveDSPSIZE = REG_READ(map->size); - crtc_state->saveDSPPOS = REG_READ(map->pos); - - crtc_state->saveDSPBASE = REG_READ(map->base); - - paletteReg = map->palette; - for (i = 0; i < 256; ++i) - crtc_state->savePalette[i] = REG_READ(paletteReg + (i << 2)); -} - -/** - * Restore HW states of giving crtc - */ -static void psb_intel_crtc_restore(struct drm_crtc *crtc) -{ - 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); - struct psb_intel_crtc_state *crtc_state = psb_intel_crtc->crtc_state; - const struct psb_offset *map = &dev_priv->regmap[psb_intel_crtc->pipe]; - uint32_t paletteReg; - int i; - - if (!crtc_state) { - dev_err(dev->dev, "No crtc state\n"); - return; - } - - if (crtc_state->saveDPLL & DPLL_VCO_ENABLE) { - REG_WRITE(map->dpll, - crtc_state->saveDPLL & ~DPLL_VCO_ENABLE); - REG_READ(map->dpll); - udelay(150); - } - - REG_WRITE(map->fp0, crtc_state->saveFP0); - REG_READ(map->fp0); - - REG_WRITE(map->fp1, crtc_state->saveFP1); - REG_READ(map->fp1); - - REG_WRITE(map->dpll, crtc_state->saveDPLL); - REG_READ(map->dpll); - udelay(150); - - REG_WRITE(map->htotal, crtc_state->saveHTOTAL); - REG_WRITE(map->hblank, crtc_state->saveHBLANK); - REG_WRITE(map->hsync, crtc_state->saveHSYNC); - REG_WRITE(map->vtotal, crtc_state->saveVTOTAL); - REG_WRITE(map->vblank, crtc_state->saveVBLANK); - REG_WRITE(map->vsync, crtc_state->saveVSYNC); - REG_WRITE(map->stride, crtc_state->saveDSPSTRIDE); - - REG_WRITE(map->size, crtc_state->saveDSPSIZE); - REG_WRITE(map->pos, crtc_state->saveDSPPOS); - - REG_WRITE(map->src, crtc_state->savePIPESRC); - REG_WRITE(map->base, crtc_state->saveDSPBASE); - REG_WRITE(map->conf, crtc_state->savePIPECONF); - - psb_intel_wait_for_vblank(dev); - - REG_WRITE(map->cntr, crtc_state->saveDSPCNTR); - REG_WRITE(map->base, crtc_state->saveDSPBASE); - - psb_intel_wait_for_vblank(dev); - - paletteReg = map->palette; - for (i = 0; i < 256; ++i) - REG_WRITE(paletteReg + (i << 2), crtc_state->savePalette[i]); -} - -static int psb_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 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; - 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 gtt_range *cursor_gt = psb_intel_crtc->cursor_gt; - struct drm_gem_object *obj; - void *tmp_dst, *tmp_src; - int ret = 0, i, cursor_pages; - - /* 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"); - ret = -ENOMEM; - goto unref_cursor; - } - - 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); - goto unref_cursor; - } - - if (dev_priv->ops->cursor_needs_phys) { - if (cursor_gt == NULL) { - dev_err(dev->dev, "No hardware cursor mem available"); - ret = -ENOMEM; - goto unref_cursor; - } - - /* Prevent overflow */ - if (gt->npage > 4) - cursor_pages = 4; - else - cursor_pages = gt->npage; - - /* Copy the cursor to cursor mem */ - tmp_dst = dev_priv->vram_addr + cursor_gt->offset; - for (i = 0; i < cursor_pages; i++) { - tmp_src = kmap(gt->pages[i]); - memcpy(tmp_dst, tmp_src, PAGE_SIZE); - kunmap(gt->pages[i]); - tmp_dst += PAGE_SIZE; - } - - addr = psb_intel_crtc->cursor_addr; - } else { - 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); - } + gma_wait_for_vblank(dev); - /* unpin the old bo */ - 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 ret; - -unref_cursor: - drm_gem_object_unreference(obj); - return ret; -} - -static int psb_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 addr; - - - 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, false)) { - REG_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp); - REG_WRITE((pipe == 0) ? CURABASE : CURBBASE, addr); - gma_power_end(dev); - } return 0; } -static 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); - int i; - - if (size != 256) - return; - - for (i = 0; i < 256; 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; - } - - psb_intel_crtc_load_lut(crtc); -} - -static int psb_crtc_set_config(struct drm_mode_set *set) -{ - int ret; - 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; -} - /* Returns the clock of the currently programmed mode of the given pipe. */ static int psb_intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) { - 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; + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + int pipe = gma_crtc->pipe; const struct psb_offset *map = &dev_priv->regmap[pipe]; u32 dpll; u32 fp; - struct psb_intel_clock_t clock; + struct gma_clock_t clock; bool is_lvds; struct psb_pipe *p = &dev_priv->regs.pipe[pipe]; @@ -1092,14 +380,14 @@ static int psb_intel_crtc_clock_get(struct drm_device *dev, struct drm_display_mode *psb_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 gma_crtc *gma_crtc = to_gma_crtc(crtc); + int pipe = gma_crtc->pipe; struct drm_display_mode *mode; int htot; int hsync; int vtot; int vsync; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_pipe *p = &dev_priv->regs.pipe[pipe]; const struct psb_offset *map = &dev_priv->regmap[pipe]; @@ -1136,58 +424,19 @@ 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) -{ - struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); - struct gtt_range *gt; - - /* 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; - } - - if (psb_intel_crtc->cursor_gt != NULL) - psb_gtt_free_range(crtc->dev, psb_intel_crtc->cursor_gt); - kfree(psb_intel_crtc->crtc_state); - drm_crtc_cleanup(crtc); - kfree(psb_intel_crtc); -} - -static void psb_intel_crtc_disable(struct drm_crtc *crtc) -{ - struct gtt_range *gt; - struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - - crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); - - if (crtc->fb) { - gt = to_psb_fb(crtc->fb)->gtt; - psb_gtt_unpin(gt); - } -} - const struct drm_crtc_helper_funcs psb_intel_helper_funcs = { - .dpms = psb_intel_crtc_dpms, - .mode_fixup = psb_intel_crtc_mode_fixup, + .dpms = gma_crtc_dpms, .mode_set = psb_intel_crtc_mode_set, - .mode_set_base = psb_intel_pipe_set_base, - .prepare = psb_intel_crtc_prepare, - .commit = psb_intel_crtc_commit, - .disable = psb_intel_crtc_disable, + .mode_set_base = gma_pipe_set_base, + .prepare = gma_crtc_prepare, + .commit = gma_crtc_commit, + .disable = gma_crtc_disable, }; -const struct drm_crtc_funcs psb_intel_crtc_funcs = { - .save = psb_intel_crtc_save, - .restore = psb_intel_crtc_restore, - .cursor_set = psb_intel_crtc_cursor_set, - .cursor_move = psb_intel_crtc_cursor_move, - .gamma_set = psb_intel_crtc_gamma_set, - .set_config = psb_crtc_set_config, - .destroy = psb_intel_crtc_destroy, +const struct gma_clock_funcs psb_clock_funcs = { + .clock = psb_intel_clock, + .limit = psb_intel_limit, + .pll_is_valid = gma_pll_is_valid, }; /* @@ -1195,174 +444,116 @@ const struct drm_crtc_funcs psb_intel_crtc_funcs = { * to zero. This is a workaround for h/w defect on Oaktrail */ static void psb_intel_cursor_init(struct drm_device *dev, - struct psb_intel_crtc *psb_intel_crtc) + struct gma_crtc *gma_crtc) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); u32 control[3] = { CURACNTR, CURBCNTR, CURCCNTR }; u32 base[3] = { CURABASE, CURBBASE, CURCBASE }; - struct gtt_range *cursor_gt; + struct psb_gem_object *cursor_pobj; if (dev_priv->ops->cursor_needs_phys) { /* Allocate 4 pages of stolen mem for a hardware cursor. That * is enough for the 64 x 64 ARGB cursors we support. */ - cursor_gt = psb_gtt_alloc_range(dev, 4 * PAGE_SIZE, "cursor", 1); - if (!cursor_gt) { - psb_intel_crtc->cursor_gt = NULL; + cursor_pobj = psb_gem_create(dev, 4 * PAGE_SIZE, "cursor", true, PAGE_SIZE); + if (IS_ERR(cursor_pobj)) { + gma_crtc->cursor_pobj = NULL; goto out; } - psb_intel_crtc->cursor_gt = cursor_gt; - psb_intel_crtc->cursor_addr = dev_priv->stolen_base + - cursor_gt->offset; + gma_crtc->cursor_pobj = cursor_pobj; + gma_crtc->cursor_addr = dev_priv->stolen_base + cursor_pobj->offset; } else { - psb_intel_crtc->cursor_gt = NULL; + gma_crtc->cursor_pobj = NULL; } out: - REG_WRITE(control[psb_intel_crtc->pipe], 0); - REG_WRITE(base[psb_intel_crtc->pipe], 0); + REG_WRITE(control[gma_crtc->pipe], 0); + REG_WRITE(base[gma_crtc->pipe], 0); } void psb_intel_crtc_init(struct drm_device *dev, int pipe, struct psb_intel_mode_device *mode_dev) { - struct drm_psb_private *dev_priv = dev->dev_private; - struct psb_intel_crtc *psb_intel_crtc; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_crtc *gma_crtc; int i; - uint16_t *r_base, *g_base, *b_base; /* We allocate a extra array of drm_connector pointers * for fbdev after the crtc */ - psb_intel_crtc = - kzalloc(sizeof(struct psb_intel_crtc) + - (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)), - GFP_KERNEL); - if (psb_intel_crtc == NULL) + gma_crtc = kzalloc(sizeof(struct gma_crtc) + + (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)), + GFP_KERNEL); + if (gma_crtc == NULL) return; - psb_intel_crtc->crtc_state = + gma_crtc->crtc_state = kzalloc(sizeof(struct psb_intel_crtc_state), GFP_KERNEL); - if (!psb_intel_crtc->crtc_state) { + if (!gma_crtc->crtc_state) { dev_err(dev->dev, "Crtc state error: No memory\n"); - kfree(psb_intel_crtc); + kfree(gma_crtc); return; } - /* 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; - psb_intel_crtc->plane = pipe; - - r_base = psb_intel_crtc->base.gamma_store; - g_base = r_base + 256; - b_base = g_base + 256; - for (i = 0; i < 256; i++) { - psb_intel_crtc->lut_r[i] = i; - psb_intel_crtc->lut_g[i] = i; - psb_intel_crtc->lut_b[i] = i; - r_base[i] = i << 8; - g_base[i] = i << 8; - b_base[i] = i << 8; - - psb_intel_crtc->lut_adj[i] = 0; - } + drm_crtc_init(dev, &gma_crtc->base, &gma_crtc_funcs); - psb_intel_crtc->mode_dev = mode_dev; - psb_intel_crtc->cursor_addr = 0; + /* Set the CRTC clock functions from chip specific data */ + gma_crtc->clock_funcs = dev_priv->ops->clock_funcs; - drm_crtc_helper_add(&psb_intel_crtc->base, + drm_mode_crtc_set_gamma_size(&gma_crtc->base, 256); + gma_crtc->pipe = pipe; + gma_crtc->plane = pipe; + + for (i = 0; i < 256; i++) + gma_crtc->lut_adj[i] = 0; + + gma_crtc->mode_dev = mode_dev; + gma_crtc->cursor_addr = 0; + + drm_crtc_helper_add(&gma_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; + gma_crtc->mode_set.crtc = &gma_crtc->base; BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) || - dev_priv->plane_to_crtc_mapping[psb_intel_crtc->plane] != NULL); - dev_priv->plane_to_crtc_mapping[psb_intel_crtc->plane] = - &psb_intel_crtc->base; - dev_priv->pipe_to_crtc_mapping[psb_intel_crtc->pipe] = - &psb_intel_crtc->base; - 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, psb_intel_crtc); + dev_priv->plane_to_crtc_mapping[gma_crtc->plane] != NULL); + dev_priv->plane_to_crtc_mapping[gma_crtc->plane] = &gma_crtc->base; + dev_priv->pipe_to_crtc_mapping[gma_crtc->pipe] = &gma_crtc->base; + gma_crtc->mode_set.connectors = (struct drm_connector **)(gma_crtc + 1); + gma_crtc->mode_set.num_connectors = 0; + psb_intel_cursor_init(dev, gma_crtc); /* Set to true so that the pipe is forced off on initial config. */ - psb_intel_crtc->active = true; -} - -int psb_intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - struct drm_psb_get_pipe_from_crtc_id_arg *pipe_from_crtc_id = data; - struct drm_mode_object *drmmode_obj; - struct psb_intel_crtc *crtc; - - if (!dev_priv) { - dev_err(dev->dev, "called with no initialization\n"); - return -EINVAL; - } - - drmmode_obj = drm_mode_object_find(dev, pipe_from_crtc_id->crtc_id, - DRM_MODE_OBJECT_CRTC); - - if (!drmmode_obj) { - dev_err(dev->dev, "no such CRTC id\n"); - return -EINVAL; - } - - crtc = to_psb_intel_crtc(obj_to_crtc(drmmode_obj)); - pipe_from_crtc_id->pipe = crtc->pipe; - - return 0; + gma_crtc->active = true; } struct drm_crtc *psb_intel_get_crtc_from_pipe(struct drm_device *dev, int pipe) { - struct drm_crtc *crtc = NULL; + struct drm_crtc *crtc; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); - if (psb_intel_crtc->pipe == pipe) - break; + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + + if (gma_crtc->pipe == pipe) + return crtc; } - return crtc; + return NULL; } -int psb_intel_connector_clones(struct drm_device *dev, int type_mask) +int gma_connector_clones(struct drm_device *dev, int type_mask) { - int index_mask = 0; + struct drm_connector_list_iter conn_iter; struct drm_connector *connector; + int index_mask = 0; int entry = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, - head) { - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); - if (type_mask & (1 << psb_intel_encoder->type)) + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + struct gma_encoder *gma_encoder = gma_attached_encoder(connector); + if (type_mask & (1 << gma_encoder->type)) index_mask |= (1 << entry); entry++; } - return index_mask; -} - -/* current intel driver doesn't take advantage of encoders - always give back the encoder for the connector -*/ -struct drm_encoder *psb_intel_best_encoder(struct drm_connector *connector) -{ - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); + drm_connector_list_iter_end(&conn_iter); - return &psb_intel_encoder->base; -} - -void psb_intel_connector_attach_encoder(struct psb_intel_connector *connector, - struct psb_intel_encoder *encoder) -{ - connector->encoder = encoder; - drm_mode_connector_attach_encoder(&connector->base, - &encoder->base); + return index_mask; } diff --git a/drivers/gpu/drm/gma500/psb_intel_display.h b/drivers/gpu/drm/gma500/psb_intel_display.h deleted file mode 100644 index 3724b971e91c..000000000000 --- a/drivers/gpu/drm/gma500/psb_intel_display.h +++ /dev/null @@ -1,25 +0,0 @@ -/* copyright (c) 2008, 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> - */ - -#ifndef _INTEL_DISPLAY_H_ -#define _INTEL_DISPLAY_H_ - -bool psb_intel_pipe_has_type(struct drm_crtc *crtc, int type); - -#endif diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h index 4dcae421a58d..979ea8ecf0d5 100644 --- a/drivers/gpu/drm/gma500/psb_intel_drv.h +++ b/drivers/gpu/drm/gma500/psb_intel_drv.h @@ -1,19 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * 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. - * */ #ifndef __INTEL_DRV_H__ @@ -22,8 +9,10 @@ #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> #include <drm/drm_crtc.h> -#include <drm/drm_crtc_helper.h> -#include <linux/gpio.h> +#include <drm/drm_encoder.h> +#include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> +#include "gma_display.h" /* * Display related stuff @@ -65,25 +54,6 @@ #define INTEL_OUTPUT_DISPLAYPORT 9 #define INTEL_OUTPUT_EDP 10 -#define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0) -#define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT) - -static inline void -psb_intel_mode_set_pixel_multiplier(struct drm_display_mode *mode, - int multiplier) -{ - mode->clock *= multiplier; - mode->private_flags |= multiplier; -} - -static inline int -psb_intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode) -{ - return (mode->private_flags & INTEL_MODE_PIXEL_MULTIPLIER_MASK) - >> INTEL_MODE_PIXEL_MULTIPLIER_SHIFT; -} - - /* * Hold information useally put on the device driver privates here, * since it needs to be shared across multiple of devices drivers privates. @@ -107,20 +77,21 @@ struct psb_intel_mode_device { uint32_t saveBLC_PWM_CTL; }; -struct psb_intel_i2c_chan { +struct gma_i2c_chan { + struct i2c_adapter base; + struct i2c_algo_bit_data algo; + u8 target_addr; + /* for getting at dev. private (mmio etc.) */ struct drm_device *drm_dev; - u32 reg; /* GPIO reg */ - struct i2c_adapter adapter; - struct i2c_algo_bit_data algo; - u8 slave_addr; + u32 reg; /* GPIO reg */ }; -struct psb_intel_encoder { +struct gma_encoder { struct drm_encoder base; int type; bool needs_tv_clock; - void (*hot_plug)(struct psb_intel_encoder *); + void (*hot_plug)(struct gma_encoder *); int crtc_mask; int clone_mask; u32 ddi_select; /* Channel info */ @@ -132,13 +103,15 @@ struct psb_intel_encoder { /* FIXME: Either make SDVO and LVDS store it's i2c here or give CDV it's own set of output privates */ - struct psb_intel_i2c_chan *i2c_bus; - struct psb_intel_i2c_chan *ddc_bus; + struct gma_i2c_chan *i2c_bus; }; -struct psb_intel_connector { +struct gma_connector { struct drm_connector base; - struct psb_intel_encoder *encoder; + struct gma_encoder *encoder; + + void (*save)(struct drm_connector *connector); + void (*restore)(struct drm_connector *connector); }; struct psb_intel_crtc_state { @@ -161,13 +134,12 @@ struct psb_intel_crtc_state { uint32_t savePalette[256]; }; -struct psb_intel_crtc { +struct gma_crtc { struct drm_crtc base; int pipe; int plane; uint32_t cursor_addr; - struct gtt_range *cursor_gt; - u8 lut_r[256], lut_g[256], lut_b[256]; + struct psb_gem_object *cursor_pobj; u8 lut_adj[256]; struct psb_intel_framebuffer *fbdev_fb; /* a mode_set for fbdev users on this crtc */ @@ -188,89 +160,62 @@ struct psb_intel_crtc { /* Saved Crtc HW states */ struct psb_intel_crtc_state *crtc_state; + + const struct gma_clock_funcs *clock_funcs; + + struct drm_pending_vblank_event *page_flip_event; }; -#define to_psb_intel_crtc(x) \ - container_of(x, struct psb_intel_crtc, base) -#define to_psb_intel_connector(x) \ - container_of(x, struct psb_intel_connector, base) -#define to_psb_intel_encoder(x) \ - container_of(x, struct psb_intel_encoder, base) +#define to_gma_crtc(x) \ + container_of(x, struct gma_crtc, base) +#define to_gma_connector(x) \ + container_of(x, struct gma_connector, base) +#define to_gma_encoder(x) \ + container_of(x, struct gma_encoder, base) #define to_psb_intel_framebuffer(x) \ container_of(x, struct psb_intel_framebuffer, base) +#define to_gma_i2c_chan(x) \ + container_of(x, struct gma_i2c_chan, base) -struct psb_intel_i2c_chan *psb_intel_i2c_create(struct drm_device *dev, - const u32 reg, const char *name); -void psb_intel_i2c_destroy(struct psb_intel_i2c_chan *chan); +struct gma_i2c_chan *gma_i2c_create(struct drm_device *dev, const u32 reg, + const char *name); +void gma_i2c_destroy(struct gma_i2c_chan *chan); int psb_intel_ddc_get_modes(struct drm_connector *connector, struct i2c_adapter *adapter); -extern bool psb_intel_ddc_probe(struct i2c_adapter *adapter); extern void psb_intel_crtc_init(struct drm_device *dev, int pipe, struct psb_intel_mode_device *mode_dev); -extern void psb_intel_crt_init(struct drm_device *dev); extern bool psb_intel_sdvo_init(struct drm_device *dev, int output_device); -extern void psb_intel_dvo_init(struct drm_device *dev); -extern void psb_intel_tv_init(struct drm_device *dev); extern void psb_intel_lvds_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev); extern void psb_intel_lvds_set_brightness(struct drm_device *dev, int level); extern void oaktrail_lvds_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev); -extern void oaktrail_wait_for_INTR_PKT_SENT(struct drm_device *dev); -extern void oaktrail_dsi_init(struct drm_device *dev, - struct psb_intel_mode_device *mode_dev); -extern void mid_dsi_init(struct drm_device *dev, - struct psb_intel_mode_device *mode_dev, int dsi_num); +struct gma_i2c_chan *oaktrail_lvds_i2c_init(struct drm_device *dev); -extern void psb_intel_crtc_load_lut(struct drm_crtc *crtc); -extern void psb_intel_encoder_prepare(struct drm_encoder *encoder); -extern void psb_intel_encoder_commit(struct drm_encoder *encoder); -extern void psb_intel_encoder_destroy(struct drm_encoder *encoder); +extern struct drm_encoder *gma_best_encoder(struct drm_connector *connector); +extern void gma_connector_attach_encoder(struct gma_connector *connector, + struct gma_encoder *encoder); -static inline struct psb_intel_encoder *psb_intel_attached_encoder( +static inline struct gma_encoder *gma_attached_encoder( struct drm_connector *connector) { - return to_psb_intel_connector(connector)->encoder; + return to_gma_connector(connector)->encoder; } -extern void psb_intel_connector_attach_encoder( - struct psb_intel_connector *connector, - struct psb_intel_encoder *encoder); - -extern struct drm_encoder *psb_intel_best_encoder(struct drm_connector - *connector); - extern struct drm_display_mode *psb_intel_crtc_mode_get(struct drm_device *dev, struct drm_crtc *crtc); -extern void psb_intel_wait_for_vblank(struct drm_device *dev); -extern int psb_intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, - struct drm_file *file_priv); extern struct drm_crtc *psb_intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); -extern struct drm_connector *psb_intel_sdvo_find(struct drm_device *dev, - int sdvoB); -extern int psb_intel_sdvo_supports_hotplug(struct drm_connector *connector); -extern void psb_intel_sdvo_set_hotplug(struct drm_connector *connector, - int enable); -extern int intelfb_probe(struct drm_device *dev); -extern int intelfb_remove(struct drm_device *dev, - struct drm_framebuffer *fb); -extern struct drm_framebuffer *psb_intel_framebuffer_create(struct drm_device - *dev, struct - drm_mode_fb_cmd - *mode_cmd, - void *mm_private); extern bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); -extern int psb_intel_lvds_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode); +extern enum drm_mode_status psb_intel_lvds_mode_valid(struct drm_connector *connector, + const struct drm_display_mode *mode); extern int psb_intel_lvds_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t value); extern void psb_intel_lvds_destroy(struct drm_connector *connector); -extern const struct drm_encoder_funcs psb_intel_lvds_enc_funcs; /* intel_gmbus.c */ extern void gma_intel_i2c_reset(struct drm_device *dev); @@ -285,9 +230,6 @@ extern void cdv_intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); -extern void psb_intel_attach_force_audio_property(struct drm_connector *connector); -extern void psb_intel_attach_broadcast_rgb_property(struct drm_connector *connector); - extern int cdv_sb_read(struct drm_device *dev, u32 reg, u32 *val); extern int cdv_sb_write(struct drm_device *dev, u32 reg, u32 val); extern void cdv_sb_reset(struct drm_device *dev); diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c index 9fa5fa2e6192..f8f3c42e67a7 100644 --- a/drivers/gpu/drm/gma500/psb_intel_lvds.c +++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright © 2006-2007 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> @@ -21,14 +9,18 @@ */ #include <linux/i2c.h> -#include <drm/drmP.h> +#include <linux/pm_runtime.h> + +#include <drm/drm_crtc_helper.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_print.h> +#include <drm/drm_simple_kms_helper.h> #include "intel_bios.h" +#include "power.h" #include "psb_drv.h" #include "psb_intel_drv.h" #include "psb_intel_reg.h" -#include "power.h" -#include <linux/pm_runtime.h> /* * LVDS I2C backlight control macros @@ -60,8 +52,7 @@ struct psb_intel_lvds_priv { uint32_t savePFIT_PGM_RATIOS; uint32_t saveBLC_PWM_CTL; - struct psb_intel_i2c_chan *i2c_bus; - struct psb_intel_i2c_chan *ddc_bus; + struct gma_i2c_chan *i2c_bus; }; @@ -70,7 +61,7 @@ struct psb_intel_lvds_priv { */ static u32 psb_intel_lvds_get_max_backlight(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); u32 ret; if (gma_power_begin(dev, false)) { @@ -99,16 +90,15 @@ static u32 psb_intel_lvds_get_max_backlight(struct drm_device *dev) static int psb_lvds_i2c_set_brightness(struct drm_device *dev, unsigned int level) { - struct drm_psb_private *dev_priv = - (struct drm_psb_private *)dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - struct psb_intel_i2c_chan *lvds_i2c_bus = dev_priv->lvds_i2c_bus; + struct gma_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, + .addr = lvds_i2c_bus->target_addr, .flags = 0, .len = 2, .buf = out_buf, @@ -125,7 +115,7 @@ static int psb_lvds_i2c_set_brightness(struct drm_device *dev, 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) { + if (i2c_transfer(&lvds_i2c_bus->base, msgs, 1) == 1) { dev_dbg(dev->dev, "I2C set brightness.(command, value) (%d, %d)\n", dev_priv->lvds_bl->brightnesscmd, blc_i2c_brightness); @@ -139,8 +129,7 @@ static int psb_lvds_i2c_set_brightness(struct drm_device *dev, static int psb_lvds_pwm_set_brightness(struct drm_device *dev, int level) { - struct drm_psb_private *dev_priv = - (struct drm_psb_private *)dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); u32 max_pwm_blc; u32 blc_pwm_duty_cycle; @@ -172,7 +161,7 @@ static int psb_lvds_pwm_set_brightness(struct drm_device *dev, int level) */ void psb_intel_lvds_set_brightness(struct drm_device *dev, int level) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); dev_dbg(dev->dev, "backlight level is %d\n", level); @@ -194,7 +183,7 @@ void psb_intel_lvds_set_brightness(struct drm_device *dev, int level) */ static void psb_intel_lvds_set_backlight(struct drm_device *dev, int level) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); u32 blc_pwm_ctl; if (gma_power_begin(dev, false)) { @@ -219,7 +208,7 @@ static void psb_intel_lvds_set_backlight(struct drm_device *dev, int level) */ static void psb_intel_lvds_set_power(struct drm_device *dev, bool on) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; u32 pp_status; @@ -227,7 +216,7 @@ static void psb_intel_lvds_set_power(struct drm_device *dev, bool on) dev_err(dev->dev, "set power, chip off!\n"); return; } - + if (on) { REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) | POWER_TARGET_ON); @@ -265,12 +254,10 @@ static void psb_intel_lvds_encoder_dpms(struct drm_encoder *encoder, int mode) static void psb_intel_lvds_save(struct drm_connector *connector) { struct drm_device *dev = connector->dev; - struct drm_psb_private *dev_priv = - (struct drm_psb_private *)dev->dev_private; - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_encoder *gma_encoder = gma_attached_encoder(connector); struct psb_intel_lvds_priv *lvds_priv = - (struct psb_intel_lvds_priv *)psb_intel_encoder->dev_priv; + (struct psb_intel_lvds_priv *)gma_encoder->dev_priv; lvds_priv->savePP_ON = REG_READ(LVDSPP_ON); lvds_priv->savePP_OFF = REG_READ(LVDSPP_OFF); @@ -307,10 +294,9 @@ static void psb_intel_lvds_restore(struct drm_connector *connector) { struct drm_device *dev = connector->dev; u32 pp_status; - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); + struct gma_encoder *gma_encoder = gma_attached_encoder(connector); struct psb_intel_lvds_priv *lvds_priv = - (struct psb_intel_lvds_priv *)psb_intel_encoder->dev_priv; + (struct psb_intel_lvds_priv *)gma_encoder->dev_priv; dev_dbg(dev->dev, "(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", lvds_priv->savePP_ON, @@ -345,16 +331,15 @@ static void psb_intel_lvds_restore(struct drm_connector *connector) } } -int psb_intel_lvds_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +enum drm_mode_status psb_intel_lvds_mode_valid(struct drm_connector *connector, + const struct drm_display_mode *mode) { - struct drm_psb_private *dev_priv = connector->dev->dev_private; - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); + struct drm_psb_private *dev_priv = to_drm_psb_private(connector->dev); + struct gma_encoder *gma_encoder = gma_attached_encoder(connector); struct drm_display_mode *fixed_mode = dev_priv->mode_dev.panel_fixed_mode; - if (psb_intel_encoder->type == INTEL_OUTPUT_MIPI2) + if (gma_encoder->type == INTEL_OUTPUT_MIPI2) fixed_mode = dev_priv->mode_dev.panel_fixed_mode2; /* just in case */ @@ -379,25 +364,23 @@ bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; - struct psb_intel_crtc *psb_intel_crtc = - to_psb_intel_crtc(encoder->crtc); + struct gma_crtc *gma_crtc = to_gma_crtc(encoder->crtc); struct drm_encoder *tmp_encoder; struct drm_display_mode *panel_fixed_mode = mode_dev->panel_fixed_mode; - struct psb_intel_encoder *psb_intel_encoder = - to_psb_intel_encoder(encoder); + struct gma_encoder *gma_encoder = to_gma_encoder(encoder); - if (psb_intel_encoder->type == INTEL_OUTPUT_MIPI2) + if (gma_encoder->type == INTEL_OUTPUT_MIPI2) panel_fixed_mode = mode_dev->panel_fixed_mode2; /* 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"); + if (!IS_MRST(dev) && gma_crtc->pipe == 0) { + pr_err("Can't support LVDS on pipe A\n"); return false; } - if (IS_MRST(dev) && psb_intel_crtc->pipe != 0) { - printk(KERN_ERR "Must use PIPE A\n"); + if (IS_MRST(dev) && gma_crtc->pipe != 0) { + pr_err("Must use PIPE A\n"); return false; } /* Should never happen!! */ @@ -405,8 +388,7 @@ bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder, 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"); + pr_err("Can't enable LVDS and another encoder on the same pipe\n"); return false; } } @@ -443,7 +425,7 @@ bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder, static void psb_intel_lvds_prepare(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; if (!gma_power_begin(dev, true)) @@ -461,7 +443,7 @@ static void psb_intel_lvds_prepare(struct drm_encoder *encoder) static void psb_intel_lvds_commit(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; if (mode_dev->backlight_duty_cycle == 0) @@ -476,7 +458,7 @@ static void psb_intel_lvds_mode_set(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); u32 pfit_control; /* @@ -505,49 +487,27 @@ static void psb_intel_lvds_mode_set(struct drm_encoder *encoder, } /* - * 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 psb_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 psb_intel_lvds_get_modes(struct drm_connector *connector) { struct drm_device *dev = connector->dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); - struct psb_intel_lvds_priv *lvds_priv = psb_intel_encoder->dev_priv; int ret = 0; if (!IS_MRST(dev)) - ret = psb_intel_ddc_get_modes(connector, &lvds_priv->i2c_bus->adapter); + ret = psb_intel_ddc_get_modes(connector, connector->ddc); 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); + if (!mode) + return 0; + drm_mode_probed_add(connector, mode); return 1; } @@ -555,24 +515,14 @@ static int psb_intel_lvds_get_modes(struct drm_connector *connector) return 0; } -/** - * psb_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 psb_intel_lvds_destroy(struct drm_connector *connector) { - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); - struct psb_intel_lvds_priv *lvds_priv = psb_intel_encoder->dev_priv; + struct gma_connector *gma_connector = to_gma_connector(connector); + struct gma_i2c_chan *ddc_bus = to_gma_i2c_chan(connector->ddc); - if (lvds_priv->ddc_bus) - psb_intel_i2c_destroy(lvds_priv->ddc_bus); - drm_sysfs_connector_remove(connector); + gma_i2c_destroy(ddc_bus); drm_connector_cleanup(connector); - kfree(connector); + kfree(gma_connector); } int psb_intel_lvds_set_property(struct drm_connector *connector, @@ -585,8 +535,7 @@ int psb_intel_lvds_set_property(struct drm_connector *connector, return -1; if (!strcmp(property->name, "scaling mode")) { - struct psb_intel_crtc *crtc = - to_psb_intel_crtc(encoder->crtc); + struct gma_crtc *crtc = to_gma_crtc(encoder->crtc); uint64_t curval; if (!crtc) @@ -622,7 +571,7 @@ int psb_intel_lvds_set_property(struct drm_connector *connector, &crtc->saved_mode, encoder->crtc->x, encoder->crtc->y, - encoder->crtc->fb)) + encoder->crtc->primary->fb)) goto set_prop_error; } } else if (!strcmp(property->name, "backlight")) { @@ -633,7 +582,7 @@ int psb_intel_lvds_set_property(struct drm_connector *connector, else gma_backlight_set(encoder->dev, value); } else if (!strcmp(property->name, "DPMS")) { - struct drm_encoder_helper_funcs *hfuncs + const struct drm_encoder_helper_funcs *hfuncs = encoder->helper_private; hfuncs->dpms(encoder, value); } @@ -656,34 +605,20 @@ const struct drm_connector_helper_funcs psb_intel_lvds_connector_helper_funcs = { .get_modes = psb_intel_lvds_get_modes, .mode_valid = psb_intel_lvds_mode_valid, - .best_encoder = psb_intel_best_encoder, + .best_encoder = gma_best_encoder, }; const struct drm_connector_funcs psb_intel_lvds_connector_funcs = { .dpms = drm_helper_connector_dpms, - .save = psb_intel_lvds_save, - .restore = psb_intel_lvds_restore, - .detect = psb_intel_lvds_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = psb_intel_lvds_set_property, .destroy = psb_intel_lvds_destroy, }; - -static void psb_intel_lvds_enc_destroy(struct drm_encoder *encoder) -{ - drm_encoder_cleanup(encoder); -} - -const struct drm_encoder_funcs psb_intel_lvds_enc_funcs = { - .destroy = psb_intel_lvds_enc_destroy, -}; - - - /** * psb_intel_lvds_init - setup LVDS connectors on this device * @dev: drm device + * @mode_dev: mode 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). @@ -691,52 +626,65 @@ const struct drm_encoder_funcs psb_intel_lvds_enc_funcs = { void psb_intel_lvds_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev) { - struct psb_intel_encoder *psb_intel_encoder; - struct psb_intel_connector *psb_intel_connector; + struct gma_encoder *gma_encoder; + struct gma_connector *gma_connector; struct psb_intel_lvds_priv *lvds_priv; struct drm_connector *connector; struct drm_encoder *encoder; struct drm_display_mode *scan; /* *modes, *bios_mode; */ struct drm_crtc *crtc; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_i2c_chan *ddc_bus; u32 lvds; int pipe; + int ret; - psb_intel_encoder = - kzalloc(sizeof(struct psb_intel_encoder), GFP_KERNEL); - if (!psb_intel_encoder) { - dev_err(dev->dev, "psb_intel_encoder allocation error\n"); + gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL); + if (!gma_encoder) { + dev_err(dev->dev, "gma_encoder allocation error\n"); return; } + encoder = &gma_encoder->base; - psb_intel_connector = - kzalloc(sizeof(struct psb_intel_connector), GFP_KERNEL); - if (!psb_intel_connector) { - dev_err(dev->dev, "psb_intel_connector allocation error\n"); - goto failed_encoder; + gma_connector = kzalloc(sizeof(struct gma_connector), GFP_KERNEL); + if (!gma_connector) { + dev_err(dev->dev, "gma_connector allocation error\n"); + goto err_free_encoder; } lvds_priv = kzalloc(sizeof(struct psb_intel_lvds_priv), GFP_KERNEL); if (!lvds_priv) { dev_err(dev->dev, "LVDS private allocation error\n"); - goto failed_connector; + goto err_free_connector; } - psb_intel_encoder->dev_priv = lvds_priv; + gma_encoder->dev_priv = lvds_priv; - connector = &psb_intel_connector->base; - encoder = &psb_intel_encoder->base; - drm_connector_init(dev, connector, - &psb_intel_lvds_connector_funcs, - DRM_MODE_CONNECTOR_LVDS); + connector = &gma_connector->base; + gma_connector->save = psb_intel_lvds_save; + gma_connector->restore = psb_intel_lvds_restore; - drm_encoder_init(dev, encoder, - &psb_intel_lvds_enc_funcs, - DRM_MODE_ENCODER_LVDS); + /* Set up the DDC bus. */ + ddc_bus = gma_i2c_create(dev, GPIOC, "LVDSDDC_C"); + if (!ddc_bus) { + dev_printk(KERN_ERR, dev->dev, + "DDC bus registration " "failed.\n"); + goto err_free_lvds_priv; + } - psb_intel_connector_attach_encoder(psb_intel_connector, - psb_intel_encoder); - psb_intel_encoder->type = INTEL_OUTPUT_LVDS; + ret = drm_connector_init_with_ddc(dev, connector, + &psb_intel_lvds_connector_funcs, + DRM_MODE_CONNECTOR_LVDS, + &ddc_bus->base); + if (ret) + goto err_ddc_destroy; + + ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_LVDS); + if (ret) + goto err_connector_cleanup; + + gma_connector_attach_encoder(gma_connector, gma_encoder); + gma_encoder->type = INTEL_OUTPUT_LVDS; drm_encoder_helper_add(encoder, &psb_intel_lvds_helper_funcs); drm_connector_helper_add(connector, @@ -757,13 +705,13 @@ void psb_intel_lvds_init(struct drm_device *dev, * Set up I2C bus * FIXME: distroy i2c_bus when exit */ - lvds_priv->i2c_bus = psb_intel_i2c_create(dev, GPIOB, "LVDSBLC_B"); + lvds_priv->i2c_bus = gma_i2c_create(dev, GPIOB, "LVDSBLC_B"); if (!lvds_priv->i2c_bus) { dev_printk(KERN_ERR, - &dev->pdev->dev, "I2C bus registration failed.\n"); - goto failed_blc_i2c; + dev->dev, "I2C bus registration failed.\n"); + goto err_encoder_cleanup; } - lvds_priv->i2c_bus->slave_addr = 0x2C; + lvds_priv->i2c_bus->target_addr = 0x2C; dev_priv->lvds_i2c_bus = lvds_priv->i2c_bus; /* @@ -776,37 +724,34 @@ void psb_intel_lvds_init(struct drm_device *dev, * if closed, act like it's not there for now */ - /* Set up the DDC bus. */ - lvds_priv->ddc_bus = psb_intel_i2c_create(dev, GPIOC, "LVDSDDC_C"); - if (!lvds_priv->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(connector, &lvds_priv->ddc_bus->adapter); + mutex_lock(&dev->mode_config.mutex); + psb_intel_ddc_get_modes(connector, &ddc_bus->base); + 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); + DRM_DEBUG_KMS("Using mode from DDC\n"); goto out; /* FIXME: check for quirks */ } } /* Failed to get EDID, what about VBT? do we need this? */ - if (mode_dev->vbt_mode) + if (dev_priv->lfp_lvds_vbt_mode) { mode_dev->panel_fixed_mode = - drm_mode_duplicate(dev, mode_dev->vbt_mode); + drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); - if (!mode_dev->panel_fixed_mode) - 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; + DRM_DEBUG_KMS("Using mode from VBT\n"); + goto out; + } + } /* * If we didn't get EDID, try checking if the panel is already turned @@ -823,6 +768,7 @@ void psb_intel_lvds_init(struct drm_device *dev, if (mode_dev->panel_fixed_mode) { mode_dev->panel_fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; + DRM_DEBUG_KMS("Using pre-programmed mode\n"); goto out; /* FIXME: check for quirks */ } } @@ -830,7 +776,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) { dev_err(dev->dev, "Found no modes on the lvds, ignoring the LVDS\n"); - goto failed_find; + goto err_unlock; } /* @@ -838,21 +784,23 @@ void psb_intel_lvds_init(struct drm_device *dev, * actually having one. */ out: - drm_sysfs_connector_add(connector); + mutex_unlock(&dev->mode_config.mutex); return; -failed_find: - if (lvds_priv->ddc_bus) - psb_intel_i2c_destroy(lvds_priv->ddc_bus); -failed_ddc: - if (lvds_priv->i2c_bus) - psb_intel_i2c_destroy(lvds_priv->i2c_bus); -failed_blc_i2c: +err_unlock: + mutex_unlock(&dev->mode_config.mutex); + gma_i2c_destroy(lvds_priv->i2c_bus); +err_encoder_cleanup: drm_encoder_cleanup(encoder); +err_connector_cleanup: drm_connector_cleanup(connector); -failed_connector: - kfree(psb_intel_connector); -failed_encoder: - kfree(psb_intel_encoder); +err_ddc_destroy: + gma_i2c_destroy(ddc_bus); +err_free_lvds_priv: + kfree(lvds_priv); +err_free_connector: + kfree(gma_connector); +err_free_encoder: + kfree(gma_encoder); } diff --git a/drivers/gpu/drm/gma500/psb_intel_modes.c b/drivers/gpu/drm/gma500/psb_intel_modes.c index 4fca0d6feebe..45b10f30a2a9 100644 --- a/drivers/gpu/drm/gma500/psb_intel_modes.c +++ b/drivers/gpu/drm/gma500/psb_intel_modes.c @@ -1,61 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2007 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. - * * Authers: Jesse Barnes <jesse.barnes@intel.com> */ #include <linux/i2c.h> -#include <linux/fb.h> -#include <drm/drmP.h> -#include "psb_intel_drv.h" -/** - * psb_intel_ddc_probe - * - */ -bool psb_intel_ddc_probe(struct i2c_adapter *adapter) -{ - u8 out_buf[] = { 0x0, 0x0 }; - u8 buf[2]; - int ret; - struct i2c_msg msgs[] = { - { - .addr = 0x50, - .flags = 0, - .len = 1, - .buf = out_buf, - }, - { - .addr = 0x50, - .flags = I2C_M_RD, - .len = 1, - .buf = buf, - } - }; - - ret = i2c_transfer(adapter, msgs, 2); - if (ret == 2) - return true; +#include <drm/drm_edid.h> - return false; -} +#include "psb_intel_drv.h" /** * psb_intel_ddc_get_modes - get modelist from monitor * @connector: DRM connector device to use + * @adapter: Associated I2C adaptor * * Fetch the EDID information from @connector using the DDC bus. */ @@ -67,7 +26,7 @@ int psb_intel_ddc_get_modes(struct drm_connector *connector, edid = drm_get_edid(connector, adapter); if (edid) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); } diff --git a/drivers/gpu/drm/gma500/psb_intel_reg.h b/drivers/gpu/drm/gma500/psb_intel_reg.h index 0be30e4d146d..ced7b433befb 100644 --- a/drivers/gpu/drm/gma500/psb_intel_reg.h +++ b/drivers/gpu/drm/gma500/psb_intel_reg.h @@ -1,18 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * 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. */ #ifndef __PSB_INTEL_REG_H__ #define __PSB_INTEL_REG_H__ @@ -562,38 +550,6 @@ #define HISTOGRAM_INT_CTRL_CLEAR (1UL << 30) #define DPST_YUV_LUMA_MODE 0 -struct dpst_ie_histogram_control { - union { - uint32_t data; - struct { - uint32_t bin_reg_index:7; - uint32_t reserved:4; - uint32_t bin_reg_func_select:1; - uint32_t sync_to_phase_in:1; - uint32_t alt_enhancement_mode:2; - uint32_t reserved1:1; - uint32_t sync_to_phase_in_count:8; - uint32_t histogram_mode_select:1; - uint32_t reserved2:4; - uint32_t ie_pipe_assignment:1; - uint32_t ie_mode_table_enabled:1; - uint32_t ie_histogram_enable:1; - }; - }; -}; - -struct dpst_guardband { - union { - uint32_t data; - struct { - uint32_t guardband:22; - uint32_t guardband_interrupt_delay:8; - uint32_t interrupt_status:1; - uint32_t interrupt_enable:1; - }; - }; -}; - #define PIPEAFRAMEHIGH 0x70040 #define PIPEAFRAMEPIXEL 0x70044 #define PIPEBFRAMEHIGH 0x71040 @@ -607,7 +563,7 @@ struct dpst_guardband { #define PIPE_PIXEL_MASK 0x00ffffff #define PIPE_PIXEL_SHIFT 0 -#define FW_BLC_SELF 0x20e0 +#define FW_BLC_SELF 0x20e0 #define FW_BLC_SELF_EN (1<<15) #define DSPARB 0x70030 @@ -801,17 +757,9 @@ struct dpst_guardband { * MOORESTOWN delta registers */ #define MRST_DPLL_A 0x0f014 -#define MDFLD_DPLL_B 0x0f018 -#define MDFLD_INPUT_REF_SEL (1 << 14) -#define MDFLD_VCO_SEL (1 << 16) #define DPLLA_MODE_LVDS (2 << 26) /* mrst */ -#define MDFLD_PLL_LATCHEN (1 << 28) -#define MDFLD_PWR_GATE_EN (1 << 30) -#define MDFLD_P1_MASK (0x1FF << 17) #define MRST_FPA0 0x0f040 #define MRST_FPA1 0x0f044 -#define MDFLD_DPLL_DIV0 0x0f048 -#define MDFLD_DPLL_DIV1 0x0f04c #define MRST_PERF_MODE 0x020f4 /* @@ -860,7 +808,6 @@ struct dpst_guardband { #define MRST_DSPABASE 0x7019c #define MRST_DSPBBASE 0x7119c -#define MDFLD_DSPCBASE 0x7219c /* * Moorestown registers. @@ -942,7 +889,6 @@ struct dpst_guardband { #define DEVICE_RESET_REG 0xb01C #define DPI_RESOLUTION_REG 0xb020 #define RES_V_POS 0x10 -#define DBI_RESOLUTION_REG 0xb024 /* Reserved for MDFLD */ #define HORIZ_SYNC_PAD_COUNT_REG 0xb028 #define HORIZ_BACK_PORCH_COUNT_REG 0xb02C #define HORIZ_FRONT_PORCH_COUNT_REG 0xb030 diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c index 19e36603b23b..553e7c7d9bb8 100644 --- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c +++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c @@ -25,18 +25,23 @@ * Authors: * Eric Anholt <eric@anholt.net> */ -#include <linux/module.h> + +#include <linux/delay.h> #include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h> #include <linux/slab.h> -#include <linux/delay.h> -#include <drm/drmP.h> + #include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> #include <drm/drm_edid.h> -#include "psb_intel_drv.h" -#include <drm/gma_drm.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_print.h> + #include "psb_drv.h" -#include "psb_intel_sdvo_regs.h" +#include "psb_intel_drv.h" #include "psb_intel_reg.h" +#include "psb_intel_sdvo_regs.h" #define SDVO_TMDS_MASK (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1) #define SDVO_RGB_MASK (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1) @@ -62,13 +67,11 @@ static const char *tv_format_names[] = { "SECAM_60" }; -#define TV_FORMAT_NUM (sizeof(tv_format_names) / sizeof(*tv_format_names)) - struct psb_intel_sdvo { - struct psb_intel_encoder base; + struct gma_encoder base; struct i2c_adapter *i2c; - u8 slave_addr; + u8 target_addr; struct i2c_adapter ddc; @@ -125,13 +128,15 @@ struct psb_intel_sdvo { bool is_lvds; /** - * This is sdvo fixed pannel mode pointer + * This is sdvo fixed panel mode pointer */ struct drm_display_mode *sdvo_lvds_fixed_mode; /* DDC bus used by this SDVO encoder */ uint8_t ddc_bus; + u8 pixel_multiplier; + /* Input timings for adjusted_mode */ struct psb_intel_sdvo_dtd input_dtd; @@ -140,7 +145,7 @@ struct psb_intel_sdvo { }; struct psb_intel_sdvo_connector { - struct psb_intel_connector base; + struct gma_connector base; /* Mark the type of connector */ uint16_t output_flag; @@ -148,7 +153,7 @@ struct psb_intel_sdvo_connector { int force_audio; /* This contains all current supported TV format */ - u8 tv_format_supported[TV_FORMAT_NUM]; + u8 tv_format_supported[ARRAY_SIZE(tv_format_names)]; int format_supported_num; struct drm_property *tv_format; @@ -200,13 +205,13 @@ static struct psb_intel_sdvo *to_psb_intel_sdvo(struct drm_encoder *encoder) static struct psb_intel_sdvo *intel_attached_sdvo(struct drm_connector *connector) { - return container_of(psb_intel_attached_encoder(connector), + return container_of(gma_attached_encoder(connector), struct psb_intel_sdvo, base); } static struct psb_intel_sdvo_connector *to_psb_intel_sdvo_connector(struct drm_connector *connector) { - return container_of(to_psb_intel_connector(connector), struct psb_intel_sdvo_connector, base); + return container_of(to_gma_connector(connector), struct psb_intel_sdvo_connector, base); } static bool @@ -219,7 +224,7 @@ static bool psb_intel_sdvo_create_enhance_property(struct psb_intel_sdvo *psb_intel_sdvo, struct psb_intel_sdvo_connector *psb_intel_sdvo_connector); -/** +/* * Writes the SDVOB or SDVOC with the given value, but always writes both * SDVOB and SDVOC to work around apparent hardware issues (according to * comments in the BIOS). @@ -228,24 +233,26 @@ static void psb_intel_sdvo_write_sdvox(struct psb_intel_sdvo *psb_intel_sdvo, u3 { struct drm_device *dev = psb_intel_sdvo->base.base.dev; u32 bval = val, cval = val; - int i; + int i, j; + int need_aux = IS_MRST(dev) ? 1 : 0; - if (psb_intel_sdvo->sdvo_reg == SDVOB) { - cval = REG_READ(SDVOC); - } else { - bval = REG_READ(SDVOB); - } - /* - * Write the registers twice for luck. Sometimes, - * writing them only once doesn't appear to 'stick'. - * The BIOS does this too. Yay, magic - */ - for (i = 0; i < 2; i++) - { - REG_WRITE(SDVOB, bval); - REG_READ(SDVOB); - REG_WRITE(SDVOC, cval); - REG_READ(SDVOC); + for (j = 0; j <= need_aux; j++) { + if (psb_intel_sdvo->sdvo_reg == SDVOB) + cval = REG_READ_WITH_AUX(SDVOC, j); + else + bval = REG_READ_WITH_AUX(SDVOB, j); + + /* + * Write the registers twice for luck. Sometimes, + * writing them only once doesn't appear to 'stick'. + * The BIOS does this too. Yay, magic + */ + for (i = 0; i < 2; i++) { + REG_WRITE_WITH_AUX(SDVOB, bval, j); + REG_READ_WITH_AUX(SDVOB, j); + REG_WRITE_WITH_AUX(SDVOC, cval, j); + REG_READ_WITH_AUX(SDVOC, j); + } } } @@ -253,13 +260,13 @@ static bool psb_intel_sdvo_read_byte(struct psb_intel_sdvo *psb_intel_sdvo, u8 a { struct i2c_msg msgs[] = { { - .addr = psb_intel_sdvo->slave_addr, + .addr = psb_intel_sdvo->target_addr, .flags = 0, .len = 1, .buf = &addr, }, { - .addr = psb_intel_sdvo->slave_addr, + .addr = psb_intel_sdvo->target_addr, .flags = I2C_M_RD, .len = 1, .buf = ch, @@ -396,26 +403,38 @@ static const struct _sdvo_cmd_name { #define IS_SDVOB(reg) (reg == SDVOB) #define SDVO_NAME(svdo) (IS_SDVOB((svdo)->sdvo_reg) ? "SDVOB" : "SDVOC") -static void psb_intel_sdvo_debug_write(struct psb_intel_sdvo *psb_intel_sdvo, u8 cmd, - const void *args, int args_len) +static void psb_intel_sdvo_debug_write(struct psb_intel_sdvo *psb_intel_sdvo, + u8 cmd, const void *args, int args_len) { - int i; + struct drm_device *dev = psb_intel_sdvo->base.base.dev; + int i, pos = 0; + char buffer[73]; + +#define BUF_PRINT(args...) \ + pos += snprintf(buffer + pos, max_t(int, sizeof(buffer) - pos, 0), args) + + for (i = 0; i < args_len; i++) { + BUF_PRINT("%02X ", ((u8 *)args)[i]); + } + + for (; i < 8; i++) { + BUF_PRINT(" "); + } - DRM_DEBUG_KMS("%s: W: %02X ", - SDVO_NAME(psb_intel_sdvo), cmd); - for (i = 0; i < args_len; i++) - DRM_LOG_KMS("%02X ", ((u8 *)args)[i]); - for (; i < 8; i++) - DRM_LOG_KMS(" "); for (i = 0; i < ARRAY_SIZE(sdvo_cmd_names); i++) { if (cmd == sdvo_cmd_names[i].cmd) { - DRM_LOG_KMS("(%s)", sdvo_cmd_names[i].name); + BUF_PRINT("(%s)", sdvo_cmd_names[i].name); break; } } + if (i == ARRAY_SIZE(sdvo_cmd_names)) - DRM_LOG_KMS("(%02X)", cmd); - DRM_LOG_KMS("\n"); + BUF_PRINT("(%02X)", cmd); + + drm_WARN_ON(dev, pos >= sizeof(buffer) - 1); +#undef BUF_PRINT + + DRM_DEBUG_KMS("%s: W: %02X %s\n", SDVO_NAME(psb_intel_sdvo), cmd, buffer); } static const char *cmd_status_names[] = { @@ -428,24 +447,31 @@ static const char *cmd_status_names[] = { "Scaling not supported" }; +#define MAX_ARG_LEN 32 + static bool psb_intel_sdvo_write_cmd(struct psb_intel_sdvo *psb_intel_sdvo, u8 cmd, const void *args, int args_len) { - u8 buf[args_len*2 + 2], status; - struct i2c_msg msgs[args_len + 3]; + u8 buf[MAX_ARG_LEN*2 + 2], status; + struct i2c_msg msgs[MAX_ARG_LEN + 3]; int i, ret; + if (args_len > MAX_ARG_LEN) { + DRM_ERROR("Need to increase arg length\n"); + return false; + } + psb_intel_sdvo_debug_write(psb_intel_sdvo, cmd, args, args_len); for (i = 0; i < args_len; i++) { - msgs[i].addr = psb_intel_sdvo->slave_addr; + msgs[i].addr = psb_intel_sdvo->target_addr; msgs[i].flags = 0; msgs[i].len = 2; msgs[i].buf = buf + 2 *i; buf[2*i + 0] = SDVO_I2C_ARG_0 - i; buf[2*i + 1] = ((u8*)args)[i]; } - msgs[i].addr = psb_intel_sdvo->slave_addr; + msgs[i].addr = psb_intel_sdvo->target_addr; msgs[i].flags = 0; msgs[i].len = 2; msgs[i].buf = buf + 2*i; @@ -454,12 +480,12 @@ static bool psb_intel_sdvo_write_cmd(struct psb_intel_sdvo *psb_intel_sdvo, u8 c /* the following two are to read the response */ status = SDVO_I2C_CMD_STATUS; - msgs[i+1].addr = psb_intel_sdvo->slave_addr; + msgs[i+1].addr = psb_intel_sdvo->target_addr; msgs[i+1].flags = 0; msgs[i+1].len = 1; msgs[i+1].buf = &status; - msgs[i+2].addr = psb_intel_sdvo->slave_addr; + msgs[i+2].addr = psb_intel_sdvo->target_addr; msgs[i+2].flags = I2C_M_RD; msgs[i+2].len = 1; msgs[i+2].buf = &status; @@ -479,13 +505,13 @@ static bool psb_intel_sdvo_write_cmd(struct psb_intel_sdvo *psb_intel_sdvo, u8 c } static bool psb_intel_sdvo_read_response(struct psb_intel_sdvo *psb_intel_sdvo, - void *response, int response_len) + void *response, int response_len) { + struct drm_device *dev = psb_intel_sdvo->base.base.dev; + char buffer[73]; + int i, pos = 0; u8 retry = 5; u8 status; - int i; - - DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(psb_intel_sdvo)); /* * The documentation states that all commands will be @@ -500,7 +526,8 @@ static bool psb_intel_sdvo_read_response(struct psb_intel_sdvo *psb_intel_sdvo, &status)) goto log_fail; - while (status == SDVO_CMD_STATUS_PENDING && retry--) { + while ((status == SDVO_CMD_STATUS_PENDING || + status == SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED) && retry--) { udelay(15); if (!psb_intel_sdvo_read_byte(psb_intel_sdvo, SDVO_I2C_CMD_STATUS, @@ -508,10 +535,13 @@ static bool psb_intel_sdvo_read_response(struct psb_intel_sdvo *psb_intel_sdvo, goto log_fail; } +#define BUF_PRINT(args...) \ + pos += snprintf(buffer + pos, max_t(int, sizeof(buffer) - pos, 0), args) + if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) - DRM_LOG_KMS("(%s)", cmd_status_names[status]); + BUF_PRINT("(%s)", cmd_status_names[status]); else - DRM_LOG_KMS("(??? %d)", status); + BUF_PRINT("(??? %d)", status); if (status != SDVO_CMD_STATUS_SUCCESS) goto log_fail; @@ -522,13 +552,18 @@ static bool psb_intel_sdvo_read_response(struct psb_intel_sdvo *psb_intel_sdvo, SDVO_I2C_RETURN_0 + i, &((u8 *)response)[i])) goto log_fail; - DRM_LOG_KMS(" %02X", ((u8 *)response)[i]); + BUF_PRINT(" %02X", ((u8 *)response)[i]); } - DRM_LOG_KMS("\n"); + + drm_WARN_ON(dev, pos >= sizeof(buffer) - 1); +#undef BUF_PRINT + + DRM_DEBUG_KMS("%s: R: %s\n", SDVO_NAME(psb_intel_sdvo), buffer); return true; log_fail: - DRM_LOG_KMS("... failed\n"); + DRM_DEBUG_KMS("%s: R: ... failed %s\n", + SDVO_NAME(psb_intel_sdvo), buffer); return false; } @@ -576,7 +611,7 @@ static bool psb_intel_sdvo_set_target_input(struct psb_intel_sdvo *psb_intel_sdv &targets, sizeof(targets)); } -/** +/* * Return whether each input is trained. * * This function is making an assumption about the layout of the response, @@ -854,36 +889,6 @@ static bool psb_intel_sdvo_set_avi_infoframe(struct psb_intel_sdvo *psb_intel_sd DRM_INFO("HDMI is not supported yet"); return false; -#if 0 - struct dip_infoframe avi_if = { - .type = DIP_TYPE_AVI, - .ver = DIP_VERSION_AVI, - .len = DIP_LEN_AVI, - }; - uint8_t tx_rate = SDVO_HBUF_TX_VSYNC; - uint8_t set_buf_index[2] = { 1, 0 }; - uint64_t *data = (uint64_t *)&avi_if; - unsigned i; - - intel_dip_infoframe_csum(&avi_if); - - if (!psb_intel_sdvo_set_value(psb_intel_sdvo, - SDVO_CMD_SET_HBUF_INDEX, - set_buf_index, 2)) - return false; - - for (i = 0; i < sizeof(avi_if); i += 8) { - if (!psb_intel_sdvo_set_value(psb_intel_sdvo, - SDVO_CMD_SET_HBUF_DATA, - data, 8)) - return false; - data++; - } - - return psb_intel_sdvo_set_value(psb_intel_sdvo, - SDVO_CMD_SET_HBUF_TXRATE, - &tx_rate, 1); -#endif } static bool psb_intel_sdvo_set_tv_format(struct psb_intel_sdvo *psb_intel_sdvo) @@ -948,7 +953,6 @@ static bool psb_intel_sdvo_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct psb_intel_sdvo *psb_intel_sdvo = to_psb_intel_sdvo(encoder); - int multiplier; /* We need to construct preferred input timings based on our * output timings. To do that, we have to set the output @@ -975,8 +979,9 @@ static bool psb_intel_sdvo_mode_fixup(struct drm_encoder *encoder, /* Make the CRTC code factor in the SDVO pixel multiplier. The * SDVO device will factor out the multiplier during mode_set. */ - multiplier = psb_intel_sdvo_get_pixel_multiplier(adjusted_mode); - psb_intel_mode_set_pixel_multiplier(adjusted_mode, multiplier); + psb_intel_sdvo->pixel_multiplier = + psb_intel_sdvo_get_pixel_multiplier(adjusted_mode); + adjusted_mode->clock *= psb_intel_sdvo->pixel_multiplier; return true; } @@ -987,13 +992,13 @@ static void psb_intel_sdvo_mode_set(struct drm_encoder *encoder, { struct drm_device *dev = encoder->dev; struct drm_crtc *crtc = encoder->crtc; - struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); struct psb_intel_sdvo *psb_intel_sdvo = to_psb_intel_sdvo(encoder); u32 sdvox; struct psb_intel_sdvo_in_out_map in_out; struct psb_intel_sdvo_dtd input_dtd; - int pixel_multiplier = psb_intel_mode_get_pixel_multiplier(adjusted_mode); int rate; + int need_aux = IS_MRST(dev) ? 1 : 0; if (!mode) return; @@ -1049,7 +1054,7 @@ static void psb_intel_sdvo_mode_set(struct drm_encoder *encoder, (void) psb_intel_sdvo_set_input_timing(psb_intel_sdvo, &input_dtd); - switch (pixel_multiplier) { + switch (psb_intel_sdvo->pixel_multiplier) { default: case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break; case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break; @@ -1059,7 +1064,11 @@ static void psb_intel_sdvo_mode_set(struct drm_encoder *encoder, return; /* Set the SDVO control regs. */ - sdvox = REG_READ(psb_intel_sdvo->sdvo_reg); + if (need_aux) + sdvox = REG_READ_AUX(psb_intel_sdvo->sdvo_reg); + else + sdvox = REG_READ(psb_intel_sdvo->sdvo_reg); + switch (psb_intel_sdvo->sdvo_reg) { case SDVOB: sdvox &= SDVOB_PRESERVE_MASK; @@ -1070,7 +1079,7 @@ static void psb_intel_sdvo_mode_set(struct drm_encoder *encoder, } sdvox |= (9 << 19) | SDVO_BORDER_ENABLE; - if (psb_intel_crtc->pipe == 1) + if (gma_crtc->pipe == 1) sdvox |= SDVO_PIPE_B_SELECT; if (psb_intel_sdvo->has_hdmi_audio) sdvox |= SDVO_AUDIO_ENABLE; @@ -1089,6 +1098,8 @@ static void psb_intel_sdvo_dpms(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct psb_intel_sdvo *psb_intel_sdvo = to_psb_intel_sdvo(encoder); u32 temp; + int i; + int need_aux = IS_MRST(dev) ? 1 : 0; switch (mode) { case DRM_MODE_DPMS_ON: @@ -1107,21 +1118,29 @@ static void psb_intel_sdvo_dpms(struct drm_encoder *encoder, int mode) psb_intel_sdvo_set_encoder_power_state(psb_intel_sdvo, mode); if (mode == DRM_MODE_DPMS_OFF) { - temp = REG_READ(psb_intel_sdvo->sdvo_reg); + if (need_aux) + temp = REG_READ_AUX(psb_intel_sdvo->sdvo_reg); + else + temp = REG_READ(psb_intel_sdvo->sdvo_reg); + if ((temp & SDVO_ENABLE) != 0) { psb_intel_sdvo_write_sdvox(psb_intel_sdvo, temp & ~SDVO_ENABLE); } } } else { bool input1, input2; - int i; u8 status; - temp = REG_READ(psb_intel_sdvo->sdvo_reg); + if (need_aux) + temp = REG_READ_AUX(psb_intel_sdvo->sdvo_reg); + else + temp = REG_READ(psb_intel_sdvo->sdvo_reg); + if ((temp & SDVO_ENABLE) == 0) psb_intel_sdvo_write_sdvox(psb_intel_sdvo, temp | SDVO_ENABLE); + for (i = 0; i < 2; i++) - psb_intel_wait_for_vblank(dev); + gma_wait_for_vblank(dev); status = psb_intel_sdvo_get_trained_inputs(psb_intel_sdvo, &input1, &input2); /* Warn if the device reported failure to sync. @@ -1140,8 +1159,8 @@ static void psb_intel_sdvo_dpms(struct drm_encoder *encoder, int mode) return; } -static int psb_intel_sdvo_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status psb_intel_sdvo_mode_valid(struct drm_connector *connector, + const struct drm_display_mode *mode) { struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector); @@ -1202,75 +1221,6 @@ static bool psb_intel_sdvo_get_capabilities(struct psb_intel_sdvo *psb_intel_sdv return true; } -/* No use! */ -#if 0 -struct drm_connector* psb_intel_sdvo_find(struct drm_device *dev, int sdvoB) -{ - struct drm_connector *connector = NULL; - struct psb_intel_sdvo *iout = NULL; - struct psb_intel_sdvo *sdvo; - - /* find the sdvo connector */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - iout = to_psb_intel_sdvo(connector); - - if (iout->type != INTEL_OUTPUT_SDVO) - continue; - - sdvo = iout->dev_priv; - - if (sdvo->sdvo_reg == SDVOB && sdvoB) - return connector; - - if (sdvo->sdvo_reg == SDVOC && !sdvoB) - return connector; - - } - - return NULL; -} - -int psb_intel_sdvo_supports_hotplug(struct drm_connector *connector) -{ - u8 response[2]; - u8 status; - struct psb_intel_sdvo *psb_intel_sdvo; - DRM_DEBUG_KMS("\n"); - - if (!connector) - return 0; - - psb_intel_sdvo = to_psb_intel_sdvo(connector); - - return psb_intel_sdvo_get_value(psb_intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, - &response, 2) && response[0]; -} - -void psb_intel_sdvo_set_hotplug(struct drm_connector *connector, int on) -{ - u8 response[2]; - u8 status; - struct psb_intel_sdvo *psb_intel_sdvo = to_psb_intel_sdvo(connector); - - psb_intel_sdvo_write_cmd(psb_intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); - psb_intel_sdvo_read_response(psb_intel_sdvo, &response, 2); - - if (on) { - psb_intel_sdvo_write_cmd(psb_intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); - status = psb_intel_sdvo_read_response(psb_intel_sdvo, &response, 2); - - psb_intel_sdvo_write_cmd(psb_intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); - } else { - response[0] = 0; - response[1] = 0; - psb_intel_sdvo_write_cmd(psb_intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); - } - - psb_intel_sdvo_write_cmd(psb_intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); - psb_intel_sdvo_read_response(psb_intel_sdvo, &response, 2); -} -#endif - static bool psb_intel_sdvo_multifunc_encoder(struct psb_intel_sdvo *psb_intel_sdvo) { @@ -1290,7 +1240,7 @@ psb_intel_sdvo_get_edid(struct drm_connector *connector) static struct edid * psb_intel_sdvo_get_analog_edid(struct drm_connector *connector) { - struct drm_psb_private *dev_priv = connector->dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(connector->dev); return drm_get_edid(connector, &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter); @@ -1448,7 +1398,7 @@ static void psb_intel_sdvo_get_ddc_modes(struct drm_connector *connector) bool connector_is_digital = !!IS_TMDS(psb_intel_sdvo_connector); if (connector_is_digital == monitor_is_digital) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); drm_add_edid_modes(connector, edid); } @@ -1559,7 +1509,7 @@ static void psb_intel_sdvo_get_tv_modes(struct drm_connector *connector) static void psb_intel_sdvo_get_lvds_modes(struct drm_connector *connector) { struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector); - struct drm_psb_private *dev_priv = connector->dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(connector->dev); struct drm_display_mode *newmode; /* @@ -1613,60 +1563,12 @@ static int psb_intel_sdvo_get_modes(struct drm_connector *connector) return !list_empty(&connector->probed_modes); } -static void -psb_intel_sdvo_destroy_enhance_property(struct drm_connector *connector) -{ - struct psb_intel_sdvo_connector *psb_intel_sdvo_connector = to_psb_intel_sdvo_connector(connector); - struct drm_device *dev = connector->dev; - - if (psb_intel_sdvo_connector->left) - drm_property_destroy(dev, psb_intel_sdvo_connector->left); - if (psb_intel_sdvo_connector->right) - drm_property_destroy(dev, psb_intel_sdvo_connector->right); - if (psb_intel_sdvo_connector->top) - drm_property_destroy(dev, psb_intel_sdvo_connector->top); - if (psb_intel_sdvo_connector->bottom) - drm_property_destroy(dev, psb_intel_sdvo_connector->bottom); - if (psb_intel_sdvo_connector->hpos) - drm_property_destroy(dev, psb_intel_sdvo_connector->hpos); - if (psb_intel_sdvo_connector->vpos) - drm_property_destroy(dev, psb_intel_sdvo_connector->vpos); - if (psb_intel_sdvo_connector->saturation) - drm_property_destroy(dev, psb_intel_sdvo_connector->saturation); - if (psb_intel_sdvo_connector->contrast) - drm_property_destroy(dev, psb_intel_sdvo_connector->contrast); - if (psb_intel_sdvo_connector->hue) - drm_property_destroy(dev, psb_intel_sdvo_connector->hue); - if (psb_intel_sdvo_connector->sharpness) - drm_property_destroy(dev, psb_intel_sdvo_connector->sharpness); - if (psb_intel_sdvo_connector->flicker_filter) - drm_property_destroy(dev, psb_intel_sdvo_connector->flicker_filter); - if (psb_intel_sdvo_connector->flicker_filter_2d) - drm_property_destroy(dev, psb_intel_sdvo_connector->flicker_filter_2d); - if (psb_intel_sdvo_connector->flicker_filter_adaptive) - drm_property_destroy(dev, psb_intel_sdvo_connector->flicker_filter_adaptive); - if (psb_intel_sdvo_connector->tv_luma_filter) - drm_property_destroy(dev, psb_intel_sdvo_connector->tv_luma_filter); - if (psb_intel_sdvo_connector->tv_chroma_filter) - drm_property_destroy(dev, psb_intel_sdvo_connector->tv_chroma_filter); - if (psb_intel_sdvo_connector->dot_crawl) - drm_property_destroy(dev, psb_intel_sdvo_connector->dot_crawl); - if (psb_intel_sdvo_connector->brightness) - drm_property_destroy(dev, psb_intel_sdvo_connector->brightness); -} - static void psb_intel_sdvo_destroy(struct drm_connector *connector) { - struct psb_intel_sdvo_connector *psb_intel_sdvo_connector = to_psb_intel_sdvo_connector(connector); + struct gma_connector *gma_connector = to_gma_connector(connector); - if (psb_intel_sdvo_connector->tv_format) - drm_property_destroy(connector->dev, - psb_intel_sdvo_connector->tv_format); - - psb_intel_sdvo_destroy_enhance_property(connector); - drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); - kfree(connector); + kfree(gma_connector); } static bool psb_intel_sdvo_detect_hdmi_audio(struct drm_connector *connector) @@ -1692,7 +1594,7 @@ psb_intel_sdvo_set_property(struct drm_connector *connector, { struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector); struct psb_intel_sdvo_connector *psb_intel_sdvo_connector = to_psb_intel_sdvo_connector(connector); - struct drm_psb_private *dev_priv = connector->dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(connector->dev); uint16_t temp_value; uint8_t cmd; int ret; @@ -1740,7 +1642,7 @@ psb_intel_sdvo_set_property(struct drm_connector *connector, } if (property == psb_intel_sdvo_connector->tv_format) { - if (val >= TV_FORMAT_NUM) + if (val >= ARRAY_SIZE(tv_format_names)) return -EINVAL; if (psb_intel_sdvo->tv_format_index == @@ -1826,7 +1728,7 @@ done: if (psb_intel_sdvo->base.base.crtc) { struct drm_crtc *crtc = psb_intel_sdvo->base.base.crtc; drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, - crtc->y, crtc->fb); + crtc->y, crtc->primary->fb); } return 0; @@ -1836,10 +1738,8 @@ done: static void psb_intel_sdvo_save(struct drm_connector *connector) { struct drm_device *dev = connector->dev; - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); - struct psb_intel_sdvo *sdvo = - to_psb_intel_sdvo(&psb_intel_encoder->base); + struct gma_encoder *gma_encoder = gma_attached_encoder(connector); + struct psb_intel_sdvo *sdvo = to_psb_intel_sdvo(&gma_encoder->base); sdvo->saveSDVO = REG_READ(sdvo->sdvo_reg); } @@ -1847,8 +1747,7 @@ static void psb_intel_sdvo_save(struct drm_connector *connector) static void psb_intel_sdvo_restore(struct drm_connector *connector) { struct drm_device *dev = connector->dev; - struct drm_encoder *encoder = - &psb_intel_attached_encoder(connector)->base; + struct drm_encoder *encoder = &gma_attached_encoder(connector)->base; struct psb_intel_sdvo *sdvo = to_psb_intel_sdvo(encoder); struct drm_crtc *crtc = encoder->crtc; @@ -1864,15 +1763,13 @@ static void psb_intel_sdvo_restore(struct drm_connector *connector) static const struct drm_encoder_helper_funcs psb_intel_sdvo_helper_funcs = { .dpms = psb_intel_sdvo_dpms, .mode_fixup = psb_intel_sdvo_mode_fixup, - .prepare = psb_intel_encoder_prepare, + .prepare = gma_encoder_prepare, .mode_set = psb_intel_sdvo_mode_set, - .commit = psb_intel_encoder_commit, + .commit = gma_encoder_commit, }; static const struct drm_connector_funcs psb_intel_sdvo_connector_funcs = { .dpms = drm_helper_connector_dpms, - .save = psb_intel_sdvo_save, - .restore = psb_intel_sdvo_restore, .detect = psb_intel_sdvo_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = psb_intel_sdvo_set_property, @@ -1882,7 +1779,7 @@ static const struct drm_connector_funcs psb_intel_sdvo_connector_funcs = { static const struct drm_connector_helper_funcs psb_intel_sdvo_connector_helper_funcs = { .get_modes = psb_intel_sdvo_get_modes, .mode_valid = psb_intel_sdvo_mode_valid, - .best_encoder = psb_intel_best_encoder, + .best_encoder = gma_best_encoder, }; static void psb_intel_sdvo_enc_destroy(struct drm_encoder *encoder) @@ -1894,7 +1791,7 @@ static void psb_intel_sdvo_enc_destroy(struct drm_encoder *encoder) psb_intel_sdvo->sdvo_lvds_fixed_mode); i2c_del_adapter(&psb_intel_sdvo->ddc); - psb_intel_encoder_destroy(encoder); + gma_encoder_destroy(encoder); } static const struct drm_encoder_funcs psb_intel_sdvo_enc_funcs = { @@ -1945,7 +1842,7 @@ psb_intel_sdvo_guess_ddc_bus(struct psb_intel_sdvo *sdvo) #endif } -/** +/* * Choose the appropriate DDC bus for control bus switch command for this * SDVO output based on the controlled output. * @@ -2003,9 +1900,9 @@ psb_intel_sdvo_is_hdmi_connector(struct psb_intel_sdvo *psb_intel_sdvo, int devi } static u8 -psb_intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg) +psb_intel_sdvo_get_target_addr(struct drm_device *dev, int sdvo_reg) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct sdvo_device_mapping *my_mapping, *other_mapping; if (IS_SDVOB(sdvo_reg)) { @@ -2017,14 +1914,14 @@ psb_intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg) } /* If the BIOS described our SDVO device, take advantage of it. */ - if (my_mapping->slave_addr) - return my_mapping->slave_addr; + if (my_mapping->target_addr) + return my_mapping->target_addr; /* If the BIOS only described a different SDVO device, use the * address that it isn't using. */ - if (other_mapping->slave_addr) { - if (other_mapping->slave_addr == 0x70) + if (other_mapping->target_addr) { + if (other_mapping->target_addr == 0x70) return 0x72; else return 0x70; @@ -2055,8 +1952,10 @@ psb_intel_sdvo_connector_init(struct psb_intel_sdvo_connector *connector, connector->base.base.doublescan_allowed = 0; connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB; - psb_intel_connector_attach_encoder(&connector->base, &encoder->base); - drm_sysfs_connector_add(&connector->base.base); + connector->base.save = psb_intel_sdvo_save; + connector->base.restore = psb_intel_sdvo_restore; + + gma_connector_attach_encoder(&connector->base, &encoder->base); } static void @@ -2075,7 +1974,7 @@ psb_intel_sdvo_dvi_init(struct psb_intel_sdvo *psb_intel_sdvo, int device) { struct drm_encoder *encoder = &psb_intel_sdvo->base.base; struct drm_connector *connector; - struct psb_intel_connector *intel_connector; + struct gma_connector *intel_connector; struct psb_intel_sdvo_connector *psb_intel_sdvo_connector; psb_intel_sdvo_connector = kzalloc(sizeof(struct psb_intel_sdvo_connector), GFP_KERNEL); @@ -2115,7 +2014,7 @@ psb_intel_sdvo_tv_init(struct psb_intel_sdvo *psb_intel_sdvo, int type) { struct drm_encoder *encoder = &psb_intel_sdvo->base.base; struct drm_connector *connector; - struct psb_intel_connector *intel_connector; + struct gma_connector *intel_connector; struct psb_intel_sdvo_connector *psb_intel_sdvo_connector; psb_intel_sdvo_connector = kzalloc(sizeof(struct psb_intel_sdvo_connector), GFP_KERNEL); @@ -2154,7 +2053,7 @@ psb_intel_sdvo_analog_init(struct psb_intel_sdvo *psb_intel_sdvo, int device) { struct drm_encoder *encoder = &psb_intel_sdvo->base.base; struct drm_connector *connector; - struct psb_intel_connector *intel_connector; + struct gma_connector *intel_connector; struct psb_intel_sdvo_connector *psb_intel_sdvo_connector; psb_intel_sdvo_connector = kzalloc(sizeof(struct psb_intel_sdvo_connector), GFP_KERNEL); @@ -2188,7 +2087,7 @@ psb_intel_sdvo_lvds_init(struct psb_intel_sdvo *psb_intel_sdvo, int device) { struct drm_encoder *encoder = &psb_intel_sdvo->base.base; struct drm_connector *connector; - struct psb_intel_connector *intel_connector; + struct gma_connector *intel_connector; struct psb_intel_sdvo_connector *psb_intel_sdvo_connector; psb_intel_sdvo_connector = kzalloc(sizeof(struct psb_intel_sdvo_connector), GFP_KERNEL); @@ -2302,7 +2201,7 @@ static bool psb_intel_sdvo_tv_create_property(struct psb_intel_sdvo *psb_intel_s return false; psb_intel_sdvo_connector->format_supported_num = 0; - for (i = 0 ; i < TV_FORMAT_NUM; i++) + for (i = 0 ; i < ARRAY_SIZE(tv_format_names); i++) if (format_map & (1 << i)) psb_intel_sdvo_connector->tv_format_supported[psb_intel_sdvo_connector->format_supported_num++] = i; @@ -2315,7 +2214,7 @@ static bool psb_intel_sdvo_tv_create_property(struct psb_intel_sdvo *psb_intel_s for (i = 0; i < psb_intel_sdvo_connector->format_supported_num; i++) drm_property_add_enum( - psb_intel_sdvo_connector->tv_format, i, + psb_intel_sdvo_connector->tv_format, i, tv_format_names[psb_intel_sdvo_connector->tv_format_supported[i]]); psb_intel_sdvo->tv_format_index = psb_intel_sdvo_connector->tv_format_supported[0]; @@ -2528,9 +2427,8 @@ psb_intel_sdvo_init_ddc_proxy(struct psb_intel_sdvo *sdvo, struct drm_device *dev) { sdvo->ddc.owner = THIS_MODULE; - sdvo->ddc.class = I2C_CLASS_DDC; snprintf(sdvo->ddc.name, I2C_NAME_SIZE, "SDVO DDC proxy"); - sdvo->ddc.dev.parent = &dev->pdev->dev; + sdvo->ddc.dev.parent = dev->dev; sdvo->ddc.algo_data = sdvo; sdvo->ddc.algo = &psb_intel_sdvo_ddc_proxy; @@ -2539,8 +2437,8 @@ psb_intel_sdvo_init_ddc_proxy(struct psb_intel_sdvo *sdvo, bool psb_intel_sdvo_init(struct drm_device *dev, int sdvo_reg) { - struct drm_psb_private *dev_priv = dev->dev_private; - struct psb_intel_encoder *psb_intel_encoder; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_encoder *gma_encoder; struct psb_intel_sdvo *psb_intel_sdvo; int i; @@ -2549,7 +2447,7 @@ bool psb_intel_sdvo_init(struct drm_device *dev, int sdvo_reg) return false; psb_intel_sdvo->sdvo_reg = sdvo_reg; - psb_intel_sdvo->slave_addr = psb_intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1; + psb_intel_sdvo->target_addr = psb_intel_sdvo_get_target_addr(dev, sdvo_reg) >> 1; psb_intel_sdvo_select_i2c_bus(dev_priv, psb_intel_sdvo, sdvo_reg); if (!psb_intel_sdvo_init_ddc_proxy(psb_intel_sdvo, dev)) { kfree(psb_intel_sdvo); @@ -2557,9 +2455,10 @@ bool psb_intel_sdvo_init(struct drm_device *dev, int sdvo_reg) } /* encoder type will be decided later */ - psb_intel_encoder = &psb_intel_sdvo->base; - psb_intel_encoder->type = INTEL_OUTPUT_SDVO; - drm_encoder_init(dev, &psb_intel_encoder->base, &psb_intel_sdvo_enc_funcs, 0); + gma_encoder = &psb_intel_sdvo->base; + gma_encoder->type = INTEL_OUTPUT_SDVO; + drm_encoder_init(dev, &gma_encoder->base, &psb_intel_sdvo_enc_funcs, + 0, NULL); /* Read the regs to test if we can talk to the device */ for (i = 0; i < 0x40; i++) { @@ -2577,7 +2476,7 @@ bool psb_intel_sdvo_init(struct drm_device *dev, int sdvo_reg) else dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS; - drm_encoder_helper_add(&psb_intel_encoder->base, &psb_intel_sdvo_helper_funcs); + drm_encoder_helper_add(&gma_encoder->base, &psb_intel_sdvo_helper_funcs); /* In default case sdvo lvds is false */ if (!psb_intel_sdvo_get_capabilities(psb_intel_sdvo, &psb_intel_sdvo->caps)) @@ -2620,7 +2519,7 @@ bool psb_intel_sdvo_init(struct drm_device *dev, int sdvo_reg) return true; err: - drm_encoder_cleanup(&psb_intel_encoder->base); + drm_encoder_cleanup(&gma_encoder->base); i2c_del_adapter(&psb_intel_sdvo->ddc); kfree(psb_intel_sdvo); diff --git a/drivers/gpu/drm/gma500/psb_irq.c b/drivers/gpu/drm/gma500/psb_irq.c index 029eccf30137..3a946b472064 100644 --- a/drivers/gpu/drm/gma500/psb_irq.c +++ b/drivers/gpu/drm/gma500/psb_irq.c @@ -1,41 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-only /************************************************************************** * Copyright (c) 2007, 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. - * * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to * develop this driver. * **************************************************************************/ -/* - */ -#include <drm/drmP.h> +#include <drm/drm_drv.h> +#include <drm/drm_print.h> +#include <drm/drm_vblank.h> + +#include "power.h" #include "psb_drv.h" -#include "psb_reg.h" #include "psb_intel_reg.h" -#include "power.h" #include "psb_irq.h" -#include "mdfld_output.h" +#include "psb_reg.h" /* * inline functions */ -static inline u32 -psb_pipestat(int pipe) +static inline u32 gma_pipestat(int pipe) { if (pipe == 0) return PIPEASTAT; @@ -46,32 +33,7 @@ psb_pipestat(int pipe) BUG(); } -static inline u32 -mid_pipe_event(int pipe) -{ - if (pipe == 0) - return _PSB_PIPEA_EVENT_FLAG; - if (pipe == 1) - return _MDFLD_PIPEB_EVENT_FLAG; - if (pipe == 2) - return _MDFLD_PIPEC_EVENT_FLAG; - BUG(); -} - -static inline u32 -mid_pipe_vsync(int pipe) -{ - if (pipe == 0) - return _PSB_VSYNC_PIPEA_FLAG; - if (pipe == 1) - return _PSB_VSYNC_PIPEB_FLAG; - if (pipe == 2) - return _MDFLD_PIPEC_VBLANK_FLAG; - BUG(); -} - -static inline u32 -mid_pipeconf(int pipe) +static inline u32 gma_pipeconf(int pipe) { if (pipe == 0) return PIPEACONF; @@ -82,74 +44,46 @@ mid_pipeconf(int pipe) BUG(); } -void -psb_enable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask) +void gma_enable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask) { if ((dev_priv->pipestat[pipe] & mask) != mask) { - u32 reg = psb_pipestat(pipe); + u32 reg = gma_pipestat(pipe); dev_priv->pipestat[pipe] |= mask; /* Enable the interrupt, clear any pending status */ - if (gma_power_begin(dev_priv->dev, false)) { + if (gma_power_begin(&dev_priv->dev, false)) { u32 writeVal = PSB_RVDC32(reg); writeVal |= (mask | (mask >> 16)); PSB_WVDC32(writeVal, reg); (void) PSB_RVDC32(reg); - gma_power_end(dev_priv->dev); + gma_power_end(&dev_priv->dev); } } } -void -psb_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask) +void gma_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask) { if ((dev_priv->pipestat[pipe] & mask) != 0) { - u32 reg = psb_pipestat(pipe); + u32 reg = gma_pipestat(pipe); dev_priv->pipestat[pipe] &= ~mask; - if (gma_power_begin(dev_priv->dev, false)) { + if (gma_power_begin(&dev_priv->dev, false)) { u32 writeVal = PSB_RVDC32(reg); writeVal &= ~mask; PSB_WVDC32(writeVal, reg); (void) PSB_RVDC32(reg); - gma_power_end(dev_priv->dev); + gma_power_end(&dev_priv->dev); } } } -static void mid_enable_pipe_event(struct drm_psb_private *dev_priv, int pipe) -{ - if (gma_power_begin(dev_priv->dev, false)) { - u32 pipe_event = mid_pipe_event(pipe); - dev_priv->vdc_irq_mask |= pipe_event; - PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R); - PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R); - gma_power_end(dev_priv->dev); - } -} - -static void mid_disable_pipe_event(struct drm_psb_private *dev_priv, int pipe) -{ - if (dev_priv->pipestat[pipe] == 0) { - if (gma_power_begin(dev_priv->dev, false)) { - u32 pipe_event = mid_pipe_event(pipe); - dev_priv->vdc_irq_mask &= ~pipe_event; - PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R); - PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R); - gma_power_end(dev_priv->dev); - } - } -} - -/** +/* * Display controller interrupt handler for pipe event. - * */ -static void mid_pipe_event_handler(struct drm_device *dev, int pipe) +static void gma_pipe_event_handler(struct drm_device *dev, int pipe) { - struct drm_psb_private *dev_priv = - (struct drm_psb_private *) dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); uint32_t pipe_stat_val = 0; - uint32_t pipe_stat_reg = psb_pipestat(pipe); + uint32_t pipe_stat_reg = gma_pipestat(pipe); uint32_t pipe_enable = dev_priv->pipestat[pipe]; uint32_t pipe_status = dev_priv->pipestat[pipe] >> 16; uint32_t pipe_clear; @@ -178,33 +112,95 @@ static void mid_pipe_event_handler(struct drm_device *dev, int pipe) "%s, can't clear status bits for pipe %d, its value = 0x%x.\n", __func__, pipe, PSB_RVDC32(pipe_stat_reg)); - if (pipe_stat_val & PIPE_VBLANK_STATUS) - drm_handle_vblank(dev, pipe); + if (pipe_stat_val & PIPE_VBLANK_STATUS) { + struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + unsigned long flags; - if (pipe_stat_val & PIPE_TE_STATUS) drm_handle_vblank(dev, pipe); + + spin_lock_irqsave(&dev->event_lock, flags); + if (gma_crtc->page_flip_event) { + drm_crtc_send_vblank_event(crtc, + gma_crtc->page_flip_event); + gma_crtc->page_flip_event = NULL; + drm_crtc_vblank_put(crtc); + } + spin_unlock_irqrestore(&dev->event_lock, flags); + } } /* * Display controller interrupt handler. */ -static void psb_vdc_interrupt(struct drm_device *dev, uint32_t vdc_stat) +static void gma_vdc_interrupt(struct drm_device *dev, uint32_t vdc_stat) { if (vdc_stat & _PSB_IRQ_ASLE) psb_intel_opregion_asle_intr(dev); if (vdc_stat & _PSB_VSYNC_PIPEA_FLAG) - mid_pipe_event_handler(dev, 0); + gma_pipe_event_handler(dev, 0); if (vdc_stat & _PSB_VSYNC_PIPEB_FLAG) - mid_pipe_event_handler(dev, 1); + gma_pipe_event_handler(dev, 1); } -irqreturn_t psb_irq_handler(DRM_IRQ_ARGS) +/* + * SGX interrupt handler + */ +static void gma_sgx_interrupt(struct drm_device *dev, u32 stat_1, u32 stat_2) +{ + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + u32 val, addr; + + if (stat_1 & _PSB_CE_TWOD_COMPLETE) + val = PSB_RSGX32(PSB_CR_2D_BLIT_STATUS); + + if (stat_2 & _PSB_CE2_BIF_REQUESTER_FAULT) { + val = PSB_RSGX32(PSB_CR_BIF_INT_STAT); + addr = PSB_RSGX32(PSB_CR_BIF_FAULT); + if (val) { + if (val & _PSB_CBI_STAT_PF_N_RW) + DRM_ERROR("SGX MMU page fault:"); + else + DRM_ERROR("SGX MMU read / write protection fault:"); + + if (val & _PSB_CBI_STAT_FAULT_CACHE) + DRM_ERROR("\tCache requestor"); + if (val & _PSB_CBI_STAT_FAULT_TA) + DRM_ERROR("\tTA requestor"); + if (val & _PSB_CBI_STAT_FAULT_VDM) + DRM_ERROR("\tVDM requestor"); + if (val & _PSB_CBI_STAT_FAULT_2D) + DRM_ERROR("\t2D requestor"); + if (val & _PSB_CBI_STAT_FAULT_PBE) + DRM_ERROR("\tPBE requestor"); + if (val & _PSB_CBI_STAT_FAULT_TSP) + DRM_ERROR("\tTSP requestor"); + if (val & _PSB_CBI_STAT_FAULT_ISP) + DRM_ERROR("\tISP requestor"); + if (val & _PSB_CBI_STAT_FAULT_USSEPDS) + DRM_ERROR("\tUSSEPDS requestor"); + if (val & _PSB_CBI_STAT_FAULT_HOST) + DRM_ERROR("\tHost requestor"); + + DRM_ERROR("\tMMU failing address is 0x%08x.\n", + (unsigned int)addr); + } + } + + /* Clear bits */ + PSB_WSGX32(stat_1, PSB_CR_EVENT_HOST_CLEAR); + PSB_WSGX32(stat_2, PSB_CR_EVENT_HOST_CLEAR2); + PSB_RSGX32(PSB_CR_EVENT_HOST_CLEAR2); +} + +static irqreturn_t gma_irq_handler(int irq, void *arg) { struct drm_device *dev = arg; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); uint32_t vdc_stat, dsp_int = 0, sgx_int = 0, hotplug_int = 0; + u32 sgx_stat_1, sgx_stat_2; int handled = 0; spin_lock(&dev_priv->irqmask_lock); @@ -214,11 +210,6 @@ irqreturn_t psb_irq_handler(DRM_IRQ_ARGS) if (vdc_stat & (_PSB_PIPE_EVENT_FLAG|_PSB_IRQ_ASLE)) dsp_int = 1; - /* FIXME: Handle Medfield - if (vdc_stat & _MDFLD_DISP_ALL_IRQ_FLAG) - dsp_int = 1; - */ - if (vdc_stat & _PSB_IRQ_SGX_FLAG) sgx_int = 1; if (vdc_stat & _PSB_IRQ_DISP_HOTSYNC) @@ -227,20 +218,15 @@ irqreturn_t psb_irq_handler(DRM_IRQ_ARGS) vdc_stat &= dev_priv->vdc_irq_mask; spin_unlock(&dev_priv->irqmask_lock); - if (dsp_int && gma_power_is_on(dev)) { - psb_vdc_interrupt(dev, vdc_stat); + if (dsp_int) { + gma_vdc_interrupt(dev, vdc_stat); handled = 1; } if (sgx_int) { - /* Not expected - we have it masked, shut it up */ - u32 s, s2; - s = PSB_RSGX32(PSB_CR_EVENT_STATUS); - s2 = PSB_RSGX32(PSB_CR_EVENT_STATUS2); - PSB_WSGX32(s, PSB_CR_EVENT_HOST_CLEAR); - PSB_WSGX32(s2, PSB_CR_EVENT_HOST_CLEAR2); - /* if s & _PSB_CE_TWOD_COMPLETE we have 2D done but - we may as well poll even if we add that ! */ + sgx_stat_1 = PSB_RSGX32(PSB_CR_EVENT_STATUS); + sgx_stat_2 = PSB_RSGX32(PSB_CR_EVENT_STATUS2); + gma_sgx_interrupt(dev, sgx_stat_1, sgx_stat_2); handled = 1; } @@ -253,7 +239,7 @@ irqreturn_t psb_irq_handler(DRM_IRQ_ARGS) PSB_WVDC32(vdc_stat, PSB_INT_IDENTITY_R); (void) PSB_RVDC32(PSB_INT_IDENTITY_R); - DRM_READMEMORYBARRIER(); + rmb(); if (!handled) return IRQ_NONE; @@ -261,77 +247,110 @@ irqreturn_t psb_irq_handler(DRM_IRQ_ARGS) return IRQ_HANDLED; } -void psb_irq_preinstall(struct drm_device *dev) +void gma_irq_preinstall(struct drm_device *dev) { - struct drm_psb_private *dev_priv = - (struct drm_psb_private *) dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct drm_crtc *crtc; unsigned long irqflags; spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); - if (gma_power_is_on(dev)) - PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM); - if (dev->vblank_enabled[0]) - dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEA_FLAG; - if (dev->vblank_enabled[1]) - dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEB_FLAG; - - /* FIXME: Handle Medfield irq mask - if (dev->vblank_enabled[1]) - dev_priv->vdc_irq_mask |= _MDFLD_PIPEB_EVENT_FLAG; - if (dev->vblank_enabled[2]) - dev_priv->vdc_irq_mask |= _MDFLD_PIPEC_EVENT_FLAG; - */ + PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM); + PSB_WVDC32(0x00000000, PSB_INT_MASK_R); + PSB_WVDC32(0x00000000, PSB_INT_ENABLE_R); + PSB_WSGX32(0x00000000, PSB_CR_EVENT_HOST_ENABLE); + PSB_RSGX32(PSB_CR_EVENT_HOST_ENABLE); + + drm_for_each_crtc(crtc, dev) { + struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); + + if (vblank->enabled) { + u32 mask = drm_crtc_index(crtc) ? _PSB_VSYNC_PIPEB_FLAG : + _PSB_VSYNC_PIPEA_FLAG; + dev_priv->vdc_irq_mask |= mask; + } + } /* Revisit this area - want per device masks ? */ if (dev_priv->ops->hotplug) dev_priv->vdc_irq_mask |= _PSB_IRQ_DISP_HOTSYNC; - dev_priv->vdc_irq_mask |= _PSB_IRQ_ASLE; + dev_priv->vdc_irq_mask |= _PSB_IRQ_ASLE | _PSB_IRQ_SGX_FLAG; /* This register is safe even if display island is off */ PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R); spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); } -int psb_irq_postinstall(struct drm_device *dev) +void gma_irq_postinstall(struct drm_device *dev) { - struct drm_psb_private *dev_priv = - (struct drm_psb_private *) dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct drm_crtc *crtc; unsigned long irqflags; spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); + /* Enable 2D and MMU fault interrupts */ + PSB_WSGX32(_PSB_CE2_BIF_REQUESTER_FAULT, PSB_CR_EVENT_HOST_ENABLE2); + PSB_WSGX32(_PSB_CE_TWOD_COMPLETE, PSB_CR_EVENT_HOST_ENABLE); + PSB_RSGX32(PSB_CR_EVENT_HOST_ENABLE); /* Post */ + /* This register is safe even if display island is off */ PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R); PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM); - if (dev->vblank_enabled[0]) - psb_enable_pipestat(dev_priv, 0, PIPE_VBLANK_INTERRUPT_ENABLE); - else - psb_disable_pipestat(dev_priv, 0, PIPE_VBLANK_INTERRUPT_ENABLE); - - if (dev->vblank_enabled[1]) - psb_enable_pipestat(dev_priv, 1, PIPE_VBLANK_INTERRUPT_ENABLE); - else - psb_disable_pipestat(dev_priv, 1, PIPE_VBLANK_INTERRUPT_ENABLE); + drm_for_each_crtc(crtc, dev) { + struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); - if (dev->vblank_enabled[2]) - psb_enable_pipestat(dev_priv, 2, PIPE_VBLANK_INTERRUPT_ENABLE); - else - psb_disable_pipestat(dev_priv, 2, PIPE_VBLANK_INTERRUPT_ENABLE); + if (vblank->enabled) + gma_enable_pipestat(dev_priv, drm_crtc_index(crtc), PIPE_VBLANK_INTERRUPT_ENABLE); + else + gma_disable_pipestat(dev_priv, drm_crtc_index(crtc), PIPE_VBLANK_INTERRUPT_ENABLE); + } if (dev_priv->ops->hotplug_enable) dev_priv->ops->hotplug_enable(dev, true); spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); +} + +int gma_irq_install(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct pci_dev *pdev = to_pci_dev(dev->dev); + int ret; + + if (dev_priv->use_msi && pci_enable_msi(pdev)) { + dev_warn(dev->dev, "Enabling MSI failed!\n"); + dev_priv->use_msi = false; + } + + if (pdev->irq == IRQ_NOTCONNECTED) + return -ENOTCONN; + + gma_irq_preinstall(dev); + + /* PCI devices require shared interrupts. */ + ret = request_irq(pdev->irq, gma_irq_handler, IRQF_SHARED, dev->driver->name, dev); + if (ret) + return ret; + + gma_irq_postinstall(dev); + + dev_priv->irq_enabled = true; + return 0; } -void psb_irq_uninstall(struct drm_device *dev) +void gma_irq_uninstall(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct pci_dev *pdev = to_pci_dev(dev->dev); + struct drm_crtc *crtc; unsigned long irqflags; + if (!dev_priv->irq_enabled) + return; + spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); if (dev_priv->ops->hotplug_enable) @@ -339,14 +358,12 @@ void psb_irq_uninstall(struct drm_device *dev) PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM); - if (dev->vblank_enabled[0]) - psb_disable_pipestat(dev_priv, 0, PIPE_VBLANK_INTERRUPT_ENABLE); - - if (dev->vblank_enabled[1]) - psb_disable_pipestat(dev_priv, 1, PIPE_VBLANK_INTERRUPT_ENABLE); + drm_for_each_crtc(crtc, dev) { + struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); - if (dev->vblank_enabled[2]) - psb_disable_pipestat(dev_priv, 2, PIPE_VBLANK_INTERRUPT_ENABLE); + if (vblank->enabled) + gma_disable_pipestat(dev_priv, drm_crtc_index(crtc), PIPE_VBLANK_INTERRUPT_ENABLE); + } dev_priv->vdc_irq_mask &= _PSB_IRQ_SGX_FLAG | _PSB_IRQ_MSVDX_FLAG | @@ -361,124 +378,20 @@ void psb_irq_uninstall(struct drm_device *dev) /* This register is safe even if display island is off */ PSB_WVDC32(PSB_RVDC32(PSB_INT_IDENTITY_R), PSB_INT_IDENTITY_R); spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); -} - -void psb_irq_turn_on_dpst(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv = - (struct drm_psb_private *) dev->dev_private; - u32 hist_reg; - u32 pwm_reg; - - if (gma_power_begin(dev, false)) { - PSB_WVDC32(1 << 31, HISTOGRAM_LOGIC_CONTROL); - hist_reg = PSB_RVDC32(HISTOGRAM_LOGIC_CONTROL); - PSB_WVDC32(1 << 31, HISTOGRAM_INT_CONTROL); - hist_reg = PSB_RVDC32(HISTOGRAM_INT_CONTROL); - - PSB_WVDC32(0x80010100, PWM_CONTROL_LOGIC); - pwm_reg = PSB_RVDC32(PWM_CONTROL_LOGIC); - PSB_WVDC32(pwm_reg | PWM_PHASEIN_ENABLE - | PWM_PHASEIN_INT_ENABLE, - PWM_CONTROL_LOGIC); - pwm_reg = PSB_RVDC32(PWM_CONTROL_LOGIC); - - psb_enable_pipestat(dev_priv, 0, PIPE_DPST_EVENT_ENABLE); - - hist_reg = PSB_RVDC32(HISTOGRAM_INT_CONTROL); - PSB_WVDC32(hist_reg | HISTOGRAM_INT_CTRL_CLEAR, - HISTOGRAM_INT_CONTROL); - pwm_reg = PSB_RVDC32(PWM_CONTROL_LOGIC); - PSB_WVDC32(pwm_reg | 0x80010100 | PWM_PHASEIN_ENABLE, - PWM_CONTROL_LOGIC); - gma_power_end(dev); - } + free_irq(pdev->irq, dev); + if (dev_priv->use_msi) + pci_disable_msi(pdev); } -int psb_irq_enable_dpst(struct drm_device *dev) +int gma_crtc_enable_vblank(struct drm_crtc *crtc) { - struct drm_psb_private *dev_priv = - (struct drm_psb_private *) dev->dev_private; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); - - /* enable DPST */ - mid_enable_pipe_event(dev_priv, 0); - psb_irq_turn_on_dpst(dev); - - spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); - return 0; -} - -void psb_irq_turn_off_dpst(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv = - (struct drm_psb_private *) dev->dev_private; - u32 hist_reg; - u32 pwm_reg; - - if (gma_power_begin(dev, false)) { - PSB_WVDC32(0x00000000, HISTOGRAM_INT_CONTROL); - hist_reg = PSB_RVDC32(HISTOGRAM_INT_CONTROL); - - psb_disable_pipestat(dev_priv, 0, PIPE_DPST_EVENT_ENABLE); - - pwm_reg = PSB_RVDC32(PWM_CONTROL_LOGIC); - PSB_WVDC32(pwm_reg & ~PWM_PHASEIN_INT_ENABLE, - PWM_CONTROL_LOGIC); - pwm_reg = PSB_RVDC32(PWM_CONTROL_LOGIC); - - gma_power_end(dev); - } -} - -int psb_irq_disable_dpst(struct drm_device *dev) -{ - struct drm_psb_private *dev_priv = - (struct drm_psb_private *) dev->dev_private; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); - - mid_disable_pipe_event(dev_priv, 0); - psb_irq_turn_off_dpst(dev); - - spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); - - return 0; -} - -#ifdef PSB_FIXME -static int psb_vblank_do_wait(struct drm_device *dev, - unsigned int *sequence, atomic_t *counter) -{ - unsigned int cur_vblank; - int ret = 0; - DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, - (((cur_vblank = atomic_read(counter)) - - *sequence) <= (1 << 23))); - *sequence = cur_vblank; - - return ret; -} -#endif - -/* - * It is used to enable VBLANK interrupt - */ -int psb_enable_vblank(struct drm_device *dev, int pipe) -{ - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_device *dev = crtc->dev; + unsigned int pipe = crtc->index; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); unsigned long irqflags; uint32_t reg_val = 0; - uint32_t pipeconf_reg = mid_pipeconf(pipe); - - /* Medfield is different - we should perhaps extract out vblank - and blacklight etc ops */ - if (IS_MFLD(dev)) - return mdfld_enable_te(dev, pipe); + uint32_t pipeconf_reg = gma_pipeconf(pipe); if (gma_power_begin(dev, false)) { reg_val = REG_READ(pipeconf_reg); @@ -497,23 +410,20 @@ int psb_enable_vblank(struct drm_device *dev, int pipe) PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R); PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R); - psb_enable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_ENABLE); + gma_enable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_ENABLE); spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); return 0; } -/* - * It is used to disable VBLANK interrupt - */ -void psb_disable_vblank(struct drm_device *dev, int pipe) +void gma_crtc_disable_vblank(struct drm_crtc *crtc) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_device *dev = crtc->dev; + unsigned int pipe = crtc->index; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); unsigned long irqflags; - if (IS_MFLD(dev)) - mdfld_disable_te(dev, pipe); spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); if (pipe == 0) @@ -523,56 +433,7 @@ void psb_disable_vblank(struct drm_device *dev, int pipe) PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R); PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R); - psb_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_ENABLE); - - spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); -} - -/* - * It is used to enable TE interrupt - */ -int mdfld_enable_te(struct drm_device *dev, int pipe) -{ - struct drm_psb_private *dev_priv = - (struct drm_psb_private *) dev->dev_private; - unsigned long irqflags; - uint32_t reg_val = 0; - uint32_t pipeconf_reg = mid_pipeconf(pipe); - - if (gma_power_begin(dev, false)) { - reg_val = REG_READ(pipeconf_reg); - gma_power_end(dev); - } - - if (!(reg_val & PIPEACONF_ENABLE)) - return -EINVAL; - - spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); - - mid_enable_pipe_event(dev_priv, pipe); - psb_enable_pipestat(dev_priv, pipe, PIPE_TE_ENABLE); - - spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); - - return 0; -} - -/* - * It is used to disable TE interrupt - */ -void mdfld_disable_te(struct drm_device *dev, int pipe) -{ - struct drm_psb_private *dev_priv = - (struct drm_psb_private *) dev->dev_private; - unsigned long irqflags; - - if (!dev_priv->dsr_enable) - return; - - spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); - - mid_disable_pipe_event(dev_priv, pipe); - psb_disable_pipestat(dev_priv, pipe, PIPE_TE_ENABLE); + gma_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_ENABLE); spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); } @@ -580,8 +441,10 @@ void mdfld_disable_te(struct drm_device *dev, int pipe) /* Called from drm generic code, passed a 'crtc', which * we use as a pipe index */ -u32 psb_get_vblank_counter(struct drm_device *dev, int pipe) +u32 gma_crtc_get_vblank_counter(struct drm_crtc *crtc) { + struct drm_device *dev = crtc->dev; + unsigned int pipe = crtc->index; uint32_t high_frame = PIPEAFRAMEHIGH; uint32_t low_frame = PIPEAFRAMEPIXEL; uint32_t pipeconf_reg = PIPEACONF; @@ -612,9 +475,9 @@ u32 psb_get_vblank_counter(struct drm_device *dev, int pipe) reg_val = REG_READ(pipeconf_reg); if (!(reg_val & PIPEACONF_ENABLE)) { - dev_err(dev->dev, "trying to get vblank count for disabled pipe %d\n", - pipe); - goto psb_get_vblank_counter_exit; + dev_err(dev->dev, "trying to get vblank count for disabled pipe %u\n", + pipe); + goto err_gma_power_end; } /* @@ -633,8 +496,7 @@ u32 psb_get_vblank_counter(struct drm_device *dev, int pipe) count = (high1 << 8) | low; -psb_get_vblank_counter_exit: - +err_gma_power_end: gma_power_end(dev); return count; diff --git a/drivers/gpu/drm/gma500/psb_irq.h b/drivers/gpu/drm/gma500/psb_irq.h index debb7f190c06..7648f69824a5 100644 --- a/drivers/gpu/drm/gma500/psb_irq.h +++ b/drivers/gpu/drm/gma500/psb_irq.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /************************************************************************** * Copyright (c) 2009-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. - * * Authors: * Benjamin Defnet <benjamin.r.defnet@intel.com> * Rajesh Poornachandran <rajesh.poornachandran@intel.com> @@ -24,24 +12,18 @@ #ifndef _PSB_IRQ_H_ #define _PSB_IRQ_H_ -#include <drm/drmP.h> - -bool sysirq_init(struct drm_device *dev); -void sysirq_uninit(struct drm_device *dev); +struct drm_crtc; +struct drm_device; -void psb_irq_preinstall(struct drm_device *dev); -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 gma_irq_preinstall(struct drm_device *dev); +void gma_irq_postinstall(struct drm_device *dev); +int gma_irq_install(struct drm_device *dev); +void gma_irq_uninstall(struct drm_device *dev); -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); -void psb_irq_turn_off_dpst(struct drm_device *dev); -int psb_enable_vblank(struct drm_device *dev, int pipe); -void psb_disable_vblank(struct drm_device *dev, int pipe); -u32 psb_get_vblank_counter(struct drm_device *dev, int pipe); +int gma_crtc_enable_vblank(struct drm_crtc *crtc); +void gma_crtc_disable_vblank(struct drm_crtc *crtc); +u32 gma_crtc_get_vblank_counter(struct drm_crtc *crtc); +void gma_enable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask); +void gma_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask); -int mdfld_enable_te(struct drm_device *dev, int pipe); -void mdfld_disable_te(struct drm_device *dev, int pipe); #endif /* _PSB_IRQ_H_ */ diff --git a/drivers/gpu/drm/gma500/psb_lid.c b/drivers/gpu/drm/gma500/psb_lid.c deleted file mode 100644 index 1d2ebb5e530f..000000000000 --- a/drivers/gpu/drm/gma500/psb_lid.c +++ /dev/null @@ -1,94 +0,0 @@ -/************************************************************************** - * Copyright (c) 2007, 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: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> - **************************************************************************/ - -#include <drm/drmP.h> -#include "psb_drv.h" -#include "psb_reg.h" -#include "psb_intel_reg.h" -#include <linux/spinlock.h> - -static void psb_lid_timer_func(unsigned long data) -{ - struct drm_psb_private * dev_priv = (struct drm_psb_private *)data; - struct drm_device *dev = (struct drm_device *)dev_priv->dev; - struct timer_list *lid_timer = &dev_priv->lid_timer; - unsigned long irq_flags; - u32 __iomem *lid_state = dev_priv->opregion.lid_state; - u32 pp_status; - - if (readl(lid_state) == dev_priv->lid_last_state) - goto lid_timer_schedule; - - if ((readl(lid_state)) & 0x01) { - /*lid state is open*/ - REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) | POWER_TARGET_ON); - do { - pp_status = REG_READ(PP_STATUS); - } while ((pp_status & PP_ON) == 0 && - (pp_status & PP_SEQUENCE_MASK) != 0); - - if (REG_READ(PP_STATUS) & PP_ON) { - /*FIXME: should be backlight level before*/ - psb_intel_lvds_set_brightness(dev, 100); - } else { - DRM_DEBUG("LVDS panel never powered up"); - return; - } - } else { - psb_intel_lvds_set_brightness(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) == 0); - } - dev_priv->lid_last_state = readl(lid_state); - -lid_timer_schedule: - spin_lock_irqsave(&dev_priv->lid_lock, irq_flags); - if (!timer_pending(lid_timer)) { - lid_timer->expires = jiffies + PSB_LID_DELAY; - add_timer(lid_timer); - } - spin_unlock_irqrestore(&dev_priv->lid_lock, irq_flags); -} - -void psb_lid_timer_init(struct drm_psb_private *dev_priv) -{ - struct timer_list *lid_timer = &dev_priv->lid_timer; - unsigned long irq_flags; - - spin_lock_init(&dev_priv->lid_lock); - spin_lock_irqsave(&dev_priv->lid_lock, irq_flags); - - init_timer(lid_timer); - - lid_timer->data = (unsigned long)dev_priv; - lid_timer->function = psb_lid_timer_func; - lid_timer->expires = jiffies + PSB_LID_DELAY; - - add_timer(lid_timer); - spin_unlock_irqrestore(&dev_priv->lid_lock, irq_flags); -} - -void psb_lid_timer_takedown(struct drm_psb_private *dev_priv) -{ - del_timer_sync(&dev_priv->lid_timer); -} - diff --git a/drivers/gpu/drm/gma500/psb_reg.h b/drivers/gpu/drm/gma500/psb_reg.h index b81c7c1e9c2d..2a229a0ef36c 100644 --- a/drivers/gpu/drm/gma500/psb_reg.h +++ b/drivers/gpu/drm/gma500/psb_reg.h @@ -1,22 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /************************************************************************** * * Copyright (c) (2005-2007) Imagination Technologies Limited. * Copyright (c) 2007, 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.. - * **************************************************************************/ #ifndef _PSB_REG_H_ @@ -562,21 +550,7 @@ #define PSB_PM_SSC 0x20 #define PSB_PM_SSS 0x30 #define PSB_PWRGT_DISPLAY_MASK 0xc /*on a different BA than video/gfx*/ -#define MDFLD_PWRGT_DISPLAY_A_CNTR 0x0000000c -#define MDFLD_PWRGT_DISPLAY_B_CNTR 0x0000c000 -#define MDFLD_PWRGT_DISPLAY_C_CNTR 0x00030000 -#define MDFLD_PWRGT_DISP_MIPI_CNTR 0x000c0000 -#define MDFLD_PWRGT_DISPLAY_CNTR (MDFLD_PWRGT_DISPLAY_A_CNTR | MDFLD_PWRGT_DISPLAY_B_CNTR | MDFLD_PWRGT_DISPLAY_C_CNTR | MDFLD_PWRGT_DISP_MIPI_CNTR) /* 0x000fc00c */ /* Display SSS register bits are different in A0 vs. B0 */ #define PSB_PWRGT_GFX_MASK 0x3 -#define MDFLD_PWRGT_DISPLAY_A_STS 0x000000c0 -#define MDFLD_PWRGT_DISPLAY_B_STS 0x00000300 -#define MDFLD_PWRGT_DISPLAY_C_STS 0x00000c00 #define PSB_PWRGT_GFX_MASK_B0 0xc3 -#define MDFLD_PWRGT_DISPLAY_A_STS_B0 0x0000000c -#define MDFLD_PWRGT_DISPLAY_B_STS_B0 0x0000c000 -#define MDFLD_PWRGT_DISPLAY_C_STS_B0 0x00030000 -#define MDFLD_PWRGT_DISP_MIPI_STS 0x000c0000 -#define MDFLD_PWRGT_DISPLAY_STS_A0 (MDFLD_PWRGT_DISPLAY_A_STS | MDFLD_PWRGT_DISPLAY_B_STS | MDFLD_PWRGT_DISPLAY_C_STS | MDFLD_PWRGT_DISP_MIPI_STS) /* 0x000fc00c */ -#define MDFLD_PWRGT_DISPLAY_STS_B0 (MDFLD_PWRGT_DISPLAY_A_STS_B0 | MDFLD_PWRGT_DISPLAY_B_STS_B0 | MDFLD_PWRGT_DISPLAY_C_STS_B0 | MDFLD_PWRGT_DISP_MIPI_STS) /* 0x000fc00c */ #endif diff --git a/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c b/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c deleted file mode 100644 index 771ff66711af..000000000000 --- a/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c +++ /dev/null @@ -1,829 +0,0 @@ -/* - * Copyright © 2011 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -#include "mdfld_dsi_dpi.h" -#include "mdfld_output.h" -#include "mdfld_dsi_pkg_sender.h" -#include "tc35876x-dsi-lvds.h" -#include <linux/i2c/tc35876x.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <asm/intel_scu_ipc.h> - -static struct i2c_client *tc35876x_client; -static struct i2c_client *cmi_lcd_i2c_client; - -#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end)) -#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end)) - -/* DSI D-PHY Layer Registers */ -#define D0W_DPHYCONTTX 0x0004 -#define CLW_DPHYCONTRX 0x0020 -#define D0W_DPHYCONTRX 0x0024 -#define D1W_DPHYCONTRX 0x0028 -#define D2W_DPHYCONTRX 0x002C -#define D3W_DPHYCONTRX 0x0030 -#define COM_DPHYCONTRX 0x0038 -#define CLW_CNTRL 0x0040 -#define D0W_CNTRL 0x0044 -#define D1W_CNTRL 0x0048 -#define D2W_CNTRL 0x004C -#define D3W_CNTRL 0x0050 -#define DFTMODE_CNTRL 0x0054 - -/* DSI PPI Layer Registers */ -#define PPI_STARTPPI 0x0104 -#define PPI_BUSYPPI 0x0108 -#define PPI_LINEINITCNT 0x0110 -#define PPI_LPTXTIMECNT 0x0114 -#define PPI_LANEENABLE 0x0134 -#define PPI_TX_RX_TA 0x013C -#define PPI_CLS_ATMR 0x0140 -#define PPI_D0S_ATMR 0x0144 -#define PPI_D1S_ATMR 0x0148 -#define PPI_D2S_ATMR 0x014C -#define PPI_D3S_ATMR 0x0150 -#define PPI_D0S_CLRSIPOCOUNT 0x0164 -#define PPI_D1S_CLRSIPOCOUNT 0x0168 -#define PPI_D2S_CLRSIPOCOUNT 0x016C -#define PPI_D3S_CLRSIPOCOUNT 0x0170 -#define CLS_PRE 0x0180 -#define D0S_PRE 0x0184 -#define D1S_PRE 0x0188 -#define D2S_PRE 0x018C -#define D3S_PRE 0x0190 -#define CLS_PREP 0x01A0 -#define D0S_PREP 0x01A4 -#define D1S_PREP 0x01A8 -#define D2S_PREP 0x01AC -#define D3S_PREP 0x01B0 -#define CLS_ZERO 0x01C0 -#define D0S_ZERO 0x01C4 -#define D1S_ZERO 0x01C8 -#define D2S_ZERO 0x01CC -#define D3S_ZERO 0x01D0 -#define PPI_CLRFLG 0x01E0 -#define PPI_CLRSIPO 0x01E4 -#define HSTIMEOUT 0x01F0 -#define HSTIMEOUTENABLE 0x01F4 - -/* DSI Protocol Layer Registers */ -#define DSI_STARTDSI 0x0204 -#define DSI_BUSYDSI 0x0208 -#define DSI_LANEENABLE 0x0210 -#define DSI_LANESTATUS0 0x0214 -#define DSI_LANESTATUS1 0x0218 -#define DSI_INTSTATUS 0x0220 -#define DSI_INTMASK 0x0224 -#define DSI_INTCLR 0x0228 -#define DSI_LPTXTO 0x0230 - -/* DSI General Registers */ -#define DSIERRCNT 0x0300 - -/* DSI Application Layer Registers */ -#define APLCTRL 0x0400 -#define RDPKTLN 0x0404 - -/* Video Path Registers */ -#define VPCTRL 0x0450 -#define HTIM1 0x0454 -#define HTIM2 0x0458 -#define VTIM1 0x045C -#define VTIM2 0x0460 -#define VFUEN 0x0464 - -/* LVDS Registers */ -#define LVMX0003 0x0480 -#define LVMX0407 0x0484 -#define LVMX0811 0x0488 -#define LVMX1215 0x048C -#define LVMX1619 0x0490 -#define LVMX2023 0x0494 -#define LVMX2427 0x0498 -#define LVCFG 0x049C -#define LVPHY0 0x04A0 -#define LVPHY1 0x04A4 - -/* System Registers */ -#define SYSSTAT 0x0500 -#define SYSRST 0x0504 - -/* GPIO Registers */ -/*#define GPIOC 0x0520*/ -#define GPIOO 0x0524 -#define GPIOI 0x0528 - -/* I2C Registers */ -#define I2CTIMCTRL 0x0540 -#define I2CMADDR 0x0544 -#define WDATAQ 0x0548 -#define RDATAQ 0x054C - -/* Chip/Rev Registers */ -#define IDREG 0x0580 - -/* Debug Registers */ -#define DEBUG00 0x05A0 -#define DEBUG01 0x05A4 - -/* Panel CABC registers */ -#define PANEL_PWM_CONTROL 0x90 -#define PANEL_FREQ_DIVIDER_HI 0x91 -#define PANEL_FREQ_DIVIDER_LO 0x92 -#define PANEL_DUTY_CONTROL 0x93 -#define PANEL_MODIFY_RGB 0x94 -#define PANEL_FRAMERATE_CONTROL 0x96 -#define PANEL_PWM_MIN 0x97 -#define PANEL_PWM_REF 0x98 -#define PANEL_PWM_MAX 0x99 -#define PANEL_ALLOW_DISTORT 0x9A -#define PANEL_BYPASS_PWMI 0x9B - -/* Panel color management registers */ -#define PANEL_CM_ENABLE 0x700 -#define PANEL_CM_HUE 0x701 -#define PANEL_CM_SATURATION 0x702 -#define PANEL_CM_INTENSITY 0x703 -#define PANEL_CM_BRIGHTNESS 0x704 -#define PANEL_CM_CE_ENABLE 0x705 -#define PANEL_CM_PEAK_EN 0x710 -#define PANEL_CM_GAIN 0x711 -#define PANEL_CM_HUETABLE_START 0x730 -#define PANEL_CM_HUETABLE_END 0x747 /* inclusive */ - -/* Input muxing for registers LVMX0003...LVMX2427 */ -enum { - INPUT_R0, /* 0 */ - INPUT_R1, - INPUT_R2, - INPUT_R3, - INPUT_R4, - INPUT_R5, - INPUT_R6, - INPUT_R7, - INPUT_G0, /* 8 */ - INPUT_G1, - INPUT_G2, - INPUT_G3, - INPUT_G4, - INPUT_G5, - INPUT_G6, - INPUT_G7, - INPUT_B0, /* 16 */ - INPUT_B1, - INPUT_B2, - INPUT_B3, - INPUT_B4, - INPUT_B5, - INPUT_B6, - INPUT_B7, - INPUT_HSYNC, /* 24 */ - INPUT_VSYNC, - INPUT_DE, - LOGIC_0, - /* 28...31 undefined */ -}; - -#define INPUT_MUX(lvmx03, lvmx02, lvmx01, lvmx00) \ - (FLD_VAL(lvmx03, 29, 24) | FLD_VAL(lvmx02, 20, 16) | \ - FLD_VAL(lvmx01, 12, 8) | FLD_VAL(lvmx00, 4, 0)) - -/** - * tc35876x_regw - Write DSI-LVDS bridge register using I2C - * @client: struct i2c_client to use - * @reg: register address - * @value: value to write - * - * Returns 0 on success, or a negative error value. - */ -static int tc35876x_regw(struct i2c_client *client, u16 reg, u32 value) -{ - int r; - u8 tx_data[] = { - /* NOTE: Register address big-endian, data little-endian. */ - (reg >> 8) & 0xff, - reg & 0xff, - value & 0xff, - (value >> 8) & 0xff, - (value >> 16) & 0xff, - (value >> 24) & 0xff, - }; - struct i2c_msg msgs[] = { - { - .addr = client->addr, - .flags = 0, - .buf = tx_data, - .len = ARRAY_SIZE(tx_data), - }, - }; - - r = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (r < 0) { - dev_err(&client->dev, "%s: reg 0x%04x val 0x%08x error %d\n", - __func__, reg, value, r); - return r; - } - - if (r < ARRAY_SIZE(msgs)) { - dev_err(&client->dev, "%s: reg 0x%04x val 0x%08x msgs %d\n", - __func__, reg, value, r); - return -EAGAIN; - } - - dev_dbg(&client->dev, "%s: reg 0x%04x val 0x%08x\n", - __func__, reg, value); - - return 0; -} - -/** - * tc35876x_regr - Read DSI-LVDS bridge register using I2C - * @client: struct i2c_client to use - * @reg: register address - * @value: pointer for storing the value - * - * Returns 0 on success, or a negative error value. - */ -static int tc35876x_regr(struct i2c_client *client, u16 reg, u32 *value) -{ - int r; - u8 tx_data[] = { - (reg >> 8) & 0xff, - reg & 0xff, - }; - u8 rx_data[4]; - struct i2c_msg msgs[] = { - { - .addr = client->addr, - .flags = 0, - .buf = tx_data, - .len = ARRAY_SIZE(tx_data), - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .buf = rx_data, - .len = ARRAY_SIZE(rx_data), - }, - }; - - r = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (r < 0) { - dev_err(&client->dev, "%s: reg 0x%04x error %d\n", __func__, - reg, r); - return r; - } - - if (r < ARRAY_SIZE(msgs)) { - dev_err(&client->dev, "%s: reg 0x%04x msgs %d\n", __func__, - reg, r); - return -EAGAIN; - } - - *value = rx_data[0] << 24 | rx_data[1] << 16 | - rx_data[2] << 8 | rx_data[3]; - - dev_dbg(&client->dev, "%s: reg 0x%04x value 0x%08x\n", __func__, - reg, *value); - - return 0; -} - -void tc35876x_set_bridge_reset_state(struct drm_device *dev, int state) -{ - struct tc35876x_platform_data *pdata; - - if (WARN(!tc35876x_client, "%s called before probe", __func__)) - return; - - dev_dbg(&tc35876x_client->dev, "%s: state %d\n", __func__, state); - - pdata = dev_get_platdata(&tc35876x_client->dev); - - if (pdata->gpio_bridge_reset == -1) - return; - - if (state) { - gpio_set_value_cansleep(pdata->gpio_bridge_reset, 0); - mdelay(10); - } else { - /* Pull MIPI Bridge reset pin to Low */ - gpio_set_value_cansleep(pdata->gpio_bridge_reset, 0); - mdelay(20); - /* Pull MIPI Bridge reset pin to High */ - gpio_set_value_cansleep(pdata->gpio_bridge_reset, 1); - mdelay(40); - } -} - -void tc35876x_configure_lvds_bridge(struct drm_device *dev) -{ - struct i2c_client *i2c = tc35876x_client; - u32 ppi_lptxtimecnt; - u32 txtagocnt; - u32 txtasurecnt; - u32 id; - - if (WARN(!tc35876x_client, "%s called before probe", __func__)) - return; - - dev_dbg(&tc35876x_client->dev, "%s\n", __func__); - - if (!tc35876x_regr(i2c, IDREG, &id)) - dev_info(&tc35876x_client->dev, "tc35876x ID 0x%08x\n", id); - else - dev_err(&tc35876x_client->dev, "Cannot read ID\n"); - - ppi_lptxtimecnt = 4; - txtagocnt = (5 * ppi_lptxtimecnt - 3) / 4; - txtasurecnt = 3 * ppi_lptxtimecnt / 2; - tc35876x_regw(i2c, PPI_TX_RX_TA, FLD_VAL(txtagocnt, 26, 16) | - FLD_VAL(txtasurecnt, 10, 0)); - tc35876x_regw(i2c, PPI_LPTXTIMECNT, FLD_VAL(ppi_lptxtimecnt, 10, 0)); - - tc35876x_regw(i2c, PPI_D0S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0)); - tc35876x_regw(i2c, PPI_D1S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0)); - tc35876x_regw(i2c, PPI_D2S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0)); - tc35876x_regw(i2c, PPI_D3S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0)); - - /* Enabling MIPI & PPI lanes, Enable 4 lanes */ - tc35876x_regw(i2c, PPI_LANEENABLE, - BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)); - tc35876x_regw(i2c, DSI_LANEENABLE, - BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)); - tc35876x_regw(i2c, PPI_STARTPPI, BIT(0)); - tc35876x_regw(i2c, DSI_STARTDSI, BIT(0)); - - /* Setting LVDS output frequency */ - tc35876x_regw(i2c, LVPHY0, FLD_VAL(1, 20, 16) | - FLD_VAL(2, 15, 14) | FLD_VAL(6, 4, 0)); /* 0x00048006 */ - - /* Setting video panel control register,0x00000120 VTGen=ON ?!?!? */ - tc35876x_regw(i2c, VPCTRL, BIT(8) | BIT(5)); - - /* Horizontal back porch and horizontal pulse width. 0x00280028 */ - tc35876x_regw(i2c, HTIM1, FLD_VAL(40, 24, 16) | FLD_VAL(40, 8, 0)); - - /* Horizontal front porch and horizontal active video size. 0x00500500*/ - tc35876x_regw(i2c, HTIM2, FLD_VAL(80, 24, 16) | FLD_VAL(1280, 10, 0)); - - /* Vertical back porch and vertical sync pulse width. 0x000e000a */ - tc35876x_regw(i2c, VTIM1, FLD_VAL(14, 23, 16) | FLD_VAL(10, 7, 0)); - - /* Vertical front porch and vertical display size. 0x000e0320 */ - tc35876x_regw(i2c, VTIM2, FLD_VAL(14, 23, 16) | FLD_VAL(800, 10, 0)); - - /* Set above HTIM1, HTIM2, VTIM1, and VTIM2 at next VSYNC. */ - tc35876x_regw(i2c, VFUEN, BIT(0)); - - /* Soft reset LCD controller. */ - tc35876x_regw(i2c, SYSRST, BIT(2)); - - /* LVDS-TX input muxing */ - tc35876x_regw(i2c, LVMX0003, - INPUT_MUX(INPUT_R5, INPUT_R4, INPUT_R3, INPUT_R2)); - tc35876x_regw(i2c, LVMX0407, - INPUT_MUX(INPUT_G2, INPUT_R7, INPUT_R1, INPUT_R6)); - tc35876x_regw(i2c, LVMX0811, - INPUT_MUX(INPUT_G1, INPUT_G0, INPUT_G4, INPUT_G3)); - tc35876x_regw(i2c, LVMX1215, - INPUT_MUX(INPUT_B2, INPUT_G7, INPUT_G6, INPUT_G5)); - tc35876x_regw(i2c, LVMX1619, - INPUT_MUX(INPUT_B4, INPUT_B3, INPUT_B1, INPUT_B0)); - tc35876x_regw(i2c, LVMX2023, - INPUT_MUX(LOGIC_0, INPUT_B7, INPUT_B6, INPUT_B5)); - tc35876x_regw(i2c, LVMX2427, - INPUT_MUX(INPUT_R0, INPUT_DE, INPUT_VSYNC, INPUT_HSYNC)); - - /* Enable LVDS transmitter. */ - tc35876x_regw(i2c, LVCFG, BIT(0)); - - /* Clear notifications. Don't write reserved bits. Was write 0xffffffff - * to 0x0288, must be in error?! */ - tc35876x_regw(i2c, DSI_INTCLR, FLD_MASK(31, 30) | FLD_MASK(22, 0)); -} - -#define GPIOPWMCTRL 0x38F -#define PWM0CLKDIV0 0x62 /* low byte */ -#define PWM0CLKDIV1 0x61 /* high byte */ - -#define SYSTEMCLK 19200000UL /* 19.2 MHz */ -#define PWM_FREQUENCY 9600 /* Hz */ - -/* f = baseclk / (clkdiv + 1) => clkdiv = (baseclk - f) / f */ -static inline u16 calc_clkdiv(unsigned long baseclk, unsigned int f) -{ - return (baseclk - f) / f; -} - -static void tc35876x_brightness_init(struct drm_device *dev) -{ - int ret; - u8 pwmctrl; - u16 clkdiv; - - /* Make sure the PWM reference is the 19.2 MHz system clock. Read first - * instead of setting directly to catch potential conflicts between PWM - * users. */ - ret = intel_scu_ipc_ioread8(GPIOPWMCTRL, &pwmctrl); - if (ret || pwmctrl != 0x01) { - if (ret) - dev_err(&dev->pdev->dev, "GPIOPWMCTRL read failed\n"); - else - dev_warn(&dev->pdev->dev, "GPIOPWMCTRL was not set to system clock (pwmctrl = 0x%02x)\n", pwmctrl); - - ret = intel_scu_ipc_iowrite8(GPIOPWMCTRL, 0x01); - if (ret) - dev_err(&dev->pdev->dev, "GPIOPWMCTRL set failed\n"); - } - - clkdiv = calc_clkdiv(SYSTEMCLK, PWM_FREQUENCY); - - ret = intel_scu_ipc_iowrite8(PWM0CLKDIV1, (clkdiv >> 8) & 0xff); - if (!ret) - ret = intel_scu_ipc_iowrite8(PWM0CLKDIV0, clkdiv & 0xff); - - if (ret) - dev_err(&dev->pdev->dev, "PWM0CLKDIV set failed\n"); - else - dev_dbg(&dev->pdev->dev, "PWM0CLKDIV set to 0x%04x (%d Hz)\n", - clkdiv, PWM_FREQUENCY); -} - -#define PWM0DUTYCYCLE 0x67 - -void tc35876x_brightness_control(struct drm_device *dev, int level) -{ - int ret; - u8 duty_val; - u8 panel_duty_val; - - level = clamp(level, 0, MDFLD_DSI_BRIGHTNESS_MAX_LEVEL); - - /* PWM duty cycle 0x00...0x63 corresponds to 0...99% */ - duty_val = level * 0x63 / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL; - - /* I won't pretend to understand this formula. The panel spec is quite - * bad engrish. - */ - panel_duty_val = (2 * level - 100) * 0xA9 / - MDFLD_DSI_BRIGHTNESS_MAX_LEVEL + 0x56; - - ret = intel_scu_ipc_iowrite8(PWM0DUTYCYCLE, duty_val); - if (ret) - dev_err(&tc35876x_client->dev, "%s: ipc write fail\n", - __func__); - - if (cmi_lcd_i2c_client) { - ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client, - PANEL_PWM_MAX, panel_duty_val); - if (ret < 0) - dev_err(&cmi_lcd_i2c_client->dev, "%s: i2c write failed\n", - __func__); - } -} - -void tc35876x_toshiba_bridge_panel_off(struct drm_device *dev) -{ - struct tc35876x_platform_data *pdata; - - if (WARN(!tc35876x_client, "%s called before probe", __func__)) - return; - - dev_dbg(&tc35876x_client->dev, "%s\n", __func__); - - pdata = dev_get_platdata(&tc35876x_client->dev); - - if (pdata->gpio_panel_bl_en != -1) - gpio_set_value_cansleep(pdata->gpio_panel_bl_en, 0); - - if (pdata->gpio_panel_vadd != -1) - gpio_set_value_cansleep(pdata->gpio_panel_vadd, 0); -} - -void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev) -{ - struct tc35876x_platform_data *pdata; - struct drm_psb_private *dev_priv = dev->dev_private; - - if (WARN(!tc35876x_client, "%s called before probe", __func__)) - return; - - dev_dbg(&tc35876x_client->dev, "%s\n", __func__); - - pdata = dev_get_platdata(&tc35876x_client->dev); - - if (pdata->gpio_panel_vadd != -1) { - gpio_set_value_cansleep(pdata->gpio_panel_vadd, 1); - msleep(260); - } - - if (cmi_lcd_i2c_client) { - int ret; - dev_dbg(&cmi_lcd_i2c_client->dev, "setting TCON\n"); - /* Bit 4 is average_saving. Setting it to 1, the brightness is - * referenced to the average of the frame content. 0 means - * reference to the maximum of frame contents. Bits 3:0 are - * allow_distort. When set to a nonzero value, all color values - * between 255-allow_distort*2 and 255 are mapped to the - * 255-allow_distort*2 value. - */ - ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client, - PANEL_ALLOW_DISTORT, 0x10); - if (ret < 0) - dev_err(&cmi_lcd_i2c_client->dev, - "i2c write failed (%d)\n", ret); - ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client, - PANEL_BYPASS_PWMI, 0); - if (ret < 0) - dev_err(&cmi_lcd_i2c_client->dev, - "i2c write failed (%d)\n", ret); - /* Set minimum brightness value - this is tunable */ - ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client, - PANEL_PWM_MIN, 0x35); - if (ret < 0) - dev_err(&cmi_lcd_i2c_client->dev, - "i2c write failed (%d)\n", ret); - } - - if (pdata->gpio_panel_bl_en != -1) - gpio_set_value_cansleep(pdata->gpio_panel_bl_en, 1); - - tc35876x_brightness_control(dev, dev_priv->brightness_adjusted); -} - -static struct drm_display_mode *tc35876x_get_config_mode(struct drm_device *dev) -{ - struct drm_display_mode *mode; - - dev_dbg(&dev->pdev->dev, "%s\n", __func__); - - mode = kzalloc(sizeof(*mode), GFP_KERNEL); - if (!mode) - return NULL; - - /* FIXME: do this properly. */ - mode->hdisplay = 1280; - mode->vdisplay = 800; - mode->hsync_start = 1360; - mode->hsync_end = 1400; - mode->htotal = 1440; - mode->vsync_start = 814; - mode->vsync_end = 824; - mode->vtotal = 838; - mode->clock = 33324 << 1; - - dev_info(&dev->pdev->dev, "hdisplay(w) = %d\n", mode->hdisplay); - dev_info(&dev->pdev->dev, "vdisplay(h) = %d\n", mode->vdisplay); - dev_info(&dev->pdev->dev, "HSS = %d\n", mode->hsync_start); - dev_info(&dev->pdev->dev, "HSE = %d\n", mode->hsync_end); - dev_info(&dev->pdev->dev, "htotal = %d\n", mode->htotal); - dev_info(&dev->pdev->dev, "VSS = %d\n", mode->vsync_start); - dev_info(&dev->pdev->dev, "VSE = %d\n", mode->vsync_end); - dev_info(&dev->pdev->dev, "vtotal = %d\n", mode->vtotal); - dev_info(&dev->pdev->dev, "clock = %d\n", mode->clock); - - drm_mode_set_name(mode); - drm_mode_set_crtcinfo(mode, 0); - - mode->type |= DRM_MODE_TYPE_PREFERRED; - - return mode; -} - -/* DV1 Active area 216.96 x 135.6 mm */ -#define DV1_PANEL_WIDTH 217 -#define DV1_PANEL_HEIGHT 136 - -static int tc35876x_get_panel_info(struct drm_device *dev, int pipe, - struct panel_info *pi) -{ - if (!dev || !pi) - return -EINVAL; - - pi->width_mm = DV1_PANEL_WIDTH; - pi->height_mm = DV1_PANEL_HEIGHT; - - return 0; -} - -static int tc35876x_bridge_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct tc35876x_platform_data *pdata; - - dev_info(&client->dev, "%s\n", __func__); - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - dev_err(&client->dev, "%s: i2c_check_functionality() failed\n", - __func__); - return -ENODEV; - } - - pdata = dev_get_platdata(&client->dev); - if (!pdata) { - dev_err(&client->dev, "%s: no platform data\n", __func__); - return -ENODEV; - } - - if (pdata->gpio_bridge_reset != -1) { - gpio_request(pdata->gpio_bridge_reset, "tc35876x bridge reset"); - gpio_direction_output(pdata->gpio_bridge_reset, 0); - } - - if (pdata->gpio_panel_bl_en != -1) { - gpio_request(pdata->gpio_panel_bl_en, "tc35876x panel bl en"); - gpio_direction_output(pdata->gpio_panel_bl_en, 0); - } - - if (pdata->gpio_panel_vadd != -1) { - gpio_request(pdata->gpio_panel_vadd, "tc35876x panel vadd"); - gpio_direction_output(pdata->gpio_panel_vadd, 0); - } - - tc35876x_client = client; - - return 0; -} - -static int tc35876x_bridge_remove(struct i2c_client *client) -{ - struct tc35876x_platform_data *pdata = dev_get_platdata(&client->dev); - - dev_dbg(&client->dev, "%s\n", __func__); - - if (pdata->gpio_bridge_reset != -1) - gpio_free(pdata->gpio_bridge_reset); - - if (pdata->gpio_panel_bl_en != -1) - gpio_free(pdata->gpio_panel_bl_en); - - if (pdata->gpio_panel_vadd != -1) - gpio_free(pdata->gpio_panel_vadd); - - tc35876x_client = NULL; - - return 0; -} - -static const struct i2c_device_id tc35876x_bridge_id[] = { - { "i2c_disp_brig", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tc35876x_bridge_id); - -static struct i2c_driver tc35876x_bridge_i2c_driver = { - .driver = { - .name = "i2c_disp_brig", - }, - .id_table = tc35876x_bridge_id, - .probe = tc35876x_bridge_probe, - .remove = tc35876x_bridge_remove, -}; - -/* LCD panel I2C */ -static int cmi_lcd_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - dev_info(&client->dev, "%s\n", __func__); - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - dev_err(&client->dev, "%s: i2c_check_functionality() failed\n", - __func__); - return -ENODEV; - } - - cmi_lcd_i2c_client = client; - - return 0; -} - -static int cmi_lcd_i2c_remove(struct i2c_client *client) -{ - dev_dbg(&client->dev, "%s\n", __func__); - - cmi_lcd_i2c_client = NULL; - - return 0; -} - -static const struct i2c_device_id cmi_lcd_i2c_id[] = { - { "cmi-lcd", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, cmi_lcd_i2c_id); - -static struct i2c_driver cmi_lcd_i2c_driver = { - .driver = { - .name = "cmi-lcd", - }, - .id_table = cmi_lcd_i2c_id, - .probe = cmi_lcd_i2c_probe, - .remove = cmi_lcd_i2c_remove, -}; - -/* HACK to create I2C device while it's not created by platform code */ -#define CMI_LCD_I2C_ADAPTER 2 -#define CMI_LCD_I2C_ADDR 0x60 - -static int cmi_lcd_hack_create_device(void) -{ - struct i2c_adapter *adapter; - struct i2c_client *client; - struct i2c_board_info info = { - .type = "cmi-lcd", - .addr = CMI_LCD_I2C_ADDR, - }; - - pr_debug("%s\n", __func__); - - adapter = i2c_get_adapter(CMI_LCD_I2C_ADAPTER); - if (!adapter) { - pr_err("%s: i2c_get_adapter(%d) failed\n", __func__, - CMI_LCD_I2C_ADAPTER); - return -EINVAL; - } - - client = i2c_new_device(adapter, &info); - if (!client) { - pr_err("%s: i2c_new_device() failed\n", __func__); - i2c_put_adapter(adapter); - return -EINVAL; - } - - return 0; -} - -static const struct drm_encoder_helper_funcs tc35876x_encoder_helper_funcs = { - .dpms = mdfld_dsi_dpi_dpms, - .mode_fixup = mdfld_dsi_dpi_mode_fixup, - .prepare = mdfld_dsi_dpi_prepare, - .mode_set = mdfld_dsi_dpi_mode_set, - .commit = mdfld_dsi_dpi_commit, -}; - -static const struct drm_encoder_funcs tc35876x_encoder_funcs = { - .destroy = drm_encoder_cleanup, -}; - -const struct panel_funcs mdfld_tc35876x_funcs = { - .encoder_funcs = &tc35876x_encoder_funcs, - .encoder_helper_funcs = &tc35876x_encoder_helper_funcs, - .get_config_mode = tc35876x_get_config_mode, - .get_panel_info = tc35876x_get_panel_info, -}; - -void tc35876x_init(struct drm_device *dev) -{ - int r; - - dev_dbg(&dev->pdev->dev, "%s\n", __func__); - - cmi_lcd_hack_create_device(); - - r = i2c_add_driver(&cmi_lcd_i2c_driver); - if (r < 0) - dev_err(&dev->pdev->dev, - "%s: i2c_add_driver() for %s failed (%d)\n", - __func__, cmi_lcd_i2c_driver.driver.name, r); - - r = i2c_add_driver(&tc35876x_bridge_i2c_driver); - if (r < 0) - dev_err(&dev->pdev->dev, - "%s: i2c_add_driver() for %s failed (%d)\n", - __func__, tc35876x_bridge_i2c_driver.driver.name, r); - - tc35876x_brightness_init(dev); -} - -void tc35876x_exit(void) -{ - pr_debug("%s\n", __func__); - - i2c_del_driver(&tc35876x_bridge_i2c_driver); - - if (cmi_lcd_i2c_client) - i2c_del_driver(&cmi_lcd_i2c_driver); -} diff --git a/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.h b/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.h deleted file mode 100644 index b14b7f9e7d1e..000000000000 --- a/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright © 2011 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef __MDFLD_DSI_LVDS_BRIDGE_H__ -#define __MDFLD_DSI_LVDS_BRIDGE_H__ - -void tc35876x_set_bridge_reset_state(struct drm_device *dev, int state); -void tc35876x_configure_lvds_bridge(struct drm_device *dev); -void tc35876x_brightness_control(struct drm_device *dev, int level); -void tc35876x_toshiba_bridge_panel_off(struct drm_device *dev); -void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev); -void tc35876x_init(struct drm_device *dev); -void tc35876x_exit(void); - -extern const struct panel_funcs mdfld_tc35876x_funcs; - -#endif /*__MDFLD_DSI_LVDS_BRIDGE_H__*/ |
