[PATCH 05/10 v2] s3c-fb: Add v4l2 subdevice to support framebuffer local fifo input path

Sylwester Nawrocki s.nawrocki at samsung.com
Thu Jul 15 05:10:36 EDT 2010


Selected multimedia devices in Samsung S3C/S5P SoC series are capable of
transferring data directly between each other, bypassing the main system
bus. Such a datapath exists between the camera interface/video
postprocessor and the lcd controller. To control the data flow from the
fimc driver level v4l2-subdevice driver is added to the framebuffer.
It enables to configure the lcd controller into FIFO or DMA input mode.

Signed-off-by: Sylwester Nawrocki <s.nawrocki at samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park at samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski at samsung.com>
---
 arch/arm/plat-samsung/include/plat/fb.h |    6 +
 drivers/video/s3c-fb.c                  |  487 +++++++++++++++++++++++++++++--
 2 files changed, 472 insertions(+), 21 deletions(-)

diff --git a/arch/arm/plat-samsung/include/plat/fb.h b/arch/arm/plat-samsung/include/plat/fb.h
index cb3ca3a..7dc6110 100644
--- a/arch/arm/plat-samsung/include/plat/fb.h
+++ b/arch/arm/plat-samsung/include/plat/fb.h
@@ -22,6 +22,10 @@
  */
 #define S3C_FB_MAX_WIN	(5)
 
