Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 18946f62 authored by Tomi Valkeinen's avatar Tomi Valkeinen
Browse files

OMAP: DSS2: move update() and sync()



Move update() and sync() from omap_dss_device to omap_dss_driver.

Also, update was hardcoded to use virtual channel 0. This patch adds a
parameter that specifies the VC.

This is part of a larger patch-set, which moves the control from omapdss
driver to the display driver.

Signed-off-by: default avatarTomi Valkeinen <tomi.valkeinen@nokia.com>
parent 446f7bff
Loading
Loading
Loading
Loading
+18 −6
Original line number Diff line number Diff line
@@ -474,9 +474,6 @@ struct omap_dss_device {
			struct omap_video_timings *timings);
	void (*get_timings)(struct omap_dss_device *dssdev,
			struct omap_video_timings *timings);
	int (*update)(struct omap_dss_device *dssdev,
			       u16 x, u16 y, u16 w, u16 h);
	int (*sync)(struct omap_dss_device *dssdev);

	int (*set_wss)(struct omap_dss_device *dssdev, u32 wss);
	u32 (*get_wss)(struct omap_dss_device *dssdev);
@@ -500,15 +497,16 @@ struct omap_dss_driver {
	int (*resume)(struct omap_dss_device *display);
	int (*run_test)(struct omap_dss_device *display, int test);

	void (*setup_update)(struct omap_dss_device *dssdev,
			u16 x, u16 y, u16 w, u16 h);
	int (*set_update_mode)(struct omap_dss_device *dssdev,
			enum omap_dss_update_mode);
	enum omap_dss_update_mode (*get_update_mode)(
			struct omap_dss_device *dssdev);

	int (*update)(struct omap_dss_device *dssdev,
			       u16 x, u16 y, u16 w, u16 h);
	int (*sync)(struct omap_dss_device *dssdev);

	int (*enable_te)(struct omap_dss_device *dssdev, bool enable);
	int (*wait_for_te)(struct omap_dss_device *dssdev);
	int (*get_te)(struct omap_dss_device *dssdev);

	u8 (*get_rotate)(struct omap_dss_device *dssdev);
@@ -566,4 +564,18 @@ int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
void omapdss_dsi_vc_enable_hs(int channel, bool enable);
int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable);

int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
				    u16 *x, u16 *y, u16 *w, u16 *h);
int omap_dsi_update(struct omap_dss_device *dssdev,
		int channel,
		u16 x, u16 y, u16 w, u16 h,
		void (*callback)(int, void *), void *data);

int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
		u16 *x, u16 *y, u16 *w, u16 *h);
int omap_rfbi_update(struct omap_dss_device *dssdev,
		u16 x, u16 y, u16 w, u16 h,
		void (*callback)(void *), void *data);


#endif
+54 −22
Original line number Diff line number Diff line
@@ -725,10 +725,58 @@ static int taal_resume(struct omap_dss_device *dssdev)
	return 0;
}

static void taal_setup_update(struct omap_dss_device *dssdev,
static void taal_framedone_cb(int err, void *data)
{
	struct omap_dss_device *dssdev = data;
	dev_dbg(&dssdev->dev, "framedone, err %d\n", err);
	dsi_bus_unlock();
}

static int taal_update(struct omap_dss_device *dssdev,
				    u16 x, u16 y, u16 w, u16 h)
{
	taal_set_update_window(x, y, w, h);
	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
	int r;

	dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);

	dsi_bus_lock();

	if (!td->enabled) {
		r = 0;
		goto err;
	}

	r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h);
	if (r)
		goto err;

	r = taal_set_update_window(x, y, w, h);
	if (r)
		goto err;

	r = omap_dsi_update(dssdev, TCH, x, y, w, h,
			taal_framedone_cb, dssdev);
	if (r)
		goto err;

	/* note: no bus_unlock here. unlock is in framedone_cb */
	return 0;
err:
	dsi_bus_unlock();
	return r;
}

static int taal_sync(struct omap_dss_device *dssdev)
{
	dev_dbg(&dssdev->dev, "sync\n");

	dsi_bus_lock();
	dsi_bus_unlock();

	dev_dbg(&dssdev->dev, "sync done\n");

	return 0;
}

