dect
/
linux-2.6
Archived
13
0
Fork 0

Merge tag 'omapdss-for-3.8' of git://gitorious.org/linux-omap-dss2/linux into for-linus

OMAPDSS changes for 3.8, including:
- use dynanic debug prints
- OMAP platform dependency removals
- Creation of compat-layer, helping us to improve omapdrm
- Misc cleanups, aiming to make omadss more in line with the upcoming common
  display framework

* tag 'omapdss-for-3.8' of git://gitorious.org/linux-omap-dss2/linux: (140 commits)
  OMAPDSS: fix TV-out issue with DSI PLL
  Revert "OMAPFB: simplify locking"
  OMAPFB: remove silly loop in fb2display()
  OMAPFB: fix error handling in omapfb_find_best_mode()
  OMAPFB: use devm_kzalloc to allocate omapfb2_device
  OMAPDSS: DISPC: remove dispc fck uses
  OMAPDSS: DISPC: get dss clock rate from dss driver
  OMAPDSS: use omapdss_compat_init() in other drivers
  OMAPDSS: export dispc functions
  OMAPDSS: export dss_feat functions
  OMAPDSS: export dss_mgr_ops functions
  OMAPDSS: separate compat files in the Makefile
  OMAPDSS: move display sysfs init to compat layer
  OMAPDSS: DPI: use dispc's check_timings
  OMAPDSS: DISPC: add dispc_ovl_check()
  OMAPDSS: move irq handling to dispc-compat
  OMAPDSS: move omap_dispc_wait_for_irq_interruptible_timeout to dispc-compat.c
  OMAPDSS: move blocking mgr enable/disable to compat layer
  OMAPDSS: manage framedone irq with mgr ops
  OMAPDSS: add manager ops
  ...
This commit is contained in:
Tomi Valkeinen 2012-12-13 14:30:56 +02:00
commit e7f5c9a16e
62 changed files with 2861 additions and 3022 deletions

View File

@ -285,7 +285,10 @@ FB0 +-- GFX ---- LCD ---- LCD
Misc notes
----------
OMAP FB allocates the framebuffer memory using the OMAP VRAM allocator.
OMAP FB allocates the framebuffer memory using the standard dma allocator. You
can enable Contiguous Memory Allocator (CONFIG_CMA) to improve the dma
allocator, and if CMA is enabled, you use "cma=" kernel parameter to increase
the global memory area for CMA.
Using DSI DPLL to generate pixel clock it is possible produce the pixel clock
of 86.5MHz (max possible), and with that you get 1280x1024@57 output from DVI.
@ -301,11 +304,6 @@ framebuffer parameters.
Kernel boot arguments
---------------------
vram=<size>[,<physaddr>]
- Amount of total VRAM to preallocate and optionally a physical start
memory address. For example, "10M". omapfb allocates memory for
framebuffers from VRAM.
omapfb.mode=<display>:<mode>[,...]
- Default video mode for specified displays. For example,
"dvi:800x400MR-24@60". See drivers/video/modedb.c.

View File

@ -16,7 +16,6 @@
#include <linux/mm.h>
#include <asm/mach-types.h>
#include <video/omapdss.h>
#include <plat/vram.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
#include "board-rx51.h"
@ -87,17 +86,4 @@ static int __init rx51_video_init(void)
}
subsys_initcall(rx51_video_init);
void __init rx51_video_mem_init(void)
{
/*
* GFX 864x480x32bpp
* VID1/2 1280x720x32bpp double buffered
*/
omap_vram_set_sdram_vram(PAGE_ALIGN(864 * 480 * 4) +
2 * PAGE_ALIGN(1280 * 720 * 4 * 2), 0);
}
#else
void __init rx51_video_mem_init(void) { }
#endif /* defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE) */

View File