+#define S3C_FB_MAX_WIN_SOURCES	(2)
+
+struct s3c_fifo_link;
+
 /**
  * struct s3c_fb_pd_win - per window setup data
  * @win_mode: The display parameters to initialise (not for window 0)
@@ -35,6 +39,8 @@ struct s3c_fb_pd_win {
 	unsigned short		max_bpp;
 	unsigned short		virtual_x;
 	unsigned short		virtual_y;
+
+	struct s3c_fifo_link	*fifo_sources[S3C_FB_MAX_WIN_SOURCES];
 };
 
 /**
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
index 8ea974d..5a453cf 100644
--- a/drivers/video/s3c-fb.c
+++ b/drivers/video/s3c-fb.c
@@ -24,9 +24,14 @@
 #include <linux/uaccess.h>
 #include <linux/interrupt.h>
 
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
 #include <mach/map.h>
 #include <plat/regs-fb-v4.h>
 #include <plat/fb.h>
+#include <plat/fifo.h>
 
 /* This driver will export a number of framebuffer interfaces depending
  * on the configuration passed in via the platform data. Each fb instance
@@ -56,6 +61,18 @@
 #define VSYNC_TIMEOUT_MSEC 50
 
 struct s3c_fb;
+struct s3c_fb_win;
+
+struct s3c_fb_win_sd {
+	struct v4l2_subdev	sd;
+	unsigned int		index;
+	struct s3c_fb_win	*win;
+	struct s3c_fifo_link	*link;
+	struct v4l2_format	fmt;
+	int			streaming;
+	struct v4l2_rect	default_osd_win;
+	struct v4l2_rect	curr_osd_win;
+};
 
 #define VALID_BPP(x) (1 << ((x) - 1))
 
@@ -65,6 +82,9 @@ struct s3c_fb;
 #define VIDOSD_C(win, variant) (OSD_BASE(win, variant) + 0x08)
 #define VIDOSD_D(win, variant) (OSD_BASE(win, variant) + 0x0C)
 
+#define s3c_fb_get_line_count(sfb) \
+	VIDCON1_LINECNT_GET(readl((sfb)->regs + VIDCON1))
+
 /**
  * struct s3c_fb_variant - fb variant information
  * @is_2443: Set if S3C2443/S3C2416 style hardware.
@@ -156,6 +176,9 @@ struct s3c_fb_palette {
  * @pseudo_palette: For use in TRUECOLOUR modes for entries 0..15/
  * @index: The window number of this window.
  * @palette: The bitfields for changing r/g/b into a hardware palette entry.
+ * @sources: The fifo mode data sources for this window
+ * @local_path: The flag indicating the lcd controller input mode:
+ *		0 - local path from other SoC subsystem, 1 - DMA
  */
 struct s3c_fb_win {
 	struct s3c_fb_pd_win	*windata;
@@ -167,6 +190,8 @@ struct s3c_fb_win {
 	u32			*palette_buffer;
 	u32			 pseudo_palette[16];
 	unsigned int		 index;
+	struct s3c_fb_win_sd	*sources[S3C_FB_MAX_WIN_SOURCES];
+	bool			local_path;
 };
 
 /**
@@ -360,13 +385,10 @@ static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
  */
 static int s3c_fb_align_word(unsigned int bpp, unsigned int pix)
 {
-	int pix_per_word;
-
 	if (bpp > 16)
 		return pix;
 
-	pix_per_word = (8 * 32) / bpp;
-	return ALIGN(pix, pix_per_word);
+	return ALIGN(pix, (bpp > 8) ? 2 : 4);
 }
 
 /**
@@ -430,6 +452,84 @@ static void shadow_protect_win(struct s3c_fb_win *win, bool protect)
 }
 
 /**
+ * s3c_fb_set_osd() - set position and size of the framebuffer window
+ *
+ * @win: framebuffer window to get data for
+ * @cr: pixel cropping reactangle
+ *
+ * Set framebuffer window position and size. cr rectangle will be modified
+ * if it does not meet the hardware alignment requirements.
+ */
+int s3c_fb_set_osd(struct s3c_fb_win *win, struct v4l2_rect *cr, int bpp)
+{
+	u32 data, width;
+	struct s3c_fb *sfb = win->parent;
+	void __iomem *regs = sfb->regs;
+
+	if (win->index >= S3C_FB_MAX_WIN)
+		return -EINVAL;
+
+	shadow_protect_win(win, 1);
+
+	cr->left = s3c_fb_align_word(bpp, cr->left);
+	data = VIDOSDxA_TOPLEFT_X(cr->left) | VIDOSDxA_TOPLEFT_Y(cr->top);
+	writel(data, regs + VIDOSD_A(win->index, sfb->variant));
+
+	width = s3c_fb_align_word(bpp, cr->width - 1);
+	data = VIDOSDxB_BOTRIGHT_X(cr->left + width)
+	     | VIDOSDxB_BOTRIGHT_Y(cr->top + cr->height - 1);
+	cr->width = ++width;
+
+	writel(data, regs + VIDOSD_B(win->index, sfb->variant));
+
+	data = cr->width * cr->height;
+	vidosd_set_size(win, data);
+
+	shadow_protect_win(win, 0);
+
+	dev_dbg(sfb->dev, "%s(): l:%d t:%d w:%d h:%d", __func__,
+		cr->left, cr->top, cr->width, cr->height);
+
+	return 0;
+}
+
+/**
+ * s3c_fb_gegt_osd() - get position and size of the frame buffer window
+ *
+ * @win: framebuffer window to get data for
+ * @cr: current cropping rectangle
+ */
+int s3c_fb_get_osd(struct s3c_fb_win *win, struct v4l2_rect *cr)
+{
+	u32 reg, ltx, lty;
+	struct s3c_fb *sfb = win->parent;
+	void __iomem *regs = sfb->regs;
+
+	if (!cr || win->index >= S3C_FB_MAX_WIN)
+		return -EINVAL;
+
+	reg = readl(regs + VIDOSD_A(win->index, sfb->variant));
+
+	ltx = (reg >> VIDOSDxA_TOPLEFT_X_SHIFT) & VIDOSDxA_TOPLEFT_X_LIMIT;
+	lty = (reg >> VIDOSDxA_TOPLEFT_Y_SHIFT) & VIDOSDxA_TOPLEFT_Y_LIMIT;
+
+	reg = readl(regs + VIDOSD_B(win->index, sfb->variant));
+
+	cr->width = ((reg >> VIDOSDxB_BOTRIGHT_X_SHIFT)
+		  & VIDOSDxB_BOTRIGHT_X_LIMIT) - ltx + 1;
+
+	cr->height = ((reg >> VIDOSDxB_BOTRIGHT_Y_SHIFT)
+			& VIDOSDxB_BOTRIGHT_Y_LIMIT) - lty + 1;
+	cr->left = ltx;
+	cr->top = lty;
+
+	dev_dbg(sfb->dev, "%s(): l:%d t:%d w:%d h:%d", __func__,
+		cr->left, cr->top, cr->width, cr->height);
+
+	return 0;
+}
+
+/**
  * s3c_fb_set_par() - framebuffer request to set new framebuffer state.
  * @info: The framebuffer to change.
  *
@@ -444,10 +544,14 @@ static int s3c_fb_set_par(struct fb_info *info)
 	void __iomem *buf = regs;
 	int win_no = win->index;
 	u32 alpha = 0;
+	struct v4l2_rect osd_win;
 	u32 data;
 	u32 pagewidth;
 	int clkdiv;
 
+	if (win->local_path)
+		return -EBUSY;
+
 	dev_dbg(sfb->dev, "setting framebuffer parameters\n");
 
 	shadow_protect_win(win, 1);
@@ -517,7 +621,7 @@ static int s3c_fb_set_par(struct fb_info *info)
 
 		data = VIDTCON2_LINEVAL(var->yres - 1) |
 		       VIDTCON2_HOZVAL(var->xres - 1);
-		writel(data, regs +sfb->variant.vidtcon + 8 );
+		writel(data, regs + sfb->variant.vidtcon + 8);
 	}
 
 	/* write the buffer address */
@@ -536,24 +640,17 @@ static int s3c_fb_set_par(struct fb_info *info)
 	writel(data, regs + sfb->variant.buf_size + (win_no * 4));
 
 	/* write 'OSD' registers to control position of framebuffer */
-
-	data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0);
-	writel(data, regs + VIDOSD_A(win_no, sfb->variant));
-
-	data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel,
-						     var->xres - 1)) |
-	       VIDOSDxB_BOTRIGHT_Y(var->yres - 1);
-
-	writel(data, regs + VIDOSD_B(win_no, sfb->variant));
-
-	data = var->xres * var->yres;
+	osd_win.left = 0;
+	osd_win.top = 0;
+	osd_win.width = var->xres;
+	osd_win.height = var->yres;
+	s3c_fb_set_osd(win, &osd_win, var->bits_per_pixel);
 
 	alpha = VIDISD14C_ALPHA1_R(0xf) |
 		VIDISD14C_ALPHA1_G(0xf) |
 		VIDISD14C_ALPHA1_B(0xf);
 
 	vidosd_set_alpha(win, alpha);
-	vidosd_set_size(win, data);
 
 	data = WINCONx_ENWIN;
 
@@ -714,6 +811,9 @@ static int s3c_fb_setcolreg(unsigned regno,
 	dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d\n",
 		__func__, win->index, regno, red, green, blue);
 
+	if (win->local_path)
+		return -EBUSY;
+
 	switch (info->fix.visual) {
 	case FB_VISUAL_TRUECOLOR:
 		/* true-colour, use pseudo-palette */
@@ -789,6 +889,9 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info)
 
 	dev_dbg(sfb->dev, "blank mode %d\n", blank_mode);
 
+	if (win->local_path)
+		return -EBUSY;
+
 	wincon = readl(sfb->regs + sfb->variant.wincon + (index * 4));
 
 	switch (blank_mode) {
@@ -896,6 +999,101 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var,
 }
 
 /**
+ * s3c_fb_enable_local() - switch window between input DMA and fifo modes
+ *
+ * @fb_sd: window subdevice for fifo input
+ * @en:    1 - switch from input DMA to fifo mode and apply
+ *	       window size and position set by the window's subdevice
+ *         0 - restore from fifo to DMA mode
+ */
+static int s3c_fb_enable_local_in(struct s3c_fb_win_sd *fb_sd, int en)
+{
+	struct s3c_fb_win *win = fb_sd->win;
+	struct s3c_fb *sfb = win->parent;
+	static u32 wincon;
+	u32 reg, data;
+	int ret = 0, bpp = 32;
+
+	/* disable video output and the window logic */
+	reg = readl(sfb->regs + WINCON(win->index));
+	writel(reg & ~WINCONx_ENWIN, sfb->regs + WINCON(win->index));
+
+	shadow_protect_win(win, 1);
+
+	if (en == 1) {
+		if (fb_sd->streaming)
+			return 0;
+
+		wincon = reg;
+
+		switch (fb_sd->fmt.fmt.pix.pixelformat) {
+		case V4L2_PIX_FMT_YUYV: /* YCbCr 4:4:4 */
+			reg |= WINCONx_YCbCr | WINCONx_ENLOCAL;
+			bpp = 16;
+			break;
+
+		case V4L2_PIX_FMT_RGB24:
+		default:
+			reg &= ~(WINCONx_YCbCr | WINCONx_WSWP | WINCONx_HAWSWP |
+				 WINCONx_BYTSWP | WINCONx_BITSWP |
+				 WINCON0_BPPMODE_MASK | WINCONx_BURSTLEN_MASK);
+
+			reg |=	WINCON0_BPPMODE_24BPP_888 |
+				WINCONx_BURSTLEN_4WORD;
+			bpp = 24;
+			break;
+		}
+
+		fb_sd->streaming = 1;
+		writel(reg, sfb->regs + WINCON(win->index));
+
+		s3c_fb_set_osd(fb_sd->win, &fb_sd->curr_osd_win, bpp);
+
+		writel(reg | WINCONx_ENLOCAL, sfb->regs + WINCON(win->index));
+
+		shadow_protect_win(win, 0);
+
+		reg = readl(sfb->regs + WINCON(win->index));
+		writel(reg | WINCONx_ENWIN, sfb->regs + WINCON(win->index));
+
+		if (sfb->variant.has_shadowcon)	{
+			data = readl(sfb->regs + SHADOWCON);
+			data |=	SHADOWCON_CHx_LOCAL_ENABLE(win->index);
+			writel(data, sfb->regs + SHADOWCON);
+		}
+
+	} else if (en == 0) {
+		if (!fb_sd->streaming)
+			return 0;
+
+		fb_sd->streaming = 0;
+
+		/* need to be aligned with VSYNC interrupt */
+		writel(wincon & ~WINCONx_ENLOCAL,
+		       sfb->regs + WINCON(win->index));
+
+		/* restore OSD values from before we enabled local mode */
+		bpp = win->fbinfo->var.bits_per_pixel;
+		s3c_fb_set_osd(fb_sd->win, &fb_sd->default_osd_win, bpp);
+
+		shadow_protect_win(win, 0);
+
+		if (sfb->variant.has_shadowcon)	{
+			data = readl(sfb->regs + SHADOWCON);
+			data &=	~SHADOWCON_CHx_LOCAL_ENABLE(win->index);
+			writel(data, sfb->regs + SHADOWCON);
+		}
+
+		reg = readl(sfb->regs + WINCON(win->index));
+		writel(reg | WINCONx_ENWIN, sfb->regs + WINCON(win->index));
+	} else {
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+/**
  * s3c_fb_enable_irq() - enable framebuffer interrupts
  * @sfb: main hardware state
  */
@@ -912,7 +1110,7 @@ static void s3c_fb_enable_irq(struct s3c_fb *sfb)
 		irq_ctrl_reg |= VIDINTCON0_INT_FRAME;
 
 		irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL0_MASK;
-		irq_ctrl_reg |= VIDINTCON0_FRAMESEL0_VSYNC;
+		irq_ctrl_reg |= VIDINTCON0_FRAMESEL0_FRONTPORCH;
 		irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL1_MASK;
 		irq_ctrl_reg |= VIDINTCON0_FRAMESEL1_NONE;
 
@@ -952,7 +1150,6 @@ static irqreturn_t s3c_fb_irq(int irq, void *dev_id)
 
 		/* VSYNC interrupt, accept it */
 		writel(VIDINTCON1_INT_FRAME, regs + VIDINTCON1);
-
 		sfb->vsync_info.count++;
 		wake_up_interruptible(&sfb->vsync_info.wait);
 	}
@@ -1089,6 +1286,246 @@ static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
 			      fbi->screen_base, fbi->fix.smem_start);
 }
 