static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
@@ -762,24 +810,6 @@ static int taal_get_te(struct omap_dss_device *dssdev)
	return td->te_enabled;
}

static int taal_wait_te(struct omap_dss_device *dssdev)
{
	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
	long wait = msecs_to_jiffies(500);

	if (!td->use_ext_te || !td->te_enabled)
		return 0;

	INIT_COMPLETION(td->te_completion);
	wait = wait_for_completion_timeout(&td->te_completion, wait);
	if (wait == 0) {
		dev_err(&dssdev->dev, "timeout waiting TE\n");
		return -ETIME;
	}

	return 0;
}

static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
{
	struct taal_data *td = dev_get_drvdata(&dssdev->dev);
@@ -1018,15 +1048,17 @@ static struct omap_dss_driver taal_driver = {
	.suspend	= taal_suspend,
	.resume		= taal_resume,

	.setup_update	= taal_setup_update,
	.set_update_mode = taal_set_update_mode,
	.get_update_mode = taal_get_update_mode,

	.update		= taal_update,
	.sync		= taal_sync,

	.get_resolution	= taal_get_resolution,
	.get_recommended_bpp = omapdss_default_get_recommended_bpp,

	.enable_te	= taal_enable_te,
	.get_te		= taal_get_te,
	.wait_for_te	= taal_wait_te,

	.set_rotate	= taal_rotate,
	.get_rotate	= taal_get_rotate,
+115 −207
Original line number Diff line number Diff line
@@ -31,8 +31,8 @@
#include <linux/seq_file.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/workqueue.h>

#include <plat/display.h>
#include <plat/clock.h>
@@ -200,7 +200,6 @@ enum dsi_vc_mode {
};

struct dsi_update_region {
	bool dirty;
	u16 x, y, w, h;
	struct omap_dss_device *device;
};
@@ -234,18 +233,18 @@ static struct

	struct completion bta_completion;

	struct task_struct *thread;
	wait_queue_head_t waitqueue;

	spinlock_t update_lock;
	bool framedone_received;
	int update_channel;
	struct dsi_update_region update_region;
	struct dsi_update_region active_update_region;
	struct completion update_completion;

	bool te_enabled;
	bool use_ext_te;

	struct work_struct framedone_work;
	void (*framedone_callback)(int, void *);
	void *framedone_data;

	struct delayed_work framedone_timeout_work;

#ifdef DSI_CATCH_MISSING_TE
	struct timer_list te_timer;
#endif
@@ -357,9 +356,9 @@ static void dsi_perf_show(const char *name)

	total_us = setup_us + trans_us;

	total_bytes = dsi.active_update_region.w *
		dsi.active_update_region.h *
		dsi.active_update_region.device->ctrl.pixel_size / 8;
	total_bytes = dsi.update_region.w *
		dsi.update_region.h *
		dsi.update_region.device->ctrl.pixel_size / 8;

	printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
			"%u bytes, %u kbytes/sec\n",
@@ -2725,7 +2724,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
	unsigned packet_len;
	u32 l;
	bool use_te_trigger;
	const unsigned channel = 0;
	const unsigned channel = dsi.update_channel;
	/* line buffer is 1024 x 24bits */
	/* XXX: for some reason using full buffer size causes considerable TX
	 * slowdown with update sizes that fill the whole buffer */
@@ -2736,6 +2735,8 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
	DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n",
			x, y, w, h);

	dsi_vc_config_vp(channel);

	bytespp	= dssdev->ctrl.pixel_size / 8;
	bytespl = w * bytespp;
	bytespf = bytespl * h;
@@ -2773,6 +2774,11 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
	 */
	dispc_disable_sidle();

	dsi_perf_mark_start();

	schedule_delayed_work(&dsi.framedone_timeout_work,
			msecs_to_jiffies(250));

	dss_start_update(dssdev);

	if (use_te_trigger) {
@@ -2795,47 +2801,63 @@ static void dsi_te_timeout(unsigned long arg)
}
#endif

static void dsi_framedone_irq_callback(void *data, u32 mask)
static void dsi_framedone_timeout_work_callback(struct work_struct *work)
{
	/* Note: We get FRAMEDONE when DISPC has finished sending pixels and
	 * turns itself off. However, DSI still has the pixels in its buffers,
	 * and is sending the data.
	 */
	int r;
	const int channel = dsi.update_channel;
	bool use_te_trigger;

	DSSERR("Framedone not received for 250ms!\n");

	/* SIDLEMODE back to smart-idle */
	dispc_enable_sidle();

	dsi.framedone_received = true;
	wake_up(&dsi.waitqueue);
	use_te_trigger = dsi.te_enabled && !dsi.use_ext_te;

	if (use_te_trigger) {
		/* enable LP_RX_TO again after the TE */
		REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
	}

static void dsi_set_update_region(struct omap_dss_device *dssdev,
		u16 x, u16 y, u16 w, u16 h)
{
	spin_lock(&dsi.update_lock);
	if (dsi.update_region.dirty) {
		dsi.update_region.x = min(x, dsi.update_region.x);
		dsi.update_region.y = min(y, dsi.update_region.y);
		dsi.update_region.w = max(w, dsi.update_region.w);
		dsi.update_region.h = max(h, dsi.update_region.h);
	} else {
		dsi.update_region.x = x;
		dsi.update_region.y = y;
		dsi.update_region.w = w;
		dsi.update_region.h = h;
	/* Send BTA after the frame. We need this for the TE to work, as TE
	 * trigger is only sent for BTAs without preceding packet. Thus we need
	 * to BTA after the pixel packets so that next BTA will cause TE
	 * trigger.
	 *
	 * This is not needed when TE is not in use, but we do it anyway to
	 * make sure that the transfer has been completed. It would be more
	 * optimal, but more complex, to wait only just before starting next
	 * transfer. */
	r = dsi_vc_send_bta_sync(channel);
	if (r)
		DSSERR("BTA after framedone failed\n");

	/* RX_FIFO_NOT_EMPTY */
	if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
		DSSERR("Received error during frame transfer:\n");
		dsi_vc_flush_receive_data(channel);
	}

	dsi.update_region.device = dssdev;
	dsi.update_region.dirty = true;
	dsi.framedone_callback(-ETIMEDOUT, dsi.framedone_data);
}

static void dsi_framedone_irq_callback(void *data, u32 mask)
{
	/* Note: We get FRAMEDONE when DISPC has finished sending pixels and
	 * turns itself off. However, DSI still has the pixels in its buffers,
	 * and is sending the data.
	 */

	spin_unlock(&dsi.update_lock);
	/* SIDLEMODE back to smart-idle */
	dispc_enable_sidle();

	schedule_work(&dsi.framedone_work);
}

static void dsi_handle_framedone(void)
{
	int r;
	const int channel = 0;
	const int channel = dsi.update_channel;
	bool use_te_trigger;

	use_te_trigger = dsi.te_enabled && !dsi.use_ext_te;
@@ -2871,105 +2893,79 @@ static void dsi_handle_framedone(void)
#endif
}

static int dsi_update_thread(void *data)
static void dsi_framedone_work_callback(struct work_struct *work)
{
	unsigned long timeout;
	struct omap_dss_device *device;
	u16 x, y, w, h;

	while (1) {
		wait_event_interruptible(dsi.waitqueue,
				dsi.update_region.dirty == true ||
				kthread_should_stop());

		if (kthread_should_stop())
			break;
	DSSDBGF();

		dsi_bus_lock();
	cancel_delayed_work_sync(&dsi.framedone_timeout_work);

		if (kthread_should_stop()) {
			dsi_bus_unlock();
			break;
		}
	dsi_handle_framedone();

		dsi_perf_mark_setup();
	dsi_perf_show("DISPC");

		if (dsi.update_region.dirty) {
			spin_lock(&dsi.update_lock);
			dsi.active_update_region = dsi.update_region;
			dsi.update_region.dirty = false;
			spin_unlock(&dsi.update_lock);
	dsi.framedone_callback(0, dsi.framedone_data);
}

		device = dsi.active_update_region.device;
		x = dsi.active_update_region.x;
		y = dsi.active_update_region.y;
		w = dsi.active_update_region.w;
		h = dsi.active_update_region.h;
int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
				    u16 *x, u16 *y, u16 *w, u16 *h)
{
	u16 dw, dh;

		if (device->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
	dssdev->driver->get_resolution(dssdev, &dw, &dh);

			dss_setup_partial_planes(device,
					&x, &y, &w, &h);
	if  (*x > dw || *y > dh)
		return -EINVAL;

			dispc_set_lcd_size(w, h);
		}
	if (*x + *w > dw)
		return -EINVAL;

		if (dsi.active_update_region.dirty) {
			dsi.active_update_region.dirty = false;
			/* XXX TODO we don't need to send the coords, if they
			 * are the same that are already programmed to the
			 * panel. That should speed up manual update a bit */
			device->driver->setup_update(device, x, y, w, h);
		}
	if (*y + *h > dh)
		return -EINVAL;

		dsi_perf_mark_start();
	if (*w == 1)
		return -EINVAL;

		if (device->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
			dsi_vc_config_vp(0);
	if (*w == 0 || *h == 0)
		return -EINVAL;

			if (dsi.te_enabled && dsi.use_ext_te)
				device->driver->wait_for_te(device);
	dsi_perf_mark_setup();

			dsi.framedone_received = false;
	if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
		dss_setup_partial_planes(dssdev, x, y, w, h);
		dispc_set_lcd_size(*w, *h);
	}

			dsi_update_screen_dispc(device, x, y, w, h);
	return 0;
}
EXPORT_SYMBOL(omap_dsi_prepare_update);

			/* wait for framedone */
			timeout = msecs_to_jiffies(1000);
			wait_event_timeout(dsi.waitqueue,
					dsi.framedone_received == true,
					timeout);
int omap_dsi_update(struct omap_dss_device *dssdev,
		int channel,
		u16 x, u16 y, u16 w, u16 h,
		void (*callback)(int, void *), void *data)
{
	dsi.update_channel = channel;

			if (!dsi.framedone_received) {
				DSSERR("framedone timeout\n");
				DSSERR("failed update %d,%d %dx%d\n",
						x, y, w, h);
	if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
		dsi.framedone_callback = callback;
		dsi.framedone_data = data;

				dispc_enable_sidle();
				device->manager->disable(device->manager);
		dsi.update_region.x = x;
		dsi.update_region.y = y;
		dsi.update_region.w = w;
		dsi.update_region.h = h;
		dsi.update_region.device = dssdev;

				dsi_reset_tx_fifo(0);
			} else {
				dsi_handle_framedone();
				dsi_perf_show("DISPC");
			}
		dsi_update_screen_dispc(dssdev, x, y, w, h);
	} else {
			dsi_update_screen_l4(device, x, y, w, h);
		dsi_update_screen_l4(dssdev, x, y, w, h);
		dsi_perf_show("L4");
		callback(0, data);
	}

		complete_all(&dsi.update_completion);

		dsi_bus_unlock();
	}

	DSSDBG("update thread exiting\n");

	return 0;
}


EXPORT_SYMBOL(omap_dsi_update);

/* Display funcs */

@@ -3324,74 +3320,6 @@ static int dsi_display_resume(struct omap_dss_device *dssdev)
	return r;
}