@ -34,8 +34,6 @@
#define RX51_GPIO_SLEEP_IND 162
extern void rx51_video_mem_init(void);
static struct gpio_led gpio_leds[] = {
{
.name = "sleep_ind",
@ -112,7 +110,6 @@ static void __init rx51_init(void)
static void __init rx51_reserve(void)
{
rx51_video_mem_init();
omap_reserve();
}

View File

@ -100,17 +100,20 @@ static const struct omap_dss_hwmod_data omap4_dss_hwmod_data[] __initconst = {
{ "dss_hdmi", "omapdss_hdmi", -1 },
};
static void __init omap4_hdmi_mux_pads(enum omap_hdmi_flags flags)
static void __init omap4_tpd12s015_mux_pads(void)
{
u32 reg;
u16 control_i2c_1;
omap_mux_init_signal("hdmi_cec",
OMAP_PIN_INPUT_PULLUP);
omap_mux_init_signal("hdmi_ddc_scl",
OMAP_PIN_INPUT_PULLUP);
omap_mux_init_signal("hdmi_ddc_sda",
OMAP_PIN_INPUT_PULLUP);
}
static void __init omap4_hdmi_mux_pads(enum omap_hdmi_flags flags)
{
u32 reg;
u16 control_i2c_1;
/*
* CONTROL_I2C_1: HDMI_DDC_SDA_PULLUPRESX (bit 28) and
@ -161,8 +164,10 @@ static int omap4_dsi_mux_pads(int dsi_id, unsigned lanes)
int __init omap_hdmi_init(enum omap_hdmi_flags flags)
{
if (cpu_is_omap44xx())
if (cpu_is_omap44xx()) {
omap4_hdmi_mux_pads(flags);
omap4_tpd12s015_mux_pads();
}
return 0;
}
@ -284,6 +289,35 @@ err:
return ERR_PTR(r);
}
static enum omapdss_version __init omap_display_get_version(void)
{
if (cpu_is_omap24xx())
return OMAPDSS_VER_OMAP24xx;
else if (cpu_is_omap3630())
return OMAPDSS_VER_OMAP3630;
else if (cpu_is_omap34xx()) {
if (soc_is_am35xx()) {
return OMAPDSS_VER_AM35xx;
} else {
if (omap_rev() < OMAP3430_REV_ES3_0)
return OMAPDSS_VER_OMAP34xx_ES1;
else
return OMAPDSS_VER_OMAP34xx_ES3;
}
} else if (omap_rev() == OMAP4430_REV_ES1_0)
return OMAPDSS_VER_OMAP4430_ES1;
else if (omap_rev() == OMAP4430_REV_ES2_0 ||
omap_rev() == OMAP4430_REV_ES2_1 ||
omap_rev() == OMAP4430_REV_ES2_2)
return OMAPDSS_VER_OMAP4430_ES2;
else if (cpu_is_omap44xx())
return OMAPDSS_VER_OMAP4;
else if (soc_is_omap54xx())
return OMAPDSS_VER_OMAP5;
else
return OMAPDSS_VER_UNKNOWN;
}
int __init omap_display_init(struct omap_dss_board_info *board_data)
{
int r = 0;
@ -291,9 +325,18 @@ int __init omap_display_init(struct omap_dss_board_info *board_data)
int i, oh_count;
const struct omap_dss_hwmod_data *curr_dss_hwmod;
struct platform_device *dss_pdev;
enum omapdss_version ver;
/* create omapdss device */
ver = omap_display_get_version();
if (ver == OMAPDSS_VER_UNKNOWN) {
pr_err("DSS not supported on this SoC\n");
return -ENODEV;
}
board_data->version = ver;
board_data->dsi_enable_pads = omap_dsi_enable_pads;
board_data->dsi_disable_pads = omap_dsi_disable_pads;
board_data->get_context_loss_count = omap_pm_get_dev_context_loss_count;

View File

@ -160,19 +160,3 @@ void __init omap2_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
sdrc_write_reg(l, SDRC_POWER);
omap2_sms_save_context();
}
void omap2_sms_write_rot_control(u32 val, unsigned ctx)
{
sms_write_reg(val, SMS_ROT_CONTROL(ctx));
}
void omap2_sms_write_rot_size(u32 val, unsigned ctx)
{
sms_write_reg(val, SMS_ROT_SIZE(ctx));
}
void omap2_sms_write_rot_physical_ba(u32 val, unsigned ctx)
{
sms_write_reg(val, SMS_ROT_PHYSICAL_BA(ctx));
}

View File

@ -17,7 +17,6 @@
#include <linux/dma-mapping.h>
#include <plat/common.h>
#include <plat/vram.h>
#include <linux/platform_data/dsp-omap.h>
#include <plat/dma.h>
@ -25,7 +24,6 @@
void __init omap_reserve(void)
{
omap_vram_reserve_sdram_memblock();
omap_dsp_reserve_sdram_memblock();
omap_secure_ram_reserve_memblock();
omap_barrier_reserve_memblock();

View File

@ -29,10 +29,72 @@
#include <linux/memblock.h>
#include <linux/io.h>
#include <linux/omapfb.h>
#include <linux/dma-mapping.h>
#include <mach/hardware.h>
#include <asm/mach/map.h>
#include <plat/cpu.h>
#ifdef CONFIG_OMAP2_VRFB
/*
* The first memory resource is the register region for VRFB,
* the rest are VRFB virtual memory areas for each VRFB context.
*/
static const struct resource omap2_vrfb_resources[] = {
DEFINE_RES_MEM_NAMED(0x68008000u, 0x40, "vrfb-regs"),
DEFINE_RES_MEM_NAMED(0x70000000u, 0x4000000, "vrfb-area-0"),
DEFINE_RES_MEM_NAMED(0x74000000u, 0x4000000, "vrfb-area-1"),
DEFINE_RES_MEM_NAMED(0x78000000u, 0x4000000, "vrfb-area-2"),
DEFINE_RES_MEM_NAMED(0x7c000000u, 0x4000000, "vrfb-area-3"),
};
static const struct resource omap3_vrfb_resources[] = {
DEFINE_RES_MEM_NAMED(0x6C000180u, 0xc0, "vrfb-regs"),
DEFINE_RES_MEM_NAMED(0x70000000u, 0x4000000, "vrfb-area-0"),
DEFINE_RES_MEM_NAMED(0x74000000u, 0x4000000, "vrfb-area-1"),
DEFINE_RES_MEM_NAMED(0x78000000u, 0x4000000, "vrfb-area-2"),
DEFINE_RES_MEM_NAMED(0x7c000000u, 0x4000000, "vrfb-area-3"),
DEFINE_RES_MEM_NAMED(0xe0000000u, 0x4000000, "vrfb-area-4"),
DEFINE_RES_MEM_NAMED(0xe4000000u, 0x4000000, "vrfb-area-5"),
DEFINE_RES_MEM_NAMED(0xe8000000u, 0x4000000, "vrfb-area-6"),
DEFINE_RES_MEM_NAMED(0xec000000u, 0x4000000, "vrfb-area-7"),
DEFINE_RES_MEM_NAMED(0xf0000000u, 0x4000000, "vrfb-area-8"),
DEFINE_RES_MEM_NAMED(0xf4000000u, 0x4000000, "vrfb-area-9"),
DEFINE_RES_MEM_NAMED(0xf8000000u, 0x4000000, "vrfb-area-10"),
DEFINE_RES_MEM_NAMED(0xfc000000u, 0x4000000, "vrfb-area-11"),
};
static int __init omap_init_vrfb(void)
{
struct platform_device *pdev;
const struct resource *res;
unsigned int num_res;
if (cpu_is_omap24xx()) {
res = omap2_vrfb_resources;
num_res = ARRAY_SIZE(omap2_vrfb_resources);
} else if (cpu_is_omap34xx()) {
res = omap3_vrfb_resources;
num_res = ARRAY_SIZE(omap3_vrfb_resources);
} else {
return 0;
}
pdev = platform_device_register_resndata(NULL, "omapvrfb", -1,
res, num_res, NULL, 0);
if (IS_ERR(pdev))
return PTR_ERR(pdev);
else
return 0;
}
arch_initcall(omap_init_vrfb);
#endif
#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
static bool omapfb_lcd_configured;
@ -45,7 +107,7 @@ static struct platform_device omap_fb_device = {
.id = -1,
.dev = {
.dma_mask = &omap_fb_dma_mask,
.coherent_dma_mask = ~(u32)0,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &omapfb_config,
},
.num_resources = 0,
@ -81,7 +143,7 @@ static struct platform_device omap_fb_device = {
.id = -1,
.dev = {
.dma_mask = &omap_fb_dma_mask,
.coherent_dma_mask = ~(u32)0,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &omapfb_config,
},
.num_resources = 0,

View File

@ -94,9 +94,6 @@
/* SMS register offsets - read/write with sms_{read,write}_reg() */
#define SMS_SYSCONFIG 0x010
#define SMS_ROT_CONTROL(context) (0x180 + 0x10 * context)
#define SMS_ROT_SIZE(context) (0x184 + 0x10 * context)
#define SMS_ROT_PHYSICAL_BA(context) (0x188 + 0x10 * context)
/* REVISIT: fill in other SMS registers here */
@ -137,10 +134,6 @@ int omap2_sdrc_get_params(unsigned long r,
void omap2_sms_save_context(void);
void omap2_sms_restore_context(void);
void omap2_sms_write_rot_control(u32 val, unsigned ctx);
void omap2_sms_write_rot_size(u32 val, unsigned ctx);
void omap2_sms_write_rot_physical_ba(u32 val, unsigned ctx);
#ifdef CONFIG_ARCH_OMAP2
struct memory_timings {

View File

@ -1,43 +0,0 @@
/*
* VRAM manager for OMAP
*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that 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.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __OMAP_VRAM_H__
#define __OMAP_VRAM_H__
#include <linux/types.h>
extern int omap_vram_add_region(unsigned long paddr, size_t size);
extern int omap_vram_free(unsigned long paddr, size_t size);
extern int omap_vram_alloc(size_t size, unsigned long *paddr);
extern int omap_vram_reserve(unsigned long paddr, size_t size);
extern void omap_vram_get_info(unsigned long *vram, unsigned long *free_vram,
unsigned long *largest_free_block);
#ifdef CONFIG_OMAP2_VRAM
extern void omap_vram_set_sdram_vram(u32 size, u32 start);
extern void omap_vram_reserve_sdram_memblock(void);
#else
static inline void omap_vram_set_sdram_vram(u32 size, u32 start) { }
static inline void omap_vram_reserve_sdram_memblock(void) { }
#endif
#endif

View File

@ -44,9 +44,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <plat/cpu.h>
#include <plat/dma.h>
#include <plat/vrfb.h>
#include <video/omapvrfb.h>
#include <video/omapdss.h>
#include "omap_voutlib.h"
@ -2064,7 +2062,7 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev)
vout->vid_info.id = k + 1;
/* Set VRFB as rotation_type for omap2 and omap3 */
if (cpu_is_omap24xx() || cpu_is_omap34xx())
if (omap_vout_dss_omap24xx() || omap_vout_dss_omap34xx())
vout->vid_info.rotation_type = VOUT_ROT_VRFB;
/* Setup the default configuration for the video devices
@ -2186,14 +2184,23 @@ static int __init omap_vout_probe(struct platform_device *pdev)
struct omap_dss_device *def_display;
struct omap2video_device *vid_dev = NULL;
ret = omapdss_compat_init();
if (ret) {
dev_err(&pdev->dev, "failed to init dss\n");
return ret;
}
if (pdev->num_resources == 0) {
dev_err(&pdev->dev, "probed for an unknown device\n");
return -ENODEV;
ret = -ENODEV;
goto err_dss_init;
}
vid_dev = kzalloc(sizeof(struct omap2video_device), GFP_KERNEL);
if (vid_dev == NULL)
return -ENOMEM;
if (vid_dev == NULL) {
ret = -ENOMEM;
goto err_dss_init;
}
vid_dev->num_displays = 0;
for_each_dss_dev(dssdev) {
@ -2288,6 +2295,8 @@ probe_err1:
}
probe_err0:
kfree(vid_dev);
err_dss_init:
omapdss_compat_uninit();
return ret;
}

View File

@ -17,7 +17,7 @@
#include <media/v4l2-device.h>
#include <plat/dma.h>
#include <plat/vrfb.h>
#include <video/omapvrfb.h>
#include "omap_voutdef.h"
#include "omap_voutlib.h"

View File

@ -12,7 +12,7 @@
#define OMAP_VOUTDEF_H
#include <video/omapdss.h>
#include <plat/vrfb.h>
#include <video/omapvrfb.h>
#define YUYV_BPP 2
#define RGB565_BPP 2

View File

@ -26,7 +26,7 @@
#include <linux/dma-mapping.h>
#include <plat/cpu.h>
#include <video/omapdss.h>
#include "omap_voutlib.h"
@ -124,7 +124,7 @@ int omap_vout_new_window(struct v4l2_rect *crop,
win->chromakey = new_win->chromakey;
/* Adjust the cropping window to allow for resizing limitation */
if (cpu_is_omap24xx()) {
if (omap_vout_dss_omap24xx()) {
/* For 24xx limit is 8x to 1/2x scaling. */
if ((crop->height/win->w.height) >= 2)
crop->height = win->w.height * 2;
@ -140,7 +140,7 @@ int omap_vout_new_window(struct v4l2_rect *crop,
if (crop->height != win->w.height)
crop->width = 768;
}
} else if (cpu_is_omap34xx()) {
} else if (omap_vout_dss_omap34xx()) {
/* For 34xx limit is 8x to 1/4x scaling. */
if ((crop->height/win->w.height) >= 4)
crop->height = win->w.height * 4;
@ -196,7 +196,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix,
if (try_crop.width <= 0 || try_crop.height <= 0)
return -EINVAL;
if (cpu_is_omap24xx()) {
if (omap_vout_dss_omap24xx()) {
if (try_crop.height != win->w.height) {
/* If we're resizing vertically, we can't support a
* crop width wider than 768 pixels.
@ -207,9 +207,9 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix,
}
/* vertical resizing */
vresize = (1024 * try_crop.height) / win->w.height;
if (cpu_is_omap24xx() && (vresize > 2048))
if (omap_vout_dss_omap24xx() && (vresize > 2048))
vresize = 2048;
else if (cpu_is_omap34xx() && (vresize > 4096))
else if (omap_vout_dss_omap34xx() && (vresize > 4096))
vresize = 4096;
win->w.height = ((1024 * try_crop.height) / vresize) & ~1;
@ -226,9 +226,9 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix,
}
/* horizontal resizing */
hresize = (1024 * try_crop.width) / win->w.width;
if (cpu_is_omap24xx() && (hresize > 2048))
if (omap_vout_dss_omap24xx() && (hresize > 2048))
hresize = 2048;
else if (cpu_is_omap34xx() && (hresize > 4096))
else if (omap_vout_dss_omap34xx() && (hresize > 4096))
hresize = 4096;
win->w.width = ((1024 * try_crop.width) / hresize) & ~1;
@ -243,7 +243,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix,
if (try_crop.width == 0)
try_crop.width = 2;
}
if (cpu_is_omap24xx()) {
if (omap_vout_dss_omap24xx()) {
if ((try_crop.height/win->w.height) >= 2)
try_crop.height = win->w.height * 2;
@ -258,7 +258,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix,
if (try_crop.height != win->w.height)
try_crop.width = 768;
}
} else if (cpu_is_omap34xx()) {
} else if (omap_vout_dss_omap34xx()) {
if ((try_crop.height/win->w.height) >= 4)
try_crop.height = win->w.height * 4;
@ -337,3 +337,21 @@ void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size)
}
free_pages((unsigned long) virtaddr, order);
}
bool omap_vout_dss_omap24xx(void)
{
return omapdss_get_version() == OMAPDSS_VER_OMAP24xx;
}
bool omap_vout_dss_omap34xx(void)
{
switch (omapdss_get_version()) {
case OMAPDSS_VER_OMAP34xx_ES1:
case OMAPDSS_VER_OMAP34xx_ES3:
case OMAPDSS_VER_OMAP3630:
case OMAPDSS_VER_AM35xx:
return true;
default:
return false;
}
}

View File

@ -32,5 +32,8 @@ void omap_vout_new_format(struct v4l2_pix_format *pix,
struct v4l2_window *win);
unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr);
void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size);
bool omap_vout_dss_omap24xx(void);
bool omap_vout_dss_omap34xx(void);
#endif /* #ifndef OMAP_VOUTLIB_H */

View File

@ -572,6 +572,14 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
dev->dev_private = priv;
ret = omapdss_compat_init();
if (ret) {
dev_err(dev->dev, "coult not init omapdss\n");
dev->dev_private = NULL;
kfree(priv);
return ret;
}
priv->wq = alloc_ordered_workqueue("omapdrm", 0);
INIT_LIST_HEAD(&priv->obj_list);
@ -583,6 +591,7 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
dev_err(dev->dev, "omap_modeset_init failed: ret=%d\n", ret);
dev->dev_private = NULL;
kfree(priv);
omapdss_compat_uninit();
return ret;
}
@ -618,6 +627,8 @@ static int dev_unload(struct drm_device *dev)
flush_workqueue(priv->wq);
destroy_workqueue(priv->wq);
omapdss_compat_uninit();
kfree(dev->dev_private);
dev->dev_private = NULL;

View File

@ -1,6 +1,3 @@
config OMAP2_VRAM
bool
config OMAP2_VRFB
bool

View File

@ -1,4 +1,3 @@
obj-$(CONFIG_OMAP2_VRAM) += vram.o
obj-$(CONFIG_OMAP2_VRFB) += vrfb.o
obj-$(CONFIG_OMAP2_DSS) += dss/

View File

@ -710,27 +710,6 @@ static void acx_panel_disable(struct omap_dss_device *dssdev)
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static int acx_panel_suspend(struct omap_dss_device *dssdev)
{
dev_dbg(&dssdev->dev, "%s\n", __func__);
acx_panel_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
return 0;
}
static int acx_panel_resume(struct omap_dss_device *dssdev)
{
int r;
dev_dbg(&dssdev->dev, "%s\n", __func__);
r = acx_panel_power_on(dssdev);
if (r)
return r;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
return 0;
}
static void acx_panel_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
@ -752,8 +731,6 @@ static struct omap_dss_driver acx_panel_driver = {
.enable = acx_panel_enable,
.disable = acx_panel_disable,
.suspend = acx_panel_suspend,
.resume = acx_panel_resume,
.set_timings = acx_panel_set_timings,
.check_timings = acx_panel_check_timings,

View File

@ -688,40 +688,6 @@ static void generic_dpi_panel_disable(struct omap_dss_device *dssdev)
mutex_unlock(&drv_data->lock);
}
static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev)
{
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
mutex_lock(&drv_data->lock);
generic_dpi_panel_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
mutex_unlock(&drv_data->lock);
return 0;
}
static int generic_dpi_panel_resume(struct omap_dss_device *dssdev)
{
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
int r;
mutex_lock(&drv_data->lock);
r = generic_dpi_panel_power_on(dssdev);
if (r)
goto err;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
err:
mutex_unlock(&drv_data->lock);
return r;
}
static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
@ -769,8 +735,6 @@ static struct omap_dss_driver dpi_driver = {
.enable = generic_dpi_panel_enable,
.disable = generic_dpi_panel_disable,
.suspend = generic_dpi_panel_suspend,
.resume = generic_dpi_panel_resume,
.set_timings = generic_dpi_panel_set_timings,
.get_timings = generic_dpi_panel_get_timings,

View File

@ -143,46 +143,12 @@ static void lb035q02_panel_disable(struct omap_dss_device *dssdev)
mutex_unlock(&ld->lock);
}
static int lb035q02_panel_suspend(struct omap_dss_device *dssdev)
{
struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev);
mutex_lock(&ld->lock);
lb035q02_panel_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
mutex_unlock(&ld->lock);
return 0;
}
static int lb035q02_panel_resume(struct omap_dss_device *dssdev)
{
struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev);
int r;
mutex_lock(&ld->lock);
r = lb035q02_panel_power_on(dssdev);
if (r)
goto err;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
mutex_unlock(&ld->lock);
return 0;
err:
mutex_unlock(&ld->lock);
return r;
}
static struct omap_dss_driver lb035q02_driver = {
.probe = lb035q02_panel_probe,
.remove = lb035q02_panel_remove,
.enable = lb035q02_panel_enable,
.disable = lb035q02_panel_disable,
.suspend = lb035q02_panel_suspend,
.resume = lb035q02_panel_resume,
.driver = {
.name = "lgphilips_lb035q02_panel",

View File

@ -574,54 +574,6 @@ static void n8x0_panel_disable(struct omap_dss_device *dssdev)
mutex_unlock(&ddata->lock);
}
static int n8x0_panel_suspend(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = get_drv_data(dssdev);
dev_dbg(&dssdev->dev, "suspend\n");
mutex_lock(&ddata->lock);
rfbi_bus_lock();
n8x0_panel_power_off(dssdev);
rfbi_bus_unlock();
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
mutex_unlock(&ddata->lock);
return 0;
}
static int n8x0_panel_resume(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = get_drv_data(dssdev);
int r;
dev_dbg(&dssdev->dev, "resume\n");
mutex_lock(&ddata->lock);
rfbi_bus_lock();
r = n8x0_panel_power_on(dssdev);
rfbi_bus_unlock();
if (r) {
mutex_unlock(&ddata->lock);
return r;
}
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
mutex_unlock(&ddata->lock);
return 0;
}
static void n8x0_panel_get_resolution(struct omap_dss_device *dssdev,
u16 *xres, u16 *yres)
{
@ -683,8 +635,6 @@ static struct omap_dss_driver n8x0_panel_driver = {
.enable = n8x0_panel_enable,
.disable = n8x0_panel_disable,
.suspend = n8x0_panel_suspend,
.resume = n8x0_panel_resume,
.update = n8x0_panel_update,
.sync = n8x0_panel_sync,
@ -702,18 +652,25 @@ static struct omap_dss_driver n8x0_panel_driver = {
static int mipid_spi_probe(struct spi_device *spi)
{
int r;
dev_dbg(&spi->dev, "mipid_spi_probe\n");
spi->mode = SPI_MODE_0;
s_drv_data.spidev = spi;
return 0;
r = omap_dss_register_driver(&n8x0_panel_driver);
if (r)
pr_err("n8x0_panel: dss driver registration failed\n");
return r;
}
static int mipid_spi_remove(struct spi_device *spi)
{
dev_dbg(&spi->dev, "mipid_spi_remove\n");
omap_dss_unregister_driver(&n8x0_panel_driver);
return 0;
}
@ -725,34 +682,6 @@ static struct spi_driver mipid_spi_driver = {
.probe = mipid_spi_probe,
.remove = __devexit_p(mipid_spi_remove),
};
module_spi_driver(mipid_spi_driver);
static int __init n8x0_panel_drv_init(void)
{
int r;
r = spi_register_driver(&mipid_spi_driver);
if (r) {
pr_err("n8x0_panel: spi driver registration failed\n");
return r;
}
r = omap_dss_register_driver(&n8x0_panel_driver);
if (r) {
pr_err("n8x0_panel: dss driver registration failed\n");
spi_unregister_driver(&mipid_spi_driver);
return r;
}
return 0;
}
static void __exit n8x0_panel_drv_exit(void)
{
spi_unregister_driver(&mipid_spi_driver);
omap_dss_unregister_driver(&n8x0_panel_driver);
}
module_init(n8x0_panel_drv_init);
module_exit(n8x0_panel_drv_exit);
MODULE_LICENSE("GPL");

View File

@ -236,28 +236,6 @@ static void nec_8048_panel_disable(struct omap_dss_device *dssdev)
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static int nec_8048_panel_suspend(struct omap_dss_device *dssdev)
{
nec_8048_panel_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
return 0;
}
static int nec_8048_panel_resume(struct omap_dss_device *dssdev)
{
int r;
r = nec_8048_panel_power_on(dssdev);
if (r)
return r;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
return 0;
}
static int nec_8048_recommended_bpp(struct omap_dss_device *dssdev)
{
return 16;
@ -268,8 +246,6 @@ static struct omap_dss_driver nec_8048_driver = {
.remove = nec_8048_panel_remove,
.enable = nec_8048_panel_enable,
.disable = nec_8048_panel_disable,
.suspend = nec_8048_panel_suspend,
.resume = nec_8048_panel_resume,
.get_recommended_bpp = nec_8048_recommended_bpp,
.driver = {

View File

@ -50,6 +50,7 @@ struct picodlp_i2c_data {
static struct i2c_device_id picodlp_i2c_id[] = {
{ "picodlp_i2c_driver", 0 },
{ }
};
struct picodlp_i2c_command {
@ -503,47 +504,6 @@ static void picodlp_panel_disable(struct omap_dss_device *dssdev)
dev_dbg(&dssdev->dev, "disabling picodlp panel\n");
}
static int picodlp_panel_suspend(struct omap_dss_device *dssdev)
{
struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
mutex_lock(&picod->lock);
/* Turn off DLP Power */
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
mutex_unlock(&picod->lock);
dev_err(&dssdev->dev, "unable to suspend picodlp panel,"
" panel is not ACTIVE\n");
return -EINVAL;
}
picodlp_panel_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
mutex_unlock(&picod->lock);
dev_dbg(&dssdev->dev, "suspending picodlp panel\n");
return 0;
}
static int picodlp_panel_resume(struct omap_dss_device *dssdev)
{
struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
int r;
mutex_lock(&picod->lock);
if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
mutex_unlock(&picod->lock);
dev_err(&dssdev->dev, "unable to resume picodlp panel,"
" panel is not ACTIVE\n");
return -EINVAL;
}
r = picodlp_panel_power_on(dssdev);
mutex_unlock(&picod->lock);
dev_dbg(&dssdev->dev, "resuming picodlp panel\n");
return r;
}
static void picodlp_get_resolution(struct omap_dss_device *dssdev,
u16 *xres, u16 *yres)
{
@ -560,9 +520,6 @@ static struct omap_dss_driver picodlp_driver = {
.get_resolution = picodlp_get_resolution,
.suspend = picodlp_panel_suspend,
.resume = picodlp_panel_resume,
.driver = {
.name = "picodlp_panel",
.owner = THIS_MODULE,

View File

@ -194,29 +194,12 @@ static void sharp_ls_panel_disable(struct omap_dss_device *dssdev)
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static int sharp_ls_panel_suspend(struct omap_dss_device *dssdev)
{
sharp_ls_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
return 0;
}
static int sharp_ls_panel_resume(struct omap_dss_device *dssdev)
{
int r;
r = sharp_ls_power_on(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
return r;
}
static struct omap_dss_driver sharp_ls_driver = {
.probe = sharp_ls_panel_probe,
.remove = __exit_p(sharp_ls_panel_remove),
.enable = sharp_ls_panel_enable,
.disable = sharp_ls_panel_disable,
.suspend = sharp_ls_panel_suspend,
.resume = sharp_ls_panel_resume,
.driver = {
.name = "sharp_ls_panel",

View File

@ -1245,76 +1245,6 @@ static void taal_disable(struct omap_dss_device *dssdev)
mutex_unlock(&td->lock);
}
static int taal_suspend(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
int r;
dev_dbg(&dssdev->dev, "suspend\n");
mutex_lock(&td->lock);
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
r = -EINVAL;
goto err;
}
taal_cancel_ulps_work(dssdev);
taal_cancel_esd_work(dssdev);
dsi_bus_lock(dssdev);
r = taal_wake_up(dssdev);
if (!r)
taal_power_off(dssdev);
dsi_bus_unlock(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
mutex_unlock(&td->lock);
return 0;
err:
mutex_unlock(&td->lock);
return r;
}
static int taal_resume(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
int r;
dev_dbg(&dssdev->dev, "resume\n");
mutex_lock(&td->lock);
if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
r = -EINVAL;
goto err;
}
dsi_bus_lock(dssdev);
r = taal_power_on(dssdev);
dsi_bus_unlock(dssdev);
if (r) {
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
} else {
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
taal_queue_esd_work(dssdev);
}
mutex_unlock(&td->lock);
return r;
err:
mutex_unlock(&td->lock);
return r;
}
static void taal_framedone_cb(int err, void *data)
{
struct omap_dss_device *dssdev = data;
@ -1818,8 +1748,6 @@ static struct omap_dss_driver taal_driver = {
.enable = taal_enable,
.disable = taal_disable,
.suspend = taal_suspend,
.resume = taal_resume,
.update = taal_update,
.sync = taal_sync,

View File

@ -189,37 +189,6 @@ static void tfp410_disable(struct omap_dss_device *dssdev)
mutex_unlock(&ddata->lock);
}
static int tfp410_suspend(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
mutex_lock(&ddata->lock);
tfp410_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
mutex_unlock(&ddata->lock);
return 0;
}
static int tfp410_resume(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
int r;
mutex_lock(&ddata->lock);
r = tfp410_power_on(dssdev);
if (r == 0)
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
mutex_unlock(&ddata->lock);
return r;
}
static void tfp410_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
@ -355,8 +324,6 @@ static struct omap_dss_driver tfp410_driver = {
.enable = tfp410_enable,
.disable = tfp410_disable,
.suspend = tfp410_suspend,
.resume = tfp410_resume,
.set_timings = tfp410_set_timings,
.get_timings = tfp410_get_timings,

View File

@ -401,24 +401,6 @@ static void tpo_td043_disable(struct omap_dss_device *dssdev)
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static int tpo_td043_suspend(struct omap_dss_device *dssdev)
{
dev_dbg(&dssdev->dev, "suspend\n");
tpo_td043_disable_dss(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
return 0;
}
static int tpo_td043_resume(struct omap_dss_device *dssdev)
{
dev_dbg(&dssdev->dev, "resume\n");
return tpo_td043_enable_dss(dssdev);
}
static int tpo_td043_probe(struct omap_dss_device *dssdev)
{
struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
@ -500,8 +482,6 @@ static struct omap_dss_driver tpo_td043_driver = {
.enable = tpo_td043_enable,
.disable = tpo_td043_disable,
.suspend = tpo_td043_suspend,
.resume = tpo_td043_resume,
.set_mirror = tpo_td043_set_hmirror,
.get_mirror = tpo_td043_get_hmirror,

View File

@ -1,33 +1,30 @@
menuconfig OMAP2_DSS
tristate "OMAP2+ Display Subsystem support"
depends on ARCH_OMAP2PLUS
help
OMAP2+ Display Subsystem support.
if OMAP2_DSS
config OMAP2_VRAM_SIZE
int "VRAM size (MB)"
range 0 32
default 0
config OMAP2_DSS_DEBUG
bool "Debug support"
default n
help
The amount of SDRAM to reserve at boot time for video RAM use.
This VRAM will be used by omapfb and other drivers that need
large continuous RAM area for video use.
This enables printing of debug messages. Alternatively, debug messages
can also be enabled by setting CONFIG_DYNAMIC_DEBUG and then setting
appropriate flags in <debugfs>/dynamic_debug/control.
You can also set this with "vram=<bytes>" kernel argument, or
in the board file.
config OMAP2_DSS_DEBUG_SUPPORT
bool "Debug support"
default y
config OMAP2_DSS_DEBUGFS
bool "Debugfs filesystem support"
depends on DEBUG_FS
default n
help
This enables debug messages. You need to enable printing
with 'debug' module parameter.
This enables debugfs for OMAPDSS at <debugfs>/omapdss. This enables
querying about clock configuration and register configuration of dss,
dispc, dsi, hdmi and rfbi.
config OMAP2_DSS_COLLECT_IRQ_STATS
bool "Collect DSS IRQ statistics"
depends on OMAP2_DSS_DEBUG_SUPPORT
depends on OMAP2_DSS_DEBUGFS
default n
help
Collect DSS IRQ statistics, printable via debugfs.
@ -62,7 +59,6 @@ config OMAP2_DSS_VENC
config OMAP4_DSS_HDMI
bool "HDMI support"
depends on ARCH_OMAP4
default y
help
HDMI Interface. This adds the High Definition Multimedia Interface.
@ -70,11 +66,9 @@ config OMAP4_DSS_HDMI
config OMAP4_DSS_HDMI_AUDIO
bool
depends on OMAP4_DSS_HDMI
config OMAP2_DSS_SDI
bool "SDI support"
depends on ARCH_OMAP3
default n
help
SDI (Serial Display Interface) support.
@ -84,7 +78,6 @@ config OMAP2_DSS_SDI
config OMAP2_DSS_DSI
bool "DSI support"
depends on ARCH_OMAP3 || ARCH_OMAP4 || ARCH_OMAP5
default n
help
MIPI DSI (Display Serial Interface) support.

View File

@ -1,6 +1,10 @@
obj-$(CONFIG_OMAP2_DSS) += omapdss.o
# Core DSS files
omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
manager.o manager-sysfs.o overlay.o overlay-sysfs.o output.o apply.o
output.o
# DSS compat layer files
omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \
dispc-compat.o display-sysfs.o
omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o
omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o venc_panel.o
@ -8,3 +12,4 @@ omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \
hdmi_panel.o ti_hdmi_4xxx_ip.o
ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG

View File

@ -18,6 +18,7 @@
#define DSS_SUBSYS_NAME "APPLY"
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/jiffies.h>
@ -26,6 +27,7 @@
#include "dss.h"
#include "dss_features.h"
#include "dispc-compat.h"
/*
* We have 4 levels of cache for the dispc settings. First two are in SW and
@ -70,7 +72,6 @@ struct ovl_priv_data {
bool shadow_extra_info_dirty;
bool enabled;
enum omap_channel channel;
u32 fifo_low, fifo_high;
/*
@ -105,6 +106,9 @@ struct mgr_priv_data {
struct omap_video_timings timings;
struct dss_lcd_mgr_config lcd_config;
void (*framedone_handler)(void *);
void *framedone_handler_data;
};
static struct {
@ -132,7 +136,7 @@ static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
return &dss_data.mgr_priv_data_array[mgr->id];
}
void dss_apply_init(void)
static void apply_init_priv(void)
{
const int num_ovls = dss_feat_get_num_ovls();
struct mgr_priv_data *mp;
@ -414,11 +418,46 @@ static void wait_pending_extra_info_updates(void)
r = wait_for_completion_timeout(&extra_updated_completion, t);
if (r == 0)
DSSWARN("timeout in wait_pending_extra_info_updates\n");
else if (r < 0)
DSSERR("wait_pending_extra_info_updates failed: %d\n", r);
}
int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
static inline struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl)
{
return ovl->manager ?
(ovl->manager->output ? ovl->manager->output->device : NULL) :
NULL;
}
static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr)
{
return mgr->output ? mgr->output->device : NULL;
}
static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
{
unsigned long timeout = msecs_to_jiffies(500);
struct omap_dss_device *dssdev = mgr->get_device(mgr);
u32 irq;
int r;
r = dispc_runtime_get();
if (r)
return r;
if (dssdev->type == OMAP_DISPLAY_TYPE_VENC)
irq = DISPC_IRQ_EVSYNC_ODD;
else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI)
irq = DISPC_IRQ_EVSYNC_EVEN;
else
irq = dispc_mgr_get_vsync_irq(mgr->id);
r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
dispc_runtime_put();
return r;
}
static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
{
unsigned long timeout = msecs_to_jiffies(500);
struct mgr_priv_data *mp = get_mgr_priv(mgr);
@ -488,7 +527,7 @@ int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
return r;
}
int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
static int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
{
unsigned long timeout = msecs_to_jiffies(500);
struct ovl_priv_data *op;
@ -573,7 +612,7 @@ static void dss_ovl_write_regs(struct omap_overlay *ovl)
struct mgr_priv_data *mp;
int r;
DSSDBGF("%d", ovl->id);
DSSDBG("writing ovl %d regs", ovl->id);
if (!op->enabled || !op->info_dirty)
return;
@ -608,7 +647,7 @@ static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
struct ovl_priv_data *op = get_ovl_priv(ovl);
struct mgr_priv_data *mp;
DSSDBGF("%d", ovl->id);
DSSDBG("writing ovl %d regs extra", ovl->id);
if (!op->extra_info_dirty)
return;
@ -617,7 +656,6 @@ static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
* disabled */
dispc_ovl_enable(ovl->id, op->enabled);
dispc_ovl_set_channel_out(ovl->id, op->channel);
dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
mp = get_mgr_priv(ovl->manager);
@ -632,7 +670,7 @@ static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
struct mgr_priv_data *mp = get_mgr_priv(mgr);
struct omap_overlay *ovl;
DSSDBGF("%d", mgr->id);
DSSDBG("writing mgr %d regs", mgr->id);
if (!mp->enabled)
return;
@ -658,7 +696,7 @@ static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr)
{
struct mgr_priv_data *mp = get_mgr_priv(mgr);
DSSDBGF("%d", mgr->id);
DSSDBG("writing mgr %d regs extra", mgr->id);
if (!mp->extra_info_dirty)
return;
@ -666,22 +704,8 @@ static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr)
dispc_mgr_set_timings(mgr->id, &mp->timings);
/* lcd_config parameters */
if (dss_mgr_is_lcd(mgr->id)) {
dispc_mgr_set_io_pad_mode(mp->lcd_config.io_pad_mode);
dispc_mgr_enable_stallmode(mgr->id, mp->lcd_config.stallmode);
dispc_mgr_enable_fifohandcheck(mgr->id,
mp->lcd_config.fifohandcheck);
dispc_mgr_set_clock_div(mgr->id, &mp->lcd_config.clock_info);
dispc_mgr_set_tft_data_lines(mgr->id,
mp->lcd_config.video_port_width);
dispc_lcd_enable_signal_polarity(mp->lcd_config.lcden_sig_polarity);
dispc_mgr_set_lcd_type_tft(mgr->id);
}
if (dss_mgr_is_lcd(mgr->id))
dispc_mgr_set_lcd_config(mgr->id, &mp->lcd_config);
mp->extra_info_dirty = false;
if (mp->updating)
@ -761,7 +785,7 @@ static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
}
}
void dss_mgr_start_update(struct omap_overlay_manager *mgr)
static void dss_mgr_start_update_compat(struct omap_overlay_manager *mgr)
{
struct mgr_priv_data *mp = get_mgr_priv(mgr);
unsigned long flags;
@ -786,9 +810,7 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr)
if (!dss_data.irq_enabled && need_isr())
dss_register_vsync_isr();
dispc_mgr_enable(mgr->id, true);
mgr_clear_shadow_dirty(mgr);
dispc_mgr_enable_sync(mgr->id);
spin_unlock_irqrestore(&data_lock, flags);
}
@ -845,7 +867,6 @@ static void dss_apply_irq_handler(void *data, u32 mask)
for (i = 0; i < num_mgrs; i++) {
struct omap_overlay_manager *mgr;
struct mgr_priv_data *mp;
bool was_updating;
mgr = omap_dss_get_overlay_manager(i);
mp = get_mgr_priv(mgr);
@ -853,7 +874,6 @@ static void dss_apply_irq_handler(void *data, u32 mask)
if (!mp->enabled)
continue;
was_updating = mp->updating;
mp->updating = dispc_mgr_is_enabled(i);
if (!mgr_manual_update(mgr)) {
@ -872,6 +892,21 @@ static void dss_apply_irq_handler(void *data, u32 mask)
if (!extra_updating)
complete_all(&extra_updated_completion);
/* call framedone handlers for manual update displays */
for (i = 0; i < num_mgrs; i++) {
struct omap_overlay_manager *mgr;
struct mgr_priv_data *mp;
mgr = omap_dss_get_overlay_manager(i);
mp = get_mgr_priv(mgr);
if (!mgr_manual_update(mgr) || !mp->framedone_handler)
continue;
if (mask & dispc_mgr_get_framedone_irq(i))
mp->framedone_handler(mp->framedone_handler_data);
}
if (!need_isr())
dss_unregister_vsync_isr();
@ -906,7 +941,7 @@ static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
mp->info = mp->user_info;
}
int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
{
unsigned long flags;
struct omap_overlay *ovl;
@ -1005,7 +1040,7 @@ static void dss_setup_fifos(void)
}
}
int dss_mgr_enable(struct omap_overlay_manager *mgr)
static int dss_mgr_enable_compat(struct omap_overlay_manager *mgr)
{
struct mgr_priv_data *mp = get_mgr_priv(mgr);
unsigned long flags;
@ -1035,10 +1070,13 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr)
if (!mgr_manual_update(mgr))
mp->updating = true;
if (!dss_data.irq_enabled && need_isr())
dss_register_vsync_isr();
spin_unlock_irqrestore(&data_lock, flags);
if (!mgr_manual_update(mgr))
dispc_mgr_enable(mgr->id, true);
dispc_mgr_enable_sync(mgr->id);
out:
mutex_unlock(&apply_lock);
@ -1052,7 +1090,7 @@ err:
return r;
}
void dss_mgr_disable(struct omap_overlay_manager *mgr)
static void dss_mgr_disable_compat(struct omap_overlay_manager *mgr)
{
struct mgr_priv_data *mp = get_mgr_priv(mgr);
unsigned long flags;
@ -1063,7 +1101,7 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr)
goto out;
if (!mgr_manual_update(mgr))
dispc_mgr_enable(mgr->id, false);
dispc_mgr_disable_sync(mgr->id);
spin_lock_irqsave(&data_lock, flags);
@ -1076,7 +1114,7 @@ out:
mutex_unlock(&apply_lock);
}
int dss_mgr_set_info(struct omap_overlay_manager *mgr,
static int dss_mgr_set_info(struct omap_overlay_manager *mgr,
struct omap_overlay_manager_info *info)
{
struct mgr_priv_data *mp = get_mgr_priv(mgr);
@ -1097,7 +1135,7 @@ int dss_mgr_set_info(struct omap_overlay_manager *mgr,
return 0;
}
void dss_mgr_get_info(struct omap_overlay_manager *mgr,
static void dss_mgr_get_info(struct omap_overlay_manager *mgr,
struct omap_overlay_manager_info *info)
{
struct mgr_priv_data *mp = get_mgr_priv(mgr);
@ -1110,7 +1148,7 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr,
spin_unlock_irqrestore(&data_lock, flags);
}
int dss_mgr_set_output(struct omap_overlay_manager *mgr,
static int dss_mgr_set_output(struct omap_overlay_manager *mgr,
struct omap_dss_output *output)
{
int r;
@ -1142,7 +1180,7 @@ err:
return r;
}
int dss_mgr_unset_output(struct omap_overlay_manager *mgr)
static int dss_mgr_unset_output(struct omap_overlay_manager *mgr)
{
int r;
struct mgr_priv_data *mp = get_mgr_priv(mgr);
@ -1189,7 +1227,7 @@ static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr,
mp->extra_info_dirty = true;
}
void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
static void dss_mgr_set_timings_compat(struct omap_overlay_manager *mgr,
const struct omap_video_timings *timings)
{
unsigned long flags;
@ -1217,7 +1255,7 @@ static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr,
mp->extra_info_dirty = true;
}
void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
static void dss_mgr_set_lcd_config_compat(struct omap_overlay_manager *mgr,
const struct dss_lcd_mgr_config *config)
{
unsigned long flags;
@ -1236,7 +1274,7 @@ out:
spin_unlock_irqrestore(&data_lock, flags);
}
int dss_ovl_set_info(struct omap_overlay *ovl,
static int dss_ovl_set_info(struct omap_overlay *ovl,
struct omap_overlay_info *info)
{
struct ovl_priv_data *op = get_ovl_priv(ovl);
@ -1257,7 +1295,7 @@ int dss_ovl_set_info(struct omap_overlay *ovl,
return 0;
}
void dss_ovl_get_info(struct omap_overlay *ovl,
static void dss_ovl_get_info(struct omap_overlay *ovl,
struct omap_overlay_info *info)
{
struct ovl_priv_data *op = get_ovl_priv(ovl);
@ -1270,7 +1308,7 @@ void dss_ovl_get_info(struct omap_overlay *ovl,
spin_unlock_irqrestore(&data_lock, flags);
}
int dss_ovl_set_manager(struct omap_overlay *ovl,
static int dss_ovl_set_manager(struct omap_overlay *ovl,
struct omap_overlay_manager *mgr)
{
struct ovl_priv_data *op = get_ovl_priv(ovl);
@ -1289,45 +1327,40 @@ int dss_ovl_set_manager(struct omap_overlay *ovl,
goto err;
}
r = dispc_runtime_get();
if (r)
goto err;
spin_lock_irqsave(&data_lock, flags);
if (op->enabled) {
spin_unlock_irqrestore(&data_lock, flags);
DSSERR("overlay has to be disabled to change the manager\n");
r = -EINVAL;
goto err;
goto err1;
}
op->channel = mgr->id;
op->extra_info_dirty = true;
dispc_ovl_set_channel_out(ovl->id, mgr->id);
ovl->manager = mgr;
list_add_tail(&ovl->list, &mgr->overlays);
spin_unlock_irqrestore(&data_lock, flags);
/* XXX: When there is an overlay on a DSI manual update display, and
* the overlay is first disabled, then moved to tv, and enabled, we
* seem to get SYNC_LOST_DIGIT error.
*
* Waiting doesn't seem to help, but updating the manual update display
* after disabling the overlay seems to fix this. This hints that the
* overlay is perhaps somehow tied to the LCD output until the output
* is updated.
*
* Userspace workaround for this is to update the LCD after disabling
* the overlay, but before moving the overlay to TV.
*/
dispc_runtime_put();
mutex_unlock(&apply_lock);
return 0;
err1:
dispc_runtime_put();
err:
mutex_unlock(&apply_lock);
return r;
}
int dss_ovl_unset_manager(struct omap_overlay *ovl)
static int dss_ovl_unset_manager(struct omap_overlay *ovl)
{
struct ovl_priv_data *op = get_ovl_priv(ovl);
unsigned long flags;
@ -1355,9 +1388,24 @@ int dss_ovl_unset_manager(struct omap_overlay *ovl)
/* wait for pending extra_info updates to ensure the ovl is disabled */
wait_pending_extra_info_updates();
/*
* For a manual update display, there is no guarantee that the overlay
* is really disabled in HW, we may need an extra update from this
* manager before the configurations can go in. Return an error if the
* overlay needed an update from the manager.
*
* TODO: Instead of returning an error, try to do a dummy manager update
* here to disable the overlay in hardware. Use the *GATED fields in
* the DISPC_CONFIG registers to do a dummy update.
*/
spin_lock_irqsave(&data_lock, flags);
op->channel = -1;
if (ovl_manual_update(ovl) && op->extra_info_dirty) {
spin_unlock_irqrestore(&data_lock, flags);
DSSERR("need an update to change the manager\n");
r = -EINVAL;
goto err;
}
ovl->manager = NULL;
list_del(&ovl->list);
@ -1372,7 +1420,7 @@ err:
return r;
}
bool dss_ovl_is_enabled(struct omap_overlay *ovl)
static bool dss_ovl_is_enabled(struct omap_overlay *ovl)
{
struct ovl_priv_data *op = get_ovl_priv(ovl);
unsigned long flags;
@ -1387,7 +1435,7 @@ bool dss_ovl_is_enabled(struct omap_overlay *ovl)
return e;
}
int dss_ovl_enable(struct omap_overlay *ovl)
static int dss_ovl_enable(struct omap_overlay *ovl)
{
struct ovl_priv_data *op = get_ovl_priv(ovl);
unsigned long flags;
@ -1437,7 +1485,7 @@ err1:
return r;
}
int dss_ovl_disable(struct omap_overlay *ovl)
static int dss_ovl_disable(struct omap_overlay *ovl)
{
struct ovl_priv_data *op = get_ovl_priv(ovl);
unsigned long flags;
@ -1472,3 +1520,152 @@ err:
return r;
}
static int dss_mgr_register_framedone_handler_compat(struct omap_overlay_manager *mgr,
void (*handler)(void *), void *data)
{
struct mgr_priv_data *mp = get_mgr_priv(mgr);
if (mp->framedone_handler)
return -EBUSY;
mp->framedone_handler = handler;
mp->framedone_handler_data = data;
return 0;
}
static void dss_mgr_unregister_framedone_handler_compat(struct omap_overlay_manager *mgr,
void (*handler)(void *), void *data)
{
struct mgr_priv_data *mp = get_mgr_priv(mgr);
WARN_ON(mp->framedone_handler != handler ||
mp->framedone_handler_data != data);
mp->framedone_handler = NULL;
mp->framedone_handler_data = NULL;
}
static const struct dss_mgr_ops apply_mgr_ops = {
.start_update = dss_mgr_start_update_compat,
.enable = dss_mgr_enable_compat,
.disable = dss_mgr_disable_compat,
.set_timings = dss_mgr_set_timings_compat,
.set_lcd_config = dss_mgr_set_lcd_config_compat,
.register_framedone_handler = dss_mgr_register_framedone_handler_compat,
.unregister_framedone_handler = dss_mgr_unregister_framedone_handler_compat,
};
static int compat_refcnt;
static DEFINE_MUTEX(compat_init_lock);
int omapdss_compat_init(void)
{
struct platform_device *pdev = dss_get_core_pdev();
struct omap_dss_device *dssdev = NULL;
int i, r;
mutex_lock(&compat_init_lock);
if (compat_refcnt++ > 0)
goto out;
apply_init_priv();
dss_init_overlay_managers(pdev);
dss_init_overlays(pdev);
for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) {
struct omap_overlay_manager *mgr;
mgr = omap_dss_get_overlay_manager(i);
mgr->set_output = &dss_mgr_set_output;
mgr->unset_output = &dss_mgr_unset_output;
mgr->apply = &omap_dss_mgr_apply;
mgr->set_manager_info = &dss_mgr_set_info;
mgr->get_manager_info = &dss_mgr_get_info;
mgr->wait_for_go = &dss_mgr_wait_for_go;
mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
mgr->get_device = &dss_mgr_get_device;
}
for (i = 0; i < omap_dss_get_num_overlays(); i++) {
struct omap_overlay *ovl = omap_dss_get_overlay(i);
ovl->is_enabled = &dss_ovl_is_enabled;
ovl->enable = &dss_ovl_enable;
ovl->disable = &dss_ovl_disable;
ovl->set_manager = &dss_ovl_set_manager;
ovl->unset_manager = &dss_ovl_unset_manager;
ovl->set_overlay_info = &dss_ovl_set_info;
ovl->get_overlay_info = &dss_ovl_get_info;
ovl->wait_for_go = &dss_mgr_wait_for_go_ovl;
ovl->get_device = &dss_ovl_get_device;
}
r = dss_install_mgr_ops(&apply_mgr_ops);
if (r)
goto err_mgr_ops;
for_each_dss_dev(dssdev) {
r = display_init_sysfs(pdev, dssdev);
/* XXX uninit sysfs files on error */
if (r)
goto err_disp_sysfs;
}
dispc_runtime_get();
r = dss_dispc_initialize_irq();
if (r)
goto err_init_irq;
dispc_runtime_put();
out:
mutex_unlock(&compat_init_lock);
return 0;
err_init_irq:
dispc_runtime_put();
err_disp_sysfs:
dss_uninstall_mgr_ops();
err_mgr_ops:
dss_uninit_overlay_managers(pdev);
dss_uninit_overlays(pdev);
compat_refcnt--;
mutex_unlock(&compat_init_lock);
return r;
}
EXPORT_SYMBOL(omapdss_compat_init);
void omapdss_compat_uninit(void)
{
struct platform_device *pdev = dss_get_core_pdev();
struct omap_dss_device *dssdev = NULL;
mutex_lock(&compat_init_lock);
if (--compat_refcnt > 0)
goto out;
dss_dispc_uninitialize_irq();
for_each_dss_dev(dssdev)
display_uninit_sysfs(pdev, dssdev);
dss_uninstall_mgr_ops();
dss_uninit_overlay_managers(pdev);
dss_uninit_overlays(pdev);
out:
mutex_unlock(&compat_init_lock);
}
EXPORT_SYMBOL(omapdss_compat_uninit);

View File

@ -53,15 +53,23 @@ static char *def_disp_name;
module_param_named(def_disp, def_disp_name, charp, 0);
MODULE_PARM_DESC(def_disp, "default display name");
#ifdef DEBUG
bool dss_debug;
module_param_named(debug, dss_debug, bool, 0644);
#endif
const char *dss_get_default_display_name(void)
const char *omapdss_get_default_display_name(void)
{
return core.default_display_name;
}
EXPORT_SYMBOL(omapdss_get_default_display_name);
enum omapdss_version omapdss_get_version(void)
{
struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
return pdata->version;
}
EXPORT_SYMBOL(omapdss_get_version);
struct platform_device *dss_get_core_pdev(void)
{
return core.pdev;
}
/* REGULATORS */
@ -93,21 +101,6 @@ struct regulator *dss_get_vdds_sdi(void)
return reg;
}
int dss_get_ctx_loss_count(struct device *dev)
{
struct omap_dss_board_info *board_data = core.pdev->dev.platform_data;
int cnt;
if (!board_data->get_context_loss_count)
return -ENOENT;
cnt = board_data->get_context_loss_count(dev);
WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt);
return cnt;
}
int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask)
{
struct omap_dss_board_info *board_data = core.pdev->dev.platform_data;
@ -122,7 +115,7 @@ void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask)
{
struct omap_dss_board_info *board_data = core.pdev->dev.platform_data;
if (!board_data->dsi_enable_pads)
if (!board_data->dsi_disable_pads)
return;
return board_data->dsi_disable_pads(dsi_id, lane_mask);
@ -138,7 +131,7 @@ int dss_set_min_bus_tput(struct device *dev, unsigned long tput)
return 0;
}
#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
#if defined(CONFIG_OMAP2_DSS_DEBUGFS)
static int dss_debug_show(struct seq_file *s, void *unused)
{
void (*func)(struct seq_file *) = s->private;
@ -193,7 +186,7 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
return 0;
}
#else /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */
#else /* CONFIG_OMAP2_DSS_DEBUGFS */
static inline int dss_initialize_debugfs(void)
{
return 0;
@ -205,7 +198,7 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
{
return 0;
}
#endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */
#endif /* CONFIG_OMAP2_DSS_DEBUGFS */
/* PLATFORM DEVICE */
static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d)
@ -237,12 +230,7 @@ static int __init omap_dss_probe(struct platform_device *pdev)
core.pdev = pdev;
dss_features_init();
dss_apply_init();
dss_init_overlay_managers(pdev);
dss_init_overlays(pdev);
dss_features_init(omapdss_get_version());
r = dss_initialize_debugfs();
if (r)
@ -268,9 +256,6 @@ static int omap_dss_remove(struct platform_device *pdev)
dss_uninitialize_debugfs();
dss_uninit_overlays(pdev);
dss_uninit_overlay_managers(pdev);
return 0;
}
@ -358,15 +343,10 @@ static int dss_driver_probe(struct device *dev)
dev_name(dev), dssdev->driver_name,
dssdrv->driver.name);
r = dss_init_device(core.pdev, dssdev);
if (r)
return r;
r = dssdrv->probe(dssdev);
if (r) {
DSSERR("driver probe failed: %d\n", r);
dss_uninit_device(core.pdev, dssdev);
return r;
}
@ -387,8 +367,6 @@ static int dss_driver_remove(struct device *dev)
dssdrv->remove(dssdev);
dss_uninit_device(core.pdev, dssdev);
dssdev->driver = NULL;
return 0;
@ -507,6 +485,9 @@ static int __init omap_dss_bus_register(void)
/* INIT */
static int (*dss_output_drv_reg_funcs[])(void) __initdata = {
#ifdef CONFIG_OMAP2_DSS_DSI
dsi_init_platform_driver,
#endif
#ifdef CONFIG_OMAP2_DSS_DPI
dpi_init_platform_driver,
#endif
@ -519,15 +500,15 @@ static int (*dss_output_drv_reg_funcs[])(void) __initdata = {
#ifdef CONFIG_OMAP2_DSS_VENC
venc_init_platform_driver,
#endif
#ifdef CONFIG_OMAP2_DSS_DSI
dsi_init_platform_driver,
#endif
#ifdef CONFIG_OMAP4_DSS_HDMI
hdmi_init_platform_driver,
#endif
};
static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = {
#ifdef CONFIG_OMAP2_DSS_DSI
dsi_uninit_platform_driver,
#endif
#ifdef CONFIG_OMAP2_DSS_DPI
dpi_uninit_platform_driver,
#endif
@ -540,9 +521,6 @@ static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = {
#ifdef CONFIG_OMAP2_DSS_VENC
venc_uninit_platform_driver,
#endif
#ifdef CONFIG_OMAP2_DSS_DSI
dsi_uninit_platform_driver,
#endif
#ifdef CONFIG_OMAP4_DSS_HDMI
hdmi_uninit_platform_driver,
#endif

View File

@ -0,0 +1,667 @@
/*
* Copyright (C) 2012 Texas Instruments
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that 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, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "APPLY"
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/jiffies.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/seq_file.h>
#include <video/omapdss.h>
#include "dss.h"
#include "dss_features.h"
#include "dispc-compat.h"
#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
DISPC_IRQ_OCP_ERR | \
DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
DISPC_IRQ_SYNC_LOST | \
DISPC_IRQ_SYNC_LOST_DIGIT)
#define DISPC_MAX_NR_ISRS 8
struct omap_dispc_isr_data {
omap_dispc_isr_t isr;
void *arg;
u32 mask;
};
struct dispc_irq_stats {
unsigned long last_reset;
unsigned irq_count;
unsigned irqs[32];
};
static struct {
spinlock_t irq_lock;
u32 irq_error_mask;
struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
u32 error_irqs;
struct work_struct error_work;
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
spinlock_t irq_stats_lock;
struct dispc_irq_stats irq_stats;
#endif
} dispc_compat;
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
static void dispc_dump_irqs(struct seq_file *s)
{
unsigned long flags;
struct dispc_irq_stats stats;
spin_lock_irqsave(&dispc_compat.irq_stats_lock, flags);
stats = dispc_compat.irq_stats;
memset(&dispc_compat.irq_stats, 0, sizeof(dispc_compat.irq_stats));
dispc_compat.irq_stats.last_reset = jiffies;
spin_unlock_irqrestore(&dispc_compat.irq_stats_lock, flags);
seq_printf(s, "period %u ms\n",
jiffies_to_msecs(jiffies - stats.last_reset));
seq_printf(s, "irqs %d\n", stats.irq_count);
#define PIS(x) \
seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);
PIS(FRAMEDONE);
PIS(VSYNC);
PIS(EVSYNC_EVEN);
PIS(EVSYNC_ODD);
PIS(ACBIAS_COUNT_STAT);
PIS(PROG_LINE_NUM);
PIS(GFX_FIFO_UNDERFLOW);
PIS(GFX_END_WIN);
PIS(PAL_GAMMA_MASK);
PIS(OCP_ERR);
PIS(VID1_FIFO_UNDERFLOW);
PIS(VID1_END_WIN);
PIS(VID2_FIFO_UNDERFLOW);
PIS(VID2_END_WIN);
if (dss_feat_get_num_ovls() > 3) {
PIS(VID3_FIFO_UNDERFLOW);
PIS(VID3_END_WIN);
}
PIS(SYNC_LOST);
PIS(SYNC_LOST_DIGIT);
PIS(WAKEUP);
if (dss_has_feature(FEAT_MGR_LCD2)) {
PIS(FRAMEDONE2);
PIS(VSYNC2);
PIS(ACBIAS_COUNT_STAT2);
PIS(SYNC_LOST2);
}
if (dss_has_feature(FEAT_MGR_LCD3)) {
PIS(FRAMEDONE3);
PIS(VSYNC3);
PIS(ACBIAS_COUNT_STAT3);
PIS(SYNC_LOST3);
}
#undef PIS
}
#endif
/* dispc.irq_lock has to be locked by the caller */
static void _omap_dispc_set_irqs(void)
{
u32 mask;
int i;
struct omap_dispc_isr_data *isr_data;
mask = dispc_compat.irq_error_mask;
for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
isr_data = &dispc_compat.registered_isr[i];
if (isr_data->isr == NULL)
continue;
mask |= isr_data->mask;
}
dispc_write_irqenable(mask);
}
int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
{
int i;
int ret;
unsigned long flags;
struct omap_dispc_isr_data *isr_data;
if (isr == NULL)
return -EINVAL;
spin_lock_irqsave(&dispc_compat.irq_lock, flags);
/* check for duplicate entry */
for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
isr_data = &dispc_compat.registered_isr[i];
if (isr_data->isr == isr && isr_data->arg == arg &&
isr_data->mask == mask) {
ret = -EINVAL;
goto err;
}
}
isr_data = NULL;
ret = -EBUSY;
for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
isr_data = &dispc_compat.registered_isr[i];
if (isr_data->isr != NULL)
continue;
isr_data->isr = isr;
isr_data->arg = arg;
isr_data->mask = mask;
ret = 0;
break;
}
if (ret)
goto err;
_omap_dispc_set_irqs();
spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
return 0;
err:
spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
return ret;
}
EXPORT_SYMBOL(omap_dispc_register_isr);
int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
{
int i;
unsigned long flags;
int ret = -EINVAL;
struct omap_dispc_isr_data *isr_data;
spin_lock_irqsave(&dispc_compat.irq_lock, flags);
for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
isr_data = &dispc_compat.registered_isr[i];
if (isr_data->isr != isr || isr_data->arg != arg ||
isr_data->mask != mask)
continue;
/* found the correct isr */
isr_data->isr = NULL;
isr_data->arg = NULL;
isr_data->mask = 0;
ret = 0;
break;
}
if (ret == 0)
_omap_dispc_set_irqs();
spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
return ret;
}
EXPORT_SYMBOL(omap_dispc_unregister_isr);
static void print_irq_status(u32 status)
{
if ((status & dispc_compat.irq_error_mask) == 0)
return;
#define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : ""
pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n",
status,
PIS(OCP_ERR),
PIS(GFX_FIFO_UNDERFLOW),
PIS(VID1_FIFO_UNDERFLOW),
PIS(VID2_FIFO_UNDERFLOW),
dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW) : "",
PIS(SYNC_LOST),
PIS(SYNC_LOST_DIGIT),
dss_has_feature(FEAT_MGR_LCD2) ? PIS(SYNC_LOST2) : "",
dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : "");
#undef PIS
}
/* Called from dss.c. Note that we don't touch clocks here,
* but we presume they are on because we got an IRQ. However,
* an irq handler may turn the clocks off, so we may not have
* clock later in the function. */
static irqreturn_t omap_dispc_irq_handler(int irq, void *arg)
{
int i;
u32 irqstatus, irqenable;
u32 handledirqs = 0;
u32 unhandled_errors;
struct omap_dispc_isr_data *isr_data;
struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
spin_lock(&dispc_compat.irq_lock);
irqstatus = dispc_read_irqstatus();
irqenable = dispc_read_irqenable();
/* IRQ is not for us */
if (!(irqstatus & irqenable)) {
spin_unlock(&dispc_compat.irq_lock);
return IRQ_NONE;
}
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
spin_lock(&dispc_compat.irq_stats_lock);
dispc_compat.irq_stats.irq_count++;
dss_collect_irq_stats(irqstatus, dispc_compat.irq_stats.irqs);
spin_unlock(&dispc_compat.irq_stats_lock);
#endif
print_irq_status(irqstatus);
/* Ack the interrupt. Do it here before clocks are possibly turned
* off */
dispc_clear_irqstatus(irqstatus);
/* flush posted write */
dispc_read_irqstatus();
/* make a copy and unlock, so that isrs can unregister
* themselves */
memcpy(registered_isr, dispc_compat.registered_isr,
sizeof(registered_isr));
spin_unlock(&dispc_compat.irq_lock);
for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
isr_data = &registered_isr[i];
if (!isr_data->isr)
continue;
if (isr_data->mask & irqstatus) {
isr_data->isr(isr_data->arg, irqstatus);
handledirqs |= isr_data->mask;
}
}
spin_lock(&dispc_compat.irq_lock);
unhandled_errors = irqstatus & ~handledirqs & dispc_compat.irq_error_mask;
if (unhandled_errors) {
dispc_compat.error_irqs |= unhandled_errors;
dispc_compat.irq_error_mask &= ~unhandled_errors;
_omap_dispc_set_irqs();
schedule_work(&dispc_compat.error_work);
}
spin_unlock(&dispc_compat.irq_lock);
return IRQ_HANDLED;
}
static void dispc_error_worker(struct work_struct *work)
{
int i;
u32 errors;
unsigned long flags;
static const unsigned fifo_underflow_bits[] = {
DISPC_IRQ_GFX_FIFO_UNDERFLOW,
DISPC_IRQ_VID1_FIFO_UNDERFLOW,
DISPC_IRQ_VID2_FIFO_UNDERFLOW,
DISPC_IRQ_VID3_FIFO_UNDERFLOW,
};
spin_lock_irqsave(&dispc_compat.irq_lock, flags);
errors = dispc_compat.error_irqs;
dispc_compat.error_irqs = 0;
spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
dispc_runtime_get();
for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
struct omap_overlay *ovl;
unsigned bit;
ovl = omap_dss_get_overlay(i);
bit = fifo_underflow_bits[i];
if (bit & errors) {
DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
ovl->name);
dispc_ovl_enable(ovl->id, false);
dispc_mgr_go(ovl->manager->id);
msleep(50);
}
}
for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
struct omap_overlay_manager *mgr;
unsigned bit;
mgr = omap_dss_get_overlay_manager(i);
bit = dispc_mgr_get_sync_lost_irq(i);
if (bit & errors) {
int j;
DSSERR("SYNC_LOST on channel %s, restarting the output "
"with video overlays disabled\n",
mgr->name);
dss_mgr_disable(mgr);
for (j = 0; j < omap_dss_get_num_overlays(); ++j) {
struct omap_overlay *ovl;
ovl = omap_dss_get_overlay(j);
if (ovl->id != OMAP_DSS_GFX &&
ovl->manager == mgr)
ovl->disable(ovl);
}
dss_mgr_enable(mgr);
}
}
if (errors & DISPC_IRQ_OCP_ERR) {
DSSERR("OCP_ERR\n");
for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
struct omap_overlay_manager *mgr;
mgr = omap_dss_get_overlay_manager(i);
dss_mgr_disable(mgr);
}
}
spin_lock_irqsave(&dispc_compat.irq_lock, flags);
dispc_compat.irq_error_mask |= errors;
_omap_dispc_set_irqs();
spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
dispc_runtime_put();
}
int dss_dispc_initialize_irq(void)
{
int r;
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
spin_lock_init(&dispc_compat.irq_stats_lock);
dispc_compat.irq_stats.last_reset = jiffies;
dss_debugfs_create_file("dispc_irq", dispc_dump_irqs);
#endif
spin_lock_init(&dispc_compat.irq_lock);
memset(dispc_compat.registered_isr, 0,
sizeof(dispc_compat.registered_isr));
dispc_compat.irq_error_mask = DISPC_IRQ_MASK_ERROR;
if (dss_has_feature(FEAT_MGR_LCD2))
dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
if (dss_has_feature(FEAT_MGR_LCD3))
dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST3;
if (dss_feat_get_num_ovls() > 3)
dispc_compat.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;
/*
* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
* so clear it
*/
dispc_clear_irqstatus(dispc_read_irqstatus());
INIT_WORK(&dispc_compat.error_work, dispc_error_worker);
_omap_dispc_set_irqs();
r = dispc_request_irq(omap_dispc_irq_handler, &dispc_compat);
if (r) {
DSSERR("dispc_request_irq failed\n");
return r;
}
return 0;
}
void dss_dispc_uninitialize_irq(void)
{
dispc_free_irq(&dispc_compat);
}
static void dispc_mgr_disable_isr(void *data, u32 mask)
{
struct completion *compl = data;
complete(compl);
}
static void dispc_mgr_enable_lcd_out(enum omap_channel channel)
{
dispc_mgr_enable(channel, true);
}
static void dispc_mgr_disable_lcd_out(enum omap_channel channel)
{
DECLARE_COMPLETION_ONSTACK(framedone_compl);
int r;
u32 irq;
if (dispc_mgr_is_enabled(channel) == false)
return;
/*
* When we disable LCD output, we need to wait for FRAMEDONE to know
* that DISPC has finished with the LCD output.
*/
irq = dispc_mgr_get_framedone_irq(channel);
r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
irq);
if (r)
DSSERR("failed to register FRAMEDONE isr\n");
dispc_mgr_enable(channel, false);
/* if we couldn't register for framedone, just sleep and exit */
if (r) {
msleep(100);
return;
}
if (!wait_for_completion_timeout(&framedone_compl,
msecs_to_jiffies(100)))
DSSERR("timeout waiting for FRAME DONE\n");
r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
irq);
if (r)
DSSERR("failed to unregister FRAMEDONE isr\n");
}
static void dispc_digit_out_enable_isr(void *data, u32 mask)
{
struct completion *compl = data;
/* ignore any sync lost interrupts */
if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD))
complete(compl);
}
static void dispc_mgr_enable_digit_out(void)
{
DECLARE_COMPLETION_ONSTACK(vsync_compl);
int r;
u32 irq_mask;
if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == true)
return;
/*
* Digit output produces some sync lost interrupts during the first
* frame when enabling. Those need to be ignored, so we register for the
* sync lost irq to prevent the error handler from triggering.
*/
irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) |
dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT);
r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl,
irq_mask);
if (r) {
DSSERR("failed to register %x isr\n", irq_mask);
return;
}
dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, true);
/* wait for the first evsync */
if (!wait_for_completion_timeout(&vsync_compl, msecs_to_jiffies(100)))
DSSERR("timeout waiting for digit out to start\n");
r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl,
irq_mask);
if (r)
DSSERR("failed to unregister %x isr\n", irq_mask);
}
static void dispc_mgr_disable_digit_out(void)
{
DECLARE_COMPLETION_ONSTACK(framedone_compl);
int r, i;
u32 irq_mask;
int num_irqs;
if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == false)
return;
/*
* When we disable the digit output, we need to wait for FRAMEDONE to
* know that DISPC has finished with the output.
*/
irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT);
num_irqs = 1;
if (!irq_mask) {
/*
* omap 2/3 don't have framedone irq for TV, so we need to use
* vsyncs for this.
*/
irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT);
/*
* We need to wait for both even and odd vsyncs. Note that this
* is not totally reliable, as we could get a vsync interrupt
* before we disable the output, which leads to timeout in the
* wait_for_completion.
*/
num_irqs = 2;
}
r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
irq_mask);
if (r)
DSSERR("failed to register %x isr\n", irq_mask);
dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, false);
/* if we couldn't register the irq, just sleep and exit */
if (r) {
msleep(100);
return;
}
for (i = 0; i < num_irqs; ++i) {
if (!wait_for_completion_timeout(&framedone_compl,
msecs_to_jiffies(100)))
DSSERR("timeout waiting for digit out to stop\n");
}
r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
irq_mask);
if (r)
DSSERR("failed to unregister %x isr\n", irq_mask);
}
void dispc_mgr_enable_sync(enum omap_channel channel)
{
if (dss_mgr_is_lcd(channel))
dispc_mgr_enable_lcd_out(channel);
else if (channel == OMAP_DSS_CHANNEL_DIGIT)
dispc_mgr_enable_digit_out();
else
WARN_ON(1);
}
void dispc_mgr_disable_sync(enum omap_channel channel)
{
if (dss_mgr_is_lcd(channel))
dispc_mgr_disable_lcd_out(channel);
else if (channel == OMAP_DSS_CHANNEL_DIGIT)
dispc_mgr_disable_digit_out();
else
WARN_ON(1);
}
int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
unsigned long timeout)
{
void dispc_irq_wait_handler(void *data, u32 mask)
{
complete((struct completion *)data);
}
int r;
DECLARE_COMPLETION_ONSTACK(completion);
r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
irqmask);
if (r)
return r;
timeout = wait_for_completion_interruptible_timeout(&completion,
timeout);
omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
if (timeout == 0)
return -ETIMEDOUT;
if (timeout == -ERESTARTSYS)
return -ERESTARTSYS;
return 0;
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (C) 2012 Texas Instruments
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __OMAP2_DSS_DISPC_COMPAT_H
#define __OMAP2_DSS_DISPC_COMPAT_H
void dispc_mgr_enable_sync(enum omap_channel channel);
void dispc_mgr_disable_sync(enum omap_channel channel);
int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
unsigned long timeout);
int dss_dispc_initialize_irq(void);
void dss_dispc_uninitialize_irq(void);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,321 @@
/*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
*
* Some code and ideas taken from drivers/video/omap/ driver
* by Imre Deak.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that 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, see <http://www.gnu.org/licenses/>.
*/
#define DSS_SUBSYS_NAME "DISPLAY"
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/platform_device.h>
#include <video/omapdss.h>
#include "dss.h"
#include "dss_features.h"
static ssize_t display_enabled_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
bool enabled = dssdev->state != OMAP_DSS_DISPLAY_DISABLED;
return snprintf(buf, PAGE_SIZE, "%d\n", enabled);
}
static ssize_t display_enabled_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
int r;
bool enabled;
r = strtobool(buf, &enabled);
if (r)
return r;
if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) {
if (enabled) {
r = dssdev->driver->enable(dssdev);
if (r)
return r;
} else {
dssdev->driver->disable(dssdev);
}
}
return size;
}
static ssize_t display_tear_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
return snprintf(buf, PAGE_SIZE, "%d\n",
dssdev->driver->get_te ?
dssdev->driver->get_te(dssdev) : 0);
}
static ssize_t display_tear_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
int r;
bool te;
if (!dssdev->driver->enable_te || !dssdev->driver->get_te)
return -ENOENT;
r = strtobool(buf, &te);
if (r)
return r;
r = dssdev->driver->enable_te(dssdev, te);
if (r)
return r;
return size;
}
static ssize_t display_timings_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
struct omap_video_timings t;
if (!dssdev->driver->get_timings)
return -ENOENT;
dssdev->driver->get_timings(dssdev, &t);
return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
t.pixel_clock,
t.x_res, t.hfp, t.hbp, t.hsw,
t.y_res, t.vfp, t.vbp, t.vsw);
}
static ssize_t display_timings_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
struct omap_video_timings t = dssdev->panel.timings;
int r, found;
if (!dssdev->driver->set_timings || !dssdev->driver->check_timings)
return -ENOENT;
found = 0;
#ifdef CONFIG_OMAP2_DSS_VENC
if (strncmp("pal", buf, 3) == 0) {
t = omap_dss_pal_timings;
found = 1;
} else if (strncmp("ntsc", buf, 4) == 0) {
t = omap_dss_ntsc_timings;
found = 1;
}
#endif
if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu",
&t.pixel_clock,
&t.x_res, &t.hfp, &t.hbp, &t.hsw,
&t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9)
return -EINVAL;
r = dssdev->driver->check_timings(dssdev, &t);
if (r)
return r;
dssdev->driver->disable(dssdev);
dssdev->driver->set_timings(dssdev, &t);
r = dssdev->driver->enable(dssdev);
if (r)
return r;
return size;
}
static ssize_t display_rotate_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
int rotate;
if (!dssdev->driver->get_rotate)
return -ENOENT;
rotate = dssdev->driver->get_rotate(dssdev);
return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
}
static ssize_t display_rotate_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
int rot, r;
if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
return -ENOENT;
r = kstrtoint(buf, 0, &rot);
if (r)
return r;
r = dssdev->driver->set_rotate(dssdev, rot);
if (r)
return r;
return size;
}
static ssize_t display_mirror_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
int mirror;
if (!dssdev->driver->get_mirror)
return -ENOENT;
mirror = dssdev->driver->get_mirror(dssdev);
return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
}
static ssize_t display_mirror_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
int r;
bool mirror;
if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
return -ENOENT;
r = strtobool(buf, &mirror);
if (r)
return r;
r = dssdev->driver->set_mirror(dssdev, mirror);
if (r)
return r;
return size;
}
static ssize_t display_wss_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
unsigned int wss;
if (!dssdev->driver->get_wss)
return -ENOENT;
wss = dssdev->driver->get_wss(dssdev);
return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
}
static ssize_t display_wss_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
u32 wss;
int r;
if (!dssdev->driver->get_wss || !dssdev->driver->set_wss)
return -ENOENT;
r = kstrtou32(buf, 0, &wss);
if (r)
return r;
if (wss > 0xfffff)
return -EINVAL;
r = dssdev->driver->set_wss(dssdev, wss);
if (r)
return r;
return size;
}
static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
display_enabled_show, display_enabled_store);
static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR,
display_tear_show, display_tear_store);
static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR,
display_timings_show, display_timings_store);
static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR,
display_rotate_show, display_rotate_store);
static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR,
display_mirror_show, display_mirror_store);
static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
display_wss_show, display_wss_store);
static struct device_attribute *display_sysfs_attrs[] = {
&dev_attr_enabled,
&dev_attr_tear_elim,
&dev_attr_timings,
&dev_attr_rotate,
&dev_attr_mirror,
&dev_attr_wss,
NULL
};
int display_init_sysfs(struct platform_device *pdev,
struct omap_dss_device *dssdev)
{
struct device_attribute *attr;
int i, r;
/* create device sysfs files */
i = 0;
while ((attr = display_sysfs_attrs[i++]) != NULL) {
r = device_create_file(&dssdev->dev, attr);
if (r) {
for (i = i - 2; i >= 0; i--) {
attr = display_sysfs_attrs[i];
device_remove_file(&dssdev->dev, attr);
}
DSSERR("failed to create sysfs file\n");
return r;
}
}
/* create display? sysfs links */
r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj,
dev_name(&dssdev->dev));
if (r) {
while ((attr = display_sysfs_attrs[i++]) != NULL)
device_remove_file(&dssdev->dev, attr);
DSSERR("failed to create sysfs display link\n");
return r;
}
return 0;
}
void display_uninit_sysfs(struct platform_device *pdev,
struct omap_dss_device *dssdev)
{
struct device_attribute *attr;
int i = 0;
sysfs_remove_link(&pdev->dev.kobj, dev_name(&dssdev->dev));
while ((attr = display_sysfs_attrs[i++]) != NULL)
device_remove_file(&dssdev->dev, attr);
}