+
+static struct s3c_fb_win_sd *to_fb_win_sd(struct v4l2_subdev *s)
+{
+	return container_of(s, struct s3c_fb_win_sd, sd);
+}
+
+/**
+ * v4l2_sd_fb_s_stream() - switch between DMA on local path mode
+ *
+ * @win: window to change operation mode for.
+ * @sd:
+ * @en: 1 - apply cropping rectangle and switch to local path,
+ *	0 - restore cropping rectangle and switch to input DMA mode.
+ */
+static int v4l2_sd_fb_s_stream(struct v4l2_subdev *sd, int en)
+{
+	unsigned long flags;
+	struct s3c_fb_win_sd *w_sd = to_fb_win_sd(sd);
+	struct s3c_fb_win *win = w_sd->win;
+	struct s3c_fb *sfb = win->parent;
+	int ret = 0;
+
+	if (win->index > 2)
+		return -EINVAL;
+
+	mutex_lock(&win->fbinfo->lock);
+
+	if (en == 1) {
+		ret = s3c_fb_enable_local_in(w_sd, en);
+		win->local_path = 1;
+	} else if (en == 0) {
+		/*
+		 * The fmc-frambuffer fifo need to be stopped shortly after
+		 * VSYNC, for this reason horizontal line count is additionally
+		 * examined after waking up by an interrupt. If it is 0 we are
+		 * still at VSYNC and therefore are save to disable fifo.
+		 */
+		ret = s3c_fb_wait_for_vsync(sfb, 0);
+
+		if (ret == -ETIMEDOUT)
+			goto ss_out;
+
+		local_irq_save(flags);
+
+		while (s3c_fb_get_line_count(sfb) != 0)
+			cpu_relax();
+
+		/* Stop FIFO at FIMC side */
+		v4l2_subdev_notify(&w_sd->sd, 0, NULL);
+
+		s3c_fb_enable_local_in(w_sd, 0);
+		local_irq_restore(flags);
+
+		win->local_path = 0;
+		ret = 0;
+	}
+ss_out:
+	mutex_unlock(&win->fbinfo->lock);
+	return ret;
+}
+
+/**
+ * v4l2_sd_fb_s_fmt() - set format for local input path mode
+ *
+ * @sd: pointer to v4l2 subdevice
+ * @fmt: pixel format to set
+ */
+static int v4l2_sd_fb_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+	struct s3c_fb_win_sd *fb_sd = to_fb_win_sd(sd);
+	int fourcc = fmt->fmt.pix.pixelformat;
+
+	if (!fmt || (fourcc != V4L2_PIX_FMT_YUYV
+		&& fourcc != V4L2_PIX_FMT_RGB24))
+		return -EINVAL;
+	fb_sd->fmt.fmt.pix.pixelformat = fmt->fmt.pix.pixelformat;
+	return 0;
+}
+
+/**
+ * v4l2_sd_fb_cropcap() - get cropping capabilities for local fifo input mode
+ *
+ * @sd: pointer to v4l2 subdevice
+ * @cc:
+ */
+static int v4l2_sd_fb_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *cc)
+{
+	struct s3c_fb_win *win = to_fb_win_sd(sd)->win;
+	struct s3c_fb_pd_win *windata = win->windata;
+
+	if (!windata)
+		return -ENODEV;
+
+	mutex_lock(&win->fbinfo->lock);
+
+	cc->defrect.width = windata->win_mode.xres;
+	cc->defrect.height = windata->win_mode.yres;
+	cc->defrect.left = 0;
+	cc->defrect.top = 0;
+	cc->bounds = cc->defrect;
+
+	mutex_unlock(&win->fbinfo->lock);
+
+	return 0;
+}
+
+/**
+ * v4l2_sd_fb_s_crop() - set window position and size
+ *
+ * @sd: pointer to v4l2 subdevice
+ * @cr: cropping rectangle to set for local path mode
+ */
+static int v4l2_sd_fb_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *cr)
+{
+	struct v4l2_rect *r;
+	struct s3c_fb_win_sd *fb_sd = to_fb_win_sd(sd);
+	u32 fourcc = fb_sd->fmt.fmt.pix.pixelformat;
+
+	fb_sd->curr_osd_win = cr->c;
+
+	if (fourcc == V4L2_PIX_FMT_YUYV) {
+		r = &cr->c;
+		r->left = round_down(r->left, 8);
+		r->top = round_down(r->top, 8);
+		r->width = round_down(r->width, 8);
+		r->height = round_down(r->height, 8);
+	}
+
+	return 0;
+}
+
+/**
+ * v4l2_sd_fb_g_crop() - set window position and size
+ *
+ * @sd: pointer to v4l2 subdevice
+ * @cr: rectangle to return current cropping parameters to
+ *
+ * Implements g_crop operation for camera interface driver.
+ */
+static int v4l2_sd_fb_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *cr)
+{
+	struct s3c_fb_win_sd *fb_sd = to_fb_win_sd(sd);
+
+	cr->c = fb_sd->curr_osd_win;
+
+	return 0;
+}
+
+
+static struct v4l2_subdev_core_ops v4l2_sd_core_fb_ops = { NULL };
+
+static struct v4l2_subdev_video_ops v4l2_sd_video_fb_ops = {
+	.s_stream = v4l2_sd_fb_s_stream,
+	.s_fmt = v4l2_sd_fb_s_fmt,
+	.cropcap = v4l2_sd_fb_cropcap,
+	.s_crop = v4l2_sd_fb_s_crop,
+	.g_crop = v4l2_sd_fb_g_crop,
+};
+
+static struct v4l2_subdev_ops v4l2_sd_fb_ops = {
+	.core = &v4l2_sd_core_fb_ops,
+	.video = &v4l2_sd_video_fb_ops,
+};
+
+static int s3c_fb_unregister_subdevices(struct s3c_fb_win *win)
+{
+	int i;
+	struct s3c_fb *sfb = win->parent;
+
+	if (win->index >= S3C_FB_MAX_WIN)
+		return -ENODEV;
+
+	for (i = 0; i < S3C_FB_MAX_WIN_SOURCES; i++) {
+		if (win->sources[i]) {
+			/* remove sub_dev pointer from link */
+			win->sources[i]->link->sub_dev = NULL;
+			kfree(win->sources[i]);
+			dev_dbg(sfb->dev,
+				"s3c-fb subdevice %d removed from window %d\n",
+				i, win->index);
+		}
+	}
+
+	return 0;
+}
+
+/* Create the subdevice per each data source of the framebuffer window.
+   Locking: The caller holds win->parent->dev->mutex. */
+static int s3c_fb_register_subdevices(struct s3c_fb_win *win)
+{
+	int i;
+	struct s3c_fb *sfb = win->parent;
+	struct s3c_fb_pd_win *windata = win->windata;
+	struct s3c_fb_win_sd *win_sd;
+	struct v4l2_rect *r;
+
+
+	if (win->index >= S3C_FB_MAX_WIN)
+		return -ENODEV;
+
+	for (i = 0; i < S3C_FB_MAX_WIN_SOURCES; i++) {
+		if (!windata->fifo_sources[i])
+			continue;
+		win_sd = kzalloc(sizeof(struct s3c_fb_win_sd), GFP_KERNEL);
+		if (win_sd == NULL)
+			return -ENOMEM;
+
+		win_sd->index = i;
+		win_sd->win = win;
+		win_sd->link = windata->fifo_sources[i];
+		win_sd->streaming = 0;
+		v4l2_subdev_init(&win_sd->sd, &v4l2_sd_fb_ops);
+		snprintf(win_sd->sd.name, sizeof(win_sd->sd.name),
+			 "s3cfb-local");
+
+		/* hook up pointer to slave device */
+		win_sd->link->sub_dev = &win_sd->sd;
+		win->sources[i] = win_sd;
+
+		/* set default rectangle to current window */
+		s3c_fb_get_osd(win, &win_sd->default_osd_win);
+
+		/* set fimc fifo output rectangle to current window */
+		r = &win_sd->curr_osd_win;
+		r->width = windata->win_mode.xres;
+		r->height = windata->win_mode.yres;
+		r->left = 0;
+		r->top = 0;
+
+		win_sd->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
+
+		dev_dbg(sfb->dev, "%s(): l:%d t:%d w:%d h:%d",
+			__func__, r->left, r->top, r->width, r->height);
+
+		dev_dbg(sfb->dev, "subdevice %d registered at window %d\n",
+			i, win->index);
+	}
+	return 0;
+}
+
 /**
  * s3c_fb_release_win() - release resources for a framebuffer window.
  * @win: The window to cleanup the resources for.
@@ -1107,6 +1544,7 @@ static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win)
 			data &= ~SHADOWCON_CHx_LOCAL_ENABLE(win->index);
 			writel(data, sfb->regs + SHADOWCON);
 		}
+		s3c_fb_unregister_subdevices(win);
 		unregister_framebuffer(win->fbinfo);
 		if (win->fbinfo->cmap.len)
 			fb_dealloc_cmap(&win->fbinfo->cmap);
@@ -1165,6 +1603,7 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
 	win->windata = windata;
 	win->index = win_no;
 	win->palette_buffer = (u32 *)(win + 1);
+	win->local_path = 0;
 
 	ret = s3c_fb_alloc_memory(sfb, win);
 	if (ret) {
@@ -1220,11 +1659,16 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
 	else
 		dev_err(sfb->dev, "failed to allocate fb cmap\n");
 
+	/* run the check_var and set_par on our configuration. */
 	s3c_fb_set_par(fbinfo);
 
-	dev_dbg(sfb->dev, "about to register framebuffer\n");
+	ret =  s3c_fb_register_subdevices(win);
+	if (ret < 0) {
+		dev_err(sfb->dev, "failed to register s3c-fb subdevices\n");
+		return ret;
+	}
 
-	/* run the check_var and set_par on our configuration. */
+	dev_dbg(sfb->dev, "about to register framebuffer\n");
 
 	ret = register_framebuffer(fbinfo);
 	if (ret < 0) {
@@ -1328,6 +1772,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
 		ret = -ENOENT;
 		goto err_ioremap;
 	}
+
 	sfb->irq_no = res->start;
 	ret = request_irq(sfb->irq_no, s3c_fb_irq,
 			  0, "s3c_fb", sfb);
-- 
1.7.0.4




More information about the linux-arm-kernel mailing list