Created
July 5, 2015 19:15
-
-
Save notro/b2704b1e6b837f1ab2bf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/drivers/video/fbdev/bcm2708_fb.c b/drivers/video/fbdev/bcm2708_fb.c | |
index f6ac7da..ee10b9e 100644 | |
--- a/drivers/video/fbdev/bcm2708_fb.c | |
+++ b/drivers/video/fbdev/bcm2708_fb.c | |
@@ -1,3 +1,4 @@ | |
+#define DEBUG | |
/* | |
* linux/drivers/video/bcm2708_fb.c | |
* | |
@@ -25,7 +26,6 @@ | |
#include <linux/ioport.h> | |
#include <linux/list.h> | |
#include <linux/platform_data/dma-bcm2708.h> | |
-#include <linux/platform_data/mailbox-bcm2708.h> | |
#include <linux/platform_device.h> | |
#include <linux/clk.h> | |
#include <linux/printk.h> | |
@@ -34,8 +34,9 @@ | |
#include <asm/sizes.h> | |
#include <linux/io.h> | |
#include <linux/dma-mapping.h> | |
+#include <soc/bcm2835/raspberrypi-firmware.h> | |
-//#define BCM2708_FB_DEBUG | |
+#define BCM2708_FB_DEBUG | |
#define MODULE_NAME "bcm2708_fb" | |
#ifdef BCM2708_FB_DEBUG | |
@@ -58,17 +59,6 @@ static u32 dma_busy_wait_threshold = 1<<15; | |
module_param(dma_busy_wait_threshold, int, 0644); | |
MODULE_PARM_DESC(dma_busy_wait_threshold, "Busy-wait for DMA completion below this area"); | |
-/* this data structure describes each frame buffer device we find */ | |
- | |
-struct fbinfo_s { | |
- u32 xres, yres, xres_virtual, yres_virtual; | |
- u32 pitch, bpp; | |
- u32 xoffset, yoffset; | |
- u32 base; | |
- u32 screen_size; | |
- u16 cmap[256]; | |
-}; | |
- | |
struct bcm2708_fb_stats { | |
struct debugfs_regset32 regset; | |
u32 dma_copies; | |
@@ -78,9 +68,9 @@ struct bcm2708_fb_stats { | |
struct bcm2708_fb { | |
struct fb_info fb; | |
struct platform_device *dev; | |
- struct fbinfo_s *info; | |
- dma_addr_t dma; | |
+ struct rpi_firmware *fw; | |
u32 cmap[16]; | |
+ u32 gpu_cmap[256]; | |
int dma_chan; | |
int dma_irq; | |
void __iomem *dma_chan_base; | |
@@ -268,56 +258,74 @@ static int bcm2708_fb_check_var(struct fb_var_screeninfo *var, | |
return 0; | |
} | |
+struct fb_alloc_tags { | |
+ struct rpi_firmware_property_tag_header tag1; | |
+ u32 xres, yres; | |
+ struct rpi_firmware_property_tag_header tag2; | |
+ u32 xres_virtual, yres_virtual; | |
+ struct rpi_firmware_property_tag_header tag3; | |
+ u32 bpp; | |
+ struct rpi_firmware_property_tag_header tag4; | |
+ u32 xoffset, yoffset; | |
+ struct rpi_firmware_property_tag_header tag5; | |
+ u32 base, screen_size; | |
+ struct rpi_firmware_property_tag_header tag6; | |
+ u32 pitch; | |
+}; | |
+ | |
static int bcm2708_fb_set_par(struct fb_info *info) | |
{ | |
- uint32_t val = 0; | |
struct bcm2708_fb *fb = to_bcm2708(info); | |
- volatile struct fbinfo_s *fbinfo = fb->info; | |
- fbinfo->xres = info->var.xres; | |
- fbinfo->yres = info->var.yres; | |
- fbinfo->xres_virtual = info->var.xres_virtual; | |
- fbinfo->yres_virtual = info->var.yres_virtual; | |
- fbinfo->bpp = info->var.bits_per_pixel; | |
- fbinfo->xoffset = info->var.xoffset; | |
- fbinfo->yoffset = info->var.yoffset; | |
- fbinfo->base = 0; /* filled in by VC */ | |
- fbinfo->pitch = 0; /* filled in by VC */ | |
+ struct fb_alloc_tags fbinfo = { | |
+ .tag1 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT, | |
+ 8, 0, }, | |
+ .xres = info->var.xres, | |
+ .yres = info->var.yres, | |
+ .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT, | |
+ 8, 0, }, | |
+ .xres_virtual = info->var.xres_virtual, | |
+ .yres_virtual = info->var.yres_virtual, | |
+ .tag3 = { RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH, 4, 0 }, | |
+ .bpp = info->var.bits_per_pixel, | |
+ .tag4 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET, 8, 0 }, | |
+ .xoffset = info->var.xoffset, | |
+ .yoffset = info->var.yoffset, | |
+ .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 }, | |
+ .base = 0, | |
+ .screen_size = 0, | |
+ .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH, 4, 0 }, | |
+ .pitch = 0, | |
+ }; | |
+ int val; | |
print_debug("bcm2708_fb_set_par info(%p) %dx%d (%dx%d), %d, %d\n", info, | |
info->var.xres, info->var.yres, info->var.xres_virtual, | |
info->var.yres_virtual, (int)info->screen_size, | |
info->var.bits_per_pixel); | |
- /* ensure last write to fbinfo is visible to GPU */ | |
- wmb(); | |
- | |
- /* inform vc about new framebuffer */ | |
- bcm_mailbox_write(MBOX_CHAN_FB, fb->dma); | |
- | |
- /* TODO: replace fb driver with vchiq version */ | |
- /* wait for response */ | |
- bcm_mailbox_read(MBOX_CHAN_FB, &val); | |
- | |
- /* ensure GPU writes are visible to us */ | |
- rmb(); | |
- | |
+ val = rpi_firmware_property_list(fb->fw, &fbinfo, sizeof(fbinfo)); | |
if (val == 0) { | |
- fb->fb.fix.line_length = fbinfo->pitch; | |
+ fb->fb.fix.line_length = fbinfo.pitch; | |
if (info->var.bits_per_pixel <= 8) | |
fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; | |
else | |
fb->fb.fix.visual = FB_VISUAL_TRUECOLOR; | |
- fb->fb_bus_address = fbinfo->base; | |
- fbinfo->base &= ~0xc0000000; | |
- fb->fb.fix.smem_start = fbinfo->base; | |
- fb->fb.fix.smem_len = fbinfo->pitch * fbinfo->yres_virtual; | |
- fb->fb.screen_size = fbinfo->screen_size; | |
+printk("fbinfo.base=0x%x\n", fbinfo.base); | |
+ fbinfo.base |= 0x40000000; | |
+ | |
+ fb->fb_bus_address = fbinfo.base; | |
+printk("fb->fb_bus_address=0x%lx\n", fb->fb_bus_address); | |
+ fbinfo.base &= ~0xc0000000; | |
+ fb->fb.fix.smem_start = fbinfo.base; | |
+printk("fb->fb.fix.smem_start=0x%lx\n", fb->fb.fix.smem_start); | |
+ fb->fb.fix.smem_len = fbinfo.pitch * fbinfo.yres_virtual; | |
+ fb->fb.screen_size = fbinfo.screen_size; | |
if (fb->fb.screen_base) | |
iounmap(fb->fb.screen_base); | |
fb->fb.screen_base = | |
- (void *)ioremap_wc(fbinfo->base, fb->fb.screen_size); | |
+ (void *)ioremap_wc(fbinfo.base, fb->fb.screen_size); | |
if (!fb->fb.screen_base) { | |
/* the console may currently be locked */ | |
console_trylock(); | |
@@ -329,8 +337,8 @@ static int bcm2708_fb_set_par(struct fb_info *info) | |
print_debug | |
("BCM2708FB: start = %p,%p width=%d, height=%d, bpp=%d, pitch=%d size=%d success=%d\n", | |
(void *)fb->fb.screen_base, (void *)fb->fb_bus_address, | |
- fbinfo->xres, fbinfo->yres, fbinfo->bpp, | |
- fbinfo->pitch, (int)fb->fb.screen_size, val); | |
+ fbinfo.xres, fbinfo.yres, fbinfo.bpp, | |
+ fbinfo.pitch, (int)fb->fb.screen_size, val); | |
return val; | |
} | |
@@ -353,14 +361,59 @@ static int bcm2708_fb_setcolreg(unsigned int regno, unsigned int red, | |
if (fb->fb.var.bits_per_pixel <= 8) { | |
if (regno < 256) { | |
/* blue [0:4], green [5:10], red [11:15] */ | |
- fb->info->cmap[regno] = ((red >> (16-5)) & 0x1f) << 11 | | |
- ((green >> (16-6)) & 0x3f) << 5 | | |
- ((blue >> (16-5)) & 0x1f) << 0; | |
+ fb->gpu_cmap[regno] = ((red >> (16-5)) & 0x1f) << 11 | | |
+ ((green >> (16-6)) & 0x3f) << 5 | | |
+ ((blue >> (16-5)) & 0x1f) << 0; | |
} | |
/* Hack: we need to tell GPU the palette has changed, but currently bcm2708_fb_set_par takes noticable time when called for every (256) colour */ | |
/* So just call it for what looks like the last colour in a list for now. */ | |
- if (regno == 15 || regno == 255) | |
- bcm2708_fb_set_par(info); | |
+ if (regno == 15 || regno == 255) { | |
+ struct packet { | |
+ u32 offset; | |
+ u32 length; | |
+ u32 cmap[256]; | |
+ } *packet; | |
+ int ret; | |
+ int i; | |
+ | |
+ packet = kmalloc(sizeof(*packet), GFP_KERNEL); | |
+ if (!packet) | |
+ return -ENOMEM; | |
+ packet->offset = 0; | |
+ packet->length = regno + 1; | |
+ memcpy(packet->cmap, fb->gpu_cmap, sizeof(packet->cmap)); | |
+ | |
+ printk("%s: set palette: regno=%u\n", __func__, regno); | |
+ for (i = 0; i < ((regno + 1) / 16); i++) | |
+ printk("%04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x\n", | |
+ packet->cmap[i*16+0], packet->cmap[i*16+1], packet->cmap[i*16+2], packet->cmap[i*16+3], | |
+ packet->cmap[i*16+4], packet->cmap[i*16+5], packet->cmap[i*16+6], packet->cmap[i*16+7], | |
+ packet->cmap[i*16+8], packet->cmap[i*16+9], packet->cmap[i*16+10], packet->cmap[i*16+11], | |
+ packet->cmap[i*16+12], packet->cmap[i*16+13], packet->cmap[i*16+14], packet->cmap[i*16+15]); | |
+ | |
+ ret = rpi_firmware_property(fb->fw, RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE, | |
+ packet, (2 + packet->length) * sizeof(u32)); | |
+ if (ret || packet->offset) | |
+ pr_err("%s: failed to set palette (%d,%u)\n", __func__, ret, packet->offset); | |
+ | |
+ | |
+ | |
+ ret = rpi_firmware_property(fb->fw, RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE, | |
+ packet->cmap, sizeof(packet->cmap)); | |
+ if (ret) | |
+ pr_err("%s: failed to get palette (%d)\n", __func__, ret); | |
+ | |
+ | |
+ printk("\n%s: get palette:\n", __func__); | |
+ for (i = 0; i < 16; i++) | |
+ printk("%04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x\n", | |
+ packet->cmap[i*16+0], packet->cmap[i*16+1], packet->cmap[i*16+2], packet->cmap[i*16+3], | |
+ packet->cmap[i*16+4], packet->cmap[i*16+5], packet->cmap[i*16+6], packet->cmap[i*16+7], | |
+ packet->cmap[i*16+8], packet->cmap[i*16+9], packet->cmap[i*16+10], packet->cmap[i*16+11], | |
+ packet->cmap[i*16+12], packet->cmap[i*16+13], packet->cmap[i*16+14], packet->cmap[i*16+15]); | |
+ | |
+ kfree(packet); | |
+ } | |
} else if (regno < 16) { | |
fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) | | |
convert_bitfield(blue, &fb->fb.var.blue) | | |
@@ -372,27 +425,30 @@ static int bcm2708_fb_setcolreg(unsigned int regno, unsigned int red, | |
static int bcm2708_fb_blank(int blank_mode, struct fb_info *info) | |
{ | |
- s32 result = -1; | |
- u32 p[7]; | |
- if ( (blank_mode == FB_BLANK_NORMAL) || | |
- (blank_mode == FB_BLANK_UNBLANK)) { | |
- | |
- p[0] = 28; // size = sizeof u32 * length of p | |
- p[1] = VCMSG_PROCESS_REQUEST; // process request | |
- p[2] = VCMSG_SET_BLANK_SCREEN; // (the tag id) | |
- p[3] = 4; // (size of the response buffer) | |
- p[4] = 4; // (size of the request data) | |
- p[5] = blank_mode; | |
- p[6] = VCMSG_PROPERTY_END; // end tag | |
- | |
- bcm_mailbox_property(&p, p[0]); | |
- | |
- if ( p[1] == VCMSG_REQUEST_SUCCESSFUL ) | |
- result = 0; | |
- else | |
- pr_err("bcm2708_fb_blank(%d) returns=%d p[1]=0x%x\n", blank_mode, p[5], p[1]); | |
+ struct bcm2708_fb *fb = to_bcm2708(info); | |
+ u32 value; | |
+ int ret; | |
+ | |
+ switch (blank_mode) { | |
+ case FB_BLANK_UNBLANK: | |
+ value = 0; | |
+ break; | |
+ case FB_BLANK_NORMAL: | |
+ case FB_BLANK_VSYNC_SUSPEND: | |
+ case FB_BLANK_HSYNC_SUSPEND: | |
+ case FB_BLANK_POWERDOWN: | |
+ value = 1; | |
+ break; | |
+ default: | |
+ return -EINVAL; | |
} | |
- return result; | |
+ | |
+ ret = rpi_firmware_property(fb->fw, RPI_FIRMWARE_FRAMEBUFFER_BLANK, | |
+ &value, sizeof(value)); | |
+ if (ret) | |
+ dev_err(info->device, "bcm2708_fb_blank(%d) returns=%d\n", blank_mode, ret); | |
+ | |
+ return ret; | |
} | |
static int bcm2708_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) | |
@@ -408,25 +464,25 @@ static int bcm2708_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info | |
static int bcm2708_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) | |
{ | |
- s32 result = -1; | |
- u32 p[7]; | |
- if (cmd == FBIO_WAITFORVSYNC) { | |
- p[0] = 28; // size = sizeof u32 * length of p | |
- p[1] = VCMSG_PROCESS_REQUEST; // process request | |
- p[2] = VCMSG_SET_VSYNC; // (the tag id) | |
- p[3] = 4; // (size of the response buffer) | |
- p[4] = 4; // (size of the request data) | |
- p[5] = 0; // dummy | |
- p[6] = VCMSG_PROPERTY_END; // end tag | |
- | |
- bcm_mailbox_property(&p, p[0]); | |
- | |
- if ( p[1] == VCMSG_REQUEST_SUCCESSFUL ) | |
- result = 0; | |
- else | |
- pr_err("bcm2708_fb_ioctl %x,%lx returns=%d p[1]=0x%x\n", cmd, arg, p[5], p[1]); | |
+ struct bcm2708_fb *fb = to_bcm2708(info); | |
+ u32 dummy = 0; | |
+ int ret; | |
+ | |
+ switch (cmd) { | |
+ case FBIO_WAITFORVSYNC: | |
+ ret = rpi_firmware_property(fb->fw, | |
+ RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC, | |
+ &dummy, sizeof(dummy)); | |
+ break; | |
+ default: | |
+ dev_err(info->device, "Unknown ioctl 0x%x\n", cmd); | |
+ return -EINVAL; | |
} | |
- return result; | |
+ | |
+ if (ret) | |
+ dev_err(info->device, "ioctl 0x%x failed (%d)\n", cmd, ret); | |
+ | |
+ return ret; | |
} | |
static void bcm2708_fb_fillrect(struct fb_info *info, | |
const struct fb_fillrect *rect) | |
@@ -621,20 +677,7 @@ static struct fb_ops bcm2708_fb_ops = { | |
static int bcm2708_fb_register(struct bcm2708_fb *fb) | |
{ | |
int ret; | |
- dma_addr_t dma; | |
- void *mem; | |
- | |
- mem = | |
- dma_alloc_coherent(&fb->dev->dev, PAGE_ALIGN(sizeof(*fb->info)), &dma, | |
- GFP_KERNEL); | |
- if (NULL == mem) { | |
- pr_err(": unable to allocate fbinfo buffer\n"); | |
- ret = -ENOMEM; | |
- } else { | |
- fb->info = (struct fbinfo_s *)mem; | |
- fb->dma = dma; | |
- } | |
fb->fb.fbops = &bcm2708_fb_ops; | |
fb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_COPYAREA; | |
fb->fb.pseudo_palette = fb->cmap; | |
@@ -693,9 +736,22 @@ out: | |
static int bcm2708_fb_probe(struct platform_device *dev) | |
{ | |
+ struct device_node *fw_np; | |
+ struct rpi_firmware *fw; | |
struct bcm2708_fb *fb; | |
int ret; | |
+ fw_np = of_parse_phandle(dev->dev.of_node, "firmware", 0); | |
+/* Uncomment when booting without Device Tree is no longer supported | |
+ if (!fw_np) { | |
+ dev_err(&dev->dev, "Missing firmware node\n"); | |
+ return -ENOENT; | |
+ } | |
+*/ | |
+ fw = rpi_firmware_get(fw_np); | |
+ if (!fw) | |
+ return -EPROBE_DEFER; | |
+ | |
fb = kzalloc(sizeof(struct bcm2708_fb), GFP_KERNEL); | |
if (!fb) { | |
dev_err(&dev->dev, | |
@@ -704,6 +760,7 @@ static int bcm2708_fb_probe(struct platform_device *dev) | |
goto free_region; | |
} | |
+ fb->fw = fw; | |
bcm2708_fb_debugfs_init(fb); | |
fb->cb_base = dma_alloc_writecombine(&dev->dev, SZ_64K, | |
@@ -769,8 +826,6 @@ static int bcm2708_fb_remove(struct platform_device *dev) | |
dma_free_writecombine(&dev->dev, SZ_64K, fb->cb_base, fb->cb_handle); | |
bcm_dma_chan_free(fb->dma_chan); | |
- dma_free_coherent(NULL, PAGE_ALIGN(sizeof(*fb->info)), (void *)fb->info, | |
- fb->dma); | |
bcm2708_fb_debugfs_deinit(fb); | |
free_irq(fb->dma_irq, fb); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment