* Re: [RFC 0/5] Generic panel framework
From: Tomi Valkeinen @ 2012-08-20 11:39 UTC (permalink / raw)
To: Laurent Pinchart
Cc: linux-fbdev, dri-devel, linux-leds, linux-media, Bryan Wu,
Richard Purdie, Marcus Lorentzon, Sumit Semwal, Archit Taneja,
Sebastien Guiriec, Inki Dae, Kyungmin Park
In-Reply-To: <4948190.AFNtaaFKXQ@avalon>
[-- Attachment #1: Type: text/plain, Size: 2284 bytes --]
On Sat, 2012-08-18 at 03:16 +0200, Laurent Pinchart wrote:
> Hi Tomi,
> mipi-dbi-bus might not belong to include/video/panel/ though, as it can be
> used for non-panel devices (at least in theory). The future mipi-dsi-bus
> certainly will.
They are both display busses. So while they could be used for anything,
I find it quite unlikely as there are much better alternatives for
generic bus needs.
> Would you be able to send incremental patches on top of v2 to implement the
> solution you have in mind ? It would be neat if you could also implement mipi-
> dsi-bus for the OMAP DSS and test the code with a real device :-)
Yes, I'd like to try this out on OMAP, both DBI and DSI. However, I fear
it'll be quite complex due to the dependencies all around we have in the
current driver. We're working on simplifying things so that it'll be
easier to try thing like the panel framework, though, so we're going in
the right direction.
> > Generally about locks, if we define that panel ops may only be called
> > exclusively, does it simplify things? I think we can make such
> > requirements, as there should be only one display framework that handles
> > the panel. Then we don't need locking for things like enable/disable.
>
> Pushing locking to callers would indeed simplify panel drivers, but we need to
> make sure we won't need to expose a panel to several callers in the future.
I have a feeling that would be a bad idea.
Display related stuff are quite sensitive to any delays, so any extra
transactions over, say, DSI bus could cause a noticeable glitch on the
screen. I'm not sure what are all the possible ops that a panel can
offer, but I think all that affect the display or could cause delays
should be handled by one controlling entity (drm or such). The
controlling entity needs to handle locking anyway, so in that sense I
don't think it's an extra burden for it.
The things that come to my mind that could possibly cause calls to the
panel outside drm: debugfs, sysfs, audio, backlight. Of those, I think
backlight should go through drm. Audio, no idea. debugfs and sysfs
locking needs to be handled by the panel driver, and they are a bit
problematic as I guess having them requires full locking.
Tomi
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* [PATCH V5 0/6] OMAPDSS: Cleanup cpu_is checks
From: Chandrabhanu Mahapatra @ 2012-08-20 13:33 UTC (permalink / raw)
To: tomi.valkeinen, tony, paul
Cc: linux-omap, linux-fbdev, Chandrabhanu Mahapatra
In-Reply-To: <cover.1343912532.git.cmahapatra@ti.com>
Hi everyone,
this patch series aims at cleaning up of DSS of cpu_is checks thereby making it
more generic.
The 1st patch cleans up cpu_is checks from DISPC code.
The 2nd patch removes unused functions from DSS code.
The 3rd patch cleans up cpu_is checks from DSS code.
The 4th patch removes cpu_is checks from VENC code.
The 5th patch disables VENC support on OMAP4.
The 6th patch removes cpu_is checks from DPI code and replaces it with a
dss feature.
Changes with respect to V1 series:
1st patch :
* moved dispc_ops structure definitions from dss_features.c to dispc.c
and renamed it to dispc_features
* moved dispc_features definitions close to dispc_init_features() thereby
eliminating various functions declarations from top of dispc.c
* used __initconst before dispc_features definitions and __init before
dispc_init_features()
* removed definitions of _dispc_lcd_timings_ok_24xx,
_dispc_lcd_timings_ok_44xx, _dispc_mgr_set_lcd_timings_hv_24xx and
_dispc_mgr_set_lcd_timings_hv_44xx replacing them with appropiate variables
* renamed various dispc_features structures to give consistent naming
3rd patch :
* moved dss_ops structure definitions from dss_features.c to dss.c and
renamed it to dss_features
* removed all functions from dss_features structure and replaced them with
appropiate variables
* used __initconst before dss_features definitions and __init before
dss_init_features()
* renamed various dss_features structures to give consistent naming
* renamed factor variable of dss_features structure to dss_fck_multiplier
All your comments and suggestions are welcome.
Refenence Tree:
git@gitorious.org:~chandrabhanu/linux-omap-dss2/chandrabhanus-linux.git dss_cleanup
Chandrabhanu Mahapatra (6):
OMAPDSS: DISPC: cleanup cpu_is_xxxx checks
OMAPDSS: DSS: Remove redundant functions
OMAPDSS: DSS: Cleanup cpu_is_xxxx checks
OMAPDSS: VENC: Remove cpu_is_xxxx checks
ARM: OMAP: Disable venc for OMAP4
OMAPDSS: DPI: Remove cpu_is_xxxx checks
arch/arm/mach-omap2/display.c | 1 -
drivers/video/omap2/dss/dispc.c | 433 ++++++++++++++++++++------------
drivers/video/omap2/dss/dpi.c | 12 +-
drivers/video/omap2/dss/dss.c | 162 ++++++------
drivers/video/omap2/dss/dss.h | 2 -
drivers/video/omap2/dss/dss_features.c | 1 +
drivers/video/omap2/dss/dss_features.h | 1 +
drivers/video/omap2/dss/venc.c | 11 -
8 files changed, 363 insertions(+), 260 deletions(-)
--
1.7.10
^ permalink raw reply
* [PATCH V5 1/6] OMAPDSS: DISPC: cleanup cpu_is_xxxx checks
From: Chandrabhanu Mahapatra @ 2012-08-20 13:34 UTC (permalink / raw)
To: tomi.valkeinen; +Cc: linux-omap, linux-fbdev, Chandrabhanu Mahapatra
In-Reply-To: <cover.1345468541.git.cmahapatra@ti.com>
All the cpu_is checks have been moved to dispc_init_features function providing
a much more generic and cleaner interface. The OMAP version and revision
specific functions and data are initialized by dispc_features structure which is
local to dispc.c.
Signed-off-by: Chandrabhanu Mahapatra <cmahapatra@ti.com>
---
drivers/video/omap2/dss/dispc.c | 433 +++++++++++++++++++++++++--------------
1 file changed, 278 insertions(+), 155 deletions(-)
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index ff52702..3fad33a 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -81,6 +81,23 @@ struct dispc_irq_stats {
unsigned irqs[32];
};
+struct dispc_features {
+ int hp_max;
+ int vp_max;
+ int sw_max;
+ int sw_start;
+ int fp_start;
+ int bp_start;
+ int (*calc_scaling) (enum omap_channel channel,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
+ u16 pos_x, unsigned long *core_clk);
+ unsigned long (*calc_core_clk) (enum omap_channel channel,
+ u16 width, u16 height, u16 out_width, u16 out_height);
+};
+
static struct {
struct platform_device *pdev;
void __iomem *base;
@@ -101,6 +118,8 @@ static struct {
bool ctx_valid;
u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
+ const struct dispc_features *feat;
+
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
spinlock_t irq_stats_lock;
struct dispc_irq_stats irq_stats;
@@ -1939,7 +1958,18 @@ static unsigned long calc_core_clk_five_taps(enum omap_channel channel,
return core_clk;
}
-static unsigned long calc_core_clk(enum omap_channel channel, u16 width,
+static unsigned long calc_core_clk_24xx(enum omap_channel channel, u16 width,
+ u16 height, u16 out_width, u16 out_height)
+{
+ unsigned long pclk = dispc_mgr_pclk_rate(channel);
+
+ if (height > out_height && width > out_width)
+ return pclk * 4;
+ else
+ return pclk * 2;
+}
+
+static unsigned long calc_core_clk_34xx(enum omap_channel channel, u16 width,
u16 height, u16 out_width, u16 out_height)
{
unsigned int hf, vf;
@@ -1958,25 +1988,163 @@ static unsigned long calc_core_clk(enum omap_channel channel, u16 width,
hf = 2;
else
hf = 1;
-
if (height > out_height)
vf = 2;
else
vf = 1;
- if (cpu_is_omap24xx()) {
- if (vf > 1 && hf > 1)
- return pclk * 4;
- else
- return pclk * 2;
- } else if (cpu_is_omap34xx()) {
- return pclk * vf * hf;
- } else {
- if (hf > 1)
- return DIV_ROUND_UP(pclk, out_width) * width;
- else
- return pclk;
+ return pclk * vf * hf;
+}
+
+static unsigned long calc_core_clk_44xx(enum omap_channel channel, u16 width,
+ u16 height, u16 out_width, u16 out_height)
+{
+ unsigned long pclk = dispc_mgr_pclk_rate(channel);
+
+ if (width > out_width)
+ return DIV_ROUND_UP(pclk, out_width) * width;
+ else
+ return pclk;
+}
+
+static int dispc_ovl_calc_scaling_24xx(enum omap_channel channel,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
+ u16 pos_x, unsigned long *core_clk)
+{
+ int error;
+ u16 in_width, in_height;
+ int min_factor = min(*decim_x, *decim_y);
+ const int maxsinglelinewidth + dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
+ *five_taps = false;
+
+ do {
+ in_height = DIV_ROUND_UP(height, *decim_y);
+ in_width = DIV_ROUND_UP(width, *decim_x);
+ *core_clk = dispc.feat->calc_core_clk(channel, in_width,
+ in_height, out_width, out_height);
+ error = (in_width > maxsinglelinewidth || !*core_clk ||
+ *core_clk > dispc_core_clk_rate());
+ if (error) {
+ if (*decim_x = *decim_y) {
+ *decim_x = min_factor;
+ ++*decim_y;
+ } else {
+ swap(*decim_x, *decim_y);
+ if (*decim_x < *decim_y)
+ ++*decim_x;
+ }
+ }
+ } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
+
+ if (in_width > maxsinglelinewidth) {
+ DSSERR("Cannot scale max input width exceeded");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int dispc_ovl_calc_scaling_34xx(enum omap_channel channel,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
+ u16 pos_x, unsigned long *core_clk)
+{
+ int error;
+ u16 in_width, in_height;
+ int min_factor = min(*decim_x, *decim_y);
+ const int maxsinglelinewidth + dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
+
+ do {
+ in_height = DIV_ROUND_UP(height, *decim_y);
+ in_width = DIV_ROUND_UP(width, *decim_x);
+ *core_clk = calc_core_clk_five_taps(channel, mgr_timings,
+ in_width, in_height, out_width, out_height, color_mode);
+
+ error = check_horiz_timing_omap3(channel, mgr_timings, pos_x,
+ in_width, in_height, out_width, out_height);
+
+ if (in_width > maxsinglelinewidth)
+ if (in_height > out_height &&
+ in_height < out_height * 2)
+ *five_taps = false;
+ if (!*five_taps)
+ *core_clk = dispc.feat->calc_core_clk(channel, in_width,
+ in_height, out_width, out_height);
+
+ error = (error || in_width > maxsinglelinewidth * 2 ||
+ (in_width > maxsinglelinewidth && *five_taps) ||
+ !*core_clk || *core_clk > dispc_core_clk_rate());
+ if (error) {
+ if (*decim_x = *decim_y) {
+ *decim_x = min_factor;
+ ++*decim_y;
+ } else {
+ swap(*decim_x, *decim_y);
+ if (*decim_x < *decim_y)
+ ++*decim_x;
+ }
+ }
+ } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
+
+ if (check_horiz_timing_omap3(channel, mgr_timings, pos_x, width, height,
+ out_width, out_height)){
+ DSSERR("horizontal timing too tight\n");
+ return -EINVAL;
+ }
+
+ if (in_width > (maxsinglelinewidth * 2)) {
+ DSSERR("Cannot setup scaling");
+ DSSERR("width exceeds maximum width possible");
+ return -EINVAL;
+ }
+
+ if (in_width > maxsinglelinewidth && *five_taps) {
+ DSSERR("cannot setup scaling with five taps");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int dispc_ovl_calc_scaling_44xx(enum omap_channel channel,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
+ u16 pos_x, unsigned long *core_clk)
+{
+ u16 in_width, in_width_max;
+ int decim_x_min = *decim_x;
+ u16 in_height = DIV_ROUND_UP(height, *decim_y);
+ const int maxsinglelinewidth + dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
+
+ in_width_max = dispc_core_clk_rate() /
+ DIV_ROUND_UP(dispc_mgr_pclk_rate(channel), out_width);
+ *decim_x = DIV_ROUND_UP(width, in_width_max);
+
+ *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min;
+ if (*decim_x > *x_predecim)
+ return -EINVAL;
+
+ do {
+ in_width = DIV_ROUND_UP(width, *decim_x);
+ } while (*decim_x <= *x_predecim &&
+ in_width > maxsinglelinewidth && ++*decim_x);
+
+ if (in_width > maxsinglelinewidth) {
+ DSSERR("Cannot scale width exceeds max line width");
+ return -EINVAL;
}
+
+ *core_clk = dispc.feat->calc_core_clk(channel, in_width, in_height,
+ out_width, out_height);
+ return 0;
}
static int dispc_ovl_calc_scaling(enum omap_plane plane,
@@ -1988,12 +2156,9 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
{
struct omap_overlay *ovl = omap_dss_get_overlay(plane);
const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
- const int maxsinglelinewidth - dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
const int max_decim_limit = 16;
unsigned long core_clk = 0;
- int decim_x, decim_y, error, min_factor;
- u16 in_width, in_height, in_width_max = 0;
+ int decim_x, decim_y, ret;
if (width = out_width && height = out_height)
return 0;
@@ -2017,118 +2182,17 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale);
decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale);
- min_factor = min(decim_x, decim_y);
-
if (decim_x > *x_predecim || out_width > width * 8)
return -EINVAL;
if (decim_y > *y_predecim || out_height > height * 8)
return -EINVAL;
- if (cpu_is_omap24xx()) {
- *five_taps = false;
-
- do {
- in_height = DIV_ROUND_UP(height, decim_y);
- in_width = DIV_ROUND_UP(width, decim_x);
- core_clk = calc_core_clk(channel, in_width, in_height,
- out_width, out_height);
- error = (in_width > maxsinglelinewidth || !core_clk ||
- core_clk > dispc_core_clk_rate());
- if (error) {
- if (decim_x = decim_y) {
- decim_x = min_factor;
- decim_y++;
- } else {
- swap(decim_x, decim_y);
- if (decim_x < decim_y)
- decim_x++;
- }
- }
- } while (decim_x <= *x_predecim && decim_y <= *y_predecim &&
- error);
-
- if (in_width > maxsinglelinewidth) {
- DSSERR("Cannot scale max input width exceeded");
- return -EINVAL;
- }
- } else if (cpu_is_omap34xx()) {
-
- do {
- in_height = DIV_ROUND_UP(height, decim_y);
- in_width = DIV_ROUND_UP(width, decim_x);
- core_clk = calc_core_clk_five_taps(channel, mgr_timings,
- in_width, in_height, out_width, out_height,
- color_mode);
-
- error = check_horiz_timing_omap3(channel, mgr_timings,
- pos_x, in_width, in_height, out_width,
- out_height);
-
- if (in_width > maxsinglelinewidth)
- if (in_height > out_height &&
- in_height < out_height * 2)
- *five_taps = false;
- if (!*five_taps)
- core_clk = calc_core_clk(channel, in_width,
- in_height, out_width, out_height);
- error = (error || in_width > maxsinglelinewidth * 2 ||
- (in_width > maxsinglelinewidth && *five_taps) ||
- !core_clk || core_clk > dispc_core_clk_rate());
- if (error) {
- if (decim_x = decim_y) {
- decim_x = min_factor;
- decim_y++;
- } else {
- swap(decim_x, decim_y);
- if (decim_x < decim_y)
- decim_x++;
- }
- }
- } while (decim_x <= *x_predecim && decim_y <= *y_predecim
- && error);
-
- if (check_horiz_timing_omap3(channel, mgr_timings, pos_x, width,
- height, out_width, out_height)){
- DSSERR("horizontal timing too tight\n");
- return -EINVAL;
- }
-
- if (in_width > (maxsinglelinewidth * 2)) {
- DSSERR("Cannot setup scaling");
- DSSERR("width exceeds maximum width possible");
- return -EINVAL;
- }
-
- if (in_width > maxsinglelinewidth && *five_taps) {
- DSSERR("cannot setup scaling with five taps");
- return -EINVAL;
- }
- } else {
- int decim_x_min = decim_x;
- in_height = DIV_ROUND_UP(height, decim_y);
- in_width_max = dispc_core_clk_rate() /
- DIV_ROUND_UP(dispc_mgr_pclk_rate(channel),
- out_width);
- decim_x = DIV_ROUND_UP(width, in_width_max);
-
- decim_x = decim_x > decim_x_min ? decim_x : decim_x_min;
- if (decim_x > *x_predecim)
- return -EINVAL;
-
- do {
- in_width = DIV_ROUND_UP(width, decim_x);
- } while (decim_x <= *x_predecim &&
- in_width > maxsinglelinewidth && decim_x++);
-
- if (in_width > maxsinglelinewidth) {
- DSSERR("Cannot scale width exceeds max line width");
- return -EINVAL;
- }
-
- core_clk = calc_core_clk(channel, in_width, in_height,
- out_width, out_height);
- }
+ ret = dispc.feat->calc_scaling(channel, mgr_timings, width, height,
+ out_width, out_height, color_mode, five_taps, x_predecim,
+ y_predecim, &decim_x, &decim_y, pos_x, &core_clk);
+ if (ret)
+ return ret;
DSSDBG("required core clk rate = %lu Hz\n", core_clk);
DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate());
@@ -2604,24 +2668,13 @@ static bool _dispc_mgr_size_ok(u16 width, u16 height)
static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
int vsw, int vfp, int vbp)
{
- if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
- if (hsw < 1 || hsw > 64 ||
- hfp < 1 || hfp > 256 ||
- hbp < 1 || hbp > 256 ||
- vsw < 1 || vsw > 64 ||
- vfp < 0 || vfp > 255 ||
- vbp < 0 || vbp > 255)
- return false;
- } else {
- if (hsw < 1 || hsw > 256 ||
- hfp < 1 || hfp > 4096 ||
- hbp < 1 || hbp > 4096 ||
- vsw < 1 || vsw > 256 ||
- vfp < 0 || vfp > 4095 ||
- vbp < 0 || vbp > 4095)
- return false;
- }
-
+ if (hsw < 1 || hsw > dispc.feat->sw_max ||
+ hfp < 1 || hfp > dispc.feat->hp_max ||
+ hbp < 1 || hbp > dispc.feat->hp_max ||
+ vsw < 1 || vsw > dispc.feat->sw_max ||
+ vfp < 0 || vfp > dispc.feat->vp_max ||
+ vbp < 0 || vbp > dispc.feat->vp_max)
+ return false;
return true;
}
@@ -2653,19 +2706,12 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
u32 timing_h, timing_v, l;
bool onoff, rf, ipc;
- if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
- timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) |
- FLD_VAL(hbp-1, 27, 20);
-
- timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) |
- FLD_VAL(vbp, 27, 20);
- } else {
- timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) |
- FLD_VAL(hbp-1, 31, 20);
-
- timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) |
- FLD_VAL(vbp, 31, 20);
- }
+ timing_h = FLD_VAL(hsw-1, dispc.feat->sw_start, 0) |
+ FLD_VAL(hfp-1, dispc.feat->fp_start, 8) |
+ FLD_VAL(hbp-1, dispc.feat->bp_start, 20);
+ timing_v = FLD_VAL(vsw-1, dispc.feat->sw_start, 0) |
+ FLD_VAL(vfp, dispc.feat->fp_start, 8) |
+ FLD_VAL(vbp, dispc.feat->bp_start, 20);
dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
@@ -3671,6 +3717,79 @@ static void _omap_dispc_initial_config(void)
dispc_ovl_enable_zorder_planes();
}
+static const struct dispc_features omap24xx_dispc_feats __initconst = {
+ .hp_max = 256,
+ .vp_max = 255,
+ .sw_max = 64,
+ .sw_start = 5,
+ .fp_start = 15,
+ .bp_start = 27,
+ .calc_scaling = dispc_ovl_calc_scaling_24xx,
+ .calc_core_clk = calc_core_clk_24xx,
+};
+
+static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = {
+ .hp_max = 256,
+ .vp_max = 255,
+ .sw_max = 64,
+ .sw_start = 5,
+ .fp_start = 15,
+ .bp_start = 27,
+ .calc_scaling = dispc_ovl_calc_scaling_34xx,
+ .calc_core_clk = calc_core_clk_34xx,
+};
+
+static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = {
+ .hp_max = 4096,
+ .vp_max = 4095,
+ .sw_max = 256,
+ .sw_start = 7,
+ .fp_start = 19,
+ .bp_start = 31,
+ .calc_scaling = dispc_ovl_calc_scaling_34xx,
+ .calc_core_clk = calc_core_clk_34xx,
+};
+
+static const struct dispc_features omap44xx_dispc_feats __initconst = {
+ .hp_max = 4096,
+ .vp_max = 4095,
+ .sw_max = 256,
+ .sw_start = 7,
+ .fp_start = 19,
+ .bp_start = 31,
+ .calc_scaling = dispc_ovl_calc_scaling_44xx,
+ .calc_core_clk = calc_core_clk_44xx,
+};
+
+static int __init dispc_init_features(struct device *dev)
+{
+ struct dispc_features *feat = devm_kzalloc(dev, sizeof(*feat),
+ GFP_KERNEL);
+ if (!feat) {
+ dev_err(dev, "Failed to allocate DISPC Features\n");
+ return -ENOMEM;
+ }
+
+ if (cpu_is_omap24xx()) {
+ memcpy(feat, &omap24xx_dispc_feats, sizeof(*feat));
+ } else if (cpu_is_omap34xx()) {
+ if (omap_rev() < OMAP3430_REV_ES3_0)
+ memcpy(feat, &omap34xx_rev1_0_dispc_feats,
+ sizeof(*feat));
+ else
+ memcpy(feat, &omap34xx_rev3_0_dispc_feats,
+ sizeof(*feat));
+ } else if (cpu_is_omap44xx()) {
+ memcpy(feat, &omap44xx_dispc_feats, sizeof(*feat));
+ } else {
+ return -ENODEV;
+ }
+
+ dispc.feat = feat;
+
+ return 0;
+}
+
/* DISPC HW IP initialisation */
static int __init omap_dispchw_probe(struct platform_device *pdev)
{
@@ -3681,6 +3800,10 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
dispc.pdev = pdev;
+ r = dispc_init_features(&dispc.pdev->dev);
+ if (r)
+ return r;
+
spin_lock_init(&dispc.irq_lock);
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
--
1.7.10
^ permalink raw reply related
* [PATCH V5 2/6] OMAPDSS: DSS: Remove redundant functions
From: Chandrabhanu Mahapatra @ 2012-08-20 13:35 UTC (permalink / raw)
To: tomi.valkeinen; +Cc: linux-omap, linux-fbdev, Chandrabhanu Mahapatra
In-Reply-To: <cover.1345468541.git.cmahapatra@ti.com>
Functions dss_calc_clock_rates() and dss_get_clock_div() are removed as these
functions have become redundant and no longer used.
Signed-off-by: Chandrabhanu Mahapatra <cmahapatra@ti.com>
---
drivers/video/omap2/dss/dss.c | 45 -----------------------------------------
drivers/video/omap2/dss/dss.h | 2 --
2 files changed, 47 deletions(-)
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 4491ab7..10566ae 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -431,31 +431,6 @@ enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
}
}
-/* calculate clock rates using dividers in cinfo */
-int dss_calc_clock_rates(struct dss_clock_info *cinfo)
-{
- if (dss.dpll4_m4_ck) {
- unsigned long prate;
- u16 fck_div_max = 16;
-
- if (cpu_is_omap3630() || cpu_is_omap44xx())
- fck_div_max = 32;
-
- if (cinfo->fck_div > fck_div_max || cinfo->fck_div = 0)
- return -EINVAL;
-
- prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
-
- cinfo->fck = prate / cinfo->fck_div;
- } else {
- if (cinfo->fck_div != 0)
- return -EINVAL;
- cinfo->fck = clk_get_rate(dss.dss_clk);
- }
-
- return 0;
-}
-
int dss_set_clock_div(struct dss_clock_info *cinfo)
{
if (dss.dpll4_m4_ck) {
@@ -478,26 +453,6 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
return 0;
}
-int dss_get_clock_div(struct dss_clock_info *cinfo)
-{
- cinfo->fck = clk_get_rate(dss.dss_clk);
-
- if (dss.dpll4_m4_ck) {
- unsigned long prate;
-
- prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
-
- if (cpu_is_omap3630() || cpu_is_omap44xx())
- cinfo->fck_div = prate / (cinfo->fck);
- else
- cinfo->fck_div = prate / (cinfo->fck / 2);
- } else {
- cinfo->fck_div = 0;
- }
-
- return 0;
-}
-
unsigned long dss_get_dpll4_rate(void)
{
if (dss.dpll4_m4_ck)
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index f67afe7..33c0952 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -296,9 +296,7 @@ void dss_set_venc_output(enum omap_dss_venc_type type);
void dss_set_dac_pwrdn_bgz(bool enable);
unsigned long dss_get_dpll4_rate(void);
-int dss_calc_clock_rates(struct dss_clock_info *cinfo);
int dss_set_clock_div(struct dss_clock_info *cinfo);
-int dss_get_clock_div(struct dss_clock_info *cinfo);
int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
struct dispc_clock_info *dispc_cinfo);
--
1.7.10
^ permalink raw reply related
* [PATCH V5 3/6] OMAPDSS: DSS: Cleanup cpu_is_xxxx checks
From: Chandrabhanu Mahapatra @ 2012-08-20 13:35 UTC (permalink / raw)
To: tomi.valkeinen; +Cc: linux-omap, linux-fbdev, Chandrabhanu Mahapatra
In-Reply-To: <cover.1345468541.git.cmahapatra@ti.com>
All the cpu_is checks have been moved to dss_init_features function providing a
much more generic and cleaner interface. The OMAP version and revision specific
initializations in various functions are cleaned and the necessary data are
moved to dss_features structure which is local to dss.c.
Signed-off-by: Chandrabhanu Mahapatra <cmahapatra@ti.com>
---
drivers/video/omap2/dss/dss.c | 117 ++++++++++++++++++++++++++---------------
1 file changed, 76 insertions(+), 41 deletions(-)
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 10566ae..f6d3d0a 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -31,6 +31,7 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/gfp.h>
#include <video/omapdss.h>
@@ -65,6 +66,12 @@ struct dss_reg {
static int dss_runtime_get(void);
static void dss_runtime_put(void);
+struct dss_features {
+ u16 fck_div_max;
+ int dss_fck_multiplier;
+ char *clk_name;
+};
+
static struct {
struct platform_device *pdev;
void __iomem *base;
@@ -83,6 +90,8 @@ static struct {
bool ctx_valid;
u32 ctx[DSS_SZ_REGS / sizeof(u32)];
+
+ const struct dss_features *feat;
} dss;
static const char * const dss_generic_clk_source_names[] = {
@@ -91,6 +100,30 @@ static const char * const dss_generic_clk_source_names[] = {
[OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK",
};
+static const struct dss_features omap24xx_dss_feats __initconst = {
+ .fck_div_max = 16,
+ .dss_fck_multiplier = 2,
+ .clk_name = NULL,
+};
+
+static const struct dss_features omap34xx_dss_feats __initconst = {
+ .fck_div_max = 16,
+ .dss_fck_multiplier = 2,
+ .clk_name = "dpll4_m4_ck",
+};
+
+static const struct dss_features omap3630_dss_feats __initconst = {
+ .fck_div_max = 32,
+ .dss_fck_multiplier = 1,
+ .clk_name = "dpll4_m4_ck",
+};
+
+static const struct dss_features omap44xx_dss_feats __initconst = {
+ .fck_div_max = 32,
+ .dss_fck_multiplier = 1,
+ .clk_name = "dpll_per_m5x2_ck",
+};
+
static inline void dss_write_reg(const struct dss_reg idx, u32 val)
{
__raw_writel(val, dss.base + idx.idx);
@@ -236,7 +269,6 @@ const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
return dss_generic_clk_source_names[clk_src];
}
-
void dss_dump_clocks(struct seq_file *s)
{
unsigned long dpll4_ck_rate;
@@ -259,18 +291,10 @@ void dss_dump_clocks(struct seq_file *s)
seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
- if (cpu_is_omap3630() || cpu_is_omap44xx())
- seq_printf(s, "%s (%s) = %lu / %lu = %lu\n",
- fclk_name, fclk_real_name,
- dpll4_ck_rate,
- dpll4_ck_rate / dpll4_m4_ck_rate,
- fclk_rate);
- else
- seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n",
- fclk_name, fclk_real_name,
- dpll4_ck_rate,
- dpll4_ck_rate / dpll4_m4_ck_rate,
- fclk_rate);
+ seq_printf(s, "%s (%s) = %lu / %lu * %d = %lu\n",
+ fclk_name, fclk_real_name, dpll4_ck_rate,
+ dpll4_ck_rate / dpll4_m4_ck_rate,
+ dss.feat->dss_fck_multiplier, fclk_rate);
} else {
seq_printf(s, "%s (%s) = %lu\n",
fclk_name, fclk_real_name,
@@ -470,7 +494,7 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
unsigned long fck, max_dss_fck;
- u16 fck_div, fck_div_max = 16;
+ u16 fck_div;
int match = 0;
int min_fck_per_pck;
@@ -480,9 +504,8 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
fck = clk_get_rate(dss.dss_clk);
- if (req_pck = dss.cache_req_pck &&
- ((cpu_is_omap34xx() && prate = dss.cache_prate) ||
- dss.cache_dss_cinfo.fck = fck)) {
+ if (req_pck = dss.cache_req_pck && 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;
@@ -519,16 +542,10 @@ retry:
goto found;
} else {
- if (cpu_is_omap3630() || cpu_is_omap44xx())
- fck_div_max = 32;
-
- for (fck_div = fck_div_max; fck_div > 0; --fck_div) {
+ for (fck_div = dss.feat->fck_div_max; fck_div > 0; --fck_div) {
struct dispc_clock_info cur_dispc;
- if (fck_div_max = 32)
- fck = prate / fck_div;
- else
- fck = prate / fck_div * 2;
+ fck = prate / fck_div * dss.feat->dss_fck_multiplier;
if (fck > max_dss_fck)
continue;
@@ -645,22 +662,11 @@ static int dss_get_clocks(void)
dss.dss_clk = clk;
- if (cpu_is_omap34xx()) {
- clk = clk_get(NULL, "dpll4_m4_ck");
- if (IS_ERR(clk)) {
- DSSERR("Failed to get dpll4_m4_ck\n");
- r = PTR_ERR(clk);
- goto err;
- }
- } else if (cpu_is_omap44xx()) {
- clk = clk_get(NULL, "dpll_per_m5x2_ck");
- if (IS_ERR(clk)) {
- DSSERR("Failed to get dpll_per_m5x2_ck\n");
- r = PTR_ERR(clk);
- goto err;
- }
- } else { /* omap24xx */
- clk = NULL;
+ clk = clk_get(NULL, dss.feat->clk_name);
+ if (IS_ERR(clk)) {
+ DSSERR("Failed to get %s\n", dss.feat->clk_name);
+ r = PTR_ERR(clk);
+ goto err;
}
dss.dpll4_m4_ck = clk;
@@ -716,6 +722,31 @@ void dss_debug_dump_clocks(struct seq_file *s)
}
#endif
+static int __init dss_init_features(struct device *dev)
+{
+ struct dss_features *feat = devm_kzalloc(dev, sizeof(*feat),
+ GFP_KERNEL);
+ if (!feat) {
+ dev_err(dev, "Failed to allocate local DSS Features\n");
+ return -ENOMEM;
+ }
+
+ if (cpu_is_omap24xx())
+ memcpy(feat, &omap24xx_dss_feats, sizeof(*feat));
+ else if (cpu_is_omap34xx())
+ memcpy(feat, &omap34xx_dss_feats, sizeof(*feat));
+ else if (cpu_is_omap3630())
+ memcpy(feat, &omap3630_dss_feats, sizeof(*feat));
+ else if (cpu_is_omap44xx())
+ memcpy(feat, &omap44xx_dss_feats, sizeof(*feat));
+ else
+ return -ENODEV;
+
+ dss.feat = feat;
+
+ return 0;
+}
+
/* DSS HW IP initialisation */
static int __init omap_dsshw_probe(struct platform_device *pdev)
{
@@ -725,6 +756,10 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
dss.pdev = pdev;
+ r = dss_init_features(&dss.pdev->dev);
+ if (r)
+ return r;
+
dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
if (!dss_mem) {
DSSERR("can't get IORESOURCE_MEM DSS\n");
--
1.7.10
^ permalink raw reply related
* [PATCH V5 4/6] OMAPDSS: VENC: Remove cpu_is_xxxx checks
From: Chandrabhanu Mahapatra @ 2012-08-20 13:36 UTC (permalink / raw)
To: tomi.valkeinen; +Cc: linux-omap, linux-fbdev, Chandrabhanu Mahapatra
In-Reply-To: <cover.1345468541.git.cmahapatra@ti.com>
OMAP4 checks are removed from VENC to provide it a cleaner interface. These
checks were introduced by patches "HACK: OMAP: DSS2: VENC: disable VENC on OMAP4
to prevent crash" (ba02fa37de) by Tomi Valkeinen <tomi.valkeinen@ti.com> and
"OMAPDSS: VENC: fix NULL pointer dereference in DSS2 VENC sysfs debug attr on
OMAP4" (cc1d3e032d) by Danny Kukawka <danny.kukawka@bisect.de> to prevent VENC
from crashing OMAP4 kernel. An alternative approach is used to do the same in
later patches.
Signed-off-by: Chandrabhanu Mahapatra <cmahapatra@ti.com>
---
drivers/video/omap2/dss/venc.c | 11 -----------
1 file changed, 11 deletions(-)
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index 3a22087..8fc165a 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -752,11 +752,6 @@ static void venc_dump_regs(struct seq_file *s)
{
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
- if (cpu_is_omap44xx()) {
- seq_printf(s, "VENC currently disabled on OMAP44xx\n");
- return;
- }
-
if (venc_runtime_get())
return;
@@ -971,16 +966,10 @@ static struct platform_driver omap_venchw_driver = {
int __init venc_init_platform_driver(void)
{
- if (cpu_is_omap44xx())
- return 0;
-
return platform_driver_probe(&omap_venchw_driver, omap_venchw_probe);
}
void __exit venc_uninit_platform_driver(void)
{
- if (cpu_is_omap44xx())
- return;
-
platform_driver_unregister(&omap_venchw_driver);
}
--
1.7.10
^ permalink raw reply related
* [PATCH V5 5/6] ARM: OMAP: Disable venc for OMAP4
From: Chandrabhanu Mahapatra @ 2012-08-20 13:36 UTC (permalink / raw)
To: tomi.valkeinen, tony, paul
Cc: linux-omap, linux-fbdev, Chandrabhanu Mahapatra
In-Reply-To: <cover.1345468541.git.cmahapatra@ti.com>
This is a alternative to "HACK: OMAP: DSS2: VENC: disable VENC on OMAP4 to
prevent crash" (ba02fa37de) by Tomi Valkeinen <tomi.valkeinen@ti.com> to prevent
VENC from crashing OMAP4 kernel. This prevents OMAPDSS from initial registration
of a device for VENC on OMAP4.
Signed-off-by: Chandrabhanu Mahapatra <cmahapatra@ti.com>
---
arch/arm/mach-omap2/display.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c
index af1ed7d..ee40739 100644
--- a/arch/arm/mach-omap2/display.c
+++ b/arch/arm/mach-omap2/display.c
@@ -95,7 +95,6 @@ static const struct omap_dss_hwmod_data omap4_dss_hwmod_data[] __initdata = {
{ "dss_core", "omapdss_dss", -1 },
{ "dss_dispc", "omapdss_dispc", -1 },
{ "dss_rfbi", "omapdss_rfbi", -1 },
- { "dss_venc", "omapdss_venc", -1 },
{ "dss_dsi1", "omapdss_dsi", 0 },
{ "dss_dsi2", "omapdss_dsi", 1 },
{ "dss_hdmi", "omapdss_hdmi", -1 },
--
1.7.10
^ permalink raw reply related
* [PATCH V5 6/6] OMAPDSS: DPI: Remove cpu_is_xxxx checks
From: Chandrabhanu Mahapatra @ 2012-08-20 13:36 UTC (permalink / raw)
To: tomi.valkeinen; +Cc: linux-omap, linux-fbdev, Chandrabhanu Mahapatra
In-Reply-To: <cover.1345468541.git.cmahapatra@ti.com>
The OMAP3 checks have been removed and replaced by a dss feature
FEAT_DPI_USES_VDDS_DSI for cleaner implementation. The patches
"OMAP: DSS2: enable VDDS_DSI when using DPI" (8a2cfea8cc) by Tomi Valkeinen
<tomi.valkeinen@nokia.com> and "ARM: omap: fix oops in
drivers/video/omap2/dss/dpi.c" (4041071571) by Russell King
<rmk+kernel@arm.linux.org.uk> had introduced these checks. As it is evident
from these patches a dependency exists for some DSS pins on VDDS_DSI which is
better shown by dss feature FEAT_DPI_USES_VDDS_DSI.
Signed-off-by: Chandrabhanu Mahapatra <cmahapatra@ti.com>
---
drivers/video/omap2/dss/dpi.c | 12 +++++++-----
drivers/video/omap2/dss/dss_features.c | 1 +
drivers/video/omap2/dss/dss_features.h | 1 +
3 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index 3266be2..b97f7b8 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -34,6 +34,7 @@
#include <plat/cpu.h>
#include "dss.h"
+#include "dss_features.h"
static struct {
struct regulator *vdds_dsi_reg;
@@ -169,7 +170,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
{
int r;
- if (cpu_is_omap34xx() && !dpi.vdds_dsi_reg) {
+ if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi.vdds_dsi_reg) {
DSSERR("no VDSS_DSI regulator\n");
return -ENODEV;
}
@@ -185,7 +186,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
goto err_start_dev;
}
- if (cpu_is_omap34xx()) {
+ if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) {
r = regulator_enable(dpi.vdds_dsi_reg);
if (r)
goto err_reg_enable;
@@ -229,7 +230,7 @@ err_dsi_pll_init:
err_get_dsi:
dispc_runtime_put();
err_get_dispc:
- if (cpu_is_omap34xx())
+ if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
regulator_disable(dpi.vdds_dsi_reg);
err_reg_enable:
omap_dss_stop_device(dssdev);
@@ -250,7 +251,7 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
dispc_runtime_put();
- if (cpu_is_omap34xx())
+ if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
regulator_disable(dpi.vdds_dsi_reg);
omap_dss_stop_device(dssdev);
@@ -329,7 +330,8 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev)
{
DSSDBG("init_display\n");
- if (cpu_is_omap34xx() && dpi.vdds_dsi_reg = NULL) {
+ if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) &&
+ dpi.vdds_dsi_reg = NULL) {
struct regulator *vdds_dsi;
vdds_dsi = dss_get_vdds_dsi();
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index 9387097..2fe39d6 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -373,6 +373,7 @@ static const enum dss_feat_id omap3430_dss_feat_list[] = {
FEAT_ALPHA_FIXED_ZORDER,
FEAT_FIFO_MERGE,
FEAT_OMAP3_DSI_FIFO_BUG,
+ FEAT_DPI_USES_VDDS_DSI,
};
static const enum dss_feat_id omap3630_dss_feat_list[] = {
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h
index 996ffcb..26d43a4 100644
--- a/drivers/video/omap2/dss/dss_features.h
+++ b/drivers/video/omap2/dss/dss_features.h
@@ -50,6 +50,7 @@ enum dss_feat_id {
FEAT_DSI_VC_OCP_WIDTH,
FEAT_DSI_REVERSE_TXCLKESC,
FEAT_DSI_GNQ,
+ FEAT_DPI_USES_VDDS_DSI,
FEAT_HDMI_CTS_SWMODE,
FEAT_HDMI_AUDIO_USE_MCLK,
FEAT_HANDLE_UV_SEPARATE,
--
1.7.10
^ permalink raw reply related
* Re: i.MX27 SLCDC driver
From: Matt Sealey @ 2012-08-20 15:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <502DEDCD.9050303@gmail.com>
On Fri, Aug 17, 2012 at 2:07 AM, Gaëtan Carlier <gcembed@gmail.com> wrote:
> Hello,
> I would like to write the driver for SmartLCD controller of i.MX27. This
> kind of interface needs a LCD with an embedded graphic controller partially
> controlled by GPIO. I want to link it with an OLED DD12832.
>
> How have I to write this driver : One driver for SLCDC and one driver for
> DD12832 ? How to link them together ?
>
> Maybe use similar philosophy than soc-camera ?
Please use DRM if you can. That way your SLCDC controller is a "crtc"
and your OLED panel is a combination "encoder" and "connector". The
DRM subsystem isn't by far the best solution since it is designed
around PCI-class graphics cards and the split is intended for those
and not for more tightly-knit LCDC+display combinations, but it does
split things the way you're thinking and with a little extra code it
will do exactly what you want if a little less efficient than your
attached driver.
I was sure Sascha had a driver for this already;
http://git.pengutronix.de/?p=imx/linux-2.6.git;a=commit;hÃ33f47fa185edfd1c9d889fc8af040dd557b02c
- it should not be too hard to add your panel and the specific gpio
control as an encoder/connector. Maybe with a user this can actually
go upstream.
--
Matt Sealey <matt@genesi-usa.com>
Product Development Analyst, Genesi USA, Inc.
^ permalink raw reply
* Re: i.MX27 SLCDC driver
From: Gaëtan Carlier @ 2012-08-20 16:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAKGA1bmuUxiHbkF0n+bOx81EBQujuhu+piDsfHSVo2LejoPmcw@mail.gmail.com>
Hello
On 08/20/2012 05:21 PM, Matt Sealey wrote:
> On Fri, Aug 17, 2012 at 2:07 AM, Gaëtan Carlier <gcembed@gmail.com> wrote:
>> Hello,
>> I would like to write the driver for SmartLCD controller of i.MX27. This
>> kind of interface needs a LCD with an embedded graphic controller partially
>> controlled by GPIO. I want to link it with an OLED DD12832.
>>
>> How have I to write this driver : One driver for SLCDC and one driver for
>> DD12832 ? How to link them together ?
>>
>> Maybe use similar philosophy than soc-camera ?
>
> Please use DRM if you can. That way your SLCDC controller is a "crtc"
> and your OLED panel is a combination "encoder" and "connector". The
> DRM subsystem isn't by far the best solution since it is designed
> around PCI-class graphics cards and the split is intended for those
> and not for more tightly-knit LCDC+display combinations, but it does
> split things the way you're thinking and with a little extra code it
> will do exactly what you want if a little less efficient than your
> attached driver.
>
> I was sure Sascha had a driver for this already;
> http://git.pengutronix.de/?p=imx/linux-2.6.git;a=commit;hÃ33f47fa185edfd1c9d889fc8af040dd557b02c
> - it should not be too hard to add your panel and the specific gpio
> control as an encoder/connector. Maybe with a user this can actually
> go upstream.
>
Thanks a lot for your advises. I will study this code.
Regards,
Gaëtan Carlier.
^ permalink raw reply
* [PATCH 0/7] framebuffer fixes
From: Mikulas Patocka @ 2012-08-20 18:04 UTC (permalink / raw)
To: linux-fbdev
Hi
Here I'm sending 7 patches for Linux framebuffer.
The first patch fixes a bug in cfb_copyarea if the position is not aligned
on 4-byte or 8-byte boundary.
The next three patches fix bugs on mach64 and remove videomode
restriction.
The next three patches fix bugs on tga and remove videomode restriction.
Mikulas
^ permalink raw reply
* [PATCH 1/7] framebuffer: fix cfb_copyarea
From: Mikulas Patocka @ 2012-08-20 18:05 UTC (permalink / raw)
To: linux-fbdev
framebuffer: fix cfb_copyarea
The function cfb_copyarea is buggy when the copy operation is not aligned on
long boundary (4 bytes on 32-bit machines, 8 bytes on 64-bit machines).
How to reproduce:
- use x86-64 machine
- use a framebuffer driver without acceleration (for example uvesafb)
- set the framebuffer to 8-bit depth
(for example fbset -a 1024x768-60 -depth 8)
- load a font with character width that is not a multiple of 8 pixels
note: the console-tools package cannot load a font that has
width different from 8 pixels. You need to install the packages
"kbd" and "console-terminus" and use the program "setfont" to
set font width (for example: setfont Uni2-Terminus20x10)
- move some text left and right on the bash command line and you get a
screen corruption
To expose more bugs,
put this line to the end of uvesafb_init_info:
info->flags |= FBINFO_HWACCEL_COPYAREA | FBINFO_READS_FAST;
- Now framebuffer console will use cfb_copyarea for console scrolling.
You get a screen corruption when console is scrolled.
This patch is a rewrite of cfb_copyarea. It fixes the bugs, with this
patch, console scrolling in 8-bit depth with a font width that is not a
multiple of 8 pixels works fine.
The cfb_copyarea code was very buggy and it looks like it was written
and never tried with non-8-pixel font.
Signed-off-by: Mikulas Patocka <mikulas@artax.karlin.mff.cuni.cz>
Cc: stable@kernel.org
---
drivers/video/cfbcopyarea.c | 153 ++++++++++++++++++++++----------------------
1 file changed, 78 insertions(+), 75 deletions(-)
Index: linux-3.4.3-fast/drivers/video/cfbcopyarea.c
=================================--- linux-3.4.3-fast.orig/drivers/video/cfbcopyarea.c 2012-07-02 02:02:08.000000000 +0200
+++ linux-3.4.3-fast/drivers/video/cfbcopyarea.c 2012-07-02 02:03:33.000000000 +0200
@@ -43,13 +43,22 @@
*/
static void
-bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
- const unsigned long __iomem *src, int src_idx, int bits,
+bitcpy(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx,
+ const unsigned long __iomem *src, unsigned src_idx, int bits,
unsigned n, u32 bswapmask)
{
unsigned long first, last;
int const shift = dst_idx-src_idx;
- int left, right;
+
+#if 0
+ /*
+ * If you suspect bug in this function, compare it with this simple
+ * memmove implementation.
+ */
+ fb_memmove((char *)dst + ((dst_idx & (bits - 1))) / 8,
+ (char *)src + ((src_idx & (bits - 1))) / 8, n / 8);
+ return;
+#endif
first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
@@ -98,9 +107,8 @@ bitcpy(struct fb_info *p, unsigned long
unsigned long d0, d1;
int m;
- right = shift & (bits - 1);
- left = -shift & (bits - 1);
- bswapmask &= shift;
+ int const left = shift & (bits - 1);
+ int const right = -shift & (bits - 1);
if (dst_idx+n <= bits) {
// Single destination word
@@ -110,15 +118,15 @@ bitcpy(struct fb_info *p, unsigned long
d0 = fb_rev_pixels_in_long(d0, bswapmask);
if (shift > 0) {
// Single source word
- d0 >>= right;
+ d0 <<= left;
} else if (src_idx+n <= bits) {
// Single source word
- d0 <<= left;
+ d0 >>= right;
} else {
// 2 source words
d1 = FB_READL(src + 1);
d1 = fb_rev_pixels_in_long(d1, bswapmask);
- d0 = d0<<left | d1>>right;
+ d0 = d0 >> right | d1 << left;
}
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
@@ -135,60 +143,59 @@ bitcpy(struct fb_info *p, unsigned long
if (shift > 0) {
// Single source word
d1 = d0;
- d0 >>= right;
- dst++;
+ d0 <<= left;
n -= bits - dst_idx;
} else {
// 2 source words
d1 = FB_READL(src++);
d1 = fb_rev_pixels_in_long(d1, bswapmask);
- d0 = d0<<left | d1>>right;
- dst++;
+ d0 = d0 >> right | d1 << left;
n -= bits - dst_idx;
}
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
d0 = d1;
+ dst++;
// Main chunk
m = n % bits;
n /= bits;
while ((n >= 4) && !bswapmask) {
d1 = FB_READL(src++);
- FB_WRITEL(d0 << left | d1 >> right, dst++);
+ FB_WRITEL(d0 >> right | d1 << left, dst++);
d0 = d1;
d1 = FB_READL(src++);
- FB_WRITEL(d0 << left | d1 >> right, dst++);
+ FB_WRITEL(d0 >> right | d1 << left, dst++);
d0 = d1;
d1 = FB_READL(src++);
- FB_WRITEL(d0 << left | d1 >> right, dst++);
+ FB_WRITEL(d0 >> right | d1 << left, dst++);
d0 = d1;
d1 = FB_READL(src++);
- FB_WRITEL(d0 << left | d1 >> right, dst++);
+ FB_WRITEL(d0 >> right | d1 << left, dst++);
d0 = d1;
n -= 4;
}
while (n--) {
d1 = FB_READL(src++);
d1 = fb_rev_pixels_in_long(d1, bswapmask);
- d0 = d0 << left | d1 >> right;
+ d0 = d0 >> right | d1 << left;
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(d0, dst++);
d0 = d1;
}
// Trailing bits
- if (last) {
- if (m <= right) {
+ if (m) {
+ if (m <= bits - right) {
// Single source word
- d0 <<= left;
+ d0 >>= right;
} else {
// 2 source words
d1 = FB_READL(src);
d1 = fb_rev_pixels_in_long(d1,
bswapmask);
- d0 = d0<<left | d1>>right;
+ d0 = d0 >> right | d1 << left;
}
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
@@ -202,43 +209,46 @@ bitcpy(struct fb_info *p, unsigned long
*/
static void
-bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
- const unsigned long __iomem *src, int src_idx, int bits,
+bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx,
+ const unsigned long __iomem *src, unsigned src_idx, int bits,
unsigned n, u32 bswapmask)
{
unsigned long first, last;
int shift;
- dst += (n-1)/bits;
- src += (n-1)/bits;
- if ((n-1) % bits) {
- dst_idx += (n-1) % bits;
- dst += dst_idx >> (ffs(bits) - 1);
- dst_idx &= bits - 1;
- src_idx += (n-1) % bits;
- src += src_idx >> (ffs(bits) - 1);
- src_idx &= bits - 1;
- }
+#if 0
+ /*
+ * If you suspect bug in this function, compare it with this simple
+ * memmove implementation.
+ */
+ fb_memmove((char *)dst + ((dst_idx & (bits - 1))) / 8,
+ (char *)src + ((src_idx & (bits - 1))) / 8, n / 8);
+ return;
+#endif
+
+ dst += (dst_idx + n - 1) / bits;
+ src += (src_idx + n - 1) / bits;
+ dst_idx = (dst_idx + n - 1) % bits;
+ src_idx = (src_idx + n - 1) % bits;
shift = dst_idx-src_idx;
- first = fb_shifted_pixels_mask_long(p, bits - 1 - dst_idx, bswapmask);
- last = ~fb_shifted_pixels_mask_long(p, bits - 1 - ((dst_idx-n) % bits),
- bswapmask);
+ first = ~fb_shifted_pixels_mask_long(p, (dst_idx + 1) % bits, bswapmask);
+ last = fb_shifted_pixels_mask_long(p, (bits + dst_idx + 1 - n) % bits, bswapmask);
if (!shift) {
// Same alignment for source and dest
if ((unsigned long)dst_idx+1 >= n) {
// Single word
- if (last)
- first &= last;
- FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
+ if (first)
+ last &= first;
+ FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
} else {
// Multiple destination words
// Leading bits
- if (first != ~0UL) {
+ if (first) {
FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
dst--;
src--;
@@ -262,7 +272,7 @@ bitcpy_rev(struct fb_info *p, unsigned l
FB_WRITEL(FB_READL(src--), dst--);
// Trailing bits
- if (last)
+ if (last != -1UL)
FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
}
} else {
@@ -270,29 +280,28 @@ bitcpy_rev(struct fb_info *p, unsigned l
unsigned long d0, d1;
int m;
- int const left = -shift & (bits-1);
- int const right = shift & (bits-1);
- bswapmask &= shift;
+ int const left = shift & (bits-1);
+ int const right = -shift & (bits-1);
if ((unsigned long)dst_idx+1 >= n) {
// Single destination word
- if (last)
- first &= last;
+ if (first)
+ last &= first;
d0 = FB_READL(src);
if (shift < 0) {
// Single source word
- d0 <<= left;
+ d0 >>= right;
} else if (1+(unsigned long)src_idx >= n) {
// Single source word
- d0 >>= right;
+ d0 <<= left;
} else {
// 2 source words
d1 = FB_READL(src - 1);
d1 = fb_rev_pixels_in_long(d1, bswapmask);
- d0 = d0>>right | d1<<left;
+ d0 = d0 << left | d1 >> right;
}
d0 = fb_rev_pixels_in_long(d0, bswapmask);
- FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
+ FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
} else {
// Multiple destination words
/** We must always remember the last value read, because in case
@@ -307,12 +316,12 @@ bitcpy_rev(struct fb_info *p, unsigned l
if (shift < 0) {
// Single source word
d1 = d0;
- d0 <<= left;
+ d0 >>= right;
} else {
// 2 source words
d1 = FB_READL(src--);
d1 = fb_rev_pixels_in_long(d1, bswapmask);
- d0 = d0>>right | d1<<left;
+ d0 = d0 << left | d1 >> right;
}
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
@@ -325,39 +334,39 @@ bitcpy_rev(struct fb_info *p, unsigned l
n /= bits;
while ((n >= 4) && !bswapmask) {
d1 = FB_READL(src--);
- FB_WRITEL(d0 >> right | d1 << left, dst--);
+ FB_WRITEL(d0 << left | d1 >> right, dst--);
d0 = d1;
d1 = FB_READL(src--);
- FB_WRITEL(d0 >> right | d1 << left, dst--);
+ FB_WRITEL(d0 << left | d1 >> right, dst--);
d0 = d1;
d1 = FB_READL(src--);
- FB_WRITEL(d0 >> right | d1 << left, dst--);
+ FB_WRITEL(d0 << left | d1 >> right, dst--);
d0 = d1;
d1 = FB_READL(src--);
- FB_WRITEL(d0 >> right | d1 << left, dst--);
+ FB_WRITEL(d0 << left | d1 >> right, dst--);
d0 = d1;
n -= 4;
}
while (n--) {
d1 = FB_READL(src--);
d1 = fb_rev_pixels_in_long(d1, bswapmask);
- d0 = d0 >> right | d1 << left;
+ d0 = d0 << left | d1 >> right;
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(d0, dst--);
d0 = d1;
}
// Trailing bits
- if (last) {
- if (m <= left) {
+ if (m) {
+ if (m <= bits - left) {
// Single source word
- d0 >>= right;
+ d0 <<= left;
} else {
// 2 source words
d1 = FB_READL(src);
d1 = fb_rev_pixels_in_long(d1,
bswapmask);
- d0 = d0>>right | d1<<left;
+ d0 = d0 << left | d1 >> right;
}
d0 = fb_rev_pixels_in_long(d0, bswapmask);
FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
@@ -371,9 +380,9 @@ void cfb_copyarea(struct fb_info *p, con
u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
u32 height = area->height, width = area->width;
unsigned long const bits_per_line = p->fix.line_length*8u;
- unsigned long __iomem *dst = NULL, *src = NULL;
+ unsigned long __iomem *base = NULL;
int bits = BITS_PER_LONG, bytes = bits >> 3;
- int dst_idx = 0, src_idx = 0, rev_copy = 0;
+ unsigned dst_idx = 0, src_idx = 0, rev_copy = 0;
u32 bswapmask = fb_compute_bswapmask(p);
if (p->state != FBINFO_STATE_RUNNING)
@@ -389,7 +398,7 @@ void cfb_copyarea(struct fb_info *p, con
// split the base of the framebuffer into a long-aligned address and the
// index of the first bit
- dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
+ base = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
// add offset of source and target area
dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
@@ -402,20 +411,14 @@ void cfb_copyarea(struct fb_info *p, con
while (height--) {
dst_idx -= bits_per_line;
src_idx -= bits_per_line;
- dst += dst_idx >> (ffs(bits) - 1);
- dst_idx &= (bytes - 1);
- src += src_idx >> (ffs(bits) - 1);
- src_idx &= (bytes - 1);
- bitcpy_rev(p, dst, dst_idx, src, src_idx, bits,
+ bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits,
+ base + (src_idx / bits), src_idx % bits, bits,
width*p->var.bits_per_pixel, bswapmask);
}
} else {
while (height--) {
- dst += dst_idx >> (ffs(bits) - 1);
- dst_idx &= (bytes - 1);
- src += src_idx >> (ffs(bits) - 1);
- src_idx &= (bytes - 1);
- bitcpy(p, dst, dst_idx, src, src_idx, bits,
+ bitcpy(p, base + (dst_idx / bits), dst_idx % bits,
+ base + (src_idx / bits), src_idx % bits, bits,
width*p->var.bits_per_pixel, bswapmask);
dst_idx += bits_per_line;
src_idx += bits_per_line;
^ permalink raw reply
* [PATCH 2/7] aty: remove mode restriction
From: Mikulas Patocka @ 2012-08-20 18:06 UTC (permalink / raw)
To: linux-fbdev
aty: remove mode restriction
The mach64 video card works fine in 1920x1080 resolution,
there's no need to limit it.
Signed-off-by: Mikulas Patocka <mpatocka@artax.karlin.mff.cuni.cz>
---
drivers/video/aty/atyfb_base.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
Index: linux-3.6-rc2-fast/drivers/video/aty/atyfb_base.c
=================================--- linux-3.6-rc2-fast.orig/drivers/video/aty/atyfb_base.c 2012-08-18 04:07:55.000000000 +0200
+++ linux-3.6-rc2-fast/drivers/video/aty/atyfb_base.c 2012-08-18 04:09:09.000000000 +0200
@@ -861,8 +861,8 @@ static int aty_var_to_crtc(const struct
h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
- if ((xres > 1600) || (yres > 1200)) {
- FAIL("MACH64 chips are designed for max 1600x1200\n"
+ if ((xres > 1920) || (yres > 1200)) {
+ FAIL("MACH64 chips are designed for max 1920x1200\n"
"select another resolution.");
}
h_sync_strt = h_disp + var->right_margin;
^ permalink raw reply
* [PATCH 3/7] mach64: fix unaligned access on sparc64
From: Mikulas Patocka @ 2012-08-20 18:07 UTC (permalink / raw)
To: linux-fbdev
mach64: use unaligned access
This patch fixes mach64 to use unaligned access to the font bitmap.
This fixes unaligned access warning on sparc64 when 14x8 font is loaded.
On x86(64), unaligned access is handled on hardware, so both functions
le32_to_cpup and get_unaligned_le32 perform the same operation.
On RISC machines, unaligned access is not handled in hardware, so we
better use get_unaligned_le32 to avoid the unaligned trap and warning.
Signed-off-by: Mikulas Patocka <mikulas@artax.karlin.mff.cuni.cz>
Cc: stable@kernel.org
---
drivers/video/aty/mach64_accel.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
Index: linux-3.4.3-fast/drivers/video/aty/mach64_accel.c
=================================--- linux-3.4.3-fast.orig/drivers/video/aty/mach64_accel.c 2012-07-02 00:10:56.000000000 +0200
+++ linux-3.4.3-fast/drivers/video/aty/mach64_accel.c 2012-07-02 00:13:29.000000000 +0200
@@ -4,6 +4,7 @@
*/
#include <linux/delay.h>
+#include <asm/unaligned.h>
#include <linux/fb.h>
#include <video/mach64.h>
#include "atyfb.h"
@@ -419,7 +420,7 @@ void atyfb_imageblit(struct fb_info *inf
u32 *pbitmap, dwords = (src_bytes + 3) / 4;
for (pbitmap = (u32*)(image->data); dwords; dwords--, pbitmap++) {
wait_for_fifo(1, par);
- aty_st_le32(HOST_DATA0, le32_to_cpup(pbitmap), par);
+ aty_st_le32(HOST_DATA0, get_unaligned_le32(pbitmap), par);
}
}
^ permalink raw reply
* [PATCH 4/7] mach64: fix cursor when character width is not a multiple of 8 pixels
From: Mikulas Patocka @ 2012-08-20 18:08 UTC (permalink / raw)
To: linux-fbdev
mach64: fix cursor when character width is not a multiple of 8 pixels
This patch fixes hardware cursor on mach64 when font width is not a
multiple of 8 pixels.
If you load such a font, the cursor is expanded to the next 8-byte
boundary and a part of the next character after the cursor is not
visible.
For example, when you load a font with 12-pixel width, the cursor width
is 16 pixels and when the cursor is displayed, 4 pixels of the next
character are not visible.
The reason is this: atyfb_cursor is called with proper parameters to
load an image that is 12-pixel wide. However, the number is aligned on
the next 8-pixel boundary on the line
"unsigned int width = (cursor->image.width + 7) >> 3;" and the whole
function acts as it is was loading a 16-pixel image.
This patch fixes it so that the value written to the framebuffer is
padded with 0xaaaa (the transparent pattern) when the image size it not
a multiple of 8 pixels.
Signed-off-by: Mikulas Patocka <mikulas@artax.karlin.mff.cuni.cz>
Cc: stable@kernel.org
---
drivers/video/aty/mach64_cursor.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
Index: linux-3.4.3-fast/drivers/video/aty/mach64_cursor.c
=================================--- linux-3.4.3-fast.orig/drivers/video/aty/mach64_cursor.c 2012-07-02 01:15:38.000000000 +0200
+++ linux-3.4.3-fast/drivers/video/aty/mach64_cursor.c 2012-07-02 01:54:10.000000000 +0200
@@ -5,6 +5,7 @@
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/string.h>
+#include "../fb_draw.h"
#include <asm/io.h>
@@ -157,24 +158,33 @@ static int atyfb_cursor(struct fb_info *
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
+ u16 l = 0xaaaa;
b = *src++;
m = *msk++;
switch (cursor->rop) {
case ROP_XOR:
// Upper 4 bits of mask data
- fb_writeb(cursor_bits_lookup[(b ^ m) >> 4], dst++);
+ l = cursor_bits_lookup[(b ^ m) >> 4] |
// Lower 4 bits of mask
- fb_writeb(cursor_bits_lookup[(b ^ m) & 0x0f],
- dst++);
+ (cursor_bits_lookup[(b ^ m) & 0x0f] << 8);
break;
case ROP_COPY:
// Upper 4 bits of mask data
- fb_writeb(cursor_bits_lookup[(b & m) >> 4], dst++);
+ l = cursor_bits_lookup[(b & m) >> 4] |
// Lower 4 bits of mask
- fb_writeb(cursor_bits_lookup[(b & m) & 0x0f],
- dst++);
+ (cursor_bits_lookup[(b & m) & 0x0f] << 8);
break;
}
+ /*
+ * If cursor size is not a multiple of 8 characters
+ * we must pad it with transparent pattern (0xaaaa).
+ */
+ if ((j + 1) * 8 > cursor->image.width) {
+ l = comp(l, 0xaaaa,
+ (1 << ((cursor->image.width & 7) * 2)) - 1);
+ }
+ fb_writeb(l & 0xff, dst++);
+ fb_writeb(l >> 8, dst++);
}
dst += offset;
}
^ permalink raw reply
* [PATCH 5/7] tgafb: fix mode setting with fbset
From: Mikulas Patocka @ 2012-08-20 18:09 UTC (permalink / raw)
To: linux-fbdev
tgafb: fix mode setting with fbset
Mode setting in the TGA driver is broken for these reasons:
- info->fix.line_length is set just once in tgafb_init_fix function. If
we change videomode, info->fix.line_length is not recalculated - so
the video mode is changed but screen is corrupted because of wrong
info->fix.line_length
- info->fix.smem_len is set in tgafb_init_fix to the size of the default
video mode (640x480). If we set a higher resolution,
info->fix.smem_len is smaller than the current screen size, preventing
the userspace program from mapping the framebuffer.
This patch fixes it:
- info->fix.line_length initialization is moved to tgafb_set_par so that
it is recalculated with each mode change.
- info->fix.smem_len is set to a fixed value representing the real
amount of video ram (the values are taken from xfree86 driver).
- add a check to tgafb_check_var to prevent us from setting a videomode
that doesn't fit into videoram.
- in tgafb_register, tgafb_init_fix is moved upwards, to be called
before fb_find_mode (because fb_find_mode already needs the videoram
size set in tgafb_init_fix).
Signed-off-by: Mikulas Patocka <mikulas@artax.karlin.mff.cuni.cz>
Cc: stable@kernel.org
---
drivers/video/tgafb.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
Index: linux-3.4.4-fast/drivers/video/tgafb.c
=================================--- linux-3.4.4-fast.orig/drivers/video/tgafb.c 2012-07-02 02:15:43.000000000 +0200
+++ linux-3.4.4-fast/drivers/video/tgafb.c 2012-07-02 02:16:48.000000000 +0200
@@ -192,6 +192,8 @@ tgafb_check_var(struct fb_var_screeninfo
if (var->xres_virtual != var->xres || var->yres_virtual != var->yres)
return -EINVAL;
+ if (var->xres * var->yres * (var->bits_per_pixel >> 3) > info->fix.smem_len)
+ return -EINVAL;
if (var->nonstd)
return -EINVAL;
if (1000000000 / var->pixclock > TGA_PLL_MAX_FREQ)
@@ -272,6 +274,7 @@ tgafb_set_par(struct fb_info *info)
par->yres = info->var.yres;
par->pll_freq = pll_freq = 1000000000 / info->var.pixclock;
par->bits_per_pixel = info->var.bits_per_pixel;
+ info->fix.line_length = par->xres * (par->bits_per_pixel >> 3);
tga_type = par->tga_type;
@@ -1480,6 +1483,7 @@ tgafb_init_fix(struct fb_info *info)
int tga_bus_tc = TGA_BUS_TC(par->dev);
u8 tga_type = par->tga_type;
const char *tga_type_name = NULL;
+ unsigned memory_size;
switch (tga_type) {
case TGA_TYPE_8PLANE:
@@ -1487,21 +1491,25 @@ tgafb_init_fix(struct fb_info *info)
tga_type_name = "Digital ZLXp-E1";
if (tga_bus_tc)
tga_type_name = "Digital ZLX-E1";
+ memory_size = 2097152;
break;
case TGA_TYPE_24PLANE:
if (tga_bus_pci)
tga_type_name = "Digital ZLXp-E2";
if (tga_bus_tc)
tga_type_name = "Digital ZLX-E2";
+ memory_size = 8388608;
break;
case TGA_TYPE_24PLUSZ:
if (tga_bus_pci)
tga_type_name = "Digital ZLXp-E3";
if (tga_bus_tc)
tga_type_name = "Digital ZLX-E3";
+ memory_size = 16777216;
break;
default:
tga_type_name = "Unknown";
+ memory_size = 16777216;
break;
}
@@ -1513,9 +1521,8 @@ tgafb_init_fix(struct fb_info *info)
? FB_VISUAL_PSEUDOCOLOR
: FB_VISUAL_DIRECTCOLOR);
- info->fix.line_length = par->xres * (par->bits_per_pixel >> 3);
info->fix.smem_start = (size_t) par->tga_fb_base;
- info->fix.smem_len = info->fix.line_length * par->yres;
+ info->fix.smem_len = memory_size;
info->fix.mmio_start = (size_t) par->tga_regs_base;
info->fix.mmio_len = 512;
@@ -1640,6 +1647,9 @@ tgafb_register(struct device *dev)
modedb_tga = &modedb_tc;
modedbsize_tga = 1;
}
+
+ tgafb_init_fix(info);
+
ret = fb_find_mode(&info->var, info,
mode_option ? mode_option : mode_option_tga,
modedb_tga, modedbsize_tga, NULL,
@@ -1657,7 +1667,6 @@ tgafb_register(struct device *dev)
}
tgafb_set_par(info);
- tgafb_init_fix(info);
if (register_framebuffer(info) < 0) {
printk(KERN_ERR "tgafb: Could not register framebuffer\n");
^ permalink raw reply
* [PATCH 6/7] tgafb: fix data copying
From: Mikulas Patocka @ 2012-08-20 18:10 UTC (permalink / raw)
To: linux-fbdev
tgafb: fix data copying
The functions for data copying copyarea_foreward_8bpp and
copyarea_backward_8bpp are buggy, they produce screen corruption.
This patch fixes the functions and moves the logic to one function
"copyarea_8bpp". For simplicity, the function only handles copying that
is aligned on 8 pixes. If we copy an unaligned area, generic function
cfb_copyarea is used.
Signed-off-by: Mikulas Patocka <mikulas@artax.karlin.mff.cuni.cz>
Cc: stable@kernel.org
---
drivers/video/tgafb.c | 266 +++++++++-----------------------------------------
1 file changed, 52 insertions(+), 214 deletions(-)
Index: linux-3.4.4-fast/drivers/video/tgafb.c
=================================--- linux-3.4.4-fast.orig/drivers/video/tgafb.c 2012-07-03 22:58:32.000000000 +0200
+++ linux-3.4.4-fast/drivers/video/tgafb.c 2012-07-04 02:32:47.000000000 +0200
@@ -1149,222 +1149,57 @@ copyarea_line_32bpp(struct fb_info *info
__raw_writel(TGA_MODE_SBM_24BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG);
}
-/* The general case of forward copy in 8bpp mode. */
+/* The (almost) general case of backward copy in 8bpp mode. */
static inline void
-copyarea_foreward_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy,
- u32 height, u32 width, u32 line_length)
+copyarea_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy,
+ u32 height, u32 width, u32 line_length,
+ const struct fb_copyarea *area)
{
struct tga_par *par = (struct tga_par *) info->par;
- unsigned long i, copied, left;
- unsigned long dpos, spos, dalign, salign, yincr;
- u32 smask_first, dmask_first, dmask_last;
- int pixel_shift, need_prime, need_second;
- unsigned long n64, n32, xincr_first;
+ unsigned i, yincr;
+ int depos, sepos, backward, last_step, step;
+ u32 mask_last;
+ unsigned n32;
void __iomem *tga_regs;
void __iomem *tga_fb;
- yincr = line_length;
- if (dy > sy) {
- dy += height - 1;
- sy += height - 1;
- yincr = -yincr;
- }
-
- /* Compute the offsets and alignments in the frame buffer.
- More than anything else, these control how we do copies. */
- dpos = dy * line_length + dx;
- spos = sy * line_length + sx;
- dalign = dpos & 7;
- salign = spos & 7;
- dpos &= -8;
- spos &= -8;
-
- /* Compute the value for the PIXELSHIFT register. This controls
- both non-co-aligned source and destination and copy direction. */
- if (dalign >= salign)
- pixel_shift = dalign - salign;
- else
- pixel_shift = 8 - (salign - dalign);
-
- /* Figure out if we need an additional priming step for the
- residue register. */
- need_prime = (salign > dalign);
- if (need_prime)
- dpos -= 8;
-
- /* Begin by copying the leading unaligned destination. Copy enough
- to make the next destination address 32-byte aligned. */
- copied = 32 - (dalign + (dpos & 31));
- if (copied = 32)
- copied = 0;
- xincr_first = (copied + 7) & -8;
- smask_first = dmask_first = (1ul << copied) - 1;
- smask_first <<= salign;
- dmask_first <<= dalign + need_prime*8;
- if (need_prime && copied > 24)
- copied -= 8;
- left = width - copied;
-
- /* Care for small copies. */
- if (copied > width) {
- u32 t;
- t = (1ul << width) - 1;
- t <<= dalign + need_prime*8;
- dmask_first &= t;
- left = 0;
- }
-
- /* Attempt to use 64-byte copies. This is only possible if the
- source and destination are co-aligned at 64 bytes. */
- n64 = need_second = 0;
- if ((dpos & 63) = (spos & 63)
- && (height = 1 || line_length % 64 = 0)) {
- /* We may need a 32-byte copy to ensure 64 byte alignment. */
- need_second = (dpos + xincr_first) & 63;
- if ((need_second & 32) != need_second)
- printk(KERN_ERR "tgafb: need_second wrong\n");
- if (left >= need_second + 64) {
- left -= need_second;
- n64 = left / 64;
- left %= 64;
- } else
- need_second = 0;
- }
-
- /* Copy trailing full 32-byte sections. This will be the main
- loop if the 64 byte loop can't be used. */
- n32 = left / 32;
- left %= 32;
-
- /* Copy the trailing unaligned destination. */
- dmask_last = (1ul << left) - 1;
-
- tga_regs = par->tga_regs_base;
- tga_fb = par->tga_fb_base;
-
- /* Set up the MODE and PIXELSHIFT registers. */
- __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_COPY, tga_regs+TGA_MODE_REG);
- __raw_writel(pixel_shift, tga_regs+TGA_PIXELSHIFT_REG);
- wmb();
-
- for (i = 0; i < height; ++i) {
- unsigned long j;
- void __iomem *sfb;
- void __iomem *dfb;
-
- sfb = tga_fb + spos;
- dfb = tga_fb + dpos;
- if (dmask_first) {
- __raw_writel(smask_first, sfb);
- wmb();
- __raw_writel(dmask_first, dfb);
- wmb();
- sfb += xincr_first;
- dfb += xincr_first;
- }
-
- if (need_second) {
- __raw_writel(0xffffffff, sfb);
- wmb();
- __raw_writel(0xffffffff, dfb);
- wmb();
- sfb += 32;
- dfb += 32;
- }
-
- if (n64 && (((unsigned long)sfb | (unsigned long)dfb) & 63))
- printk(KERN_ERR
- "tgafb: misaligned copy64 (s:%p, d:%p)\n",
- sfb, dfb);
-
- for (j = 0; j < n64; ++j) {
- __raw_writel(sfb - tga_fb, tga_regs+TGA_COPY64_SRC);
- wmb();
- __raw_writel(dfb - tga_fb, tga_regs+TGA_COPY64_DST);
- wmb();
- sfb += 64;
- dfb += 64;
- }
-
- for (j = 0; j < n32; ++j) {
- __raw_writel(0xffffffff, sfb);
- wmb();
- __raw_writel(0xffffffff, dfb);
- wmb();
- sfb += 32;
- dfb += 32;
- }
-
- if (dmask_last) {
- __raw_writel(0xffffffff, sfb);
- wmb();
- __raw_writel(dmask_last, dfb);
- wmb();
- }
-
- spos += yincr;
- dpos += yincr;
+ /* Do acceleration only if we are aligned on 8 pixels */
+ if ((dx | sx | width) & 7) {
+ cfb_copyarea(info, area);
+ return;
}
- /* Reset the MODE register to normal. */
- __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG);
-}
-
-/* The (almost) general case of backward copy in 8bpp mode. */
-static inline void
-copyarea_backward_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy,
- u32 height, u32 width, u32 line_length,
- const struct fb_copyarea *area)
-{
- struct tga_par *par = (struct tga_par *) info->par;
- unsigned long i, left, yincr;
- unsigned long depos, sepos, dealign, sealign;
- u32 mask_first, mask_last;
- unsigned long n32;
- void __iomem *tga_regs;
- void __iomem *tga_fb;
-
yincr = line_length;
if (dy > sy) {
dy += height - 1;
sy += height - 1;
yincr = -yincr;
}
+ backward = dy = sy && dx > sx && dx < sx + width;
/* Compute the offsets and alignments in the frame buffer.
More than anything else, these control how we do copies. */
- depos = dy * line_length + dx + width;
- sepos = sy * line_length + sx + width;
- dealign = depos & 7;
- sealign = sepos & 7;
-
- /* ??? The documentation appears to be incorrect (or very
- misleading) wrt how pixel shifting works in backward copy
- mode, i.e. when PIXELSHIFT is negative. I give up for now.
- Do handle the common case of co-aligned backward copies,
- but frob everything else back on generic code. */
- if (dealign != sealign) {
- cfb_copyarea(info, area);
- return;
- }
-
- /* We begin the copy with the trailing pixels of the
- unaligned destination. */
- mask_first = (1ul << dealign) - 1;
- left = width - dealign;
-
- /* Care for small copies. */
- if (dealign > width) {
- mask_first ^= (1ul << (dealign - width)) - 1;
- left = 0;
- }
+ depos = dy * line_length + dx;
+ sepos = sy * line_length + sx;
+ if (backward)
+ depos += width, sepos += width;
/* Next copy full words at a time. */
- n32 = left / 32;
- left %= 32;
+ n32 = width / 32;
+ last_step = width % 32;
/* Finally copy the unaligned head of the span. */
- mask_last = -1 << (32 - left);
+ mask_last = (1ul << last_step) - 1;
+
+ if (!backward) {
+ step = 32;
+ last_step = 32;
+ } else {
+ step = -32;
+ last_step = -last_step;
+ sepos -= 32;
+ depos -= 32;
+ }
tga_regs = par->tga_regs_base;
tga_fb = par->tga_fb_base;
@@ -1381,25 +1216,33 @@ copyarea_backward_8bpp(struct fb_info *i
sfb = tga_fb + sepos;
dfb = tga_fb + depos;
- if (mask_first) {
- __raw_writel(mask_first, sfb);
- wmb();
- __raw_writel(mask_first, dfb);
- wmb();
- }
- for (j = 0; j < n32; ++j) {
- sfb -= 32;
- dfb -= 32;
+ for (j = 0; j < n32; j++) {
+ if (j < 2 && j + 1 < n32 && !backward &&
+ !(((unsigned long)sfb | (unsigned long)dfb) & 63)) {
+ do {
+ __raw_writel(sfb - tga_fb, tga_regs+TGA_COPY64_SRC);
+ wmb();
+ __raw_writel(dfb - tga_fb, tga_regs+TGA_COPY64_DST);
+ wmb();
+ sfb += 64;
+ dfb += 64;
+ j += 2;
+ } while (j + 1 < n32);
+ j--;
+ continue;
+ }
__raw_writel(0xffffffff, sfb);
wmb();
__raw_writel(0xffffffff, dfb);
wmb();
+ sfb += step;
+ dfb += step;
}
if (mask_last) {
- sfb -= 32;
- dfb -= 32;
+ sfb += last_step - step;
+ dfb += last_step - step;
__raw_writel(mask_last, sfb);
wmb();
__raw_writel(mask_last, dfb);
@@ -1460,14 +1303,9 @@ tgafb_copyarea(struct fb_info *info, con
else if (bpp = 32)
cfb_copyarea(info, area);
- /* Detect overlapping source and destination that requires
- a backward copy. */
- else if (dy = sy && dx > sx && dx < sx + width)
- copyarea_backward_8bpp(info, dx, dy, sx, sy, height,
- width, line_length, area);
else
- copyarea_foreward_8bpp(info, dx, dy, sx, sy, height,
- width, line_length);
+ copyarea_8bpp(info, dx, dy, sx, sy, height,
+ width, line_length, area);
}
^ permalink raw reply
* [PATCH 7/7] tgafb: avoid restriction on modes with line length not a multiple of 64
From: Mikulas Patocka @ 2012-08-20 18:12 UTC (permalink / raw)
To: linux-fbdev
tgafb: avoid restriction on modes with line length not a multiple of 64
In tgafb there is a restriction that prevents the user from setting a
videomode with line length not a multiple of 64 bytes (for example
800x600 is not allowed).
The reason for this restriction it that functions copyarea_line_8bpp and
copyarea_line_32bpp can not handle a line length that is not a multiple
of 64 bytes.
This patch removes this restriction on mode setting and makes sure that
the functions copyarea_line_8bpp and copyarea_line_32bpp are called only
if line length is a multiple of 64 bytes. If we set a mode 800x600,
the functions copyarea_line_8bpp and copyarea_line_32bpp are not used,
generic functions for copying are used instead and it works just fine.
Signed-off-by: Mikulas Patocka <mikulas@artax.karlin.mff.cuni.cz>
---
drivers/video/tgafb.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
Index: linux-3.6-rc2-fast/drivers/video/tgafb.c
=================================--- linux-3.6-rc2-fast.orig/drivers/video/tgafb.c 2012-08-20 19:40:02.000000000 +0200
+++ linux-3.6-rc2-fast/drivers/video/tgafb.c 2012-08-20 19:40:33.000000000 +0200
@@ -202,8 +202,8 @@ tgafb_check_var(struct fb_var_screeninfo
return -EINVAL;
/* Some of the acceleration routines assume the line width is
- a multiple of 64 bytes. */
- if (var->xres * (par->tga_type = TGA_TYPE_8PLANE ? 1 : 4) % 64)
+ a multiple of 8 bytes. */
+ if (var->xres % 8)
return -EINVAL;
return 0;
@@ -1290,7 +1290,7 @@ tgafb_copyarea(struct fb_info *info, con
bpp = info->var.bits_per_pixel;
/* Detect copies of the entire line. */
- if (width * (bpp >> 3) = line_length) {
+ if (!(line_length & 63) && width * (bpp >> 3) = line_length) {
if (bpp = 8)
copyarea_line_8bpp(info, dy, sy, height, width);
else
^ permalink raw reply
* [PATCH] video: hpfb: Fix error handling
From: Emil Goode @ 2012-08-20 18:32 UTC (permalink / raw)
To: FlorianSchandinat; +Cc: linux-fbdev, linux-kernel, kernel-janitors, Emil Goode
This patch solves problems with the error handling by
introducing labels for proper error paths and it also
frees resources that where missed.
Signed-off-by: Emil Goode <emilgoode@gmail.com>
---
drivers/video/hpfb.c | 28 +++++++++++++++++++++-------
1 file changed, 21 insertions(+), 7 deletions(-)
diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c
index ebf8495..7324865 100644
--- a/drivers/video/hpfb.c
+++ b/drivers/video/hpfb.c
@@ -210,6 +210,7 @@ static int __devinit hpfb_init_one(unsigned long phys_base,
unsigned long virt_base)
{
unsigned long fboff, fb_width, fb_height, fb_start;
+ int ret;
fb_regs = virt_base;
fboff = (in_8(fb_regs + HPFB_FBOMSB) << 8) | in_8(fb_regs + HPFB_FBOLSB);
@@ -290,19 +291,29 @@ static int __devinit hpfb_init_one(unsigned long phys_base,
fb_info.var = hpfb_defined;
fb_info.screen_base = (char *)fb_start;
- fb_alloc_cmap(&fb_info.cmap, 1 << hpfb_defined.bits_per_pixel, 0);
+ ret = fb_alloc_cmap(&fb_info.cmap, 1 << hpfb_defined.bits_per_pixel, 0);
+ if (ret < 0)
+ goto unmap_screen_base;
- if (register_framebuffer(&fb_info) < 0) {
- fb_dealloc_cmap(&fb_info.cmap);
- iounmap(fb_info.screen_base);
- fb_info.screen_base = NULL;
- return 1;
- }
+ ret = register_framebuffer(&fb_info);
+ if (ret < 0)
+ goto dealloc_cmap;
printk(KERN_INFO "fb%d: %s frame buffer device\n",
fb_info.node, fb_info.fix.id);
return 0;
+
+dealloc_cmap:
+ fb_dealloc_cmap(&fb_info.cmap);
+
+unmap_screen_base:
+ if (fb_info.screen_base) {
+ iounmap(fb_info.screen_base);
+ fb_info.screen_base = NULL;
+ }
+
+ return ret;
}
/*
@@ -345,6 +356,9 @@ static void __devexit hpfb_remove_one(struct dio_dev *d)
if (d->scode >= DIOII_SCBASE)
iounmap((void *)fb_regs);
release_mem_region(d->resource.start, resource_size(&d->resource));
+ fb_dealloc_cmap(&fb_info.cmap);
+ if (fb_info.screen_base)
+ iounmap(fb_info.screen_base);
}
static struct dio_device_id hpfb_dio_tbl[] = {
--
1.7.10.4
^ permalink raw reply related
* Re: [RFC 0/5] Generic panel framework
From: Laurent Pinchart @ 2012-08-20 23:29 UTC (permalink / raw)
To: Tomi Valkeinen
Cc: linux-fbdev, Marcus Lorentzon, dri-devel, Kyungmin Park,
Richard Purdie, Sebastien Guiriec, Bryan Wu, linux-leds,
linux-media
In-Reply-To: <1345462770.2684.23.camel@deskari>
Hi Tomi,
On Monday 20 August 2012 14:39:30 Tomi Valkeinen wrote:
> On Sat, 2012-08-18 at 03:16 +0200, Laurent Pinchart wrote:
> > Hi Tomi,
> >
> > mipi-dbi-bus might not belong to include/video/panel/ though, as it can be
> > used for non-panel devices (at least in theory). The future mipi-dsi-bus
> > certainly will.
>
> They are both display busses. So while they could be used for anything,
> I find it quite unlikely as there are much better alternatives for
> generic bus needs.
My point is that they could be used for display devices other than panels.
This is especially true for DSI, as there are DSI to HDMI converters.
Technically speaking that's also true for DBI, as DBI chips convert from DBI
to DPI, but we can group both the DBI-to-DPI chip and the panel in a single
panel object.
> > Would you be able to send incremental patches on top of v2 to implement
> > the solution you have in mind ? It would be neat if you could also
> > implement mipi- dsi-bus for the OMAP DSS and test the code with a real
> > device :-)
>
> Yes, I'd like to try this out on OMAP, both DBI and DSI. However, I fear
> it'll be quite complex due to the dependencies all around we have in the
> current driver. We're working on simplifying things so that it'll be
> easier to try thing like the panel framework, though, so we're going in
> the right direction.
If you want the panel framework to support your use cases I'm afraid you will
need to work on that ;-)
> > > Generally about locks, if we define that panel ops may only be called
> > > exclusively, does it simplify things? I think we can make such
> > > requirements, as there should be only one display framework that handles
> > > the panel. Then we don't need locking for things like enable/disable.
> >
> > Pushing locking to callers would indeed simplify panel drivers, but we
> > need to make sure we won't need to expose a panel to several callers in
> > the future.
>
> I have a feeling that would be a bad idea.
>
> Display related stuff are quite sensitive to any delays, so any extra
> transactions over, say, DSI bus could cause a noticeable glitch on the
> screen. I'm not sure what are all the possible ops that a panel can
> offer, but I think all that affect the display or could cause delays
> should be handled by one controlling entity (drm or such). The
> controlling entity needs to handle locking anyway, so in that sense I
> don't think it's an extra burden for it.
>
> The things that come to my mind that could possibly cause calls to the
> panel outside drm: debugfs, sysfs, audio, backlight. Of those, I think
> backlight should go through drm. Audio, no idea. debugfs and sysfs
> locking needs to be handled by the panel driver, and they are a bit
> problematic as I guess having them requires full locking.
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [RFC 0/5] Generic panel framework
From: Tomi Valkeinen @ 2012-08-21 5:49 UTC (permalink / raw)
To: Laurent Pinchart
Cc: linux-fbdev, dri-devel, linux-leds, linux-media, Bryan Wu,
Richard Purdie, Marcus Lorentzon, Sumit Semwal, Archit Taneja,
Sebastien Guiriec, Inki Dae, Kyungmin Park
In-Reply-To: <3937256.gcqPRVoNWN@avalon>
[-- Attachment #1: Type: text/plain, Size: 1828 bytes --]
On Tue, 2012-08-21 at 01:29 +0200, Laurent Pinchart wrote:
> Hi Tomi,
>
> On Monday 20 August 2012 14:39:30 Tomi Valkeinen wrote:
> > On Sat, 2012-08-18 at 03:16 +0200, Laurent Pinchart wrote:
> > > Hi Tomi,
> > >
> > > mipi-dbi-bus might not belong to include/video/panel/ though, as it can be
> > > used for non-panel devices (at least in theory). The future mipi-dsi-bus
> > > certainly will.
> >
> > They are both display busses. So while they could be used for anything,
> > I find it quite unlikely as there are much better alternatives for
> > generic bus needs.
>
> My point is that they could be used for display devices other than panels.
> This is especially true for DSI, as there are DSI to HDMI converters.
> Technically speaking that's also true for DBI, as DBI chips convert from DBI
> to DPI, but we can group both the DBI-to-DPI chip and the panel in a single
> panel object.
Ah, ok. I thought "panels" would include these buffer/converter chips.
I think we should have one driver for one indivisible hardware entity.
So if you've got a panel module that contains DBI receiver, buffer
memory and a DPI panel, let's just have one "DBI panel" driver for it.
If we get lots of different panel modules containing the same DBI RX IP,
we could have the DBI IP part as a common library, but still have one
panel driver per panel module.
But how do you see the case for separate converter/buffer chips? Are
they part of the generic panel framework? I guess they kinda have to be.
On one side they use the "panel" API control the bus they are connected
to, and on the other they offer an API for the connected panel to use
the bus they provide.
Did you just mean we should have a separate directory for them, while
still part of the same framework, or...?
Tomi
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* RE: [PATCH v3] da8xx-fb: allow frame to complete after disabling LCDC
From: Manjunathappa, Prakash @ 2012-08-21 5:52 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1344950605-18945-1-git-send-email-prakash.pm@ti.com>
SGkgU2VraGFyLA0KDQpPbiBGcmksIEF1ZyAxNywgMjAxMiBhdCAxMjoxNTowMSwgTm9yaSwgU2Vr
aGFyIHdyb3RlOg0KPiBIaSBQcmFrYXNoLA0KPiANCj4gT24gOC8xNC8yMDEyIDY6NTMgUE0sIE1h
bmp1bmF0aGFwcGEsIFByYWthc2ggd3JvdGU6DQo+ID4gV2FpdCBmb3IgYWN0aXZlIGZyYW1lIHRy
YW5zZmVyIHRvIGNvbXBsZXRlIGFmdGVyIGRpc2FibGluZyBMQ0RDLg0KPiA+IEF0IHRoZSBzYW1l
IHRoaXMgd2FpdCBpcyBub3QgYmUgcmVxdWlyZWQgd2hlbiB0aGVyZSBhcmUgc3luYyBhbmQNCj4g
PiB1bmRlcmZsb3cgZXJyb3JzLg0KPiA+IE1vcmUgaW5mb3JtYXRpb24gb24gZGlzYWJsZSBhbmQg
cmVzZXQgc2VxdWVuY2UgY2FuIGJlIGZvdW5kIGluDQo+ID4gc2VjdGlvbiAxMy40LjYgb2YgQU0z
MzV4IFRSTSBAd3d3LnRpLmNvbS9hbTMzNXguDQo+ID4gDQo+ID4gU2lnbmVkLW9mZi1ieTogTWFu
anVuYXRoYXBwYSwgUHJha2FzaCA8cHJha2FzaC5wbUB0aS5jb20+DQo+ID4gLS0tDQo+ID4gQXBw
bGllcyBvbiB0b3Agb2YgZmJkZXYtbmV4dCBvZiBGbG9yaWFuIFRvYmlhcyBTY2hhbmRpbmF0J3Mg
dHJlZS4NCj4gPiBTaW5jZSB2MjoNCj4gPiBPcHRpbWl6ZWQgdGhlIGxjZF9kaXNhYmxlX3Jhc3Rl
ciBmdW5jdGlvbi4NCj4gPiBTaW5jZSB2MToNCj4gPiBDaGFuZ2VkIHRoZSBjb21taXQgbWVzc2Fn
ZSwgYWxzbyBhZGRlZCBsaW5rIHRvIGhhcmR3YXJlIHNwZWNpZmljYXRpb24uDQo+ID4gDQo+ID4g
IGRyaXZlcnMvdmlkZW8vZGE4eHgtZmIuYyB8ICAgNDkgKysrKysrKysrKysrKysrKysrKysrKysr
KysrKysrKysrKysrLS0tLS0tLS0tDQo+ID4gIDEgZmlsZXMgY2hhbmdlZCwgMzkgaW5zZXJ0aW9u
cygrKSwgMTAgZGVsZXRpb25zKC0pDQo+ID4gDQo+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvdmlk
ZW8vZGE4eHgtZmIuYyBiL2RyaXZlcnMvdmlkZW8vZGE4eHgtZmIuYw0KPiA+IGluZGV4IDdhZTlk
NTMuLmNiNjk2ZmYgMTAwNjQ0DQo+ID4gLS0tIGEvZHJpdmVycy92aWRlby9kYTh4eC1mYi5jDQo+
ID4gKysrIGIvZHJpdmVycy92aWRlby9kYTh4eC1mYi5jDQo+ID4gQEAgLTQ4LDYgKzQ4LDcgQEAN
Cj4gPiAgI2RlZmluZSBMQ0RfUExfTE9BRF9ET05FCQlCSVQoNikNCj4gPiAgI2RlZmluZSBMQ0Rf
RklGT19VTkRFUkZMT1cJCUJJVCg1KQ0KPiA+ICAjZGVmaW5lIExDRF9TWU5DX0xPU1QJCQlCSVQo
MikNCj4gPiArI2RlZmluZSBMQ0RfRlJBTUVfRE9ORQkJCUJJVCgwKQ0KPiA+ICANCj4gPiAgLyog
TENEIERNQSBDb250cm9sIFJlZ2lzdGVyICovDQo+ID4gICNkZWZpbmUgTENEX0RNQV9CVVJTVF9T
SVpFKHgpCQkoKHgpIDw8IDQpDQo+ID4gQEAgLTI4OCwxMyArMjg5LDQxIEBAIHN0YXRpYyBpbmxp
bmUgdm9pZCBsY2RfZW5hYmxlX3Jhc3Rlcih2b2lkKQ0KPiA+ICB9DQo+ID4gIA0KPiA+ICAvKiBE
aXNhYmxlIHRoZSBSYXN0ZXIgRW5naW5lIG9mIHRoZSBMQ0QgQ29udHJvbGxlciAqLw0KPiA+IC1z
dGF0aWMgaW5saW5lIHZvaWQgbGNkX2Rpc2FibGVfcmFzdGVyKHZvaWQpDQo+ID4gK3N0YXRpYyBp
bmxpbmUgdm9pZCBsY2RfZGlzYWJsZV9yYXN0ZXIoYm9vbCB3YWl0X2Zvcl9mcmFtZV9kb25lKQ0K
PiA+ICB7DQo+ID4gIAl1MzIgcmVnOw0KPiA+ICsJdTMyIHN0YXRfcmVnID0gTENEX1NUQVRfUkVH
Ow0KPiA+ICsJdTMyIGxvb3BfY250ID0gMDsNCj4gPiAgDQo+ID4gIAlyZWcgPSBsY2RjX3JlYWQo
TENEX1JBU1RFUl9DVFJMX1JFRyk7DQo+ID4gIAlpZiAocmVnICYgTENEX1JBU1RFUl9FTkFCTEUp
DQo+ID4gIAkJbGNkY193cml0ZShyZWcgJiB+TENEX1JBU1RFUl9FTkFCTEUsIExDRF9SQVNURVJf
Q1RSTF9SRUcpOw0KPiA+ICsNCj4gPiArCWlmIChsY2RfcmV2aXNpb24gPT0gTENEX1ZFUlNJT05f
MikNCj4gPiArCQlzdGF0X3JlZyA9IExDRF9SQVdfU1RBVF9SRUc7DQo+ID4gKw0KPiA+ICsJaWYg
KHdhaXRfZm9yX2ZyYW1lX2RvbmUpIHsNCj4gPiArCQkvKg0KPiA+ICsJCSAqIDUwIG1pbGxpIHNl
Y29uZHMgc2hvdWxkIGJlIHN1ZmZpY2llbnQgZm9yIGEgZnJhbWUgdG8NCj4gPiArCQkgKiBjb21w
bGV0ZQ0KPiA+ICsJCSAqLw0KPiA+ICsJCWxvb3BfY250ID0gNTA7DQo+ID4gKwkJd2hpbGUgKCEo
bGNkY19yZWFkKHN0YXRfcmVnKSAmIExDRF9GUkFNRV9ET05FKSkgew0KPiA+ICsJCQkvKiBIYW5k
bGUgdGltZW91dCAqLw0KPiA+ICsJCQlpZiAodW5saWtlbHkoMCA9PSAtLWxvb3BfY250KSkgew0K
PiA+ICsJCQkJcHJfZXJyKCJMQ0QgQ29udHJvbGxlciB0aW1lZCBvdXRcbiIpOw0KPiA+ICsJCQkJ
YnJlYWs7DQo+ID4gKwkJCX0NCj4gPiArCQkJbWRlbGF5KDEpOw0KPiA+ICsJCX0NCj4gPiArCX0N
Cj4gDQo+IFRoZSBUUk0geW91IHJlZmVyZW5jZWQgaW4gdGhlIHBhdGNoIGRlc2NyaXB0aW9uIHN1
Z2dlc3RzIHdhaXRpbmcgZm9yDQo+IGZyYW1lIGRvbmUgaW50ZXJydXB0LiBDYW4gd2UgYWN0dWFs
bHkgd2FpdCBmb3IgdGhlIGludGVycnVwdCBoZXJlDQo+IGluc3RlYWQgb2YgYnVzeSBsb29waW5n
Pw0KPiANCg0KSSBhZ3JlZSwgd2lsbCBzdWJtaXQgbmV4dCB2ZXJzaW9uIG9mIHBhdGNoIGNvbnNp
ZGVyaW5nIGFib3ZlLg0KDQpUaGFua3MsDQpQcmFrYXNoDQoNCj4gVGhhbmtzLA0KPiBTZWtoYXIN
Cj4gDQoNCg=
^ permalink raw reply
* [PATCH 0/2] OMAPDSS: fixes for -rc
From: Tomi Valkeinen @ 2012-08-21 6:09 UTC (permalink / raw)
To: Florian Tobias Schandinat; +Cc: linux-fbdev, linux-omap, Tomi Valkeinen
Hi Florian,
Here are two small fixes for omapfb and omapdss. The first one fixes an old bug
that causes colors to be wrong on fb console. The other fixes SDI output that
got broken in the previous merge window.
Tomi
Grazvydas Ignotas (1):
OMAPFB: fix framebuffer console colors
Tomi Valkeinen (1):
OMAPDSS: Fix SDI PLL locking
drivers/video/omap2/dss/sdi.c | 14 ++++++++++++++
drivers/video/omap2/omapfb/omapfb-main.c | 2 +-
2 files changed, 15 insertions(+), 1 deletion(-)
--
1.7.9.5
^ permalink raw reply
* [PATCH 1/2] OMAPDSS: Fix SDI PLL locking
From: Tomi Valkeinen @ 2012-08-21 6:09 UTC (permalink / raw)
To: Florian Tobias Schandinat; +Cc: linux-fbdev, linux-omap, Tomi Valkeinen
In-Reply-To: <1345529388-3509-1-git-send-email-tomi.valkeinen@ti.com>
Commit f476ae9dab3234532d41d36beb4ba7be838fa786 (OMAPDSS: APPLY: Remove
DISPC writes to manager's lcd parameters in interface) broke the SDI
output, as it causes the SDI PLL locking to fail.
LCLK and PCLK divisors are located in shadow registers, and we normally
write them to DISPC registers when enabling the output. However, SDI
uses pck-free as source clock for its PLL, and pck-free is affected by
the divisors. And as we need the PLL before enabling the output, we need
to write the divisors early.
It seems just writing to the DISPC register is enough, and we don't need
to care about the shadow register mechanism for pck-free. The exact
reason for this is unknown.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Reported-by: Aaro Koskinen <aaro.koskinen@iki.fi>
---
drivers/video/omap2/dss/sdi.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index 5d31699..f43bfe1 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -105,6 +105,20 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
sdi_config_lcd_manager(dssdev);
+ /*
+ * LCLK and PCLK divisors are located in shadow registers, and we
+ * normally write them to DISPC registers when enabling the output.
+ * However, SDI uses pck-free as source clock for its PLL, and pck-free
+ * is affected by the divisors. And as we need the PLL before enabling
+ * the output, we need to write the divisors early.
+ *
+ * It seems just writing to the DISPC register is enough, and we don't
+ * need to care about the shadow register mechanism for pck-free. The
+ * exact reason for this is unknown.
+ */
+ dispc_mgr_set_clock_div(dssdev->manager->id,
+ &sdi.mgr_config.clock_info);
+
dss_sdi_init(dssdev->phy.sdi.datapairs);
r = dss_sdi_enable();
if (r)
--
1.7.9.5
^ permalink raw reply related
* [PATCH 2/2] OMAPFB: fix framebuffer console colors
From: Tomi Valkeinen @ 2012-08-21 6:09 UTC (permalink / raw)
To: Florian Tobias Schandinat
Cc: linux-fbdev, linux-omap, Grazvydas Ignotas, Tomi Valkeinen
In-Reply-To: <1345529388-3509-1-git-send-email-tomi.valkeinen@ti.com>
From: Grazvydas Ignotas <notasas@gmail.com>
omapfb does not currently set pseudo palette correctly for color depths
above 16bpp, making red text invisible, command like
echo -e '\e[0;31mRED' > /dev/tty1
will display nothing on framebuffer console in 24bpp mode.
This is because temporary variable is declared incorrectly, fix it.
Signed-off-by: Grazvydas Ignotas <notasas@gmail.com>
Cc: stable@vger.kernel.org # v3.x
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/omapfb/omapfb-main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index 08ec1a7..fc671d3 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -1192,7 +1192,7 @@ static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green,
break;
if (regno < 16) {
- u16 pal;
+ u32 pal;
pal = ((red >> (16 - var->red.length)) <<
var->red.offset) |
((green >> (16 - var->green.length)) <<
--
1.7.9.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox