From: Felix Domke <tmbinc@elitedvb.net>
To: Linuxppc-dev@ozlabs.org
Subject: [patch 7/7] xenon: add framebuffer support (ugly)
Date: Wed, 07 Mar 2007 19:01:51 +0100 [thread overview]
Message-ID: <20070307180526.470069000@elitedvb.net> (raw)
In-Reply-To: 20070307180144.812594000@elitedvb.net
This adds support for a framebuffer on the "Xenos" graphics chip used in the
Xbox 360 machine. It requires a pre-initialized framebuffer.
The major problem is that the graphics chip only supports a 'tiled' mode,
thus this patch also uses some serious ugly patches to allow the framebuffer
console to handle this. So this patch is given just for completeness, to have
a working console output, and of course not meant for inclusion into the
kernel.
This patch can probably be rewritten using the deferred io support in a
much nicer way.
Signed-off-by: Felix Domke <tmbinc@elitedvb.net>
---
drivers/video/Kconfig | 9 +
drivers/video/Makefile | 1
drivers/video/cfbimgblt.c | 23 +--
drivers/video/xenonfb.c | 337 ++++++++++++++++++++++++++++++++++++++++++++++
include/linux/fb.h | 12 +
5 files changed, 373 insertions(+), 9 deletions(-)
Index: linux-2.6.20/drivers/video/Kconfig
===================================================================
--- linux-2.6.20.orig/drivers/video/Kconfig 2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/drivers/video/Kconfig 2007-03-07 19:01:23.000000000 +0100
@@ -568,6 +568,15 @@
help
This is the frame buffer device driver for the Intel-based Macintosh
+config FB_XENON
+ bool "Xbox 360 Framebuffer Support"
+ depends on (FB = y) && PPC
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ This is the frame buffer device driver for the Microsoft Xbox 360.
+
config FB_HGA
tristate "Hercules mono graphics support"
depends on FB && X86
Index: linux-2.6.20/drivers/video/Makefile
===================================================================
--- linux-2.6.20.orig/drivers/video/Makefile 2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/drivers/video/Makefile 2007-03-07 19:01:23.000000000 +0100
@@ -104,6 +104,7 @@
# Platform or fallback drivers go here
obj-$(CONFIG_FB_VESA) += vesafb.o
obj-$(CONFIG_FB_IMAC) += imacfb.o
+obj-$(CONFIG_FB_XENON) += xenonfb.o
obj-$(CONFIG_FB_VGA16) += vga16fb.o vgastate.o
obj-$(CONFIG_FB_OF) += offb.o
Index: linux-2.6.20/drivers/video/cfbimgblt.c
===================================================================
--- linux-2.6.20.orig/drivers/video/cfbimgblt.c 2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/drivers/video/cfbimgblt.c 2007-03-07 19:01:23.000000000 +0100
@@ -72,8 +72,13 @@
0x00000000, 0xffffffff
};
-#define FB_WRITEL fb_writel
-#define FB_READL fb_readl
+#if 0
+#define FB_WRITEL(p,b,addr) fb_writel(b,addr)
+#define FB_READL(p,addr) fb_readl(addr)
+#else
+#define FB_READL(p,addr) fb_readl(xenon_convert(p, addr))
+#define FB_WRITEL(p,b,addr) fb_writel(b, xenon_convert(p, addr))
+#endif
static inline void color_imageblit(const struct fb_image *image,
struct fb_info *p, u8 __iomem *dst1,
@@ -97,7 +102,7 @@
if (start_index) {
u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0, start_index));
- val = FB_READL(dst) & start_mask;
+ val = FB_READL(p, dst) & start_mask;
shift = start_index;
}
while (n--) {
@@ -109,7 +114,7 @@
color <<= FB_LEFT_POS(bpp);
val |= FB_SHIFT_HIGH(color, shift);
if (shift >= null_bits) {
- FB_WRITEL(val, dst++);
+ FB_WRITEL(p, val, dst++);
val = (shift == null_bits) ? 0 :
FB_SHIFT_LOW(color, 32 - shift);
@@ -121,7 +126,7 @@
if (shift) {
u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
- FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
+ FB_WRITEL(p, (FB_READL(p, dst) & end_mask) | val, dst);
}
dst1 += p->fix.line_length;
if (pitch_index) {
@@ -162,7 +167,7 @@
/* write leading bits */
if (start_index) {
u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,start_index));
- val = FB_READL(dst) & start_mask;
+ val = FB_READL(p, dst) & start_mask;
shift = start_index;
}
@@ -173,7 +178,7 @@
/* Did the bitshift spill bits to the next long? */
if (shift >= null_bits) {
- FB_WRITEL(val, dst++);
+ FB_WRITEL(p, val, dst++);
val = (shift == null_bits) ? 0 :
FB_SHIFT_LOW(color,32 - shift);
}
@@ -186,7 +191,7 @@
if (shift) {
u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
- FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
+ FB_WRITEL(p, (FB_READL(p, dst) & end_mask) | val, dst);
}
dst1 += pitch;
@@ -251,7 +256,7 @@
for (j = k; j--; ) {
shift -= ppw;
end_mask = tab[(*src >> shift) & bit_mask];
- FB_WRITEL((end_mask & eorx)^bgx, dst++);
+ FB_WRITEL(p, (end_mask & eorx)^bgx, dst++);
if (!shift) { shift = 8; src++; }
}
dst1 += p->fix.line_length;
Index: linux-2.6.20/include/linux/fb.h
===================================================================
--- linux-2.6.20.orig/include/linux/fb.h 2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/include/linux/fb.h 2007-03-07 19:01:23.000000000 +0100
@@ -907,6 +907,18 @@
}
}
+static inline int *xenon_convert(struct fb_info *p, int *addr)
+{
+ int index = ((char*)addr) - ((char*)p->screen_base);
+ int y = index / (p->fix.line_length);
+ int x = index % (p->fix.line_length)/4;
+ unsigned int base = ((((y & ~31)*p->var.xres) + (x & ~31)*32 ) +
+ (((x&3) + ((y&1)<<2) + ((x&28)<<1) + ((y&30)<<5)) ^ ((y&8)<<2))) * 4;
+
+ return (int*)(((char*)p->screen_base)+base);
+}
+
+
/* drivers/video/fbsysfs.c */
extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev);
extern void framebuffer_release(struct fb_info *info);
Index: linux-2.6.20/drivers/video/xenonfb.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.20/drivers/video/xenonfb.c 2007-03-07 19:01:23.000000000 +0100
@@ -0,0 +1,337 @@
+/*
+ * framebuffer driver for Microsoft Xbox 360
+ *
+ * (c) 2006 ...
+ * Original vesafb driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/dmi.h>
+
+#include <asm/io.h>
+
+#include <video/vga.h>
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo xenonfb_defined __initdata = {
+ .activate = FB_ACTIVATE_NOW,
+ .height = -1,
+ .width = -1,
+ .right_margin = 32,
+ .upper_margin = 16,
+ .lower_margin = 4,
+ .vsync_len = 4,
+ .vmode = FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo xenonfb_fix __initdata = {
+ .id = "XENON FB",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .accel = FB_ACCEL_NONE,
+ .visual = FB_VISUAL_TRUECOLOR,
+};
+
+typedef struct {
+ uint32_t unknown1[4];
+ uint32_t base;
+ uint32_t unknown2[8];
+ uint32_t width;
+ uint32_t height;
+} ati_info;
+
+#define DEFAULT_FB_MEM 1024*1024*16
+
+/* --------------------------------------------------------------------- */
+
+static int xenonfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
+{
+ /*
+ * Set a single color register. The values supplied are
+ * already rounded down to the hardware's capabilities
+ * (according to the entries in the `var' structure). Return
+ * != 0 for invalid regno.
+ */
+
+ if (regno >= info->cmap.len)
+ return 1;
+
+ if (regno < 16) {
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ ((u32 *)(info->pseudo_palette))[regno] =
+ (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset);
+ }
+ return 0;
+}
+
+#define XENON_XY_TO_STD_PTR(x,y) ((int*)(((char*)p->screen_base)+y*p->fix.line_length+x*(p->var.bits_per_pixel/8)))
+#define XENON_XY_TO_XENON_PTR(x,y) xenon_convert(p, XENON_XY_TO_STD_PTR(x,y))
+
+inline void xenon_pset(struct fb_info *p, int x, int y, int color)
+{
+ fb_writel(color, XENON_XY_TO_XENON_PTR(x,y));
+}
+
+inline int xenon_pget(struct fb_info *p, int x, int y)
+{
+ return fb_readl(XENON_XY_TO_XENON_PTR(x,y));
+}
+
+void xenon_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
+{
+
+ __u32 x, y;
+ for (y=0; y<rect->height; y++) {
+ for (x=0; x<rect->width; x++) {
+ xenon_pset(p, rect->dx+x, rect->dy+y, rect->color);
+
+ }
+ }
+}
+
+void xenon_copyarea(struct fb_info *p, const struct fb_copyarea *area)
+{
+
+ /* if the beginning of the target area might overlap with the end of
+ the source area, be have to copy the area reverse. */
+ if ((area->dy == area->sy && area->dx > area->sx) || (area->dy > area->sy)) {
+ __s32 x, y;
+ for (y=area->height-1; y>0; y--) {
+ for (x=area->width-1; x>0; x--) {
+ xenon_pset(p, area->dx+x, area->dy+y, xenon_pget(p, area->sx+x, area->sy+y));
+ }
+ }
+ } else {
+ __u32 x, y;
+ for (y=0; y<area->height; y++) {
+ for (x=0; x<area->width; x++) {
+ xenon_pset(p, area->dx+x, area->dy+y, xenon_pget(p, area->sx+x, area->sy+y));
+ }
+ }
+ }
+}
+
+static struct fb_ops xenonfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_setcolreg = xenonfb_setcolreg,
+ .fb_fillrect = xenon_fillrect,
+ .fb_copyarea = xenon_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+static int __init xenonfb_probe(struct platform_device *dev)
+{
+ struct fb_info *info;
+ int err;
+ unsigned int size_vmode;
+ unsigned int size_remap;
+ unsigned int size_total;
+
+ screen_info.lfb_depth = 32;
+ screen_info.lfb_size = DEFAULT_FB_MEM / 0x10000;
+ screen_info.pages=1;
+ screen_info.blue_size = 8;
+ screen_info.blue_pos = 24;
+ screen_info.green_size = 8;
+ screen_info.green_pos = 16;
+ screen_info.red_size = 8;
+ screen_info.red_pos = 8;
+ screen_info.rsvd_size = 8;
+ screen_info.rsvd_pos = 0;
+
+ ati_info *ai = ioremap(0x200ec806100ULL, sizeof(ati_info));
+
+
+
+
+
+
+
+ screen_info.lfb_base = ai->base;
+ screen_info.lfb_width = ai->width;
+ screen_info.lfb_height = ai->height;
+ screen_info.lfb_linelength = screen_info.lfb_width * screen_info.lfb_depth/4;
+
+ printk(KERN_INFO "xenonfb: detected %dx%d framebuffer @ 0x%08x\n", screen_info.lfb_width, screen_info.lfb_height, screen_info.lfb_base);
+
+
+ iounmap(ai);
+
+ xenonfb_fix.smem_start = screen_info.lfb_base;
+ xenonfb_defined.bits_per_pixel = screen_info.lfb_depth;
+ xenonfb_defined.xres = screen_info.lfb_width;
+ xenonfb_defined.yres = screen_info.lfb_height;
+ xenonfb_defined.xoffset = 0;
+ xenonfb_defined.yoffset = 0;
+ xenonfb_fix.line_length = screen_info.lfb_linelength;
+
+ /* size_vmode -- that is the amount of memory needed for the
+ * used video mode, i.e. the minimum amount of
+ * memory we need. */
+ size_vmode = xenonfb_defined.yres * xenonfb_fix.line_length;
+
+ /* size_total -- all video memory we have. Used for
+ * entries, ressource allocation and bounds
+ * checking. */
+ size_total = screen_info.lfb_size * 65536;
+ if (size_total < size_vmode)
+ size_total = size_vmode;
+
+ /* size_remap -- the amount of video memory we are going to
+ * use for xenonfb. With modern cards it is no
+ * option to simply use size_total as that
+ * wastes plenty of kernel address space. */
+ size_remap = size_vmode * 2;
+ if (size_remap < size_vmode)
+ size_remap = size_vmode;
+ if (size_remap > size_total)
+ size_remap = size_total;
+ xenonfb_fix.smem_len = size_remap;
+
+ if (!request_mem_region(xenonfb_fix.smem_start, size_total, "xenonfb")) {
+ printk(KERN_WARNING
+ "xenonfb: cannot reserve video memory at 0x%lx\n",
+ xenonfb_fix.smem_start);
+ /* We cannot make this fatal. Sometimes this comes from magic
+ spaces our resource handlers simply don't know about */
+ }
+
+ info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
+ if (!info) {
+ err = -ENOMEM;
+ goto err_release_mem;
+ }
+ info->pseudo_palette = info->par;
+ info->par = NULL;
+
+ info->screen_base = ioremap(xenonfb_fix.smem_start, xenonfb_fix.smem_len);
+ if (!info->screen_base) {
+ printk(KERN_ERR "xenonfb: abort, cannot ioremap video memory "
+ "0x%x @ 0x%lx\n",
+ xenonfb_fix.smem_len, xenonfb_fix.smem_start);
+ err = -EIO;
+ goto err_unmap;
+ }
+
+ printk(KERN_INFO "xenonfb: framebuffer at 0x%lx, mapped to 0x%p, "
+ "using %dk, total %dk\n",
+ xenonfb_fix.smem_start, info->screen_base,
+ size_remap/1024, size_total/1024);
+ printk(KERN_INFO "xenonfb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
+ xenonfb_defined.xres, xenonfb_defined.yres,
+ xenonfb_defined.bits_per_pixel, xenonfb_fix.line_length,
+ screen_info.pages);
+
+ xenonfb_defined.xres_virtual = xenonfb_defined.xres;
+ xenonfb_defined.yres_virtual = xenonfb_fix.smem_len /
+ xenonfb_fix.line_length;
+ printk(KERN_INFO "xenonfb: scrolling: redraw\n");
+ xenonfb_defined.yres_virtual = xenonfb_defined.yres;
+
+ /* some dummy values for timing to make fbset happy */
+ xenonfb_defined.pixclock = 10000000 / xenonfb_defined.xres *
+ 1000 / xenonfb_defined.yres;
+ xenonfb_defined.left_margin = (xenonfb_defined.xres / 8) & 0xf8;
+ xenonfb_defined.hsync_len = (xenonfb_defined.xres / 8) & 0xf8;
+
+ xenonfb_defined.red.offset = screen_info.red_pos;
+ xenonfb_defined.red.length = screen_info.red_size;
+ xenonfb_defined.green.offset = screen_info.green_pos;
+ xenonfb_defined.green.length = screen_info.green_size;
+ xenonfb_defined.blue.offset = screen_info.blue_pos;
+ xenonfb_defined.blue.length = screen_info.blue_size;
+ xenonfb_defined.transp.offset = screen_info.rsvd_pos;
+ xenonfb_defined.transp.length = screen_info.rsvd_size;
+
+ printk(KERN_INFO "xenonfb: %s: "
+ "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+ "Truecolor",
+ screen_info.rsvd_size,
+ screen_info.red_size,
+ screen_info.green_size,
+ screen_info.blue_size,
+ screen_info.rsvd_pos,
+ screen_info.red_pos,
+ screen_info.green_pos,
+ screen_info.blue_pos);
+
+ xenonfb_fix.ypanstep = 0;
+ xenonfb_fix.ywrapstep = 0;
+
+ /* request failure does not faze us, as vgacon probably has this
+ * region already (FIXME) */
+ request_region(0x3c0, 32, "xenonfb");
+
+ info->fbops = &xenonfb_ops;
+ info->var = xenonfb_defined;
+ info->fix = xenonfb_fix;
+ info->flags = FBINFO_FLAG_DEFAULT;
+
+ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+ err = -ENOMEM;
+ goto err_unmap;
+ }
+ if (register_framebuffer(info)<0) {
+ err = -EINVAL;
+ goto err_fb_dealoc;
+ }
+ printk(KERN_INFO "fb%d: %s frame buffer device\n",
+ info->node, info->fix.id);
+ return 0;
+
+err_fb_dealoc:
+ fb_dealloc_cmap(&info->cmap);
+err_unmap:
+ iounmap(info->screen_base);
+ framebuffer_release(info);
+err_release_mem:
+ release_mem_region(xenonfb_fix.smem_start, size_total);
+ return err;
+}
+
+static struct platform_driver xenonfb_driver = {
+ .probe = xenonfb_probe,
+ .driver = {
+ .name = "xenonfb",
+ },
+};
+
+static struct platform_device xenonfb_device = {
+ .name = "xenonfb",
+};
+
+static int __init xenonfb_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&xenonfb_driver);
+
+ if (!ret) {
+ ret = platform_device_register(&xenonfb_device);
+ if (ret)
+ platform_driver_unregister(&xenonfb_driver);
+ }
+ return ret;
+}
+module_init(xenonfb_init);
+
+MODULE_LICENSE("GPL");
+
--
next prev parent reply other threads:[~2007-03-07 18:01 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-03-07 18:01 [patch 0/7] [RFC] Xenon support Felix Domke
2007-03-07 18:01 ` [patch 1/7] xenon: add PCI Vendor ID: Microsoft Felix Domke
2007-03-07 18:01 ` [patch 2/7] xenon: add platform support Felix Domke
2007-03-07 23:06 ` Arnd Bergmann
2007-03-07 18:01 ` [patch 3/7] xenon: udbg support (ugly) Felix Domke
2007-03-07 21:00 ` Geert Uytterhoeven
2007-03-07 18:01 ` [patch 4/7] xenon: add southbridge ethernet support Felix Domke
2007-03-07 23:27 ` Arnd Bergmann
2007-03-07 18:01 ` [patch 5/7] xenon: add SATA support Felix Domke
2007-03-07 21:02 ` Sergei Shtylyov
2007-03-07 21:07 ` Felix Domke
2007-03-07 21:14 ` Sergei Shtylyov
2007-03-07 18:01 ` [patch 6/7] xenon: add SMC support Felix Domke
2007-03-07 21:54 ` Arnd Bergmann
2007-03-08 23:29 ` Linas Vepstas
2007-03-07 18:01 ` Felix Domke [this message]
2007-03-07 21:06 ` [patch 0/7] [RFC] Xenon support Josh Boyer
2007-03-07 21:14 ` Felix Domke
2007-03-08 9:48 ` Benjamin Herrenschmidt
2007-03-08 0:35 ` Stephen Rothwell
2007-03-08 0:52 ` Felix Domke
2007-03-08 11:02 ` Christoph Hellwig
2007-03-08 23:50 ` Linas Vepstas
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=20070307180526.470069000@elitedvb.net \
--to=tmbinc@elitedvb.net \
--cc=Linuxppc-dev@ozlabs.org \
/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).