static int dsi_display_update(struct omap_dss_device *dssdev,
			u16 x, u16 y, u16 w, u16 h)
{
	int r = 0;
	u16 dw, dh;

	DSSDBG("dsi_display_update(%d,%d %dx%d)\n", x, y, w, h);

	mutex_lock(&dsi.lock);

	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
		goto end;

	dssdev->driver->get_resolution(dssdev, &dw, &dh);

	if  (x > dw || y > dh)
		goto end;

	if (x + w > dw)
		w = dw - x;

	if (y + h > dh)
		h = dh - y;

	if (w == 0 || h == 0)
		goto end;

	if (w == 1) {
		r = -EINVAL;
		goto end;
	}

	dsi_set_update_region(dssdev, x, y, w, h);

	wake_up(&dsi.waitqueue);

end:
	mutex_unlock(&dsi.lock);

	return r;
}

static int dsi_display_sync(struct omap_dss_device *dssdev)
{
	bool wait;

	DSSDBG("dsi_display_sync()\n");

	mutex_lock(&dsi.lock);
	dsi_bus_lock();

	if (dsi.update_region.dirty) {
		INIT_COMPLETION(dsi.update_completion);
		wait = true;
	} else {
		wait = false;
	}

	dsi_bus_unlock();
	mutex_unlock(&dsi.lock);

	if (wait)
		wait_for_completion_interruptible(&dsi.update_completion);

	DSSDBG("dsi_display_sync() done\n");
	return 0;
}

