aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2005-05-01 11:59:22 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-05-01 11:59:22 -0400
commit7149437669f79b497830e643a2b13d26a017b038 (patch)
treef5df8234c2e3cca1a335cf64b9f387c98c123fcf
parent5b052d8bb3ad9108489e7475868e14372774ca08 (diff)
[PATCH] fbdev: Batch cmap changes at driver level
This patch adds to the fbdev interface a set_cmap callback that allow the driver to "batch" palette changes. This is useful for drivers like radeonfb which might require lenghtly workarounds on palette accesses, thus allowing to factor out those workarounds efficiently. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/video/aty/radeon_base.c118
-rw-r--r--drivers/video/fbcmap.c32
-rw-r--r--include/linux/fb.h3
3 files changed, 127 insertions, 26 deletions
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index e8eb124754b1..ee25b9e8db60 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -1057,13 +1057,14 @@ static int radeonfb_blank (int blank, struct fb_info *info)
1057 return radeon_screen_blank(rinfo, blank, 0); 1057 return radeon_screen_blank(rinfo, blank, 0);
1058} 1058}
1059 1059
1060static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green, 1060static int radeon_setcolreg (unsigned regno, unsigned red, unsigned green,
1061 unsigned blue, unsigned transp, struct fb_info *info) 1061 unsigned blue, unsigned transp,
1062 struct radeonfb_info *rinfo)
1062{ 1063{
1063 struct radeonfb_info *rinfo = info->par;
1064 u32 pindex; 1064 u32 pindex;
1065 unsigned int i; 1065 unsigned int i;
1066 1066
1067
1067 if (regno > 255) 1068 if (regno > 255)
1068 return 1; 1069 return 1;
1069 1070
@@ -1078,20 +1079,7 @@ static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green,
1078 pindex = regno; 1079 pindex = regno;
1079 1080
1080 if (!rinfo->asleep) { 1081 if (!rinfo->asleep) {
1081 u32 dac_cntl2, vclk_cntl = 0;
1082
1083 radeon_fifo_wait(9); 1082 radeon_fifo_wait(9);
1084 if (rinfo->is_mobility) {
1085 vclk_cntl = INPLL(VCLK_ECP_CNTL);
1086 OUTPLL(VCLK_ECP_CNTL, vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb);
1087 }
1088
1089 /* Make sure we are on first palette */
1090 if (rinfo->has_CRTC2) {
1091 dac_cntl2 = INREG(DAC_CNTL2);
1092 dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL;
1093 OUTREG(DAC_CNTL2, dac_cntl2);
1094 }
1095 1083
1096 if (rinfo->bpp == 16) { 1084 if (rinfo->bpp == 16) {
1097 pindex = regno * 8; 1085 pindex = regno * 8;
@@ -1101,24 +1089,27 @@ static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green,
1101 if (rinfo->depth == 15 && regno > 31) 1089 if (rinfo->depth == 15 && regno > 31)
1102 return 1; 1090 return 1;
1103 1091
1104 /* For 565, the green component is mixed one order below */ 1092 /* For 565, the green component is mixed one order
1093 * below
1094 */
1105 if (rinfo->depth == 16) { 1095 if (rinfo->depth == 16) {
1106 OUTREG(PALETTE_INDEX, pindex>>1); 1096 OUTREG(PALETTE_INDEX, pindex>>1);
1107 OUTREG(PALETTE_DATA, (rinfo->palette[regno>>1].red << 16) | 1097 OUTREG(PALETTE_DATA,
1108 (green << 8) | (rinfo->palette[regno>>1].blue)); 1098 (rinfo->palette[regno>>1].red << 16) |
1099 (green << 8) |
1100 (rinfo->palette[regno>>1].blue));
1109 green = rinfo->palette[regno<<1].green; 1101 green = rinfo->palette[regno<<1].green;
1110 } 1102 }
1111 } 1103 }
1112 1104
1113 if (rinfo->depth != 16 || regno < 32) { 1105 if (rinfo->depth != 16 || regno < 32) {
1114 OUTREG(PALETTE_INDEX, pindex); 1106 OUTREG(PALETTE_INDEX, pindex);
1115 OUTREG(PALETTE_DATA, (red << 16) | (green << 8) | blue); 1107 OUTREG(PALETTE_DATA, (red << 16) |
1108 (green << 8) | blue);
1116 } 1109 }
1117 if (rinfo->is_mobility)
1118 OUTPLL(VCLK_ECP_CNTL, vclk_cntl);
1119 } 1110 }
1120 if (regno < 16) { 1111 if (regno < 16) {
1121 u32 *pal = info->pseudo_palette; 1112 u32 *pal = rinfo->info->pseudo_palette;
1122 switch (rinfo->depth) { 1113 switch (rinfo->depth) {
1123 case 15: 1114 case 15:
1124 pal[regno] = (regno << 10) | (regno << 5) | regno; 1115 pal[regno] = (regno << 10) | (regno << 5) | regno;
@@ -1138,6 +1129,84 @@ static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green,
1138 return 0; 1129 return 0;
1139} 1130}
1140 1131
1132static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green,
1133 unsigned blue, unsigned transp,
1134 struct fb_info *info)
1135{
1136 struct radeonfb_info *rinfo = info->par;
1137 u32 dac_cntl2, vclk_cntl = 0;
1138 int rc;
1139
1140 if (!rinfo->asleep) {
1141 if (rinfo->is_mobility) {
1142 vclk_cntl = INPLL(VCLK_ECP_CNTL);
1143 OUTPLL(VCLK_ECP_CNTL,
1144 vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb);
1145 }
1146
1147 /* Make sure we are on first palette */
1148 if (rinfo->has_CRTC2) {
1149 dac_cntl2 = INREG(DAC_CNTL2);
1150 dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL;
1151 OUTREG(DAC_CNTL2, dac_cntl2);
1152 }
1153 }
1154
1155 rc = radeon_setcolreg (regno, red, green, blue, transp, rinfo);
1156
1157 if (!rinfo->asleep && rinfo->is_mobility)
1158 OUTPLL(VCLK_ECP_CNTL, vclk_cntl);
1159
1160 return rc;
1161}
1162
1163static int radeonfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
1164{
1165 struct radeonfb_info *rinfo = info->par;
1166 u16 *red, *green, *blue, *transp;
1167 u32 dac_cntl2, vclk_cntl = 0;
1168 int i, start, rc = 0;
1169
1170 if (!rinfo->asleep) {
1171 if (rinfo->is_mobility) {
1172 vclk_cntl = INPLL(VCLK_ECP_CNTL);
1173 OUTPLL(VCLK_ECP_CNTL,
1174 vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb);
1175 }
1176
1177 /* Make sure we are on first palette */
1178 if (rinfo->has_CRTC2) {
1179 dac_cntl2 = INREG(DAC_CNTL2);
1180 dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL;
1181 OUTREG(DAC_CNTL2, dac_cntl2);
1182 }
1183 }
1184
1185 red = cmap->red;
1186 green = cmap->green;
1187 blue = cmap->blue;
1188 transp = cmap->transp;
1189 start = cmap->start;
1190
1191 for (i = 0; i < cmap->len; i++) {
1192 u_int hred, hgreen, hblue, htransp = 0xffff;
1193
1194 hred = *red++;
1195 hgreen = *green++;
1196 hblue = *blue++;
1197 if (transp)
1198 htransp = *transp++;
1199 rc = radeon_setcolreg (start++, hred, hgreen, hblue, htransp,
1200 rinfo);
1201 if (rc)
1202 break;
1203 }
1204
1205 if (!rinfo->asleep && rinfo->is_mobility)
1206 OUTPLL(VCLK_ECP_CNTL, vclk_cntl);
1207
1208 return rc;
1209}
1141 1210
1142static void radeon_save_state (struct radeonfb_info *rinfo, 1211static void radeon_save_state (struct radeonfb_info *rinfo,
1143 struct radeon_regs *save) 1212 struct radeon_regs *save)
@@ -1796,6 +1865,7 @@ static struct fb_ops radeonfb_ops = {
1796 .fb_check_var = radeonfb_check_var, 1865 .fb_check_var = radeonfb_check_var,
1797 .fb_set_par = radeonfb_set_par, 1866 .fb_set_par = radeonfb_set_par,
1798 .fb_setcolreg = radeonfb_setcolreg, 1867 .fb_setcolreg = radeonfb_setcolreg,
1868 .fb_setcmap = radeonfb_setcmap,
1799 .fb_pan_display = radeonfb_pan_display, 1869 .fb_pan_display = radeonfb_pan_display,
1800 .fb_blank = radeonfb_blank, 1870 .fb_blank = radeonfb_blank,
1801 .fb_ioctl = radeonfb_ioctl, 1871 .fb_ioctl = radeonfb_ioctl,
diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c
index c51f8fb5c1de..4e5ce8f7d65e 100644
--- a/drivers/video/fbcmap.c
+++ b/drivers/video/fbcmap.c
@@ -222,8 +222,11 @@ int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *info)
222 transp = cmap->transp; 222 transp = cmap->transp;
223 start = cmap->start; 223 start = cmap->start;
224 224
225 if (start < 0 || !info->fbops->fb_setcolreg) 225 if (start < 0 || (!info->fbops->fb_setcolreg &&
226 !info->fbops->fb_setcmap))
226 return -EINVAL; 227 return -EINVAL;
228 if (info->fbops->fb_setcmap)
229 return info->fbops->fb_setcmap(cmap, info);
227 for (i = 0; i < cmap->len; i++) { 230 for (i = 0; i < cmap->len; i++) {
228 hred = *red++; 231 hred = *red++;
229 hgreen = *green++; 232 hgreen = *green++;
@@ -250,8 +253,33 @@ int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info)
250 transp = cmap->transp; 253 transp = cmap->transp;
251 start = cmap->start; 254 start = cmap->start;
252 255
253 if (start < 0 || !info->fbops->fb_setcolreg) 256 if (start < 0 || (!info->fbops->fb_setcolreg &&
257 !info->fbops->fb_setcmap))
254 return -EINVAL; 258 return -EINVAL;
259
260 /* If we can batch, do it */
261 if (info->fbops->fb_setcmap && cmap->len > 1) {
262 struct fb_cmap umap;
263 int size = cmap->len * sizeof(u16);
264 int rc;
265
266 memset(&umap, 0, sizeof(struct fb_cmap));
267 rc = fb_alloc_cmap(&umap, cmap->len, transp != NULL);
268 if (rc)
269 return rc;
270 if (copy_from_user(umap.red, red, size) ||
271 copy_from_user(umap.green, green, size) ||
272 copy_from_user(umap.blue, blue, size) ||
273 (transp && copy_from_user(umap.transp, transp, size))) {
274 rc = -EFAULT;
275 }
276 umap.start = start;
277 if (rc == 0)
278 rc = info->fbops->fb_setcmap(&umap, info);
279 fb_dealloc_cmap(&umap);
280 return rc;
281 }
282
255 for (i = 0; i < cmap->len; i++, red++, blue++, green++) { 283 for (i = 0; i < cmap->len; i++, red++, blue++, green++) {
256 if (get_user(hred, red) || 284 if (get_user(hred, red) ||
257 get_user(hgreen, green) || 285 get_user(hgreen, green) ||
diff --git a/include/linux/fb.h b/include/linux/fb.h
index b45d3e2d711a..b468bf496547 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -563,6 +563,9 @@ struct fb_ops {
563 int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green, 563 int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
564 unsigned blue, unsigned transp, struct fb_info *info); 564 unsigned blue, unsigned transp, struct fb_info *info);
565 565
566 /* set color registers in batch */
567 int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);
568
566 /* blank display */ 569 /* blank display */
567 int (*fb_blank)(int blank, struct fb_info *info); 570 int (*fb_blank)(int blank, struct fb_info *info);
568 571