patch-2.2.18 linux/drivers/video/acornfb.c
Next file: linux/drivers/video/aty128.h
Previous file: linux/drivers/video/Makefile
Back to the patch index
Back to the overall index
- Lines: 1145
- Date:
Fri Sep 15 23:31:12 2000
- Orig file:
v2.2.17/drivers/video/acornfb.c
- Orig date:
Fri Apr 21 12:46:37 2000
diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/video/acornfb.c linux/drivers/video/acornfb.c
@@ -1,7 +1,7 @@
/*
- * linux/drivers/video/acorn.c
+ * linux/drivers/video/acornfb.c
*
- * Copyright (C) 1998,1999 Russell King
+ * Copyright (C) 1998-2000 Russell King
*
* Frame buffer code for Acorn platforms
*
@@ -34,6 +34,7 @@
#include <video/fbcon-cfb4.h>
#include <video/fbcon-cfb8.h>
#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb32.h>
/*
* Default resolution.
@@ -42,6 +43,25 @@
*/
#define DEFAULT_XRES 640
#define DEFAULT_YRES 480
+/*
+ * The order here defines which BPP we
+ * pick depending on which resolutions
+ * we have configured.
+ */
+#if defined(FBCON_HAS_CFB4)
+# define DEFAULT_BPP 4
+#elif defined(FBCON_HAS_CFB8)
+# define DEFAULT_BPP 8
+#elif defined(FBCON_HAS_CFB16)
+# define DEFAULT_BPP 16
+#elif defined(FBCON_HAS_CFB2)
+# define DEFAULT_BPP 2
+#elif defined(FBCON_HAS_MFB)
+# define DEFAULT_BPP 1
+#else
+#error No suitable framebuffers configured
+#endif
+
/*
* define this to debug the video mode selection
@@ -94,7 +114,6 @@
unsigned int palette_size;
signed int montype;
signed int currcon;
- unsigned int allow_modeset : 1;
unsigned int using_vram : 1;
unsigned int dpms : 1;
@@ -106,14 +125,37 @@
} cmap;
};
+struct vidc_timing {
+ u_int h_cycle;
+ u_int h_sync_width;
+ u_int h_border_start;
+ u_int h_display_start;
+ u_int h_display_end;
+ u_int h_border_end;
+ u_int h_interlace;
+
+ u_int v_cycle;
+ u_int v_sync_width;
+ u_int v_border_start;
+ u_int v_display_start;
+ u_int v_display_end;
+ u_int v_border_end;
+
+ u_int control;
+
+ /* VIDC20 only */
+ u_int pll_ctl;
+};
+
/*
* Translation from RISC OS monitor types to actual
* HSYNC and VSYNC frequency ranges. These are
- * probably not right...
+ * probably not right, but they're the best info I
+ * have. Allow 1% either way on the nominal for TVs.
*/
#define NR_MONTYPES 6
static struct fb_monspecs monspecs[NR_MONTYPES] __initdata = {
- { 15625, 15625, 50, 50, 0 }, /* TV */
+ { 15469, 15781, 49, 51, 0 }, /* TV */
{ 0, 99999, 0, 99, 0 }, /* Multi Freq */
{ 58608, 58608, 64, 64, 0 }, /* Hi-res mono */
{ 30000, 70000, 60, 60, 0 }, /* VGA */
@@ -124,34 +166,12 @@
static struct display global_disp;
static struct fb_info fb_info;
static struct acornfb_par current_par;
+static struct vidc_timing current_vidc;
static struct fb_var_screeninfo __initdata init_var = {};
extern int acornfb_depth; /* set by setup.c */
extern unsigned int vram_size; /* set by setup.c */
-
-static struct vidc_timing {
- u_int h_cycle;
- u_int h_sync_width;
- u_int h_border_start;
- u_int h_display_start;
- u_int h_display_end;
- u_int h_border_end;
- u_int h_interlace;
-
- u_int v_cycle;
- u_int v_sync_width;
- u_int v_border_start;
- u_int v_display_start;
- u_int v_display_end;
- u_int v_border_end;
-
- u_int control;
-
- /* VIDC20 only */
- u_int pll_ctl;
-} current_vidc;
-
#ifdef HAS_VIDC
#define VID_CTL_VS_NVSYNC (1 << 3)
@@ -254,7 +274,9 @@
bandwidth = var->pixclock * 8 / var->bits_per_pixel;
/* 25.175, 4bpp = 79.444ns per byte, 317.776ns per word: fifo = 2,6 */
- if (bandwidth > 71750)
+ if (bandwidth > 143500)
+ vidc_ctl |= VIDC_CTRL_FIFO_3_7;
+ else if (bandwidth > 71750)
vidc_ctl |= VIDC_CTRL_FIFO_2_6;
else if (bandwidth > 35875)
vidc_ctl |= VIDC_CTRL_FIFO_1_5;
@@ -648,15 +670,19 @@
ext_ctl = VIDC20_ECTL_DAC | VIDC20_ECTL_REG(3);
- if (var->sync & FB_SYNC_HOR_HIGH_ACT)
- ext_ctl |= VIDC20_ECTL_HS_HSYNC;
- else
- ext_ctl |= VIDC20_ECTL_HS_NHSYNC;
+ if (var->sync & FB_SYNC_COMP_HIGH_ACT) /* should be FB_SYNC_COMP */
+ ext_ctl |= VIDC20_ECTL_HS_NCSYNC | VIDC20_ECTL_VS_NCSYNC;
+ else {
+ if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+ ext_ctl |= VIDC20_ECTL_HS_HSYNC;
+ else
+ ext_ctl |= VIDC20_ECTL_HS_NHSYNC;
- if (var->sync & FB_SYNC_VERT_HIGH_ACT)
- ext_ctl |= VIDC20_ECTL_VS_VSYNC;
- else
- ext_ctl |= VIDC20_ECTL_VS_NVSYNC;
+ if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+ ext_ctl |= VIDC20_ECTL_VS_VSYNC;
+ else
+ ext_ctl |= VIDC20_ECTL_VS_NVSYNC;
+ }
outl(VIDC20_ECTL | ext_ctl, IO_VIDC_BASE);
@@ -740,8 +766,8 @@
* Before selecting the timing parameters, adjust
* the resolution to fit the rules.
*/
-static void
-acornfb_pre_adjust_timing(struct fb_var_screeninfo *var, int con)
+static int
+acornfb_adjust_timing(struct fb_var_screeninfo *var, int con)
{
u_int font_line_len;
u_int fontht;
@@ -783,6 +809,13 @@
font_line_len = var->xres * var->bits_per_pixel * fontht / 8;
min_size = var->xres * var->yres * var->bits_per_pixel / 8;
+ /*
+ * If minimum screen size is greater than that we have
+ * available, reject it.
+ */
+ if (min_size > current_par.screen_size)
+ return -EINVAL;
+
/* Find int 'y', such that y * fll == s * sam < maxsize
* y = s * sam / fll; s = maxsize / sam
*/
@@ -794,14 +827,16 @@
break;
}
- if (min_size > size) {
- /*
- * failed, use ypan
- */
- size = current_par.screen_size;
- var->yres_virtual = size / (font_line_len / fontht);
- } else
- var->yres_virtual = nr_y * fontht;
+ if (var->accel_flags & FB_ACCELF_TEXT) {
+ if (min_size > size) {
+ /*
+ * failed, use ypan
+ */
+ size = current_par.screen_size;
+ var->yres_virtual = size / (font_line_len / fontht);
+ } else
+ var->yres_virtual = nr_y * fontht;
+ }
current_par.screen_end = current_par.screen_base_p + size;
@@ -818,16 +853,7 @@
if (var->yoffset + var->yres > var->yres_virtual)
var->yoffset = var->yres_virtual - var->yres;
}
-}
-/*
- * After selecting the timing parameters, adjust
- * the timing to suit the chip.
- * NOTE! Only minor adjustments should be made here.
- */
-static void
-acornfb_post_adjust_timing(struct fb_var_screeninfo *var)
-{
/* hsync_len must be even */
var->hsync_len = (var->hsync_len + 1) & ~1;
@@ -854,6 +880,31 @@
if (var->vsync_len < 1)
var->vsync_len = 1;
+
+ return 0;
+}
+
+static int
+acornfb_validate_timing(struct fb_var_screeninfo *var,
+ struct fb_monspecs *monspecs)
+{
+ unsigned long hs, vs;
+
+ /*
+ * hs(Hz) = 10^12 / (pixclock * xtotal)
+ * vs(Hz) = hs(Hz) / ytotal
+ *
+ * No need to do long long divisions or anything
+ * like that if you factor it correctly
+ */
+ hs = 1953125000 / var->pixclock;
+ hs = hs * 512 /
+ (var->xres + var->left_margin + var->right_margin + var->hsync_len);
+ vs = hs /
+ (var->yres + var->upper_margin + var->lower_margin + var->vsync_len);
+
+ return (vs >= monspecs->vfmin && vs <= monspecs->vfmax &&
+ hs >= monspecs->hfmin && hs <= monspecs->hfmax) ? 0 : -EINVAL;
}
static inline void
@@ -895,32 +946,75 @@
return 0;
}
+/*
+ * We have to take note of the VIDC20's 16-bit palette here.
+ * The VIDC20 looks up a 16 bit pixel as follows:
+ *
+ * bits 111111
+ * 5432109876543210
+ * red ++++++++ (8 bits, 7 to 0)
+ * green ++++++++ (8 bits, 11 to 4)
+ * blue ++++++++ (8 bits, 15 to 8)
+ *
+ * We use a pixel which looks like:
+ *
+ * bits 111111
+ * 5432109876543210
+ * red +++++ (5 bits, 4 to 0)
+ * green +++++ (5 bits, 9 to 5)
+ * blue +++++ (5 bits, 14 to 10)
+ */
static int
acornfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int trans, struct fb_info *info)
{
union palette pal;
+ int bpp = fb_display[current_par.currcon].var.bits_per_pixel;
if (regno >= current_par.palette_size)
return 1;
pal = acornfb_palette_encode(regno, red, green, blue, trans);
- acornfb_palette_write(regno, pal);
current_par.palette[regno] = pal;
+#ifdef HAS_VIDC20
if (regno < 16) {
- switch (info->disp->var.bits_per_pixel) {
+ switch (bpp) {
#ifdef FBCON_HAS_CFB16
- case 16: /* RGB555 */
- current_par.cmap.cfb16[regno] = (regno << 10) | (regno << 5) | regno;
+ case 16:
+ current_par.cmap.cfb16[regno] =
+ regno | regno << 5 | regno << 10;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ current_par.cmap.cfb32[regno] =
+ regno | regno << 8 | regno << 16;
break;
#endif
-
default:
break;
}
}
+#ifdef FBCON_HAS_CFB16
+ if (bpp == 16) {
+ int i;
+
+ pal.p = 0;
+ outl(0x10000000, IO_VIDC_BASE);
+ for (i = 0; i < 256; i += 1) {
+ pal.vidc20.red = current_par.palette[ i & 31].vidc20.red;
+ pal.vidc20.green = current_par.palette[(i >> 1) & 31].vidc20.green;
+ pal.vidc20.blue = current_par.palette[(i >> 2) & 31].vidc20.blue;
+ outl(pal.p, IO_VIDC_BASE);
+ /* Palette register pointer auto-increments */
+ }
+ } else
+#endif
+#endif
+ acornfb_palette_write(regno, pal);
+
return 0;
}
@@ -963,6 +1057,8 @@
static int
acornfb_decode_var(struct fb_var_screeninfo *var, int con, int *visual)
{
+ int err;
+
switch (var->bits_per_pixel) {
#ifdef FBCON_HAS_MFB
case 1:
@@ -988,10 +1084,18 @@
*visual = FB_VISUAL_PSEUDOCOLOR;
break;
#endif
+#ifdef HAS_VIDC20
+#ifdef FBCON_HAS_CFB16
case 16:
- case 24:
+ *visual = FB_VISUAL_DIRECTCOLOR;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
case 32:
*visual = FB_VISUAL_TRUECOLOR;
+ break;
+#endif
+#endif
default:
return -EINVAL;
}
@@ -1000,25 +1104,60 @@
return -EINVAL;
/*
- * Adjust the resolution before using it.
+ * Validate and adjust the resolution to
+ * match the video generator hardware.
+ */
+ err = acornfb_adjust_timing(var, con);
+ if (err)
+ return err;
+
+ /*
+ * Validate the timing against the
+ * monitor hardware.
*/
- acornfb_pre_adjust_timing(var, con);
+ err = acornfb_validate_timing(var, &fb_info.monspecs);
+ if (err)
+ return err;
#if defined(HAS_VIDC20)
- var->red.length = 8;
- var->transp.length = 4;
+ switch (var->bits_per_pixel) {
+ case 1: case 2: case 4: case 8:
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green = var->red;
+ var->blue = var->red;
+ var->transp.offset = 0;
+ var->transp.length = 4;
+ break;
+
+ case 16:
+ var->red.offset = 0;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->blue.offset = 10;
+ var->blue.length = 5;
+ var->transp.offset = 15;
+ var->transp.length = 1;
+ break;
+
+ case 32:
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 16;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 4;
+ break;
+ }
#elif defined(HAS_VIDC)
var->red.length = 4;
+ var->green = var->red;
+ var->blue = var->red;
var->transp.length = 1;
#endif
- var->green = var->red;
- var->blue = var->red;
-
- /*
- * Now adjust the timing parameters
- */
- acornfb_post_adjust_timing(var);
-
return 0;
}
@@ -1071,9 +1210,6 @@
else
display = &global_disp;
- if (!current_par.allow_modeset && con != -1)
- return -EINVAL;
-
err = acornfb_decode_var(var, con, &visual);
if (err)
return err;
@@ -1151,11 +1287,18 @@
#endif
#ifdef FBCON_HAS_CFB16
case 16:
- current_par.palette_size = VIDC_PALETTE_SIZE;
+ current_par.palette_size = 32;
display->dispsw = &fbcon_cfb16;
display->dispsw_data = current_par.cmap.cfb16;
break;
#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ current_par.palette_size = VIDC_PALETTE_SIZE;
+ display->dispsw = &fbcon_cfb32;
+ display->dispsw_data = current_par.cmap.cfb32;
+ break;
+#endif
default:
display->dispsw = &fbcon_dummy;
break;
@@ -1194,9 +1337,7 @@
outl(control, IOMD_VIDCR);
#endif
acornfb_update_dma(var);
-
- if (current_par.allow_modeset)
- acornfb_set_timing(var);
+ acornfb_set_timing(var);
if (display->cmap.len)
cmap = &display->cmap;
@@ -1288,236 +1429,154 @@
static void
acornfb_blank(int blank, struct fb_info *info)
{
- int i;
+ union palette p;
+ int i, bpp = fb_display[current_par.currcon].var.bits_per_pixel;
- if (blank)
+ if (bpp != 16) {
for (i = 0; i < current_par.palette_size; i++) {
- union palette p;
-
- p = acornfb_palette_encode(i, 0, 0, 0, 0);
+ if (blank)
+ p = acornfb_palette_encode(i, 0, 0, 0, 0);
+ else
+ p = current_par.palette[i];
acornfb_palette_write(i, p);
}
- else
- for (i = 0; i < current_par.palette_size; i++)
+ }
+#ifdef FBCON_HAS_CFB16
+ else {
+ p.p = 0;
+
+ for (i = 0; i < 256; i++) {
+ if (blank)
+ p = acornfb_palette_encode(i, 0, 0, 0, 0);
+ else {
+ p.vidc20.red = current_par.palette[ i & 31].vidc20.red;
+ p.vidc20.green = current_par.palette[(i >> 1) & 31].vidc20.green;
+ p.vidc20.blue = current_par.palette[(i >> 2) & 31].vidc20.blue;
+ }
acornfb_palette_write(i, current_par.palette[i]);
+ }
+ }
+#endif
}
/*
* Everything after here is initialisation!!!
*/
-struct modey_params {
- u_int y_res;
- u_int u_margin;
- u_int b_margin;
- u_int vsync_len;
- u_int vf;
-};
-
-struct modex_params {
- u_int x_res;
- u_int l_margin;
- u_int r_margin;
- u_int hsync_len;
- u_int clock;
- u_int hf;
- const struct modey_params *modey;
-};
-
-static const struct modey_params modey_640_15600[] __initdata = {
- { 250, 38, 21, 3, 50 }, /* 640x 250, 50Hz */
- { 256, 35, 18, 3, 50 }, /* 640x 256, 50Hz */
- { 0, 0, 0, 0, 0 }
-};
-
-static const struct modey_params modey_640_26800[] __initdata = {
- { 512, 18, 1, 3, 50 }, /* 640x 512, 50Hz */
- { 0, 0, 0, 0, 0 }
-};
-
-static const struct modey_params modey_640_31500[] __initdata = {
- { 250, 109, 88, 2, 70 }, /* 640x 250, 70Hz */
- { 256, 106, 85, 2, 70 }, /* 640x 256, 70Hz */
- { 352, 58, 37, 2, 70 }, /* 640x 352, 70Hz */
- { 480, 32, 11, 2, 60 }, /* 640x 480, 60Hz */
- { 0, 0, 0, 0, 0 }
-};
-
-static const struct modey_params modey_800_35200[] __initdata = {
- { 600, 22, 1, 2, 56 }, /* 800x 600, 56Hz */
- { 0, 0, 0, 0, 0 }
-};
-
-static const struct modey_params modey_896_21800[] __initdata = {
- { 352, 9, 0, 3, 60 }, /* 896x 352, 60Hz */
- { 0, 0, 0, 0, 0 }
-};
-
-/* everything after here is not supported */
-static const struct modey_params modey_1024_uk[] __initdata = {
- { 768, 0, 0, 0, 0 }, /* 1024x 768 */
- { 0, 0, 0, 0, 0 }
-};
+#define fb_videomode fb_2_3_videomode
-static const struct modey_params modey_1056_uk[] __initdata = {
- { 250, 0, 0, 0, 0 }, /* 1056x 250 */
- { 256, 0, 0, 0, 0 }, /* 1056x 256 */
- { 0, 0, 0, 0, 0 }
-};
-
-static const struct modey_params modey_1152_uk[] __initdata = {
- { 896, 0, 0, 0, 0 }, /* 1152x 896 */
- { 0, 0, 0, 0, 0 }
-};
-
-static const struct modey_params modey_1280_63600[] __initdata = {
- { 1024, 0, 0, 0, 60 }, /* 1280x1024, 60Hz */
- { 0, 0, 0, 0, 0 }
-};
-
-static const struct modey_params modey_1600_uk[] __initdata = {
- { 1280, 0, 0, 0, 0 }, /* 1600x1280 */
- { 0, 0, 0, 0, 0 }
-};
-
-/*
- * Horizontal video programming requirements.
- * This table is searched for the required horizontal
- * and required frequency, and then the tables above
- * are then searched for the required vertical
- * resolution.
- *
- * NOTE! we can match multiple entries, so we search
- * all horizontal entries for which the hfreq is within
- * the monitor's range.
- */
-static const struct modex_params modex_params[] __initdata = {
- { /* X: 640, 15.6kHz */
- 640, 185, 123, 76, 16000, 15625, modey_640_15600
- },
- { /* X: 640, 26.8kHz */
- 640, 113, 87, 56, 24000, 26800, modey_640_26800
- },
- { /* X: 640, 31.5kHz */
- 640, 48, 16, 96, 25175, 31500, modey_640_31500
- },
- { /* X: 800, 35.2kHz */
- 800, 101, 23, 100, 36000, 35200, modey_800_35200
- },
- { /* X: 896, 21.8kHz */
- 896, 59, 27, 118, 24000, 21800, modey_896_21800
- },
- { /* X: 1024 */
- 1024, 0, 0, 0, 0, 0, modey_1024_uk
- },
- { /* X: 1056 */
- 1056, 0, 0, 0, 0, 0, modey_1056_uk
- },
- { /* X: 1152 */
- 1152, 0, 0, 0, 0, 0, modey_1152_uk
- },
- { /* X: 1280, 63.6kHz */
- 1280, 0, 0, 0, 0, 63600, modey_1280_63600
- },
- { /* X: 1600 */
- 1600, 0, 0, 0, 0, 0, modey_1600_uk
- },
- {
+struct fb_videomode {
+ const char *name; /* optional */
+ u32 refresh; /* optional */
+ u32 xres;
+ u32 yres;
+ u32 pixclock;
+ u32 left_margin;
+ u32 right_margin;
+ u32 upper_margin;
+ u32 lower_margin;
+ u32 hsync_len;
+ u32 vsync_len;
+ u32 sync;
+ u32 vmode;
+};
+
+static struct fb_videomode modedb[] __initdata = {
+ { /* 320x256 @ 50Hz */
+ NULL, 50, 320, 256, 125000, 92, 62, 35, 19, 38, 2,
+ FB_SYNC_COMP_HIGH_ACT,
+ FB_VMODE_NONINTERLACED
+ }, { /* 640x250 @ 50Hz, 15.6 kHz hsync */
+ NULL, 50, 640, 250, 62500, 185, 123, 38, 21, 76, 3,
+ 0,
+ FB_VMODE_NONINTERLACED
+ }, { /* 640x256 @ 50Hz, 15.6 kHz hsync */
+ NULL, 50, 640, 256, 62500, 185, 123, 35, 18, 76, 3,
+ 0,
+ FB_VMODE_NONINTERLACED
+ }, { /* 640x512 @ 50Hz, 26.8 kHz hsync */
+ NULL, 50, 640, 512, 41667, 113, 87, 18, 1, 56, 3,
+ 0,
+ FB_VMODE_NONINTERLACED
+ }, { /* 640x250 @ 70Hz, 31.5 kHz hsync */
+ NULL, 70, 640, 250, 39722, 48, 16, 109, 88, 96, 2,
+ 0,
+ FB_VMODE_NONINTERLACED
+ }, { /* 640x256 @ 70Hz, 31.5 kHz hsync */
+ NULL, 70, 640, 256, 39722, 48, 16, 106, 85, 96, 2,
+ 0,
+ FB_VMODE_NONINTERLACED
+ }, { /* 640x352 @ 70Hz, 31.5 kHz hsync */
+ NULL, 70, 640, 352, 39722, 48, 16, 58, 37, 96, 2,
0,
+ FB_VMODE_NONINTERLACED
+ }, { /* 640x480 @ 60Hz, 31.5 kHz hsync */
+ NULL, 60, 640, 480, 39722, 48, 16, 32, 11, 96, 2,
+ 0,
+ FB_VMODE_NONINTERLACED
+ }, { /* 800x600 @ 56Hz, 35.2 kHz hsync */
+ NULL, 56, 800, 600, 27778, 101, 23, 22, 1, 100, 2,
+ 0,
+ FB_VMODE_NONINTERLACED
+ }, { /* 896x352 @ 60Hz, 21.8 kHz hsync */
+ NULL, 60, 896, 352, 41667, 59, 27, 9, 0, 118, 3,
+ 0,
+ FB_VMODE_NONINTERLACED
+ }, { /* 1024x 768 @ 60Hz, 48.4 kHz hsync */
+ NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
+ 0,
+ FB_VMODE_NONINTERLACED
+ }, { /* 1280x1024 @ 60Hz, 63.8 kHz hsync */
+ NULL, 60, 1280, 1024, 9090, 186, 96, 38, 1, 160, 3,
+ 0,
+ FB_VMODE_NONINTERLACED
}
};
-__initfunc(static int
-acornfb_lookup_timing(struct fb_var_screeninfo *var))
-{
- const struct modex_params *x;
- const struct modey_params *y;
-
- /*
- * We must adjust the resolution parameters
- * before selecting the timing parameters.
- */
- acornfb_pre_adjust_timing(var, -1);
-
- for (x = modex_params; x->x_res; x++) {
-
- /*
- * Is this resolution one we're looking for?
- */
- if (x->x_res != var->xres)
- continue;
-
- /*
- * Is the hsync frequency ok for our monitor?
- */
- if (x->hf > fb_info.monspecs.hfmax ||
- x->hf < fb_info.monspecs.hfmin)
- continue;
-
- /*
- * Try to find a vertical resolution
- */
- for (y = x->modey; y->y_res; y++) {
- /*
- * Is this resolution one we're looking for?
- */
- if (y->y_res != var->yres)
- continue;
-
- /*
- * Is the vsync frequency ok for our monitor?
- */
- if (y->vf > fb_info.monspecs.vfmax ||
- y->vf < fb_info.monspecs.vfmin)
- continue;
-
- goto found;
- }
- }
-
- var->pixclock = 0;
-
- return -EINVAL;
-
-found:
- /*
- * Why is pixclock in picoseconds?
- */
- switch (x->clock) {
- case 36000: var->pixclock = 27778; break;
- case 25175: var->pixclock = 39722; break;
- case 24000: var->pixclock = 41667; break;
- case 16000: var->pixclock = 62500; break;
- case 12000: var->pixclock = 83333; break;
- case 8000: var->pixclock = 125000; break;
- default: var->pixclock = 0; break;
- }
-
-#ifdef DEBUG_MODE_SELECTION
- printk(KERN_DEBUG "Found %dx%d at %d.%3dkHz, %dHz, pix %d\n",
- x->x_res, y->y_res,
- x->hf / 1000, x->hf % 1000,
- y->vf, var->pixclock);
-#endif
-
- var->left_margin = x->l_margin;
- var->right_margin = x->r_margin;
- var->upper_margin = y->u_margin;
- var->lower_margin = y->b_margin;
- var->hsync_len = x->hsync_len;
- var->vsync_len = y->vsync_len;
- var->sync = 0;
-
- /*
- * Now adjust the parameters we found
- */
- acornfb_post_adjust_timing(var);
-
- return 0;
+static struct fb_videomode __initdata
+acornfb_default_mode = {
+ name: NULL,
+ refresh: 60,
+ xres: 640,
+ yres: 480,
+ pixclock: 39722,
+ left_margin: 56,
+ right_margin: 16,
+ upper_margin: 34,
+ lower_margin: 9,
+ hsync_len: 88,
+ vsync_len: 2,
+ sync: 0,
+ vmode: FB_VMODE_NONINTERLACED
+};
+
+static int fb_find_mode(struct fb_var_screeninfo *var, struct fb_info *info,
+ const char *mode_option, const struct fb_videomode *db,
+ unsigned int dbsize, const struct fb_videomode *default_mode,
+ unsigned int default_bpp)
+{
+ var->xres = default_mode->xres;
+ var->yres = default_mode->yres;
+ var->xres_virtual = default_mode->xres;
+ var->yres_virtual = default_mode->yres;
+ var->xoffset = 0;
+ var->yoffset = 0;
+ var->bits_per_pixel = default_bpp;
+ var->activate = 0;
+ var->pixclock = default_mode->pixclock;
+ var->left_margin = default_mode->left_margin;
+ var->right_margin = default_mode->right_margin;
+ var->upper_margin = default_mode->upper_margin;
+ var->lower_margin = default_mode->lower_margin;
+ var->hsync_len = default_mode->hsync_len;
+ var->vsync_len = default_mode->vsync_len;
+ var->sync = default_mode->sync;
+ var->vmode = default_mode->vmode;
+ return 3;
}
-__initfunc(static void
-acornfb_init_fbinfo(void))
+static void __init
+acornfb_init_fbinfo(void)
{
static int first = 1;
@@ -1543,20 +1602,6 @@
* setup initial parameters
*/
memset(&init_var, 0, sizeof(init_var));
- init_var.xres = DEFAULT_XRES;
- init_var.yres = DEFAULT_YRES;
-
-#if defined(FBCON_HAS_CFB4)
- init_var.bits_per_pixel = 4;
-#elif defined(FBCON_HAS_CFB8)
- init_var.bits_per_pixel = 8;
-#elif defined(FBCON_HAS_CFB2)
- init_var.bits_per_pixel = 2;
-#elif defined(FBCON_HAS_MFB)
- init_var.bits_per_pixel = 1;
-#else
-#error No suitable framebuffers configured
-#endif
#if defined(HAS_VIDC20)
init_var.red.length = 8;
@@ -1572,6 +1617,7 @@
init_var.height = -1;
init_var.width = -1;
init_var.vmode = FB_VMODE_NONINTERLACED;
+ init_var.accel_flags = FB_ACCELF_TEXT;
current_par.dram_size = 0;
current_par.montype = -1;
@@ -1610,48 +1656,62 @@
* size can optionally be followed by 'M' or 'K' for
* MB or KB respectively.
*/
-__initfunc(static void
-acornfb_parse_font(char *opt))
+static void __init
+acornfb_parse_font(char *opt)
{
strcpy(fb_info.fontname, opt);
}
-__initfunc(static void
-acornfb_parse_mon(char *opt))
+static void __init
+acornfb_parse_mon(char *opt)
{
- fb_info.monspecs.hfmin = simple_strtoul(opt, &opt, 0);
- if (*opt == '-')
- fb_info.monspecs.hfmax = simple_strtoul(opt + 1, &opt, 0);
+ char *p = opt;
+
+ current_par.montype = -2;
+
+ fb_info.monspecs.hfmin = simple_strtoul(p, &p, 0);
+ if (*p == '-')
+ fb_info.monspecs.hfmax = simple_strtoul(p + 1, &p, 0);
else
fb_info.monspecs.hfmax = fb_info.monspecs.hfmin;
- if (*opt != ':')
- return;
+ if (*p != ':')
+ goto bad;
- fb_info.monspecs.vfmin = simple_strtoul(opt + 1, &opt, 0);
- if (*opt == '-')
- fb_info.monspecs.vfmax = simple_strtoul(opt + 1, &opt, 0);
+ fb_info.monspecs.vfmin = simple_strtoul(p + 1, &p, 0);
+ if (*p == '-')
+ fb_info.monspecs.vfmax = simple_strtoul(p + 1, &p, 0);
else
fb_info.monspecs.vfmax = fb_info.monspecs.vfmin;
- if (*opt != ':')
- return;
+ if (*p != ':')
+ goto check_values;
- fb_info.monspecs.dpms = simple_strtoul(opt + 1, &opt, 0);
+ fb_info.monspecs.dpms = simple_strtoul(p + 1, &p, 0);
- if (*opt != ':')
- return;
+ if (*p != ':')
+ goto check_values;
- init_var.width = simple_strtoul(opt + 1, &opt, 0);
+ init_var.width = simple_strtoul(p + 1, &p, 0);
- if (*opt != ':')
- return;
+ if (*p != ':')
+ goto check_values;
- init_var.height = simple_strtoul(opt + 1, NULL, 0);
+ init_var.height = simple_strtoul(p + 1, NULL, 0);
+
+check_values:
+ if (fb_info.monspecs.hfmax < fb_info.monspecs.hfmin ||
+ fb_info.monspecs.vfmax < fb_info.monspecs.vfmin)
+ goto bad;
+ return;
+
+bad:
+ printk("Acornfb: bad monitor settings: %s\n", opt);
+ current_par.montype = -1;
}
-__initfunc(static void
-acornfb_parse_montype(char *opt))
+static void __init
+acornfb_parse_montype(char *opt)
{
current_par.montype = -2;
@@ -1692,8 +1752,8 @@
}
}
-__initfunc(static void
-acornfb_parse_dram(char *opt))
+static void __init
+acornfb_parse_dram(char *opt)
{
unsigned int size;
@@ -1726,8 +1786,8 @@
{ NULL, NULL }
};
-__initfunc(void
-acornfb_setup(char *options, int *ints))
+void __init
+acornfb_setup(char *options, int *ints)
{
struct options *optp;
char *opt;
@@ -1763,8 +1823,8 @@
* Detect type of monitor connected
* For now, we just assume SVGA
*/
-__initfunc(static int
-acornfb_detect_monitortype(void))
+static int __init
+acornfb_detect_monitortype(void)
{
return 4;
}
@@ -1800,22 +1860,45 @@
printk("acornfb: freed %dK memory\n", mb_freed);
}
-__initfunc(void
-acornfb_init(void))
+void __init
+acornfb_init(void)
{
unsigned long size;
u_int h_sync, v_sync;
+ int rc, i;
acornfb_init_fbinfo();
if (current_par.montype == -1)
current_par.montype = acornfb_detect_monitortype();
- if (current_par.montype < 0 || current_par.montype > NR_MONTYPES)
+ if (current_par.montype == -1 || current_par.montype > NR_MONTYPES)
current_par.montype = 4;
- fb_info.monspecs = monspecs[current_par.montype];
- fb_info.monspecs.dpms = current_par.dpms;
+ if (current_par.montype > 0) {
+ fb_info.monspecs = monspecs[current_par.montype];
+ fb_info.monspecs.dpms = current_par.dpms;
+ }
+
+ /*
+ * Try to select a suitable default mode
+ */
+ for (i = 0; i < sizeof(modedb) / sizeof(*modedb); i++) {
+ unsigned long hs;
+
+ hs = modedb[i].refresh *
+ (modedb[i].yres + modedb[i].upper_margin +
+ modedb[i].lower_margin + modedb[i].vsync_len);
+ if (modedb[i].xres == DEFAULT_XRES &&
+ modedb[i].yres == DEFAULT_YRES &&
+ modedb[i].refresh >= fb_info.monspecs.vfmin &&
+ modedb[i].refresh <= fb_info.monspecs.vfmax &&
+ hs >= fb_info.monspecs.hfmin &&
+ hs <= fb_info.monspecs.hfmax) {
+ acornfb_default_mode = modedb[i];
+ break;
+ }
+ }
current_par.currcon = -1;
current_par.screen_base = SCREEN2_BASE;
@@ -1839,7 +1922,7 @@
size = PAGE_ALIGN(size);
-#ifdef CONFIG_ARCH_RPC
+#if defined(HAS_VIDC20)
if (!current_par.using_vram) {
/*
* RiscPC needs to allocate the DRAM memory
@@ -1847,17 +1930,30 @@
* VRAM. Archimedes/A5000 machines use a
* fixed address for their framebuffers.
*/
- current_par.screen_base = (unsigned long)kmalloc(size, GFP_KERNEL);
+ int order = 0;
+ unsigned long page, top;
+ while (size > (PAGE_SIZE * (1 << order)))
+ order++;
+ current_par.screen_base = __get_free_pages(GFP_KERNEL, order);
if (current_par.screen_base == 0) {
printk(KERN_ERR "acornfb: unable to allocate screen "
"memory\n");
return;
}
+ top = current_par.screen_base + (PAGE_SIZE * (1 << order));
+ /* Mark the framebuffer pages as reserved so mmap will work. */
+ for (page = current_par.screen_base;
+ page < PAGE_ALIGN(current_par.screen_base + size);
+ page += PAGE_SIZE)
+ mem_map[MAP_NR(page)].flags |= (1 << PG_reserved);
+ /* Hand back any excess pages that we allocated. */
+ for (page = current_par.screen_base + size; page < top; page += PAGE_SIZE)
+ free_page(page);
current_par.screen_base_p =
virt_to_phys(current_par.screen_base);
}
#endif
-#if defined(CONFIG_ARCH_A5K) || defined(CONFIG_ARCH_ARC)
+#if defined(HAS_VIDC)
#define MAX_SIZE 480*1024
/*
* Limit maximum screen size.
@@ -1873,22 +1969,20 @@
current_par.screen_size = size;
current_par.palette_size = VIDC_PALETTE_SIZE;
- current_par.allow_modeset = 1;
/*
* Lookup the timing for this resolution. If we can't
* find it, then we can't restore it if we change
* the resolution, so we disable this feature.
*/
- if (acornfb_lookup_timing(&init_var))
- current_par.allow_modeset = 0;
-
- /*
- * Again, if this does not succeed, then we disallow
- * changes to the resolution parameters.
- */
- if (acornfb_set_var(&init_var, -1, &fb_info))
- current_par.allow_modeset = 0;
+ rc = fb_find_mode(&init_var, &fb_info, NULL, modedb,
+ sizeof(modedb) / sizeof(*modedb),
+ &acornfb_default_mode, DEFAULT_BPP);
+
+ if (!rc && fb_find_mode(&init_var, &fb_info, NULL, NULL, 0,
+ &acornfb_default_mode, DEFAULT_BPP)) {
+ printk("Acornfb: no valid mode found\n");
+ }
h_sync = 1953125000 / init_var.pixclock;
h_sync = h_sync * 512 / (init_var.xres + init_var.left_margin +
@@ -1901,6 +1995,15 @@
current_par.using_vram ? 'V' : 'D',
VIDC_NAME, init_var.xres, init_var.yres,
h_sync / 1000, h_sync % 1000, v_sync);
+
+ printk("Acornfb: Monitor: %d.%03d-%d.%03dkHz, %d-%dHz%s\n",
+ fb_info.monspecs.hfmin / 1000, fb_info.monspecs.hfmin % 1000,
+ fb_info.monspecs.hfmax / 1000, fb_info.monspecs.hfmax % 1000,
+ fb_info.monspecs.vfmin, fb_info.monspecs.vfmax,
+ fb_info.monspecs.dpms ? ", DPMS" : "");
+
+ if (acornfb_set_var(&init_var, -1, &fb_info))
+ printk(KERN_ERR "Acornfb: unable to set display parameters\n");
register_framebuffer(&fb_info);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)