View File

@ -31,250 +31,6 @@
#include "dss.h"
#include "dss_features.h"
static ssize_t display_enabled_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
bool enabled = dssdev->state != OMAP_DSS_DISPLAY_DISABLED;
return snprintf(buf, PAGE_SIZE, "%d\n", enabled);
}
static ssize_t display_enabled_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
int r;
bool enabled;
r = strtobool(buf, &enabled);
if (r)
return r;
if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) {
if (enabled) {
r = dssdev->driver->enable(dssdev);
if (r)
return r;
} else {
dssdev->driver->disable(dssdev);
}
}
return size;
}
static ssize_t display_tear_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
return snprintf(buf, PAGE_SIZE, "%d\n",
dssdev->driver->get_te ?
dssdev->driver->get_te(dssdev) : 0);
}
static ssize_t display_tear_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
int r;
bool te;
if (!dssdev->driver->enable_te || !dssdev->driver->get_te)
return -ENOENT;
r = strtobool(buf, &te);
if (r)
return r;
r = dssdev->driver->enable_te(dssdev, te);
if (r)
return r;
return size;
}
static ssize_t display_timings_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
struct omap_video_timings t;
if (!dssdev->driver->get_timings)
return -ENOENT;
dssdev->driver->get_timings(dssdev, &t);
return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
t.pixel_clock,
t.x_res, t.hfp, t.hbp, t.hsw,
t.y_res, t.vfp, t.vbp, t.vsw);
}
static ssize_t display_timings_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
struct omap_video_timings t = dssdev->panel.timings;
int r, found;
if (!dssdev->driver->set_timings || !dssdev->driver->check_timings)
return -ENOENT;
found = 0;
#ifdef CONFIG_OMAP2_DSS_VENC
if (strncmp("pal", buf, 3) == 0) {
t = omap_dss_pal_timings;
found = 1;
} else if (strncmp("ntsc", buf, 4) == 0) {
t = omap_dss_ntsc_timings;
found = 1;
}
#endif
if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu",
&t.pixel_clock,
&t.x_res, &t.hfp, &t.hbp, &t.hsw,
&t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9)
return -EINVAL;
r = dssdev->driver->check_timings(dssdev, &t);
if (r)
return r;
dssdev->driver->disable(dssdev);
dssdev->driver->set_timings(dssdev, &t);
r = dssdev->driver->enable(dssdev);
if (r)
return r;
return size;
}
static ssize_t display_rotate_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
int rotate;
if (!dssdev->driver->get_rotate)
return -ENOENT;
rotate = dssdev->driver->get_rotate(dssdev);
return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
}
static ssize_t display_rotate_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
int rot, r;
if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
return -ENOENT;
r = kstrtoint(buf, 0, &rot);
if (r)
return r;
r = dssdev->driver->set_rotate(dssdev, rot);
if (r)
return r;
return size;
}
static ssize_t display_mirror_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
int mirror;
if (!dssdev->driver->get_mirror)
return -ENOENT;
mirror = dssdev->driver->get_mirror(dssdev);
return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
}
static ssize_t display_mirror_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
int r;
bool mirror;
if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
return -ENOENT;
r = strtobool(buf, &mirror);
if (r)
return r;
r = dssdev->driver->set_mirror(dssdev, mirror);
if (r)
return r;
return size;
}
static ssize_t display_wss_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
unsigned int wss;
if (!dssdev->driver->get_wss)
return -ENOENT;
wss = dssdev->driver->get_wss(dssdev);
return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
}
static ssize_t display_wss_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
u32 wss;
int r;
if (!dssdev->driver->get_wss || !dssdev->driver->set_wss)
return -ENOENT;
r = kstrtou32(buf, 0, &wss);
if (r)
return r;
if (wss > 0xfffff)
return -EINVAL;
r = dssdev->driver->set_wss(dssdev, wss);
if (r)
return r;
return size;
}
static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
display_enabled_show, display_enabled_store);
static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR,
display_tear_show, display_tear_store);
static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR,
display_timings_show, display_timings_store);
static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR,
display_rotate_show, display_rotate_store);
static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR,
display_mirror_show, display_mirror_store);
static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
display_wss_show, display_wss_store);
static struct device_attribute *display_sysfs_attrs[] = {
&dev_attr_enabled,
&dev_attr_tear_elim,
&dev_attr_timings,
&dev_attr_rotate,
&dev_attr_mirror,
&dev_attr_wss,
NULL
};
void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
u16 *xres, u16 *yres)
{
@ -320,136 +76,8 @@ void omapdss_default_get_timings(struct omap_dss_device *dssdev,
}
EXPORT_SYMBOL(omapdss_default_get_timings);
/*
* Connect dssdev to a manager if the manager is free or if force is specified.
* Connect all overlays to that manager if they are free or if force is
* specified.
*/
static int dss_init_connections(struct omap_dss_device *dssdev, bool force)
{
struct omap_dss_output *out;
struct omap_overlay_manager *mgr;
int i, r;
out = omapdss_get_output_from_dssdev(dssdev);
WARN_ON(dssdev->output);
WARN_ON(out->device);
r = omapdss_output_set_device(out, dssdev);
if (r) {
DSSERR("failed to connect output to new device\n");
return r;
}
mgr = omap_dss_get_overlay_manager(dssdev->channel);
if (mgr->output && !force)
return 0;
if (mgr->output)
mgr->unset_output(mgr);
r = mgr->set_output(mgr, out);
if (r) {
DSSERR("failed to connect manager to output of new device\n");
/* remove the output-device connection we just made */
omapdss_output_unset_device(out);
return r;
}
for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
struct omap_overlay *ovl = omap_dss_get_overlay(i);
if (!ovl->manager || force) {
if (ovl->manager)
ovl->unset_manager(ovl);
r = ovl->set_manager(ovl, mgr);
if (r) {
DSSERR("failed to set initial overlay\n");
return r;
}
}
}
return 0;
}
static void dss_uninit_connections(struct omap_dss_device *dssdev)
{
if (dssdev->output) {
struct omap_overlay_manager *mgr = dssdev->output->manager;
if (mgr)
mgr->unset_output(mgr);
omapdss_output_unset_device(dssdev->output);
}
}
int dss_init_device(struct platform_device *pdev,
struct omap_dss_device *dssdev)
{
struct device_attribute *attr;
int i, r;
const char *def_disp_name = dss_get_default_display_name();
bool force;
force = def_disp_name && strcmp(def_disp_name, dssdev->name) == 0;
dss_init_connections(dssdev, force);
/* create device sysfs files */
i = 0;
while ((attr = display_sysfs_attrs[i++]) != NULL) {
r = device_create_file(&dssdev->dev, attr);
if (r) {
for (i = i - 2; i >= 0; i--) {
attr = display_sysfs_attrs[i];
device_remove_file(&dssdev->dev, attr);
}
dss_uninit_connections(dssdev);
DSSERR("failed to create sysfs file\n");
return r;
}
}
/* create display? sysfs links */
r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj,
dev_name(&dssdev->dev));
if (r) {
while ((attr = display_sysfs_attrs[i++]) != NULL)
device_remove_file(&dssdev->dev, attr);
dss_uninit_connections(dssdev);
DSSERR("failed to create sysfs display link\n");
return r;
}
return 0;
}
void dss_uninit_device(struct platform_device *pdev,
struct omap_dss_device *dssdev)
{
struct device_attribute *attr;
int i = 0;
sysfs_remove_link(&pdev->dev.kobj, dev_name(&dssdev->dev));
while ((attr = display_sysfs_attrs[i++]) != NULL)
device_remove_file(&dssdev->dev, attr);
dss_uninit_connections(dssdev);
}
static int dss_suspend_device(struct device *dev, void *data)
{
int r;
struct omap_dss_device *dssdev = to_dss_device(dev);
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
@ -457,15 +85,7 @@ static int dss_suspend_device(struct device *dev, void *data)
return 0;
}
if (!dssdev->driver->suspend) {
DSSERR("display '%s' doesn't implement suspend\n",
dssdev->name);
return -ENOSYS;
}
r = dssdev->driver->suspend(dssdev);
if (r)
return r;
dssdev->driver->disable(dssdev);
dssdev->activate_after_resume = true;
@ -492,8 +112,8 @@ static int dss_resume_device(struct device *dev, void *data)
int r;
struct omap_dss_device *dssdev = to_dss_device(dev);
if (dssdev->activate_after_resume && dssdev->driver->resume) {
r = dssdev->driver->resume(dssdev);
if (dssdev->activate_after_resume) {
r = dssdev->driver->enable(dssdev);
if (r)
return r;
}

View File

@ -49,34 +49,53 @@ static struct {
struct omap_dss_output output;
} dpi;
static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk)
static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
{
int dsi_module;
/*
* XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL
* would also be used for DISPC fclk. Meaning, when the DPI output is
* disabled, DISPC clock will be disabled, and TV out will stop.
*/
switch (omapdss_get_version()) {
case OMAPDSS_VER_OMAP24xx:
case OMAPDSS_VER_OMAP34xx_ES1:
case OMAPDSS_VER_OMAP34xx_ES3:
case OMAPDSS_VER_OMAP3630:
case OMAPDSS_VER_AM35xx:
return NULL;
default:
break;
}
dsi_module = clk == OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ? 0 : 1;
return dsi_get_dsidev_from_id(dsi_module);
switch (channel) {
case OMAP_DSS_CHANNEL_LCD:
return dsi_get_dsidev_from_id(0);
case OMAP_DSS_CHANNEL_LCD2:
return dsi_get_dsidev_from_id(1);
default:
return NULL;
}
}
static bool dpi_use_dsi_pll(struct omap_dss_device *dssdev)
static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
{
if (dssdev->clocks.dispc.dispc_fclk_src ==
OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ||
dssdev->clocks.dispc.dispc_fclk_src ==
OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC ||
dssdev->clocks.dispc.channel.lcd_clk_src ==
OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ||
dssdev->clocks.dispc.channel.lcd_clk_src ==
OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC)
return true;
else
return false;
switch (channel) {
case OMAP_DSS_CHANNEL_LCD:
return OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC;
case OMAP_DSS_CHANNEL_LCD2:
return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
default:
/* this shouldn't happen */
WARN_ON(1);
return OMAP_DSS_CLK_SRC_FCK;
}
}
static int dpi_set_dsi_clk(struct omap_dss_device *dssdev,
unsigned long pck_req, unsigned long *fck, int *lck_div,
int *pck_div)
{
struct omap_overlay_manager *mgr = dssdev->output->manager;
struct dsi_clock_info dsi_cinfo;
struct dispc_clock_info dispc_cinfo;
int r;
@ -90,7 +109,8 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev,
if (r)
return r;
dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
dss_select_lcd_clk_source(mgr->id,
dpi_get_alt_clk_src(mgr->id));
dpi.mgr_config.clock_info = dispc_cinfo;
@ -135,7 +155,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
unsigned long pck;
int r = 0;
if (dpi_use_dsi_pll(dssdev))
if (dpi.dsidev)
r = dpi_set_dsi_clk(dssdev, t->pixel_clock * 1000, &fck,
&lck_div, &pck_div);
else
@ -214,7 +234,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
if (r)
goto err_src_sel;
if (dpi_use_dsi_pll(dssdev)) {
if (dpi.dsidev) {
r = dsi_runtime_get(dpi.dsidev);
if (r)
goto err_get_dsi;
@ -242,10 +262,10 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
err_mgr_enable:
err_set_mode:
if (dpi_use_dsi_pll(dssdev))
if (dpi.dsidev)
dsi_pll_uninit(dpi.dsidev, true);
err_dsi_pll_init:
if (dpi_use_dsi_pll(dssdev))
if (dpi.dsidev)
dsi_runtime_put(dpi.dsidev);
err_get_dsi:
err_src_sel:
@ -271,8 +291,8 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
dss_mgr_disable(mgr);
if (dpi_use_dsi_pll(dssdev)) {
dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
if (dpi.dsidev) {
dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
dsi_pll_uninit(dpi.dsidev, true);
dsi_runtime_put(dpi.dsidev);
}
@ -311,13 +331,13 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
unsigned long pck;
struct dispc_clock_info dispc_cinfo;
if (dss_mgr_check_timings(mgr, timings))
if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
return -EINVAL;
if (timings->pixel_clock == 0)
return -EINVAL;
if (dpi_use_dsi_pll(dssdev)) {
if (dpi.dsidev) {
struct dsi_clock_info dsi_cinfo;
r = dsi_pll_calc_clock_div_pck(dpi.dsidev,
timings->pixel_clock * 1000,
@ -359,8 +379,32 @@ void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
}
EXPORT_SYMBOL(omapdss_dpi_set_data_lines);
static int __init dpi_verify_dsi_pll(struct platform_device *dsidev)
{
int r;
/* do initial setup with the PLL to see if it is operational */
r = dsi_runtime_get(dsidev);
if (r)
return r;
r = dsi_pll_init(dsidev, 0, 1);
if (r) {
dsi_runtime_put(dsidev);
return r;
}
dsi_pll_uninit(dsidev, true);
dsi_runtime_put(dsidev);
return 0;
}
static int __init dpi_init_display(struct omap_dss_device *dssdev)
{
struct platform_device *dsidev;
DSSDBG("init_display\n");
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) &&
@ -377,19 +421,30 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev)
dpi.vdds_dsi_reg = vdds_dsi;
}
if (dpi_use_dsi_pll(dssdev)) {
enum omap_dss_clk_source dispc_fclk_src =
dssdev->clocks.dispc.dispc_fclk_src;
dpi.dsidev = dpi_get_dsidev(dispc_fclk_src);
/*
* XXX We shouldn't need dssdev->channel for this. The dsi pll clock
* source for DPI is SoC integration detail, not something that should
* be configured in the dssdev
*/
dsidev = dpi_get_dsidev(dssdev->channel);
if (dsidev && dpi_verify_dsi_pll(dsidev)) {
dsidev = NULL;
DSSWARN("DSI PLL not operational\n");
}
if (dsidev)
DSSDBG("using DSI PLL for DPI clock\n");
dpi.dsidev = dsidev;
return 0;
}
static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
const char *def_disp_name = dss_get_default_display_name();
const char *def_disp_name = omapdss_get_default_display_name();
struct omap_dss_device *def_dssdev;
int i;
@ -438,9 +493,18 @@ static void __init dpi_probe_pdata(struct platform_device *dpidev)
return;
}
r = omapdss_output_set_device(&dpi.output, dssdev);
if (r) {
DSSERR("failed to connect output to new device: %s\n",
dssdev->name);
dss_put_device(dssdev);
return;
}
r = dss_add_device(dssdev);
if (r) {
DSSERR("device %s register failed: %d\n", dssdev->name, r);
omapdss_output_unset_device(&dpi.output);
dss_put_device(dssdev);
return;
}

View File

@ -45,7 +45,6 @@
#include "dss.h"
#include "dss_features.h"
/*#define VERBOSE_IRQ*/
#define DSI_CATCH_MISSING_TE
struct dsi_reg { u16 idx; };
@ -535,42 +534,38 @@ static inline void dsi_perf_show(struct platform_device *dsidev,
}
#endif
static int verbose_irq;
static void print_irq_status(u32 status)
{
if (status == 0)
return;
#ifndef VERBOSE_IRQ
if ((status & ~DSI_IRQ_CHANNEL_MASK) == 0)
if (!verbose_irq && (status & ~DSI_IRQ_CHANNEL_MASK) == 0)
return;
#endif
printk(KERN_DEBUG "DSI IRQ: 0x%x: ", status);
#define PIS(x) \
if (status & DSI_IRQ_##x) \
printk(#x " ");
#ifdef VERBOSE_IRQ
PIS(VC0);
PIS(VC1);
PIS(VC2);
PIS(VC3);
#endif
PIS(WAKEUP);
PIS(RESYNC);
PIS(PLL_LOCK);
PIS(PLL_UNLOCK);
PIS(PLL_RECALL);
PIS(COMPLEXIO_ERR);
PIS(HS_TX_TIMEOUT);
PIS(LP_RX_TIMEOUT);
PIS(TE_TRIGGER);
PIS(ACK_TRIGGER);
PIS(SYNC_LOST);
PIS(LDO_POWER_GOOD);
PIS(TA_TIMEOUT);
#define PIS(x) (status & DSI_IRQ_##x) ? (#x " ") : ""
pr_debug("DSI IRQ: 0x%x: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
status,
verbose_irq ? PIS(VC0) : "",
verbose_irq ? PIS(VC1) : "",
verbose_irq ? PIS(VC2) : "",
verbose_irq ? PIS(VC3) : "",
PIS(WAKEUP),
PIS(RESYNC),
PIS(PLL_LOCK),
PIS(PLL_UNLOCK),
PIS(PLL_RECALL),
PIS(COMPLEXIO_ERR),
PIS(HS_TX_TIMEOUT),
PIS(LP_RX_TIMEOUT),
PIS(TE_TRIGGER),
PIS(ACK_TRIGGER),
PIS(SYNC_LOST),
PIS(LDO_POWER_GOOD),
PIS(TA_TIMEOUT));
#undef PIS
printk("\n");
}
static void print_irq_status_vc(int channel, u32 status)
@ -578,28 +573,24 @@ static void print_irq_status_vc(int channel, u32 status)
if (status == 0)
return;
#ifndef VERBOSE_IRQ
if ((status & ~DSI_VC_IRQ_PACKET_SENT) == 0)
if (!verbose_irq && (status & ~DSI_VC_IRQ_PACKET_SENT) == 0)
return;
#endif
printk(KERN_DEBUG "DSI VC(%d) IRQ 0x%x: ", channel, status);
#define PIS(x) \
if (status & DSI_VC_IRQ_##x) \
printk(#x " ");
PIS(CS);
PIS(ECC_CORR);
#ifdef VERBOSE_IRQ
PIS(PACKET_SENT);
#endif
PIS(FIFO_TX_OVF);
PIS(FIFO_RX_OVF);
PIS(BTA);
PIS(ECC_NO_CORR);
PIS(FIFO_TX_UDF);
PIS(PP_BUSY_CHANGE);
#define PIS(x) (status & DSI_VC_IRQ_##x) ? (#x " ") : ""
pr_debug("DSI VC(%d) IRQ 0x%x: %s%s%s%s%s%s%s%s%s\n",
channel,
status,
PIS(CS),
PIS(ECC_CORR),
PIS(ECC_NO_CORR),
verbose_irq ? PIS(PACKET_SENT) : "",
PIS(BTA),
PIS(FIFO_TX_OVF),
PIS(FIFO_RX_OVF),
PIS(FIFO_TX_UDF),
PIS(PP_BUSY_CHANGE));
#undef PIS
printk("\n");
}
static void print_irq_status_cio(u32 status)
@ -607,34 +598,31 @@ static void print_irq_status_cio(u32 status)
if (status == 0)
return;
printk(KERN_DEBUG "DSI CIO IRQ 0x%x: ", status);
#define PIS(x) (status & DSI_CIO_IRQ_##x) ? (#x " ") : ""
#define PIS(x) \
if (status & DSI_CIO_IRQ_##x) \
printk(#x " ");
PIS(ERRSYNCESC1);
PIS(ERRSYNCESC2);
PIS(ERRSYNCESC3);
PIS(ERRESC1);
PIS(ERRESC2);
PIS(ERRESC3);
PIS(ERRCONTROL1);
PIS(ERRCONTROL2);
PIS(ERRCONTROL3);
PIS(STATEULPS1);
PIS(STATEULPS2);
PIS(STATEULPS3);
PIS(ERRCONTENTIONLP0_1);
PIS(ERRCONTENTIONLP1_1);
PIS(ERRCONTENTIONLP0_2);
PIS(ERRCONTENTIONLP1_2);
PIS(ERRCONTENTIONLP0_3);
PIS(ERRCONTENTIONLP1_3);
PIS(ULPSACTIVENOT_ALL0);
PIS(ULPSACTIVENOT_ALL1);
pr_debug("DSI CIO IRQ 0x%x: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
status,
PIS(ERRSYNCESC1),
PIS(ERRSYNCESC2),
PIS(ERRSYNCESC3),
PIS(ERRESC1),
PIS(ERRESC2),
PIS(ERRESC3),
PIS(ERRCONTROL1),
PIS(ERRCONTROL2),
PIS(ERRCONTROL3),
PIS(STATEULPS1),
PIS(STATEULPS2),
PIS(STATEULPS3),
PIS(ERRCONTENTIONLP0_1),
PIS(ERRCONTENTIONLP1_1),
PIS(ERRCONTENTIONLP0_2),
PIS(ERRCONTENTIONLP1_2),
PIS(ERRCONTENTIONLP0_3),
PIS(ERRCONTENTIONLP1_3),
PIS(ULPSACTIVENOT_ALL0),
PIS(ULPSACTIVENOT_ALL1));
#undef PIS
printk("\n");
}
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
@ -1116,28 +1104,16 @@ static inline void dsi_enable_pll_clock(struct platform_device *dsidev,
}
}
#ifdef DEBUG
static void _dsi_print_reset_status(struct platform_device *dsidev)
{
u32 l;
int b0, b1, b2;
if (!dss_debug)
return;
/* A dummy read using the SCP interface to any DSIPHY register is
* required after DSIPHY reset to complete the reset of the DSI complex
* I/O. */
l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
printk(KERN_DEBUG "DSI resets: ");
l = dsi_read_reg(dsidev, DSI_PLL_STATUS);
printk("PLL (%d) ", FLD_GET(l, 0, 0));
l = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1);
printk("CIO (%d) ", FLD_GET(l, 29, 29));
if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) {
b0 = 28;
b1 = 27;
@ -1148,18 +1124,21 @@ static void _dsi_print_reset_status(struct platform_device *dsidev)
b2 = 26;
}
l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
printk("PHY (%x%x%x, %d, %d, %d)\n",
FLD_GET(l, b0, b0),
FLD_GET(l, b1, b1),
FLD_GET(l, b2, b2),
FLD_GET(l, 29, 29),
FLD_GET(l, 30, 30),
FLD_GET(l, 31, 31));
#define DSI_FLD_GET(fld, start, end)\
FLD_GET(dsi_read_reg(dsidev, DSI_##fld), start, end)
pr_debug("DSI resets: PLL (%d) CIO (%d) PHY (%x%x%x, %d, %d, %d)\n",
DSI_FLD_GET(PLL_STATUS, 0, 0),
DSI_FLD_GET(COMPLEXIO_CFG1, 29, 29),
DSI_FLD_GET(DSIPHY_CFG5, b0, b0),
DSI_FLD_GET(DSIPHY_CFG5, b1, b1),
DSI_FLD_GET(DSIPHY_CFG5, b2, b2),
DSI_FLD_GET(DSIPHY_CFG5, 29, 29),
DSI_FLD_GET(DSIPHY_CFG5, 30, 30),
DSI_FLD_GET(DSIPHY_CFG5, 31, 31));
#undef DSI_FLD_GET
}
#else
#define _dsi_print_reset_status(x)
#endif
static inline int dsi_if_enable(struct platform_device *dsidev, bool enable)
{
@ -1407,6 +1386,11 @@ retry:
cur.dsi_pll_hsdiv_dispc_clk =
cur.clkin4ddr / cur.regm_dispc;
if (cur.regm_dispc > 1 &&
cur.regm_dispc % 2 != 0 &&
req_pck >= 1000000)
continue;
/* this will narrow down the search a bit,
* but still give pixclocks below what was
* requested */
@ -1621,7 +1605,7 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev,
u8 regn_start, regn_end, regm_start, regm_end;
u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end;
DSSDBGF();
DSSDBG("DSI PLL clock config starts");
dsi->current_cinfo.clkin = cinfo->clkin;
dsi->current_cinfo.fint = cinfo->fint;
@ -1757,11 +1741,21 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
DSSDBG("PLL init\n");
/*
* It seems that on many OMAPs we need to enable both to have a
* functional HSDivider.
*/
enable_hsclk = enable_hsdiv = true;
if (dsi->vdds_dsi_reg == NULL) {
struct regulator *vdds_dsi;
vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi");
/* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */
if (IS_ERR(vdds_dsi))
vdds_dsi = regulator_get(&dsi->pdev->dev, "VCXIO");
if (IS_ERR(vdds_dsi)) {
DSSERR("can't get VDDS_DSI regulator\n");
return PTR_ERR(vdds_dsi);
@ -2440,7 +2434,7 @@ static int dsi_cio_init(struct platform_device *dsidev)
int r;
u32 l;
DSSDBGF();
DSSDBG("DSI CIO init starts");
r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
if (r)
@ -2791,7 +2785,7 @@ static void dsi_vc_initial_config(struct platform_device *dsidev, int channel)
{
u32 r;
DSSDBGF("%d", channel);
DSSDBG("Initial config of virtual channel %d", channel);
r = dsi_read_reg(dsidev, DSI_VC_CTRL(channel));
@ -2823,7 +2817,7 @@ static int dsi_vc_config_source(struct platform_device *dsidev, int channel,
if (dsi->vc[channel].source == source)
return 0;
DSSDBGF("%d", channel);
DSSDBG("Source config of virtual channel %d", channel);
dsi_sync_vc(dsidev, channel);
@ -3581,7 +3575,7 @@ static int dsi_enter_ulps(struct platform_device *dsidev)
int r, i;
unsigned mask;
DSSDBGF();
DSSDBG("Entering ULPS");
WARN_ON(!dsi_bus_is_locked(dsidev));
@ -4285,7 +4279,7 @@ int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev,
unsigned long pck;
int r;
DSSDBGF("ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk);
DSSDBG("Setting DSI clocks: ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk);
mutex_lock(&dsi->lock);
@ -4541,7 +4535,7 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work)
dsi_handle_framedone(dsi->pdev, -ETIMEDOUT);
}
static void dsi_framedone_irq_callback(void *data, u32 mask)
static void dsi_framedone_irq_callback(void *data)
{
struct platform_device *dsidev = (struct platform_device *) data;
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
@ -4615,7 +4609,6 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
struct omap_overlay_manager *mgr = dssdev->output->manager;
int r;
u32 irq = 0;
if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) {
dsi->timings.hsw = 1;
@ -4625,12 +4618,10 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
dsi->timings.vfp = 0;
dsi->timings.vbp = 0;
irq = dispc_mgr_get_framedone_irq(mgr->id);
r = omap_dispc_register_isr(dsi_framedone_irq_callback,
(void *) dsidev, irq);
r = dss_mgr_register_framedone_handler(mgr,
dsi_framedone_irq_callback, dsidev);
if (r) {
DSSERR("can't get FRAMEDONE irq\n");
DSSERR("can't register FRAMEDONE handler\n");
goto err;
}
@ -4668,8 +4659,8 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
return 0;
err1:
if (dsi->mode == OMAP_DSS_DSI_CMD_MODE)
omap_dispc_unregister_isr(dsi_framedone_irq_callback,
(void *) dsidev, irq);
dss_mgr_unregister_framedone_handler(mgr,
dsi_framedone_irq_callback, dsidev);
err:
return r;
}
@ -4680,14 +4671,9 @@ static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
struct omap_overlay_manager *mgr = dssdev->output->manager;
if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) {
u32 irq;
irq = dispc_mgr_get_framedone_irq(mgr->id);
omap_dispc_unregister_isr(dsi_framedone_irq_callback,
(void *) dsidev, irq);
}
if (dsi->mode == OMAP_DSS_DSI_CMD_MODE)
dss_mgr_unregister_framedone_handler(mgr,
dsi_framedone_irq_callback, dsidev);
}
static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
@ -4730,7 +4716,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
if (r)
goto err1;
dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src);
dss_select_lcd_clk_source(mgr->id,
dssdev->clocks.dispc.channel.lcd_clk_src);
@ -4765,7 +4750,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
err3:
dsi_cio_uninit(dsidev);
err2:
dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
@ -4792,7 +4776,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
dsi_vc_enable(dsidev, 2, 0);
dsi_vc_enable(dsidev, 3, 0);
dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
dsi_cio_uninit(dsidev);
@ -4981,6 +4964,10 @@ static int __init dsi_init_display(struct omap_dss_device *dssdev)
vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi");
/* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */
if (IS_ERR(vdds_dsi))
vdds_dsi = regulator_get(&dsi->pdev->dev, "VCXIO");
if (IS_ERR(vdds_dsi)) {
DSSERR("can't get VDDS_DSI regulator\n");
return PTR_ERR(vdds_dsi);
@ -5121,7 +5108,7 @@ static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *p
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
struct dsi_data *dsi = dsi_get_dsidrv_data(pdev);
const char *def_disp_name = dss_get_default_display_name();
const char *def_disp_name = omapdss_get_default_display_name();
struct omap_dss_device *def_dssdev;
int i;
@ -5151,6 +5138,7 @@ static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *p
static void __init dsi_probe_pdata(struct platform_device *dsidev)
{
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
struct omap_dss_device *plat_dssdev;
struct omap_dss_device *dssdev;
int r;
@ -5173,9 +5161,18 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev)
return;
}
r = omapdss_output_set_device(&dsi->output, dssdev);
if (r) {
DSSERR("failed to connect output to new device: %s\n",
dssdev->name);
dss_put_device(dssdev);
return;
}
r = dss_add_device(dssdev);
if (r) {
DSSERR("device %s register failed: %d\n", dssdev->name, r);
omapdss_output_unset_device(&dsi->output);
dss_put_device(dssdev);
return;
}

View File

@ -32,11 +32,10 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/gfp.h>
#include <linux/sizes.h>
#include <video/omapdss.h>
#include <plat/cpu.h>
#include "dss.h"
#include "dss_features.h"
@ -78,6 +77,7 @@ static struct {
struct clk *dpll4_m4_ck;
struct clk *dss_clk;
unsigned long dss_clk_rate;
unsigned long cache_req_pck;
unsigned long cache_prate;
@ -98,6 +98,8 @@ static const char * const dss_generic_clk_source_names[] = {
[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC",
[OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI",
[OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK",
[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DSI_PLL2_HSDIV_DISPC",
[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DSI_PLL2_HSDIV_DSI",
};
static inline void dss_write_reg(const struct dss_reg idx, u32 val)
@ -153,6 +155,21 @@ static void dss_restore_context(void)
#undef SR
#undef RR
int dss_get_ctx_loss_count(void)
{
struct omap_dss_board_info *board_data = dss.pdev->dev.platform_data;
int cnt;
if (!board_data->get_context_loss_count)
return -ENOENT;
cnt = board_data->get_context_loss_count(&dss.pdev->dev);
WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt);
return cnt;
}
void dss_sdi_init(int datapairs)
{
u32 l;
@ -303,7 +320,7 @@ static void dss_dump_regs(struct seq_file *s)
#undef DUMPREG
}
void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
{
struct platform_device *dsidev;
int b;
@ -374,8 +391,10 @@ void dss_select_lcd_clk_source(enum omap_channel channel,
struct platform_device *dsidev;
int b, ix, pos;
if (!dss_has_feature(FEAT_LCD_CLK_SRC))
if (!dss_has_feature(FEAT_LCD_CLK_SRC)) {
dss_select_dispc_clk_source(clk_src);
return;
}
switch (clk_src) {
case OMAP_DSS_CLK_SRC_FCK:
@ -431,6 +450,29 @@ enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
}
}
/* calculate clock rates using dividers in cinfo */
int dss_calc_clock_rates(struct dss_clock_info *cinfo)
{
if (dss.dpll4_m4_ck) {
unsigned long prate;
if (cinfo->fck_div > dss.feat->fck_div_max ||
cinfo->fck_div == 0)
return -EINVAL;
prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
cinfo->fck = prate / cinfo->fck_div *
dss.feat->dss_fck_multiplier;
} else {
if (cinfo->fck_div != 0)
return -EINVAL;
cinfo->fck = clk_get_rate(dss.dss_clk);
}
return 0;
}
int dss_set_clock_div(struct dss_clock_info *cinfo)
{
if (dss.dpll4_m4_ck) {
@ -448,6 +490,10 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
return -EINVAL;
}
dss.dss_clk_rate = clk_get_rate(dss.dss_clk);
WARN_ONCE(dss.dss_clk_rate != cinfo->fck, "clk rate mismatch");
DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div);
return 0;
@ -461,6 +507,41 @@ unsigned long dss_get_dpll4_rate(void)
return 0;
}
unsigned long dss_get_dispc_clk_rate(void)
{
return dss.dss_clk_rate;
}
static int dss_setup_default_clock(void)
{
unsigned long max_dss_fck, prate;
unsigned fck_div;
struct dss_clock_info dss_cinfo = { 0 };
int r;
if (dss.dpll4_m4_ck == NULL)
return 0;
max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
prate = dss_get_dpll4_rate();
fck_div = DIV_ROUND_UP(prate * dss.feat->dss_fck_multiplier,
max_dss_fck);
dss_cinfo.fck_div = fck_div;
r = dss_calc_clock_rates(&dss_cinfo);
if (r)
return r;
r = dss_set_clock_div(&dss_cinfo);
if (r)
return r;
return 0;
}
int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
struct dispc_clock_info *dispc_cinfo)
{
@ -750,7 +831,7 @@ static void dss_runtime_put(void)
}
/* DEBUGFS */
#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
#if defined(CONFIG_OMAP2_DSS_DEBUGFS)
void dss_debug_dump_clocks(struct seq_file *s)
{
dss_dump_clocks(s);
@ -796,29 +877,45 @@ static const struct dss_features omap54xx_dss_feats __initconst = {
.dpi_select_source = &dss_dpi_select_source_omap5,
};
static int __init dss_init_features(struct device *dev)
static int __init dss_init_features(struct platform_device *pdev)
{
const struct dss_features *src;
struct dss_features *dst;
dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL);
dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
if (!dst) {
dev_err(dev, "Failed to allocate local DSS Features\n");
dev_err(&pdev->dev, "Failed to allocate local DSS Features\n");
return -ENOMEM;
}
if (cpu_is_omap24xx())
switch (omapdss_get_version()) {
case OMAPDSS_VER_OMAP24xx:
src = &omap24xx_dss_feats;
else if (cpu_is_omap3630())
src = &omap3630_dss_feats;
else if (cpu_is_omap34xx())
break;
case OMAPDSS_VER_OMAP34xx_ES1:
case OMAPDSS_VER_OMAP34xx_ES3:
case OMAPDSS_VER_AM35xx:
src = &omap34xx_dss_feats;
else if (cpu_is_omap44xx())
break;
case OMAPDSS_VER_OMAP3630:
src = &omap3630_dss_feats;
break;
case OMAPDSS_VER_OMAP4430_ES1:
case OMAPDSS_VER_OMAP4430_ES2:
case OMAPDSS_VER_OMAP4:
src = &omap44xx_dss_feats;
else if (soc_is_omap54xx())
break;
case OMAPDSS_VER_OMAP5:
src = &omap54xx_dss_feats;
else
break;
default:
return -ENODEV;
}
memcpy(dst, src, sizeof(*dst));
dss.feat = dst;
@ -835,7 +932,7 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
dss.pdev = pdev;
r = dss_init_features(&dss.pdev->dev);
r = dss_init_features(dss.pdev);
if (r)
return r;
@ -856,15 +953,23 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
if (r)
return r;
r = dss_setup_default_clock();
if (r)
goto err_setup_clocks;
pm_runtime_enable(&pdev->dev);
r = dss_runtime_get();
if (r)
goto err_runtime_get;
dss.dss_clk_rate = clk_get_rate(dss.dss_clk);
/* Select DPLL */
REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
#ifdef CONFIG_OMAP2_DSS_VENC
REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */
REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */
@ -888,6 +993,7 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
err_runtime_get:
pm_runtime_disable(&pdev->dev);
err_setup_clocks:
dss_put_clocks();
return r;
}

View File

@ -23,44 +23,20 @@
#ifndef __OMAP2_DSS_H
#define __OMAP2_DSS_H
#ifdef CONFIG_OMAP2_DSS_DEBUG_SUPPORT
#define DEBUG
#endif
#include <linux/interrupt.h>
#ifdef DEBUG
extern bool dss_debug;
#ifdef DSS_SUBSYS_NAME
#define DSSDBG(format, ...) \
if (dss_debug) \
printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME ": " format, \
## __VA_ARGS__)
#else
#define DSSDBG(format, ...) \
if (dss_debug) \
printk(KERN_DEBUG "omapdss: " format, ## __VA_ARGS__)
#ifdef pr_fmt
#undef pr_fmt
#endif
#ifdef DSS_SUBSYS_NAME
#define DSSDBGF(format, ...) \
if (dss_debug) \
printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME \
": %s(" format ")\n", \
__func__, \
## __VA_ARGS__)
#define pr_fmt(fmt) DSS_SUBSYS_NAME ": " fmt
#else
#define DSSDBGF(format, ...) \
if (dss_debug) \
printk(KERN_DEBUG "omapdss: " \
": %s(" format ")\n", \
__func__, \
## __VA_ARGS__)
#endif
#else /* DEBUG */
#define DSSDBG(format, ...)
#define DSSDBGF(format, ...)
#define pr_fmt(fmt) fmt
#endif
#define DSSDBG(format, ...) \
pr_debug(format, ## __VA_ARGS__)
#ifdef DSS_SUBSYS_NAME
#define DSSERR(format, ...) \
@ -186,11 +162,10 @@ struct seq_file;
struct platform_device;
/* core */
const char *dss_get_default_display_name(void);
struct platform_device *dss_get_core_pdev(void);
struct bus_type *dss_get_bus(void);
struct regulator *dss_get_vdds_dsi(void);
struct regulator *dss_get_vdds_sdi(void);
int dss_get_ctx_loss_count(struct device *dev);
int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask);
void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask);
int dss_set_min_bus_tput(struct device *dev, unsigned long tput);
@ -204,55 +179,18 @@ void dss_put_device(struct omap_dss_device *dssdev);
void dss_copy_device_pdata(struct omap_dss_device *dst,
const struct omap_dss_device *src);
/* apply */
void dss_apply_init(void);
int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr);
int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl);
void dss_mgr_start_update(struct omap_overlay_manager *mgr);
int omap_dss_mgr_apply(struct omap_overlay_manager *mgr);
int dss_mgr_enable(struct omap_overlay_manager *mgr);
void dss_mgr_disable(struct omap_overlay_manager *mgr);
int dss_mgr_set_info(struct omap_overlay_manager *mgr,
struct omap_overlay_manager_info *info);
void dss_mgr_get_info(struct omap_overlay_manager *mgr,
struct omap_overlay_manager_info *info);
int dss_mgr_set_device(struct omap_overlay_manager *mgr,
struct omap_dss_device *dssdev);
int dss_mgr_unset_device(struct omap_overlay_manager *mgr);
int dss_mgr_set_output(struct omap_overlay_manager *mgr,
struct omap_dss_output *output);
int dss_mgr_unset_output(struct omap_overlay_manager *mgr);
void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
const struct omap_video_timings *timings);
void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
const struct dss_lcd_mgr_config *config);
const struct omap_video_timings *dss_mgr_get_timings(struct omap_overlay_manager *mgr);
bool dss_ovl_is_enabled(struct omap_overlay *ovl);
int dss_ovl_enable(struct omap_overlay *ovl);
int dss_ovl_disable(struct omap_overlay *ovl);
int dss_ovl_set_info(struct omap_overlay *ovl,
struct omap_overlay_info *info);
void dss_ovl_get_info(struct omap_overlay *ovl,
struct omap_overlay_info *info);
int dss_ovl_set_manager(struct omap_overlay *ovl,
struct omap_overlay_manager *mgr);
int dss_ovl_unset_manager(struct omap_overlay *ovl);
/* output */
void dss_register_output(struct omap_dss_output *out);
void dss_unregister_output(struct omap_dss_output *out);
struct omap_dss_output *omapdss_get_output_from_dssdev(struct omap_dss_device *dssdev);
/* display */
int dss_suspend_all_devices(void);
int dss_resume_all_devices(void);
void dss_disable_all_devices(void);
int dss_init_device(struct platform_device *pdev,
int display_init_sysfs(struct platform_device *pdev,
struct omap_dss_device *dssdev);
void dss_uninit_device(struct platform_device *pdev,
void display_uninit_sysfs(struct platform_device *pdev,
struct omap_dss_device *dssdev);
/* manager */
@ -299,21 +237,23 @@ void dss_overlay_kobj_uninit(struct omap_overlay *ovl);
int dss_init_platform_driver(void) __init;
void dss_uninit_platform_driver(void);
unsigned long dss_get_dispc_clk_rate(void);
int dss_dpi_select_source(enum omap_channel channel);
void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void);
const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
void dss_dump_clocks(struct seq_file *s);
#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
#if defined(CONFIG_OMAP2_DSS_DEBUGFS)
void dss_debug_dump_clocks(struct seq_file *s);
#endif
int dss_get_ctx_loss_count(void);
void dss_sdi_init(int datapairs);
int dss_sdi_enable(void);
void dss_sdi_disable(void);
void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src);
void dss_select_dsi_clk_source(int dsi_module,
enum omap_dss_clk_source clk_src);
void dss_select_lcd_clk_source(enum omap_channel channel,
@ -326,6 +266,7 @@ void dss_set_venc_output(enum omap_dss_venc_type type);
void dss_set_dac_pwrdn_bgz(bool enable);
unsigned long dss_get_dpll4_rate(void);
int dss_calc_clock_rates(struct dss_clock_info *cinfo);
int dss_set_clock_div(struct dss_clock_info *cinfo);
int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
struct dispc_clock_info *dispc_cinfo);
@ -413,8 +354,6 @@ static inline void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev)
}
static inline struct platform_device *dsi_get_dsidev_from_id(int module)
{
WARN("%s: DSI not compiled in, returning platform device as NULL\n",
__func__);
return NULL;
}
#endif
@ -427,15 +366,10 @@ void dpi_uninit_platform_driver(void) __exit;
int dispc_init_platform_driver(void) __init;
void dispc_uninit_platform_driver(void) __exit;
void dispc_dump_clocks(struct seq_file *s);
void dispc_irq_handler(void);
int dispc_runtime_get(void);
void dispc_runtime_put(void);
void dispc_enable_sidle(void);
void dispc_disable_sidle(void);
void dispc_lcd_enable_signal_polarity(bool act_high);
void dispc_lcd_enable_signal(bool enable);
void dispc_pck_free_enable(bool enable);
void dispc_enable_fifomerge(bool enable);
@ -455,36 +389,14 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high);
void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
u32 *fifo_low, u32 *fifo_high, bool use_fifomerge,
bool manual_update);
int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi,
bool replication, const struct omap_video_timings *mgr_timings,
bool mem_to_mem);
int dispc_ovl_enable(enum omap_plane plane, bool enable);
void dispc_ovl_set_channel_out(enum omap_plane plane,
enum omap_channel channel);
void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable);
u32 dispc_mgr_get_vsync_irq(enum omap_channel channel);
u32 dispc_mgr_get_framedone_irq(enum omap_channel channel);
bool dispc_mgr_go_busy(enum omap_channel channel);
void dispc_mgr_go(enum omap_channel channel);
bool dispc_mgr_is_enabled(enum omap_channel channel);
void dispc_mgr_enable(enum omap_channel channel, bool enable);
bool dispc_mgr_is_channel_enabled(enum omap_channel channel);
void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode);
void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable);
void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines);
void dispc_mgr_set_lcd_type_tft(enum omap_channel channel);
void dispc_mgr_set_timings(enum omap_channel channel,
struct omap_video_timings *timings);
unsigned long dispc_mgr_lclk_rate(enum omap_channel channel);
unsigned long dispc_mgr_pclk_rate(enum omap_channel channel);
unsigned long dispc_core_clk_rate(void);
void dispc_mgr_set_clock_div(enum omap_channel channel,
struct dispc_clock_info *cinfo);
const struct dispc_clock_info *cinfo);
int dispc_mgr_get_clock_div(enum omap_channel channel,
struct dispc_clock_info *cinfo);
void dispc_mgr_setup(enum omap_channel channel,
struct omap_overlay_manager_info *info);
u32 dispc_wb_get_framedone_irq(void);
bool dispc_wb_go_busy(void);
@ -536,6 +448,8 @@ static inline unsigned long hdmi_get_pixel_clock(void)
#endif
int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev);
void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev);
int omapdss_hdmi_core_enable(struct omap_dss_device *dssdev);
void omapdss_hdmi_core_disable(struct omap_dss_device *dssdev);
void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev,
struct omap_video_timings *timings);
int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,

