aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/s3fb.c
diff options
context:
space:
mode:
authorOndrej Zary <linux@rainbow-software.org>2011-04-18 06:14:57 -0400
committerPaul Mundt <lethal@linux-sh.org>2011-04-19 02:50:53 -0400
commit86c0f043a737dadf034a4e6f29aefb074f4a1146 (patch)
tree4cacb1364fd037a0128b91e8f714335d2332851e /drivers/video/s3fb.c
parent6e4b26805a90b6682dd4ea0fd426dcda8ca5164a (diff)
s3fb: add DDC support
Add I2C support for the DDC bus and also default mode initialization by reading monitor EDID to the s3fb driver. Tested on Trio64V+ (2 cards), Trio64V2/DX, Virge (3 cards), Virge/DX (3 cards), Virge/GX2, Trio3D/2X (4 cards), Trio3D. Will probably not work on Trio32 - my 2 cards have DDC support in BIOS that looks different from the other cards but the DDC pins on the VGA connector are not connected. Signed-off-by: Ondrej Zary <linux@rainbow-software.org> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/video/s3fb.c')
-rw-r--r--drivers/video/s3fb.c206
1 files changed, 201 insertions, 5 deletions
diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c
index c4482f2e5799..9a345209535b 100644
--- a/drivers/video/s3fb.c
+++ b/drivers/video/s3fb.c
@@ -25,6 +25,9 @@
25#include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */ 25#include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */
26#include <video/vga.h> 26#include <video/vga.h>
27 27
28#include <linux/i2c.h>
29#include <linux/i2c-algo-bit.h>
30
28#ifdef CONFIG_MTRR 31#ifdef CONFIG_MTRR
29#include <asm/mtrr.h> 32#include <asm/mtrr.h>
30#endif 33#endif
@@ -36,6 +39,12 @@ struct s3fb_info {
36 struct mutex open_lock; 39 struct mutex open_lock;
37 unsigned int ref_count; 40 unsigned int ref_count;
38 u32 pseudo_palette[16]; 41 u32 pseudo_palette[16];
42#ifdef CONFIG_FB_S3_DDC
43 u8 __iomem *mmio;
44 bool ddc_registered;
45 struct i2c_adapter ddc_adapter;
46 struct i2c_algo_bit_data ddc_algo;
47#endif
39}; 48};
40 49
41 50
@@ -105,6 +114,9 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64",
105#define CHIP_UNDECIDED_FLAG 0x80 114#define CHIP_UNDECIDED_FLAG 0x80
106#define CHIP_MASK 0xFF 115#define CHIP_MASK 0xFF
107 116
117#define MMIO_OFFSET 0x1000000
118#define MMIO_SIZE 0x10000
119
108/* CRT timing register sets */ 120/* CRT timing register sets */
109 121
110static const struct vga_regset s3_h_total_regs[] = {{0x00, 0, 7}, {0x5D, 0, 0}, VGA_REGSET_END}; 122static const struct vga_regset s3_h_total_regs[] = {{0x00, 0, 7}, {0x5D, 0, 0}, VGA_REGSET_END};
@@ -140,7 +152,7 @@ static const struct svga_timing_regs s3_timing_regs = {
140/* Module parameters */ 152/* Module parameters */
141 153
142 154
143static char *mode_option __devinitdata = "640x480-8@60"; 155static char *mode_option __devinitdata;
144 156
145#ifdef CONFIG_MTRR 157#ifdef CONFIG_MTRR
146static int mtrr __devinitdata = 1; 158static int mtrr __devinitdata = 1;
@@ -169,6 +181,119 @@ MODULE_PARM_DESC(fasttext, "Enable S3 fast text mode (1=enable, 0=disable, defau
169 181
170/* ------------------------------------------------------------------------- */ 182/* ------------------------------------------------------------------------- */
171 183
184#ifdef CONFIG_FB_S3_DDC
185
186#define DDC_REG 0xaa /* Trio 3D/1X/2X */
187#define DDC_MMIO_REG 0xff20 /* all other chips */
188#define DDC_SCL_OUT (1 << 0)
189#define DDC_SDA_OUT (1 << 1)
190#define DDC_SCL_IN (1 << 2)
191#define DDC_SDA_IN (1 << 3)
192#define DDC_DRIVE_EN (1 << 4)
193
194static bool s3fb_ddc_needs_mmio(int chip)
195{
196 return !(chip == CHIP_360_TRIO3D_1X ||
197 chip == CHIP_362_TRIO3D_2X ||
198 chip == CHIP_368_TRIO3D_2X);
199}
200
201static u8 s3fb_ddc_read(struct s3fb_info *par)
202{
203 if (s3fb_ddc_needs_mmio(par->chip))
204 return readb(par->mmio + DDC_MMIO_REG);
205 else
206 return vga_rcrt(par->state.vgabase, DDC_REG);
207}
208
209static void s3fb_ddc_write(struct s3fb_info *par, u8 val)
210{
211 if (s3fb_ddc_needs_mmio(par->chip))
212 writeb(val, par->mmio + DDC_MMIO_REG);
213 else
214 vga_wcrt(par->state.vgabase, DDC_REG, val);
215}
216
217static void s3fb_ddc_setscl(void *data, int val)
218{
219 struct s3fb_info *par = data;
220 unsigned char reg;
221
222 reg = s3fb_ddc_read(par) | DDC_DRIVE_EN;
223 if (val)
224 reg |= DDC_SCL_OUT;
225 else
226 reg &= ~DDC_SCL_OUT;
227 s3fb_ddc_write(par, reg);
228}
229
230static void s3fb_ddc_setsda(void *data, int val)
231{
232 struct s3fb_info *par = data;
233 unsigned char reg;
234
235 reg = s3fb_ddc_read(par) | DDC_DRIVE_EN;
236 if (val)
237 reg |= DDC_SDA_OUT;
238 else
239 reg &= ~DDC_SDA_OUT;
240 s3fb_ddc_write(par, reg);
241}
242
243static int s3fb_ddc_getscl(void *data)
244{
245 struct s3fb_info *par = data;
246
247 return !!(s3fb_ddc_read(par) & DDC_SCL_IN);
248}
249
250static int s3fb_ddc_getsda(void *data)
251{
252 struct s3fb_info *par = data;
253
254 return !!(s3fb_ddc_read(par) & DDC_SDA_IN);
255}
256
257static int __devinit s3fb_setup_ddc_bus(struct fb_info *info)
258{
259 struct s3fb_info *par = info->par;
260
261 strlcpy(par->ddc_adapter.name, info->fix.id,
262 sizeof(par->ddc_adapter.name));
263 par->ddc_adapter.owner = THIS_MODULE;
264 par->ddc_adapter.class = I2C_CLASS_DDC;
265 par->ddc_adapter.algo_data = &par->ddc_algo;
266 par->ddc_adapter.dev.parent = info->device;
267 par->ddc_algo.setsda = s3fb_ddc_setsda;
268 par->ddc_algo.setscl = s3fb_ddc_setscl;
269 par->ddc_algo.getsda = s3fb_ddc_getsda;
270 par->ddc_algo.getscl = s3fb_ddc_getscl;
271 par->ddc_algo.udelay = 10;
272 par->ddc_algo.timeout = 20;
273 par->ddc_algo.data = par;
274
275 i2c_set_adapdata(&par->ddc_adapter, par);
276
277 /*
278 * some Virge cards have external MUX to switch chip I2C bus between
279 * DDC and extension pins - switch it do DDC
280 */
281/* vga_wseq(par->state.vgabase, 0x08, 0x06); - not needed, already unlocked */
282 if (par->chip == CHIP_357_VIRGE_GX2 ||
283 par->chip == CHIP_359_VIRGE_GX2P)
284 svga_wseq_mask(par->state.vgabase, 0x0d, 0x01, 0x03);
285 else
286 svga_wseq_mask(par->state.vgabase, 0x0d, 0x00, 0x03);
287 /* some Virge need this or the DDC is ignored */
288 svga_wcrt_mask(par->state.vgabase, 0x5c, 0x03, 0x03);
289
290 return i2c_bit_add_bus(&par->ddc_adapter);
291}
292#endif /* CONFIG_FB_S3_DDC */
293
294
295/* ------------------------------------------------------------------------- */
296
172/* Set font in S3 fast text mode */ 297/* Set font in S3 fast text mode */
173 298
174static void s3fb_settile_fast(struct fb_info *info, struct fb_tilemap *map) 299static void s3fb_settile_fast(struct fb_info *info, struct fb_tilemap *map)
@@ -994,6 +1119,7 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
994 struct s3fb_info *par; 1119 struct s3fb_info *par;
995 int rc; 1120 int rc;
996 u8 regval, cr38, cr39; 1121 u8 regval, cr38, cr39;
1122 bool found = false;
997 1123
998 /* Ignore secondary VGA device because there is no VGA arbitration */ 1124 /* Ignore secondary VGA device because there is no VGA arbitration */
999 if (! svga_primary_device(dev)) { 1125 if (! svga_primary_device(dev)) {
@@ -1110,12 +1236,69 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
1110 info->fix.ypanstep = 0; 1236 info->fix.ypanstep = 0;
1111 info->fix.accel = FB_ACCEL_NONE; 1237 info->fix.accel = FB_ACCEL_NONE;
1112 info->pseudo_palette = (void*) (par->pseudo_palette); 1238 info->pseudo_palette = (void*) (par->pseudo_palette);
1239 info->var.bits_per_pixel = 8;
1240
1241#ifdef CONFIG_FB_S3_DDC
1242 /* Enable MMIO if needed */
1243 if (s3fb_ddc_needs_mmio(par->chip)) {
1244 par->mmio = ioremap(info->fix.smem_start + MMIO_OFFSET, MMIO_SIZE);
1245 if (par->mmio)
1246 svga_wcrt_mask(par->state.vgabase, 0x53, 0x08, 0x08); /* enable MMIO */
1247 else
1248 dev_err(info->device, "unable to map MMIO at 0x%lx, disabling DDC",
1249 info->fix.smem_start + MMIO_OFFSET);
1250 }
1251 if (!s3fb_ddc_needs_mmio(par->chip) || par->mmio)
1252 if (s3fb_setup_ddc_bus(info) == 0) {
1253 u8 *edid = fb_ddc_read(&par->ddc_adapter);
1254 par->ddc_registered = true;
1255 if (edid) {
1256 fb_edid_to_monspecs(edid, &info->monspecs);
1257 kfree(edid);
1258 if (!info->monspecs.modedb)
1259 dev_err(info->device, "error getting mode database\n");
1260 else {
1261 const struct fb_videomode *m;
1262
1263 fb_videomode_to_modelist(info->monspecs.modedb,
1264 info->monspecs.modedb_len,
1265 &info->modelist);
1266 m = fb_find_best_display(&info->monspecs, &info->modelist);
1267 if (m) {
1268 fb_videomode_to_var(&info->var, m);
1269 /* fill all other info->var's fields */
1270 if (s3fb_check_var(&info->var, info) == 0)
1271 found = true;
1272 }
1273 }
1274 }
1275 }
1276#endif
1277 if (!mode_option && !found)
1278 mode_option = "640x480-8@60";
1113 1279
1114 /* Prepare startup mode */ 1280 /* Prepare startup mode */
1115 rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8); 1281 if (mode_option) {
1116 if (! ((rc == 1) || (rc == 2))) { 1282 rc = fb_find_mode(&info->var, info, mode_option,
1117 rc = -EINVAL; 1283 info->monspecs.modedb, info->monspecs.modedb_len,
1118 dev_err(info->device, "mode %s not found\n", mode_option); 1284 NULL, info->var.bits_per_pixel);
1285 if (!rc || rc == 4) {
1286 rc = -EINVAL;
1287 dev_err(info->device, "mode %s not found\n", mode_option);
1288 fb_destroy_modedb(info->monspecs.modedb);
1289 info->monspecs.modedb = NULL;
1290 goto err_find_mode;
1291 }
1292 }
1293
1294 fb_destroy_modedb(info->monspecs.modedb);
1295 info->monspecs.modedb = NULL;
1296
1297 /* maximize virtual vertical size for fast scrolling */
1298 info->var.yres_virtual = info->fix.smem_len * 8 /
1299 (info->var.bits_per_pixel * info->var.xres_virtual);
1300 if (info->var.yres_virtual < info->var.yres) {
1301 dev_err(info->device, "virtual vertical size smaller than real\n");
1119 goto err_find_mode; 1302 goto err_find_mode;
1120 } 1303 }
1121 1304
@@ -1164,6 +1347,12 @@ err_reg_fb:
1164 fb_dealloc_cmap(&info->cmap); 1347 fb_dealloc_cmap(&info->cmap);
1165err_alloc_cmap: 1348err_alloc_cmap:
1166err_find_mode: 1349err_find_mode:
1350#ifdef CONFIG_FB_S3_DDC
1351 if (par->ddc_registered)
1352 i2c_del_adapter(&par->ddc_adapter);
1353 if (par->mmio)
1354 iounmap(par->mmio);
1355#endif
1167 pci_iounmap(dev, info->screen_base); 1356 pci_iounmap(dev, info->screen_base);
1168err_iomap: 1357err_iomap:
1169 pci_release_regions(dev); 1358 pci_release_regions(dev);
@@ -1195,6 +1384,13 @@ static void __devexit s3_pci_remove(struct pci_dev *dev)
1195 unregister_framebuffer(info); 1384 unregister_framebuffer(info);
1196 fb_dealloc_cmap(&info->cmap); 1385 fb_dealloc_cmap(&info->cmap);
1197 1386
1387#ifdef CONFIG_FB_S3_DDC
1388 if (par->ddc_registered)
1389 i2c_del_adapter(&par->ddc_adapter);
1390 if (par->mmio)
1391 iounmap(par->mmio);
1392#endif
1393
1198 pci_iounmap(dev, info->screen_base); 1394 pci_iounmap(dev, info->screen_base);
1199 pci_release_regions(dev); 1395 pci_release_regions(dev);
1200/* pci_disable_device(dev); */ 1396/* pci_disable_device(dev); */