Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

unicore32 machine related: add frame buffer driver for pkunity-v3 soc

change from original version -- by advice of Paul Mundt
1. remove videomemorysize definitions
2. remove unifb_enable and unifb_setup
3. use dev_warn instead of printk in fb driver
4. remove judgement for FB_ACCEL_PUV3_UNIGFX
5. adjust clk_get and clk_set_rate calls
6. add resources definitions
7. remove unifb_option
8. adjust register for platform_device
9. adjust unifb_ops position and unifb_regs assignment position

Signed-off-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
Acked-by: Arnd Bergmann <arnd@arndb.de>

+879 -2
+1
MAINTAINERS
··· 4902 4902 T: git git://git.kernel.org/pub/scm/linux/kernel/git/epip/linux-2.6-unicore32.git 4903 4903 F: drivers/input/serio/i8042-unicore32io.h 4904 4904 F: drivers/i2c/busses/i2c-puv3.c 4905 + F: drivers/video/fb-puv3.c 4905 4906 4906 4907 PMC SIERRA MaxRAID DRIVER 4907 4908 M: Anil Ravindranath <anil_ravindranath@pmc-sierra.com>
+2 -1
arch/unicore32/configs/debug_defconfig
··· 66 66 67 67 CONFIG_PUV3_RTC=y 68 68 CONFIG_PUV3_UMAL=y 69 - CONFIG_PUV3_UNIGFX=y 70 69 CONFIG_PUV3_MUSB=n 71 70 CONFIG_PUV3_AC97=n 72 71 CONFIG_PUV3_NAND=n ··· 129 130 CONFIG_USB_VIDEO_CLASS=n 130 131 131 132 # Graphics support 133 + CONFIG_FB=y 134 + CONFIG_FB_PUV3_UNIGFX=y 132 135 # Console display driver support 133 136 CONFIG_VGA_CONSOLE=n 134 137 CONFIG_FRAMEBUFFER_CONSOLE=y
+1 -1
arch/unicore32/include/mach/memory.h
··· 50 50 51 51 /* kuser area */ 52 52 #define KUSER_VECPAGE_BASE (KUSER_BASE + UL(0x3fff0000)) 53 - #define KUSER_UNIGFX_BASE (KUSER_BASE + PKUNITY_UNIGFX_MMAP_BASE) 53 + #define KUSER_UNIGFX_BASE (PAGE_OFFSET + PKUNITY_UNIGFX_MMAP_BASE) 54 54 /* kuser_vecpage (0xbfff0000) is ro, and vectors page (0xffff0000) is rw */ 55 55 #define kuser_vecpage_to_vectors(x) ((x) - (KUSER_VECPAGE_BASE) \ 56 56 + (VECTORS_BASE))
+15
arch/unicore32/kernel/puv3-core.c
··· 93 93 }, 94 94 }; 95 95 96 + static struct resource puv3_unigfx_resources[] = { 97 + [0] = { 98 + .start = PKUNITY_UNIGFX_BASE, 99 + .end = PKUNITY_UNIGFX_BASE + 0xfff, 100 + .flags = IORESOURCE_MEM, 101 + }, 102 + [1] = { 103 + .start = PKUNITY_UNIGFX_MMAP_BASE, 104 + .end = PKUNITY_UNIGFX_MMAP_BASE + PKUNITY_UNIGFX_MMAP_SIZE, 105 + .flags = IORESOURCE_MEM, 106 + }, 107 + }; 108 + 96 109 static struct resource puv3_rtc_resources[] = { 97 110 [0] = { 98 111 .start = PKUNITY_RTC_BASE, ··· 269 256 puv3_umal_resources, ARRAY_SIZE(puv3_umal_resources)); 270 257 platform_device_register_simple("PKUnity-v3-MMC", -1, 271 258 puv3_mmc_resources, ARRAY_SIZE(puv3_mmc_resources)); 259 + platform_device_register_simple("PKUnity-v3-UNIGFX", -1, 260 + puv3_unigfx_resources, ARRAY_SIZE(puv3_unigfx_resources)); 272 261 platform_device_register_simple("PKUnity-v3-PWM", -1, 273 262 puv3_pwm_resources, ARRAY_SIZE(puv3_pwm_resources)); 274 263 platform_device_register_simple("PKUnity-v3-UART", 0,
+11
drivers/video/Kconfig
··· 2365 2365 help 2366 2366 Framebuffer support for the JZ4740 SoC. 2367 2367 2368 + config FB_PUV3_UNIGFX 2369 + tristate "PKUnity v3 Unigfx framebuffer support" 2370 + depends on FB && UNICORE32 && ARCH_PUV3 2371 + select FB_SYS_FILLRECT 2372 + select FB_SYS_COPYAREA 2373 + select FB_SYS_IMAGEBLIT 2374 + select FB_SYS_FOPS 2375 + help 2376 + Choose this option if you want to use the Unigfx device as a 2377 + framebuffer device. Without the support of PCI & AGP. 2378 + 2368 2379 source "drivers/video/omap/Kconfig" 2369 2380 source "drivers/video/omap2/Kconfig" 2370 2381
+1
drivers/video/Makefile
··· 139 139 obj-$(CONFIG_FB_MSM) += msm/ 140 140 obj-$(CONFIG_FB_NUC900) += nuc900fb.o 141 141 obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o 142 + obj-$(CONFIG_FB_PUV3_UNIGFX) += fb-puv3.o 142 143 143 144 # Platform or fallback drivers go here 144 145 obj-$(CONFIG_FB_UVESA) += uvesafb.o
+846
drivers/video/fb-puv3.c
··· 1 + /* 2 + * Frame Buffer Driver for PKUnity-v3 Unigfx 3 + * Code specific to PKUnity SoC and UniCore ISA 4 + * 5 + * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> 6 + * Copyright (C) 2001-2010 Guan Xuetao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + 13 + #include <linux/module.h> 14 + #include <linux/kernel.h> 15 + #include <linux/errno.h> 16 + #include <linux/vmalloc.h> 17 + #include <linux/platform_device.h> 18 + #include <linux/clk.h> 19 + #include <linux/fb.h> 20 + #include <linux/init.h> 21 + #include <linux/console.h> 22 + 23 + #include <asm/sizes.h> 24 + #include <mach/hardware.h> 25 + 26 + /* Platform_data reserved for unifb registers. */ 27 + #define UNIFB_REGS_NUM 10 28 + /* RAM reserved for the frame buffer. */ 29 + #define UNIFB_MEMSIZE (SZ_4M) /* 4 MB for 1024*768*32b */ 30 + 31 + /* 32 + * cause UNIGFX don not have EDID 33 + * all the modes are organized as follow 34 + */ 35 + static const struct fb_videomode unifb_modes[] = { 36 + /* 0 640x480-60 VESA */ 37 + { "640x480@60", 60, 640, 480, 25175000, 48, 16, 34, 10, 96, 1, 38 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 39 + /* 1 640x480-75 VESA */ 40 + { "640x480@75", 75, 640, 480, 31500000, 120, 16, 18, 1, 64, 1, 41 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 42 + /* 2 800x600-60 VESA */ 43 + { "800x600@60", 60, 800, 600, 40000000, 88, 40, 26, 1, 128, 1, 44 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 45 + /* 3 800x600-75 VESA */ 46 + { "800x600@75", 75, 800, 600, 49500000, 160, 16, 23, 1, 80, 1, 47 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 48 + /* 4 1024x768-60 VESA */ 49 + { "1024x768@60", 60, 1024, 768, 65000000, 160, 24, 34, 3, 136, 1, 50 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 51 + /* 5 1024x768-75 VESA */ 52 + { "1024x768@75", 75, 1024, 768, 78750000, 176, 16, 30, 1, 96, 1, 53 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 54 + /* 6 1280x960-60 VESA */ 55 + { "1280x960@60", 60, 1280, 960, 108000000, 312, 96, 38, 1, 112, 1, 56 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 57 + /* 7 1440x900-60 VESA */ 58 + { "1440x900@60", 60, 1440, 900, 106500000, 232, 80, 30, 3, 152, 1, 59 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 60 + /* 8 FIXME 9 1024x600-60 VESA UNTESTED */ 61 + { "1024x600@60", 60, 1024, 600, 50650000, 160, 24, 26, 1, 136, 1, 62 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 63 + /* 9 FIXME 10 1024x600-75 VESA UNTESTED */ 64 + { "1024x600@75", 75, 1024, 600, 61500000, 176, 16, 23, 1, 96, 1, 65 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 66 + /* 10 FIXME 11 1366x768-60 VESA UNTESTED */ 67 + { "1366x768@60", 60, 1366, 768, 85500000, 256, 58, 18, 1, 112, 3, 68 + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 69 + }; 70 + 71 + static struct fb_var_screeninfo unifb_default = { 72 + .xres = 640, 73 + .yres = 480, 74 + .xres_virtual = 640, 75 + .yres_virtual = 480, 76 + .bits_per_pixel = 16, 77 + .red = { 11, 5, 0 }, 78 + .green = { 5, 6, 0 }, 79 + .blue = { 0, 5, 0 }, 80 + .activate = FB_ACTIVATE_NOW, 81 + .height = -1, 82 + .width = -1, 83 + .pixclock = 25175000, 84 + .left_margin = 48, 85 + .right_margin = 16, 86 + .upper_margin = 33, 87 + .lower_margin = 10, 88 + .hsync_len = 96, 89 + .vsync_len = 2, 90 + .vmode = FB_VMODE_NONINTERLACED, 91 + }; 92 + 93 + static struct fb_fix_screeninfo unifb_fix = { 94 + .id = "UNIGFX FB", 95 + .type = FB_TYPE_PACKED_PIXELS, 96 + .visual = FB_VISUAL_TRUECOLOR, 97 + .xpanstep = 1, 98 + .ypanstep = 1, 99 + .ywrapstep = 1, 100 + .accel = FB_ACCEL_NONE, 101 + }; 102 + 103 + static void unifb_sync(struct fb_info *info) 104 + { 105 + /* TODO: may, this can be replaced by interrupt */ 106 + int cnt; 107 + 108 + for (cnt = 0; cnt < 0x10000000; cnt++) { 109 + if (readl(UGE_COMMAND) & 0x1000000) 110 + return; 111 + } 112 + 113 + if (cnt > 0x8000000) 114 + dev_warn(info->device, "Warning: UniGFX GE time out ...\n"); 115 + } 116 + 117 + static void unifb_prim_fillrect(struct fb_info *info, 118 + const struct fb_fillrect *region) 119 + { 120 + int awidth = region->width; 121 + int aheight = region->height; 122 + int m_iBpp = info->var.bits_per_pixel; 123 + int screen_width = info->var.xres; 124 + int src_sel = 1; /* from fg_color */ 125 + int pat_sel = 1; 126 + int src_x0 = 0; 127 + int dst_x0 = region->dx; 128 + int src_y0 = 0; 129 + int dst_y0 = region->dy; 130 + int rop_alpha_sel = 0; 131 + int rop_alpha_code = 0xCC; 132 + int x_dir = 1; 133 + int y_dir = 1; 134 + int alpha_r = 0; 135 + int alpha_sel = 0; 136 + int dst_pitch = screen_width * (m_iBpp / 8); 137 + int dst_offset = dst_y0 * dst_pitch + dst_x0 * (m_iBpp / 8); 138 + int src_pitch = screen_width * (m_iBpp / 8); 139 + int src_offset = src_y0 * src_pitch + src_x0 * (m_iBpp / 8); 140 + unsigned int command = 0; 141 + int clip_region = 0; 142 + int clip_en = 0; 143 + int tp_en = 0; 144 + int fg_color = 0; 145 + int bottom = info->var.yres - 1; 146 + int right = info->var.xres - 1; 147 + int top = 0; 148 + 149 + bottom = (bottom << 16) | right; 150 + command = (rop_alpha_sel << 26) | (pat_sel << 18) | (src_sel << 16) 151 + | (x_dir << 20) | (y_dir << 21) | (command << 24) 152 + | (clip_region << 23) | (clip_en << 22) | (tp_en << 27); 153 + src_pitch = (dst_pitch << 16) | src_pitch; 154 + awidth = awidth | (aheight << 16); 155 + alpha_r = ((rop_alpha_code & 0xff) << 8) | (alpha_r & 0xff) 156 + | (alpha_sel << 16); 157 + src_x0 = (src_x0 & 0x1fff) | ((src_y0 & 0x1fff) << 16); 158 + dst_x0 = (dst_x0 & 0x1fff) | ((dst_y0 & 0x1fff) << 16); 159 + fg_color = region->color; 160 + 161 + unifb_sync(info); 162 + 163 + writel(((u32 *)(info->pseudo_palette))[fg_color], UGE_FCOLOR); 164 + writel(0, UGE_BCOLOR); 165 + writel(src_pitch, UGE_PITCH); 166 + writel(src_offset, UGE_SRCSTART); 167 + writel(dst_offset, UGE_DSTSTART); 168 + writel(awidth, UGE_WIDHEIGHT); 169 + writel(top, UGE_CLIP0); 170 + writel(bottom, UGE_CLIP1); 171 + writel(alpha_r, UGE_ROPALPHA); 172 + writel(src_x0, UGE_SRCXY); 173 + writel(dst_x0, UGE_DSTXY); 174 + writel(command, UGE_COMMAND); 175 + } 176 + 177 + static void unifb_fillrect(struct fb_info *info, 178 + const struct fb_fillrect *region) 179 + { 180 + struct fb_fillrect modded; 181 + int vxres, vyres; 182 + 183 + if (info->flags & FBINFO_HWACCEL_DISABLED) { 184 + sys_fillrect(info, region); 185 + return; 186 + } 187 + 188 + vxres = info->var.xres_virtual; 189 + vyres = info->var.yres_virtual; 190 + 191 + memcpy(&modded, region, sizeof(struct fb_fillrect)); 192 + 193 + if (!modded.width || !modded.height || 194 + modded.dx >= vxres || modded.dy >= vyres) 195 + return; 196 + 197 + if (modded.dx + modded.width > vxres) 198 + modded.width = vxres - modded.dx; 199 + if (modded.dy + modded.height > vyres) 200 + modded.height = vyres - modded.dy; 201 + 202 + unifb_prim_fillrect(info, &modded); 203 + } 204 + 205 + static void unifb_prim_copyarea(struct fb_info *info, 206 + const struct fb_copyarea *area) 207 + { 208 + int awidth = area->width; 209 + int aheight = area->height; 210 + int m_iBpp = info->var.bits_per_pixel; 211 + int screen_width = info->var.xres; 212 + int src_sel = 2; /* from mem */ 213 + int pat_sel = 0; 214 + int src_x0 = area->sx; 215 + int dst_x0 = area->dx; 216 + int src_y0 = area->sy; 217 + int dst_y0 = area->dy; 218 + 219 + int rop_alpha_sel = 0; 220 + int rop_alpha_code = 0xCC; 221 + int x_dir = 1; 222 + int y_dir = 1; 223 + 224 + int alpha_r = 0; 225 + int alpha_sel = 0; 226 + int dst_pitch = screen_width * (m_iBpp / 8); 227 + int dst_offset = dst_y0 * dst_pitch + dst_x0 * (m_iBpp / 8); 228 + int src_pitch = screen_width * (m_iBpp / 8); 229 + int src_offset = src_y0 * src_pitch + src_x0 * (m_iBpp / 8); 230 + unsigned int command = 0; 231 + int clip_region = 0; 232 + int clip_en = 1; 233 + int tp_en = 0; 234 + int top = 0; 235 + int bottom = info->var.yres; 236 + int right = info->var.xres; 237 + int fg_color = 0; 238 + int bg_color = 0; 239 + 240 + if (src_x0 < 0) 241 + src_x0 = 0; 242 + if (src_y0 < 0) 243 + src_y0 = 0; 244 + 245 + if (src_y0 - dst_y0 > 0) { 246 + y_dir = 1; 247 + } else { 248 + y_dir = 0; 249 + src_offset = (src_y0 + aheight) * src_pitch + 250 + src_x0 * (m_iBpp / 8); 251 + dst_offset = (dst_y0 + aheight) * dst_pitch + 252 + dst_x0 * (m_iBpp / 8); 253 + src_y0 += aheight; 254 + dst_y0 += aheight; 255 + } 256 + 257 + command = (rop_alpha_sel << 26) | (pat_sel << 18) | (src_sel << 16) | 258 + (x_dir << 20) | (y_dir << 21) | (command << 24) | 259 + (clip_region << 23) | (clip_en << 22) | (tp_en << 27); 260 + src_pitch = (dst_pitch << 16) | src_pitch; 261 + awidth = awidth | (aheight << 16); 262 + alpha_r = ((rop_alpha_code & 0xff) << 8) | (alpha_r & 0xff) | 263 + (alpha_sel << 16); 264 + src_x0 = (src_x0 & 0x1fff) | ((src_y0 & 0x1fff) << 16); 265 + dst_x0 = (dst_x0 & 0x1fff) | ((dst_y0 & 0x1fff) << 16); 266 + bottom = (bottom << 16) | right; 267 + 268 + unifb_sync(info); 269 + 270 + writel(src_pitch, UGE_PITCH); 271 + writel(src_offset, UGE_SRCSTART); 272 + writel(dst_offset, UGE_DSTSTART); 273 + writel(awidth, UGE_WIDHEIGHT); 274 + writel(top, UGE_CLIP0); 275 + writel(bottom, UGE_CLIP1); 276 + writel(bg_color, UGE_BCOLOR); 277 + writel(fg_color, UGE_FCOLOR); 278 + writel(alpha_r, UGE_ROPALPHA); 279 + writel(src_x0, UGE_SRCXY); 280 + writel(dst_x0, UGE_DSTXY); 281 + writel(command, UGE_COMMAND); 282 + } 283 + 284 + static void unifb_copyarea(struct fb_info *info, const struct fb_copyarea *area) 285 + { 286 + struct fb_copyarea modded; 287 + u32 vxres, vyres; 288 + modded.sx = area->sx; 289 + modded.sy = area->sy; 290 + modded.dx = area->dx; 291 + modded.dy = area->dy; 292 + modded.width = area->width; 293 + modded.height = area->height; 294 + 295 + if (info->flags & FBINFO_HWACCEL_DISABLED) { 296 + sys_copyarea(info, area); 297 + return; 298 + } 299 + 300 + vxres = info->var.xres_virtual; 301 + vyres = info->var.yres_virtual; 302 + 303 + if (!modded.width || !modded.height || 304 + modded.sx >= vxres || modded.sy >= vyres || 305 + modded.dx >= vxres || modded.dy >= vyres) 306 + return; 307 + 308 + if (modded.sx + modded.width > vxres) 309 + modded.width = vxres - modded.sx; 310 + if (modded.dx + modded.width > vxres) 311 + modded.width = vxres - modded.dx; 312 + if (modded.sy + modded.height > vyres) 313 + modded.height = vyres - modded.sy; 314 + if (modded.dy + modded.height > vyres) 315 + modded.height = vyres - modded.dy; 316 + 317 + unifb_prim_copyarea(info, &modded); 318 + } 319 + 320 + static void unifb_imageblit(struct fb_info *info, const struct fb_image *image) 321 + { 322 + sys_imageblit(info, image); 323 + } 324 + 325 + static u_long get_line_length(int xres_virtual, int bpp) 326 + { 327 + u_long length; 328 + 329 + length = xres_virtual * bpp; 330 + length = (length + 31) & ~31; 331 + length >>= 3; 332 + return length; 333 + } 334 + 335 + /* 336 + * Setting the video mode has been split into two parts. 337 + * First part, xxxfb_check_var, must not write anything 338 + * to hardware, it should only verify and adjust var. 339 + * This means it doesn't alter par but it does use hardware 340 + * data from it to check this var. 341 + */ 342 + static int unifb_check_var(struct fb_var_screeninfo *var, 343 + struct fb_info *info) 344 + { 345 + u_long line_length; 346 + 347 + /* 348 + * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! 349 + * as FB_VMODE_SMOOTH_XPAN is only used internally 350 + */ 351 + 352 + if (var->vmode & FB_VMODE_CONUPDATE) { 353 + var->vmode |= FB_VMODE_YWRAP; 354 + var->xoffset = info->var.xoffset; 355 + var->yoffset = info->var.yoffset; 356 + } 357 + 358 + /* 359 + * Some very basic checks 360 + */ 361 + if (!var->xres) 362 + var->xres = 1; 363 + if (!var->yres) 364 + var->yres = 1; 365 + if (var->xres > var->xres_virtual) 366 + var->xres_virtual = var->xres; 367 + if (var->yres > var->yres_virtual) 368 + var->yres_virtual = var->yres; 369 + if (var->bits_per_pixel <= 1) 370 + var->bits_per_pixel = 1; 371 + else if (var->bits_per_pixel <= 8) 372 + var->bits_per_pixel = 8; 373 + else if (var->bits_per_pixel <= 16) 374 + var->bits_per_pixel = 16; 375 + else if (var->bits_per_pixel <= 24) 376 + var->bits_per_pixel = 24; 377 + else if (var->bits_per_pixel <= 32) 378 + var->bits_per_pixel = 32; 379 + else 380 + return -EINVAL; 381 + 382 + if (var->xres_virtual < var->xoffset + var->xres) 383 + var->xres_virtual = var->xoffset + var->xres; 384 + if (var->yres_virtual < var->yoffset + var->yres) 385 + var->yres_virtual = var->yoffset + var->yres; 386 + 387 + /* 388 + * Memory limit 389 + */ 390 + line_length = 391 + get_line_length(var->xres_virtual, var->bits_per_pixel); 392 + if (line_length * var->yres_virtual > UNIFB_MEMSIZE) 393 + return -ENOMEM; 394 + 395 + /* 396 + * Now that we checked it we alter var. The reason being is that the 397 + * video mode passed in might not work but slight changes to it might 398 + * make it work. This way we let the user know what is acceptable. 399 + */ 400 + switch (var->bits_per_pixel) { 401 + case 1: 402 + case 8: 403 + var->red.offset = 0; 404 + var->red.length = 8; 405 + var->green.offset = 0; 406 + var->green.length = 8; 407 + var->blue.offset = 0; 408 + var->blue.length = 8; 409 + var->transp.offset = 0; 410 + var->transp.length = 0; 411 + break; 412 + case 16: /* RGBA 5551 */ 413 + if (var->transp.length) { 414 + var->red.offset = 0; 415 + var->red.length = 5; 416 + var->green.offset = 5; 417 + var->green.length = 5; 418 + var->blue.offset = 10; 419 + var->blue.length = 5; 420 + var->transp.offset = 15; 421 + var->transp.length = 1; 422 + } else { /* RGB 565 */ 423 + var->red.offset = 11; 424 + var->red.length = 5; 425 + var->green.offset = 5; 426 + var->green.length = 6; 427 + var->blue.offset = 0; 428 + var->blue.length = 5; 429 + var->transp.offset = 0; 430 + var->transp.length = 0; 431 + } 432 + break; 433 + case 24: /* RGB 888 */ 434 + var->red.offset = 0; 435 + var->red.length = 8; 436 + var->green.offset = 8; 437 + var->green.length = 8; 438 + var->blue.offset = 16; 439 + var->blue.length = 8; 440 + var->transp.offset = 0; 441 + var->transp.length = 0; 442 + break; 443 + case 32: /* RGBA 8888 */ 444 + var->red.offset = 16; 445 + var->red.length = 8; 446 + var->green.offset = 8; 447 + var->green.length = 8; 448 + var->blue.offset = 0; 449 + var->blue.length = 8; 450 + var->transp.offset = 24; 451 + var->transp.length = 8; 452 + break; 453 + } 454 + var->red.msb_right = 0; 455 + var->green.msb_right = 0; 456 + var->blue.msb_right = 0; 457 + var->transp.msb_right = 0; 458 + 459 + return 0; 460 + } 461 + 462 + /* 463 + * This routine actually sets the video mode. It's in here where we 464 + * the hardware state info->par and fix which can be affected by the 465 + * change in par. For this driver it doesn't do much. 466 + */ 467 + static int unifb_set_par(struct fb_info *info) 468 + { 469 + int hTotal, vTotal, hSyncStart, hSyncEnd, vSyncStart, vSyncEnd; 470 + int format; 471 + 472 + #ifdef CONFIG_PUV3_PM 473 + struct clk *clk_vga; 474 + u32 pixclk = 0; 475 + int i; 476 + 477 + for (i = 0; i <= 10; i++) { 478 + if (info->var.xres == unifb_modes[i].xres 479 + && info->var.yres == unifb_modes[i].yres 480 + && info->var.upper_margin == unifb_modes[i].upper_margin 481 + && info->var.lower_margin == unifb_modes[i].lower_margin 482 + && info->var.left_margin == unifb_modes[i].left_margin 483 + && info->var.right_margin == unifb_modes[i].right_margin 484 + && info->var.hsync_len == unifb_modes[i].hsync_len 485 + && info->var.vsync_len == unifb_modes[i].vsync_len) { 486 + pixclk = unifb_modes[i].pixclock; 487 + break; 488 + } 489 + } 490 + 491 + /* set clock rate */ 492 + clk_vga = clk_get(info->device, "VGA_CLK"); 493 + if (clk_vga == ERR_PTR(-ENOENT)) 494 + return -ENOENT; 495 + 496 + if (pixclk != 0) { 497 + if (clk_set_rate(clk_vga, pixclk)) { /* set clock failed */ 498 + info->fix = unifb_fix; 499 + info->var = unifb_default; 500 + if (clk_set_rate(clk_vga, unifb_default.pixclock)) 501 + return -EINVAL; 502 + } 503 + } 504 + #endif 505 + 506 + info->fix.line_length = get_line_length(info->var.xres_virtual, 507 + info->var.bits_per_pixel); 508 + 509 + hSyncStart = info->var.xres + info->var.right_margin; 510 + hSyncEnd = hSyncStart + info->var.hsync_len; 511 + hTotal = hSyncEnd + info->var.left_margin; 512 + 513 + vSyncStart = info->var.yres + info->var.lower_margin; 514 + vSyncEnd = vSyncStart + info->var.vsync_len; 515 + vTotal = vSyncEnd + info->var.upper_margin; 516 + 517 + switch (info->var.bits_per_pixel) { 518 + case 8: 519 + format = UDE_CFG_DST8; 520 + break; 521 + case 16: 522 + format = UDE_CFG_DST16; 523 + break; 524 + case 24: 525 + format = UDE_CFG_DST24; 526 + break; 527 + case 32: 528 + format = UDE_CFG_DST32; 529 + break; 530 + default: 531 + return -EINVAL; 532 + } 533 + 534 + writel(PKUNITY_UNIGFX_MMAP_BASE, UDE_FSA); 535 + writel(info->var.yres, UDE_LS); 536 + writel(get_line_length(info->var.xres, 537 + info->var.bits_per_pixel) >> 3, UDE_PS); 538 + /* >> 3 for hardware required. */ 539 + writel((hTotal << 16) | (info->var.xres), UDE_HAT); 540 + writel(((hTotal - 1) << 16) | (info->var.xres - 1), UDE_HBT); 541 + writel(((hSyncEnd - 1) << 16) | (hSyncStart - 1), UDE_HST); 542 + writel((vTotal << 16) | (info->var.yres), UDE_VAT); 543 + writel(((vTotal - 1) << 16) | (info->var.yres - 1), UDE_VBT); 544 + writel(((vSyncEnd - 1) << 16) | (vSyncStart - 1), UDE_VST); 545 + writel(UDE_CFG_GDEN_ENABLE | UDE_CFG_TIMEUP_ENABLE 546 + | format | 0xC0000001, UDE_CFG); 547 + 548 + return 0; 549 + } 550 + 551 + /* 552 + * Set a single color register. The values supplied are already 553 + * rounded down to the hardware's capabilities (according to the 554 + * entries in the var structure). Return != 0 for invalid regno. 555 + */ 556 + static int unifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 557 + u_int transp, struct fb_info *info) 558 + { 559 + if (regno >= 256) /* no. of hw registers */ 560 + return 1; 561 + 562 + /* grayscale works only partially under directcolor */ 563 + if (info->var.grayscale) { 564 + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ 565 + red = green = blue = 566 + (red * 77 + green * 151 + blue * 28) >> 8; 567 + } 568 + 569 + #define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16) 570 + switch (info->fix.visual) { 571 + case FB_VISUAL_TRUECOLOR: 572 + case FB_VISUAL_PSEUDOCOLOR: 573 + red = CNVT_TOHW(red, info->var.red.length); 574 + green = CNVT_TOHW(green, info->var.green.length); 575 + blue = CNVT_TOHW(blue, info->var.blue.length); 576 + transp = CNVT_TOHW(transp, info->var.transp.length); 577 + break; 578 + case FB_VISUAL_DIRECTCOLOR: 579 + red = CNVT_TOHW(red, 8); /* expect 8 bit DAC */ 580 + green = CNVT_TOHW(green, 8); 581 + blue = CNVT_TOHW(blue, 8); 582 + /* hey, there is bug in transp handling... */ 583 + transp = CNVT_TOHW(transp, 8); 584 + break; 585 + } 586 + #undef CNVT_TOHW 587 + /* Truecolor has hardware independent palette */ 588 + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { 589 + u32 v; 590 + 591 + if (regno >= 16) 592 + return 1; 593 + 594 + v = (red << info->var.red.offset) | 595 + (green << info->var.green.offset) | 596 + (blue << info->var.blue.offset) | 597 + (transp << info->var.transp.offset); 598 + switch (info->var.bits_per_pixel) { 599 + case 8: 600 + break; 601 + case 16: 602 + case 24: 603 + case 32: 604 + ((u32 *) (info->pseudo_palette))[regno] = v; 605 + break; 606 + default: 607 + return 1; 608 + } 609 + return 0; 610 + } 611 + return 0; 612 + } 613 + 614 + /* 615 + * Pan or Wrap the Display 616 + * 617 + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag 618 + */ 619 + static int unifb_pan_display(struct fb_var_screeninfo *var, 620 + struct fb_info *info) 621 + { 622 + if (var->vmode & FB_VMODE_YWRAP) { 623 + if (var->yoffset < 0 624 + || var->yoffset >= info->var.yres_virtual 625 + || var->xoffset) 626 + return -EINVAL; 627 + } else { 628 + if (var->xoffset + var->xres > info->var.xres_virtual || 629 + var->yoffset + var->yres > info->var.yres_virtual) 630 + return -EINVAL; 631 + } 632 + info->var.xoffset = var->xoffset; 633 + info->var.yoffset = var->yoffset; 634 + if (var->vmode & FB_VMODE_YWRAP) 635 + info->var.vmode |= FB_VMODE_YWRAP; 636 + else 637 + info->var.vmode &= ~FB_VMODE_YWRAP; 638 + return 0; 639 + } 640 + 641 + int unifb_mmap(struct fb_info *info, 642 + struct vm_area_struct *vma) 643 + { 644 + unsigned long size = vma->vm_end - vma->vm_start; 645 + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; 646 + unsigned long pos = info->fix.smem_start + offset; 647 + 648 + if (offset + size > info->fix.smem_len) 649 + return -EINVAL; 650 + 651 + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 652 + 653 + if (io_remap_pfn_range(vma, vma->vm_start, pos >> PAGE_SHIFT, size, 654 + vma->vm_page_prot)) 655 + return -EAGAIN; 656 + 657 + vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ 658 + return 0; 659 + 660 + } 661 + 662 + static struct fb_ops unifb_ops = { 663 + .fb_read = fb_sys_read, 664 + .fb_write = fb_sys_write, 665 + .fb_check_var = unifb_check_var, 666 + .fb_set_par = unifb_set_par, 667 + .fb_setcolreg = unifb_setcolreg, 668 + .fb_pan_display = unifb_pan_display, 669 + .fb_fillrect = unifb_fillrect, 670 + .fb_copyarea = unifb_copyarea, 671 + .fb_imageblit = unifb_imageblit, 672 + .fb_mmap = unifb_mmap, 673 + }; 674 + 675 + /* 676 + * Initialisation 677 + */ 678 + static int unifb_probe(struct platform_device *dev) 679 + { 680 + struct fb_info *info; 681 + u32 unifb_regs[UNIFB_REGS_NUM]; 682 + int retval = -ENOMEM; 683 + struct resource *iomem, *mapmem; 684 + 685 + info = framebuffer_alloc(sizeof(u32)*256, &dev->dev); 686 + if (!info) 687 + goto err; 688 + 689 + info->screen_base = (char __iomem *)KUSER_UNIGFX_BASE; 690 + info->fbops = &unifb_ops; 691 + 692 + retval = fb_find_mode(&info->var, info, NULL, 693 + unifb_modes, 10, &unifb_modes[0], 16); 694 + 695 + if (!retval || (retval == 4)) 696 + info->var = unifb_default; 697 + 698 + iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); 699 + unifb_fix.mmio_start = iomem->start; 700 + 701 + mapmem = platform_get_resource(dev, IORESOURCE_MEM, 1); 702 + unifb_fix.smem_start = mapmem->start; 703 + unifb_fix.smem_len = UNIFB_MEMSIZE; 704 + 705 + info->fix = unifb_fix; 706 + info->pseudo_palette = info->par; 707 + info->par = NULL; 708 + info->flags = FBINFO_FLAG_DEFAULT; 709 + #ifdef FB_ACCEL_PUV3_UNIGFX 710 + info->fix.accel = FB_ACCEL_PUV3_UNIGFX; 711 + #endif 712 + 713 + retval = fb_alloc_cmap(&info->cmap, 256, 0); 714 + if (retval < 0) 715 + goto err1; 716 + 717 + retval = register_framebuffer(info); 718 + if (retval < 0) 719 + goto err2; 720 + platform_set_drvdata(dev, info); 721 + platform_device_add_data(dev, unifb_regs, sizeof(u32) * UNIFB_REGS_NUM); 722 + 723 + printk(KERN_INFO 724 + "fb%d: Virtual frame buffer device, using %dM of video memory\n", 725 + info->node, UNIFB_MEMSIZE >> 20); 726 + return 0; 727 + err2: 728 + fb_dealloc_cmap(&info->cmap); 729 + err1: 730 + framebuffer_release(info); 731 + err: 732 + return retval; 733 + } 734 + 735 + static int unifb_remove(struct platform_device *dev) 736 + { 737 + struct fb_info *info = platform_get_drvdata(dev); 738 + 739 + if (info) { 740 + unregister_framebuffer(info); 741 + fb_dealloc_cmap(&info->cmap); 742 + framebuffer_release(info); 743 + } 744 + return 0; 745 + } 746 + 747 + #ifdef CONFIG_PM 748 + static int unifb_resume(struct platform_device *dev) 749 + { 750 + int rc = 0; 751 + u32 *unifb_regs = dev->dev.platform_data; 752 + 753 + if (dev->dev.power.power_state.event == PM_EVENT_ON) 754 + return 0; 755 + 756 + console_lock(); 757 + 758 + if (dev->dev.power.power_state.event == PM_EVENT_SUSPEND) { 759 + writel(unifb_regs[0], UDE_FSA); 760 + writel(unifb_regs[1], UDE_LS); 761 + writel(unifb_regs[2], UDE_PS); 762 + writel(unifb_regs[3], UDE_HAT); 763 + writel(unifb_regs[4], UDE_HBT); 764 + writel(unifb_regs[5], UDE_HST); 765 + writel(unifb_regs[6], UDE_VAT); 766 + writel(unifb_regs[7], UDE_VBT); 767 + writel(unifb_regs[8], UDE_VST); 768 + writel(unifb_regs[9], UDE_CFG); 769 + } 770 + dev->dev.power.power_state = PMSG_ON; 771 + 772 + console_unlock(); 773 + 774 + return rc; 775 + } 776 + 777 + static int unifb_suspend(struct platform_device *dev, pm_message_t mesg) 778 + { 779 + u32 *unifb_regs = dev->dev.platform_data; 780 + 781 + unifb_regs[0] = readl(UDE_FSA); 782 + unifb_regs[1] = readl(UDE_LS); 783 + unifb_regs[2] = readl(UDE_PS); 784 + unifb_regs[3] = readl(UDE_HAT); 785 + unifb_regs[4] = readl(UDE_HBT); 786 + unifb_regs[5] = readl(UDE_HST); 787 + unifb_regs[6] = readl(UDE_VAT); 788 + unifb_regs[7] = readl(UDE_VBT); 789 + unifb_regs[8] = readl(UDE_VST); 790 + unifb_regs[9] = readl(UDE_CFG); 791 + 792 + if (mesg.event == dev->dev.power.power_state.event) 793 + return 0; 794 + 795 + switch (mesg.event) { 796 + case PM_EVENT_FREEZE: /* about to take snapshot */ 797 + case PM_EVENT_PRETHAW: /* before restoring snapshot */ 798 + goto done; 799 + } 800 + 801 + console_lock(); 802 + 803 + /* do nothing... */ 804 + 805 + console_unlock(); 806 + 807 + done: 808 + dev->dev.power.power_state = mesg; 809 + 810 + return 0; 811 + } 812 + #else 813 + #define unifb_resume NULL 814 + #define unifb_suspend NULL 815 + #endif 816 + 817 + static struct platform_driver unifb_driver = { 818 + .probe = unifb_probe, 819 + .remove = unifb_remove, 820 + .resume = unifb_resume, 821 + .suspend = unifb_suspend, 822 + .driver = { 823 + .name = "PKUnity-v3-UNIGFX", 824 + }, 825 + }; 826 + 827 + static int __init unifb_init(void) 828 + { 829 + #ifndef MODULE 830 + if (fb_get_options("unifb", NULL)) 831 + return -ENODEV; 832 + #endif 833 + 834 + return platform_driver_register(&unifb_driver); 835 + } 836 + 837 + module_init(unifb_init); 838 + 839 + static void __exit unifb_exit(void) 840 + { 841 + platform_driver_unregister(&unifb_driver); 842 + } 843 + 844 + module_exit(unifb_exit); 845 + 846 + MODULE_LICENSE("GPL v2");
+2
include/linux/fb.h
··· 152 152 #define FB_ACCEL_PROSAVAGE_DDR 0x8d /* S3 ProSavage DDR */ 153 153 #define FB_ACCEL_PROSAVAGE_DDRK 0x8e /* S3 ProSavage DDR-K */ 154 154 155 + #define FB_ACCEL_PUV3_UNIGFX 0xa0 /* PKUnity-v3 Unigfx */ 156 + 155 157 struct fb_fix_screeninfo { 156 158 char id[16]; /* identification string eg "TT Builtin" */ 157 159 unsigned long smem_start; /* Start of frame buffer mem */