View File

@ -18,12 +18,12 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <video/omapdss.h>
#include <plat/cpu.h>
#include "dss.h"
#include "dss_features.h"
@ -430,8 +430,6 @@ static const struct dss_param_range omap2_dss_param_range[] = {
* scaler cannot scale a image with width more than 768.
*/
[FEAT_PARAM_LINEWIDTH] = { 1, 768 },
[FEAT_PARAM_MGR_WIDTH] = { 1, 2048 },
[FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 },
};
static const struct dss_param_range omap3_dss_param_range[] = {
@ -446,8 +444,6 @@ static const struct dss_param_range omap3_dss_param_range[] = {
[FEAT_PARAM_DSI_FCK] = { 0, 173000000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
[FEAT_PARAM_LINEWIDTH] = { 1, 1024 },
[FEAT_PARAM_MGR_WIDTH] = { 1, 2048 },
[FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 },
};
static const struct dss_param_range omap4_dss_param_range[] = {
@ -462,8 +458,6 @@ static const struct dss_param_range omap4_dss_param_range[] = {
[FEAT_PARAM_DSI_FCK] = { 0, 170000000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
[FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
[FEAT_PARAM_MGR_WIDTH] = { 1, 2048 },
[FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 },
};
static const struct dss_param_range omap5_dss_param_range[] = {
@ -478,8 +472,6 @@ static const struct dss_param_range omap5_dss_param_range[] = {
[FEAT_PARAM_DSI_FCK] = { 0, 170000000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
[FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
[FEAT_PARAM_MGR_WIDTH] = { 1, 2048 },
[FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 },
};
static const enum dss_feat_id omap2_dss_feat_list[] = {
@ -821,14 +813,25 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = {
.audio_start = ti_hdmi_4xxx_audio_start,
.audio_stop = ti_hdmi_4xxx_audio_stop,
.audio_config = ti_hdmi_4xxx_audio_config,
.audio_get_dma_port = ti_hdmi_4xxx_audio_get_dma_port,
#endif
};
void dss_init_hdmi_ip_ops(struct hdmi_ip_data *ip_data)
void dss_init_hdmi_ip_ops(struct hdmi_ip_data *ip_data,
enum omapdss_version version)
{
if (cpu_is_omap44xx())
switch (version) {
case OMAPDSS_VER_OMAP4430_ES1:
case OMAPDSS_VER_OMAP4430_ES2:
case OMAPDSS_VER_OMAP4:
ip_data->ops = &omap4_hdmi_functions;
break;
default:
ip_data->ops = NULL;
}
WARN_ON(ip_data->ops == NULL);
}
#endif
@ -837,11 +840,13 @@ int dss_feat_get_num_mgrs(void)
{
return omap_current_dss_features->num_mgrs;
}
EXPORT_SYMBOL(dss_feat_get_num_mgrs);
int dss_feat_get_num_ovls(void)
{
return omap_current_dss_features->num_ovls;
}
EXPORT_SYMBOL(dss_feat_get_num_ovls);
int dss_feat_get_num_wbs(void)
{
@ -862,16 +867,19 @@ enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel
{
return omap_current_dss_features->supported_displays[channel];
}
EXPORT_SYMBOL(dss_feat_get_supported_displays);
enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel)
{
return omap_current_dss_features->supported_outputs[channel];
}
EXPORT_SYMBOL(dss_feat_get_supported_outputs);
enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane)
{
return omap_current_dss_features->supported_color_modes[plane];
}
EXPORT_SYMBOL(dss_feat_get_supported_color_modes);
enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane)
{
@ -929,29 +937,44 @@ bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type)
return omap_current_dss_features->supported_rotation_types & rot_type;
}
void dss_features_init(void)
void dss_features_init(enum omapdss_version version)
{
if (cpu_is_omap24xx())
switch (version) {
case OMAPDSS_VER_OMAP24xx:
omap_current_dss_features = &omap2_dss_features;
else if (cpu_is_omap3630())
break;
case OMAPDSS_VER_OMAP34xx_ES1:
case OMAPDSS_VER_OMAP34xx_ES3:
omap_current_dss_features = &omap3430_dss_features;
break;
case OMAPDSS_VER_OMAP3630:
omap_current_dss_features = &omap3630_dss_features;
else if (cpu_is_omap34xx()) {
if (soc_is_am35xx()) {
omap_current_dss_features = &am35xx_dss_features;
} else {
omap_current_dss_features = &omap3430_dss_features;
}
}
else if (omap_rev() == OMAP4430_REV_ES1_0)
break;
case OMAPDSS_VER_OMAP4430_ES1:
omap_current_dss_features = &omap4430_es1_0_dss_features;
else if (omap_rev() == OMAP4430_REV_ES2_0 ||
omap_rev() == OMAP4430_REV_ES2_1 ||
omap_rev() == OMAP4430_REV_ES2_2)
break;
case OMAPDSS_VER_OMAP4430_ES2:
omap_current_dss_features = &omap4430_es2_0_1_2_dss_features;
else if (cpu_is_omap44xx())
break;
case OMAPDSS_VER_OMAP4:
omap_current_dss_features = &omap4_dss_features;
else if (soc_is_omap54xx())
break;
case OMAPDSS_VER_OMAP5:
omap_current_dss_features = &omap5_dss_features;
else
break;
case OMAPDSS_VER_AM35xx:
omap_current_dss_features = &am35xx_dss_features;
break;
default:
DSSWARN("Unsupported OMAP version");
break;
}
}

View File

@ -98,19 +98,12 @@ enum dss_range_param {
FEAT_PARAM_DSI_FCK,
FEAT_PARAM_DOWNSCALE,
FEAT_PARAM_LINEWIDTH,
FEAT_PARAM_MGR_WIDTH,
FEAT_PARAM_MGR_HEIGHT,
};
/* DSS Feature Functions */
int dss_feat_get_num_mgrs(void);
int dss_feat_get_num_ovls(void);
int dss_feat_get_num_wbs(void);
unsigned long dss_feat_get_param_min(enum dss_range_param param);
unsigned long dss_feat_get_param_max(enum dss_range_param param);
enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel);
enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel);
enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane);
enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane);
bool dss_feat_color_mode_supported(enum omap_plane plane,
enum omap_color_mode color_mode);
@ -123,8 +116,9 @@ bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type);
bool dss_has_feature(enum dss_feat_id id);
void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
void dss_features_init(void);
void dss_features_init(enum omapdss_version version);
#if defined(CONFIG_OMAP4_DSS_HDMI)
void dss_init_hdmi_ip_ops(struct hdmi_ip_data *ip_data);
void dss_init_hdmi_ip_ops(struct hdmi_ip_data *ip_data,
enum omapdss_version version);
#endif
#endif

View File

@ -60,6 +60,7 @@
static struct {
struct mutex lock;
struct platform_device *pdev;
struct hdmi_ip_data ip_data;
struct clk *sys_clk;
@ -295,6 +296,12 @@ static const struct hdmi_config vesa_timings[] = {
false, },
{ 0x55, HDMI_DVI },
},
{
{ 1920, 1200, 154000, 32, 48, 80, 6, 3, 26,
OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
false, },
{ 0x44, HDMI_DVI },
},
};
static int hdmi_runtime_get(void)
@ -333,13 +340,17 @@ static int __init hdmi_init_display(struct omap_dss_device *dssdev)
DSSDBG("init_display\n");
dss_init_hdmi_ip_ops(&hdmi.ip_data);
dss_init_hdmi_ip_ops(&hdmi.ip_data, omapdss_get_version());
if (hdmi.vdda_hdmi_dac_reg == NULL) {
struct regulator *reg;
reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac");
/* DT HACK: try VDAC to make omapdss work for o4 sdp/panda */
if (IS_ERR(reg))
reg = devm_regulator_get(&hdmi.pdev->dev, "VDAC");
if (IS_ERR(reg)) {
DSSERR("can't get VDDA_HDMI_DAC regulator\n");
return PTR_ERR(reg);
@ -355,7 +366,7 @@ static int __init hdmi_init_display(struct omap_dss_device *dssdev)
return 0;
}
static void __exit hdmi_uninit_display(struct omap_dss_device *dssdev)
static void hdmi_uninit_display(struct omap_dss_device *dssdev)
{
DSSDBG("uninit_display\n");
@ -398,7 +409,8 @@ static bool hdmi_timings_compare(struct omap_video_timings *timing1,
{
int timing1_vsync, timing1_hsync, timing2_vsync, timing2_hsync;
if ((timing2->pixel_clock == timing1->pixel_clock) &&
if ((DIV_ROUND_CLOSEST(timing2->pixel_clock, 1000) ==
DIV_ROUND_CLOSEST(timing1->pixel_clock, 1000)) &&
(timing2->x_res == timing1->x_res) &&
(timing2->y_res == timing1->y_res)) {
@ -500,12 +512,9 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
}
static int hdmi_power_on(struct omap_dss_device *dssdev)
static int hdmi_power_on_core(struct omap_dss_device *dssdev)
{
int r;
struct omap_video_timings *p;
struct omap_overlay_manager *mgr = dssdev->output->manager;
unsigned long phy;
gpio_set_value(hdmi.ct_cp_hpd_gpio, 1);
gpio_set_value(hdmi.ls_oe_gpio, 1);
@ -521,6 +530,38 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
if (r)
goto err_runtime_get;
/* Make selection of HDMI in DSS */
dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);
return 0;
err_runtime_get:
regulator_disable(hdmi.vdda_hdmi_dac_reg);
err_vdac_enable:
gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
gpio_set_value(hdmi.ls_oe_gpio, 0);
return r;
}
static void hdmi_power_off_core(struct omap_dss_device *dssdev)
{
hdmi_runtime_put();
regulator_disable(hdmi.vdda_hdmi_dac_reg);
gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
gpio_set_value(hdmi.ls_oe_gpio, 0);
}
static int hdmi_power_on_full(struct omap_dss_device *dssdev)
{
int r;
struct omap_video_timings *p;
struct omap_overlay_manager *mgr = dssdev->output->manager;
unsigned long phy;
r = hdmi_power_on_core(dssdev);
if (r)
return r;
dss_mgr_disable(mgr);
p = &hdmi.ip_data.cfg.timings;
@ -548,17 +589,6 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
hdmi.ip_data.ops->video_configure(&hdmi.ip_data);
/* Make selection of HDMI in DSS */
dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);
/* Select the dispc clock source as PRCM clock, to ensure that it is not
* DSI PLL source as the clock selected by DSI PLL might not be
* sufficient for the resolution selected / that can be changed
* dynamically by user. This can be moved to single location , say
* Boardfile.
*/
dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
/* bypass TV gamma table */
dispc_enable_gamma_table(0);
@ -582,16 +612,11 @@ err_vid_enable:
err_phy_enable:
hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
err_pll_enable:
hdmi_runtime_put();
err_runtime_get:
regulator_disable(hdmi.vdda_hdmi_dac_reg);
err_vdac_enable:
gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
gpio_set_value(hdmi.ls_oe_gpio, 0);
hdmi_power_off_core(dssdev);
return -EIO;
}
static void hdmi_power_off(struct omap_dss_device *dssdev)
static void hdmi_power_off_full(struct omap_dss_device *dssdev)
{
struct omap_overlay_manager *mgr = dssdev->output->manager;
@ -600,12 +625,8 @@ static void hdmi_power_off(struct omap_dss_device *dssdev)
hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
hdmi_runtime_put();
regulator_disable(hdmi.vdda_hdmi_dac_reg);
gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
gpio_set_value(hdmi.ls_oe_gpio, 0);
hdmi_power_off_core(dssdev);
}
int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
@ -715,7 +736,7 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
goto err0;
}
r = hdmi_power_on(dssdev);
r = hdmi_power_on_full(dssdev);
if (r) {
DSSERR("failed to power on device\n");
goto err1;
@ -737,13 +758,48 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
mutex_lock(&hdmi.lock);
hdmi_power_off(dssdev);
hdmi_power_off_full(dssdev);
omap_dss_stop_device(dssdev);
mutex_unlock(&hdmi.lock);
}
int omapdss_hdmi_core_enable(struct omap_dss_device *dssdev)
{
int r = 0;
DSSDBG("ENTER omapdss_hdmi_core_enable\n");
mutex_lock(&hdmi.lock);
hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio;
r = hdmi_power_on_core(dssdev);
if (r) {
DSSERR("failed to power on device\n");
goto err0;
}
mutex_unlock(&hdmi.lock);
return 0;
err0:
mutex_unlock(&hdmi.lock);
return r;
}
void omapdss_hdmi_core_disable(struct omap_dss_device *dssdev)
{
DSSDBG("Enter omapdss_hdmi_core_disable\n");
mutex_lock(&hdmi.lock);
hdmi_power_off_core(dssdev);
mutex_unlock(&hdmi.lock);
}
static int hdmi_get_clocks(struct platform_device *pdev)
{
struct clk *clk;
@ -912,7 +968,7 @@ int hdmi_audio_config(struct omap_dss_audio *audio)
static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
const char *def_disp_name = dss_get_default_display_name();
const char *def_disp_name = omapdss_get_default_display_name();
struct omap_dss_device *def_dssdev;
int i;
@ -970,9 +1026,19 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev)
return;
}
r = omapdss_output_set_device(&hdmi.output, dssdev);
if (r) {
DSSERR("failed to connect output to new device: %s\n",
dssdev->name);
dss_put_device(dssdev);
return;
}
r = dss_add_device(dssdev);
if (r) {
DSSERR("device %s register failed: %d\n", dssdev->name, r);
omapdss_output_unset_device(&hdmi.output);
hdmi_uninit_display(dssdev);
dss_put_device(dssdev);
return;
}
@ -999,22 +1065,22 @@ static void __exit hdmi_uninit_output(struct platform_device *pdev)
/* HDMI HW IP initialisation */
static int __init omapdss_hdmihw_probe(struct platform_device *pdev)
{
struct resource *hdmi_mem;
struct resource *res;
int r;
hdmi.pdev = pdev;
mutex_init(&hdmi.lock);
mutex_init(&hdmi.ip_data.lock);
hdmi_mem = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0);
if (!hdmi_mem) {
res = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0);
if (!res) {
DSSERR("can't get IORESOURCE_MEM HDMI\n");
return -EINVAL;
}
/* Base address taken from platform */
hdmi.ip_data.base_wp = ioremap(hdmi_mem->start,
resource_size(hdmi_mem));
hdmi.ip_data.base_wp = devm_request_and_ioremap(&pdev->dev, res);
if (!hdmi.ip_data.base_wp) {
DSSERR("can't ioremap WP\n");
return -ENOMEM;
@ -1022,7 +1088,7 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev)
r = hdmi_get_clocks(pdev);
if (r) {
iounmap(hdmi.ip_data.base_wp);
DSSERR("can't get clocks\n");
return r;
}
@ -1033,9 +1099,11 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev)
hdmi.ip_data.pll_offset = HDMI_PLLCTRL;
hdmi.ip_data.phy_offset = HDMI_PHY;
mutex_init(&hdmi.ip_data.lock);
hdmi_panel_init();
r = hdmi_panel_init();
if (r) {
DSSERR("can't init panel\n");
goto err_panel_init;
}
dss_debugfs_create_file("hdmi", hdmi_dump_regs);
@ -1044,6 +1112,10 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev)
hdmi_probe_pdata(pdev);
return 0;
err_panel_init:
hdmi_put_clocks();
return r;
}
static int __exit hdmi_remove_child(struct device *dev, void *data)
@ -1067,8 +1139,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
hdmi_put_clocks();
iounmap(hdmi.ip_data.base_wp);
return 0;
}