int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
{
	dsi.te_enabled = enable;
@@ -3420,8 +3348,6 @@ int dsi_init_display(struct omap_dss_device *dssdev)
	dssdev->disable = dsi_display_disable;
	dssdev->suspend = dsi_display_suspend;
	dssdev->resume = dsi_display_resume;
	dssdev->update = dsi_display_update;
	dssdev->sync = dsi_display_sync;

	/* XXX these should be figured out dynamically */
	dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
@@ -3437,9 +3363,6 @@ int dsi_init(struct platform_device *pdev)
{
	u32 rev;
	int r;
	struct sched_param param = {
		.sched_priority = MAX_USER_RT_PRIO-1
	};

	spin_lock_init(&dsi.errors_lock);
	dsi.errors = 0;
@@ -3450,28 +3373,19 @@ int dsi_init(struct platform_device *pdev)
#endif

	init_completion(&dsi.bta_completion);
	init_completion(&dsi.update_completion);

	dsi.thread = kthread_create(dsi_update_thread, NULL, "dsi");
	if (IS_ERR(dsi.thread)) {
		DSSERR("cannot create kthread\n");
		r = PTR_ERR(dsi.thread);
		goto err0;
	}
	sched_setscheduler(dsi.thread, SCHED_FIFO, &param);

	init_waitqueue_head(&dsi.waitqueue);
	spin_lock_init(&dsi.update_lock);

	mutex_init(&dsi.lock);
	sema_init(&dsi.bus_lock, 1);

	INIT_WORK(&dsi.framedone_work, dsi_framedone_work_callback);
	INIT_DELAYED_WORK_DEFERRABLE(&dsi.framedone_timeout_work,
			dsi_framedone_timeout_work_callback);

#ifdef DSI_CATCH_MISSING_TE
	init_timer(&dsi.te_timer);
	dsi.te_timer.function = dsi_te_timeout;
	dsi.te_timer.data = 0;
#endif

	dsi.base = ioremap(DSI_BASE, DSI_SZ_REGS);
	if (!dsi.base) {
		DSSERR("can't ioremap DSI\n");
@@ -3495,21 +3409,15 @@ int dsi_init(struct platform_device *pdev)

	enable_clocks(0);

	wake_up_process(dsi.thread);

	return 0;
err2:
	iounmap(dsi.base);
err1:
	kthread_stop(dsi.thread);
err0:
	return r;
}

void dsi_exit(void)
{
	kthread_stop(dsi.thread);

	iounmap(dsi.base);

	DSSDBG("omap_dsi_exit\n");
+29 −261
Original line number Diff line number Diff line
@@ -36,8 +36,6 @@
#include <plat/display.h>
#include "dss.h"

/*#define MEASURE_PERF*/

#define RFBI_BASE               0x48050800

struct rfbi_reg { u16 idx; };
@@ -66,8 +64,6 @@ struct rfbi_reg { u16 idx; };
#define RFBI_VSYNC_WIDTH	RFBI_REG(0x0090)
#define RFBI_HSYNC_WIDTH	RFBI_REG(0x0094)

#define RFBI_CMD_FIFO_LEN_BYTES (16 * sizeof(struct update_param))

#define REG_FLD_MOD(idx, val, start, end) \
	rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end))

@@ -102,7 +98,6 @@ enum update_cmd {

static int rfbi_convert_timings(struct rfbi_timings *t);
static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div);
static void process_cmd_fifo(void);

static struct {
	void __iomem	*base;
@@ -125,11 +120,6 @@ static struct {
	struct completion cmd_done;
	atomic_t          cmd_fifo_full;
	atomic_t          cmd_pending;
#ifdef MEASURE_PERF
	unsigned perf_bytes;
	ktime_t perf_setup_time;
	ktime_t perf_start_time;
#endif
} rfbi;

struct update_region {
@@ -139,16 +129,6 @@ struct update_region {
	u16     h;
};

struct update_param {
	u8 rfbi_module;
	u8 cmd;

	union {
		struct update_region r;
		struct completion *sync;
	} par;
};

static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val)
{
	__raw_writel(val, rfbi.base + idx.idx);
@@ -321,55 +301,6 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
}
EXPORT_SYMBOL(omap_rfbi_write_pixels);

#ifdef MEASURE_PERF
static void perf_mark_setup(void)
{
	rfbi.perf_setup_time = ktime_get();
}

static void perf_mark_start(void)
{
	rfbi.perf_start_time = ktime_get();
}

static void perf_show(const char *name)
{
	ktime_t t, setup_time, trans_time;
	u32 total_bytes;
	u32 setup_us, trans_us, total_us;

	t = ktime_get();

	setup_time = ktime_sub(rfbi.perf_start_time, rfbi.perf_setup_time);
	setup_us = (u32)ktime_to_us(setup_time);
	if (setup_us == 0)
		setup_us = 1;

	trans_time = ktime_sub(t, rfbi.perf_start_time);
	trans_us = (u32)ktime_to_us(trans_time);
	if (trans_us == 0)
		trans_us = 1;

	total_us = setup_us + trans_us;

	total_bytes = rfbi.perf_bytes;

	DSSINFO("%s update %u us + %u us = %u us (%uHz), %u bytes, "
			"%u kbytes/sec\n",
			name,
			setup_us,
			trans_us,
			total_us,
			1000*1000 / total_us,
			total_bytes,
			total_bytes * 1000 / total_us);
}
#else
#define perf_mark_setup()
#define perf_mark_start()
#define perf_show(x)
#endif

void rfbi_transfer_area(u16 width, u16 height,
			     void (callback)(void *data), void *data)
{
@@ -396,8 +327,6 @@ void rfbi_transfer_area(u16 width, u16 height,
	if (!rfbi.te_enabled)
		l = FLD_MOD(l, 1, 4, 4); /* ITE */

	perf_mark_start();

	rfbi_write_reg(RFBI_CONTROL, l);
}

@@ -407,8 +336,6 @@ static void framedone_callback(void *data, u32 mask)

	DSSDBG("FRAMEDONE\n");

	perf_show("DISPC");

	REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0);

	rfbi_enable_clocks(0);
@@ -416,11 +343,10 @@ static void framedone_callback(void *data, u32 mask)
	callback = rfbi.framedone_callback;
	rfbi.framedone_callback = NULL;

	/*callback(rfbi.framedone_callback_data);*/
	if (callback != NULL)
		callback(rfbi.framedone_callback_data);

	atomic_set(&rfbi.cmd_pending, 0);

	process_cmd_fifo();
}

#if 1 /* VERBOSE */
@@ -937,52 +863,43 @@ int rfbi_configure(int rfbi_module, int bpp, int lines)
}
EXPORT_SYMBOL(rfbi_configure);

