lkml.org 
[lkml]   [2009]   [Nov]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 07/19] OMAP: DSS2: Display Subsystem Driver core
    Date
    The core files of DSS2. DSS2 commits are split a bit artificially to
    make the individual commits smaller, and DSS2 doesn't compile properly
    without the rest of the core commits. This shouldn't be a problem, as no
    configuration uses DSS2 yet.

    Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>
    ---
    arch/arm/plat-omap/include/plat/display.h | 575 ++++++++++++++++++
    drivers/video/omap2/Kconfig | 2 +
    drivers/video/omap2/Makefile | 2 +
    drivers/video/omap2/dss/Kconfig | 89 +++
    drivers/video/omap2/dss/Makefile | 6 +
    drivers/video/omap2/dss/core.c | 919 +++++++++++++++++++++++++++++
    drivers/video/omap2/dss/dss.c | 596 +++++++++++++++++++
    drivers/video/omap2/dss/dss.h | 370 ++++++++++++
    8 files changed, 2559 insertions(+), 0 deletions(-)
    create mode 100644 arch/arm/plat-omap/include/plat/display.h
    create mode 100644 drivers/video/omap2/dss/Kconfig
    create mode 100644 drivers/video/omap2/dss/Makefile
    create mode 100644 drivers/video/omap2/dss/core.c
    create mode 100644 drivers/video/omap2/dss/dss.c
    create mode 100644 drivers/video/omap2/dss/dss.h

    diff --git a/arch/arm/plat-omap/include/plat/display.h b/arch/arm/plat-omap/include/plat/display.h
    new file mode 100644
    index 0000000..c66e464
    --- /dev/null
    +++ b/arch/arm/plat-omap/include/plat/display.h
    @@ -0,0 +1,575 @@
    +/*
    + * linux/include/asm-arm/arch-omap/display.h
    + *
    + * Copyright (C) 2008 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, see <http://www.gnu.org/licenses/>.
    + */
    +
    +#ifndef __ASM_ARCH_OMAP_DISPLAY_H
    +#define __ASM_ARCH_OMAP_DISPLAY_H
    +
    +#include <linux/list.h>
    +#include <linux/kobject.h>
    +#include <linux/device.h>
    +#include <asm/atomic.h>
    +
    +#define DISPC_IRQ_FRAMEDONE (1 << 0)
    +#define DISPC_IRQ_VSYNC (1 << 1)
    +#define DISPC_IRQ_EVSYNC_EVEN (1 << 2)
    +#define DISPC_IRQ_EVSYNC_ODD (1 << 3)
    +#define DISPC_IRQ_ACBIAS_COUNT_STAT (1 << 4)
    +#define DISPC_IRQ_PROG_LINE_NUM (1 << 5)
    +#define DISPC_IRQ_GFX_FIFO_UNDERFLOW (1 << 6)
    +#define DISPC_IRQ_GFX_END_WIN (1 << 7)
    +#define DISPC_IRQ_PAL_GAMMA_MASK (1 << 8)
    +#define DISPC_IRQ_OCP_ERR (1 << 9)
    +#define DISPC_IRQ_VID1_FIFO_UNDERFLOW (1 << 10)
    +#define DISPC_IRQ_VID1_END_WIN (1 << 11)
    +#define DISPC_IRQ_VID2_FIFO_UNDERFLOW (1 << 12)
    +#define DISPC_IRQ_VID2_END_WIN (1 << 13)
    +#define DISPC_IRQ_SYNC_LOST (1 << 14)
    +#define DISPC_IRQ_SYNC_LOST_DIGIT (1 << 15)
    +#define DISPC_IRQ_WAKEUP (1 << 16)
    +
    +struct omap_dss_device;
    +struct omap_overlay_manager;
    +
    +enum omap_display_type {
    + OMAP_DISPLAY_TYPE_NONE = 0,
    + OMAP_DISPLAY_TYPE_DPI = 1 << 0,
    + OMAP_DISPLAY_TYPE_DBI = 1 << 1,
    + OMAP_DISPLAY_TYPE_SDI = 1 << 2,
    + OMAP_DISPLAY_TYPE_DSI = 1 << 3,
    + OMAP_DISPLAY_TYPE_VENC = 1 << 4,
    +};
    +
    +enum omap_plane {
    + OMAP_DSS_GFX = 0,
    + OMAP_DSS_VIDEO1 = 1,
    + OMAP_DSS_VIDEO2 = 2
    +};
    +
    +enum omap_channel {
    + OMAP_DSS_CHANNEL_LCD = 0,
    + OMAP_DSS_CHANNEL_DIGIT = 1,
    +};
    +
    +enum omap_color_mode {
    + OMAP_DSS_COLOR_CLUT1 = 1 << 0, /* BITMAP 1 */
    + OMAP_DSS_COLOR_CLUT2 = 1 << 1, /* BITMAP 2 */
    + OMAP_DSS_COLOR_CLUT4 = 1 << 2, /* BITMAP 4 */
    + OMAP_DSS_COLOR_CLUT8 = 1 << 3, /* BITMAP 8 */
    + OMAP_DSS_COLOR_RGB12U = 1 << 4, /* RGB12, 16-bit container */
    + OMAP_DSS_COLOR_ARGB16 = 1 << 5, /* ARGB16 */
    + OMAP_DSS_COLOR_RGB16 = 1 << 6, /* RGB16 */
    + OMAP_DSS_COLOR_RGB24U = 1 << 7, /* RGB24, 32-bit container */
    + OMAP_DSS_COLOR_RGB24P = 1 << 8, /* RGB24, 24-bit container */
    + OMAP_DSS_COLOR_YUV2 = 1 << 9, /* YUV2 4:2:2 co-sited */
    + OMAP_DSS_COLOR_UYVY = 1 << 10, /* UYVY 4:2:2 co-sited */
    + OMAP_DSS_COLOR_ARGB32 = 1 << 11, /* ARGB32 */
    + OMAP_DSS_COLOR_RGBA32 = 1 << 12, /* RGBA32 */
    + OMAP_DSS_COLOR_RGBX32 = 1 << 13, /* RGBx32 */
    +
    + OMAP_DSS_COLOR_GFX_OMAP2 =
    + OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
    + OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
    + OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
    + OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P,
    +
    + OMAP_DSS_COLOR_VID_OMAP2 =
    + OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
    + OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
    + OMAP_DSS_COLOR_UYVY,
    +
    + OMAP_DSS_COLOR_GFX_OMAP3 =
    + OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
    + OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
    + OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
    + OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
    + OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
    + OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
    +
    + OMAP_DSS_COLOR_VID1_OMAP3 =
    + OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
    + OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P |
    + OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY,
    +
    + OMAP_DSS_COLOR_VID2_OMAP3 =
    + OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
    + OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
    + OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
    + OMAP_DSS_COLOR_UYVY | OMAP_DSS_COLOR_ARGB32 |
    + OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
    +};
    +
    +enum omap_lcd_display_type {
    + OMAP_DSS_LCD_DISPLAY_STN,
    + OMAP_DSS_LCD_DISPLAY_TFT,
    +};
    +
    +enum omap_dss_load_mode {
    + OMAP_DSS_LOAD_CLUT_AND_FRAME = 0,
    + OMAP_DSS_LOAD_CLUT_ONLY = 1,
    + OMAP_DSS_LOAD_FRAME_ONLY = 2,
    + OMAP_DSS_LOAD_CLUT_ONCE_FRAME = 3,
    +};
    +
    +enum omap_dss_trans_key_type {
    + OMAP_DSS_COLOR_KEY_GFX_DST = 0,
    + OMAP_DSS_COLOR_KEY_VID_SRC = 1,
    +};
    +
    +enum omap_rfbi_te_mode {
    + OMAP_DSS_RFBI_TE_MODE_1 = 1,
    + OMAP_DSS_RFBI_TE_MODE_2 = 2,
    +};
    +
    +enum omap_panel_config {
    + OMAP_DSS_LCD_IVS = 1<<0,
    + OMAP_DSS_LCD_IHS = 1<<1,
    + OMAP_DSS_LCD_IPC = 1<<2,
    + OMAP_DSS_LCD_IEO = 1<<3,
    + OMAP_DSS_LCD_RF = 1<<4,
    + OMAP_DSS_LCD_ONOFF = 1<<5,
    +
    + OMAP_DSS_LCD_TFT = 1<<20,
    +};
    +
    +enum omap_dss_venc_type {
    + OMAP_DSS_VENC_TYPE_COMPOSITE,
    + OMAP_DSS_VENC_TYPE_SVIDEO,
    +};
    +
    +enum omap_display_caps {
    + OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE = 1 << 0,
    + OMAP_DSS_DISPLAY_CAP_TEAR_ELIM = 1 << 1,
    +};
    +
    +enum omap_dss_update_mode {
    + OMAP_DSS_UPDATE_DISABLED = 0,
    + OMAP_DSS_UPDATE_AUTO,
    + OMAP_DSS_UPDATE_MANUAL,
    +};
    +
    +enum omap_dss_display_state {
    + OMAP_DSS_DISPLAY_DISABLED = 0,
    + OMAP_DSS_DISPLAY_ACTIVE,
    + OMAP_DSS_DISPLAY_SUSPENDED,
    +};
    +
    +/* XXX perhaps this should be removed */
    +enum omap_dss_overlay_managers {
    + OMAP_DSS_OVL_MGR_LCD,
    + OMAP_DSS_OVL_MGR_TV,
    +};
    +
    +enum omap_dss_rotation_type {
    + OMAP_DSS_ROT_DMA = 0,
    + OMAP_DSS_ROT_VRFB = 1,
    +};
    +
    +/* clockwise rotation angle */
    +enum omap_dss_rotation_angle {
    + OMAP_DSS_ROT_0 = 0,
    + OMAP_DSS_ROT_90 = 1,
    + OMAP_DSS_ROT_180 = 2,
    + OMAP_DSS_ROT_270 = 3,
    +};
    +
    +enum omap_overlay_caps {
    + OMAP_DSS_OVL_CAP_SCALE = 1 << 0,
    + OMAP_DSS_OVL_CAP_DISPC = 1 << 1,
    +};
    +
    +enum omap_overlay_manager_caps {
    + OMAP_DSS_OVL_MGR_CAP_DISPC = 1 << 0,
    +};
    +
    +/* RFBI */
    +
    +struct rfbi_timings {
    + int cs_on_time;
    + int cs_off_time;
    + int we_on_time;
    + int we_off_time;
    + int re_on_time;
    + int re_off_time;
    + int we_cycle_time;
    + int re_cycle_time;
    + int cs_pulse_width;
    + int access_time;
    +
    + int clk_div;
    +
    + u32 tim[5]; /* set by rfbi_convert_timings() */
    +
    + int converted;
    +};
    +
    +void omap_rfbi_write_command(const void *buf, u32 len);
    +void omap_rfbi_read_data(void *buf, u32 len);
    +void omap_rfbi_write_data(const void *buf, u32 len);
    +void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
    + u16 x, u16 y,
    + u16 w, u16 h);
    +int omap_rfbi_enable_te(bool enable, unsigned line);
    +int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
    + unsigned hs_pulse_time, unsigned vs_pulse_time,
    + int hs_pol_inv, int vs_pol_inv, int extif_div);
    +
    +/* DSI */
    +void dsi_bus_lock(void);
    +void dsi_bus_unlock(void);
    +int dsi_vc_dcs_write(int channel, u8 *data, int len);
    +int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len);
    +int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen);
    +int dsi_vc_set_max_rx_packet_size(int channel, u16 len);
    +int dsi_vc_send_null(int channel);
    +int dsi_vc_send_bta_sync(int channel);
    +
    +/* Board specific data */
    +struct omap_dss_board_info {
    + int (*get_last_off_on_transaction_id)(struct device *dev);
    + int num_devices;
    + struct omap_dss_device **devices;
    + struct omap_dss_device *default_device;
    +};
    +
    +struct omap_video_timings {
    + /* Unit: pixels */
    + u16 x_res;
    + /* Unit: pixels */
    + u16 y_res;
    + /* Unit: KHz */
    + u32 pixel_clock;
    + /* Unit: pixel clocks */
    + u16 hsw; /* Horizontal synchronization pulse width */
    + /* Unit: pixel clocks */
    + u16 hfp; /* Horizontal front porch */
    + /* Unit: pixel clocks */
    + u16 hbp; /* Horizontal back porch */
    + /* Unit: line clocks */
    + u16 vsw; /* Vertical synchronization pulse width */
    + /* Unit: line clocks */
    + u16 vfp; /* Vertical front porch */
    + /* Unit: line clocks */
    + u16 vbp; /* Vertical back porch */
    +};
    +
    +#ifdef CONFIG_OMAP2_DSS_VENC
    +/* Hardcoded timings for tv modes. Venc only uses these to
    + * identify the mode, and does not actually use the configs
    + * itself. However, the configs should be something that
    + * a normal monitor can also show */
    +const extern struct omap_video_timings omap_dss_pal_timings;
    +const extern struct omap_video_timings omap_dss_ntsc_timings;
    +#endif
    +
    +struct omap_overlay_info {
    + bool enabled;
    +
    + u32 paddr;
    + void __iomem *vaddr;
    + u16 screen_width;
    + u16 width;
    + u16 height;
    + enum omap_color_mode color_mode;
    + u8 rotation;
    + enum omap_dss_rotation_type rotation_type;
    + bool mirror;
    +
    + u16 pos_x;
    + u16 pos_y;
    + u16 out_width; /* if 0, out_width == width */
    + u16 out_height; /* if 0, out_height == height */
    + u8 global_alpha;
    +};
    +
    +struct omap_overlay {
    + struct kobject kobj;
    + struct list_head list;
    +
    + /* static fields */
    + const char *name;
    + int id;
    + enum omap_color_mode supported_modes;
    + enum omap_overlay_caps caps;
    +
    + /* dynamic fields */
    + struct omap_overlay_manager *manager;
    + struct omap_overlay_info info;
    +
    + /* if true, info has been changed, but not applied() yet */
    + bool info_dirty;
    +
    + int (*set_manager)(struct omap_overlay *ovl,
    + struct omap_overlay_manager *mgr);
    + int (*unset_manager)(struct omap_overlay *ovl);
    +
    + int (*set_overlay_info)(struct omap_overlay *ovl,
    + struct omap_overlay_info *info);
    + void (*get_overlay_info)(struct omap_overlay *ovl,
    + struct omap_overlay_info *info);
    +
    + int (*wait_for_go)(struct omap_overlay *ovl);
    +};
    +
    +struct omap_overlay_manager_info {
    + u32 default_color;
    +
    + enum omap_dss_trans_key_type trans_key_type;
    + u32 trans_key;
    + bool trans_enabled;
    +
    + bool alpha_enabled;
    +};
    +
    +struct omap_overlay_manager {
    + struct kobject kobj;
    + struct list_head list;
    +
    + /* static fields */
    + const char *name;
    + int id;
    + enum omap_overlay_manager_caps caps;
    + int num_overlays;
    + struct omap_overlay **overlays;
    + enum omap_display_type supported_displays;
    +
    + /* dynamic fields */
    + struct omap_dss_device *device;
    + struct omap_overlay_manager_info info;
    +
    + bool device_changed;
    + /* if true, info has been changed but not applied() yet */
    + bool info_dirty;
    +
    + int (*set_device)(struct omap_overlay_manager *mgr,
    + struct omap_dss_device *dssdev);
    + int (*unset_device)(struct omap_overlay_manager *mgr);
    +
    + int (*set_manager_info)(struct omap_overlay_manager *mgr,
    + struct omap_overlay_manager_info *info);
    + void (*get_manager_info)(struct omap_overlay_manager *mgr,
    + struct omap_overlay_manager_info *info);
    +
    + int (*apply)(struct omap_overlay_manager *mgr);
    + int (*wait_for_go)(struct omap_overlay_manager *mgr);
    +};
    +
    +struct omap_dss_device {
    + struct device dev;
    +
    + enum omap_display_type type;
    +
    + union {
    + struct {
    + u8 data_lines;
    + } dpi;
    +
    + struct {
    + u8 channel;
    + u8 data_lines;
    + } rfbi;
    +
    + struct {
    + u8 datapairs;
    + } sdi;
    +
    + struct {
    + u8 clk_lane;
    + u8 clk_pol;
    + u8 data1_lane;
    + u8 data1_pol;
    + u8 data2_lane;
    + u8 data2_pol;
    +
    + struct {
    + u16 regn;
    + u16 regm;
    + u16 regm3;
    + u16 regm4;
    +
    + u16 lp_clk_div;
    +
    + u16 lck_div;
    + u16 pck_div;
    + } div;
    +
    + bool ext_te;
    + u8 ext_te_gpio;
    + } dsi;
    +
    + struct {
    + enum omap_dss_venc_type type;
    + bool invert_polarity;
    + } venc;
    + } phy;
    +
    + 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_panel_config config;
    +
    + u8 recommended_bpp;
    +
    + struct omap_dss_device *ctrl;
    + } panel;
    +
    + struct {
    + u8 pixel_size;
    + struct rfbi_timings rfbi_timings;
    + struct omap_dss_device *panel;
    + } ctrl;
    +
    + int reset_gpio;
    +
    + int max_backlight_level;
    +
    + const char *name;
    +
    + /* used to match device to driver */
    + const char *driver_name;
    +
    + void *data;
    +
    + struct omap_dss_driver *driver;
    +
    + /* helper variable for driver suspend/resume */
    + bool activate_after_resume;
    +
    + enum omap_display_caps caps;
    +
    + struct omap_overlay_manager *manager;
    +
    + enum omap_dss_display_state state;
    +
    + int (*enable)(struct omap_dss_device *dssdev);
    + void (*disable)(struct omap_dss_device *dssdev);
    +
    + int (*suspend)(struct omap_dss_device *dssdev);
    + int (*resume)(struct omap_dss_device *dssdev);
    +
    + void (*get_resolution)(struct omap_dss_device *dssdev,
    + u16 *xres, u16 *yres);
    + int (*get_recommended_bpp)(struct omap_dss_device *dssdev);
    +
    + int (*check_timings)(struct omap_dss_device *dssdev,
    + struct omap_video_timings *timings);
    + void (*set_timings)(struct omap_dss_device *dssdev,
    + struct omap_video_timings *timings);
    + void (*get_timings)(struct omap_dss_device *dssdev,
    + struct omap_video_timings *timings);
    + int (*update)(struct omap_dss_device *dssdev,
    + u16 x, u16 y, u16 w, u16 h);
    + int (*sync)(struct omap_dss_device *dssdev);
    + int (*wait_vsync)(struct omap_dss_device *dssdev);
    +
    + int (*set_update_mode)(struct omap_dss_device *dssdev,
    + enum omap_dss_update_mode);
    + enum omap_dss_update_mode (*get_update_mode)
    + (struct omap_dss_device *dssdev);
    +
    + int (*enable_te)(struct omap_dss_device *dssdev, bool enable);
    + int (*get_te)(struct omap_dss_device *dssdev);
    +
    + u8 (*get_rotate)(struct omap_dss_device *dssdev);
    + int (*set_rotate)(struct omap_dss_device *dssdev, u8 rotate);
    +
    + bool (*get_mirror)(struct omap_dss_device *dssdev);
    + int (*set_mirror)(struct omap_dss_device *dssdev, bool enable);
    +
    + int (*run_test)(struct omap_dss_device *dssdev, int test);
    + int (*memory_read)(struct omap_dss_device *dssdev,
    + void *buf, size_t size,
    + u16 x, u16 y, u16 w, u16 h);
    +
    + int (*set_wss)(struct omap_dss_device *dssdev, u32 wss);
    + u32 (*get_wss)(struct omap_dss_device *dssdev);
    +
    + /* platform specific */
    + int (*platform_enable)(struct omap_dss_device *dssdev);
    + void (*platform_disable)(struct omap_dss_device *dssdev);
    + int (*set_backlight)(struct omap_dss_device *dssdev, int level);
    + int (*get_backlight)(struct omap_dss_device *dssdev);
    +};
    +
    +struct omap_dss_driver {
    + struct device_driver driver;
    +
    + int (*probe)(struct omap_dss_device *);
    + void (*remove)(struct omap_dss_device *);
    +
    + 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);
    +
    + void (*setup_update)(struct omap_dss_device *dssdev,
    + u16 x, u16 y, u16 w, u16 h);
    +
    + int (*enable_te)(struct omap_dss_device *dssdev, bool enable);
    + int (*wait_for_te)(struct omap_dss_device *dssdev);
    +
    + u8 (*get_rotate)(struct omap_dss_device *dssdev);
    + int (*set_rotate)(struct omap_dss_device *dssdev, u8 rotate);
    +
    + bool (*get_mirror)(struct omap_dss_device *dssdev);
    + int (*set_mirror)(struct omap_dss_device *dssdev, bool enable);
    +
    + int (*memory_read)(struct omap_dss_device *dssdev,
    + void *buf, size_t size,
    + u16 x, u16 y, u16 w, u16 h);
    +};
    +
    +int omap_dss_register_driver(struct omap_dss_driver *);
    +void omap_dss_unregister_driver(struct omap_dss_driver *);
    +
    +int omap_dss_register_device(struct omap_dss_device *);
    +void omap_dss_unregister_device(struct omap_dss_device *);
    +
    +void omap_dss_get_device(struct omap_dss_device *dssdev);
    +void omap_dss_put_device(struct omap_dss_device *dssdev);
    +#define for_each_dss_dev(d) while ((d = omap_dss_get_next_device(d)) != NULL)
    +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));
    +
    +int omap_dss_start_device(struct omap_dss_device *dssdev);
    +void omap_dss_stop_device(struct omap_dss_device *dssdev);
    +
    +int omap_dss_get_num_overlay_managers(void);
    +struct omap_overlay_manager *omap_dss_get_overlay_manager(int num);
    +
    +int omap_dss_get_num_overlays(void);
    +struct omap_overlay *omap_dss_get_overlay(int num);
    +
    +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);
    +
    +#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)
    +
    +#endif
    diff --git a/drivers/video/omap2/Kconfig b/drivers/video/omap2/Kconfig
    index ac8b650..55b4c42 100644
    --- a/drivers/video/omap2/Kconfig
    +++ b/drivers/video/omap2/Kconfig
    @@ -3,3 +3,5 @@ config OMAP2_VRAM

    config OMAP2_VRFB
    bool
    +
    +source "drivers/video/omap2/dss/Kconfig"
    diff --git a/drivers/video/omap2/Makefile b/drivers/video/omap2/Makefile
    index aa3751b..ee0644f 100644
    --- a/drivers/video/omap2/Makefile
    +++ b/drivers/video/omap2/Makefile
    @@ -1,2 +1,4 @@
    obj-$(CONFIG_OMAP2_VRAM) += vram.o
    obj-$(CONFIG_OMAP2_VRFB) += vrfb.o
    +
    +obj-y += dss/
    diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig
    new file mode 100644
    index 0000000..71d8dec
    --- /dev/null
    +++ b/drivers/video/omap2/dss/Kconfig
    @@ -0,0 +1,89 @@
    +menuconfig OMAP2_DSS
    + tristate "OMAP2/3 Display Subsystem support (EXPERIMENTAL)"
    + depends on ARCH_OMAP2 || ARCH_OMAP3
    + help
    + OMAP2/3 Display Subsystem support.
    +
    +if OMAP2_DSS
    +
    +config OMAP2_VRAM_SIZE
    + int "VRAM size (MB)"
    + range 0 32
    + default 0
    + 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.
    +
    + 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
    + help
    + This enables debug messages. You need to enable printing
    + with 'debug' module parameter.
    +
    +config OMAP2_DSS_RFBI
    + bool "RFBI support"
    + default n
    + help
    + MIPI DBI, or RFBI (Remote Framebuffer Interface), support.
    +
    +config OMAP2_DSS_VENC
    + bool "VENC support"
    + default y
    + help
    + OMAP Video Encoder support.
    +
    +config OMAP2_DSS_SDI
    + bool "SDI support"
    + depends on ARCH_OMAP3
    + default n
    + help
    + SDI (Serial Display Interface) support.
    +
    +config OMAP2_DSS_DSI
    + bool "DSI support"
    + depends on ARCH_OMAP3
    + default n
    + help
    + MIPI DSI support.
    +
    +config OMAP2_DSS_USE_DSI_PLL
    + bool "Use DSI PLL for PCLK (EXPERIMENTAL)"
    + default n
    + depends on OMAP2_DSS_DSI
    + help
    + Use DSI PLL to generate pixel clock. Currently only for DPI output.
    + DSI PLL can be used to generate higher and more precise pixel clocks.
    +
    +config OMAP2_DSS_FAKE_VSYNC
    + bool "Fake VSYNC irq from manual update displays"
    + default n
    + help
    + If this is selected, DSI will generate a fake DISPC VSYNC interrupt
    + when DSI has sent a frame. This is only needed with DSI or RFBI
    + displays using manual mode, and you want VSYNC to, for example,
    + time animation.
    +
    +config OMAP2_DSS_MIN_FCK_PER_PCK
    + int "Minimum FCK/PCK ratio (for scaling)"
    + range 0 32
    + default 0
    + help
    + This can be used to adjust the minimum FCK/PCK ratio.
    +
    + With this you can make sure that DISPC FCK is at least
    + n x PCK. Video plane scaling requires higher FCK than
    + normally.
    +
    + If this is set to 0, there's no extra constraint on the
    + DISPC FCK. However, the FCK will at minimum be
    + 2xPCK (if active matrix) or 3xPCK (if passive matrix).
    +
    + Max FCK is 173MHz, so this doesn't work if your PCK
    + is very high.
    +
    +endif
    diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile
    new file mode 100644
    index 0000000..980c72c
    --- /dev/null
    +++ b/drivers/video/omap2/dss/Makefile
    @@ -0,0 +1,6 @@
    +obj-$(CONFIG_OMAP2_DSS) += omapdss.o
    +omapdss-y := core.o dss.o dispc.o dpi.o display.o manager.o overlay.o
    +omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
    +omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
    +omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
    +omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
    diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
    new file mode 100644
    index 0000000..29497a0
    --- /dev/null
    +++ b/drivers/video/omap2/dss/core.c
    @@ -0,0 +1,919 @@
    +/*
    + * linux/drivers/video/omap2/dss/core.c
    + *
    + * 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 "CORE"
    +
    +#include <linux/kernel.h>
    +#include <linux/module.h>
    +#include <linux/clk.h>
    +#include <linux/err.h>
    +#include <linux/platform_device.h>
    +#include <linux/seq_file.h>
    +#include <linux/debugfs.h>
    +#include <linux/io.h>
    +#include <linux/device.h>
    +
    +#include <plat/display.h>
    +#include <plat/clock.h>
    +
    +#include "dss.h"
    +
    +static struct {
    + struct platform_device *pdev;
    + int ctx_id;
    +
    + struct clk *dss_ick;
    + struct clk *dss1_fck;
    + struct clk *dss2_fck;
    + struct clk *dss_54m_fck;
    + struct clk *dss_96m_fck;
    + unsigned num_clks_enabled;
    +} core;
    +
    +static void dss_clk_enable_all_no_ctx(void);
    +static void dss_clk_disable_all_no_ctx(void);
    +static void dss_clk_enable_no_ctx(enum dss_clock clks);
    +static void dss_clk_disable_no_ctx(enum dss_clock clks);
    +
    +static char *def_disp_name;
    +module_param_named(def_disp, def_disp_name, charp, 0);
    +MODULE_PARM_DESC(def_disp_name, "default display name");
    +
    +#ifdef DEBUG
    +unsigned int dss_debug;
    +module_param_named(debug, dss_debug, bool, 0644);
    +#endif
    +
    +/* CONTEXT */
    +static int dss_get_ctx_id(void)
    +{
    + struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
    + int r;
    +
    + if (!pdata->get_last_off_on_transaction_id)
    + return 0;
    + r = pdata->get_last_off_on_transaction_id(&core.pdev->dev);
    + if (r < 0) {
    + dev_err(&core.pdev->dev, "getting transaction ID failed, "
    + "will force context restore\n");
    + r = -1;
    + }
    + return r;
    +}
    +
    +int dss_need_ctx_restore(void)
    +{
    + int id = dss_get_ctx_id();
    +
    + if (id < 0 || id != core.ctx_id) {
    + DSSDBG("ctx id %d -> id %d\n",
    + core.ctx_id, id);
    + core.ctx_id = id;
    + return 1;
    + } else {
    + return 0;
    + }
    +}
    +
    +static void save_all_ctx(void)
    +{
    + DSSDBG("save context\n");
    +
    + dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
    +
    + dss_save_context();
    + dispc_save_context();
    +#ifdef CONFIG_OMAP2_DSS_DSI
    + dsi_save_context();
    +#endif
    +
    + dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
    +}
    +
    +static void restore_all_ctx(void)
    +{
    + DSSDBG("restore context\n");
    +
    + dss_clk_enable_all_no_ctx();
    +
    + dss_restore_context();
    + dispc_restore_context();
    +#ifdef CONFIG_OMAP2_DSS_DSI
    + dsi_restore_context();
    +#endif
    +
    + dss_clk_disable_all_no_ctx();
    +}
    +
    +/* CLOCKS */
    +static void core_dump_clocks(struct seq_file *s)
    +{
    + int i;
    + struct clk *clocks[5] = {
    + core.dss_ick,
    + core.dss1_fck,
    + core.dss2_fck,
    + core.dss_54m_fck,
    + core.dss_96m_fck
    + };
    +
    + seq_printf(s, "- CORE -\n");
    +
    + seq_printf(s, "internal clk count\t\t%u\n", core.num_clks_enabled);
    +
    + for (i = 0; i < 5; i++) {
    + if (!clocks[i])
    + continue;
    + seq_printf(s, "%-15s\t%lu\t%d\n",
    + clocks[i]->name,
    + clk_get_rate(clocks[i]),
    + clocks[i]->usecount);
    + }
    +}
    +
    +static int dss_get_clock(struct clk **clock, const char *clk_name)
    +{
    + struct clk *clk;
    +
    + clk = clk_get(&core.pdev->dev, clk_name);
    +
    + if (IS_ERR(clk)) {
    + DSSERR("can't get clock %s", clk_name);
    + return PTR_ERR(clk);
    + }
    +
    + *clock = clk;
    +
    + DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk));
    +
    + return 0;
    +}
    +
    +static int dss_get_clocks(void)
    +{
    + int r;
    +
    + core.dss_ick = NULL;
    + core.dss1_fck = NULL;
    + core.dss2_fck = NULL;
    + core.dss_54m_fck = NULL;
    + core.dss_96m_fck = NULL;
    +
    + r = dss_get_clock(&core.dss_ick, "ick");
    + if (r)
    + goto err;
    +
    + r = dss_get_clock(&core.dss1_fck, "dss1_fck");
    + if (r)
    + goto err;
    +
    + r = dss_get_clock(&core.dss2_fck, "dss2_fck");
    + if (r)
    + goto err;
    +
    + r = dss_get_clock(&core.dss_54m_fck, "tv_fck");
    + if (r)
    + goto err;
    +
    + r = dss_get_clock(&core.dss_96m_fck, "video_fck");
    + if (r)
    + goto err;
    +
    + return 0;
    +
    +err:
    + if (core.dss_ick)
    + clk_put(core.dss_ick);
    + if (core.dss1_fck)
    + clk_put(core.dss1_fck);
    + if (core.dss2_fck)
    + clk_put(core.dss2_fck);
    + if (core.dss_54m_fck)
    + clk_put(core.dss_54m_fck);
    + if (core.dss_96m_fck)
    + clk_put(core.dss_96m_fck);
    +
    + return r;
    +}
    +
    +static void dss_put_clocks(void)
    +{
    + if (core.dss_96m_fck)
    + clk_put(core.dss_96m_fck);
    + clk_put(core.dss_54m_fck);
    + clk_put(core.dss1_fck);
    + clk_put(core.dss2_fck);
    + clk_put(core.dss_ick);
    +}
    +
    +unsigned long dss_clk_get_rate(enum dss_clock clk)
    +{
    + switch (clk) {
    + case DSS_CLK_ICK:
    + return clk_get_rate(core.dss_ick);
    + case DSS_CLK_FCK1:
    + return clk_get_rate(core.dss1_fck);
    + case DSS_CLK_FCK2:
    + return clk_get_rate(core.dss2_fck);
    + case DSS_CLK_54M:
    + return clk_get_rate(core.dss_54m_fck);
    + case DSS_CLK_96M:
    + return clk_get_rate(core.dss_96m_fck);
    + }
    +
    + BUG();
    + return 0;
    +}
    +
    +static unsigned count_clk_bits(enum dss_clock clks)
    +{
    + unsigned num_clks = 0;
    +
    + if (clks & DSS_CLK_ICK)
    + ++num_clks;
    + if (clks & DSS_CLK_FCK1)
    + ++num_clks;
    + if (clks & DSS_CLK_FCK2)
    + ++num_clks;
    + if (clks & DSS_CLK_54M)
    + ++num_clks;
    + if (clks & DSS_CLK_96M)
    + ++num_clks;
    +
    + return num_clks;
    +}
    +
    +static void dss_clk_enable_no_ctx(enum dss_clock clks)
    +{
    + unsigned num_clks = count_clk_bits(clks);
    +
    + if (clks & DSS_CLK_ICK)
    + clk_enable(core.dss_ick);
    + if (clks & DSS_CLK_FCK1)
    + clk_enable(core.dss1_fck);
    + if (clks & DSS_CLK_FCK2)
    + clk_enable(core.dss2_fck);
    + if (clks & DSS_CLK_54M)
    + clk_enable(core.dss_54m_fck);
    + if (clks & DSS_CLK_96M)
    + clk_enable(core.dss_96m_fck);
    +
    + core.num_clks_enabled += num_clks;
    +}
    +
    +void dss_clk_enable(enum dss_clock clks)
    +{
    + dss_clk_enable_no_ctx(clks);
    +
    + if (cpu_is_omap34xx() && dss_need_ctx_restore())
    + restore_all_ctx();
    +}
    +
    +static void dss_clk_disable_no_ctx(enum dss_clock clks)
    +{
    + unsigned num_clks = count_clk_bits(clks);
    +
    + if (clks & DSS_CLK_ICK)
    + clk_disable(core.dss_ick);
    + if (clks & DSS_CLK_FCK1)
    + clk_disable(core.dss1_fck);
    + if (clks & DSS_CLK_FCK2)
    + clk_disable(core.dss2_fck);
    + if (clks & DSS_CLK_54M)
    + clk_disable(core.dss_54m_fck);
    + if (clks & DSS_CLK_96M)
    + clk_disable(core.dss_96m_fck);
    +
    + core.num_clks_enabled -= num_clks;
    +}
    +
    +void dss_clk_disable(enum dss_clock clks)
    +{
    + if (cpu_is_omap34xx()) {
    + unsigned num_clks = count_clk_bits(clks);
    +
    + BUG_ON(core.num_clks_enabled < num_clks);
    +
    + if (core.num_clks_enabled == num_clks)
    + save_all_ctx();
    + }
    +
    + dss_clk_disable_no_ctx(clks);
    +}
    +
    +static void dss_clk_enable_all_no_ctx(void)
    +{
    + enum dss_clock clks;
    +
    + clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
    + if (cpu_is_omap34xx())
    + clks |= DSS_CLK_96M;
    + dss_clk_enable_no_ctx(clks);
    +}
    +
    +static void dss_clk_disable_all_no_ctx(void)
    +{
    + enum dss_clock clks;
    +
    + clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
    + if (cpu_is_omap34xx())
    + clks |= DSS_CLK_96M;
    + dss_clk_disable_no_ctx(clks);
    +}
    +
    +static void dss_clk_disable_all(void)
    +{
    + enum dss_clock clks;
    +
    + clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
    + if (cpu_is_omap34xx())
    + clks |= DSS_CLK_96M;
    + dss_clk_disable(clks);
    +}
    +
    +/* DEBUGFS */
    +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
    +static void dss_debug_dump_clocks(struct seq_file *s)
    +{
    + core_dump_clocks(s);
    + dss_dump_clocks(s);
    + dispc_dump_clocks(s);
    +#ifdef CONFIG_OMAP2_DSS_DSI
    + dsi_dump_clocks(s);
    +#endif
    +}
    +
    +static int dss_debug_show(struct seq_file *s, void *unused)
    +{
    + void (*func)(struct seq_file *) = s->private;
    + func(s);
    + return 0;
    +}
    +
    +static int dss_debug_open(struct inode *inode, struct file *file)
    +{
    + return single_open(file, dss_debug_show, inode->i_private);
    +}
    +
    +static const struct file_operations dss_debug_fops = {
    + .open = dss_debug_open,
    + .read = seq_read,
    + .llseek = seq_lseek,
    + .release = single_release,
    +};
    +
    +static struct dentry *dss_debugfs_dir;
    +
    +static int dss_initialize_debugfs(void)
    +{
    + dss_debugfs_dir = debugfs_create_dir("omapdss", NULL);
    + if (IS_ERR(dss_debugfs_dir)) {
    + int err = PTR_ERR(dss_debugfs_dir);
    + dss_debugfs_dir = NULL;
    + return err;
    + }
    +
    + debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir,
    + &dss_debug_dump_clocks, &dss_debug_fops);
    +
    + debugfs_create_file("dss", S_IRUGO, dss_debugfs_dir,
    + &dss_dump_regs, &dss_debug_fops);
    + debugfs_create_file("dispc", S_IRUGO, dss_debugfs_dir,
    + &dispc_dump_regs, &dss_debug_fops);
    +#ifdef CONFIG_OMAP2_DSS_RFBI
    + debugfs_create_file("rfbi", S_IRUGO, dss_debugfs_dir,
    + &rfbi_dump_regs, &dss_debug_fops);
    +#endif
    +#ifdef CONFIG_OMAP2_DSS_DSI
    + debugfs_create_file("dsi", S_IRUGO, dss_debugfs_dir,
    + &dsi_dump_regs, &dss_debug_fops);
    +#endif
    +#ifdef CONFIG_OMAP2_DSS_VENC
    + debugfs_create_file("venc", S_IRUGO, dss_debugfs_dir,
    + &venc_dump_regs, &dss_debug_fops);
    +#endif
    + return 0;
    +}
    +
    +static void dss_uninitialize_debugfs(void)
    +{
    + if (dss_debugfs_dir)
    + debugfs_remove_recursive(dss_debugfs_dir);
    +}
    +#endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */
    +
    +/* PLATFORM DEVICE */
    +static int omap_dss_probe(struct platform_device *pdev)
    +{
    + struct omap_dss_board_info *pdata = pdev->dev.platform_data;
    + int skip_init = 0;
    + int r;
    + int i;
    +
    + core.pdev = pdev;
    +
    + dss_init_overlay_managers(pdev);
    + dss_init_overlays(pdev);
    +
    + r = dss_get_clocks();
    + if (r)
    + goto fail0;
    +
    + dss_clk_enable_all_no_ctx();
    +
    + core.ctx_id = dss_get_ctx_id();
    + DSSDBG("initial ctx id %u\n", core.ctx_id);
    +
    +#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
    + /* DISPC_CONTROL */
    + if (omap_readl(0x48050440) & 1) /* LCD enabled? */
    + skip_init = 1;
    +#endif
    +
    + r = dss_init(skip_init);
    + if (r) {
    + DSSERR("Failed to initialize DSS\n");
    + goto fail0;
    + }
    +
    +#ifdef CONFIG_OMAP2_DSS_RFBI
    + r = rfbi_init();
    + if (r) {
    + DSSERR("Failed to initialize rfbi\n");
    + goto fail0;
    + }
    +#endif
    +
    + r = dpi_init();
    + if (r) {
    + DSSERR("Failed to initialize dpi\n");
    + goto fail0;
    + }
    +
    + r = dispc_init();
    + if (r) {
    + DSSERR("Failed to initialize dispc\n");
    + goto fail0;
    + }
    +#ifdef CONFIG_OMAP2_DSS_VENC
    + r = venc_init(pdev);
    + if (r) {
    + DSSERR("Failed to initialize venc\n");
    + goto fail0;
    + }
    +#endif
    + if (cpu_is_omap34xx()) {
    +#ifdef CONFIG_OMAP2_DSS_SDI
    + r = sdi_init(skip_init);
    + if (r) {
    + DSSERR("Failed to initialize SDI\n");
    + goto fail0;
    + }
    +#endif
    +#ifdef CONFIG_OMAP2_DSS_DSI
    + r = dsi_init(pdev);
    + if (r) {
    + DSSERR("Failed to initialize DSI\n");
    + goto fail0;
    + }
    +#endif
    + }
    +
    +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
    + r = dss_initialize_debugfs();
    + if (r)
    + goto fail0;
    +#endif
    +
    + for (i = 0; i < pdata->num_devices; ++i) {
    + struct omap_dss_device *dssdev = pdata->devices[i];
    +
    + r = omap_dss_register_device(dssdev);
    + if (r)
    + DSSERR("device reg failed %d\n", i);
    +
    + if (def_disp_name && strcmp(def_disp_name, dssdev->name) == 0)
    + pdata->default_device = dssdev;
    + }
    +
    + dss_clk_disable_all();
    +
    + return 0;
    +
    + /* XXX fail correctly */
    +fail0:
    + return r;
    +}
    +
    +static int omap_dss_remove(struct platform_device *pdev)
    +{
    + struct omap_dss_board_info *pdata = pdev->dev.platform_data;
    + int i;
    + int c;
    +
    +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
    + dss_uninitialize_debugfs();
    +#endif
    +
    +#ifdef CONFIG_OMAP2_DSS_VENC
    + venc_exit();
    +#endif
    + dispc_exit();
    + dpi_exit();
    +#ifdef CONFIG_OMAP2_DSS_RFBI
    + rfbi_exit();
    +#endif
    + if (cpu_is_omap34xx()) {
    +#ifdef CONFIG_OMAP2_DSS_DSI
    + dsi_exit();
    +#endif
    +#ifdef CONFIG_OMAP2_DSS_SDI
    + sdi_exit();
    +#endif
    + }
    +
    + dss_exit();
    +
    + /* these should be removed at some point */
    + c = core.dss_ick->usecount;
    + if (c > 0) {
    + DSSERR("warning: dss_ick usecount %d, disabling\n", c);
    + while (c-- > 0)
    + clk_disable(core.dss_ick);
    + }
    +
    + c = core.dss1_fck->usecount;
    + if (c > 0) {
    + DSSERR("warning: dss1_fck usecount %d, disabling\n", c);
    + while (c-- > 0)
    + clk_disable(core.dss1_fck);
    + }
    +
    + c = core.dss2_fck->usecount;
    + if (c > 0) {
    + DSSERR("warning: dss2_fck usecount %d, disabling\n", c);
    + while (c-- > 0)
    + clk_disable(core.dss2_fck);
    + }
    +
    + c = core.dss_54m_fck->usecount;
    + if (c > 0) {
    + DSSERR("warning: dss_54m_fck usecount %d, disabling\n", c);
    + while (c-- > 0)
    + clk_disable(core.dss_54m_fck);
    + }
    +
    + if (core.dss_96m_fck) {
    + c = core.dss_96m_fck->usecount;
    + if (c > 0) {
    + DSSERR("warning: dss_96m_fck usecount %d, disabling\n",
    + c);
    + while (c-- > 0)
    + clk_disable(core.dss_96m_fck);
    + }
    + }
    +
    + dss_put_clocks();
    +
    + dss_uninit_overlays(pdev);
    + dss_uninit_overlay_managers(pdev);
    +
    + for (i = 0; i < pdata->num_devices; ++i)
    + omap_dss_unregister_device(pdata->devices[i]);
    +
    + return 0;
    +}
    +
    +static void omap_dss_shutdown(struct platform_device *pdev)
    +{
    + DSSDBG("shutdown\n");
    + dss_disable_all_devices();
    +}
    +
    +static int omap_dss_suspend(struct platform_device *pdev, pm_message_t state)
    +{
    + DSSDBG("suspend %d\n", state.event);
    +
    + return dss_suspend_all_devices();
    +}
    +
    +static int omap_dss_resume(struct platform_device *pdev)
    +{
    + DSSDBG("resume\n");
    +
    + return dss_resume_all_devices();
    +}
    +
    +static struct platform_driver omap_dss_driver = {
    + .probe = omap_dss_probe,
    + .remove = omap_dss_remove,
    + .shutdown = omap_dss_shutdown,
    + .suspend = omap_dss_suspend,
    + .resume = omap_dss_resume,
    + .driver = {
    + .name = "omapdss",
    + .owner = THIS_MODULE,
    + },
    +};
    +
    +/* BUS */
    +static int dss_bus_match(struct device *dev, struct device_driver *driver)
    +{
    + struct omap_dss_device *dssdev = to_dss_device(dev);
    +
    + DSSDBG("bus_match. dev %s/%s, drv %s\n",
    + dev_name(dev), dssdev->driver_name, driver->name);
    +
    + return strcmp(dssdev->driver_name, driver->name) == 0;
    +}
    +
    +static ssize_t device_name_show(struct device *dev,
    + struct device_attribute *attr, char *buf)
    +{
    + struct omap_dss_device *dssdev = to_dss_device(dev);
    + return snprintf(buf, PAGE_SIZE, "%s\n",
    + dssdev->name ?
    + dssdev->name : "");
    +}
    +
    +static struct device_attribute default_dev_attrs[] = {
    + __ATTR(name, S_IRUGO, device_name_show, NULL),
    + __ATTR_NULL,
    +};
    +
    +static ssize_t driver_name_show(struct device_driver *drv, char *buf)
    +{
    + struct omap_dss_driver *dssdrv = to_dss_driver(drv);
    + return snprintf(buf, PAGE_SIZE, "%s\n",
    + dssdrv->driver.name ?
    + dssdrv->driver.name : "");
    +}
    +static struct driver_attribute default_drv_attrs[] = {
    + __ATTR(name, S_IRUGO, driver_name_show, NULL),
    + __ATTR_NULL,
    +};
    +
    +static struct bus_type dss_bus_type = {
    + .name = "omapdss",
    + .match = dss_bus_match,
    + .dev_attrs = default_dev_attrs,
    + .drv_attrs = default_drv_attrs,
    +};
    +
    +static void dss_bus_release(struct device *dev)
    +{
    + DSSDBG("bus_release\n");
    +}
    +
    +static struct device dss_bus = {
    + .release = dss_bus_release,
    +};
    +
    +struct bus_type *dss_get_bus(void)
    +{
    + return &dss_bus_type;
    +}
    +
    +/* DRIVER */
    +static int dss_driver_probe(struct device *dev)
    +{
    + int r;
    + struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
    + struct omap_dss_device *dssdev = to_dss_device(dev);
    + struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
    + bool force;
    +
    + DSSDBG("driver_probe: dev %s/%s, drv %s\n",
    + dev_name(dev), dssdev->driver_name,
    + dssdrv->driver.name);
    +
    + dss_init_device(core.pdev, dssdev);
    +
    + /* skip this if the device is behind a ctrl */
    + if (!dssdev->panel.ctrl) {
    + force = pdata->default_device == dssdev;
    + dss_recheck_connections(dssdev, force);
    + }
    +
    + r = dssdrv->probe(dssdev);
    +
    + if (r) {
    + DSSERR("driver probe failed: %d\n", r);
    + return r;
    + }
    +
    + DSSDBG("probe done for device %s\n", dev_name(dev));
    +
    + dssdev->driver = dssdrv;
    +
    + return 0;
    +}
    +
    +static int dss_driver_remove(struct device *dev)
    +{
    + struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
    + struct omap_dss_device *dssdev = to_dss_device(dev);
    +
    + DSSDBG("driver_remove: dev %s/%s\n", dev_name(dev),
    + dssdev->driver_name);
    +
    + dssdrv->remove(dssdev);
    +
    + dss_uninit_device(core.pdev, dssdev);
    +
    + dssdev->driver = NULL;
    +
    + return 0;
    +}
    +
    +int omap_dss_register_driver(struct omap_dss_driver *dssdriver)
    +{
    + dssdriver->driver.bus = &dss_bus_type;
    + dssdriver->driver.probe = dss_driver_probe;
    + dssdriver->driver.remove = dss_driver_remove;
    + return driver_register(&dssdriver->driver);
    +}
    +EXPORT_SYMBOL(omap_dss_register_driver);
    +
    +void omap_dss_unregister_driver(struct omap_dss_driver *dssdriver)
    +{
    + driver_unregister(&dssdriver->driver);
    +}
    +EXPORT_SYMBOL(omap_dss_unregister_driver);
    +
    +/* DEVICE */
    +static void reset_device(struct device *dev, int check)
    +{
    + u8 *dev_p = (u8 *)dev;
    + u8 *dev_end = dev_p + sizeof(*dev);
    + void *saved_pdata;
    +
    + saved_pdata = dev->platform_data;
    + if (check) {
    + /*
    + * Check if there is any other setting than platform_data
    + * in struct device; warn that these will be reset by our
    + * init.
    + */
    + dev->platform_data = NULL;
    + while (dev_p < dev_end) {
    + if (*dev_p) {
    + WARN("%s: struct device fields will be "
    + "discarded\n",
    + __func__);
    + break;
    + }
    + dev_p++;
    + }
    + }
    + memset(dev, 0, sizeof(*dev));
    + dev->platform_data = saved_pdata;
    +}
    +
    +
    +static void omap_dss_dev_release(struct device *dev)
    +{
    + reset_device(dev, 0);
    +}
    +
    +int omap_dss_register_device(struct omap_dss_device *dssdev)
    +{
    + static int dev_num;
    + static int panel_num;
    + int r;
    +
    + WARN_ON(!dssdev->driver_name);
    +
    + reset_device(&dssdev->dev, 1);
    + dssdev->dev.bus = &dss_bus_type;
    + dssdev->dev.parent = &dss_bus;
    + dssdev->dev.release = omap_dss_dev_release;
    + dev_set_name(&dssdev->dev, "display%d", dev_num++);
    + r = device_register(&dssdev->dev);
    + if (r)
    + return r;
    +
    + if (dssdev->ctrl.panel) {
    + struct omap_dss_device *panel = dssdev->ctrl.panel;
    +
    + panel->panel.ctrl = dssdev;
    +
    + reset_device(&panel->dev, 1);
    + panel->dev.bus = &dss_bus_type;
    + panel->dev.parent = &dssdev->dev;
    + panel->dev.release = omap_dss_dev_release;
    + dev_set_name(&panel->dev, "panel%d", panel_num++);
    + r = device_register(&panel->dev);
    + if (r)
    + return r;
    + }
    +
    + return 0;
    +}
    +
    +void omap_dss_unregister_device(struct omap_dss_device *dssdev)
    +{
    + device_unregister(&dssdev->dev);
    +
    + if (dssdev->ctrl.panel) {
    + struct omap_dss_device *panel = dssdev->ctrl.panel;
    + device_unregister(&panel->dev);
    + }
    +}
    +
    +/* BUS */
    +static int omap_dss_bus_register(void)
    +{
    + int r;
    +
    + r = bus_register(&dss_bus_type);
    + if (r) {
    + DSSERR("bus register failed\n");
    + return r;
    + }
    +
    + dev_set_name(&dss_bus, "omapdss");
    + r = device_register(&dss_bus);
    + if (r) {
    + DSSERR("bus driver register failed\n");
    + bus_unregister(&dss_bus_type);
    + return r;
    + }
    +
    + return 0;
    +}
    +
    +/* INIT */
    +
    +#ifdef CONFIG_OMAP2_DSS_MODULE
    +static void omap_dss_bus_unregister(void)
    +{
    + device_unregister(&dss_bus);
    +
    + bus_unregister(&dss_bus_type);
    +}
    +
    +static int __init omap_dss_init(void)
    +{
    + int r;
    +
    + r = omap_dss_bus_register();
    + if (r)
    + return r;
    +
    + r = platform_driver_register(&omap_dss_driver);
    + if (r) {
    + omap_dss_bus_unregister();
    + return r;
    + }
    +
    + return 0;
    +}
    +
    +static void __exit omap_dss_exit(void)
    +{
    + platform_driver_unregister(&omap_dss_driver);
    +
    + omap_dss_bus_unregister();
    +}
    +
    +module_init(omap_dss_init);
    +module_exit(omap_dss_exit);
    +#else
    +static int __init omap_dss_init(void)
    +{
    + return omap_dss_bus_register();
    +}
    +
    +static int __init omap_dss_init2(void)
    +{
    + return platform_driver_register(&omap_dss_driver);
    +}
    +
    +core_initcall(omap_dss_init);
    +device_initcall(omap_dss_init2);
    +#endif
    +
    +MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
    +MODULE_DESCRIPTION("OMAP2/3 Display Subsystem");
    +MODULE_LICENSE("GPL v2");
    +
    diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
    new file mode 100644
    index 0000000..9b05ee6
    --- /dev/null
    +++ b/drivers/video/omap2/dss/dss.c
    @@ -0,0 +1,596 @@
    +/*
    + * linux/drivers/video/omap2/dss/dss.c
    + *
    + * 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 "DSS"
    +
    +#include <linux/kernel.h>
    +#include <linux/io.h>
    +#include <linux/err.h>
    +#include <linux/delay.h>
    +#include <linux/interrupt.h>
    +#include <linux/seq_file.h>
    +#include <linux/clk.h>
    +
    +#include <plat/display.h>
    +#include "dss.h"
    +
    +#define DSS_BASE 0x48050000
    +
    +#define DSS_SZ_REGS SZ_512
    +
    +struct dss_reg {
    + u16 idx;
    +};
    +
    +#define DSS_REG(idx) ((const struct dss_reg) { idx })
    +
    +#define DSS_REVISION DSS_REG(0x0000)
    +#define DSS_SYSCONFIG DSS_REG(0x0010)
    +#define DSS_SYSSTATUS DSS_REG(0x0014)
    +#define DSS_IRQSTATUS DSS_REG(0x0018)
    +#define DSS_CONTROL DSS_REG(0x0040)
    +#define DSS_SDI_CONTROL DSS_REG(0x0044)
    +#define DSS_PLL_CONTROL DSS_REG(0x0048)
    +#define DSS_SDI_STATUS DSS_REG(0x005C)
    +
    +#define REG_GET(idx, start, end) \
    + FLD_GET(dss_read_reg(idx), start, end)
    +
    +#define REG_FLD_MOD(idx, val, start, end) \
    + dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
    +
    +static struct {
    + void __iomem *base;
    +
    + struct clk *dpll4_m4_ck;
    +
    + unsigned long cache_req_pck;
    + unsigned long cache_prate;
    + struct dss_clock_info cache_dss_cinfo;
    + struct dispc_clock_info cache_dispc_cinfo;
    +
    + u32 ctx[DSS_SZ_REGS / sizeof(u32)];
    +} dss;
    +
    +static int _omap_dss_wait_reset(void);
    +
    +static inline void dss_write_reg(const struct dss_reg idx, u32 val)
    +{
    + __raw_writel(val, dss.base + idx.idx);
    +}
    +
    +static inline u32 dss_read_reg(const struct dss_reg idx)
    +{
    + return __raw_readl(dss.base + idx.idx);
    +}
    +
    +#define SR(reg) \
    + dss.ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(DSS_##reg)
    +#define RR(reg) \
    + dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
    +
    +void dss_save_context(void)
    +{
    + if (cpu_is_omap24xx())
    + return;
    +
    + SR(SYSCONFIG);
    + SR(CONTROL);
    +
    +#ifdef CONFIG_OMAP2_DSS_SDI
    + SR(SDI_CONTROL);
    + SR(PLL_CONTROL);
    +#endif
    +}
    +
    +void dss_restore_context(void)
    +{
    + if (_omap_dss_wait_reset())
    + DSSERR("DSS not coming out of reset after sleep\n");
    +
    + RR(SYSCONFIG);
    + RR(CONTROL);
    +
    +#ifdef CONFIG_OMAP2_DSS_SDI
    + RR(SDI_CONTROL);
    + RR(PLL_CONTROL);
    +#endif
    +}
    +
    +#undef SR
    +#undef RR
    +
    +void dss_sdi_init(u8 datapairs)
    +{
    + u32 l;
    +
    + BUG_ON(datapairs > 3 || datapairs < 1);
    +
    + l = dss_read_reg(DSS_SDI_CONTROL);
    + l = FLD_MOD(l, 0xf, 19, 15); /* SDI_PDIV */
    + l = FLD_MOD(l, datapairs-1, 3, 2); /* SDI_PRSEL */
    + l = FLD_MOD(l, 2, 1, 0); /* SDI_BWSEL */
    + dss_write_reg(DSS_SDI_CONTROL, l);
    +
    + l = dss_read_reg(DSS_PLL_CONTROL);
    + l = FLD_MOD(l, 0x7, 25, 22); /* SDI_PLL_FREQSEL */
    + l = FLD_MOD(l, 0xb, 16, 11); /* SDI_PLL_REGN */
    + l = FLD_MOD(l, 0xb4, 10, 1); /* SDI_PLL_REGM */
    + dss_write_reg(DSS_PLL_CONTROL, l);
    +}
    +
    +int dss_sdi_enable(void)
    +{
    + unsigned long timeout;
    +
    + dispc_pck_free_enable(1);
    +
    + /* Reset SDI PLL */
    + REG_FLD_MOD(DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */
    + udelay(1); /* wait 2x PCLK */
    +
    + /* Lock SDI PLL */
    + REG_FLD_MOD(DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */
    +
    + /* Waiting for PLL lock request to complete */
    + timeout = jiffies + msecs_to_jiffies(500);
    + while (dss_read_reg(DSS_SDI_STATUS) & (1 << 6)) {
    + if (time_after_eq(jiffies, timeout)) {
    + DSSERR("PLL lock request timed out\n");
    + goto err1;
    + }
    + }
    +
    + /* Clearing PLL_GO bit */
    + REG_FLD_MOD(DSS_PLL_CONTROL, 0, 28, 28);
    +
    + /* Waiting for PLL to lock */
    + timeout = jiffies + msecs_to_jiffies(500);
    + while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5))) {
    + if (time_after_eq(jiffies, timeout)) {
    + DSSERR("PLL lock timed out\n");
    + goto err1;
    + }
    + }
    +
    + dispc_lcd_enable_signal(1);
    +
    + /* Waiting for SDI reset to complete */
    + timeout = jiffies + msecs_to_jiffies(500);
    + while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 2))) {
    + if (time_after_eq(jiffies, timeout)) {
    + DSSERR("SDI reset timed out\n");
    + goto err2;
    + }
    + }
    +
    + return 0;
    +
    + err2:
    + dispc_lcd_enable_signal(0);
    + err1:
    + /* Reset SDI PLL */
    + REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
    +
    + dispc_pck_free_enable(0);
    +
    + return -ETIMEDOUT;
    +}
    +
    +void dss_sdi_disable(void)
    +{
    + dispc_lcd_enable_signal(0);
    +
    + dispc_pck_free_enable(0);
    +
    + /* Reset SDI PLL */
    + REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
    +}
    +
    +void dss_dump_clocks(struct seq_file *s)
    +{
    + unsigned long dpll4_ck_rate;
    + unsigned long dpll4_m4_ck_rate;
    +
    + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
    +
    + dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
    + dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck);
    +
    + seq_printf(s, "- DSS -\n");
    +
    + seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
    +
    + seq_printf(s, "dss1_alwon_fclk = %lu / %lu * 2 = %lu\n",
    + dpll4_ck_rate,
    + dpll4_ck_rate / dpll4_m4_ck_rate,
    + dss_clk_get_rate(DSS_CLK_FCK1));
    +
    + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
    +}
    +
    +void dss_dump_regs(struct seq_file *s)
    +{
    +#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
    +
    + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
    +
    + DUMPREG(DSS_REVISION);
    + DUMPREG(DSS_SYSCONFIG);
    + DUMPREG(DSS_SYSSTATUS);
    + DUMPREG(DSS_IRQSTATUS);
    + DUMPREG(DSS_CONTROL);
    + DUMPREG(DSS_SDI_CONTROL);
    + DUMPREG(DSS_PLL_CONTROL);
    + DUMPREG(DSS_SDI_STATUS);
    +
    + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
    +#undef DUMPREG
    +}
    +
    +void dss_select_clk_source(bool dsi, bool dispc)
    +{
    + u32 r;
    + r = dss_read_reg(DSS_CONTROL);
    + r = FLD_MOD(r, dsi, 1, 1); /* DSI_CLK_SWITCH */
    + r = FLD_MOD(r, dispc, 0, 0); /* DISPC_CLK_SWITCH */
    + dss_write_reg(DSS_CONTROL, r);
    +}
    +
    +int dss_get_dsi_clk_source(void)
    +{
    + return FLD_GET(dss_read_reg(DSS_CONTROL), 1, 1);
    +}
    +
    +int dss_get_dispc_clk_source(void)
    +{
    + return FLD_GET(dss_read_reg(DSS_CONTROL), 0, 0);
    +}
    +
    +/* calculate clock rates using dividers in cinfo */
    +int dss_calc_clock_rates(struct dss_clock_info *cinfo)
    +{
    + unsigned long prate;
    +
    + if (cinfo->fck_div > 16 || cinfo->fck_div == 0)
    + return -EINVAL;
    +
    + prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
    +
    + cinfo->fck = prate / cinfo->fck_div;
    +
    + return 0;
    +}
    +
    +int dss_set_clock_div(struct dss_clock_info *cinfo)
    +{
    + unsigned long prate;
    + int r;
    +
    + if (cpu_is_omap34xx()) {
    + prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
    + DSSDBG("dpll4_m4 = %ld\n", prate);
    +
    + r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div);
    + if (r)
    + return r;
    + }
    +
    + DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div);
    +
    + return 0;
    +}
    +
    +int dss_get_clock_div(struct dss_clock_info *cinfo)
    +{
    + cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK1);
    +
    + if (cpu_is_omap34xx()) {
    + unsigned long prate;
    + prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
    + cinfo->fck_div = prate / (cinfo->fck / 2);
    + } else {
    + cinfo->fck_div = 0;
    + }
    +
    + return 0;
    +}
    +
    +unsigned long dss_get_dpll4_rate(void)
    +{
    + if (cpu_is_omap34xx())
    + return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
    + else
    + return 0;
    +}
    +
    +int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
    + struct dss_clock_info *dss_cinfo,
    + struct dispc_clock_info *dispc_cinfo)
    +{
    + unsigned long prate;
    + struct dss_clock_info best_dss;
    + struct dispc_clock_info best_dispc;
    +
    + unsigned long fck;
    +
    + u16 fck_div;
    +
    + int match = 0;
    + int min_fck_per_pck;
    +
    + prate = dss_get_dpll4_rate();
    +
    + fck = dss_clk_get_rate(DSS_CLK_FCK1);
    + if (req_pck == dss.cache_req_pck &&
    + ((cpu_is_omap34xx() && prate == dss.cache_prate) ||
    + dss.cache_dss_cinfo.fck == fck)) {
    + DSSDBG("dispc clock info found from cache.\n");
    + *dss_cinfo = dss.cache_dss_cinfo;
    + *dispc_cinfo = dss.cache_dispc_cinfo;
    + return 0;
    + }
    +
    + min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
    +
    + if (min_fck_per_pck &&
    + req_pck * min_fck_per_pck > DISPC_MAX_FCK) {
    + DSSERR("Requested pixel clock not possible with the current "
    + "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
    + "the constraint off.\n");
    + min_fck_per_pck = 0;
    + }
    +
    +retry:
    + memset(&best_dss, 0, sizeof(best_dss));
    + memset(&best_dispc, 0, sizeof(best_dispc));
    +
    + if (cpu_is_omap24xx()) {
    + struct dispc_clock_info cur_dispc;
    + /* XXX can we change the clock on omap2? */
    + fck = dss_clk_get_rate(DSS_CLK_FCK1);
    + fck_div = 1;
    +
    + dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
    + match = 1;
    +
    + best_dss.fck = fck;
    + best_dss.fck_div = fck_div;
    +
    + best_dispc = cur_dispc;
    +
    + goto found;
    + } else if (cpu_is_omap34xx()) {
    + for (fck_div = 16; fck_div > 0; --fck_div) {
    + struct dispc_clock_info cur_dispc;
    +
    + fck = prate / fck_div * 2;
    +
    + if (fck > DISPC_MAX_FCK)
    + continue;
    +
    + if (min_fck_per_pck &&
    + fck < req_pck * min_fck_per_pck)
    + continue;
    +
    + match = 1;
    +
    + dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
    +
    + if (abs(cur_dispc.pck - req_pck) <
    + abs(best_dispc.pck - req_pck)) {
    +
    + best_dss.fck = fck;
    + best_dss.fck_div = fck_div;
    +
    + best_dispc = cur_dispc;
    +
    + if (cur_dispc.pck == req_pck)
    + goto found;
    + }
    + }
    + } else {
    + BUG();
    + }
    +
    +found:
    + if (!match) {
    + if (min_fck_per_pck) {
    + DSSERR("Could not find suitable clock settings.\n"
    + "Turning FCK/PCK constraint off and"
    + "trying again.\n");
    + min_fck_per_pck = 0;
    + goto retry;
    + }
    +
    + DSSERR("Could not find suitable clock settings.\n");
    +
    + return -EINVAL;
    + }
    +
    + if (dss_cinfo)
    + *dss_cinfo = best_dss;
    + if (dispc_cinfo)
    + *dispc_cinfo = best_dispc;
    +
    + dss.cache_req_pck = req_pck;
    + dss.cache_prate = prate;
    + dss.cache_dss_cinfo = best_dss;
    + dss.cache_dispc_cinfo = best_dispc;
    +
    + return 0;
    +}
    +
    +
    +
    +static irqreturn_t dss_irq_handler_omap2(int irq, void *arg)
    +{
    + dispc_irq_handler();
    +
    + return IRQ_HANDLED;
    +}
    +
    +static irqreturn_t dss_irq_handler_omap3(int irq, void *arg)
    +{
    + u32 irqstatus;
    +
    + irqstatus = dss_read_reg(DSS_IRQSTATUS);
    +
    + if (irqstatus & (1<<0)) /* DISPC_IRQ */
    + dispc_irq_handler();
    +#ifdef CONFIG_OMAP2_DSS_DSI
    + if (irqstatus & (1<<1)) /* DSI_IRQ */
    + dsi_irq_handler();
    +#endif
    +
    + return IRQ_HANDLED;
    +}
    +
    +static int _omap_dss_wait_reset(void)
    +{
    + unsigned timeout = 1000;
    +
    + while (REG_GET(DSS_SYSSTATUS, 0, 0) == 0) {
    + udelay(1);
    + if (!--timeout) {
    + DSSERR("soft reset failed\n");
    + return -ENODEV;
    + }
    + }
    +
    + return 0;
    +}
    +
    +static int _omap_dss_reset(void)
    +{
    + /* Soft reset */
    + REG_FLD_MOD(DSS_SYSCONFIG, 1, 1, 1);
    + return _omap_dss_wait_reset();
    +}
    +
    +void dss_set_venc_output(enum omap_dss_venc_type type)
    +{
    + int l = 0;
    +
    + if (type == OMAP_DSS_VENC_TYPE_COMPOSITE)
    + l = 0;
    + else if (type == OMAP_DSS_VENC_TYPE_SVIDEO)
    + l = 1;
    + else
    + BUG();
    +
    + /* venc out selection. 0 = comp, 1 = svideo */
    + REG_FLD_MOD(DSS_CONTROL, l, 6, 6);
    +}
    +
    +void dss_set_dac_pwrdn_bgz(bool enable)
    +{
    + REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
    +}
    +
    +int dss_init(bool skip_init)
    +{
    + int r;
    + u32 rev;
    +
    + dss.base = ioremap(DSS_BASE, DSS_SZ_REGS);
    + if (!dss.base) {
    + DSSERR("can't ioremap DSS\n");
    + r = -ENOMEM;
    + goto fail0;
    + }
    +
    + if (!skip_init) {
    + /* disable LCD and DIGIT output. This seems to fix the synclost
    + * problem that we get, if the bootloader starts the DSS and
    + * the kernel resets it */
    + omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
    +
    + /* We need to wait here a bit, otherwise we sometimes start to
    + * get synclost errors, and after that only power cycle will
    + * restore DSS functionality. I have no idea why this happens.
    + * And we have to wait _before_ resetting the DSS, but after
    + * enabling clocks.
    + */
    + msleep(50);
    +
    + _omap_dss_reset();
    + }
    +
    + /* autoidle */
    + REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0);
    +
    + /* Select DPLL */
    + REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
    +
    +#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 */
    + REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */
    +#endif
    +
    + r = request_irq(INT_24XX_DSS_IRQ,
    + cpu_is_omap24xx()
    + ? dss_irq_handler_omap2
    + : dss_irq_handler_omap3,
    + 0, "OMAP DSS", NULL);
    +
    + if (r < 0) {
    + DSSERR("omap2 dss: request_irq failed\n");
    + goto fail1;
    + }
    +
    + if (cpu_is_omap34xx()) {
    + dss.dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck");
    + if (IS_ERR(dss.dpll4_m4_ck)) {
    + DSSERR("Failed to get dpll4_m4_ck\n");
    + r = PTR_ERR(dss.dpll4_m4_ck);
    + goto fail2;
    + }
    + }
    +
    + dss_save_context();
    +
    + rev = dss_read_reg(DSS_REVISION);
    + printk(KERN_INFO "OMAP DSS rev %d.%d\n",
    + FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
    +
    + return 0;
    +
    +fail2:
    + free_irq(INT_24XX_DSS_IRQ, NULL);
    +fail1:
    + iounmap(dss.base);
    +fail0:
    + return r;
    +}
    +
    +void dss_exit(void)
    +{
    + if (cpu_is_omap34xx())
    + clk_put(dss.dpll4_m4_ck);
    +
    + free_irq(INT_24XX_DSS_IRQ, NULL);
    +
    + iounmap(dss.base);
    +}
    +
    diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
    new file mode 100644
    index 0000000..8da5ac4
    --- /dev/null
    +++ b/drivers/video/omap2/dss/dss.h
    @@ -0,0 +1,370 @@
    +/*
    + * linux/drivers/video/omap2/dss/dss.h
    + *
    + * 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/>.
    + */
    +
    +#ifndef __OMAP2_DSS_H
    +#define __OMAP2_DSS_H
    +
    +#ifdef CONFIG_OMAP2_DSS_DEBUG_SUPPORT
    +#define DEBUG
    +#endif
    +
    +#ifdef DEBUG
    +extern unsigned int 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__)
    +#endif
    +
    +#ifdef DSS_SUBSYS_NAME
    +#define DSSDBGF(format, ...) \
    + if (dss_debug) \
    + printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME \
    + ": %s(" format ")\n", \
    + __func__, \
    + ## __VA_ARGS__)
    +#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, ...)
    +#endif
    +
    +
    +#ifdef DSS_SUBSYS_NAME
    +#define DSSERR(format, ...) \
    + printk(KERN_ERR "omapdss " DSS_SUBSYS_NAME " error: " format, \
    + ## __VA_ARGS__)
    +#else
    +#define DSSERR(format, ...) \
    + printk(KERN_ERR "omapdss error: " format, ## __VA_ARGS__)
    +#endif
    +
    +#ifdef DSS_SUBSYS_NAME
    +#define DSSINFO(format, ...) \
    + printk(KERN_INFO "omapdss " DSS_SUBSYS_NAME ": " format, \
    + ## __VA_ARGS__)
    +#else
    +#define DSSINFO(format, ...) \
    + printk(KERN_INFO "omapdss: " format, ## __VA_ARGS__)
    +#endif
    +
    +#ifdef DSS_SUBSYS_NAME
    +#define DSSWARN(format, ...) \
    + printk(KERN_WARNING "omapdss " DSS_SUBSYS_NAME ": " format, \
    + ## __VA_ARGS__)
    +#else
    +#define DSSWARN(format, ...) \
    + printk(KERN_WARNING "omapdss: " format, ## __VA_ARGS__)
    +#endif
    +
    +/* OMAP TRM gives bitfields as start:end, where start is the higher bit
    + number. For example 7:0 */
    +#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
    +#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
    +#define FLD_GET(val, start, end) (((val) & FLD_MASK(start, end)) >> (end))
    +#define FLD_MOD(orig, val, start, end) \
    + (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
    +
    +#define DISPC_MAX_FCK 173000000
    +
    +enum omap_burst_size {
    + OMAP_DSS_BURST_4x32 = 0,
    + OMAP_DSS_BURST_8x32 = 1,
    + OMAP_DSS_BURST_16x32 = 2,
    +};
    +
    +enum omap_parallel_interface_mode {
    + OMAP_DSS_PARALLELMODE_BYPASS, /* MIPI DPI */
    + OMAP_DSS_PARALLELMODE_RFBI, /* MIPI DBI */
    + OMAP_DSS_PARALLELMODE_DSI,
    +};
    +
    +enum dss_clock {
    + DSS_CLK_ICK = 1 << 0,
    + DSS_CLK_FCK1 = 1 << 1,
    + DSS_CLK_FCK2 = 1 << 2,
    + DSS_CLK_54M = 1 << 3,
    + DSS_CLK_96M = 1 << 4,
    +};
    +
    +struct dss_clock_info {
    + /* rates that we get with dividers below */
    + unsigned long fck;
    +
    + /* dividers */
    + u16 fck_div;
    +};
    +
    +struct dispc_clock_info {
    + /* rates that we get with dividers below */
    + unsigned long lck;
    + unsigned long pck;
    +
    + /* dividers */
    + u16 lck_div;
    + u16 pck_div;
    +};
    +
    +struct dsi_clock_info {
    + /* rates that we get with dividers below */
    + unsigned long fint;
    + unsigned long clkin4ddr;
    + unsigned long clkin;
    + unsigned long dsi1_pll_fclk;
    + unsigned long dsi2_pll_fclk;
    +
    + unsigned long lp_clk;
    +
    + /* dividers */
    + u16 regn;
    + u16 regm;
    + u16 regm3;
    + u16 regm4;
    +
    + u16 lp_clk_div;
    +
    + u8 highfreq;
    + bool use_dss2_fck;
    +};
    +
    +struct seq_file;
    +struct platform_device;
    +
    +/* core */
    +void dss_clk_enable(enum dss_clock clks);
    +void dss_clk_disable(enum dss_clock clks);
    +unsigned long dss_clk_get_rate(enum dss_clock clk);
    +int dss_need_ctx_restore(void);
    +void dss_dump_clocks(struct seq_file *s);
    +struct bus_type *dss_get_bus(void);
    +
    +/* display */
    +int dss_suspend_all_devices(void);
    +int dss_resume_all_devices(void);
    +void dss_disable_all_devices(void);
    +
    +void dss_init_device(struct platform_device *pdev,
    + struct omap_dss_device *dssdev);
    +void dss_uninit_device(struct platform_device *pdev,
    + struct omap_dss_device *dssdev);
    +bool dss_use_replication(struct omap_dss_device *dssdev,
    + enum omap_color_mode mode);
    +void default_get_overlay_fifo_thresholds(enum omap_plane plane,
    + u32 fifo_size, enum omap_burst_size *burst_size,
    + u32 *fifo_low, u32 *fifo_high);
    +
    +/* manager */
    +int dss_init_overlay_managers(struct platform_device *pdev);
    +void dss_uninit_overlay_managers(struct platform_device *pdev);
    +int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl);
    +void dss_setup_partial_planes(struct omap_dss_device *dssdev,
    + u16 *x, u16 *y, u16 *w, u16 *h);
    +void dss_start_update(struct omap_dss_device *dssdev);
    +
    +/* overlay */
    +void dss_init_overlays(struct platform_device *pdev);
    +void dss_uninit_overlays(struct platform_device *pdev);
    +int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev);
    +void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr);
    +#ifdef L4_EXAMPLE
    +void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr);
    +#endif
    +void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
    +
    +/* DSS */
    +int dss_init(bool skip_init);
    +void dss_exit(void);
    +
    +void dss_save_context(void);
    +void dss_restore_context(void);
    +
    +void dss_dump_regs(struct seq_file *s);
    +
    +void dss_sdi_init(u8 datapairs);
    +int dss_sdi_enable(void);
    +void dss_sdi_disable(void);
    +
    +void dss_select_clk_source(bool dsi, bool dispc);
    +int dss_get_dsi_clk_source(void);
    +int dss_get_dispc_clk_source(void);
    +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_get_clock_div(struct dss_clock_info *cinfo);
    +int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
    + struct dss_clock_info *dss_cinfo,
    + struct dispc_clock_info *dispc_cinfo);
    +
    +/* SDI */
    +int sdi_init(bool skip_init);
    +void sdi_exit(void);
    +int sdi_init_display(struct omap_dss_device *display);
    +
    +/* DSI */
    +int dsi_init(struct platform_device *pdev);
    +void dsi_exit(void);
    +
    +void dsi_dump_clocks(struct seq_file *s);
    +void dsi_dump_regs(struct seq_file *s);
    +
    +void dsi_save_context(void);
    +void dsi_restore_context(void);
    +
    +int dsi_init_display(struct omap_dss_device *display);
    +void dsi_irq_handler(void);
    +unsigned long dsi_get_dsi1_pll_rate(void);
    +int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo);
    +int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
    + struct dsi_clock_info *cinfo,
    + struct dispc_clock_info *dispc_cinfo);
    +int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
    + bool enable_hsdiv);
    +void dsi_pll_uninit(void);
    +void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
    + u32 fifo_size, enum omap_burst_size *burst_size,
    + u32 *fifo_low, u32 *fifo_high);
    +
    +/* DPI */
    +int dpi_init(void);
    +void dpi_exit(void);
    +int dpi_init_display(struct omap_dss_device *dssdev);
    +
    +/* DISPC */
    +int dispc_init(void);
    +void dispc_exit(void);
    +void dispc_dump_clocks(struct seq_file *s);
    +void dispc_dump_regs(struct seq_file *s);
    +void dispc_irq_handler(void);
    +void dispc_fake_vsync_irq(void);
    +
    +void dispc_save_context(void);
    +void dispc_restore_context(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_fifohandcheck(bool enable);
    +
    +void dispc_set_lcd_size(u16 width, u16 height);
    +void dispc_set_digit_size(u16 width, u16 height);
    +u32 dispc_get_plane_fifo_size(enum omap_plane plane);
    +void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high);
    +void dispc_enable_fifomerge(bool enable);
    +void dispc_set_burst_size(enum omap_plane plane,
    + enum omap_burst_size burst_size);
    +
    +void dispc_set_plane_ba0(enum omap_plane plane, u32 paddr);
    +void dispc_set_plane_ba1(enum omap_plane plane, u32 paddr);
    +void dispc_set_plane_pos(enum omap_plane plane, u16 x, u16 y);
    +void dispc_set_plane_size(enum omap_plane plane, u16 width, u16 height);
    +void dispc_set_channel_out(enum omap_plane plane,
    + enum omap_channel channel_out);
    +
    +int dispc_setup_plane(enum omap_plane plane,
    + u32 paddr, u16 screen_width,
    + u16 pos_x, u16 pos_y,
    + u16 width, u16 height,
    + u16 out_width, u16 out_height,
    + enum omap_color_mode color_mode,
    + bool ilace,
    + enum omap_dss_rotation_type rotation_type,
    + u8 rotation, bool mirror,
    + u8 global_alpha);
    +
    +bool dispc_go_busy(enum omap_channel channel);
    +void dispc_go(enum omap_channel channel);
    +void dispc_enable_lcd_out(bool enable);
    +void dispc_enable_digit_out(bool enable);
    +int dispc_enable_plane(enum omap_plane plane, bool enable);
    +void dispc_enable_replication(enum omap_plane plane, bool enable);
    +
    +void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode);
    +void dispc_set_tft_data_lines(u8 data_lines);
    +void dispc_set_lcd_display_type(enum omap_lcd_display_type type);
    +void dispc_set_loadmode(enum omap_dss_load_mode mode);
    +
    +void dispc_set_default_color(enum omap_channel channel, u32 color);
    +u32 dispc_get_default_color(enum omap_channel channel);
    +void dispc_set_trans_key(enum omap_channel ch,
    + enum omap_dss_trans_key_type type,
    + u32 trans_key);
    +void dispc_get_trans_key(enum omap_channel ch,
    + enum omap_dss_trans_key_type *type,
    + u32 *trans_key);
    +void dispc_enable_trans_key(enum omap_channel ch, bool enable);
    +void dispc_enable_alpha_blending(enum omap_channel ch, bool enable);
    +bool dispc_trans_key_enabled(enum omap_channel ch);
    +bool dispc_alpha_blending_enabled(enum omap_channel ch);
    +
    +bool dispc_lcd_timings_ok(struct omap_video_timings *timings);
    +void dispc_set_lcd_timings(struct omap_video_timings *timings);
    +unsigned long dispc_fclk_rate(void);
    +unsigned long dispc_lclk_rate(void);
    +unsigned long dispc_pclk_rate(void);
    +void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb);
    +void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
    + struct dispc_clock_info *cinfo);
    +int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
    + struct dispc_clock_info *cinfo);
    +int dispc_set_clock_div(struct dispc_clock_info *cinfo);
    +int dispc_get_clock_div(struct dispc_clock_info *cinfo);
    +
    +
    +/* VENC */
    +int venc_init(struct platform_device *pdev);
    +void venc_exit(void);
    +void venc_dump_regs(struct seq_file *s);
    +int venc_init_display(struct omap_dss_device *display);
    +
    +/* RFBI */
    +int rfbi_init(void);
    +void rfbi_exit(void);
    +void rfbi_dump_regs(struct seq_file *s);
    +
    +int rfbi_configure(int rfbi_module, int bpp, int lines);
    +void rfbi_enable_rfbi(bool enable);
    +void rfbi_transfer_area(u16 width, u16 height,
    + void (callback)(void *data), void *data);
    +void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t);
    +unsigned long rfbi_get_max_tx_rate(void);
    +int rfbi_init_display(struct omap_dss_device *display);
    +
    +#endif
    --
    1.6.5.1


    \
     
     \ /
      Last update: 2009-11-09 12:55    [W:0.162 / U:60.240 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site