View File

@ -280,58 +280,6 @@ static void hdmi_panel_disable(struct omap_dss_device *dssdev)
mutex_unlock(&hdmi.lock);
}
static int hdmi_panel_suspend(struct omap_dss_device *dssdev)
{
int r = 0;
mutex_lock(&hdmi.lock);
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
r = -EINVAL;
goto err;
}
/*
* TODO: notify audio users that the display was suspended. For now,
* disable audio locally to not break our audio state machine.
*/
hdmi_panel_audio_disable(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
omapdss_hdmi_display_disable(dssdev);
err:
mutex_unlock(&hdmi.lock);
return r;
}
static int hdmi_panel_resume(struct omap_dss_device *dssdev)
{
int r = 0;
mutex_lock(&hdmi.lock);
if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
r = -EINVAL;
goto err;
}
r = omapdss_hdmi_display_enable(dssdev);
if (r) {
DSSERR("failed to power on\n");
goto err;
}
/* TODO: notify audio users that the panel resumed. */
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
err:
mutex_unlock(&hdmi.lock);
return r;
}
static void hdmi_get_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
@ -379,20 +327,22 @@ static int hdmi_check_timings(struct omap_dss_device *dssdev,
static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len)
{
int r;
bool need_enable;
mutex_lock(&hdmi.lock);
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
r = omapdss_hdmi_display_enable(dssdev);
need_enable = dssdev->state == OMAP_DSS_DISPLAY_DISABLED;
if (need_enable) {
r = omapdss_hdmi_core_enable(dssdev);
if (r)
goto err;
}
r = omapdss_hdmi_read_edid(buf, len);
if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED ||
dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
omapdss_hdmi_display_disable(dssdev);
if (need_enable)
omapdss_hdmi_core_disable(dssdev);
err:
mutex_unlock(&hdmi.lock);
@ -402,20 +352,22 @@ err:
static bool hdmi_detect(struct omap_dss_device *dssdev)
{
int r;
bool need_enable;
mutex_lock(&hdmi.lock);
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
r = omapdss_hdmi_display_enable(dssdev);
need_enable = dssdev->state == OMAP_DSS_DISPLAY_DISABLED;
if (need_enable) {
r = omapdss_hdmi_core_enable(dssdev);
if (r)
goto err;
}
r = omapdss_hdmi_detect();
if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED ||
dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
omapdss_hdmi_display_disable(dssdev);
if (need_enable)
omapdss_hdmi_core_disable(dssdev);
err:
mutex_unlock(&hdmi.lock);
@ -427,8 +379,6 @@ static struct omap_dss_driver hdmi_driver = {
.remove = hdmi_panel_remove,
.enable = hdmi_panel_enable,
.disable = hdmi_panel_disable,
.suspend = hdmi_panel_suspend,
.resume = hdmi_panel_resume,
.get_timings = hdmi_get_timings,
.set_timings = hdmi_set_timings,
.check_timings = hdmi_check_timings,
@ -454,9 +404,7 @@ int hdmi_panel_init(void)
spin_lock_init(&hdmi.audio_lock);
#endif
omap_dss_register_driver(&hdmi_driver);
return 0;
return omap_dss_register_driver(&hdmi_driver);
}
void hdmi_panel_exit(void)

View File

@ -36,36 +36,6 @@
static int num_managers;
static struct omap_overlay_manager *managers;
static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr)
{
return mgr->output ? mgr->output->device : NULL;
}
static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
{
unsigned long timeout = msecs_to_jiffies(500);
struct omap_dss_device *dssdev = mgr->get_device(mgr);
u32 irq;
int r;
r = dispc_runtime_get();
if (r)
return r;
if (dssdev->type == OMAP_DISPLAY_TYPE_VENC)
irq = DISPC_IRQ_EVSYNC_ODD;
else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI)
irq = DISPC_IRQ_EVSYNC_EVEN;
else
irq = dispc_mgr_get_vsync_irq(mgr->id);
r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
dispc_runtime_put();
return r;
}
int dss_init_overlay_managers(struct platform_device *pdev)
{
int i, r;
@ -99,15 +69,6 @@ int dss_init_overlay_managers(struct platform_device *pdev)
break;
}
mgr->set_output = &dss_mgr_set_output;
mgr->unset_output = &dss_mgr_unset_output;
mgr->apply = &omap_dss_mgr_apply;
mgr->set_manager_info = &dss_mgr_set_info;
mgr->get_manager_info = &dss_mgr_get_info;
mgr->wait_for_go = &dss_mgr_wait_for_go;
mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
mgr->get_device = &dss_mgr_get_device;
mgr->caps = 0;
mgr->supported_displays =
dss_feat_get_supported_displays(mgr->id);

