mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: "Magnus Damm" <magnus.damm@gmail.com>
To: "Uwe Kleine-König" <Uwe.Kleine-Koenig@digi.com>
Cc: "Paul Mundt" <lethal@linux-sh.org>,
	"Hans J. Koch" <hjk@linutronix.de>,
	linux-kernel@vger.kernel.org, gregkh@suse.de,
	linux-sh@vger.kernel.org, "Katsuya MATSUBARA" <matsu@igel.co.jp>
Subject: Re: [PATCH 00/03][RFC] Reusable UIO Platform Driver
Date: Wed, 21 May 2008 17:22:32 +0900	[thread overview]
Message-ID: <aec7e5c30805210122w5bdb8443r69bb7776e085276b@mail.gmail.com> (raw)
In-Reply-To: <20080521080503.GA28751@digi.com>

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

On Wed, May 21, 2008 at 5:05 PM, Uwe Kleine-König
<Uwe.Kleine-Koenig@digi.com> wrote:
> @Magnus: Maybe you can provide the userspace part of the driver?
> How is that mapping used there?

[Added Matsubara-san as CC]

Sure, here is a little test program. Have a look at "uio_mem". The
"address" member contains the physical address that can be used for
bus mastering DMA. Compare that to "iomem" which is the pointer to the
virtual memory area in user space.

Hope this helps!

/ magnus

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: veu_lab.c --]
[-- Type: text/x-csrc; name=veu_lab.c, Size: 7353 bytes --]

/*
 * sh7722 VEU scaling example using UIO - 20080521 Magnus Damm
 *
 * Derived from
 * "Simple tick timer through Sky TMU UIO driver" by Katsuya Matsubara
 */
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/fb.h>

static int fgets_with_openclose(char *fname, char *buf, size_t maxlen) {
	FILE *fp;

	if ((fp = fopen(fname, "r")) != NULL) {
		fgets(buf, maxlen, fp);
		fclose(fp);
		return strlen(buf);
	} else {
		return -1;
	}
}

struct uio_device {
  char *name;
  char *path;
  int fd;
};

#define MAXUIOIDS  100
#define MAXNAMELEN 256

static int locate_uio_device(char *name, struct uio_device *udp)
{
	char fname[MAXNAMELEN], buf[MAXNAMELEN];
	int uio_id;

	for (uio_id = 0; uio_id < MAXUIOIDS; uio_id++) {
		sprintf(fname, "/sys/class/uio/uio%d/name", uio_id);
		if (fgets_with_openclose(fname, buf, MAXNAMELEN) < 0)
			continue;
		if (strncmp(name, buf, strlen(name)) == 0)
			break;
	}

	if (uio_id >= MAXUIOIDS)
		return -1;

	udp->name = strdup(buf);
	udp->path = strdup(fname);
	udp->path[strlen(udp->path) - 4] = '\0';

	sprintf(buf, "/dev/uio%d", uio_id);
	udp->fd = open(buf, O_RDWR|O_SYNC);

	if (udp->fd < 0) {
		perror("open");
		return -1;
	}

	return 0;
}

struct uio_map {
  unsigned long address;
  unsigned long size;
  void *iomem;
};

static int setup_uio_map(struct uio_device *udp, int nr, struct uio_map *ump)
{
	char fname[MAXNAMELEN], buf[MAXNAMELEN];
 
	sprintf(fname, "%s/maps/map%d/addr", udp->path, nr);
	if (fgets_with_openclose(fname, buf, MAXNAMELEN) <= 0)
		return -1;

	ump->address = strtoul(buf, NULL, 0);

	sprintf(fname, "%s/maps/map%d/size", udp->path, nr);
	if (fgets_with_openclose(fname, buf, MAXNAMELEN) <= 0)
		return -1;

	ump->size = strtoul(buf, NULL, 0);

	ump->iomem = mmap(0, ump->size,
			  PROT_READ|PROT_WRITE, MAP_SHARED,
			  udp->fd, nr * getpagesize());

	if (ump->iomem == MAP_FAILED)
		return -1;

	return 0;
}

struct fb_info {
  unsigned long width;
  unsigned long height;
  unsigned long bpp;
  unsigned long line_length;

  unsigned long address;
  unsigned long size;
};