static int rfbi_find_display(struct omap_dss_device *dssdev)
int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
		u16 *x, u16 *y, u16 *w, u16 *h)
{
	if (dssdev == rfbi.dssdev[0])
		return 0;
	u16 dw, dh;

	if (dssdev == rfbi.dssdev[1])
		return 1;
	dssdev->driver->get_resolution(dssdev, &dw, &dh);

	BUG();
	return -1;
}
	if  (*x > dw || *y > dh)
		return -EINVAL;

	if (*x + *w > dw)
		return -EINVAL;

static void signal_fifo_waiters(void)
{
	if (atomic_read(&rfbi.cmd_fifo_full) > 0) {
		/* DSSDBG("SIGNALING: Fifo not full for waiter!\n"); */
		complete(&rfbi.cmd_done);
		atomic_dec(&rfbi.cmd_fifo_full);
	}
}
	if (*y + *h > dh)
		return -EINVAL;

/* returns 1 for async op, and 0 for sync op */
static int do_update(struct omap_dss_device *dssdev, struct update_region *upd)
{
	u16 x = upd->x;
	u16 y = upd->y;
	u16 w = upd->w;
	u16 h = upd->h;
	if (*w == 1)
		return -EINVAL;

	perf_mark_setup();
	if (*w == 0 || *h == 0)
		return -EINVAL;

	if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
		/*dssdev->driver->enable_te(dssdev, 1); */
		dss_setup_partial_planes(dssdev, &x, &y, &w, &h);
		dss_setup_partial_planes(dssdev, x, y, w, h);
		dispc_set_lcd_size(*w, *h);
	}