View File

@ -114,35 +114,67 @@ struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id)
return NULL;
}
struct omap_dss_output *omapdss_get_output_from_dssdev(struct omap_dss_device *dssdev)
static const struct dss_mgr_ops *dss_mgr_ops;
int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops)
{
struct omap_dss_output *out = NULL;
enum omap_dss_output_id id;
if (dss_mgr_ops)
return -EBUSY;
switch (dssdev->type) {
case OMAP_DISPLAY_TYPE_DPI:
out = omap_dss_get_output(OMAP_DSS_OUTPUT_DPI);
break;
case OMAP_DISPLAY_TYPE_DBI:
out = omap_dss_get_output(OMAP_DSS_OUTPUT_DBI);
break;
case OMAP_DISPLAY_TYPE_SDI:
out = omap_dss_get_output(OMAP_DSS_OUTPUT_SDI);
break;
case OMAP_DISPLAY_TYPE_VENC:
out = omap_dss_get_output(OMAP_DSS_OUTPUT_VENC);
break;
case OMAP_DISPLAY_TYPE_HDMI:
out = omap_dss_get_output(OMAP_DSS_OUTPUT_HDMI);
break;
case OMAP_DISPLAY_TYPE_DSI:
id = dssdev->phy.dsi.module == 0 ? OMAP_DSS_OUTPUT_DSI1 :
OMAP_DSS_OUTPUT_DSI2;
out = omap_dss_get_output(id);
break;
default:
break;
}
dss_mgr_ops = mgr_ops;
return out;
return 0;
}
EXPORT_SYMBOL(dss_install_mgr_ops);
void dss_uninstall_mgr_ops(void)
{
dss_mgr_ops = NULL;
}
EXPORT_SYMBOL(dss_uninstall_mgr_ops);
void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
const struct omap_video_timings *timings)
{
dss_mgr_ops->set_timings(mgr, timings);
}
EXPORT_SYMBOL(dss_mgr_set_timings);
void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
const struct dss_lcd_mgr_config *config)
{
dss_mgr_ops->set_lcd_config(mgr, config);
}
EXPORT_SYMBOL(dss_mgr_set_lcd_config);
int dss_mgr_enable(struct omap_overlay_manager *mgr)
{
return dss_mgr_ops->enable(mgr);
}
EXPORT_SYMBOL(dss_mgr_enable);
void dss_mgr_disable(struct omap_overlay_manager *mgr)
{
dss_mgr_ops->disable(mgr);
}
EXPORT_SYMBOL(dss_mgr_disable);
void dss_mgr_start_update(struct omap_overlay_manager *mgr)
{
dss_mgr_ops->start_update(mgr);
}
EXPORT_SYMBOL(dss_mgr_start_update);
int dss_mgr_register_framedone_handler(struct omap_overlay_manager *mgr,
void (*handler)(void *), void *data)
{
return dss_mgr_ops->register_framedone_handler(mgr, handler, data);
}
EXPORT_SYMBOL(dss_mgr_register_framedone_handler);
void dss_mgr_unregister_framedone_handler(struct omap_overlay_manager *mgr,
void (*handler)(void *), void *data)
{
dss_mgr_ops->unregister_framedone_handler(mgr, handler, data);
}
EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler);

