All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.