static int get_fb_info(char *device, struct fb_info *fip)
{
	struct fb_var_screeninfo vinfo;
	struct fb_fix_screeninfo finfo;
	int fd;

	fd = open(device, O_RDWR);
	if (fd < 0) {
		perror("open");
		return -1;
	}

	if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
		perror("ioctl(FBIOGET_VSCREENINFO)");
		return -1;
	}

	fip->width = vinfo.xres;
	fip->height = vinfo.yres;
	fip->bpp = vinfo.bits_per_pixel;

	if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) {
		perror("ioctl(FBIOGET_FSCREENINFO)");
		return -1;
	}

	fip->address = finfo.smem_start;
	fip->size = finfo.smem_len;
	fip->line_length = finfo.line_length;
	
	close(fd);
	return 0;
}

#define VESTR 0x00 /* start register */
#define VESWR 0x10 /* src: line length */
#define VESSR 0x14 /* src: image size */
#define VSAYR 0x18 /* src: y/rgb plane address */
#define VSACR 0x1c /* src: c plane address */
#define VBSSR 0x20 /* bundle mode register */
#define VEDWR 0x30 /* dst: line length */
#define VDAYR 0x34 /* dst: y/rgb plane address */
#define VDACR 0x38 /* dst: c plane address */
#define VTRCR 0x50 /* transform control */
#define VRFCR 0x54 /* resize scale */
#define VRFSR 0x58 /* resize clip */
#define VENHR 0x5c /* enhance */
#define VFMCR 0x70 /* filter mode */ 
#define VVTCR 0x74 /* lowpass vertical */
#define VHTCR 0x78 /* lowpass horizontal */
#define VAPCR 0x80 /* color match */
#define VECCR 0x84 /* color replace */
#define VAFXR 0x90 /* fixed mode */
#define VSWPR 0x94 /* swap */
#define VEIER 0xa0 /* interrupt mask */
#define VEVTR 0xa4 /* interrupt event */
#define VSTAR 0xb0 /* status */
#define VBSRR 0xb4 /* reset */

static unsigned long read_reg(struct uio_map *ump, int reg_nr)
{
	  volatile unsigned long *reg = ump->iomem + reg_nr;

	  return *reg;
}

static void write_reg(struct uio_map *ump, unsigned long value, int reg_nr)
{
	  volatile unsigned long *reg = ump->iomem + reg_nr;

	  *reg = value;
}

static void set_scale(struct uio_map *ump, int vertical,
		      int size_in, int size_out)
{
	unsigned long fixpoint, mant, frac, value;

	/* calculate FRAC and MANT */

	fixpoint = (4096 * (size_in - 1)) / (size_out + 1);
	mant = fixpoint / 4096;
	frac = fixpoint - (mant * 4096);

	if (frac & 0x07) {
		frac &= ~0x07;

		if (size_out > size_in)
			frac -= 8; /* round down if scaling up */
		else
			frac += 8; /* round up if scaling down */
	}

	/* set scale */
	
	value = read_reg(ump, VRFCR);
	
	if (vertical) {
		value &= ~0xffff0000;
  		value |= ((mant << 12) | frac) << 16;
	}
	else {
		value &= ~0xffff;
  		value |= (mant << 12) | frac;
	}
	
	write_reg(ump, value, VRFCR);

	/* set clip */

	value = read_reg(ump, VRFSR);

	if (vertical) {
		value &= ~0xffff0000;
  		value |= size_out << 16;
	}
	else {
		value &= ~0xffff;
  		value |= size_out;
	}
	
	write_reg(ump, value, VRFSR);
}