View File

@ -38,13 +38,6 @@
static int num_overlays;
static struct omap_overlay *overlays;
static inline struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl)
{
return ovl->manager ?
(ovl->manager->output ? ovl->manager->output->device : NULL) :
NULL;
}
int omap_dss_get_num_overlays(void)
{
return num_overlays;
@ -93,16 +86,6 @@ void dss_init_overlays(struct platform_device *pdev)
break;
}
ovl->is_enabled = &dss_ovl_is_enabled;
ovl->enable = &dss_ovl_enable;
ovl->disable = &dss_ovl_disable;
ovl->set_manager = &dss_ovl_set_manager;
ovl->unset_manager = &dss_ovl_unset_manager;
ovl->set_overlay_info = &dss_ovl_set_info;
ovl->get_overlay_info = &dss_ovl_get_info;
ovl->wait_for_go = &dss_mgr_wait_for_go_ovl;
ovl->get_device = &dss_ovl_get_device;
ovl->caps = dss_feat_get_overlay_caps(ovl->id);
ovl->supported_modes =
dss_feat_get_supported_color_modes(ovl->id);

View File

@ -342,7 +342,7 @@ static int rfbi_transfer_area(struct omap_dss_device *dssdev,
return 0;
}
static void framedone_callback(void *data, u32 mask)
static void framedone_callback(void *data)
{
void (*callback)(void *data);
@ -908,8 +908,8 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
goto err0;
}
r = omap_dispc_register_isr(framedone_callback, NULL,
DISPC_IRQ_FRAMEDONE);
r = dss_mgr_register_framedone_handler(out->manager,
framedone_callback, NULL);
if (r) {
DSSERR("can't get FRAMEDONE irq\n");
goto err1;
@ -933,8 +933,10 @@ EXPORT_SYMBOL(omapdss_rfbi_display_enable);
void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev)
{
omap_dispc_unregister_isr(framedone_callback, NULL,
DISPC_IRQ_FRAMEDONE);
struct omap_dss_output *out = dssdev->output;
dss_mgr_unregister_framedone_handler(out->manager,
framedone_callback, NULL);
omap_dss_stop_device(dssdev);
rfbi_runtime_put();
@ -950,7 +952,7 @@ static int __init rfbi_init_display(struct omap_dss_device *dssdev)
static struct omap_dss_device * __init rfbi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
const char *def_disp_name = dss_get_default_display_name();
const char *def_disp_name = omapdss_get_default_display_name();
struct omap_dss_device *def_dssdev;
int i;
@ -999,9 +1001,18 @@ static void __init rfbi_probe_pdata(struct platform_device *rfbidev)
return;
}
r = omapdss_output_set_device(&rfbi.output, dssdev);
if (r) {
DSSERR("failed to connect output to new device: %s\n",
dssdev->name);
dss_put_device(dssdev);
return;
}
r = dss_add_device(dssdev);
if (r) {
DSSERR("device %s register failed: %d\n", dssdev->name, r);
omapdss_output_unset_device(&rfbi.output);
dss_put_device(dssdev);
return;
}

View File

@ -205,7 +205,7 @@ static int __init sdi_init_display(struct omap_dss_device *dssdev)
static struct omap_dss_device * __init sdi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
const char *def_disp_name = dss_get_default_display_name();
const char *def_disp_name = omapdss_get_default_display_name();
struct omap_dss_device *def_dssdev;
int i;
@ -254,9 +254,18 @@ static void __init sdi_probe_pdata(struct platform_device *sdidev)
return;
}
r = omapdss_output_set_device(&sdi.output, dssdev);
if (r) {
DSSERR("failed to connect output to new device: %s\n",
dssdev->name);
dss_put_device(dssdev);
return;
}
r = dss_add_device(dssdev);
if (r) {
DSSERR("device %s register failed: %d\n", dssdev->name, r);
omapdss_output_unset_device(&sdi.output);
dss_put_device(dssdev);
return;
}

View File

@ -102,6 +102,8 @@ struct ti_hdmi_ip_ops {
int (*audio_config)(struct hdmi_ip_data *ip_data,
struct omap_dss_audio *audio);
int (*audio_get_dma_port)(u32 *offset, u32 *size);
#endif
};
@ -183,5 +185,6 @@ int ti_hdmi_4xxx_audio_start(struct hdmi_ip_data *ip_data);
void ti_hdmi_4xxx_audio_stop(struct hdmi_ip_data *ip_data);
int ti_hdmi_4xxx_audio_config(struct hdmi_ip_data *ip_data,
struct omap_dss_audio *audio);
int ti_hdmi_4xxx_audio_get_dma_port(u32 *offset, u32 *size);
#endif
#endif

View File

@ -899,7 +899,7 @@ void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s)
#define DUMPCOREAV(r) seq_printf(s, "%-35s %08x\n", #r,\
hdmi_read_reg(hdmi_av_base(ip_data), r))
#define DUMPCOREAV2(i, r) seq_printf(s, "%s[%d]%*s %08x\n", #r, i, \
(i < 10) ? 32 - strlen(#r) : 31 - strlen(#r), " ", \
(i < 10) ? 32 - (int)strlen(#r) : 31 - (int)strlen(#r), " ", \
hdmi_read_reg(hdmi_av_base(ip_data), CORE_REG(i, r)))
DUMPCORE(HDMI_CORE_SYS_VND_IDL);
@ -1418,4 +1418,13 @@ void ti_hdmi_4xxx_audio_stop(struct hdmi_ip_data *ip_data)
REG_FLD_MOD(hdmi_wp_base(ip_data),
HDMI_WP_AUDIO_CTRL, false, 30, 30);
}
int ti_hdmi_4xxx_audio_get_dma_port(u32 *offset, u32 *size)
{
if (!offset || !size)
return -EINVAL;
*offset = HDMI_WP_AUDIO_DATA;
*size = 4;
return 0;
}
#endif

View File

@ -744,7 +744,7 @@ static void venc_put_clocks(void)
static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
const char *def_disp_name = dss_get_default_display_name();
const char *def_disp_name = omapdss_get_default_display_name();
struct omap_dss_device *def_dssdev;
int i;
@ -795,9 +795,18 @@ static void __init venc_probe_pdata(struct platform_device *vencdev)
return;
}
r = omapdss_output_set_device(&venc.output, dssdev);
if (r) {
DSSERR("failed to connect output to new device: %s\n",
dssdev->name);
dss_put_device(dssdev);
return;
}
r = dss_add_device(dssdev);
if (r) {
DSSERR("device %s register failed: %d\n", dssdev->name, r);
omapdss_output_unset_device(&venc.output);
dss_put_device(dssdev);
return;
}

View File

