Skip to content

Commit 69c9820

Browse files
soci64hdeller
authored andcommitted
fbdev: s3fb: Implement 1 and 2 BPP modes, improve 4 BPP
With the right setup S3 cards can display 1 and 2 BPP packed pixel modes, even in high resolutions. So this patch makes them available. The 4 BPP packed pixel mode had one pixel column of garbage on the left side due to how the shift register works, this is fixed now. There was a limitation that only 8 pixel wide fonts could be used at 4 BPP. Since the CFB routines were updated to handle reverse pixel ordering correctly that limitation doesn't exists and was removed now. In 4 BPP interleaved planes mode font widths of multiply of 8 are accepted now, not just 8 pixels. The horizontal screen position will not move as much between modes as it used to. That was caused by the various amount of pipeline delay which is compensated now as much as possible. While adjusting the code direct port access of PEL registers was corrected. Should work now on systems where these are memory mapped. I've noticed that when in 1 BPP mode the console is used with Unicode fonts erasing might be done with non-blanks. That's a bug in the VT code and so not part of this patch. Signed-off-by: Zsolt Kajtar <soci@c64.rulez.org> Signed-off-by: Helge Deller <deller@gmx.de>
1 parent 43b30be commit 69c9820

File tree

2 files changed

+105
-36
lines changed

2 files changed

+105
-36
lines changed

drivers/video/fbdev/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,7 @@ config FB_S3
10601060
select FB_TILEBLITTING
10611061
select FB_SVGALIB
10621062
select VGASTATE
1063+
select FB_CFB_REV_PIXELS_IN_BYTE
10631064
select FONT_8x16 if FRAMEBUFFER_CONSOLE
10641065
help
10651066
Driver for graphics boards with S3 Trio / S3 Virge chip.

drivers/video/fbdev/s3fb.c

Lines changed: 104 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,14 @@ struct s3fb_info {
5050
static const struct svga_fb_format s3fb_formats[] = {
5151
{ 0, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
5252
FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP4, FB_VISUAL_PSEUDOCOLOR, 8, 16},
53-
{ 4, {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, 0,
54-
FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 16},
53+
{ 1, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 0, 0}, 2,
54+
FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 32, 64},
55+
{ 2, {0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0}, 2,
56+
FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 16, 32},
5557
{ 4, {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, 1,
5658
FB_TYPE_INTERLEAVED_PLANES, 1, FB_VISUAL_PSEUDOCOLOR, 8, 16},
59+
{ 4, {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, 2,
60+
FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 16},
5761
{ 8, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0,
5862
FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 4, 8},
5963
{16, {10, 5, 0}, {5, 5, 0}, {0, 5, 0}, {0, 0, 0}, 0,
@@ -557,7 +561,7 @@ static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
557561

558562
/* 32bpp mode is not supported on VIRGE VX,
559563
24bpp is not supported on others */
560-
if ((par->chip == CHIP_988_VIRGE_VX) ? (rv == 7) : (rv == 6))
564+
if ((par->chip == CHIP_988_VIRGE_VX) ? (rv == 9) : (rv == 8))
561565
rv = -EINVAL;
562566

563567
if (rv < 0) {
@@ -607,7 +611,7 @@ static int s3fb_set_par(struct fb_info *info)
607611
struct s3fb_info *par = info->par;
608612
u32 value, mode, hmul, offset_value, screen_size, multiplex, dbytes;
609613
u32 bpp = info->var.bits_per_pixel;
610-
u32 htotal, hsstart;
614+
u32 htotal, hsstart, pel_msk;
611615

612616
if (bpp != 0) {
613617
info->fix.ypanstep = 1;
@@ -617,9 +621,11 @@ static int s3fb_set_par(struct fb_info *info)
617621
info->tileops = NULL;
618622

619623
/* in 4bpp supports 8p wide tiles only, any tiles otherwise */
620-
if (bpp == 4) {
624+
if (bpp == 4 && (info->var.nonstd & 1) != 0) {
625+
int i;
621626
bitmap_zero(info->pixmap.blit_x, FB_MAX_BLIT_WIDTH);
622-
set_bit(8 - 1, info->pixmap.blit_x);
627+
for (i = 8; i <= FB_MAX_BLIT_WIDTH; i += 8)
628+
set_bit(i - 1, info->pixmap.blit_x);
623629
} else {
624630
bitmap_fill(info->pixmap.blit_x, FB_MAX_BLIT_WIDTH);
625631
}
@@ -730,7 +736,7 @@ static int s3fb_set_par(struct fb_info *info)
730736
vga_wcrt(par->state.vgabase, 0x50, 0x00);
731737
vga_wcrt(par->state.vgabase, 0x67, 0x50);
732738
msleep(10); /* screen remains blank sometimes without this */
733-
vga_wcrt(par->state.vgabase, 0x63, (mode <= 2) ? 0x90 : 0x09);
739+
vga_wcrt(par->state.vgabase, 0x63, (mode <= 4) ? 0x90 : 0x09);
734740
vga_wcrt(par->state.vgabase, 0x66, 0x90);
735741
}
736742

@@ -763,12 +769,17 @@ static int s3fb_set_par(struct fb_info *info)
763769
svga_wcrt_mask(par->state.vgabase, 0x31, 0x00, 0x40);
764770
multiplex = 0;
765771
hmul = 1;
772+
pel_msk = 0xff;
773+
774+
svga_wcrt_mask(par->state.vgabase, 0x08, 0x00, 0x60);
775+
svga_wcrt_mask(par->state.vgabase, 0x05, 0x00, 0x60);
766776

767777
/* Set mode-specific register values */
768778
switch (mode) {
769779
case 0:
770780
fb_dbg(info, "text mode\n");
771781
svga_set_textmode_vga_regs(par->state.vgabase);
782+
pel_msk = 0x0f;
772783

773784
/* Set additional registers like in 8-bit mode */
774785
svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30);
@@ -783,8 +794,11 @@ static int s3fb_set_par(struct fb_info *info)
783794
}
784795
break;
785796
case 1:
786-
fb_dbg(info, "4 bit pseudocolor\n");
787-
vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x40);
797+
fb_dbg(info, "1 bit pseudocolor\n");
798+
svga_wseq_mask(par->state.vgabase, 0x01, 0x10, 0x14);
799+
svga_wcrt_mask(par->state.vgabase, 0x08, 0x60, 0x60);
800+
svga_wcrt_mask(par->state.vgabase, 0x05, 0x40, 0x60);
801+
pel_msk = 0x01;
788802

789803
/* Set additional registers like in 8-bit mode */
790804
svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30);
@@ -794,7 +808,13 @@ static int s3fb_set_par(struct fb_info *info)
794808
svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30);
795809
break;
796810
case 2:
797-
fb_dbg(info, "4 bit pseudocolor, planar\n");
811+
fb_dbg(info, "2 bit pseudocolor\n");
812+
svga_wseq_mask(par->state.vgabase, 0x01, 0x04, 0x14);
813+
svga_wseq_mask(par->state.vgabase, 0x04, 0x08, 0x08);
814+
vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x20);
815+
svga_wcrt_mask(par->state.vgabase, 0x08, 0x20, 0x60);
816+
svga_wcrt_mask(par->state.vgabase, 0x05, 0x40, 0x60);
817+
pel_msk = 0x03;
798818

799819
/* Set additional registers like in 8-bit mode */
800820
svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30);
@@ -804,8 +824,35 @@ static int s3fb_set_par(struct fb_info *info)
804824
svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30);
805825
break;
806826
case 3:
827+
fb_dbg(info, "4 bit pseudocolor, planar\n");
828+
pel_msk = 0x0f;
829+
830+
/* Set additional registers like in 8-bit mode */
831+
svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30);
832+
svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0);
833+
svga_wcrt_mask(par->state.vgabase, 0x05, 0x40, 0x60);
834+
835+
/* disable enhanced mode */
836+
svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30);
837+
break;
838+
case 4:
839+
fb_dbg(info, "4 bit pseudocolor\n");
840+
vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x40);
841+
svga_wattr(par->state.vgabase, 0x33, 0x01);
842+
svga_wcrt_mask(par->state.vgabase, 0x05, 0x40, 0x60);
843+
pel_msk = 0xf0;
844+
845+
/* Set additional registers like in 8-bit mode */
846+
svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30);
847+
svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0);
848+
849+
/* disable enhanced mode */
850+
svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30);
851+
break;
852+
case 5:
807853
fb_dbg(info, "8 bit pseudocolor\n");
808854
svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30);
855+
svga_wcrt_mask(par->state.vgabase, 0x05, 0x20, 0x60);
809856
if (info->var.pixclock > 20000 ||
810857
par->chip == CHIP_357_VIRGE_GX2 ||
811858
par->chip == CHIP_359_VIRGE_GX2P ||
@@ -819,7 +866,7 @@ static int s3fb_set_par(struct fb_info *info)
819866
multiplex = 1;
820867
}
821868
break;
822-
case 4:
869+
case 6:
823870
fb_dbg(info, "5/5/5 truecolor\n");
824871
if (par->chip == CHIP_988_VIRGE_VX) {
825872
if (info->var.pixclock > 20000)
@@ -847,7 +894,7 @@ static int s3fb_set_par(struct fb_info *info)
847894
hmul = 2;
848895
}
849896
break;
850-
case 5:
897+
case 7:
851898
fb_dbg(info, "5/6/5 truecolor\n");
852899
if (par->chip == CHIP_988_VIRGE_VX) {
853900
if (info->var.pixclock > 20000)
@@ -875,12 +922,12 @@ static int s3fb_set_par(struct fb_info *info)
875922
hmul = 2;
876923
}
877924
break;
878-
case 6:
925+
case 8:
879926
/* VIRGE VX case */
880927
fb_dbg(info, "8/8/8 truecolor\n");
881928
svga_wcrt_mask(par->state.vgabase, 0x67, 0xD0, 0xF0);
882929
break;
883-
case 7:
930+
case 9:
884931
fb_dbg(info, "8/8/8/8 truecolor\n");
885932
svga_wcrt_mask(par->state.vgabase, 0x50, 0x30, 0x30);
886933
svga_wcrt_mask(par->state.vgabase, 0x67, 0xD0, 0xF0);
@@ -889,6 +936,7 @@ static int s3fb_set_par(struct fb_info *info)
889936
fb_err(info, "unsupported mode - bug\n");
890937
return -EINVAL;
891938
}
939+
vga_w(par->state.vgabase, VGA_PEL_MSK, pel_msk);
892940

893941
if (par->chip != CHIP_988_VIRGE_VX) {
894942
svga_wseq_mask(par->state.vgabase, 0x15, multiplex ? 0x10 : 0x00, 0x10);
@@ -927,33 +975,26 @@ static int s3fb_set_par(struct fb_info *info)
927975
static int s3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
928976
u_int transp, struct fb_info *fb)
929977
{
978+
struct s3fb_info *par = fb->par;
979+
int cols;
980+
930981
switch (fb->var.bits_per_pixel) {
931982
case 0:
983+
case 1:
984+
case 2:
932985
case 4:
933-
if (regno >= 16)
934-
return -EINVAL;
935-
936-
if ((fb->var.bits_per_pixel == 4) &&
937-
(fb->var.nonstd == 0)) {
938-
outb(0xF0, VGA_PEL_MSK);
939-
outb(regno*16, VGA_PEL_IW);
940-
} else {
941-
outb(0x0F, VGA_PEL_MSK);
942-
outb(regno, VGA_PEL_IW);
943-
}
944-
outb(red >> 10, VGA_PEL_D);
945-
outb(green >> 10, VGA_PEL_D);
946-
outb(blue >> 10, VGA_PEL_D);
947-
break;
948986
case 8:
949-
if (regno >= 256)
987+
cols = 1 << (fb->var.bits_per_pixel ? fb->var.bits_per_pixel : 4);
988+
if (regno >= cols)
950989
return -EINVAL;
951990

952-
outb(0xFF, VGA_PEL_MSK);
953-
outb(regno, VGA_PEL_IW);
954-
outb(red >> 10, VGA_PEL_D);
955-
outb(green >> 10, VGA_PEL_D);
956-
outb(blue >> 10, VGA_PEL_D);
991+
if ((fb->var.bits_per_pixel == 4) && ((fb->var.nonstd & 1) == 0))
992+
regno <<= 4;
993+
994+
vga_w(par->state.vgabase, VGA_PEL_IW, regno);
995+
vga_w(par->state.vgabase, VGA_PEL_D, red >> 10);
996+
vga_w(par->state.vgabase, VGA_PEL_D, green >> 10);
997+
vga_w(par->state.vgabase, VGA_PEL_D, blue >> 10);
957998
break;
958999
case 16:
9591000
if (regno >= 16)
@@ -1041,6 +1082,33 @@ static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
10411082
return 0;
10421083
}
10431084

1085+
/* Get capabilities of accelerator based on the mode */
1086+
1087+
static void s3fb_get_caps(struct fb_info *info, struct fb_blit_caps *caps,
1088+
struct fb_var_screeninfo *var)
1089+
{
1090+
int i;
1091+
1092+
if (var->bits_per_pixel == 0) {
1093+
/* can only support 256 8x16 bitmap */
1094+
bitmap_zero(caps->x, FB_MAX_BLIT_WIDTH);
1095+
set_bit(8 - 1, caps->x);
1096+
bitmap_zero(caps->y, FB_MAX_BLIT_HEIGHT);
1097+
set_bit(16 - 1, caps->y);
1098+
caps->len = 256;
1099+
} else {
1100+
if (var->bits_per_pixel == 4 && (var->nonstd & 1) != 0) {
1101+
bitmap_zero(caps->x, FB_MAX_BLIT_WIDTH);
1102+
for (i = 8; i <= FB_MAX_BLIT_WIDTH; i += 8)
1103+
set_bit(i - 1, caps->x);
1104+
} else {
1105+
bitmap_fill(caps->x, FB_MAX_BLIT_WIDTH);
1106+
}
1107+
bitmap_fill(caps->y, FB_MAX_BLIT_HEIGHT);
1108+
caps->len = ~(u32)0;
1109+
}
1110+
}
1111+
10441112
/* ------------------------------------------------------------------------- */
10451113

10461114
/* Frame buffer operations */
@@ -1059,7 +1127,7 @@ static const struct fb_ops s3fb_ops = {
10591127
.fb_copyarea = cfb_copyarea,
10601128
.fb_imageblit = s3fb_imageblit,
10611129
__FB_DEFAULT_IOMEM_OPS_MMAP,
1062-
.fb_get_caps = svga_get_caps,
1130+
.fb_get_caps = s3fb_get_caps,
10631131
};
10641132

10651133
/* ------------------------------------------------------------------------- */

0 commit comments

Comments
 (0)