static int foo(void)
{
	struct fb_info fbi;
	struct uio_device uio_dev;
	struct uio_map uio_mmio, uio_mem;
	unsigned long addr;
	int src_w, src_h, src_bpp;
	int dst_w, dst_h;
	int ret;

	ret = get_fb_info("/dev/fb0", &fbi);
	if (ret < 0)
		return ret;

	printf("using %lux%lu %ld bpp framebuffer at 0x%08lx (0x%08lx).\n",
	       fbi.width, fbi.height, fbi.bpp, fbi.address, fbi.size);

	ret = locate_uio_device("VEU", &uio_dev);
	if (ret < 0)
		return ret;
	
	printf("found matching UIO device at %s\n", uio_dev.path);

	ret = setup_uio_map(&uio_dev, 0, &uio_mmio);
	if (ret < 0)
		return ret;

	ret = setup_uio_map(&uio_dev, 1, &uio_mem);
	if (ret < 0)
		return ret;

	printf("VSTAR = 0x%lx\n", read_reg(&uio_mmio, VSTAR));
	printf("VEVTR = 0x%lx\n", read_reg(&uio_mmio, VEVTR));

	/* reset VEU */

	printf("VBSRR = 0x%lx\n", read_reg(&uio_mmio, VBSRR));
	write_reg(&uio_mmio, 0x100, VBSRR);
	printf("VBSRR(2) = 0x%lx\n", read_reg(&uio_mmio, VBSRR));

	/* destination: get from fb */

	dst_w = fbi.width;
	dst_h = fbi.height;

	/* source bitmap */

	src_w = 32;
	src_h = 32;
	src_bpp = 16;

 new_color:

	{
	  struct timeval tv;
	  int k;
	  unsigned char *buf = uio_mem.iomem;

	  gettimeofday(&tv, NULL);

	  for (k = 0; k < (src_w * src_h * (src_bpp / 8)); k++)
		buf[k] = k ^ (tv.tv_sec + tv.tv_usec);
	}

	addr = fbi.address;
	addr += (fbi.bpp / 8) * ((fbi.width - dst_w) / 2);
	addr += fbi.line_length * ((fbi.height - dst_h) / 2);

 again:
	write_reg(&uio_mmio, src_w * (src_bpp / 8), VESWR);
	write_reg(&uio_mmio, src_w | (src_h << 16), VESSR);
	write_reg(&uio_mmio, uio_mem.address, VSAYR);
	write_reg(&uio_mmio, 0, VSACR); /* unused in case of RGB */
	write_reg(&uio_mmio, 0, VBSSR); /* not using bundle mode */

	write_reg(&uio_mmio, fbi.line_length, VEDWR);
	write_reg(&uio_mmio, addr, VDAYR);
	write_reg(&uio_mmio, 0, VDACR); /* unused in case of RGB */

	write_reg(&uio_mmio, (6 << 16) | (3 << 8) | 1, VTRCR);

	set_scale(&uio_mmio, 0, src_w, dst_w);
	set_scale(&uio_mmio, 1, src_h, dst_h);

	write_reg(&uio_mmio, 1, VEIER); /* enable interrupt */
	write_reg(&uio_mmio, 1, VESTR);

	/* Wait for an interrupt */
	{
		unsigned long n_pending;
		read(uio_dev.fd, &n_pending, sizeof(u_long));
	}

	write_reg(&uio_mmio, 0x100, VEVTR); /* ack int, write 0 to bit 0 */

	goto again;
	goto new_color;
} 

int main(int argc, char ** argv)
{
	foo();

	return 0;
}

  reply	other threads:[~2008-05-21  8:23 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-05-20 10:51 Magnus Damm
2008-05-20 10:51 ` [PATCH 01/03] uio: Add enable_irq() callback Magnus Damm
2008-05-21 11:58   ` Magnus Damm
2008-05-22 20:18     ` Hans J. Koch
2008-05-23  1:24       ` Magnus Damm
2008-05-23  8:43         ` Hans J. Koch
2008-05-20 10:51 ` [PATCH 02/03] uio: Add uio_platform driver Magnus Damm
2008-05-20 10:51 ` [PATCH 03/03] sh: Export sh7343/sh7722/sh7723 VPU/VEU blocks Magnus Damm
2008-05-20 21:07 ` [PATCH 00/03][RFC] Reusable UIO Platform Driver Hans J. Koch
2008-05-21  3:31   ` Magnus Damm
2008-05-21  6:49     ` Uwe Kleine-König
2008-05-21  7:49       ` Paul Mundt
2008-05-21  8:05         ` Uwe Kleine-König
2008-05-21  8:22           ` Magnus Damm [this message]
2008-05-21  8:50             ` Uwe Kleine-König
2008-05-21  8:09       ` Magnus Damm
2008-05-21  9:25         ` Uwe Kleine-König
2008-05-21 10:50           ` Magnus Damm
2008-05-21 11:04             ` Uwe Kleine-König
2008-05-21 11:56               ` Magnus Damm
2008-05-21 12:09                 ` Uwe Kleine-König

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=aec7e5c30805210122w5bdb8443r69bb7776e085276b@mail.gmail.com \
    --to=magnus.damm@gmail.com \
    --cc=Uwe.Kleine-Koenig@digi.com \
    --cc=gregkh@suse.de \
    --cc=hjk@linutronix.de \
    --cc=lethal@linux-sh.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-sh@vger.kernel.org \
    --cc=matsu@igel.co.jp \
    /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

all inboxes | Powered by JetHome®