提交 537d8478 编写于 作者: L Linus Torvalds

Merge branch 'for-linus' of git://gitorious.org/linux-omap-dss2/linux

* 'for-linus' of git://gitorious.org/linux-omap-dss2/linux: (64 commits)
  OMAP: DSS2: OMAPFB: add support for FBIO_WAITFORVSYNC
  OMAP: DSS2: Replace strncmp() with sysfs_streq() in overlay_manager_store()
  OMAP: DSS2: Fix error path in omap_dsi_update()
  OMAP: DSS2: TDO35S: fix video signaling
  OMAP: DSS2: OMAPFB: Fix invalid bpp for PAL and NTSC modes
  OMAP: DSS2: OMAPFB: Fix probe error path
  OMAP3EVM: Replace vdvi regulator supply with vdds_dsi
  OMAP: DSS2: Remove extra return statement
  OMAP: DSS2: adjust YUV overlay width to be even
  OMAP: DSS2: OMAPFB: Fix sysfs mirror input check
  OMAP: DSS2: OMAPFB: Remove redundant color register range check
  OMAP: DSS2: OMAPFB: Remove redundant rotate range check
  OMAP: DSS2: OMAPFB: Check fb2display() return value
  OMAP: DSS2: Taal: Optimize enable_te, rotate, mirror when value unchanged
  OMAP: DSS2: DSI: detect unsupported update requests
  OMAP: DSS2: DSI: increase FIFO low threshold
  OMAP: DSS2: DSI: Add error IRQ mask for DSI complexIO
  OMAP: DSS2: DSI: Remove BTA after set_max_rx_packet_size
  OMAP: DSS2: change manual update scaling setup
  OMAP: DSS2: DSI: use BTA to end the frame transfer
  ...
