linux-fbdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: amaora <nemashinist@rambler.ru>
To: linux-fbdev-devel@lists.sourceforge.net
Subject: True color framebuffer
Date: Sat, 6 Jun 2009 01:25:17 +0400	[thread overview]
Message-ID: <20090605212517.GA19565@core> (raw)

[-- Attachment #1: Type: text/plain, Size: 334 bytes --]

Hi,

I write framebuffer driver for the PCF8833, it work, but only if
xxx_fix.visual == FB_VISUAL_PSEUDOCOLOR, TRUECOLOR/DIRECTCOLOR don't work.
Kernel is blocked (stalled) in function register_framebuffer on line
fb_notifier_call_chain(...), i don't know how to find stall point more deep.
Why this happening?

Thanks,

Roman Belov


[-- Attachment #2: pcf8833.c --]
[-- Type: text/plain, Size: 8970 bytes --]

/*
 * Copyright (C) 2009, Roman Belov
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License. See the file COPYING in the main directory of this archive for
 * more details.
 *
 * Layout is based on pcf8833.c by Alexander Kudjashev
 *
 * This driver was written to be used with nokia 6100 lcd
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spinlock.h>

#define PCF8833_FB_MIRROR_X		0x00000040
#define PCF8833_FB_MIRROR_Y		0x00000080
#define PCF8833_FB_SWAP_XY		0x00000020

#define PCF8833_FB_3R3G2B		0x00000200
#define PCF8833_FB_4R4G4B		0x00000300
#define PCF8833_FB_5R6G5B		0x00000500

#define PCF8833_FB_WIDTH		130
#define PCF8833_FB_HEIGHT		130
#define PCF8833_FB_XOFF			1
#define PCF8833_FB_YOFF			1
#define PCF8833_FB_DEFCBITS		16

#define PCF8833_FB_MEMSIZE		(PCF8833_FB_WIDTH*PCF8833_FB_HEIGHT*PCF8833_FB_DEFCBITS/8)
#define PCF8833_FB_BUFFSIZE		(PCF8833_FB_MEMSIZE*2 + 7*2)

#define PCF8833_FB_QUEUESIZE		1024
#define PCF8833_FB_QUEUE_INC(val)	(((val)+1)&(PCF8833_FB_QUEUESIZE-1))

union pcf8833_rect {
	u32 _32;
	u8 _8[4];
};

struct pcf8833_queue {
	u32 buff[PCF8833_FB_QUEUESIZE];
	volatile int r, w;
};

static inline void
pcf8833_queue_init(struct pcf8833_queue *q)
{
	q->r = 0;
	q->w = 0;
}

static inline int
pcf8833_queue_read(struct pcf8833_queue *q, u32 *ret)
{
	int r = q->r;

	if (r != q->w) {
		*ret = q->buff[r];
		q->r = PCF8833_FB_QUEUE_INC(r);
		return 0;
	}

	return -1;
}

static inline int
pcf8833_queue_write(struct pcf8833_queue *q, u32 val)
{
	int w = q->w;
	int wn = PCF8833_FB_QUEUE_INC(w);

	if (q->r != wn) {
		q->buff[w] = val;
		q->w = wn;
		return 0;
	}

	return -1;
}

typedef u16 pixel_t;

struct pcf8833_par {
	struct spi_device *spi;
	struct spi_message msg;
	struct spi_transfer xfer;
	struct pcf8833_queue queue;
	u16 *buffer;
	pixel_t *screen;
};

static struct fb_fix_screeninfo pcf8833_fix __devinitdata = {
	.id             = "pcf8833",
	.type           = FB_TYPE_PACKED_PIXELS,
	.visual         = FB_VISUAL_PSEUDOCOLOR,
	.xpanstep       = 0,
	.ypanstep       = 0,
	.ywrapstep      = 0,
	.line_length    = PCF8833_FB_WIDTH * PCF8833_FB_DEFCBITS / 8,
	.accel          = FB_ACCEL_NONE
};

static struct fb_var_screeninfo pcf8833_var __devinitdata = {
	.xres           = PCF8833_FB_WIDTH,
	.yres           = PCF8833_FB_HEIGHT,
	.xres_virtual   = PCF8833_FB_WIDTH,
	.yres_virtual   = PCF8833_FB_HEIGHT,
	.height         = -1,
	.width          = -1,
	.activate       = FB_ACTIVATE_NOW,
	.vmode          = FB_VMODE_NONINTERLACED,
	.bits_per_pixel = PCF8833_FB_DEFCBITS,
	.red            = { 11, 5, 0 },
	.green          = { 5, 6, 0 },
	.blue           = { 0, 5, 0 },
	.nonstd         = 0
};

static void
pcf8833_command(struct spi_device *spi, u8 cmd)
{
	u16 w = (u16) cmd;
	spi_write(spi, (u8*)&w, 2);
}

static void
pcf8833_data(struct spi_device *spi, u8 data)
{
	u16 w = (u16) data | 0x0100;
	spi_write(spi, (u8*)&w, 2);
}

static int
pcf8833_blank(int blank_mode, struct fb_info *info)
{
	struct pcf8833_par *par = info->par;

	switch (blank_mode) {
		case FB_BLANK_UNBLANK:
			pcf8833_command(par->spi, 0x29);
			break;
		case FB_BLANK_NORMAL:
		case FB_BLANK_VSYNC_SUSPEND:
		case FB_BLANK_HSYNC_SUSPEND:
		case FB_BLANK_POWERDOWN:
			pcf8833_command(par->spi, 0x28);
			break;
		default:
			return -EINVAL;
	}

	return 0;
}

static int
pcf8833_add_rect(const pixel_t *screen,
		u16 *ptr,
		int xs,
		int ys,
		int xe,
		int ye)
{
	u16 *sv_ptr = ptr;
	const pixel_t *lptr;
	pixel_t col;
	int x, y;

	*ptr++ = 0x002a;
	*ptr++ = (u16) (xs + PCF8833_FB_XOFF) | 0x0100;
	*ptr++ = (u16) (xe + PCF8833_FB_XOFF) | 0x0100;
	*ptr++ = 0x002b;
	*ptr++ = (u16) (ys + PCF8833_FB_YOFF) | 0x0100;
	*ptr++ = (u16) (ye + PCF8833_FB_YOFF) | 0x0100;
	*ptr++ = 0x002c;

	for (y = ys; y <= ye; ++y) {
		lptr = screen + y * PCF8833_FB_WIDTH;
		for (x = xs; x <= xe; ++x) {
			col = *(lptr + x);
			*ptr++ = (u16) (col & 0x00ff) | 0x0100;
			*ptr++ = (u16) ((col >> 8) & 0x00ff) | 0x0100;
		}
	}

	return (ptr - sv_ptr) * 2;
}

static void
pcf8833_spi_callback(void *param)
{
	struct pcf8833_par *par = (struct pcf8833_par *) param;
	union pcf8833_rect rect;
	int ret;

	ret = pcf8833_queue_read(&par->queue, &rect._32);

	if (!ret) {
		ret = pcf8833_add_rect(par->screen, par->buffer,
				(int) rect._8[0],
				(int) rect._8[1],
				(int) rect._8[2],
				(int) rect._8[3]);

		par->xfer.len = ret;
		spi_async(par->spi, &par->msg);
	}
}

static void
pcf8833_vram_update(struct pcf8833_par *par,
		int xs,
		int ys,
		int xe,
		int ye)
{
	int ret;
	union pcf8833_rect rect;

	rect._8[0] = (u8) xs;
	rect._8[1] = (u8) ys;
	rect._8[2] = (u8) xe;
	rect._8[3] = (u8) ye;

	ret = pcf8833_queue_write(&par->queue, rect._32);

	if (ret < 0) {
		// wait for queue and try to write again 
	}

	if (par->msg.status == 0) {
		pcf8833_spi_callback(par);
	}
}

static int
pcf8833_loinit(struct spi_device *spi, int flags)
{
	int ret;
	spi->mode = SPI_MODE_0;
	spi->bits_per_word = 9;

	ret = spi_setup(spi);
	if (ret < 0)
		return ret;

	pcf8833_command(spi, 0x01);
	mdelay(10);

	pcf8833_command(spi, 0x11);
	mdelay(10);

	pcf8833_command(spi, 0x03);
	mdelay(10);

	pcf8833_command(spi, 0x20);
	mdelay(10);

	pcf8833_command(spi, 0x36);
	pcf8833_data(spi, flags & 0x000000ff);
	mdelay(10);

	pcf8833_command(spi, 0x3a);
	pcf8833_data(spi, (flags >> 8) & 0x000000ff);
	mdelay(10);

	pcf8833_command(spi, 0x29);
	mdelay(10);

	return 0;
}

void pcf8833_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
{
	sys_fillrect(p, rect);
	pcf8833_vram_update(p->par, rect->dx, rect->dy,
			rect->dx + rect->width - 1,
			rect->dy + rect->height - 1);
}

void pcf8833_copyarea(struct fb_info *p, const struct fb_copyarea *rect)
{
	sys_copyarea(p, rect);
	pcf8833_vram_update(p->par, rect->dx, rect->dy,
			rect->dx + rect->width - 1,
			rect->dy + rect->height - 1);
}

void pcf8833_imageblit(struct fb_info *p, const struct fb_image *rect)
{
	sys_imageblit(p, rect);
	pcf8833_vram_update(p->par, rect->dx, rect->dy,
			rect->dx + rect->width - 1,
			rect->dy + rect->height - 1);
}

static struct fb_ops pcf8833_ops = {
	.owner          = THIS_MODULE,
	.fb_read        = fb_sys_read,
	.fb_write       = fb_sys_write,
	.fb_fillrect    = pcf8833_fillrect,
	.fb_copyarea    = pcf8833_copyarea,
	.fb_imageblit   = pcf8833_imageblit,
	.fb_blank       = pcf8833_blank,
};

static int __devinit pcf8833_probe(struct spi_device *spi)
{
	struct fb_info *info;
	struct pcf8833_par *par;
	int ret;

	printk(KERN_INFO "Philips PCF8833 framebuffer driver\n");

	ret = pcf8833_loinit(spi, PCF8833_FB_5R6G5B | PCF8833_FB_MIRROR_X | PCF8833_FB_MIRROR_Y);
	if (ret < 0)
		return ret;

	ret = -ENOMEM;

	info = framebuffer_alloc(sizeof(struct pcf8833_par), &spi->dev);
	if (!info)
		return ret;

	info->fbops = &pcf8833_ops;
	info->var = pcf8833_var;
	info->fix = pcf8833_fix;
	info->flags = FBINFO_FLAG_DEFAULT;

	par = info->par;
	par->spi = spi;

	pcf8833_queue_init(&par->queue);

	par->screen = vmalloc(PCF8833_FB_MEMSIZE);
	if (!par->screen)
		goto err_fb_release;

	memset(par->screen, 0, PCF8833_FB_MEMSIZE);
	info->screen_base = (char __iomem *) par->screen;
	info->screen_size = PCF8833_FB_MEMSIZE;

	par->buffer = kmalloc(PCF8833_FB_BUFFSIZE, GFP_KERNEL | GFP_DMA);
	if (!par->buffer)
		goto err_screen_free;

	spi_message_init(&par->msg);
	spi_message_add_tail(&par->xfer, &par->msg);

	par->xfer.tx_buf = par->buffer;
	par->msg.complete = pcf8833_spi_callback;
	par->msg.context = par;

	ret = register_framebuffer(info);
	if (ret < 0)
		goto err_buffer_free;

	dev_set_drvdata(&spi->dev, info);

	printk(KERN_INFO "fb%d: %s fb device, %dK of video memory\n",
	       info->node, info->fix.id, PCF8833_FB_MEMSIZE >> 10);

	return 0;

err_buffer_free:
	kfree(par->buffer);
err_screen_free:
	vfree(par->screen);
err_fb_release:
	framebuffer_release(info);

	return ret;
}

static int __devexit pcf8833_remove(struct spi_device *spi)
{
	struct fb_info *info = dev_get_drvdata(&spi->dev);

	if (info) {
		struct pcf8833_par *par = info->par;

		pcf8833_command(spi, 0x28);

		unregister_framebuffer(info);
		kfree(par->buffer);
		vfree(par->screen);
		framebuffer_release(info);
	}

	return 0;
}

static struct spi_driver pcf8833_driver = {
	.driver = {
		.name       = "pcf8833",
		.bus        = &spi_bus_type,
		.owner      = THIS_MODULE,
	},
	.probe      = pcf8833_probe,
	.remove     = __devexit_p(pcf8833_remove),
};

static int __init pcf8833_init(void)
{
	return spi_register_driver(&pcf8833_driver);
}

static void __exit pcf8833_exit(void)
{
	spi_unregister_driver(&pcf8833_driver);
}

module_init(pcf8833_init);
module_exit(pcf8833_exit);

MODULE_AUTHOR("Roman Belov");
MODULE_DESCRIPTION("PCF8833 fb driver");
MODULE_LICENSE("GPL");


[-- Attachment #3: Type: text/plain, Size: 408 bytes --]

------------------------------------------------------------------------------
OpenSolaris 2009.06 is a cutting edge operating system for enterprises 
looking to deploy the next generation of Solaris that includes the latest 
innovations from Sun and the OpenSource community. Download a copy and 
enjoy capabilities such as Networking, Storage and Virtualization. 
Go to: http://p.sf.net/sfu/opensolaris-get

[-- Attachment #4: Type: text/plain, Size: 182 bytes --]

_______________________________________________
Linux-fbdev-devel mailing list
Linux-fbdev-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-fbdev-devel

             reply	other threads:[~2009-06-05 21:22 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-06-05 21:25 amaora [this message]
2009-06-06 19:00 ` True color framebuffer amaora

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20090605212517.GA19565@core \
    --to=nemashinist@rambler.ru \
    --cc=linux-fbdev-devel@lists.sourceforge.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).