@ -157,12 +157,6 @@ static void venc_panel_disable(struct omap_dss_device *dssdev)
if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
goto end;
if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) {
/* suspended is the same as disabled with venc */
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
goto end;
}
omapdss_venc_display_disable(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
@ -170,17 +164,6 @@ end:
mutex_unlock(&venc_panel.lock);
}
static int venc_panel_suspend(struct omap_dss_device *dssdev)
{
venc_panel_disable(dssdev);
return 0;
}
static int venc_panel_resume(struct omap_dss_device *dssdev)
{
return venc_panel_enable(dssdev);
}
static void venc_panel_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
@ -222,8 +205,6 @@ static struct omap_dss_driver venc_driver = {
.enable = venc_panel_enable,
.disable = venc_panel_disable,
.suspend = venc_panel_suspend,
.resume = venc_panel_resume,
.get_resolution = omapdss_default_get_resolution,
.get_recommended_bpp = omapdss_default_get_recommended_bpp,

View File

@ -2,7 +2,6 @@ menuconfig FB_OMAP2
tristate "OMAP2+ frame buffer support"
depends on FB && OMAP2_DSS && !DRM_OMAP
select OMAP2_VRAM
select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA

View File

@ -28,10 +28,10 @@
#include <linux/omapfb.h>
#include <linux/vmalloc.h>
#include <linux/export.h>
#include <linux/sizes.h>
#include <video/omapdss.h>
#include <plat/vrfb.h>
#include <plat/vram.h>
#include <video/omapvrfb.h>
#include "omapfb.h"
@ -211,6 +211,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
{
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev;
struct omap_dss_device *display = fb2display(fbi);
struct omapfb2_mem_region *rg;
int r = 0, i;
size_t size;
@ -220,6 +221,9 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
size = PAGE_ALIGN(mi->size);
if (display && display->driver->sync)
display->driver->sync(display);
rg = ofbi->region;
down_write_nested(&rg->lock, rg->id);
@ -279,7 +283,7 @@ static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
return 0;
}
static int omapfb_update_window_nolock(struct fb_info *fbi,
static int omapfb_update_window(struct fb_info *fbi,
u32 x, u32 y, u32 w, u32 h)
{
struct omap_dss_device *display = fb2display(fbi);
@ -299,27 +303,6 @@ static int omapfb_update_window_nolock(struct fb_info *fbi,
return display->driver->update(display, x, y, w, h);
}
/* This function is exported for SGX driver use */
int omapfb_update_window(struct fb_info *fbi,
u32 x, u32 y, u32 w, u32 h)
{
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev;
int r;
if (!lock_fb_info(fbi))
return -ENODEV;
omapfb_lock(fbdev);
r = omapfb_update_window_nolock(fbi, x, y, w, h);
omapfb_unlock(fbdev);
unlock_fb_info(fbi);
return r;
}
EXPORT_SYMBOL(omapfb_update_window);
int omapfb_set_update_mode(struct fb_info *fbi,
enum omapfb_update_mode mode)
{
@ -646,7 +629,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
break;
}
r = omapfb_update_window_nolock(fbi, p.uwnd_o.x, p.uwnd_o.y,
r = omapfb_update_window(fbi, p.uwnd_o.x, p.uwnd_o.y,
p.uwnd_o.width, p.uwnd_o.height);
break;
@ -663,7 +646,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
break;
}
r = omapfb_update_window_nolock(fbi, p.uwnd.x, p.uwnd.y,
r = omapfb_update_window(fbi, p.uwnd.x, p.uwnd.y,
p.uwnd.width, p.uwnd.height);
break;
@ -853,14 +836,15 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
break;
case OMAPFB_GET_VRAM_INFO: {
unsigned long vram, free, largest;
DBG("ioctl GET_VRAM_INFO\n");
omap_vram_get_info(&vram, &free, &largest);
p.vram_info.total = vram;
p.vram_info.free = free;
p.vram_info.largest_free_block = largest;
/*
* We don't have the ability to get this vram info anymore.
* Fill in something that should keep the applications working.
*/
p.vram_info.total = SZ_1M * 64;
p.vram_info.free = SZ_1M * 64;
p.vram_info.largest_free_block = SZ_1M * 64;
if (copy_to_user((void __user *)arg, &p.vram_info,
sizeof(p.vram_info)))

View File

@ -31,9 +31,7 @@
#include <linux/omapfb.h>
#include <video/omapdss.h>
#include <plat/cpu.h>
#include <plat/vram.h>
#include <plat/vrfb.h>
#include <video/omapvrfb.h>
#include "omapfb.h"
@ -1259,11 +1257,10 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
switch (blank) {
case FB_BLANK_UNBLANK:
if (display->state != OMAP_DSS_DISPLAY_SUSPENDED)
if (display->state == OMAP_DSS_DISPLAY_ACTIVE)
goto exit;
if (display->driver->resume)
r = display->driver->resume(display);
r = display->driver->enable(display);
if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) &&
d->update_mode == OMAPFB_AUTO_UPDATE &&
@ -1284,8 +1281,7 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
if (d->auto_update_work_enabled)
omapfb_stop_auto_update(fbdev, display);
if (display->driver->suspend)
r = display->driver->suspend(display);
display->driver->disable(display);
break;
@ -1336,24 +1332,25 @@ static void omapfb_free_fbmem(struct fb_info *fbi)
rg = ofbi->region;
if (rg->token == NULL)
return;
WARN_ON(atomic_read(&rg->map_count));
if (rg->paddr)
if (omap_vram_free(rg->paddr, rg->size))
dev_err(fbdev->dev, "VRAM FREE failed\n");
if (rg->vaddr)
iounmap(rg->vaddr);
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
/* unmap the 0 angle rotation */
if (rg->vrfb.vaddr[0]) {
iounmap(rg->vrfb.vaddr[0]);
omap_vrfb_release_ctx(&rg->vrfb);
rg->vrfb.vaddr[0] = NULL;
}
omap_vrfb_release_ctx(&rg->vrfb);
}
dma_free_attrs(fbdev->dev, rg->size, rg->token, rg->dma_handle,
&rg->attrs);
rg->token = NULL;
rg->vaddr = NULL;
rg->paddr = 0;
rg->alloc = 0;
@ -1388,7 +1385,9 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev;
struct omapfb2_mem_region *rg;
void __iomem *vaddr;
void *token;
DEFINE_DMA_ATTRS(attrs);
dma_addr_t dma_handle;
int r;
rg = ofbi->region;
@ -1403,42 +1402,40 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
size = PAGE_ALIGN(size);
if (!paddr) {
DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);
r = omap_vram_alloc(size, &paddr);
} else {
DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr,
ofbi->id);
r = omap_vram_reserve(paddr, size);
}
dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
if (r) {
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs);
DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);
token = dma_alloc_attrs(fbdev->dev, size, &dma_handle,
GFP_KERNEL, &attrs);
if (token == NULL) {
dev_err(fbdev->dev, "failed to allocate framebuffer\n");
return -ENOMEM;
}
if (ofbi->rotation_type != OMAP_DSS_ROT_VRFB) {
vaddr = ioremap_wc(paddr, size);
DBG("allocated VRAM paddr %lx, vaddr %p\n",
(unsigned long)dma_handle, token);
if (!vaddr) {
dev_err(fbdev->dev, "failed to ioremap framebuffer\n");
omap_vram_free(paddr, size);
return -ENOMEM;
}
DBG("allocated VRAM paddr %lx, vaddr %p\n", paddr, vaddr);
} else {
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
r = omap_vrfb_request_ctx(&rg->vrfb);
if (r) {
dma_free_attrs(fbdev->dev, size, token, dma_handle,
&attrs);
dev_err(fbdev->dev, "vrfb create ctx failed\n");
return r;
}
vaddr = NULL;
}
rg->paddr = paddr;
rg->vaddr = vaddr;
rg->attrs = attrs;
rg->token = token;
rg->dma_handle = dma_handle;
rg->paddr = (unsigned long)dma_handle;
rg->vaddr = (void __iomem *)token;
rg->size = size;
rg->alloc = 1;
@ -1532,6 +1529,9 @@ static int omapfb_parse_vram_param(const char *param, int max_entries,
}
WARN_ONCE(paddr,
"reserving memory at predefined address not supported\n");
paddrs[fbnum] = paddr;
sizes[fbnum] = size;
@ -1611,7 +1611,6 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
{
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev;
struct omap_dss_device *display = fb2display(fbi);
struct omapfb2_mem_region *rg = ofbi->region;
unsigned long old_size = rg->size;
unsigned long old_paddr = rg->paddr;
@ -1626,9 +1625,6 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
if (old_size == size && old_type == type)
return 0;
if (display && display->driver->sync)
display->driver->sync(display);
omapfb_free_fbmem(fbi);
if (size == 0) {
@ -1883,7 +1879,6 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev)
}
dev_set_drvdata(fbdev->dev, NULL);
kfree(fbdev);
}
static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
@ -2259,26 +2254,28 @@ static int omapfb_find_best_mode(struct omap_dss_device *display,
{
struct fb_monspecs *specs;
u8 *edid;
int r, i, best_xres, best_idx, len;
int r, i, best_idx, len;
if (!display->driver->read_edid)
return -ENODEV;
len = 0x80 * 2;
edid = kmalloc(len, GFP_KERNEL);
if (edid == NULL)
return -ENOMEM;
r = display->driver->read_edid(display, edid, len);
if (r < 0)
goto err1;
specs = kzalloc(sizeof(*specs), GFP_KERNEL);
if (specs == NULL) {
r = -ENOMEM;
goto err1;
}
fb_edid_to_monspecs(edid, specs);
if (edid[126] > 0)
fb_edid_add_monspecs(edid + 0x80, specs);
best_xres = 0;
best_idx = -1;
for (i = 0; i < specs->modedb_len; ++i) {
@ -2294,16 +2291,20 @@ static int omapfb_find_best_mode(struct omap_dss_device *display,
if (m->xres == 2880 || m->xres == 1440)
continue;
if (m->vmode & FB_VMODE_INTERLACED ||
m->vmode & FB_VMODE_DOUBLE)
continue;
fb_videomode_to_omap_timings(m, display, &t);
r = display->driver->check_timings(display, &t);
if (r == 0 && best_xres < m->xres) {
best_xres = m->xres;
if (r == 0) {
best_idx = i;
break;
}
}
if (best_xres == 0) {
if (best_idx == -1) {
r = -ENOENT;
goto err2;
}
@ -2372,15 +2373,62 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
return 0;
}
static int omapfb_init_connections(struct omapfb2_device *fbdev,
struct omap_dss_device *def_dssdev)
{
int i, r;
struct omap_overlay_manager *mgr;
if (!def_dssdev->output) {
dev_err(fbdev->dev, "no output for the default display\n");
return -EINVAL;
}
for (i = 0; i < fbdev->num_displays; ++i) {
struct omap_dss_device *dssdev = fbdev->displays[i].dssdev;
struct omap_dss_output *out = dssdev->output;
mgr = omap_dss_get_overlay_manager(dssdev->channel);
if (!mgr || !out)
continue;
if (mgr->output)
mgr->unset_output(mgr);
mgr->set_output(mgr, out);
}
mgr = def_dssdev->output->manager;
if (!mgr) {
dev_err(fbdev->dev, "no ovl manager for the default display\n");
return -EINVAL;
}
for (i = 0; i < fbdev->num_overlays; i++) {
struct omap_overlay *ovl = fbdev->overlays[i];
if (ovl->manager)
ovl->unset_manager(ovl);
r = ovl->set_manager(ovl, mgr);
if (r)
dev_warn(fbdev->dev,
"failed to connect overlay %s to manager %s\n",
ovl->name, mgr->name);
}
return 0;
}
static int __init omapfb_probe(struct platform_device *pdev)
{
struct omapfb2_device *fbdev = NULL;
int r = 0;
int i;
struct omap_overlay *ovl;
struct omap_dss_device *def_display;
struct omap_dss_device *dssdev;
struct omap_dss_device *ovl_device;
DBG("omapfb_probe\n");
@ -2390,28 +2438,28 @@ static int __init omapfb_probe(struct platform_device *pdev)
goto err0;
}
fbdev = kzalloc(sizeof(struct omapfb2_device), GFP_KERNEL);
fbdev = devm_kzalloc(&pdev->dev, sizeof(struct omapfb2_device),
GFP_KERNEL);
if (fbdev == NULL) {
r = -ENOMEM;
goto err0;
}
/* TODO : Replace cpu check with omap_has_vrfb once HAS_FEATURE
* available for OMAP2 and OMAP3
*/
if (def_vrfb && !cpu_is_omap24xx() && !cpu_is_omap34xx()) {
if (def_vrfb && !omap_vrfb_supported()) {
def_vrfb = 0;
dev_warn(&pdev->dev, "VRFB is not supported on this hardware, "
"ignoring the module parameter vrfb=y\n");
}
r = omapdss_compat_init();
if (r)
goto err0;
mutex_init(&fbdev->mtx);
fbdev->dev = &pdev->dev;
platform_set_drvdata(pdev, fbdev);
r = 0;
fbdev->num_displays = 0;
dssdev = NULL;
for_each_dss_dev(dssdev) {
@ -2434,9 +2482,6 @@ static int __init omapfb_probe(struct platform_device *pdev)
d->update_mode = OMAPFB_AUTO_UPDATE;
}
if (r)
goto cleanup;
if (fbdev->num_displays == 0) {
dev_err(&pdev->dev, "no displays\n");
r = -EINVAL;
@ -2451,15 +2496,33 @@ static int __init omapfb_probe(struct platform_device *pdev)
for (i = 0; i < fbdev->num_managers; i++)
fbdev->managers[i] = omap_dss_get_overlay_manager(i);
/* gfx overlay should be the default one. find a display
* connected to that, and use it as default display */
ovl = omap_dss_get_overlay(0);
ovl_device = ovl->get_device(ovl);
if (ovl_device) {
def_display = ovl_device;
} else {
dev_warn(&pdev->dev, "cannot find default display\n");
def_display = NULL;
def_display = NULL;
for (i = 0; i < fbdev->num_displays; ++i) {
struct omap_dss_device *dssdev;
const char *def_name;
def_name = omapdss_get_default_display_name();
dssdev = fbdev->displays[i].dssdev;
if (def_name == NULL ||
(dssdev->name && strcmp(def_name, dssdev->name) == 0)) {
def_display = dssdev;
break;
}
}
if (def_display == NULL) {
dev_err(fbdev->dev, "failed to find default display\n");
r = -EINVAL;
goto cleanup;
}
r = omapfb_init_connections(fbdev, def_display);
if (r) {
dev_err(fbdev->dev, "failed to init overlay connections\n");
goto cleanup;
}
if (def_mode && strlen(def_mode) > 0) {
@ -2510,6 +2573,7 @@ static int __init omapfb_probe(struct platform_device *pdev)
cleanup:
omapfb_free_resources(fbdev);
omapdss_compat_uninit();
err0:
dev_err(&pdev->dev, "failed to setup omapfb\n");
return r;
@ -2525,6 +2589,8 @@ static int __exit omapfb_remove(struct platform_device *pdev)
omapfb_free_resources(fbdev);
omapdss_compat_uninit();
return 0;
}

View File

@ -30,7 +30,7 @@
#include <linux/omapfb.h>
#include <video/omapdss.h>
#include <plat/vrfb.h>
#include <video/omapvrfb.h>
#include "omapfb.h"
@ -441,6 +441,7 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev;
struct omap_dss_device *display = fb2display(fbi);
struct omapfb2_mem_region *rg;
unsigned long size;
int r;
@ -455,6 +456,9 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
if (!lock_fb_info(fbi))
return -ENODEV;
if (display && display->driver->sync)
display->driver->sync(display);
rg = ofbi->region;
down_write_nested(&rg->lock, rg->id);

View File

@ -28,6 +28,8 @@
#endif
#include <linux/rwsem.h>
#include <linux/dma-attrs.h>
#include <linux/dma-mapping.h>
#include <video/omapdss.h>
@ -49,6 +51,9 @@ extern bool omapfb_debug;
struct omapfb2_mem_region {
int id;
struct dma_attrs attrs;
void *token;
dma_addr_t dma_handle;
u32 paddr;
void __iomem *vaddr;
struct vrfb vrfb;
@ -124,9 +129,6 @@ void omapfb_remove_sysfs(struct omapfb2_device *fbdev);
int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg);
int omapfb_update_window(struct fb_info *fbi,
u32 x, u32 y, u32 w, u32 h);
int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
struct fb_var_screeninfo *var);
@ -144,16 +146,16 @@ int omapfb_set_update_mode(struct fb_info *fbi, enum omapfb_update_mode mode);
static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
{
struct omapfb_info *ofbi = FB2OFB(fbi);
int i;
struct omap_overlay *ovl;
/* XXX: returns the display connected to first attached overlay */
for (i = 0; i < ofbi->num_overlays; i++) {
struct omap_overlay *ovl = ofbi->overlays[i];
return ovl->get_device(ovl);
}
if (ofbi->num_overlays == 0)
return NULL;
return NULL;
ovl = ofbi->overlays[0];
return ovl->get_device(ovl);
}
static inline struct omapfb_display_data *get_display_data(

View File

@ -1,514 +0,0 @@
/*
* VRAM manager for OMAP
*
* Copyright (C) 2009 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that 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.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*#define DEBUG*/
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/seq_file.h>
#include <linux/memblock.h>
#include <linux/completion.h>
#include <linux/debugfs.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <asm/setup.h>
#include <plat/vram.h>
#ifdef DEBUG
#define DBG(format, ...) pr_debug("VRAM: " format, ## __VA_ARGS__)
#else
#define DBG(format, ...)
#endif
/* postponed regions are used to temporarily store region information at boot
* time when we cannot yet allocate the region list */
#define MAX_POSTPONED_REGIONS 10
static bool vram_initialized;
static int postponed_cnt;
static struct {
unsigned long paddr;
size_t size;
} postponed_regions[MAX_POSTPONED_REGIONS];
struct vram_alloc {
struct list_head list;
unsigned long paddr;
unsigned pages;
};
struct vram_region {
struct list_head list;
struct list_head alloc_list;
unsigned long paddr;
unsigned pages;
};
static DEFINE_MUTEX(region_mutex);
static LIST_HEAD(region_list);
static struct vram_region *omap_vram_create_region(unsigned long paddr,
unsigned pages)
{
struct vram_region *rm;
rm = kzalloc(sizeof(*rm), GFP_KERNEL);
if (rm) {
INIT_LIST_HEAD(&rm->alloc_list);
rm->paddr = paddr;
rm->pages = pages;
}
return rm;
}
#if 0
static void omap_vram_free_region(struct vram_region *vr)
{
list_del(&vr->list);
kfree(vr);
}
#endif
static struct vram_alloc *omap_vram_create_allocation(struct vram_region *vr,
unsigned long paddr, unsigned pages)
{
struct vram_alloc *va;
struct vram_alloc *new;
new = kzalloc(sizeof(*va), GFP_KERNEL);
if (!new)
return NULL;
new->paddr = paddr;
new->pages = pages;
list_for_each_entry(va, &vr->alloc_list, list) {
if (va->paddr > new->paddr)
break;
}
list_add_tail(&new->list, &va->list);
return new;
}
static void omap_vram_free_allocation(struct vram_alloc *va)
{
list_del(&va->list);
kfree(va);
}
int omap_vram_add_region(unsigned long paddr, size_t size)
{
struct vram_region *rm;
unsigned pages;
if (vram_initialized) {
DBG("adding region paddr %08lx size %d\n",
paddr, size);
size &= PAGE_MASK;
pages = size >> PAGE_SHIFT;
rm = omap_vram_create_region(paddr, pages);
if (rm == NULL)
return -ENOMEM;
list_add(&rm->list, &region_list);
} else {
if (postponed_cnt == MAX_POSTPONED_REGIONS)
return -ENOMEM;
postponed_regions[postponed_cnt].paddr = paddr;
postponed_regions[postponed_cnt].size = size;
++postponed_cnt;
}
return 0;
}
int omap_vram_free(unsigned long paddr, size_t size)
{
struct vram_region *rm;
struct vram_alloc *alloc;
unsigned start, end;
DBG("free mem paddr %08lx size %d\n", paddr, size);
size = PAGE_ALIGN(size);
mutex_lock(&region_mutex);
list_for_each_entry(rm, &region_list, list) {
list_for_each_entry(alloc, &rm->alloc_list, list) {
start = alloc->paddr;
end = alloc->paddr + (alloc->pages >> PAGE_SHIFT);
if (start >= paddr && end < paddr + size)
goto found;
}
}
mutex_unlock(&region_mutex);
return -EINVAL;
found:
omap_vram_free_allocation(alloc);
mutex_unlock(&region_mutex);
return 0;
}
EXPORT_SYMBOL(omap_vram_free);
static int _omap_vram_reserve(unsigned long paddr, unsigned pages)
{
struct vram_region *rm;
struct vram_alloc *alloc;
size_t size;
size = pages << PAGE_SHIFT;
list_for_each_entry(rm, &region_list, list) {
unsigned long start, end;
DBG("checking region %lx %d\n", rm->paddr, rm->pages);
start = rm->paddr;
end = start + (rm->pages << PAGE_SHIFT) - 1;
if (start > paddr || end < paddr + size - 1)
continue;
DBG("block ok, checking allocs\n");
list_for_each_entry(alloc, &rm->alloc_list, list) {
end = alloc->paddr - 1;
if (start <= paddr && end >= paddr + size - 1)
goto found;
start = alloc->paddr + (alloc->pages << PAGE_SHIFT);
}
end = rm->paddr + (rm->pages << PAGE_SHIFT) - 1;
if (!(start <= paddr && end >= paddr + size - 1))
continue;
found:
DBG("found area start %lx, end %lx\n", start, end);
if (omap_vram_create_allocation(rm, paddr, pages) == NULL)
return -ENOMEM;
return 0;
}
return -ENOMEM;
}
int omap_vram_reserve(unsigned long paddr, size_t size)
{
unsigned pages;
int r;
DBG("reserve mem paddr %08lx size %d\n", paddr, size);
size = PAGE_ALIGN(size);
pages = size >> PAGE_SHIFT;
mutex_lock(&region_mutex);
r = _omap_vram_reserve(paddr, pages);
mutex_unlock(&region_mutex);
return r;
}
EXPORT_SYMBOL(omap_vram_reserve);
static int _omap_vram_alloc(unsigned pages, unsigned long *paddr)
{
struct vram_region *rm;
struct vram_alloc *alloc;
list_for_each_entry(rm, &region_list, list) {
unsigned long start, end;
DBG("checking region %lx %d\n", rm->paddr, rm->pages);
start = rm->paddr;
list_for_each_entry(alloc, &rm->alloc_list, list) {
end = alloc->paddr;
if (end - start >= pages << PAGE_SHIFT)
goto found;
start = alloc->paddr + (alloc->pages << PAGE_SHIFT);
}
end = rm->paddr + (rm->pages << PAGE_SHIFT);
found:
if (end - start < pages << PAGE_SHIFT)
continue;
DBG("found %lx, end %lx\n", start, end);
alloc = omap_vram_create_allocation(rm, start, pages);
if (alloc == NULL)
return -ENOMEM;
*paddr = start;
return 0;
}
return -ENOMEM;
}
int omap_vram_alloc(size_t size, unsigned long *paddr)
{
unsigned pages;
int r;
BUG_ON(!size);
DBG("alloc mem size %d\n", size);
size = PAGE_ALIGN(size);
pages = size >> PAGE_SHIFT;
mutex_lock(&region_mutex);
r = _omap_vram_alloc(pages, paddr);
mutex_unlock(&region_mutex);
return r;
}
EXPORT_SYMBOL(omap_vram_alloc);
void omap_vram_get_info(unsigned long *vram,
unsigned long *free_vram,
unsigned long *largest_free_block)
{
struct vram_region *vr;
struct vram_alloc *va;
*vram = 0;
*free_vram = 0;
*largest_free_block = 0;
mutex_lock(&region_mutex);
list_for_each_entry(vr, &region_list, list) {
unsigned free;
unsigned long pa;
pa = vr->paddr;
*vram += vr->pages << PAGE_SHIFT;
list_for_each_entry(va, &vr->alloc_list, list) {
free = va->paddr - pa;
*free_vram += free;
if (free > *largest_free_block)
*largest_free_block = free;
pa = va->paddr + (va->pages << PAGE_SHIFT);
}
free = vr->paddr + (vr->pages << PAGE_SHIFT) - pa;
*free_vram += free;
if (free > *largest_free_block)
*largest_free_block = free;
}
mutex_unlock(&region_mutex);
}
EXPORT_SYMBOL(omap_vram_get_info);
#if defined(CONFIG_DEBUG_FS)
static int vram_debug_show(struct seq_file *s, void *unused)
{
struct vram_region *vr;
struct vram_alloc *va;
unsigned size;
mutex_lock(&region_mutex);
list_for_each_entry(vr, &region_list, list) {
size = vr->pages << PAGE_SHIFT;
seq_printf(s, "%08lx-%08lx (%d bytes)\n",
vr->paddr, vr->paddr + size - 1,
size);
list_for_each_entry(va, &vr->alloc_list, list) {
size = va->pages << PAGE_SHIFT;
seq_printf(s, " %08lx-%08lx (%d bytes)\n",
va->paddr, va->paddr + size - 1,
size);
}
}
mutex_unlock(&region_mutex);
return 0;
}
static int vram_debug_open(struct inode *inode, struct file *file)
{
return single_open(file, vram_debug_show, inode->i_private);
}
static const struct file_operations vram_debug_fops = {
.open = vram_debug_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int __init omap_vram_create_debugfs(void)
{
struct dentry *d;
d = debugfs_create_file("vram", S_IRUGO, NULL,
NULL, &vram_debug_fops);
if (IS_ERR(d))
return PTR_ERR(d);
return 0;
}
#endif
static __init int omap_vram_init(void)
{
int i;
vram_initialized = 1;
for (i = 0; i < postponed_cnt; i++)
omap_vram_add_region(postponed_regions[i].paddr,
postponed_regions[i].size);
#ifdef CONFIG_DEBUG_FS
if (omap_vram_create_debugfs())
pr_err("VRAM: Failed to create debugfs file\n");
#endif
return 0;
}
arch_initcall(omap_vram_init);
/* boottime vram alloc stuff */
/* set from board file */
static u32 omap_vram_sdram_start __initdata;
static u32 omap_vram_sdram_size __initdata;
/* set from kernel cmdline */
static u32 omap_vram_def_sdram_size __initdata;
static u32 omap_vram_def_sdram_start __initdata;
static int __init omap_vram_early_vram(char *p)
{
omap_vram_def_sdram_size = memparse(p, &p);
if (*p == ',')
omap_vram_def_sdram_start = simple_strtoul(p + 1, &p, 16);
return 0;
}
early_param("vram", omap_vram_early_vram);
/*
* Called from map_io. We need to call to this early enough so that we
* can reserve the fixed SDRAM regions before VM could get hold of them.
*/
void __init omap_vram_reserve_sdram_memblock(void)
{
u32 paddr;
u32 size = 0;
/* cmdline arg overrides the board file definition */
if (omap_vram_def_sdram_size) {
size = omap_vram_def_sdram_size;
paddr = omap_vram_def_sdram_start;
}
if (!size) {
size = omap_vram_sdram_size;
paddr = omap_vram_sdram_start;
}
#ifdef CONFIG_OMAP2_VRAM_SIZE
if (!size) {
size = CONFIG_OMAP2_VRAM_SIZE * 1024 * 1024;
paddr = 0;
}
#endif
if (!size)
return;
size = ALIGN(size, SZ_2M);
if (paddr) {
if (paddr & ~PAGE_MASK) {
pr_err("VRAM start address 0x%08x not page aligned\n",
paddr);
return;
}
if (!memblock_is_region_memory(paddr, size)) {
pr_err("Illegal SDRAM region 0x%08x..0x%08x for VRAM\n",
paddr, paddr + size - 1);
return;
}
if (memblock_is_region_reserved(paddr, size)) {
pr_err("FB: failed to reserve VRAM - busy\n");
return;
}
if (memblock_reserve(paddr, size) < 0) {
pr_err("FB: failed to reserve VRAM - no memory\n");
return;
}
} else {
paddr = memblock_alloc(size, SZ_2M);
}
memblock_free(paddr, size);
memblock_remove(paddr, size);
omap_vram_add_region(paddr, size);
pr_info("Reserving %u bytes SDRAM for VRAM\n", size);
}
void __init omap_vram_set_sdram_vram(u32 size, u32 start)
{
omap_vram_sdram_start = start;
omap_vram_sdram_size = size;
}

View File

@ -26,9 +26,9 @@
#include <linux/io.h>
#include <linux/bitops.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <plat/vrfb.h>
#include <plat/sdrc.h>
#include <video/omapvrfb.h>
#ifdef DEBUG
#define DBG(format, ...) pr_debug("VRFB: " format, ## __VA_ARGS__)
@ -36,10 +36,10 @@
#define DBG(format, ...)
#endif
#define SMS_ROT_VIRT_BASE(context, rot) \
(((context >= 4) ? 0xD0000000 : 0x70000000) \
+ (0x4000000 * (context)) \
+ (0x1000000 * (rot)))
#define SMS_ROT_CONTROL(context) (0x0 + 0x10 * context)
#define SMS_ROT_SIZE(context) (0x4 + 0x10 * context)
#define SMS_ROT_PHYSICAL_BA(context) (0x8 + 0x10 * context)
#define SMS_ROT_VIRT_BASE(rot) (0x1000000 * (rot))
#define OMAP_VRFB_SIZE (2048 * 2048 * 4)
@ -53,10 +53,16 @@
#define SMS_PW_OFFSET 4
#define SMS_PS_OFFSET 0
#define VRFB_NUM_CTXS 12
/* bitmap of reserved contexts */
static unsigned long ctx_map;
struct vrfb_ctx {
u32 base;
u32 physical_ba;
u32 control;
u32 size;
};
static DEFINE_MUTEX(ctx_lock);
/*
@ -65,17 +71,34 @@ static DEFINE_MUTEX(ctx_lock);
* we don't need locking, since no drivers will run until after the wake-up
* has finished.
*/
static struct {
u32 physical_ba;
u32 control;
u32 size;
} vrfb_hw_context[VRFB_NUM_CTXS];
static void __iomem *vrfb_base;
static int num_ctxs;
static struct vrfb_ctx *ctxs;
static bool vrfb_loaded;
static void omap2_sms_write_rot_control(u32 val, unsigned ctx)
{
__raw_writel(val, vrfb_base + SMS_ROT_CONTROL(ctx));
}
static void omap2_sms_write_rot_size(u32 val, unsigned ctx)
{
__raw_writel(val, vrfb_base + SMS_ROT_SIZE(ctx));
}
static void omap2_sms_write_rot_physical_ba(u32 val, unsigned ctx)
{
__raw_writel(val, vrfb_base + SMS_ROT_PHYSICAL_BA(ctx));
}
static inline void restore_hw_context(int ctx)
{
omap2_sms_write_rot_control(vrfb_hw_context[ctx].control, ctx);
omap2_sms_write_rot_size(vrfb_hw_context[ctx].size, ctx);
omap2_sms_write_rot_physical_ba(vrfb_hw_context[ctx].physical_ba, ctx);
omap2_sms_write_rot_control(ctxs[ctx].control, ctx);
omap2_sms_write_rot_size(ctxs[ctx].size, ctx);
omap2_sms_write_rot_physical_ba(ctxs[ctx].physical_ba, ctx);
}
static u32 get_image_width_roundup(u16 width, u8 bytespp)
@ -196,9 +219,9 @@ void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr,
control |= VRFB_PAGE_WIDTH_EXP << SMS_PW_OFFSET;
control |= VRFB_PAGE_HEIGHT_EXP << SMS_PH_OFFSET;
vrfb_hw_context[ctx].physical_ba = paddr;
vrfb_hw_context[ctx].size = size;
vrfb_hw_context[ctx].control = control;
ctxs[ctx].physical_ba = paddr;
ctxs[ctx].size = size;
ctxs[ctx].control = control;
omap2_sms_write_rot_physical_ba(paddr, ctx);
omap2_sms_write_rot_size(size, ctx);
@ -274,11 +297,11 @@ int omap_vrfb_request_ctx(struct vrfb *vrfb)
mutex_lock(&ctx_lock);
for (ctx = 0; ctx < VRFB_NUM_CTXS; ++ctx)
for (ctx = 0; ctx < num_ctxs; ++ctx)
if ((ctx_map & (1 << ctx)) == 0)
break;
if (ctx == VRFB_NUM_CTXS) {
if (ctx == num_ctxs) {
pr_err("vrfb: no free contexts\n");
r = -EBUSY;
goto out;
@ -293,7 +316,7 @@ int omap_vrfb_request_ctx(struct vrfb *vrfb)
vrfb->context = ctx;
for (rot = 0; rot < 4; ++rot) {
paddr = SMS_ROT_VIRT_BASE(ctx, rot);
paddr = ctxs[ctx].base + SMS_ROT_VIRT_BASE(rot);
if (!request_mem_region(paddr, OMAP_VRFB_SIZE, "vrfb")) {
pr_err("vrfb: failed to reserve VRFB "
"area for ctx %d, rotation %d\n",
@ -314,3 +337,80 @@ out:
return r;
}
EXPORT_SYMBOL(omap_vrfb_request_ctx);
bool omap_vrfb_supported(void)
{
return vrfb_loaded;
}
EXPORT_SYMBOL(omap_vrfb_supported);
static int __init vrfb_probe(struct platform_device *pdev)
{
struct resource *mem;
int i;
/* first resource is the register res, the rest are vrfb contexts */
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(&pdev->dev, "can't get vrfb base address\n");
return -EINVAL;
}
vrfb_base = devm_request_and_ioremap(&pdev->dev, mem);
if (!vrfb_base) {
dev_err(&pdev->dev, "can't ioremap vrfb memory\n");
return -ENOMEM;
}
num_ctxs = pdev->num_resources - 1;
ctxs = devm_kzalloc(&pdev->dev,
sizeof(struct vrfb_ctx) * num_ctxs,
GFP_KERNEL);
if (!ctxs)
return -ENOMEM;
for (i = 0; i < num_ctxs; ++i) {
mem = platform_get_resource(pdev, IORESOURCE_MEM, 1 + i);
if (!mem) {
dev_err(&pdev->dev, "can't get vrfb ctx %d address\n",
i);
return -EINVAL;
}
ctxs[i].base = mem->start;
}
vrfb_loaded = true;
return 0;
}
static void __exit vrfb_remove(struct platform_device *pdev)
{
vrfb_loaded = false;
}
static struct platform_driver vrfb_driver = {
.driver.name = "omapvrfb",
.remove = __exit_p(vrfb_remove),
};
static int __init vrfb_init(void)
{
return platform_driver_probe(&vrfb_driver, &vrfb_probe);
}
static void __exit vrfb_exit(void)
{
platform_driver_unregister(&vrfb_driver);
}
module_init(vrfb_init);
module_exit(vrfb_exit);
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
MODULE_DESCRIPTION("OMAP VRFB");
MODULE_LICENSE("GPL v2");

View File

@ -21,6 +21,7 @@
#include <linux/list.h>
#include <linux/kobject.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#define DISPC_IRQ_FRAMEDONE (1 << 0)
#define DISPC_IRQ_VSYNC (1 << 1)
@ -55,6 +56,7 @@
struct omap_dss_device;
struct omap_overlay_manager;
struct dss_lcd_mgr_config;
struct snd_aes_iec958;
struct snd_cea_861_aud_if;
@ -158,7 +160,6 @@ enum omap_display_caps {
enum omap_dss_display_state {
OMAP_DSS_DISPLAY_DISABLED = 0,
OMAP_DSS_DISPLAY_ACTIVE,
OMAP_DSS_DISPLAY_SUSPENDED,
};
enum omap_dss_audio_state {
@ -314,6 +315,19 @@ int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel);
int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel);
void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel);
enum omapdss_version {
OMAPDSS_VER_UNKNOWN = 0,
OMAPDSS_VER_OMAP24xx,
OMAPDSS_VER_OMAP34xx_ES1, /* OMAP3430 ES1.0, 2.0 */
OMAPDSS_VER_OMAP34xx_ES3, /* OMAP3430 ES3.0+ */
OMAPDSS_VER_OMAP3630,
OMAPDSS_VER_AM35xx,
OMAPDSS_VER_OMAP4430_ES1, /* OMAP4430 ES1.0 */
OMAPDSS_VER_OMAP4430_ES2, /* OMAP4430 ES2.0, 2.1, 2.2 */
OMAPDSS_VER_OMAP4, /* All other OMAP4s */
OMAPDSS_VER_OMAP5,
};
/* Board specific data */
struct omap_dss_board_info {
int (*get_context_loss_count)(struct device *dev);
@ -323,6 +337,7 @@ struct omap_dss_board_info {
int (*dsi_enable_pads)(int dsi_id, unsigned lane_mask);
void (*dsi_disable_pads)(int dsi_id, unsigned lane_mask);
int (*set_min_bus_tput)(struct device *dev, unsigned long r);
enum omapdss_version version;
};
/* Init with the board info */
@ -607,10 +622,6 @@ struct omap_dss_device {
struct {
struct omap_video_timings timings;
int acbi; /* ac-bias pin transitions per interrupt */
/* Unit: line clocks */
int acb; /* ac-bias pin frequency */
enum omap_dss_dsi_pixel_format dsi_pix_fmt;
enum omap_dss_dsi_mode dsi_mode;
struct omap_dss_dsi_videomode_timings dsi_vm_timings;
@ -672,8 +683,6 @@ struct omap_dss_driver {
int (*enable)(struct omap_dss_device *display);
void (*disable)(struct omap_dss_device *display);
int (*suspend)(struct omap_dss_device *display);
int (*resume)(struct omap_dss_device *display);
int (*run_test)(struct omap_dss_device *display, int test);
int (*update)(struct omap_dss_device *dssdev,
@ -731,6 +740,8 @@ struct omap_dss_driver {
};
enum omapdss_version omapdss_get_version(void);
int omap_dss_register_driver(struct omap_dss_driver *);
void omap_dss_unregister_driver(struct omap_dss_driver *);
@ -740,10 +751,19 @@ void omap_dss_put_device(struct omap_dss_device *dssdev);
struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from);
struct omap_dss_device *omap_dss_find_device(void *data,
int (*match)(struct omap_dss_device *dssdev, void *data));
const char *omapdss_get_default_display_name(void);
int omap_dss_start_device(struct omap_dss_device *dssdev);
void omap_dss_stop_device(struct omap_dss_device *dssdev);
int dss_feat_get_num_mgrs(void);
int dss_feat_get_num_ovls(void);
enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel);
enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel);
enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane);
int omap_dss_get_num_overlay_managers(void);
struct omap_overlay_manager *omap_dss_get_overlay_manager(int num);
@ -765,9 +785,43 @@ typedef void (*omap_dispc_isr_t) (void *arg, u32 mask);
int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask);
int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask);
int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout);
int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
unsigned long timeout);
u32 dispc_read_irqstatus(void);
void dispc_clear_irqstatus(u32 mask);
u32 dispc_read_irqenable(void);
void dispc_write_irqenable(u32 mask);
int dispc_request_irq(irq_handler_t handler, void *dev_id);
void dispc_free_irq(void *dev_id);
int dispc_runtime_get(void);
void dispc_runtime_put(void);
void dispc_mgr_enable(enum omap_channel channel, bool enable);
bool dispc_mgr_is_enabled(enum omap_channel channel);
u32 dispc_mgr_get_vsync_irq(enum omap_channel channel);
u32 dispc_mgr_get_framedone_irq(enum omap_channel channel);
u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel);
bool dispc_mgr_go_busy(enum omap_channel channel);
void dispc_mgr_go(enum omap_channel channel);
void dispc_mgr_set_lcd_config(enum omap_channel channel,
const struct dss_lcd_mgr_config *config);
void dispc_mgr_set_timings(enum omap_channel channel,
const struct omap_video_timings *timings);
void dispc_mgr_setup(enum omap_channel channel,
const struct omap_overlay_manager_info *info);
int dispc_ovl_check(enum omap_plane plane, enum omap_channel channel,
const struct omap_overlay_info *oi,
const struct omap_video_timings *timings,
int *x_predecim, int *y_predecim);
int dispc_ovl_enable(enum omap_plane plane, bool enable);
bool dispc_ovl_enabled(enum omap_plane plane);
void dispc_ovl_set_channel_out(enum omap_plane plane,
enum omap_channel channel);
int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi,
bool replication, const struct omap_video_timings *mgr_timings,
bool mem_to_mem);
#define to_dss_driver(x) container_of((x), struct omap_dss_driver, driver)
#define to_dss_device(x) container_of((x), struct omap_dss_device, dev)
@ -826,4 +880,35 @@ void omapdss_rfbi_set_data_lines(struct omap_dss_device *dssdev,
void omapdss_rfbi_set_interface_timings(struct omap_dss_device *dssdev,
struct rfbi_timings *timings);
int omapdss_compat_init(void);
void omapdss_compat_uninit(void);
struct dss_mgr_ops {
void (*start_update)(struct omap_overlay_manager *mgr);
int (*enable)(struct omap_overlay_manager *mgr);
void (*disable)(struct omap_overlay_manager *mgr);
void (*set_timings)(struct omap_overlay_manager *mgr,
const struct omap_video_timings *timings);
void (*set_lcd_config)(struct omap_overlay_manager *mgr,
const struct dss_lcd_mgr_config *config);
int (*register_framedone_handler)(struct omap_overlay_manager *mgr,
void (*handler)(void *), void *data);
void (*unregister_framedone_handler)(struct omap_overlay_manager *mgr,
void (*handler)(void *), void *data);
};
int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops);
void dss_uninstall_mgr_ops(void);
void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
const struct omap_video_timings *timings);
void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
const struct dss_lcd_mgr_config *config);
int dss_mgr_enable(struct omap_overlay_manager *mgr);
void dss_mgr_disable(struct omap_overlay_manager *mgr);
void dss_mgr_start_update(struct omap_overlay_manager *mgr);
int dss_mgr_register_framedone_handler(struct omap_overlay_manager *mgr,
void (*handler)(void *), void *data);
void dss_mgr_unregister_framedone_handler(struct omap_overlay_manager *mgr,
void (*handler)(void *), void *data);
#endif

View File

@ -36,6 +36,7 @@ struct vrfb {
};
#ifdef CONFIG_OMAP2_VRFB
extern bool omap_vrfb_supported(void);
extern int omap_vrfb_request_ctx(struct vrfb *vrfb);
extern void omap_vrfb_release_ctx(struct vrfb *vrfb);
extern void omap_vrfb_adjust_size(u16 *width, u16 *height,
@ -49,6 +50,7 @@ extern int omap_vrfb_map_angle(struct vrfb *vrfb, u16 height, u8 rot);
extern void omap_vrfb_restore_context(void);
#else
static inline bool omap_vrfb_supported(void) { return false; }
static inline int omap_vrfb_request_ctx(struct vrfb *vrfb) { return 0; }
static inline void omap_vrfb_release_ctx(struct vrfb *vrfb) {}
static inline void omap_vrfb_adjust_size(u16 *width, u16 *height,