/* * sh7722 VEU scaling example using UIO - 20080521 Magnus Damm * * Derived from * "Simple tick timer through Sky TMU UIO driver" by Katsuya Matsubara */ #include #include #include #include #include #include #include #include #include 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; }