无相关合并请求
...@@ -514,14 +514,11 @@ static struct regulator_init_data omap3_evm_vdac = { ...@@ -514,14 +514,11 @@ static struct regulator_init_data omap3_evm_vdac = {
}; };
/* VPLL2 for digital video outputs */ /* VPLL2 for digital video outputs */
static struct regulator_consumer_supply omap3_evm_vpll2_supply = { static struct regulator_consumer_supply omap3_evm_vpll2_supply =
.supply = "vdvi", REGULATOR_SUPPLY("vdds_dsi", "omapdss");
.dev = &omap3_evm_lcd_device.dev,
};
static struct regulator_init_data omap3_evm_vpll2 = { static struct regulator_init_data omap3_evm_vpll2 = {
.constraints = { .constraints = {
.name = "VDVI",
.min_uV = 1800000, .min_uV = 1800000,
.max_uV = 1800000, .max_uV = 1800000,
.apply_uV = true, .apply_uV = true,
......
...@@ -238,7 +238,7 @@ int dsi_vc_dcs_write_1(int channel, u8 dcs_cmd, u8 param); ...@@ -238,7 +238,7 @@ int dsi_vc_dcs_write_1(int channel, u8 dcs_cmd, u8 param);
int dsi_vc_dcs_write_nosync(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_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen);
int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data); int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data);
int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u16 *data); int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u8 *data1, u8 *data2);
int dsi_vc_set_max_rx_packet_size(int channel, u16 len); int dsi_vc_set_max_rx_packet_size(int channel, u16 len);
int dsi_vc_send_null(int channel); int dsi_vc_send_null(int channel);
int dsi_vc_send_bta_sync(int channel); int dsi_vc_send_bta_sync(int channel);
...@@ -277,8 +277,8 @@ struct omap_video_timings { ...@@ -277,8 +277,8 @@ struct omap_video_timings {
* identify the mode, and does not actually use the configs * identify the mode, and does not actually use the configs
* itself. However, the configs should be something that * itself. However, the configs should be something that
* a normal monitor can also show */ * a normal monitor can also show */
const extern struct omap_video_timings omap_dss_pal_timings; extern const struct omap_video_timings omap_dss_pal_timings;
const extern struct omap_video_timings omap_dss_ntsc_timings; extern const struct omap_video_timings omap_dss_ntsc_timings;
#endif #endif
struct omap_overlay_info { struct omap_overlay_info {
...@@ -560,7 +560,8 @@ void omapdss_dsi_vc_enable_hs(int channel, bool enable); ...@@ -560,7 +560,8 @@ void omapdss_dsi_vc_enable_hs(int channel, bool enable);
int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable); int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable);
int omap_dsi_prepare_update(struct omap_dss_device *dssdev, int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
u16 *x, u16 *y, u16 *w, u16 *h); u16 *x, u16 *y, u16 *w, u16 *h,
bool enlarge_update_area);
int omap_dsi_update(struct omap_dss_device *dssdev, int omap_dsi_update(struct omap_dss_device *dssdev,
int channel, int channel,
u16 x, u16 y, u16 w, u16 h, u16 x, u16 y, u16 w, u16 h,
......
#ifndef __ARCH_ARM_PLAT_OMAP_NOKIA_DSI_PANEL_H
#define __ARCH_ARM_PLAT_OMAP_NOKIA_DSI_PANEL_H
#include "display.h"
/**
* struct nokia_dsi_panel_data - Nokia DSI panel driver configuration
* @name: panel name
* @use_ext_te: use external TE
* @ext_te_gpio: external TE GPIO
* @use_esd_check: perform ESD checks
* @max_backlight_level: maximum backlight level
* @set_backlight: pointer to backlight set function
* @get_backlight: pointer to backlight get function
*/
struct nokia_dsi_panel_data {
const char *name;
int reset_gpio;
bool use_ext_te;
int ext_te_gpio;
bool use_esd_check;
int max_backlight_level;
int (*set_backlight)(struct omap_dss_device *dssdev, int level);
int (*get_backlight)(struct omap_dss_device *dssdev);
};
#endif /* __ARCH_ARM_PLAT_OMAP_NOKIA_DSI_PANEL_H */
...@@ -73,8 +73,12 @@ static void toppoly_tdo_panel_power_off(struct omap_dss_device *dssdev) ...@@ -73,8 +73,12 @@ static void toppoly_tdo_panel_power_off(struct omap_dss_device *dssdev)
static int toppoly_tdo_panel_probe(struct omap_dss_device *dssdev) static int toppoly_tdo_panel_probe(struct omap_dss_device *dssdev)
{ {
dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | dssdev->panel.config = OMAP_DSS_LCD_TFT |
OMAP_DSS_LCD_IHS; OMAP_DSS_LCD_IVS |
OMAP_DSS_LCD_IHS |
OMAP_DSS_LCD_IPC |
OMAP_DSS_LCD_ONOFF;
dssdev->panel.timings = toppoly_tdo_panel_timings; dssdev->panel.timings = toppoly_tdo_panel_timings;
return 0; return 0;
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/hardirq.h>
#include <plat/sram.h> #include <plat/sram.h>
#include <plat/clock.h> #include <plat/clock.h>
...@@ -335,7 +336,7 @@ void dispc_save_context(void) ...@@ -335,7 +336,7 @@ void dispc_save_context(void)
void dispc_restore_context(void) void dispc_restore_context(void)
{ {
RR(SYSCONFIG); RR(SYSCONFIG);
RR(IRQENABLE); /*RR(IRQENABLE);*/
/*RR(CONTROL);*/ /*RR(CONTROL);*/
RR(CONFIG); RR(CONFIG);
RR(DEFAULT_COLOR0); RR(DEFAULT_COLOR0);
...@@ -472,6 +473,15 @@ void dispc_restore_context(void) ...@@ -472,6 +473,15 @@ void dispc_restore_context(void)
/* enable last, because LCD & DIGIT enable are here */ /* enable last, because LCD & DIGIT enable are here */
RR(CONTROL); RR(CONTROL);
/* clear spurious SYNC_LOST_DIGIT interrupts */
dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
/*
* enable last so IRQs won't trigger before
* the context is fully restored
*/
RR(IRQENABLE);
} }
#undef SR #undef SR
...@@ -3019,7 +3029,7 @@ void dispc_fake_vsync_irq(void) ...@@ -3019,7 +3029,7 @@ void dispc_fake_vsync_irq(void)
u32 irqstatus = DISPC_IRQ_VSYNC; u32 irqstatus = DISPC_IRQ_VSYNC;
int i; int i;
local_irq_disable(); WARN_ON(!in_interrupt());
for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
struct omap_dispc_isr_data *isr_data; struct omap_dispc_isr_data *isr_data;
...@@ -3031,8 +3041,6 @@ void dispc_fake_vsync_irq(void) ...@@ -3031,8 +3041,6 @@ void dispc_fake_vsync_irq(void)
if (isr_data->mask & irqstatus) if (isr_data->mask & irqstatus)
isr_data->isr(isr_data->arg, irqstatus); isr_data->isr(isr_data->arg, irqstatus);
} }
local_irq_enable();
} }
#endif #endif
......
...@@ -82,6 +82,9 @@ static ssize_t display_upd_mode_store(struct device *dev, ...@@ -82,6 +82,9 @@ static ssize_t display_upd_mode_store(struct device *dev,
int val, r; int val, r;
enum omap_dss_update_mode mode; enum omap_dss_update_mode mode;
if (!dssdev->driver->set_update_mode)
return -EINVAL;
val = simple_strtoul(buf, NULL, 10); val = simple_strtoul(buf, NULL, 10);
switch (val) { switch (val) {
...@@ -343,7 +346,6 @@ int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev) ...@@ -343,7 +346,6 @@ int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
case OMAP_DISPLAY_TYPE_VENC: case OMAP_DISPLAY_TYPE_VENC:
case OMAP_DISPLAY_TYPE_SDI: case OMAP_DISPLAY_TYPE_SDI:
return 24; return 24;
return 24;
default: default:
BUG(); BUG();
} }
......
此差异已折叠。
...@@ -265,6 +265,9 @@ void dss_select_dispc_clk_source(enum dss_clk_source clk_src) ...@@ -265,6 +265,9 @@ void dss_select_dispc_clk_source(enum dss_clk_source clk_src)
b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1; b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1;
if (clk_src == DSS_SRC_DSI1_PLL_FCLK)
dsi_wait_dsi1_pll_active();
REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */ REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */
dss.dispc_clk_source = clk_src; dss.dispc_clk_source = clk_src;
...@@ -279,6 +282,9 @@ void dss_select_dsi_clk_source(enum dss_clk_source clk_src) ...@@ -279,6 +282,9 @@ void dss_select_dsi_clk_source(enum dss_clk_source clk_src)
b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1; b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1;
if (clk_src == DSS_SRC_DSI2_PLL_FCLK)
dsi_wait_dsi2_pll_active();
REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */ REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */
dss.dsi_clk_source = clk_src; dss.dsi_clk_source = clk_src;
......
...@@ -199,7 +199,8 @@ int dss_init_overlay_managers(struct platform_device *pdev); ...@@ -199,7 +199,8 @@ int dss_init_overlay_managers(struct platform_device *pdev);
void dss_uninit_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); int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl);
void dss_setup_partial_planes(struct omap_dss_device *dssdev, void dss_setup_partial_planes(struct omap_dss_device *dssdev,
u16 *x, u16 *y, u16 *w, u16 *h); u16 *x, u16 *y, u16 *w, u16 *h,
bool enlarge_update_area);
void dss_start_update(struct omap_dss_device *dssdev); void dss_start_update(struct omap_dss_device *dssdev);
/* overlay */ /* overlay */
...@@ -281,6 +282,8 @@ void dsi_pll_uninit(void); ...@@ -281,6 +282,8 @@ void dsi_pll_uninit(void);
void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
u32 fifo_size, enum omap_burst_size *burst_size, u32 fifo_size, enum omap_burst_size *burst_size,
u32 *fifo_low, u32 *fifo_high); u32 *fifo_low, u32 *fifo_high);
void dsi_wait_dsi1_pll_active(void);
void dsi_wait_dsi2_pll_active(void);
#else #else
static inline int dsi_init(struct platform_device *pdev) static inline int dsi_init(struct platform_device *pdev)
{ {
...@@ -289,6 +292,12 @@ static inline int dsi_init(struct platform_device *pdev) ...@@ -289,6 +292,12 @@ static inline int dsi_init(struct platform_device *pdev)
static inline void dsi_exit(void) static inline void dsi_exit(void)
{ {
} }
static inline void dsi_wait_dsi1_pll_active(void)
{
}
static inline void dsi_wait_dsi2_pll_active(void)
{
}
#endif #endif
/* DPI */ /* DPI */
......
...@@ -440,6 +440,10 @@ struct manager_cache_data { ...@@ -440,6 +440,10 @@ struct manager_cache_data {
/* manual update region */ /* manual update region */
u16 x, y, w, h; u16 x, y, w, h;
/* enlarge the update area if the update area contains scaled
* overlays */
bool enlarge_update_area;
}; };
static struct { static struct {
...@@ -525,7 +529,7 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) ...@@ -525,7 +529,7 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
int i; int i;
struct omap_dss_device *dssdev = mgr->device; struct omap_dss_device *dssdev = mgr->device;
if (!dssdev) if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return 0; return 0;
if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
...@@ -596,11 +600,14 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) ...@@ -596,11 +600,14 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
int r; int r;
int i; int i;
if (!ovl->manager || !ovl->manager->device) if (!ovl->manager)
return 0; return 0;
dssdev = ovl->manager->device; dssdev = ovl->manager->device;
if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return 0;
if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
channel = OMAP_DSS_CHANNEL_DIGIT; channel = OMAP_DSS_CHANNEL_DIGIT;
...@@ -718,6 +725,7 @@ static int configure_overlay(enum omap_plane plane) ...@@ -718,6 +725,7 @@ static int configure_overlay(enum omap_plane plane)
u16 x, y, w, h; u16 x, y, w, h;
u32 paddr; u32 paddr;
int r; int r;
u16 orig_w, orig_h, orig_outw, orig_outh;
DSSDBGF("%d", plane); DSSDBGF("%d", plane);
...@@ -738,8 +746,16 @@ static int configure_overlay(enum omap_plane plane) ...@@ -738,8 +746,16 @@ static int configure_overlay(enum omap_plane plane)
outh = c->out_height == 0 ? c->height : c->out_height; outh = c->out_height == 0 ? c->height : c->out_height;
paddr = c->paddr; paddr = c->paddr;
orig_w = w;
orig_h = h;
orig_outw = outw;
orig_outh = outh;
if (c->manual_update && mc->do_manual_update) { if (c->manual_update && mc->do_manual_update) {
unsigned bpp; unsigned bpp;
unsigned scale_x_m = w, scale_x_d = outw;
unsigned scale_y_m = h, scale_y_d = outh;
/* If the overlay is outside the update region, disable it */ /* If the overlay is outside the update region, disable it */
if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h, if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h,
x, y, outw, outh)) { x, y, outw, outh)) {
...@@ -770,38 +786,47 @@ static int configure_overlay(enum omap_plane plane) ...@@ -770,38 +786,47 @@ static int configure_overlay(enum omap_plane plane)
BUG(); BUG();
} }
if (dispc_is_overlay_scaled(c)) { if (mc->x > c->pos_x) {
/* If the overlay is scaled, the update area has x = 0;
* already been enlarged to cover the whole overlay. We outw -= (mc->x - c->pos_x);
* only need to adjust x/y here */ paddr += (mc->x - c->pos_x) *
x = c->pos_x - mc->x; scale_x_m / scale_x_d * bpp / 8;
y = c->pos_y - mc->y;
} else { } else {
if (mc->x > c->pos_x) { x = c->pos_x - mc->x;
x = 0; }
w -= (mc->x - c->pos_x);
paddr += (mc->x - c->pos_x) * bpp / 8;
} else {
x = c->pos_x - mc->x;
}
if (mc->y > c->pos_y) {
y = 0;
h -= (mc->y - c->pos_y);
paddr += (mc->y - c->pos_y) * c->screen_width *
bpp / 8;
} else {
y = c->pos_y - mc->y;
}
if (mc->w < (x+w))
w -= (x+w) - (mc->w);
if (mc->h < (y+h)) if (mc->y > c->pos_y) {
h -= (y+h) - (mc->h); y = 0;
outh -= (mc->y - c->pos_y);
paddr += (mc->y - c->pos_y) *
scale_y_m / scale_y_d *
c->screen_width * bpp / 8;
} else {
y = c->pos_y - mc->y;
}
outw = w; if (mc->w < (x + outw))
outh = h; outw -= (x + outw) - (mc->w);
if (mc->h < (y + outh))
outh -= (y + outh) - (mc->h);
w = w * outw / orig_outw;
h = h * outh / orig_outh;
/* YUV mode overlay's input width has to be even and the
* algorithm above may adjust the width to be odd.
*
* Here we adjust the width if needed, preferring to increase
* the width if the original width was bigger.
*/
if ((w & 1) &&
(c->color_mode == OMAP_DSS_COLOR_YUV2 ||
c->color_mode == OMAP_DSS_COLOR_UYVY)) {
if (orig_w > w)
w += 1;
else
w -= 1;
} }
} }
...@@ -960,7 +985,7 @@ static void make_even(u16 *x, u16 *w) ...@@ -960,7 +985,7 @@ static void make_even(u16 *x, u16 *w)
/* Configure dispc for partial update. Return possibly modified update /* Configure dispc for partial update. Return possibly modified update
* area */ * area */
void dss_setup_partial_planes(struct omap_dss_device *dssdev, void dss_setup_partial_planes(struct omap_dss_device *dssdev,
u16 *xi, u16 *yi, u16 *wi, u16 *hi) u16 *xi, u16 *yi, u16 *wi, u16 *hi, bool enlarge_update_area)
{ {
struct overlay_cache_data *oc; struct overlay_cache_data *oc;
struct manager_cache_data *mc; struct manager_cache_data *mc;
...@@ -969,6 +994,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev, ...@@ -969,6 +994,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
int i; int i;
u16 x, y, w, h; u16 x, y, w, h;
unsigned long flags; unsigned long flags;
bool area_changed;
x = *xi; x = *xi;
y = *yi; y = *yi;
...@@ -989,73 +1015,91 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev, ...@@ -989,73 +1015,91 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
spin_lock_irqsave(&dss_cache.lock, flags); spin_lock_irqsave(&dss_cache.lock, flags);
/* We need to show the whole overlay if it is scaled. So look for /*
* those, and make the update area larger if found. * Execute the outer loop until the inner loop has completed
* Also mark the overlay cache dirty */ * once without increasing the update area. This will ensure that
for (i = 0; i < num_ovls; ++i) { * all scaled overlays end up completely within the update area.
unsigned x1, y1, x2, y2; */
unsigned outw, outh; do {
area_changed = false;
oc = &dss_cache.overlay_cache[i]; /* We need to show the whole overlay if it is scaled. So look
* for those, and make the update area larger if found.
* Also mark the overlay cache dirty */
for (i = 0; i < num_ovls; ++i) {
unsigned x1, y1, x2, y2;
unsigned outw, outh;
if (oc->channel != mgr->id) oc = &dss_cache.overlay_cache[i];
continue;
oc->dirty = true; if (oc->channel != mgr->id)
continue;
if (!oc->enabled) oc->dirty = true;
continue;
if (!dispc_is_overlay_scaled(oc)) if (!enlarge_update_area)
continue; continue;
outw = oc->out_width == 0 ? oc->width : oc->out_width; if (!oc->enabled)
outh = oc->out_height == 0 ? oc->height : oc->out_height; continue;
/* is the overlay outside the update region? */ if (!dispc_is_overlay_scaled(oc))
if (!rectangle_intersects(x, y, w, h, continue;
oc->pos_x, oc->pos_y,
outw, outh))
continue;
/* if the overlay totally inside the update region? */ outw = oc->out_width == 0 ?
if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh, oc->width : oc->out_width;
x, y, w, h)) outh = oc->out_height == 0 ?
continue; oc->height : oc->out_height;
/* is the overlay outside the update region? */
if (!rectangle_intersects(x, y, w, h,
oc->pos_x, oc->pos_y,
outw, outh))
continue;
if (x > oc->pos_x) /* if the overlay totally inside the update region? */
x1 = oc->pos_x; if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh,
else x, y, w, h))
x1 = x; continue;
if (y > oc->pos_y) if (x > oc->pos_x)
y1 = oc->pos_y; x1 = oc->pos_x;
else else
y1 = y; x1 = x;
if ((x + w) < (oc->pos_x + outw)) if (y > oc->pos_y)
x2 = oc->pos_x + outw; y1 = oc->pos_y;
else else
x2 = x + w; y1 = y;
if ((y + h) < (oc->pos_y + outh)) if ((x + w) < (oc->pos_x + outw))
y2 = oc->pos_y + outh; x2 = oc->pos_x + outw;
else else
y2 = y + h; x2 = x + w;
x = x1; if ((y + h) < (oc->pos_y + outh))
y = y1; y2 = oc->pos_y + outh;
w = x2 - x1; else
h = y2 - y1; y2 = y + h;
make_even(&x, &w); x = x1;
y = y1;
w = x2 - x1;
h = y2 - y1;
DSSDBG("changing upd area due to ovl(%d) scaling %d,%d %dx%d\n", make_even(&x, &w);
DSSDBG("changing upd area due to ovl(%d) "
"scaling %d,%d %dx%d\n",
i, x, y, w, h); i, x, y, w, h);
}
area_changed = true;
}
} while (area_changed);
mc = &dss_cache.manager_cache[mgr->id]; mc = &dss_cache.manager_cache[mgr->id];
mc->do_manual_update = true; mc->do_manual_update = true;
mc->enlarge_update_area = enlarge_update_area;
mc->x = x; mc->x = x;
mc->y = y; mc->y = y;
mc->w = w; mc->w = w;
......
...@@ -65,7 +65,7 @@ static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf, ...@@ -65,7 +65,7 @@ static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
mgr = omap_dss_get_overlay_manager(i); mgr = omap_dss_get_overlay_manager(i);
if (strncmp(buf, mgr->name, len) == 0) if (sysfs_streq(buf, mgr->name))
break; break;
mgr = NULL; mgr = NULL;
......
...@@ -886,7 +886,7 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, ...@@ -886,7 +886,7 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
return -EINVAL; return -EINVAL;
if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
dss_setup_partial_planes(dssdev, x, y, w, h); dss_setup_partial_planes(dssdev, x, y, w, h, true);
dispc_set_lcd_size(*w, *h); dispc_set_lcd_size(*w, *h);
} }
......
...@@ -34,12 +34,37 @@ ...@@ -34,12 +34,37 @@
#include "omapfb.h" #include "omapfb.h"
static u8 get_mem_idx(struct omapfb_info *ofbi)
{
if (ofbi->id == ofbi->region->id)
return 0;
return OMAPFB_MEM_IDX_ENABLED | ofbi->region->id;
}
static struct omapfb2_mem_region *get_mem_region(struct omapfb_info *ofbi,
u8 mem_idx)
{
struct omapfb2_device *fbdev = ofbi->fbdev;
if (mem_idx & OMAPFB_MEM_IDX_ENABLED)
mem_idx &= OMAPFB_MEM_IDX_MASK;
else
mem_idx = ofbi->id;
if (mem_idx >= fbdev->num_fbs)
return NULL;
return &fbdev->regions[mem_idx];
}
static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
{ {
struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev; struct omapfb2_device *fbdev = ofbi->fbdev;
struct omap_overlay *ovl; struct omap_overlay *ovl;
struct omap_overlay_info info; struct omap_overlay_info old_info;
struct omapfb2_mem_region *old_rg, *new_rg;
int r = 0; int r = 0;
DBG("omapfb_setup_plane\n"); DBG("omapfb_setup_plane\n");
...@@ -52,36 +77,106 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) ...@@ -52,36 +77,106 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
/* XXX uses only the first overlay */ /* XXX uses only the first overlay */
ovl = ofbi->overlays[0]; ovl = ofbi->overlays[0];
if (pi->enabled && !ofbi->region.size) { old_rg = ofbi->region;
new_rg = get_mem_region(ofbi, pi->mem_idx);
if (!new_rg) {
r = -EINVAL;
goto out;
}
/* Take the locks in a specific order to keep lockdep happy */
if (old_rg->id < new_rg->id) {
omapfb_get_mem_region(old_rg);
omapfb_get_mem_region(new_rg);
} else if (new_rg->id < old_rg->id) {
omapfb_get_mem_region(new_rg);
omapfb_get_mem_region(old_rg);
} else
omapfb_get_mem_region(old_rg);
if (pi->enabled && !new_rg->size) {
/* /*
* This plane's memory was freed, can't enable it * This plane's memory was freed, can't enable it
* until it's reallocated. * until it's reallocated.
*/ */
r = -EINVAL; r = -EINVAL;
goto out; goto put_mem;
} }
ovl->get_overlay_info(ovl, &info); ovl->get_overlay_info(ovl, &old_info);
info.pos_x = pi->pos_x; if (old_rg != new_rg) {
info.pos_y = pi->pos_y; ofbi->region = new_rg;
info.out_width = pi->out_width; set_fb_fix(fbi);
info.out_height = pi->out_height; }
info.enabled = pi->enabled;
r = ovl->set_overlay_info(ovl, &info); if (pi->enabled) {
if (r) struct omap_overlay_info info;
goto out;
if (ovl->manager) { r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y,
r = ovl->manager->apply(ovl->manager); pi->out_width, pi->out_height);
if (r) if (r)
goto out; goto undo;
ovl->get_overlay_info(ovl, &info);
if (!info.enabled) {
info.enabled = pi->enabled;
r = ovl->set_overlay_info(ovl, &info);
if (r)
goto undo;
}
} else {
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
info.enabled = pi->enabled;
info.pos_x = pi->pos_x;
info.pos_y = pi->pos_y;
info.out_width = pi->out_width;
info.out_height = pi->out_height;
r = ovl->set_overlay_info(ovl, &info);
if (r)
goto undo;
} }
out: if (ovl->manager)
if (r) ovl->manager->apply(ovl->manager);
dev_err(fbdev->dev, "setup_plane failed\n");
/* Release the locks in a specific order to keep lockdep happy */
if (old_rg->id > new_rg->id) {
omapfb_put_mem_region(old_rg);
omapfb_put_mem_region(new_rg);
} else if (new_rg->id > old_rg->id) {
omapfb_put_mem_region(new_rg);
omapfb_put_mem_region(old_rg);
} else
omapfb_put_mem_region(old_rg);
return 0;
undo:
if (old_rg != new_rg) {
ofbi->region = old_rg;
set_fb_fix(fbi);
}
ovl->set_overlay_info(ovl, &old_info);
put_mem:
/* Release the locks in a specific order to keep lockdep happy */
if (old_rg->id > new_rg->id) {
omapfb_put_mem_region(old_rg);
omapfb_put_mem_region(new_rg);
} else if (new_rg->id > old_rg->id) {
omapfb_put_mem_region(new_rg);
omapfb_put_mem_region(old_rg);
} else
omapfb_put_mem_region(old_rg);
out:
dev_err(fbdev->dev, "setup_plane failed\n");
return r; return r;
} }
...@@ -92,8 +187,8 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) ...@@ -92,8 +187,8 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
if (ofbi->num_overlays != 1) { if (ofbi->num_overlays != 1) {
memset(pi, 0, sizeof(*pi)); memset(pi, 0, sizeof(*pi));
} else { } else {
struct omap_overlay_info *ovli;
struct omap_overlay *ovl; struct omap_overlay *ovl;
struct omap_overlay_info *ovli;
ovl = ofbi->overlays[0]; ovl = ofbi->overlays[0];
ovli = &ovl->info; ovli = &ovl->info;
...@@ -103,6 +198,7 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) ...@@ -103,6 +198,7 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
pi->enabled = ovli->enabled; pi->enabled = ovli->enabled;
pi->channel_out = 0; /* xxx */ pi->channel_out = 0; /* xxx */
pi->mirror = 0; pi->mirror = 0;
pi->mem_idx = get_mem_idx(ofbi);
pi->out_width = ovli->out_width; pi->out_width = ovli->out_width;
pi->out_height = ovli->out_height; pi->out_height = ovli->out_height;
} }
...@@ -115,7 +211,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) ...@@ -115,7 +211,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev; struct omapfb2_device *fbdev = ofbi->fbdev;
struct omapfb2_mem_region *rg; struct omapfb2_mem_region *rg;
int r, i; int r = 0, i;
size_t size; size_t size;
if (mi->type > OMAPFB_MEMTYPE_MAX) if (mi->type > OMAPFB_MEMTYPE_MAX)
...@@ -123,22 +219,44 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) ...@@ -123,22 +219,44 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
size = PAGE_ALIGN(mi->size); size = PAGE_ALIGN(mi->size);
rg = &ofbi->region; rg = ofbi->region;
for (i = 0; i < ofbi->num_overlays; i++) { down_write_nested(&rg->lock, rg->id);
if (ofbi->overlays[i]->info.enabled) atomic_inc(&rg->lock_count);
return -EBUSY;
if (atomic_read(&rg->map_count)) {
r = -EBUSY;
goto out;
}
for (i = 0; i < fbdev->num_fbs; i++) {
struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
int j;
if (ofbi2->region != rg)
continue;
for (j = 0; j < ofbi2->num_overlays; j++) {
if (ofbi2->overlays[j]->info.enabled) {
r = -EBUSY;
goto out;
}
}
} }
if (rg->size != size || rg->type != mi->type) { if (rg->size != size || rg->type != mi->type) {
r = omapfb_realloc_fbmem(fbi, size, mi->type); r = omapfb_realloc_fbmem(fbi, size, mi->type);
if (r) { if (r) {
dev_err(fbdev->dev, "realloc fbmem failed\n"); dev_err(fbdev->dev, "realloc fbmem failed\n");
return r; goto out;
} }
} }
return 0; out:
atomic_dec(&rg->lock_count);
up_write(&rg->lock);
return r;
} }
static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
...@@ -146,12 +264,14 @@ static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) ...@@ -146,12 +264,14 @@ static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_mem_region *rg; struct omapfb2_mem_region *rg;
rg = &ofbi->region; rg = omapfb_get_mem_region(ofbi->region);
memset(mi, 0, sizeof(*mi)); memset(mi, 0, sizeof(*mi));
mi->size = rg->size; mi->size = rg->size;
mi->type = rg->type; mi->type = rg->type;
omapfb_put_mem_region(rg);
return 0; return 0;
} }
...@@ -490,6 +610,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) ...@@ -490,6 +610,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
struct omapfb_vram_info vram_info; struct omapfb_vram_info vram_info;
struct omapfb_tearsync_info tearsync_info; struct omapfb_tearsync_info tearsync_info;
struct omapfb_display_info display_info; struct omapfb_display_info display_info;
u32 crt;
} p; } p;
int r = 0; int r = 0;
...@@ -648,6 +769,17 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) ...@@ -648,6 +769,17 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
r = -EFAULT; r = -EFAULT;
break; break;
case FBIO_WAITFORVSYNC:
if (get_user(p.crt, (__u32 __user *)arg)) {
r = -EFAULT;
break;
}
if (p.crt != 0) {
r = -ENODEV;
break;
}
/* FALLTHROUGH */
case OMAPFB_WAITFORVSYNC: case OMAPFB_WAITFORVSYNC:
DBG("ioctl WAITFORVSYNC\n"); DBG("ioctl WAITFORVSYNC\n");
if (!display) { if (!display) {
...@@ -738,7 +870,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) ...@@ -738,7 +870,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
break; break;
} }
if (!display->driver->enable_te) { if (!display || !display->driver->enable_te) {
r = -ENODEV; r = -ENODEV;
break; break;
} }
......
...@@ -157,7 +157,7 @@ static void fill_fb(struct fb_info *fbi) ...@@ -157,7 +157,7 @@ static void fill_fb(struct fb_info *fbi)
static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot) static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot)
{ {
const struct vrfb *vrfb = &ofbi->region.vrfb; const struct vrfb *vrfb = &ofbi->region->vrfb;
unsigned offset; unsigned offset;
switch (rot) { switch (rot) {
...@@ -185,27 +185,27 @@ static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot) ...@@ -185,27 +185,27 @@ static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot)
static u32 omapfb_get_region_rot_paddr(const struct omapfb_info *ofbi, int rot) static u32 omapfb_get_region_rot_paddr(const struct omapfb_info *ofbi, int rot)
{ {
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
return ofbi->region.vrfb.paddr[rot] return ofbi->region->vrfb.paddr[rot]
+ omapfb_get_vrfb_offset(ofbi, rot); + omapfb_get_vrfb_offset(ofbi, rot);
} else { } else {
return ofbi->region.paddr; return ofbi->region->paddr;
} }
} }
static u32 omapfb_get_region_paddr(const struct omapfb_info *ofbi) static u32 omapfb_get_region_paddr(const struct omapfb_info *ofbi)
{ {
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
return ofbi->region.vrfb.paddr[0]; return ofbi->region->vrfb.paddr[0];
else else
return ofbi->region.paddr; return ofbi->region->paddr;
} }
static void __iomem *omapfb_get_region_vaddr(const struct omapfb_info *ofbi) static void __iomem *omapfb_get_region_vaddr(const struct omapfb_info *ofbi)
{ {
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
return ofbi->region.vrfb.vaddr[0]; return ofbi->region->vrfb.vaddr[0];
else else
return ofbi->region.vaddr; return ofbi->region->vaddr;
} }
static struct omapfb_colormode omapfb_colormodes[] = { static struct omapfb_colormode omapfb_colormodes[] = {
...@@ -450,7 +450,7 @@ static int check_vrfb_fb_size(unsigned long region_size, ...@@ -450,7 +450,7 @@ static int check_vrfb_fb_size(unsigned long region_size,
static int check_fb_size(const struct omapfb_info *ofbi, static int check_fb_size(const struct omapfb_info *ofbi,
struct fb_var_screeninfo *var) struct fb_var_screeninfo *var)
{ {
unsigned long max_frame_size = ofbi->region.size; unsigned long max_frame_size = ofbi->region->size;
int bytespp = var->bits_per_pixel >> 3; int bytespp = var->bits_per_pixel >> 3;
unsigned long line_size = var->xres_virtual * bytespp; unsigned long line_size = var->xres_virtual * bytespp;
...@@ -497,7 +497,7 @@ static int check_fb_size(const struct omapfb_info *ofbi, ...@@ -497,7 +497,7 @@ static int check_fb_size(const struct omapfb_info *ofbi,
static int setup_vrfb_rotation(struct fb_info *fbi) static int setup_vrfb_rotation(struct fb_info *fbi)
{ {
struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_mem_region *rg = &ofbi->region; struct omapfb2_mem_region *rg = ofbi->region;
struct vrfb *vrfb = &rg->vrfb; struct vrfb *vrfb = &rg->vrfb;
struct fb_var_screeninfo *var = &fbi->var; struct fb_var_screeninfo *var = &fbi->var;
struct fb_fix_screeninfo *fix = &fbi->fix; struct fb_fix_screeninfo *fix = &fbi->fix;
...@@ -558,9 +558,9 @@ static int setup_vrfb_rotation(struct fb_info *fbi) ...@@ -558,9 +558,9 @@ static int setup_vrfb_rotation(struct fb_info *fbi)
return r; return r;
/* used by open/write in fbmem.c */ /* used by open/write in fbmem.c */
fbi->screen_base = ofbi->region.vrfb.vaddr[0]; fbi->screen_base = ofbi->region->vrfb.vaddr[0];
fix->smem_start = ofbi->region.vrfb.paddr[0]; fix->smem_start = ofbi->region->vrfb.paddr[0];
switch (var->nonstd) { switch (var->nonstd) {
case OMAPFB_COLOR_YUV422: case OMAPFB_COLOR_YUV422:
...@@ -599,7 +599,7 @@ void set_fb_fix(struct fb_info *fbi) ...@@ -599,7 +599,7 @@ void set_fb_fix(struct fb_info *fbi)
struct fb_fix_screeninfo *fix = &fbi->fix; struct fb_fix_screeninfo *fix = &fbi->fix;
struct fb_var_screeninfo *var = &fbi->var; struct fb_var_screeninfo *var = &fbi->var;
struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_mem_region *rg = &ofbi->region; struct omapfb2_mem_region *rg = ofbi->region;
DBG("set_fb_fix\n"); DBG("set_fb_fix\n");
...@@ -668,8 +668,7 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var) ...@@ -668,8 +668,7 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
DBG("check_fb_var %d\n", ofbi->id); DBG("check_fb_var %d\n", ofbi->id);
if (ofbi->region.size == 0) WARN_ON(!atomic_read(&ofbi->region->lock_count));
return 0;
r = fb_mode_to_dss_mode(var, &mode); r = fb_mode_to_dss_mode(var, &mode);
if (r) { if (r) {
...@@ -684,13 +683,14 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var) ...@@ -684,13 +683,14 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
} }
} }
if (var->rotate < 0 || var->rotate > 3) if (var->rotate > 3)
return -EINVAL; return -EINVAL;
if (check_fb_res_bounds(var)) if (check_fb_res_bounds(var))
return -EINVAL; return -EINVAL;
if (check_fb_size(ofbi, var)) /* When no memory is allocated ignore the size check */
if (ofbi->region->size != 0 && check_fb_size(ofbi, var))
return -EINVAL; return -EINVAL;
if (var->xres + var->xoffset > var->xres_virtual) if (var->xres + var->xoffset > var->xres_virtual)
...@@ -822,9 +822,43 @@ static unsigned calc_rotation_offset_vrfb(const struct fb_var_screeninfo *var, ...@@ -822,9 +822,43 @@ static unsigned calc_rotation_offset_vrfb(const struct fb_var_screeninfo *var,
return offset; return offset;
} }
static void omapfb_calc_addr(const struct omapfb_info *ofbi,
const struct fb_var_screeninfo *var,
const struct fb_fix_screeninfo *fix,
int rotation, u32 *paddr, void __iomem **vaddr)
{
u32 data_start_p;
void __iomem *data_start_v;
int offset;
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation);
data_start_v = NULL;
} else {
data_start_p = omapfb_get_region_paddr(ofbi);
data_start_v = omapfb_get_region_vaddr(ofbi);
}
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
offset = calc_rotation_offset_vrfb(var, fix, rotation);
else
offset = calc_rotation_offset_dma(var, fix, rotation);
data_start_p += offset;
data_start_v += offset;
if (offset)
DBG("offset %d, %d = %d\n",
var->xoffset, var->yoffset, offset);
DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v);
*paddr = data_start_p;
*vaddr = data_start_v;
}
/* setup overlay according to the fb */ /* setup overlay according to the fb */
static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
u16 posx, u16 posy, u16 outw, u16 outh) u16 posx, u16 posy, u16 outw, u16 outh)
{ {
int r = 0; int r = 0;
...@@ -832,9 +866,8 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, ...@@ -832,9 +866,8 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
struct fb_var_screeninfo *var = &fbi->var; struct fb_var_screeninfo *var = &fbi->var;
struct fb_fix_screeninfo *fix = &fbi->fix; struct fb_fix_screeninfo *fix = &fbi->fix;
enum omap_color_mode mode = 0; enum omap_color_mode mode = 0;
int offset; u32 data_start_p = 0;
u32 data_start_p; void __iomem *data_start_v = NULL;
void __iomem *data_start_v;
struct omap_overlay_info info; struct omap_overlay_info info;
int xres, yres; int xres, yres;
int screen_width; int screen_width;
...@@ -842,6 +875,8 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, ...@@ -842,6 +875,8 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
int rotation = var->rotate; int rotation = var->rotate;
int i; int i;
WARN_ON(!atomic_read(&ofbi->region->lock_count));
for (i = 0; i < ofbi->num_overlays; i++) { for (i = 0; i < ofbi->num_overlays; i++) {
if (ovl != ofbi->overlays[i]) if (ovl != ofbi->overlays[i])
continue; continue;
...@@ -861,28 +896,9 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, ...@@ -861,28 +896,9 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
yres = var->yres; yres = var->yres;
} }
if (ofbi->region->size)
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { omapfb_calc_addr(ofbi, var, fix, rotation,
data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation); &data_start_p, &data_start_v);
data_start_v = NULL;
} else {
data_start_p = omapfb_get_region_paddr(ofbi);
data_start_v = omapfb_get_region_vaddr(ofbi);
}
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
offset = calc_rotation_offset_vrfb(var, fix, rotation);
else
offset = calc_rotation_offset_dma(var, fix, rotation);
data_start_p += offset;
data_start_v += offset;
if (offset)
DBG("offset %d, %d = %d\n",
var->xoffset, var->yoffset, offset);
DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v);
r = fb_mode_to_dss_mode(var, &mode); r = fb_mode_to_dss_mode(var, &mode);
if (r) { if (r) {
...@@ -954,12 +970,14 @@ int omapfb_apply_changes(struct fb_info *fbi, int init) ...@@ -954,12 +970,14 @@ int omapfb_apply_changes(struct fb_info *fbi, int init)
fill_fb(fbi); fill_fb(fbi);
#endif #endif
WARN_ON(!atomic_read(&ofbi->region->lock_count));
for (i = 0; i < ofbi->num_overlays; i++) { for (i = 0; i < ofbi->num_overlays; i++) {
ovl = ofbi->overlays[i]; ovl = ofbi->overlays[i];
DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id); DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id);
if (ofbi->region.size == 0) { if (ofbi->region->size == 0) {
/* the fb is not available. disable the overlay */ /* the fb is not available. disable the overlay */
omapfb_overlay_enable(ovl, 0); omapfb_overlay_enable(ovl, 0);
if (!init && ovl->manager) if (!init && ovl->manager)
...@@ -1007,36 +1025,48 @@ int omapfb_apply_changes(struct fb_info *fbi, int init) ...@@ -1007,36 +1025,48 @@ int omapfb_apply_changes(struct fb_info *fbi, int init)
* DO NOT MODIFY PAR */ * DO NOT MODIFY PAR */
static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi) static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
{ {
struct omapfb_info *ofbi = FB2OFB(fbi);
int r; int r;
DBG("check_var(%d)\n", FB2OFB(fbi)->id); DBG("check_var(%d)\n", FB2OFB(fbi)->id);
omapfb_get_mem_region(ofbi->region);
r = check_fb_var(fbi, var); r = check_fb_var(fbi, var);
omapfb_put_mem_region(ofbi->region);
return r; return r;
} }
/* set the video mode according to info->var */ /* set the video mode according to info->var */
static int omapfb_set_par(struct fb_info *fbi) static int omapfb_set_par(struct fb_info *fbi)
{ {
struct omapfb_info *ofbi = FB2OFB(fbi);
int r; int r;
DBG("set_par(%d)\n", FB2OFB(fbi)->id); DBG("set_par(%d)\n", FB2OFB(fbi)->id);
omapfb_get_mem_region(ofbi->region);
set_fb_fix(fbi); set_fb_fix(fbi);
r = setup_vrfb_rotation(fbi); r = setup_vrfb_rotation(fbi);
if (r) if (r)
return r; goto out;
r = omapfb_apply_changes(fbi, 0); r = omapfb_apply_changes(fbi, 0);
out:
omapfb_put_mem_region(ofbi->region);
return r; return r;
} }
static int omapfb_pan_display(struct fb_var_screeninfo *var, static int omapfb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *fbi) struct fb_info *fbi)
{ {
struct omapfb_info *ofbi = FB2OFB(fbi);
struct fb_var_screeninfo new_var; struct fb_var_screeninfo new_var;
int r; int r;
...@@ -1052,23 +1082,31 @@ static int omapfb_pan_display(struct fb_var_screeninfo *var, ...@@ -1052,23 +1082,31 @@ static int omapfb_pan_display(struct fb_var_screeninfo *var,
fbi->var = new_var; fbi->var = new_var;
omapfb_get_mem_region(ofbi->region);
r = omapfb_apply_changes(fbi, 0); r = omapfb_apply_changes(fbi, 0);
omapfb_put_mem_region(ofbi->region);
return r; return r;
} }
static void mmap_user_open(struct vm_area_struct *vma) static void mmap_user_open(struct vm_area_struct *vma)
{ {
struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data; struct omapfb2_mem_region *rg = vma->vm_private_data;
atomic_inc(&ofbi->map_count); omapfb_get_mem_region(rg);
atomic_inc(&rg->map_count);
omapfb_put_mem_region(rg);
} }
static void mmap_user_close(struct vm_area_struct *vma) static void mmap_user_close(struct vm_area_struct *vma)
{ {
struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data; struct omapfb2_mem_region *rg = vma->vm_private_data;
atomic_dec(&ofbi->map_count); omapfb_get_mem_region(rg);
atomic_dec(&rg->map_count);
omapfb_put_mem_region(rg);
} }
static struct vm_operations_struct mmap_user_ops = { static struct vm_operations_struct mmap_user_ops = {
...@@ -1080,9 +1118,11 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) ...@@ -1080,9 +1118,11 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
{ {
struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb_info *ofbi = FB2OFB(fbi);
struct fb_fix_screeninfo *fix = &fbi->fix; struct fb_fix_screeninfo *fix = &fbi->fix;
struct omapfb2_mem_region *rg;
unsigned long off; unsigned long off;
unsigned long start; unsigned long start;
u32 len; u32 len;
int r = -EINVAL;
if (vma->vm_end - vma->vm_start == 0) if (vma->vm_end - vma->vm_start == 0)
return 0; return 0;
...@@ -1090,12 +1130,14 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) ...@@ -1090,12 +1130,14 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
return -EINVAL; return -EINVAL;
off = vma->vm_pgoff << PAGE_SHIFT; off = vma->vm_pgoff << PAGE_SHIFT;
rg = omapfb_get_mem_region(ofbi->region);
start = omapfb_get_region_paddr(ofbi); start = omapfb_get_region_paddr(ofbi);
len = fix->smem_len; len = fix->smem_len;
if (off >= len) if (off >= len)
return -EINVAL; goto error;
if ((vma->vm_end - vma->vm_start + off) > len) if ((vma->vm_end - vma->vm_start + off) > len)
return -EINVAL; goto error;
off += start; off += start;
...@@ -1105,13 +1147,25 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) ...@@ -1105,13 +1147,25 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
vma->vm_flags |= VM_IO | VM_RESERVED; vma->vm_flags |= VM_IO | VM_RESERVED;
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
vma->vm_ops = &mmap_user_ops; vma->vm_ops = &mmap_user_ops;
vma->vm_private_data = ofbi; vma->vm_private_data = rg;
if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_page_prot)) vma->vm_end - vma->vm_start,
return -EAGAIN; vma->vm_page_prot)) {
r = -EAGAIN;
goto error;
}
/* vm_ops.open won't be called for mmap itself. */ /* vm_ops.open won't be called for mmap itself. */
atomic_inc(&ofbi->map_count); atomic_inc(&rg->map_count);
omapfb_put_mem_region(rg);
return 0; return 0;
error:
omapfb_put_mem_region(ofbi->region);
return r;
} }
/* Store a single color palette entry into a pseudo palette or the hardware /* Store a single color palette entry into a pseudo palette or the hardware
...@@ -1154,11 +1208,6 @@ static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green, ...@@ -1154,11 +1208,6 @@ static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green,
if (r != 0) if (r != 0)
break; break;
if (regno < 0) {
r = -EINVAL;
break;
}
if (regno < 16) { if (regno < 16) {
u16 pal; u16 pal;
pal = ((red >> (16 - var->red.length)) << pal = ((red >> (16 - var->red.length)) <<
...@@ -1217,6 +1266,9 @@ static int omapfb_blank(int blank, struct fb_info *fbi) ...@@ -1217,6 +1266,9 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
int do_update = 0; int do_update = 0;
int r = 0; int r = 0;
if (!display)
return -EINVAL;
omapfb_lock(fbdev); omapfb_lock(fbdev);
switch (blank) { switch (blank) {
...@@ -1300,7 +1352,9 @@ static void omapfb_free_fbmem(struct fb_info *fbi) ...@@ -1300,7 +1352,9 @@ static void omapfb_free_fbmem(struct fb_info *fbi)
struct omapfb2_device *fbdev = ofbi->fbdev; struct omapfb2_device *fbdev = ofbi->fbdev;
struct omapfb2_mem_region *rg; struct omapfb2_mem_region *rg;
rg = &ofbi->region; rg = ofbi->region;
WARN_ON(atomic_read(&rg->map_count));
if (rg->paddr) if (rg->paddr)
if (omap_vram_free(rg->paddr, rg->size)) if (omap_vram_free(rg->paddr, rg->size))
...@@ -1355,8 +1409,15 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size, ...@@ -1355,8 +1409,15 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
void __iomem *vaddr; void __iomem *vaddr;
int r; int r;
rg = &ofbi->region; rg = ofbi->region;
memset(rg, 0, sizeof(*rg));
rg->paddr = 0;
rg->vaddr = NULL;
memset(&rg->vrfb, 0, sizeof rg->vrfb);
rg->size = 0;
rg->type = 0;
rg->alloc = false;
rg->map = false;
size = PAGE_ALIGN(size); size = PAGE_ALIGN(size);
...@@ -1609,7 +1670,7 @@ static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev) ...@@ -1609,7 +1670,7 @@ static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
for (i = 0; i < fbdev->num_fbs; i++) { for (i = 0; i < fbdev->num_fbs; i++) {
struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]); struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
struct omapfb2_mem_region *rg; struct omapfb2_mem_region *rg;
rg = &ofbi->region; rg = ofbi->region;
DBG("region%d phys %08x virt %p size=%lu\n", DBG("region%d phys %08x virt %p size=%lu\n",
i, i,
...@@ -1626,7 +1687,7 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) ...@@ -1626,7 +1687,7 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev; struct omapfb2_device *fbdev = ofbi->fbdev;
struct omap_dss_device *display = fb2display(fbi); struct omap_dss_device *display = fb2display(fbi);
struct omapfb2_mem_region *rg = &ofbi->region; struct omapfb2_mem_region *rg = ofbi->region;
unsigned long old_size = rg->size; unsigned long old_size = rg->size;
unsigned long old_paddr = rg->paddr; unsigned long old_paddr = rg->paddr;
int old_type = rg->type; int old_type = rg->type;
...@@ -1709,7 +1770,7 @@ static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi) ...@@ -1709,7 +1770,7 @@ static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
fbi->flags = FBINFO_FLAG_DEFAULT; fbi->flags = FBINFO_FLAG_DEFAULT;
fbi->pseudo_palette = fbdev->pseudo_palette; fbi->pseudo_palette = fbdev->pseudo_palette;
if (ofbi->region.size == 0) { if (ofbi->region->size == 0) {
clear_fb_info(fbi); clear_fb_info(fbi);
return 0; return 0;
} }
...@@ -1871,6 +1932,10 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) ...@@ -1871,6 +1932,10 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
ofbi->fbdev = fbdev; ofbi->fbdev = fbdev;
ofbi->id = i; ofbi->id = i;
ofbi->region = &fbdev->regions[i];
ofbi->region->id = i;
init_rwsem(&ofbi->region->lock);
/* assign these early, so that fb alloc can use them */ /* assign these early, so that fb alloc can use them */
ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB : ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
OMAP_DSS_ROT_DMA; OMAP_DSS_ROT_DMA;
...@@ -1900,7 +1965,13 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) ...@@ -1900,7 +1965,13 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
/* setup fb_infos */ /* setup fb_infos */
for (i = 0; i < fbdev->num_fbs; i++) { for (i = 0; i < fbdev->num_fbs; i++) {
r = omapfb_fb_init(fbdev, fbdev->fbs[i]); struct fb_info *fbi = fbdev->fbs[i];
struct omapfb_info *ofbi = FB2OFB(fbi);
omapfb_get_mem_region(ofbi->region);
r = omapfb_fb_init(fbdev, fbi);
omapfb_put_mem_region(ofbi->region);
if (r) { if (r) {
dev_err(fbdev->dev, "failed to setup fb_info\n"); dev_err(fbdev->dev, "failed to setup fb_info\n");
return r; return r;
...@@ -1921,20 +1992,19 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) ...@@ -1921,20 +1992,19 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
DBG("framebuffers registered\n"); DBG("framebuffers registered\n");
for (i = 0; i < fbdev->num_fbs; i++) { for (i = 0; i < fbdev->num_fbs; i++) {
r = omapfb_apply_changes(fbdev->fbs[i], 1); struct fb_info *fbi = fbdev->fbs[i];
struct omapfb_info *ofbi = FB2OFB(fbi);
omapfb_get_mem_region(ofbi->region);
r = omapfb_apply_changes(fbi, 1);
omapfb_put_mem_region(ofbi->region);
if (r) { if (r) {
dev_err(fbdev->dev, "failed to change mode\n"); dev_err(fbdev->dev, "failed to change mode\n");
return r; return r;
} }
} }
DBG("create sysfs for fbs\n");
r = omapfb_create_sysfs(fbdev);
if (r) {
dev_err(fbdev->dev, "failed to create sysfs entries\n");
return r;
}
/* Enable fb0 */ /* Enable fb0 */
if (fbdev->num_fbs > 0) { if (fbdev->num_fbs > 0) {
struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]); struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]);
...@@ -1968,11 +2038,11 @@ static int omapfb_mode_to_timings(const char *mode_str, ...@@ -1968,11 +2038,11 @@ static int omapfb_mode_to_timings(const char *mode_str,
#ifdef CONFIG_OMAP2_DSS_VENC #ifdef CONFIG_OMAP2_DSS_VENC
if (strcmp(mode_str, "pal") == 0) { if (strcmp(mode_str, "pal") == 0) {
*timings = omap_dss_pal_timings; *timings = omap_dss_pal_timings;
*bpp = 0; *bpp = 24;
return 0; return 0;
} else if (strcmp(mode_str, "ntsc") == 0) { } else if (strcmp(mode_str, "ntsc") == 0) {
*timings = omap_dss_ntsc_timings; *timings = omap_dss_ntsc_timings;
*bpp = 0; *bpp = 24;
return 0; return 0;
} }
#endif #endif
...@@ -2220,6 +2290,13 @@ static int omapfb_probe(struct platform_device *pdev) ...@@ -2220,6 +2290,13 @@ static int omapfb_probe(struct platform_device *pdev)
} }
} }
DBG("create sysfs for fbs\n");
r = omapfb_create_sysfs(fbdev);
if (r) {
dev_err(fbdev->dev, "failed to create sysfs entries\n");
goto cleanup;
}
return 0; return 0;
cleanup: cleanup:
......
...@@ -49,6 +49,7 @@ static ssize_t store_rotate_type(struct device *dev, ...@@ -49,6 +49,7 @@ static ssize_t store_rotate_type(struct device *dev,
{ {
struct fb_info *fbi = dev_get_drvdata(dev); struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_mem_region *rg;
enum omap_dss_rotation_type rot_type; enum omap_dss_rotation_type rot_type;
int r; int r;
...@@ -64,9 +65,11 @@ static ssize_t store_rotate_type(struct device *dev, ...@@ -64,9 +65,11 @@ static ssize_t store_rotate_type(struct device *dev,
if (rot_type == ofbi->rotation_type) if (rot_type == ofbi->rotation_type)
goto out; goto out;
if (ofbi->region.size) { rg = omapfb_get_mem_region(ofbi->region);
if (rg->size) {
r = -EBUSY; r = -EBUSY;
goto out; goto put_region;
} }
ofbi->rotation_type = rot_type; ofbi->rotation_type = rot_type;
...@@ -75,6 +78,8 @@ static ssize_t store_rotate_type(struct device *dev, ...@@ -75,6 +78,8 @@ static ssize_t store_rotate_type(struct device *dev,
* Since the VRAM for this FB is not allocated at the moment we don't * Since the VRAM for this FB is not allocated at the moment we don't
* need to do any further parameter checking at this point. * need to do any further parameter checking at this point.
*/ */
put_region:
omapfb_put_mem_region(rg);
out: out:
unlock_fb_info(fbi); unlock_fb_info(fbi);
...@@ -97,7 +102,7 @@ static ssize_t store_mirror(struct device *dev, ...@@ -97,7 +102,7 @@ static ssize_t store_mirror(struct device *dev,
{ {
struct fb_info *fbi = dev_get_drvdata(dev); struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb_info *ofbi = FB2OFB(fbi);
bool mirror; unsigned long mirror;
int r; int r;
struct fb_var_screeninfo new_var; struct fb_var_screeninfo new_var;
...@@ -111,6 +116,8 @@ static ssize_t store_mirror(struct device *dev, ...@@ -111,6 +116,8 @@ static ssize_t store_mirror(struct device *dev,
ofbi->mirror = mirror; ofbi->mirror = mirror;
omapfb_get_mem_region(ofbi->region);
memcpy(&new_var, &fbi->var, sizeof(new_var)); memcpy(&new_var, &fbi->var, sizeof(new_var));
r = check_fb_var(fbi, &new_var); r = check_fb_var(fbi, &new_var);
if (r) if (r)
...@@ -125,6 +132,8 @@ static ssize_t store_mirror(struct device *dev, ...@@ -125,6 +132,8 @@ static ssize_t store_mirror(struct device *dev,
r = count; r = count;
out: out:
omapfb_put_mem_region(ofbi->region);
unlock_fb_info(fbi); unlock_fb_info(fbi);
return r; return r;
...@@ -263,11 +272,15 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr, ...@@ -263,11 +272,15 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
DBG("detaching %d\n", ofbi->overlays[i]->id); DBG("detaching %d\n", ofbi->overlays[i]->id);
omapfb_get_mem_region(ofbi->region);
omapfb_overlay_enable(ovl, 0); omapfb_overlay_enable(ovl, 0);
if (ovl->manager) if (ovl->manager)
ovl->manager->apply(ovl->manager); ovl->manager->apply(ovl->manager);
omapfb_put_mem_region(ofbi->region);
for (t = i + 1; t < ofbi->num_overlays; t++) { for (t = i + 1; t < ofbi->num_overlays; t++) {
ofbi->rotation[t-1] = ofbi->rotation[t]; ofbi->rotation[t-1] = ofbi->rotation[t];
ofbi->overlays[t-1] = ofbi->overlays[t]; ofbi->overlays[t-1] = ofbi->overlays[t];
...@@ -300,7 +313,12 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr, ...@@ -300,7 +313,12 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
} }
if (added) { if (added) {
omapfb_get_mem_region(ofbi->region);
r = omapfb_apply_changes(fbi, 0); r = omapfb_apply_changes(fbi, 0);
omapfb_put_mem_region(ofbi->region);
if (r) if (r)
goto out; goto out;
} }
...@@ -388,7 +406,12 @@ static ssize_t store_overlays_rotate(struct device *dev, ...@@ -388,7 +406,12 @@ static ssize_t store_overlays_rotate(struct device *dev,
for (i = 0; i < num_ovls; ++i) for (i = 0; i < num_ovls; ++i)
ofbi->rotation[i] = rotation[i]; ofbi->rotation[i] = rotation[i];
omapfb_get_mem_region(ofbi->region);
r = omapfb_apply_changes(fbi, 0); r = omapfb_apply_changes(fbi, 0);
omapfb_put_mem_region(ofbi->region);
if (r) if (r)
goto out; goto out;
...@@ -408,7 +431,7 @@ static ssize_t show_size(struct device *dev, ...@@ -408,7 +431,7 @@ static ssize_t show_size(struct device *dev,
struct fb_info *fbi = dev_get_drvdata(dev); struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb_info *ofbi = FB2OFB(fbi);
return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region.size); return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region->size);
} }
static ssize_t store_size(struct device *dev, struct device_attribute *attr, static ssize_t store_size(struct device *dev, struct device_attribute *attr,
...@@ -416,6 +439,8 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, ...@@ -416,6 +439,8 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
{ {
struct fb_info *fbi = dev_get_drvdata(dev); struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev;
struct omapfb2_mem_region *rg;
unsigned long size; unsigned long size;
int r; int r;
int i; int i;
...@@ -425,15 +450,33 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, ...@@ -425,15 +450,33 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
if (!lock_fb_info(fbi)) if (!lock_fb_info(fbi))
return -ENODEV; return -ENODEV;
for (i = 0; i < ofbi->num_overlays; i++) { rg = ofbi->region;
if (ofbi->overlays[i]->info.enabled) {
r = -EBUSY; down_write_nested(&rg->lock, rg->id);
goto out; atomic_inc(&rg->lock_count);
if (atomic_read(&rg->map_count)) {
r = -EBUSY;
goto out;
}
for (i = 0; i < fbdev->num_fbs; i++) {
struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
int j;
if (ofbi2->region != rg)
continue;
for (j = 0; j < ofbi2->num_overlays; j++) {
if (ofbi2->overlays[j]->info.enabled) {
r = -EBUSY;
goto out;
}
} }
} }
if (size != ofbi->region.size) { if (size != ofbi->region->size) {
r = omapfb_realloc_fbmem(fbi, size, ofbi->region.type); r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type);
if (r) { if (r) {
dev_err(dev, "realloc fbmem failed\n"); dev_err(dev, "realloc fbmem failed\n");
goto out; goto out;
...@@ -442,6 +485,9 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, ...@@ -442,6 +485,9 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
r = count; r = count;
out: out:
atomic_dec(&rg->lock_count);
up_write(&rg->lock);
unlock_fb_info(fbi); unlock_fb_info(fbi);
return r; return r;
...@@ -453,7 +499,7 @@ static ssize_t show_phys(struct device *dev, ...@@ -453,7 +499,7 @@ static ssize_t show_phys(struct device *dev,
struct fb_info *fbi = dev_get_drvdata(dev); struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb_info *ofbi = FB2OFB(fbi);
return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region.paddr); return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region->paddr);
} }
static ssize_t show_virt(struct device *dev, static ssize_t show_virt(struct device *dev,
...@@ -462,7 +508,7 @@ static ssize_t show_virt(struct device *dev, ...@@ -462,7 +508,7 @@ static ssize_t show_virt(struct device *dev,
struct fb_info *fbi = dev_get_drvdata(dev); struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb_info *ofbi = FB2OFB(fbi);
return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region.vaddr); return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr);
} }
static struct device_attribute omapfb_attrs[] = { static struct device_attribute omapfb_attrs[] = {
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#define DEBUG #define DEBUG
#endif #endif
#include <linux/rwsem.h>
#include <plat/display.h> #include <plat/display.h>
#ifdef DEBUG #ifdef DEBUG
...@@ -44,6 +46,7 @@ extern unsigned int omapfb_debug; ...@@ -44,6 +46,7 @@ extern unsigned int omapfb_debug;
#define OMAPFB_MAX_OVL_PER_FB 3 #define OMAPFB_MAX_OVL_PER_FB 3
struct omapfb2_mem_region { struct omapfb2_mem_region {
int id;
u32 paddr; u32 paddr;
void __iomem *vaddr; void __iomem *vaddr;
struct vrfb vrfb; struct vrfb vrfb;
...@@ -51,13 +54,15 @@ struct omapfb2_mem_region { ...@@ -51,13 +54,15 @@ struct omapfb2_mem_region {
u8 type; /* OMAPFB_PLANE_MEM_* */ u8 type; /* OMAPFB_PLANE_MEM_* */
bool alloc; /* allocated by the driver */ bool alloc; /* allocated by the driver */
bool map; /* kernel mapped by the driver */ bool map; /* kernel mapped by the driver */
atomic_t map_count;
struct rw_semaphore lock;
atomic_t lock_count;
}; };
/* appended to fb_info */ /* appended to fb_info */
struct omapfb_info { struct omapfb_info {
int id; int id;
struct omapfb2_mem_region region; struct omapfb2_mem_region *region;
atomic_t map_count;
int num_overlays; int num_overlays;
struct omap_overlay *overlays[OMAPFB_MAX_OVL_PER_FB]; struct omap_overlay *overlays[OMAPFB_MAX_OVL_PER_FB];
struct omapfb2_device *fbdev; struct omapfb2_device *fbdev;
...@@ -76,6 +81,7 @@ struct omapfb2_device { ...@@ -76,6 +81,7 @@ struct omapfb2_device {
unsigned num_fbs; unsigned num_fbs;
struct fb_info *fbs[10]; struct fb_info *fbs[10];
struct omapfb2_mem_region regions[10];
unsigned num_displays; unsigned num_displays;
struct omap_dss_device *displays[10]; struct omap_dss_device *displays[10];
...@@ -117,6 +123,9 @@ int omapfb_update_window(struct fb_info *fbi, ...@@ -117,6 +123,9 @@ int omapfb_update_window(struct fb_info *fbi,
int dss_mode_to_fb_mode(enum omap_color_mode dssmode, int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
struct fb_var_screeninfo *var); struct fb_var_screeninfo *var);
int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
u16 posx, u16 posy, u16 outw, u16 outh);
/* find the display connected to this fb, if any */ /* find the display connected to this fb, if any */
static inline struct omap_dss_device *fb2display(struct fb_info *fbi) static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
{ {
...@@ -148,8 +157,24 @@ static inline int omapfb_overlay_enable(struct omap_overlay *ovl, ...@@ -148,8 +157,24 @@ static inline int omapfb_overlay_enable(struct omap_overlay *ovl,
struct omap_overlay_info info; struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info); ovl->get_overlay_info(ovl, &info);
if (info.enabled == enable)
return 0;
info.enabled = enable; info.enabled = enable;
return ovl->set_overlay_info(ovl, &info); return ovl->set_overlay_info(ovl, &info);
} }
static inline struct omapfb2_mem_region *
omapfb_get_mem_region(struct omapfb2_mem_region *rg)
{
down_read_nested(&rg->lock, rg->id);
atomic_inc(&rg->lock_count);
return rg;
}
static inline void omapfb_put_mem_region(struct omapfb2_mem_region *rg)
{
atomic_dec(&rg->lock_count);
up_read(&rg->lock);
}
#endif #endif
...@@ -85,6 +85,9 @@ ...@@ -85,6 +85,9 @@
#define OMAPFB_MEMTYPE_SRAM 1 #define OMAPFB_MEMTYPE_SRAM 1
#define OMAPFB_MEMTYPE_MAX 1 #define OMAPFB_MEMTYPE_MAX 1
#define OMAPFB_MEM_IDX_ENABLED 0x80
#define OMAPFB_MEM_IDX_MASK 0x7f
enum omapfb_color_format { enum omapfb_color_format {
OMAPFB_COLOR_RGB565 = 0, OMAPFB_COLOR_RGB565 = 0,
OMAPFB_COLOR_YUV422, OMAPFB_COLOR_YUV422,
...@@ -136,7 +139,7 @@ struct omapfb_plane_info { ...@@ -136,7 +139,7 @@ struct omapfb_plane_info {
__u8 enabled; __u8 enabled;
__u8 channel_out; __u8 channel_out;
__u8 mirror; __u8 mirror;
__u8 reserved1; __u8 mem_idx;
__u32 out_width; __u32 out_width;
__u32 out_height; __u32 out_height;
__u32 reserved2[12]; __u32 reserved2[12];
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
反馈
建议
客服 返回
顶部