#ifdef MEASURE_PERF
	rfbi.perf_bytes = w * h * 2; /* XXX always 16bit */
#endif

	dssdev->driver->setup_update(dssdev, x, y, w, h);
	return 0;
}
EXPORT_SYMBOL(omap_rfbi_prepare_update);

int omap_rfbi_update(struct omap_dss_device *dssdev,
		u16 x, u16 y, u16 w, u16 h,
		void (*callback)(void *), void *data)
{
	if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
		rfbi_transfer_area(w, h, NULL, NULL);
		return 1;
		rfbi_transfer_area(w, h, callback, data);
	} else {
		struct omap_overlay *ovl;
		void __iomem *addr;
@@ -994,123 +911,12 @@ static int do_update(struct omap_dss_device *dssdev, struct update_region *upd)

		omap_rfbi_write_pixels(addr, scr_width, x, y, w, h);

		perf_show("L4");

		return 0;
	}
}

static void process_cmd_fifo(void)
{
	int len;
	struct update_param p;
	struct omap_dss_device *dssdev;
	unsigned long flags;

	if (atomic_inc_return(&rfbi.cmd_pending) != 1)
		return;

	while (true) {
		spin_lock_irqsave(&rfbi.cmd_lock, flags);

		len = kfifo_out(&rfbi.cmd_fifo, (unsigned char *)&p,
				  sizeof(struct update_param));
		if (len == 0) {
			DSSDBG("nothing more in fifo\n");
			atomic_set(&rfbi.cmd_pending, 0);
			spin_unlock_irqrestore(&rfbi.cmd_lock, flags);
			break;
		}

		/* DSSDBG("fifo full %d\n", rfbi.cmd_fifo_full.counter);*/

		spin_unlock_irqrestore(&rfbi.cmd_lock, flags);

		BUG_ON(len != sizeof(struct update_param));
		BUG_ON(p.rfbi_module > 1);

		dssdev = rfbi.dssdev[p.rfbi_module];

		if (p.cmd == RFBI_CMD_UPDATE) {
			if (do_update(dssdev, &p.par.r))
				break; /* async op */
		} else if (p.cmd == RFBI_CMD_SYNC) {
			DSSDBG("Signaling SYNC done!\n");
			complete(p.par.sync);
		} else
			BUG();
		callback(data);
	}

	signal_fifo_waiters();
}

static void rfbi_push_cmd(struct update_param *p)
{
	int ret;

	while (1) {
		unsigned long flags;
		int available;

		spin_lock_irqsave(&rfbi.cmd_lock, flags);
		available = RFBI_CMD_FIFO_LEN_BYTES -
			kfifo_len(&rfbi.cmd_fifo);

/*		DSSDBG("%d bytes left in fifo\n", available); */
		if (available < sizeof(struct update_param)) {
			DSSDBG("Going to wait because FIFO FULL..\n");
			spin_unlock_irqrestore(&rfbi.cmd_lock, flags);
			atomic_inc(&rfbi.cmd_fifo_full);
			wait_for_completion(&rfbi.cmd_done);
			/*DSSDBG("Woke up because fifo not full anymore\n");*/
			continue;
		}

		ret = kfifo_in(&rfbi.cmd_fifo, (unsigned char *)p,
				  sizeof(struct update_param));
/*		DSSDBG("pushed %d bytes\n", ret);*/

		spin_unlock_irqrestore(&rfbi.cmd_lock, flags);

		BUG_ON(ret != sizeof(struct update_param));

		break;
	}
}

static void rfbi_push_update(int rfbi_module, int x, int y, int w, int h)
{
	struct update_param p;

	p.rfbi_module = rfbi_module;
	p.cmd = RFBI_CMD_UPDATE;

	p.par.r.x = x;
	p.par.r.y = y;
	p.par.r.w = w;
	p.par.r.h = h;

	DSSDBG("RFBI pushed %d,%d %dx%d\n", x, y, w, h);

	rfbi_push_cmd(&p);

	process_cmd_fifo();
}

static void rfbi_push_sync(int rfbi_module, struct completion *sync_comp)
{
	struct update_param p;

	p.rfbi_module = rfbi_module;
	p.cmd = RFBI_CMD_SYNC;
	p.par.sync = sync_comp;

	rfbi_push_cmd(&p);

	DSSDBG("RFBI sync pushed to cmd fifo\n");

	process_cmd_fifo();
	return 0;
}
EXPORT_SYMBOL(omap_rfbi_update);

void rfbi_dump_regs(struct seq_file *s)
{
@@ -1155,12 +961,8 @@ int rfbi_init(void)
{
	u32 rev;
	u32 l;
	int r;

	spin_lock_init(&rfbi.cmd_lock);
	r = kfifo_alloc(&rfbi.cmd_fifo, RFBI_CMD_FIFO_LEN_BYTES, GFP_KERNEL);
	if (r)
		return r;

	init_completion(&rfbi.cmd_done);
	atomic_set(&rfbi.cmd_fifo_full, 0);
@@ -1196,42 +998,10 @@ void rfbi_exit(void)
{
	DSSDBG("rfbi_exit\n");

	kfifo_free(&rfbi.cmd_fifo);

	iounmap(rfbi.base);
}

/* struct omap_display support */
static int rfbi_display_update(struct omap_dss_device *dssdev,
			u16 x, u16 y, u16 w, u16 h)
{
	int rfbi_module;

	if (w == 0 || h == 0)
		return 0;

	rfbi_module = rfbi_find_display(dssdev);

	rfbi_push_update(rfbi_module, x, y, w, h);

	return 0;
}

static int rfbi_display_sync(struct omap_dss_device *dssdev)
{
	struct completion sync_comp;
	int rfbi_module;

	rfbi_module = rfbi_find_display(dssdev);

	init_completion(&sync_comp);
	rfbi_push_sync(rfbi_module, &sync_comp);
	DSSDBG("Waiting for SYNC to happen...\n");
	wait_for_completion(&sync_comp);
	DSSDBG("Released from SYNC\n");
	return 0;
}

static int rfbi_display_enable(struct omap_dss_device *dssdev)
{
	int r;
@@ -1291,8 +1061,6 @@ int rfbi_init_display(struct omap_dss_device *dssdev)
{
	dssdev->enable = rfbi_display_enable;
	dssdev->disable = rfbi_display_disable;
	dssdev->update = rfbi_display_update;
	dssdev->sync = rfbi_display_sync;

	rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;

+5 −5
Original line number Diff line number Diff line
@@ -172,7 +172,7 @@ static int omapfb_update_window_nolock(struct fb_info *fbi,
	if (x + w > dw || y + h > dh)
		return -EINVAL;

	return display->update(display, x, y, w, h);
	return display->driver->update(display, x, y, w, h);
}

/* This function is exported for SGX driver use */
@@ -496,18 +496,18 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
	switch (cmd) {
	case OMAPFB_SYNC_GFX:
		DBG("ioctl SYNC_GFX\n");
		if (!display || !display->sync) {
		if (!display || !display->driver->sync) {
			/* DSS1 never returns an error here, so we neither */
			/*r = -EINVAL;*/
			break;
		}

		r = display->sync(display);
		r = display->driver->sync(display);
		break;

	case OMAPFB_UPDATE_WINDOW_OLD:
		DBG("ioctl UPDATE_WINDOW_OLD\n");
		if (!display || !display->update) {
		if (!display || !display->driver->update) {
			r = -EINVAL;
			break;
		}
@@ -525,7 +525,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)

	case OMAPFB_UPDATE_WINDOW:
		DBG("ioctl UPDATE_WINDOW\n");
		if (!display || !display->update) {
		if (!display || !display->driver->update) {
			r = -EINVAL;
			break;
		}
Loading