From c3635c78e500a52c9fcd55de381a72928d9e054d Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 26 Mar 2010 16:44:01 -0700 Subject: DMAENGINE: generic slave control v2 Convert the device_terminate_all() operation on the DMA engine to a generic device_control() operation which can now optionally support also pausing and resuming DMA on a certain channel. Implemented for the COH 901 318 DMAC as an example. [dan.j.williams@intel.com: update for timberdale] Signed-off-by: Linus Walleij Acked-by: Mark Brown Cc: Maciej Sosnowski Cc: Nicolas Ferre Cc: Pavel Machek Cc: Li Yang Cc: Guennadi Liakhovetski Cc: Paul Mundt Cc: Ralf Baechle Cc: Haavard Skinnemoen Cc: Magnus Damm Cc: Liam Girdwood Cc: Joe Perches Cc: Roland Dreier Signed-off-by: Dan Williams --- drivers/video/mx3fb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/video') diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index 772ba3f45e6f..3aa50bc276eb 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -387,7 +387,8 @@ static void sdc_disable_channel(struct mx3fb_info *mx3_fbi) spin_unlock_irqrestore(&mx3fb->lock, flags); - mx3_fbi->txd->chan->device->device_terminate_all(mx3_fbi->txd->chan); + mx3_fbi->txd->chan->device->device_control(mx3_fbi->txd->chan, + DMA_TERMINATE_ALL); mx3_fbi->txd = NULL; mx3_fbi->cookie = -EINVAL; } -- cgit v1.2.1 From 109771a68bedda77606500dc14455eca92df6769 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 19 May 2009 17:12:58 +0800 Subject: viafb: Fix various resource leaks during module_init() The current code executed from module_init() in viafb does not have proper error checking and [partial] resoure release paths in case an error happens half way through driver initialization. This patch adresses the most obvious of those issues, such as a leftover i2c bus if module_init (and thus module load) fails. [jc: fixed merge conflicts] [jc: also restored -ENOMEM return on ioremap() fail] Cc: Florian Tobias Schandinat Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Signed-off-by: Harald Welte --- drivers/video/via/viafbdev.c | 52 +++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 13 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index ce7783b63f6a..b7018ef69778 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved. * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. * This program is free software; you can redistribute it and/or @@ -1737,6 +1737,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, u32 default_xres, default_yres; struct VideoModeTable *vmode_entry; struct fb_var_screeninfo default_var; + int rc; u32 viafb_par_length; DEBUG_MSG(KERN_INFO "VIAFB PCI Probe!!\n"); @@ -1751,7 +1752,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, &pdev->dev); if (!viafbinfo) { printk(KERN_ERR"Could not allocate memory for viafb_info.\n"); - return -ENODEV; + return -ENOMEM; } viaparinfo = (struct viafb_par *)viafbinfo->par; @@ -1774,7 +1775,9 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, viafb_dual_fb = 0; /* Set up I2C bus stuff */ - viafb_create_i2c_bus(viaparinfo); + rc = viafb_create_i2c_bus(viaparinfo); + if (rc) + goto out_fb_release; viafb_init_chip_info(pdev, ent); viaparinfo->fbmem = pci_resource_start(pdev, 0); @@ -1785,7 +1788,8 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, viaparinfo->memsize); if (!viafbinfo->screen_base) { printk(KERN_INFO "ioremap failed\n"); - return -ENOMEM; + rc = -ENOMEM; + goto out_delete_i2c; } viafbinfo->fix.mmio_start = pci_resource_start(pdev, 1); @@ -1861,8 +1865,8 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, if (!viafbinfo1) { printk(KERN_ERR "allocate the second framebuffer struct error\n"); - framebuffer_release(viafbinfo); - return -ENOMEM; + rc = -ENOMEM; + goto out_delete_i2c; } viaparinfo1 = viafbinfo1->par; memcpy(viaparinfo1, viaparinfo, viafb_par_length); @@ -1913,21 +1917,26 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, viaparinfo->depth = fb_get_color_depth(&viafbinfo->var, &viafbinfo->fix); default_var.activate = FB_ACTIVATE_NOW; - fb_alloc_cmap(&viafbinfo->cmap, 256, 0); + rc = fb_alloc_cmap(&viafbinfo->cmap, 256, 0); + if (rc) + goto out_fb1_release; if (viafb_dual_fb && (viafb_primary_dev == LCD_Device) && (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)) { - if (register_framebuffer(viafbinfo1) < 0) - return -EINVAL; + rc = register_framebuffer(viafbinfo1); + if (rc) + goto out_dealloc_cmap; } - if (register_framebuffer(viafbinfo) < 0) - return -EINVAL; + rc = register_framebuffer(viafbinfo); + if (rc) + goto out_fb1_unreg_lcd_cle266; if (viafb_dual_fb && ((viafb_primary_dev != LCD_Device) || (viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266))) { - if (register_framebuffer(viafbinfo1) < 0) - return -EINVAL; + rc = register_framebuffer(viafbinfo1); + if (rc) + goto out_fb_unreg; } DEBUG_MSG(KERN_INFO "fb%d: %s frame buffer device %dx%d-%dbpp\n", viafbinfo->node, viafbinfo->fix.id, default_var.xres, @@ -1936,6 +1945,23 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, viafb_init_proc(&viaparinfo->shared->proc_entry); viafb_init_dac(IGA2); return 0; + +out_fb_unreg: + unregister_framebuffer(viafbinfo); +out_fb1_unreg_lcd_cle266: + if (viafb_dual_fb && (viafb_primary_dev == LCD_Device) + && (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)) + unregister_framebuffer(viafbinfo1); +out_dealloc_cmap: + fb_dealloc_cmap(&viafbinfo->cmap); +out_fb1_release: + if (viafbinfo1) + framebuffer_release(viafbinfo1); +out_delete_i2c: + viafb_delete_i2c_buss(viaparinfo); +out_fb_release: + framebuffer_release(viafbinfo); + return rc; } static void __devexit via_pci_remove(struct pci_dev *pdev) -- cgit v1.2.1 From b72a5070c74f5ca9a45a03c2d625daab66d0a820 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 19 May 2009 15:50:58 +0800 Subject: viafb: use proper pci config API This patch alters viafb to use the proper Linux in-kernel API to access PCI configuration space, rather than poking at I/O ports by itself. Cc: Florian Tobias Schandinat Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Signed-off-by: Harald Welte --- drivers/video/via/hw.c | 62 +++++++++++++++++++++++++++----------------- drivers/video/via/hw.h | 4 +-- drivers/video/via/viafbdev.c | 4 +++ 3 files changed, 44 insertions(+), 26 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index f2583b1b527f..c94bcce71eaf 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -2473,24 +2473,37 @@ static void disable_second_display_channel(void) viafb_write_reg_mask(CR6A, VIACR, BIT6, BIT6); } +static u_int16_t via_function3[] = { + CLE266_FUNCTION3, KM400_FUNCTION3, CN400_FUNCTION3, CN700_FUNCTION3, + CX700_FUNCTION3, KM800_FUNCTION3, KM890_FUNCTION3, P4M890_FUNCTION3, + P4M900_FUNCTION3, VX800_FUNCTION3, VX855_FUNCTION3, +}; + +/* Get the BIOS-configured framebuffer size from PCI configuration space + * of function 3 in the respective chipset */ int viafb_get_fb_size_from_pci(void) { - unsigned long configid, deviceid, FBSize = 0; - int VideoMemSize; - int DeviceFound = false; - - for (configid = 0x80000000; configid < 0x80010800; configid += 0x100) { - outl(configid, (unsigned long)0xCF8); - deviceid = (inl((unsigned long)0xCFC) >> 16) & 0xffff; - - switch (deviceid) { - case CLE266: - case KM400: - outl(configid + 0xE0, (unsigned long)0xCF8); - FBSize = inl((unsigned long)0xCFC); - DeviceFound = true; /* Found device id */ - break; + int i; + u_int8_t offset = 0; + u_int32_t FBSize; + u_int32_t VideoMemSize; + + /* search for the "FUNCTION3" device in this chipset */ + for (i = 0; i < ARRAY_SIZE(via_function3); i++) { + struct pci_dev *pdev; + + pdev = pci_get_device(PCI_VENDOR_ID_VIA, via_function3[i], + NULL); + if (!pdev) + continue; + + DEBUG_MSG(KERN_INFO "Device ID = %x\n", pdev->device); + switch (pdev->device) { + case CLE266_FUNCTION3: + case KM400_FUNCTION3: + offset = 0xE0; + break; case CN400_FUNCTION3: case CN700_FUNCTION3: case CX700_FUNCTION3: @@ -2500,21 +2513,22 @@ int viafb_get_fb_size_from_pci(void) case P4M900_FUNCTION3: case VX800_FUNCTION3: case VX855_FUNCTION3: - /*case CN750_FUNCTION3: */ - outl(configid + 0xA0, (unsigned long)0xCF8); - FBSize = inl((unsigned long)0xCFC); - DeviceFound = true; /* Found device id */ - break; - - default: + /*case CN750_FUNCTION3: */ + offset = 0xA0; break; } - if (DeviceFound) + if (!offset) break; + + pci_read_config_dword(pdev, offset, &FBSize); + pci_dev_put(pdev); } - DEBUG_MSG(KERN_INFO "Device ID = %lx\n", deviceid); + if (!offset) { + printk(KERN_ERR "cannot determine framebuffer size\n"); + return -EIO; + } FBSize = FBSize & 0x00007000; DEBUG_MSG(KERN_INFO "FB Size = %x\n", FBSize); diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index 12ef32d334cb..d6b25acd4a99 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h @@ -823,8 +823,8 @@ struct iga2_crtc_timing { }; /* device ID */ -#define CLE266 0x3123 -#define KM400 0x3205 +#define CLE266_FUNCTION3 0x3123 +#define KM400_FUNCTION3 0x3205 #define CN400_FUNCTION2 0x2259 #define CN400_FUNCTION3 0x3259 /* support VT3314 chipset */ diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index b7018ef69778..8af405bf077b 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -1782,6 +1782,10 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, viafb_init_chip_info(pdev, ent); viaparinfo->fbmem = pci_resource_start(pdev, 0); viaparinfo->memsize = viafb_get_fb_size_from_pci(); + if (viaparinfo->memsize < 0) { + rc = viaparinfo->memsize; + goto out_delete_i2c; + } viaparinfo->fbmem_free = viaparinfo->memsize; viaparinfo->fbmem_used = 0; viafbinfo->screen_base = ioremap_nocache(viaparinfo->fbmem, -- cgit v1.2.1 From 1b1f8cd299d3c5a90c2ec1c24c271a0b536e5891 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Fri, 26 Mar 2010 15:45:39 -0600 Subject: viafb: Unmap the frame buffer on initialization error This was part of Harald's "make viafb a first-class citizen using pci_driver" patch, but somehow got dropped when that patch went into mainline. Cc: Florian Tobias Schandinat Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Signed-off-by: Jonathan Corbet --- drivers/video/via/viafbdev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/video') diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 8af405bf077b..8955ab4caac8 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -1870,7 +1870,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, printk(KERN_ERR "allocate the second framebuffer struct error\n"); rc = -ENOMEM; - goto out_delete_i2c; + goto out_unmap_screen; } viaparinfo1 = viafbinfo1->par; memcpy(viaparinfo1, viaparinfo, viafb_par_length); @@ -1961,6 +1961,8 @@ out_dealloc_cmap: out_fb1_release: if (viafbinfo1) framebuffer_release(viafbinfo1); +out_unmap_screen: + iounmap(viafbinfo->screen_base); out_delete_i2c: viafb_delete_i2c_buss(viaparinfo); out_fb_release: -- cgit v1.2.1 From 9ca43cf41d014e12f4b25d4538f362d7513448dd Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Sat, 27 Mar 2010 12:14:52 -0600 Subject: viafb: Retain GEMODE reserved bits Commit c3e25673843153ea75fda79a47cf12f10a25ca37 (viafb: 2D engine rewrite) changed the setting of the GEMODE register so that the reserved bits are no longer preserved. Fix that; at the same time, move this code to its own function and restore the use of symbolic constants. Cc: Florian Tobias Schandinat Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Signed-off-by: Jonathan Corbet --- drivers/video/via/accel.c | 49 +++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 16 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c index d5077dfa9e00..a52147cf7f09 100644 --- a/drivers/video/via/accel.c +++ b/drivers/video/via/accel.c @@ -165,12 +165,42 @@ static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height, return 0; } +/* + * Figure out an appropriate bytes-per-pixel setting. + */ +static int viafb_set_bpp(void __iomem *engine, u8 bpp) +{ + u32 gemode; + + /* Preserve the reserved bits */ + /* Lowest 2 bits to zero gives us no rotation */ + gemode = readl(engine + VIA_REG_GEMODE) & 0xfffffcfc; + switch (bpp) { + case 8: + gemode |= VIA_GEM_8bpp; + break; + case 16: + gemode |= VIA_GEM_16bpp; + break; + case 32: + gemode |= VIA_GEM_32bpp; + break; + default: + printk(KERN_WARNING "hw_bitblt_2: Unsupported bpp %d\n", bpp); + return -EINVAL; + } + writel(gemode, engine + VIA_REG_GEMODE); + return 0; +} + + static int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height, u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y, u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y, u32 fg_color, u32 bg_color, u8 fill_rop) { u32 ge_cmd = 0, tmp, i; + int ret; if (!op || op > 3) { printk(KERN_WARNING "hw_bitblt_2: Invalid operation: %d\n", op); @@ -204,22 +234,9 @@ static int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height, } } - switch (dst_bpp) { - case 8: - tmp = 0x00000000; - break; - case 16: - tmp = 0x00000100; - break; - case 32: - tmp = 0x00000300; - break; - default: - printk(KERN_WARNING "hw_bitblt_2: Unsupported bpp %d\n", - dst_bpp); - return -EINVAL; - } - writel(tmp, engine + 0x04); + ret = viafb_set_bpp(engine, dst_bpp); + if (ret) + return ret; if (op == VIA_BITBLT_FILL) tmp = 0; -- cgit v1.2.1 From f1b99aa9dbe908b2839885aa999d6e8512fe1040 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Fri, 9 Apr 2010 14:06:16 -0600 Subject: viafb: Unify duplicated set_bpp() code As suggested by Florian: make both mode-setting paths use the same code. Cc: Florian Tobias Schandinat Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Signed-off-by: Jonathan Corbet --- drivers/video/via/accel.c | 78 ++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 45 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c index a52147cf7f09..7c1d9c41623d 100644 --- a/drivers/video/via/accel.c +++ b/drivers/video/via/accel.c @@ -20,12 +20,42 @@ */ #include "global.h" +/* + * Figure out an appropriate bytes-per-pixel setting. + */ +static int viafb_set_bpp(void __iomem *engine, u8 bpp) +{ + u32 gemode; + + /* Preserve the reserved bits */ + /* Lowest 2 bits to zero gives us no rotation */ + gemode = readl(engine + VIA_REG_GEMODE) & 0xfffffcfc; + switch (bpp) { + case 8: + gemode |= VIA_GEM_8bpp; + break; + case 16: + gemode |= VIA_GEM_16bpp; + break; + case 32: + gemode |= VIA_GEM_32bpp; + break; + default: + printk(KERN_WARNING "viafb_set_bpp: Unsupported bpp %d\n", bpp); + return -EINVAL; + } + writel(gemode, engine + VIA_REG_GEMODE); + return 0; +} + + static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height, u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y, u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y, u32 fg_color, u32 bg_color, u8 fill_rop) { u32 ge_cmd = 0, tmp, i; + int ret; if (!op || op > 3) { printk(KERN_WARNING "hw_bitblt_1: Invalid operation: %d\n", op); @@ -59,22 +89,9 @@ static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height, } } - switch (dst_bpp) { - case 8: - tmp = 0x00000000; - break; - case 16: - tmp = 0x00000100; - break; - case 32: - tmp = 0x00000300; - break; - default: - printk(KERN_WARNING "hw_bitblt_1: Unsupported bpp %d\n", - dst_bpp); - return -EINVAL; - } - writel(tmp, engine + 0x04); + ret = viafb_set_bpp(engine, dst_bpp); + if (ret) + return ret; if (op != VIA_BITBLT_FILL) { if (src_x & (op == VIA_BITBLT_MONO ? 0xFFFF8000 : 0xFFFFF000) @@ -165,35 +182,6 @@ static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height, return 0; } -/* - * Figure out an appropriate bytes-per-pixel setting. - */ -static int viafb_set_bpp(void __iomem *engine, u8 bpp) -{ - u32 gemode; - - /* Preserve the reserved bits */ - /* Lowest 2 bits to zero gives us no rotation */ - gemode = readl(engine + VIA_REG_GEMODE) & 0xfffffcfc; - switch (bpp) { - case 8: - gemode |= VIA_GEM_8bpp; - break; - case 16: - gemode |= VIA_GEM_16bpp; - break; - case 32: - gemode |= VIA_GEM_32bpp; - break; - default: - printk(KERN_WARNING "hw_bitblt_2: Unsupported bpp %d\n", bpp); - return -EINVAL; - } - writel(gemode, engine + VIA_REG_GEMODE); - return 0; -} - - static int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height, u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y, u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y, -- cgit v1.2.1 From 107ea34db4560e6db41a9da90128ccc5e60f6b21 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 20 May 2009 01:36:03 +0800 Subject: viafb: Determine type of 2D engine and store it in chip_info This will help us for the upcoming support for 2D acceleration using the M1 engine. [jc: fixed merge conflicts] Signed-off-by: Harald Welte --- drivers/video/via/chip.h | 8 ++++++++ drivers/video/via/hw.c | 15 +++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'drivers/video') diff --git a/drivers/video/via/chip.h b/drivers/video/via/chip.h index 8c06bd3c0b4d..d9b6e06e0700 100644 --- a/drivers/video/via/chip.h +++ b/drivers/video/via/chip.h @@ -121,9 +121,17 @@ struct lvds_chip_information { int i2c_port; }; +/* The type of 2D engine */ +enum via_2d_engine { + VIA_2D_ENG_H2, + VIA_2D_ENG_H5, + VIA_2D_ENG_M1, +}; + struct chip_information { int gfx_chip_name; int gfx_chip_revision; + enum via_2d_engine twod_engine; struct tmds_chip_information tmds_chip_info; struct lvds_chip_information lvds_chip_info; struct lvds_chip_information lvds_chip_info2; diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index c94bcce71eaf..ae664fbd7e80 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -2016,6 +2016,21 @@ static void init_gfx_chip_info(struct pci_dev *pdev, CX700_REVISION_700; } } + + /* Determine which 2D engine we have */ + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_VX800: + case UNICHROME_VX855: + viaparinfo->chip_info->twod_engine = VIA_2D_ENG_M1; + break; + case UNICHROME_K8M890: + case UNICHROME_P4M900: + viaparinfo->chip_info->twod_engine = VIA_2D_ENG_H5; + break; + default: + viaparinfo->chip_info->twod_engine = VIA_2D_ENG_H2; + break; + } } static void init_tmds_chip_info(void) -- cgit v1.2.1 From 1317824376482781200980c6f026ef576d7ed1dd Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Sat, 27 Mar 2010 13:08:23 -0600 Subject: viafb: complete support for VX800/VX855 accelerated framebuffer This patch is a painful merge of change a90bab567ece3e915d0ccd55ab00c9bb333fa8c0 (viafb: Add support for 2D accelerated framebuffer on VX800/VX855) in the OLPC tree, originally by Harald Welte. Harald's changelog read: The VX800/VX820 and the VX855/VX875 chipsets have a different 2D acceleration engine called "M1". The M1 engine has some subtle (and some not-so-subtle) differences to the previous engines, so support for accelerated framebuffer on those chipsets was disabled so far. This merge tries to preserve Harald's changes in the framework of the much-changed 2.6.34 viafb code. Cc: Florian Tobias Schandinat Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Signed-off-by: Jonathan Corbet --- drivers/video/via/accel.c | 42 +++++++++++++++++++++++++++++++++--------- drivers/video/via/accel.h | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 9 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c index 7c1d9c41623d..0d90c859cc1c 100644 --- a/drivers/video/via/accel.c +++ b/drivers/video/via/accel.c @@ -317,6 +317,7 @@ int viafb_init_engine(struct fb_info *info) { struct viafb_par *viapar = info->par; void __iomem *engine; + int highest_reg, i; u32 vq_start_addr, vq_end_addr, vq_start_low, vq_end_low, vq_high, vq_len, chip_name = viapar->shared->chip_info.gfx_chip_name; @@ -328,6 +329,18 @@ int viafb_init_engine(struct fb_info *info) return -ENOMEM; } + /* Initialize registers to reset the 2D engine */ + switch (viapar->shared->chip_info.twod_engine) { + case VIA_2D_ENG_M1: + highest_reg = 0x5c; + break; + default: + highest_reg = 0x40; + break; + } + for (i = 0; i <= highest_reg; i += 4) + writel(0x0, engine + i); + switch (chip_name) { case UNICHROME_CLE266: case UNICHROME_K400: @@ -357,13 +370,12 @@ int viafb_init_engine(struct fb_info *info) viapar->shared->vq_vram_addr = viapar->fbmem_free; viapar->fbmem_used += VQ_SIZE; - /* Init 2D engine reg to reset 2D engine */ - writel(0x0, engine + VIA_REG_KEYCONTROL); - /* Init AGP and VQ regs */ switch (chip_name) { case UNICHROME_K8M890: case UNICHROME_P4M900: + case UNICHROME_VX800: + case UNICHROME_VX855: writel(0x00100000, engine + VIA_REG_CR_TRANSET); writel(0x680A0000, engine + VIA_REG_CR_TRANSPACE); writel(0x02000000, engine + VIA_REG_CR_TRANSPACE); @@ -398,6 +410,8 @@ int viafb_init_engine(struct fb_info *info) switch (chip_name) { case UNICHROME_K8M890: case UNICHROME_P4M900: + case UNICHROME_VX800: + case UNICHROME_VX855: vq_start_low |= 0x20000000; vq_end_low |= 0x20000000; vq_high |= 0x20000000; @@ -475,15 +489,25 @@ void viafb_wait_engine_idle(struct fb_info *info) { struct viafb_par *viapar = info->par; int loop = 0; + u32 mask; - while (!(readl(viapar->shared->engine_mmio + VIA_REG_STATUS) & - VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) { - loop++; - cpu_relax(); + switch (viapar->shared->chip_info.twod_engine) { + case VIA_2D_ENG_H5: + case VIA_2D_ENG_M1: + mask = VIA_CMD_RGTR_BUSY_M1 | VIA_2D_ENG_BUSY_M1 | + VIA_3D_ENG_BUSY_M1; + break; + default: + while (!(readl(viapar->shared->engine_mmio + VIA_REG_STATUS) & + VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) { + loop++; + cpu_relax(); + } + mask = VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY; + break; } - while ((readl(viapar->shared->engine_mmio + VIA_REG_STATUS) & - (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)) && + while ((readl(viapar->shared->engine_mmio + VIA_REG_STATUS) & mask) && (loop < MAXLOOP)) { loop++; cpu_relax(); diff --git a/drivers/video/via/accel.h b/drivers/video/via/accel.h index 615c84ad0f01..2c122d292365 100644 --- a/drivers/video/via/accel.h +++ b/drivers/video/via/accel.h @@ -67,6 +67,34 @@ /* from 0x100 to 0x1ff */ #define VIA_REG_COLORPAT 0x100 +/* defines for VIA 2D registers for vt3353/3409 (M1 engine)*/ +#define VIA_REG_GECMD_M1 0x000 +#define VIA_REG_GEMODE_M1 0x004 +#define VIA_REG_GESTATUS_M1 0x004 /* as same as VIA_REG_GEMODE */ +#define VIA_REG_PITCH_M1 0x008 /* pitch of src and dst */ +#define VIA_REG_DIMENSION_M1 0x00C /* width and height */ +#define VIA_REG_DSTPOS_M1 0x010 +#define VIA_REG_LINE_XY_M1 0x010 +#define VIA_REG_DSTBASE_M1 0x014 +#define VIA_REG_SRCPOS_M1 0x018 +#define VIA_REG_LINE_K1K2_M1 0x018 +#define VIA_REG_SRCBASE_M1 0x01C +#define VIA_REG_PATADDR_M1 0x020 +#define VIA_REG_MONOPAT0_M1 0x024 +#define VIA_REG_MONOPAT1_M1 0x028 +#define VIA_REG_OFFSET_M1 0x02C +#define VIA_REG_LINE_ERROR_M1 0x02C +#define VIA_REG_CLIPTL_M1 0x040 /* top and left of clipping */ +#define VIA_REG_CLIPBR_M1 0x044 /* bottom and right of clipping */ +#define VIA_REG_KEYCONTROL_M1 0x048 /* color key control */ +#define VIA_REG_FGCOLOR_M1 0x04C +#define VIA_REG_DSTCOLORKEY_M1 0x04C /* as same as VIA_REG_FG */ +#define VIA_REG_BGCOLOR_M1 0x050 +#define VIA_REG_SRCCOLORKEY_M1 0x050 /* as same as VIA_REG_BG */ +#define VIA_REG_MONOPATFGC_M1 0x058 /* Add BG color of Pattern. */ +#define VIA_REG_MONOPATBGC_M1 0x05C /* Add FG color of Pattern. */ +#define VIA_REG_COLORPAT_M1 0x100 /* from 0x100 to 0x1ff */ + /* VIA_REG_PITCH(0x38): Pitch Setting */ #define VIA_PITCH_ENABLE 0x80000000 @@ -157,6 +185,18 @@ /* Virtual Queue is busy */ #define VIA_VR_QUEUE_BUSY 0x00020000 +/* VIA_REG_STATUS(0x400): Engine Status for H5 */ +#define VIA_CMD_RGTR_BUSY_H5 0x00000010 /* Command Regulator is busy */ +#define VIA_2D_ENG_BUSY_H5 0x00000002 /* 2D Engine is busy */ +#define VIA_3D_ENG_BUSY_H5 0x00001FE1 /* 3D Engine is busy */ +#define VIA_VR_QUEUE_BUSY_H5 0x00000004 /* Virtual Queue is busy */ + +/* VIA_REG_STATUS(0x400): Engine Status for VT3353/3409 */ +#define VIA_CMD_RGTR_BUSY_M1 0x00000010 /* Command Regulator is busy */ +#define VIA_2D_ENG_BUSY_M1 0x00000002 /* 2D Engine is busy */ +#define VIA_3D_ENG_BUSY_M1 0x00001FE1 /* 3D Engine is busy */ +#define VIA_VR_QUEUE_BUSY_M1 0x00000004 /* Virtual Queue is busy */ + #define MAXLOOP 0xFFFFFF #define VIA_BITBLT_COLOR 1 -- cgit v1.2.1 From c205d932530719d2a6ddb9152650e5bbe80c9400 Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Sun, 7 Jun 2009 13:59:51 -0400 Subject: viafb: Add 1200x900 DCON/LCD panel modes for OLPC XO-1.5 [jc: extensive merge conflict fixes] Cc: Florian Tobias Schandinat Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Signed-off-by: Chris Ball --- drivers/video/via/hw.c | 1 + drivers/video/via/ioctl.h | 2 +- drivers/video/via/lcd.c | 9 +++++++++ drivers/video/via/lcd.h | 2 ++ drivers/video/via/share.h | 7 +++++++ drivers/video/via/viamode.c | 14 ++++++++++++++ 6 files changed, 34 insertions(+), 1 deletion(-) (limited to 'drivers/video') diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index ae664fbd7e80..2322612fbb95 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -62,6 +62,7 @@ static struct pll_map pll_value[] = { CX700_52_977M, VX855_52_977M}, {CLK_56_250M, CLE266_PLL_56_250M, K800_PLL_56_250M, CX700_56_250M, VX855_56_250M}, + {CLK_57_275M, 0, 0, 0, VX855_57_275M}, {CLK_60_466M, CLE266_PLL_60_466M, K800_PLL_60_466M, CX700_60_466M, VX855_60_466M}, {CLK_61_500M, CLE266_PLL_61_500M, K800_PLL_61_500M, diff --git a/drivers/video/via/ioctl.h b/drivers/video/via/ioctl.h index de899807eade..c430fa23008a 100644 --- a/drivers/video/via/ioctl.h +++ b/drivers/video/via/ioctl.h @@ -75,7 +75,7 @@ /*SAMM operation flag*/ #define OP_SAMM 0x80 -#define LCD_PANEL_ID_MAXIMUM 22 +#define LCD_PANEL_ID_MAXIMUM 23 #define STATE_ON 0x1 #define STATE_OFF 0x0 diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c index 1b1ccdc2d83d..09020f0b2d2a 100644 --- a/drivers/video/via/lcd.c +++ b/drivers/video/via/lcd.c @@ -398,6 +398,15 @@ static void fp_id_to_vindex(int panel_id) viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; viaparinfo->lvds_setting_info->LCDDithering = 1; break; + case 0x17: + /* OLPC XO-1.5 panel */ + viaparinfo->lvds_setting_info->lcd_panel_hres = 1200; + viaparinfo->lvds_setting_info->lcd_panel_vres = 900; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_IDD_1200X900; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; + viaparinfo->lvds_setting_info->LCDDithering = 0; + break; default: viaparinfo->lvds_setting_info->lcd_panel_hres = 800; viaparinfo->lvds_setting_info->lcd_panel_vres = 600; diff --git a/drivers/video/via/lcd.h b/drivers/video/via/lcd.h index 071f47cf5be1..9762ec62b495 100644 --- a/drivers/video/via/lcd.h +++ b/drivers/video/via/lcd.h @@ -60,6 +60,8 @@ #define LCD_PANEL_IDB_1360X768 0x0B /* Resolution: 480x640, Channel: single, Dithering: Enable */ #define LCD_PANEL_IDC_480X640 0x0C +/* Resolution: 1200x900, Channel: single, Dithering: Disable */ +#define LCD_PANEL_IDD_1200X900 0x0D extern int viafb_LCD2_ON; diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h index d55aaa7b912c..f974c7333522 100644 --- a/drivers/video/via/share.h +++ b/drivers/video/via/share.h @@ -570,6 +570,10 @@ #define M1200X720_R60_HSP NEGATIVE #define M1200X720_R60_VSP POSITIVE +/* 1200x900@60 Sync Polarity (DCON) */ +#define M1200X900_R60_HSP NEGATIVE +#define M1200X900_R60_VSP NEGATIVE + /* 1280x600@60 Sync Polarity (GTF Mode) */ #define M1280x600_R60_HSP NEGATIVE #define M1280x600_R60_VSP POSITIVE @@ -651,6 +655,7 @@ #define CLK_52_406M 52406000 #define CLK_52_977M 52977000 #define CLK_56_250M 56250000 +#define CLK_57_275M 57275000 #define CLK_60_466M 60466000 #define CLK_61_500M 61500000 #define CLK_65_000M 65000000 @@ -939,6 +944,7 @@ #define VX855_52_406M 0x00580C03 #define VX855_52_977M 0x00940C05 #define VX855_56_250M 0x009D0C05 +#define VX855_57_275M 0x009D8C85 /* Used by XO panel */ #define VX855_60_466M 0x00A90C05 #define VX855_61_500M 0x00AC0C05 #define VX855_65_000M 0x006D0C03 @@ -1065,6 +1071,7 @@ #define RES_1600X1200_60HZ_PIXCLOCK 6172 #define RES_1600X1200_75HZ_PIXCLOCK 4938 #define RES_1280X720_60HZ_PIXCLOCK 13426 +#define RES_1200X900_60HZ_PIXCLOCK 17459 #define RES_1920X1080_60HZ_PIXCLOCK 5787 #define RES_1400X1050_60HZ_PIXCLOCK 8214 #define RES_1400X1050_75HZ_PIXCLOCK 6410 diff --git a/drivers/video/via/viamode.c b/drivers/video/via/viamode.c index af50e244016c..6f3bcda8cb47 100644 --- a/drivers/video/via/viamode.c +++ b/drivers/video/via/viamode.c @@ -66,6 +66,7 @@ struct res_map_refresh res_map_refresh_tbl[] = { {1088, 612, RES_1088X612_60HZ_PIXCLOCK, 60}, {1152, 720, RES_1152X720_60HZ_PIXCLOCK, 60}, {1200, 720, RES_1200X720_60HZ_PIXCLOCK, 60}, + {1200, 900, RES_1200X900_60HZ_PIXCLOCK, 60}, {1280, 600, RES_1280X600_60HZ_PIXCLOCK, 60}, {1280, 720, RES_1280X720_50HZ_PIXCLOCK, 50}, {1280, 768, RES_1280X768_50HZ_PIXCLOCK, 50}, @@ -759,6 +760,16 @@ struct crt_mode_table CRTM1200x720[] = { {1568, 1200, 1200, 368, 1256, 128, 746, 720, 720, 26, 721, 3} } }; +/* 1200x900 (DCON) */ +struct crt_mode_table DCON1200x900[] = { + /* r_rate, vclk, hsp, vsp */ + {REFRESH_60, CLK_57_275M, M1200X900_R60_HSP, M1200X900_R60_VSP, + /* The correct htotal is 1240, but this doesn't raster on VX855. */ + /* Via suggested changing to a multiple of 16, hence 1264. */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {1264, 1200, 1200, 64, 1211, 32, 912, 900, 900, 12, 901, 10} } +}; + /* 1280x600 (GTF) */ struct crt_mode_table CRTM1280x600[] = { /* r_rate, vclk, hsp, vsp */ @@ -937,6 +948,9 @@ struct VideoModeTable viafb_modes[] = { /* Display : 1200x720 (GTF) */ {CRTM1200x720, ARRAY_SIZE(CRTM1200x720)}, + /* Display : 1200x900 (DCON) */ + {DCON1200x900, ARRAY_SIZE(DCON1200x900)}, + /* Display : 1280x600 (GTF) */ {CRTM1280x600, ARRAY_SIZE(CRTM1280x600)}, -- cgit v1.2.1 From a63445a31a76474dd3f9e852e8bf08f81ee7437a Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Thu, 22 Apr 2010 14:00:18 -0700 Subject: drivers: video: msm: default to no It doesn't cure cancer .. Signed-off-by: Daniel Walker --- drivers/video/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/video') diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 6e16244f3ed1..87f36efe46f3 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -2186,7 +2186,6 @@ config FB_MSM select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - default y config FB_MX3 tristate "MX3 Framebuffer support" -- cgit v1.2.1 From 8a3bdfe6cd841880a5d849c40f90093b3817f6e0 Mon Sep 17 00:00:00 2001 From: Thomas Gerlach Date: Fri, 23 Apr 2010 13:17:50 -0400 Subject: drivers/video/efifb.c: support framebuffer for NVIDIA 9400M in MacBook Pro 5,1 Description of patch: --------------------- This is a patch for the EFI framebuffer driver to enable the framebuffer of the NVIDIA 9400M as found in MacBook Pro (MBP) 5,1 and up. The framebuffer of the NVIDIA graphic cards are located at the following addresses in memory: 9400M: 0xC0010000 9600M GT: 0xB0030000 The patch delivered right here only provides the memory location of the framebuffer of the 9400M device. The 9600M GT is not covered. It is assumed that the 9400M is used when powered up the MBP. The information which device is currently powered and in use is stored in the 64 bytes large EFI variable "gpu-power-prefs". More specifically, byte 0x3B indicates whether 9600M GT (0x00) or 9400M (0x01) is online. The PCI bus IDs are the following: 9400M: PCI 03:00:00 9600M GT: PCI 02:00:00 The EFI variables can be easily read-out and manipulated with "rEFIt", an MBP specific bootloader tool. For more information on how handle rEFIt and EFI variables please consult "http://refit.sourceforge.net" and "http://ubuntuforums.org/archive/index.php/t-1076879.html". IMPORTANT NOTE: The information on how to activate the 9400M device given at "ubuntuforums.org" is not correct, since it states gpu-power-prefs[0x3B] = 0x00 -> 9400M (PCI 02:00:00) gpu-power-prefs[0x3B] = 0x01 -> 9600M GT (PCI 03:00:00) Actually, the assignment of the values and the PCI bus IDs are swapped. Suggestions: ------------ To cover framebuffers of both 9400M and 9600M GT, I would suggest to implement a conditional on "gpu-power-prefs". Depending on the value of byte 0x3B, the according framebuffer is selected. However, this requires kernel access to the EFI variables. [akpm@linux-foundation.org: rename optname, per Peter Jones] Signed-off-by: Thomas Gerlach Acked-by: Peter Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/efifb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/video') diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index 581d2dbf675a..ecf405562f5c 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c @@ -49,6 +49,7 @@ enum { M_MBP_2, /* MacBook Pro 2nd gen */ M_MBP_SR, /* MacBook Pro (Santa Rosa) */ M_MBP_4, /* MacBook Pro, 4th gen */ + M_MBP_5_1, /* MacBook Pro, 5,1th gen */ M_UNKNOWN /* placeholder */ }; @@ -70,6 +71,7 @@ static struct efifb_dmi_info { [M_MBP_2] = { "mbp2", 0, 0, 0, 0 }, /* placeholder */ [M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900 }, [M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200 }, + [M_MBP_5_1] = { "mbp51", 0xc0010000, 2048 * 4, 1440, 900 }, [M_UNKNOWN] = { NULL, 0, 0, 0, 0 } }; @@ -106,6 +108,7 @@ static struct dmi_system_id __initdata dmi_system_table[] = { EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro3,1", M_MBP_SR), EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro3,1", M_MBP_SR), EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro4,1", M_MBP_4), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,1", M_MBP_5_1), {}, }; -- cgit v1.2.1 From 277d32a36cba0b42c9c6836ff07f9b978566e95c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 23 May 2009 00:35:39 +0800 Subject: viafb: rework the I2C support in the VIA framebuffer driver This patch changes the way how the various I2C busses are used internally inside the viafb driver: Previosuly, only a single i2c_adapter was created, even though two different hardware I2C busses are accessed: A structure member in a global variable was modified to indicate the bus to be used. Now, all existing hardware busses are registered with the i2c core, and the viafb_i2c_{read,write}byte[s]() function take the adapter number as function call parameter, rather than referring to the global structure member. [jc: even more painful merge with mainline changes ->2.6.34] [jc: painful merge with OLPC changes] Cc: Florian Tobias Schandinat Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Signed-off-by: Harald Welte Signed-off-by: Jonathan Corbet --- drivers/video/via/dvi.c | 35 ++++----- drivers/video/via/lcd.c | 19 ++--- drivers/video/via/via_i2c.c | 171 +++++++++++++++++++++++++++---------------- drivers/video/via/via_i2c.h | 43 +++++++---- drivers/video/via/viafbdev.c | 6 +- drivers/video/via/viafbdev.h | 4 +- drivers/video/via/vt1636.c | 36 +++++---- drivers/video/via/vt1636.h | 2 +- 8 files changed, 182 insertions(+), 134 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c index abe59b8c7a05..be513701e4e6 100644 --- a/drivers/video/via/dvi.c +++ b/drivers/video/via/dvi.c @@ -96,7 +96,7 @@ int viafb_tmds_trasmitter_identify(void) viaparinfo->chip_info->tmds_chip_info.tmds_chip_name = VT1632_TMDS; viaparinfo->chip_info-> tmds_chip_info.tmds_chip_slave_addr = VT1632_TMDS_I2C_ADDR; - viaparinfo->chip_info->tmds_chip_info.i2c_port = I2CPORTINDEX; + viaparinfo->chip_info->tmds_chip_info.i2c_port = VIA_I2C_ADAP_31; if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID) != FAIL) { /* * Currently only support 12bits,dual edge,add 24bits mode later @@ -110,7 +110,7 @@ int viafb_tmds_trasmitter_identify(void) viaparinfo->chip_info->tmds_chip_info.i2c_port); return OK; } else { - viaparinfo->chip_info->tmds_chip_info.i2c_port = GPIOPORTINDEX; + viaparinfo->chip_info->tmds_chip_info.i2c_port = VIA_I2C_ADAP_2C; if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID) != FAIL) { tmds_register_write(0x08, 0x3b); @@ -160,32 +160,26 @@ int viafb_tmds_trasmitter_identify(void) static void tmds_register_write(int index, u8 data) { - viaparinfo->shared->i2c_stuff.i2c_port = - viaparinfo->chip_info->tmds_chip_info.i2c_port; - - viafb_i2c_writebyte(viaparinfo->chip_info->tmds_chip_info. - tmds_chip_slave_addr, index, - data); + viafb_i2c_writebyte(viaparinfo->chip_info->tmds_chip_info.i2c_port, + viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr, + index, data); } static int tmds_register_read(int index) { u8 data; - viaparinfo->shared->i2c_stuff.i2c_port = - viaparinfo->chip_info->tmds_chip_info.i2c_port; - viafb_i2c_readbyte((u8) viaparinfo->chip_info-> - tmds_chip_info.tmds_chip_slave_addr, - (u8) index, &data); + viafb_i2c_readbyte(viaparinfo->chip_info->tmds_chip_info.i2c_port, + (u8) viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr, + (u8) index, &data); return data; } static int tmds_register_read_bytes(int index, u8 *buff, int buff_len) { - viaparinfo->shared->i2c_stuff.i2c_port = - viaparinfo->chip_info->tmds_chip_info.i2c_port; - viafb_i2c_readbytes((u8) viaparinfo->chip_info->tmds_chip_info. - tmds_chip_slave_addr, (u8) index, buff, buff_len); + viafb_i2c_readbytes(viaparinfo->chip_info->tmds_chip_info.i2c_port, + (u8) viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr, + (u8) index, buff, buff_len); return 0; } @@ -541,9 +535,10 @@ void viafb_dvi_enable(void) else data = 0x37; viafb_i2c_writebyte(viaparinfo->chip_info-> - tmds_chip_info. - tmds_chip_slave_addr, - 0x08, data); + tmds_chip_info.i2c_port, + viaparinfo->chip_info-> + tmds_chip_info.tmds_chip_slave_addr, + 0x08, data); } } } diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c index 09020f0b2d2a..e19441d9e49f 100644 --- a/drivers/video/via/lcd.c +++ b/drivers/video/via/lcd.c @@ -172,18 +172,16 @@ static bool lvds_identify_integratedlvds(void) int viafb_lvds_trasmitter_identify(void) { - viaparinfo->shared->i2c_stuff.i2c_port = I2CPORTINDEX; - if (viafb_lvds_identify_vt1636()) { - viaparinfo->chip_info->lvds_chip_info.i2c_port = I2CPORTINDEX; + if (viafb_lvds_identify_vt1636(VIA_I2C_ADAP_31)) { + viaparinfo->chip_info->lvds_chip_info.i2c_port = VIA_I2C_ADAP_31; DEBUG_MSG(KERN_INFO - "Found VIA VT1636 LVDS on port i2c 0x31 \n"); + "Found VIA VT1636 LVDS on port i2c 0x31\n"); } else { - viaparinfo->shared->i2c_stuff.i2c_port = GPIOPORTINDEX; - if (viafb_lvds_identify_vt1636()) { + if (viafb_lvds_identify_vt1636(VIA_I2C_ADAP_2C)) { viaparinfo->chip_info->lvds_chip_info.i2c_port = - GPIOPORTINDEX; + VIA_I2C_ADAP_2C; DEBUG_MSG(KERN_INFO - "Found VIA VT1636 LVDS on port gpio 0x2c \n"); + "Found VIA VT1636 LVDS on port gpio 0x2c\n"); } } @@ -421,9 +419,8 @@ static int lvds_register_read(int index) { u8 data; - viaparinfo->shared->i2c_stuff.i2c_port = GPIOPORTINDEX; - viafb_i2c_readbyte((u8) viaparinfo->chip_info-> - lvds_chip_info.lvds_chip_slave_addr, + viafb_i2c_readbyte(VIA_I2C_ADAP_2C, + (u8) viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr, (u8) index, &data); return data; } diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c index 15543e968248..8f8e0bf0cf91 100644 --- a/drivers/video/via/via_i2c.c +++ b/drivers/video/via/via_i2c.c @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved. * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. * This program is free software; you can redistribute it and/or @@ -24,40 +24,44 @@ static void via_i2c_setscl(void *data, int state) { u8 val; - struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data; + struct via_i2c_adap_cfg *adap_data = data; - val = viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0xF0; + printk(KERN_DEBUG "reading index 0x%02x from IO 0x%x\n", + adap_data->ioport_index, adap_data->io_port); + val = viafb_read_reg(adap_data->io_port, + adap_data->ioport_index) & 0xF0; if (state) val |= 0x20; else val &= ~0x20; - switch (via_i2c_chan->i2c_port) { - case I2CPORTINDEX: + switch (adap_data->type) { + case VIA_I2C_I2C: val |= 0x01; break; - case GPIOPORTINDEX: + case VIA_I2C_GPIO: val |= 0x80; break; default: - DEBUG_MSG("via_i2c: specify wrong i2c port.\n"); + DEBUG_MSG("viafb_i2c: specify wrong i2c type.\n"); } - viafb_write_reg(via_i2c_chan->i2c_port, VIASR, val); + viafb_write_reg(adap_data->ioport_index, + adap_data->io_port, val); } static int via_i2c_getscl(void *data) { - struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data; + struct via_i2c_adap_cfg *adap_data = data; - if (viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0x08) + if (viafb_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x08) return 1; return 0; } static int via_i2c_getsda(void *data) { - struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data; + struct via_i2c_adap_cfg *adap_data = data; - if (viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0x04) + if (viafb_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x04) return 1; return 0; } @@ -65,27 +69,29 @@ static int via_i2c_getsda(void *data) static void via_i2c_setsda(void *data, int state) { u8 val; - struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data; + struct via_i2c_adap_cfg *adap_data = data; - val = viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0xF0; + val = viafb_read_reg(adap_data->io_port, + adap_data->ioport_index) & 0xF0; if (state) val |= 0x10; else val &= ~0x10; - switch (via_i2c_chan->i2c_port) { - case I2CPORTINDEX: + switch (adap_data->type) { + case VIA_I2C_I2C: val |= 0x01; break; - case GPIOPORTINDEX: + case VIA_I2C_GPIO: val |= 0x40; break; default: - DEBUG_MSG("via_i2c: specify wrong i2c port.\n"); + DEBUG_MSG("viafb_i2c: specify wrong i2c type.\n"); } - viafb_write_reg(via_i2c_chan->i2c_port, VIASR, val); + viafb_write_reg(adap_data->ioport_index, + adap_data->io_port, val); } -int viafb_i2c_readbyte(u8 slave_addr, u8 index, u8 *pdata) +int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata) { u8 mm1[] = {0x00}; struct i2c_msg msgs[2]; @@ -97,12 +103,11 @@ int viafb_i2c_readbyte(u8 slave_addr, u8 index, u8 *pdata) mm1[0] = index; msgs[0].len = 1; msgs[1].len = 1; msgs[0].buf = mm1; msgs[1].buf = pdata; - i2c_transfer(&viaparinfo->shared->i2c_stuff.adapter, msgs, 2); - - return 0; + return i2c_transfer(&viaparinfo->shared->i2c_stuff[adap].adapter, + msgs, 2); } -int viafb_i2c_writebyte(u8 slave_addr, u8 index, u8 data) +int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data) { u8 msg[2] = { index, data }; struct i2c_msg msgs; @@ -111,10 +116,11 @@ int viafb_i2c_writebyte(u8 slave_addr, u8 index, u8 data) msgs.addr = slave_addr / 2; msgs.len = 2; msgs.buf = msg; - return i2c_transfer(&viaparinfo->shared->i2c_stuff.adapter, &msgs, 1); + return i2c_transfer(&viaparinfo->shared->i2c_stuff[adap].adapter, + &msgs, 1); } -int viafb_i2c_readbytes(u8 slave_addr, u8 index, u8 *buff, int buff_len) +int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len) { u8 mm1[] = {0x00}; struct i2c_msg msgs[2]; @@ -125,53 +131,88 @@ int viafb_i2c_readbytes(u8 slave_addr, u8 index, u8 *buff, int buff_len) mm1[0] = index; msgs[0].len = 1; msgs[1].len = buff_len; msgs[0].buf = mm1; msgs[1].buf = buff; - i2c_transfer(&viaparinfo->shared->i2c_stuff.adapter, msgs, 2); - return 0; + return i2c_transfer(&viaparinfo->shared->i2c_stuff[adap].adapter, + msgs, 2); } -int viafb_create_i2c_bus(void *viapar) +static int create_i2c_bus(struct i2c_adapter *adapter, + struct i2c_algo_bit_data *algo, + struct via_i2c_adap_cfg *adap_cfg, + struct pci_dev *pdev) { - int ret; - struct via_i2c_stuff *i2c_stuff = - &((struct viafb_par *)viapar)->shared->i2c_stuff; - - strcpy(i2c_stuff->adapter.name, "via_i2c"); - i2c_stuff->i2c_port = 0x0; - i2c_stuff->adapter.owner = THIS_MODULE; - i2c_stuff->adapter.id = 0x01FFFF; - i2c_stuff->adapter.class = 0; - i2c_stuff->adapter.algo_data = &i2c_stuff->algo; - i2c_stuff->adapter.dev.parent = NULL; - i2c_stuff->algo.setsda = via_i2c_setsda; - i2c_stuff->algo.setscl = via_i2c_setscl; - i2c_stuff->algo.getsda = via_i2c_getsda; - i2c_stuff->algo.getscl = via_i2c_getscl; - i2c_stuff->algo.udelay = 40; - i2c_stuff->algo.timeout = 20; - i2c_stuff->algo.data = i2c_stuff; - - i2c_set_adapdata(&i2c_stuff->adapter, i2c_stuff); + printk(KERN_DEBUG "viafb: creating bus adap=0x%p, algo_bit_data=0x%p, adap_cfg=0x%p\n", adapter, algo, adap_cfg); + + algo->setsda = via_i2c_setsda; + algo->setscl = via_i2c_setscl; + algo->getsda = via_i2c_getsda; + algo->getscl = via_i2c_getscl; + algo->udelay = 40; + algo->timeout = 20; + algo->data = adap_cfg; + + sprintf(adapter->name, "viafb i2c io_port idx 0x%02x", + adap_cfg->ioport_index); + adapter->owner = THIS_MODULE; + adapter->id = 0x01FFFF; + adapter->class = I2C_CLASS_DDC; + adapter->algo_data = algo; + if (pdev) + adapter->dev.parent = &pdev->dev; + else + adapter->dev.parent = NULL; + /* i2c_set_adapdata(adapter, adap_cfg); */ /* Raise SCL and SDA */ - i2c_stuff->i2c_port = I2CPORTINDEX; - via_i2c_setsda(i2c_stuff, 1); - via_i2c_setscl(i2c_stuff, 1); - - i2c_stuff->i2c_port = GPIOPORTINDEX; - via_i2c_setsda(i2c_stuff, 1); - via_i2c_setscl(i2c_stuff, 1); + via_i2c_setsda(adap_cfg, 1); + via_i2c_setscl(adap_cfg, 1); udelay(20); - ret = i2c_bit_add_bus(&i2c_stuff->adapter); - if (ret == 0) - DEBUG_MSG("I2C bus %s registered.\n", i2c_stuff->adapter.name); - else - DEBUG_MSG("Failed to register I2C bus %s.\n", - i2c_stuff->adapter.name); - return ret; + return i2c_bit_add_bus(adapter); +} + +static struct via_i2c_adap_cfg adap_configs[] = { + [VIA_I2C_ADAP_26] = { VIA_I2C_I2C, VIASR, 0x26 }, + [VIA_I2C_ADAP_31] = { VIA_I2C_I2C, VIASR, 0x31 }, + [VIA_I2C_ADAP_25] = { VIA_I2C_GPIO, VIASR, 0x25 }, + [VIA_I2C_ADAP_2C] = { VIA_I2C_GPIO, VIASR, 0x2c }, + [VIA_I2C_ADAP_3D] = { VIA_I2C_GPIO, VIASR, 0x3d }, + { 0, 0, 0 } +}; + +int viafb_create_i2c_busses(struct viafb_par *viapar) +{ + int i, ret; + + for (i = 0; i < VIAFB_NUM_I2C; i++) { + struct via_i2c_adap_cfg *adap_cfg = &adap_configs[i]; + struct via_i2c_stuff *i2c_stuff = &viapar->shared->i2c_stuff[i]; + + if (adap_cfg->type == 0) + break; + + ret = create_i2c_bus(&i2c_stuff->adapter, + &i2c_stuff->algo, adap_cfg, + NULL); /* FIXME: PCIDEV */ + if (ret < 0) { + printk(KERN_ERR "viafb: cannot create i2c bus %u:%d\n", + i, ret); + /* FIXME: properly release previous busses */ + return ret; + } + } + + return 0; } -void viafb_delete_i2c_buss(void *par) +void viafb_delete_i2c_busses(struct viafb_par *par) { - i2c_del_adapter(&((struct viafb_par *)par)->shared->i2c_stuff.adapter); + int i; + + for (i = 0; i < ARRAY_SIZE(par->shared->i2c_stuff); i++) { + struct via_i2c_stuff *i2c_stuff = &par->shared->i2c_stuff[i]; + /* only remove those entries in the array that we've + * actually used (and thus initialized algo_data) */ + if (i2c_stuff->adapter.algo_data == &i2c_stuff->algo) + i2c_del_adapter(&i2c_stuff->adapter); + } } diff --git a/drivers/video/via/via_i2c.h b/drivers/video/via/via_i2c.h index 3a13242a3152..00ed97886842 100644 --- a/drivers/video/via/via_i2c.h +++ b/drivers/video/via/via_i2c.h @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved. * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. * This program is free software; you can redistribute it and/or @@ -24,23 +24,38 @@ #include #include +enum via_i2c_type { + VIA_I2C_NONE, + VIA_I2C_I2C, + VIA_I2C_GPIO, +}; + +/* private data for each adapter */ +struct via_i2c_adap_cfg { + enum via_i2c_type type; + u_int16_t io_port; + u_int8_t ioport_index; +}; + struct via_i2c_stuff { u16 i2c_port; /* GPIO or I2C port */ struct i2c_adapter adapter; struct i2c_algo_bit_data algo; }; -#define I2CPORT 0x3c4 -#define I2CPORTINDEX 0x31 -#define GPIOPORT 0x3C4 -#define GPIOPORTINDEX 0x2C -#define I2C_BUS 1 -#define GPIO_BUS 2 -#define DELAYPORT 0x3C3 - -int viafb_i2c_readbyte(u8 slave_addr, u8 index, u8 *pdata); -int viafb_i2c_writebyte(u8 slave_addr, u8 index, u8 data); -int viafb_i2c_readbytes(u8 slave_addr, u8 index, u8 *buff, int buff_len); -int viafb_create_i2c_bus(void *par); -void viafb_delete_i2c_buss(void *par); +enum viafb_i2c_adap { + VIA_I2C_ADAP_26, + VIA_I2C_ADAP_31, + VIA_I2C_ADAP_25, + VIA_I2C_ADAP_2C, + VIA_I2C_ADAP_3D, +}; + +int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata); +int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data); +int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len); + +struct viafb_par; +int viafb_create_i2c_busses(struct viafb_par *par); +void viafb_delete_i2c_busses(struct viafb_par *par); #endif /* __VIA_I2C_H__ */ diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 8955ab4caac8..fa1004997c63 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -1775,7 +1775,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, viafb_dual_fb = 0; /* Set up I2C bus stuff */ - rc = viafb_create_i2c_bus(viaparinfo); + rc = viafb_create_i2c_busses(viaparinfo); if (rc) goto out_fb_release; @@ -1964,7 +1964,7 @@ out_fb1_release: out_unmap_screen: iounmap(viafbinfo->screen_base); out_delete_i2c: - viafb_delete_i2c_buss(viaparinfo); + viafb_delete_i2c_busses(viaparinfo); out_fb_release: framebuffer_release(viafbinfo); return rc; @@ -1980,7 +1980,7 @@ static void __devexit via_pci_remove(struct pci_dev *pdev) iounmap((void *)viafbinfo->screen_base); iounmap(viaparinfo->shared->engine_mmio); - viafb_delete_i2c_buss(viaparinfo); + viafb_delete_i2c_busses(viaparinfo); framebuffer_release(viafbinfo); if (viafb_dual_fb) diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h index 61b5953cd159..4bc00ec8fb1c 100644 --- a/drivers/video/via/viafbdev.h +++ b/drivers/video/via/viafbdev.h @@ -37,11 +37,13 @@ #define VERSION_OS 0 /* 0: for 32 bits OS, 1: for 64 bits OS */ #define VERSION_MINOR 4 +#define VIAFB_NUM_I2C 5 + struct viafb_shared { struct proc_dir_entry *proc_entry; /*viafb proc entry */ /* I2C stuff */ - struct via_i2c_stuff i2c_stuff; + struct via_i2c_stuff i2c_stuff[VIAFB_NUM_I2C]; /* All the information will be needed to set engine */ struct tmds_setting_information tmds_setting_info; diff --git a/drivers/video/via/vt1636.c b/drivers/video/via/vt1636.c index a6b37494e79a..4589c6e73c5d 100644 --- a/drivers/video/via/vt1636.c +++ b/drivers/video/via/vt1636.c @@ -27,9 +27,8 @@ u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information { u8 data; - viaparinfo->shared->i2c_stuff.i2c_port = plvds_chip_info->i2c_port; - viafb_i2c_readbyte(plvds_chip_info->lvds_chip_slave_addr, index, &data); - + viafb_i2c_readbyte(plvds_chip_info->i2c_port, + plvds_chip_info->lvds_chip_slave_addr, index, &data); return data; } @@ -39,14 +38,13 @@ void viafb_gpio_i2c_write_mask_lvds(struct lvds_setting_information { int index, data; - viaparinfo->shared->i2c_stuff.i2c_port = plvds_chip_info->i2c_port; - index = io_data.Index; data = viafb_gpio_i2c_read_lvds(plvds_setting_info, plvds_chip_info, index); data = (data & (~io_data.Mask)) | io_data.Data; - viafb_i2c_writebyte(plvds_chip_info->lvds_chip_slave_addr, index, data); + viafb_i2c_writebyte(plvds_chip_info->i2c_port, + plvds_chip_info->lvds_chip_slave_addr, index, data); } void viafb_init_lvds_vt1636(struct lvds_setting_information @@ -159,7 +157,7 @@ void viafb_disable_lvds_vt1636(struct lvds_setting_information } } -bool viafb_lvds_identify_vt1636(void) +bool viafb_lvds_identify_vt1636(u8 i2c_adapter) { u8 Buffer[2]; @@ -170,23 +168,23 @@ bool viafb_lvds_identify_vt1636(void) VT1636_LVDS_I2C_ADDR; /* Check vendor ID first: */ - viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info. - lvds_chip_slave_addr, - 0x00, &Buffer[0]); - viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info. - lvds_chip_slave_addr, - 0x01, &Buffer[1]); + viafb_i2c_readbyte(i2c_adapter, + (u8) viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr, + 0x00, &Buffer[0]); + viafb_i2c_readbyte(i2c_adapter, + (u8) viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr, + 0x01, &Buffer[1]); if (!((Buffer[0] == 0x06) && (Buffer[1] == 0x11))) return false; /* Check Chip ID: */ - viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info. - lvds_chip_slave_addr, - 0x02, &Buffer[0]); - viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info. - lvds_chip_slave_addr, - 0x03, &Buffer[1]); + viafb_i2c_readbyte(i2c_adapter, + (u8) viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr, + 0x02, &Buffer[0]); + viafb_i2c_readbyte(i2c_adapter, + (u8) viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr, + 0x03, &Buffer[1]); if ((Buffer[0] == 0x45) && (Buffer[1] == 0x33)) { viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = VT1636_LVDS; diff --git a/drivers/video/via/vt1636.h b/drivers/video/via/vt1636.h index 2a150c58c7ed..4c1314e57468 100644 --- a/drivers/video/via/vt1636.h +++ b/drivers/video/via/vt1636.h @@ -22,7 +22,7 @@ #ifndef _VT1636_H_ #define _VT1636_H_ #include "chip.h" -bool viafb_lvds_identify_vt1636(void); +bool viafb_lvds_identify_vt1636(u8 i2c_adapter); void viafb_init_lvds_vt1636(struct lvds_setting_information *plvds_setting_info, struct lvds_chip_information *plvds_chip_info); void viafb_enable_lvds_vt1636(struct lvds_setting_information -- cgit v1.2.1 From c774c13dd2826eb91ab6396fd8501df2fc2d83b3 Mon Sep 17 00:00:00 2001 From: Paul Fox Date: Wed, 7 Oct 2009 11:13:01 -0400 Subject: suppress verbose debug messages: change printk() to DEBUG_MSG() [jc: no signoff, added my own] Cc: Florian Tobias Schandinat Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Signed-off-by: Jonathan Corbet --- drivers/video/via/via_i2c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c index 8f8e0bf0cf91..fe5535cf1480 100644 --- a/drivers/video/via/via_i2c.c +++ b/drivers/video/via/via_i2c.c @@ -26,7 +26,7 @@ static void via_i2c_setscl(void *data, int state) u8 val; struct via_i2c_adap_cfg *adap_data = data; - printk(KERN_DEBUG "reading index 0x%02x from IO 0x%x\n", + DEBUG_MSG(KERN_DEBUG "reading index 0x%02x from IO 0x%x\n", adap_data->ioport_index, adap_data->io_port); val = viafb_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0; @@ -140,7 +140,7 @@ static int create_i2c_bus(struct i2c_adapter *adapter, struct via_i2c_adap_cfg *adap_cfg, struct pci_dev *pdev) { - printk(KERN_DEBUG "viafb: creating bus adap=0x%p, algo_bit_data=0x%p, adap_cfg=0x%p\n", adapter, algo, adap_cfg); + DEBUG_MSG(KERN_DEBUG "viafb: creating bus adap=0x%p, algo_bit_data=0x%p, adap_cfg=0x%p\n", adapter, algo, adap_cfg); algo->setsda = via_i2c_setsda; algo->setscl = via_i2c_setscl; -- cgit v1.2.1 From 4da62e6c6e056d709e5dc04ac7c5e81692cf924f Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Sun, 25 Apr 2010 08:30:41 -0600 Subject: viafb: Only establish i2c busses on ports that always had them ...otherwise it seems we run into conflicts with shadowy other users which don't expect to see i2c taking control of ports it never used to do anything with. Reported-by: Florian Tobias Schandinat Signed-off-by: Jonathan Corbet --- drivers/video/via/via_i2c.c | 19 +++++++++++++------ drivers/video/via/via_i2c.h | 1 + 2 files changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c index fe5535cf1480..b5253e3099f8 100644 --- a/drivers/video/via/via_i2c.c +++ b/drivers/video/via/via_i2c.c @@ -170,13 +170,18 @@ static int create_i2c_bus(struct i2c_adapter *adapter, return i2c_bit_add_bus(adapter); } +/* + * By default, we only activate busses on ports 2c and 31 to avoid + * conflicts with other possible users; that default can be changed + * below. + */ static struct via_i2c_adap_cfg adap_configs[] = { - [VIA_I2C_ADAP_26] = { VIA_I2C_I2C, VIASR, 0x26 }, - [VIA_I2C_ADAP_31] = { VIA_I2C_I2C, VIASR, 0x31 }, - [VIA_I2C_ADAP_25] = { VIA_I2C_GPIO, VIASR, 0x25 }, - [VIA_I2C_ADAP_2C] = { VIA_I2C_GPIO, VIASR, 0x2c }, - [VIA_I2C_ADAP_3D] = { VIA_I2C_GPIO, VIASR, 0x3d }, - { 0, 0, 0 } + [VIA_I2C_ADAP_26] = { VIA_I2C_I2C, VIASR, 0x26, 0 }, + [VIA_I2C_ADAP_31] = { VIA_I2C_I2C, VIASR, 0x31, 1 }, + [VIA_I2C_ADAP_25] = { VIA_I2C_GPIO, VIASR, 0x25, 0 }, + [VIA_I2C_ADAP_2C] = { VIA_I2C_GPIO, VIASR, 0x2c, 1 }, + [VIA_I2C_ADAP_3D] = { VIA_I2C_GPIO, VIASR, 0x3d, 0 }, + { 0, 0, 0, 0 } }; int viafb_create_i2c_busses(struct viafb_par *viapar) @@ -189,6 +194,8 @@ int viafb_create_i2c_busses(struct viafb_par *viapar) if (adap_cfg->type == 0) break; + if (!adap_cfg->is_active) + continue; ret = create_i2c_bus(&i2c_stuff->adapter, &i2c_stuff->algo, adap_cfg, diff --git a/drivers/video/via/via_i2c.h b/drivers/video/via/via_i2c.h index 00ed97886842..73d682fcf269 100644 --- a/drivers/video/via/via_i2c.h +++ b/drivers/video/via/via_i2c.h @@ -35,6 +35,7 @@ struct via_i2c_adap_cfg { enum via_i2c_type type; u_int16_t io_port; u_int8_t ioport_index; + u8 is_active; }; struct via_i2c_stuff { -- cgit v1.2.1 From 7d7fb0e6eb78600e5d4fb0f28858e97d38ef6bbf Mon Sep 17 00:00:00 2001 From: Henrik Kretzschmar Date: Wed, 28 Apr 2010 12:25:02 +0200 Subject: cocbalt_lcdfb: correct sections Since the drivers probe call was changed from .init.text to .devinit.text in commit c2e13037e6794bd0d9de3f9ecabf5615f15c160b the fb_fix_screeninfo structure must be changed from .init.data to .devinit.data, too. Signed-off-by: Henrik Kretzschmar Tested-by: Ralf Baechle Signed-off-by: Jiri Kosina --- drivers/video/cobalt_lcdfb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/video') diff --git a/drivers/video/cobalt_lcdfb.c b/drivers/video/cobalt_lcdfb.c index 5eb61b5adfe8..42fe155aba0e 100644 --- a/drivers/video/cobalt_lcdfb.c +++ b/drivers/video/cobalt_lcdfb.c @@ -123,7 +123,7 @@ static void lcd_clear(struct fb_info *info) lcd_write_control(info, LCD_RESET); } -static struct fb_fix_screeninfo cobalt_lcdfb_fix __initdata = { +static struct fb_fix_screeninfo cobalt_lcdfb_fix __devinitdata = { .id = "cobalt-lcd", .type = FB_TYPE_TEXT, .type_aux = FB_AUX_TEXT_MDA, -- cgit v1.2.1 From 8bed90557d2600d25e58de30df48b244980164ec Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 30 Apr 2010 16:07:00 +0000 Subject: sh: fix a number of Oopses and leaks in SH framebuffer driver Fix a number of Oopses, memory leaks and unbalanced calls on error paths in sh_mobile_lcdcfb.c. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_lcdcfb.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index e14bd0749129..e8c769944812 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -695,6 +695,7 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev, * 1) Enable Runtime PM * 2) Force Runtime PM Resume since hardware is accessed from probe() */ + priv->dev = &pdev->dev; pm_runtime_enable(priv->dev); pm_runtime_resume(priv->dev); return 0; @@ -957,25 +958,24 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) if (!pdev->dev.platform_data) { dev_err(&pdev->dev, "no platform data defined\n"); - error = -EINVAL; - goto err0; + return -EINVAL; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); i = platform_get_irq(pdev, 0); if (!res || i < 0) { dev_err(&pdev->dev, "cannot get platform resources\n"); - error = -ENOENT; - goto err0; + return -ENOENT; } priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { dev_err(&pdev->dev, "cannot allocate device data\n"); - error = -ENOMEM; - goto err0; + return -ENOMEM; } + platform_set_drvdata(pdev, priv); + error = request_irq(i, sh_mobile_lcdc_irq, IRQF_DISABLED, dev_name(&pdev->dev), priv); if (error) { @@ -984,8 +984,6 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) } priv->irq = i; - priv->dev = &pdev->dev; - platform_set_drvdata(pdev, priv); pdata = pdev->dev.platform_data; j = 0; @@ -1099,9 +1097,9 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) info = ch->info; if (info->fbdefio) { - priv->ch->sglist = vmalloc(sizeof(struct scatterlist) * + ch->sglist = vmalloc(sizeof(struct scatterlist) * info->fix.smem_len >> PAGE_SHIFT); - if (!priv->ch->sglist) { + if (!ch->sglist) { dev_err(&pdev->dev, "cannot allocate sglist\n"); goto err1; } @@ -1126,9 +1124,9 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) } return 0; - err1: +err1: sh_mobile_lcdc_remove(pdev); - err0: + return error; } @@ -1139,7 +1137,7 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev) int i; for (i = 0; i < ARRAY_SIZE(priv->ch); i++) - if (priv->ch[i].info->dev) + if (priv->ch[i].info && priv->ch[i].info->dev) unregister_framebuffer(priv->ch[i].info); sh_mobile_lcdc_stop(priv); @@ -1162,7 +1160,8 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev) if (priv->dot_clk) clk_put(priv->dot_clk); - pm_runtime_disable(priv->dev); + if (priv->dev) + pm_runtime_disable(priv->dev); if (priv->base) iounmap(priv->base); -- cgit v1.2.1 From f045f77bc0bf238a871b10bea9e425329a8e4abc Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Tue, 1 Dec 2009 20:29:39 -0700 Subject: viafb: Move core stuff into via-core.c The first step toward turning viafb into a multifunction driver. This patch creates a new via-core.c file which serves as the main PCI driver; everything else comes below that. Some work has been done to rationalize the i2c drivers in this new scheme. Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Cc: Harald Welte Acked-by: Florian Tobias Schandinat Signed-off-by: Jonathan Corbet --- drivers/video/via/Makefile | 2 +- drivers/video/via/dvi.c | 4 +- drivers/video/via/global.h | 1 + drivers/video/via/lcd.c | 10 ++-- drivers/video/via/via-core.c | 116 +++++++++++++++++++++++++++++++++++++++++++ drivers/video/via/via-core.h | 55 ++++++++++++++++++++ drivers/video/via/via_i2c.c | 74 ++++++++++++--------------- drivers/video/via/via_i2c.h | 26 ++-------- drivers/video/via/viafbdev.c | 69 ++++++------------------- drivers/video/via/viafbdev.h | 17 +++++-- 10 files changed, 242 insertions(+), 132 deletions(-) create mode 100644 drivers/video/via/via-core.c create mode 100644 drivers/video/via/via-core.h (limited to 'drivers/video') diff --git a/drivers/video/via/Makefile b/drivers/video/via/Makefile index eeed238ad6a2..aec3f8b24a96 100644 --- a/drivers/video/via/Makefile +++ b/drivers/video/via/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_FB_VIA) += viafb.o -viafb-y :=viafbdev.o hw.o via_i2c.o dvi.o lcd.o ioctl.o accel.o via_utility.o vt1636.o global.o tblDPASetting.o viamode.o tbl1636.o +viafb-y :=viafbdev.o hw.o via_i2c.o dvi.o lcd.o ioctl.o accel.o via_utility.o vt1636.o global.o tblDPASetting.o viamode.o tbl1636.o via-core.o diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c index be513701e4e6..e357c4d1cd0f 100644 --- a/drivers/video/via/dvi.c +++ b/drivers/video/via/dvi.c @@ -96,7 +96,7 @@ int viafb_tmds_trasmitter_identify(void) viaparinfo->chip_info->tmds_chip_info.tmds_chip_name = VT1632_TMDS; viaparinfo->chip_info-> tmds_chip_info.tmds_chip_slave_addr = VT1632_TMDS_I2C_ADDR; - viaparinfo->chip_info->tmds_chip_info.i2c_port = VIA_I2C_ADAP_31; + viaparinfo->chip_info->tmds_chip_info.i2c_port = VIA_PORT_31; if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID) != FAIL) { /* * Currently only support 12bits,dual edge,add 24bits mode later @@ -110,7 +110,7 @@ int viafb_tmds_trasmitter_identify(void) viaparinfo->chip_info->tmds_chip_info.i2c_port); return OK; } else { - viaparinfo->chip_info->tmds_chip_info.i2c_port = VIA_I2C_ADAP_2C; + viaparinfo->chip_info->tmds_chip_info.i2c_port = VIA_PORT_2C; if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID) != FAIL) { tmds_register_write(0x08, 0x3b); diff --git a/drivers/video/via/global.h b/drivers/video/via/global.h index 8d95d5fd1388..be48e73da045 100644 --- a/drivers/video/via/global.h +++ b/drivers/video/via/global.h @@ -35,6 +35,7 @@ #include "debug.h" +#include "via-core.h" #include "viafbdev.h" #include "chip.h" #include "accel.h" diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c index e19441d9e49f..8ef60c035fa2 100644 --- a/drivers/video/via/lcd.c +++ b/drivers/video/via/lcd.c @@ -172,14 +172,14 @@ static bool lvds_identify_integratedlvds(void) int viafb_lvds_trasmitter_identify(void) { - if (viafb_lvds_identify_vt1636(VIA_I2C_ADAP_31)) { - viaparinfo->chip_info->lvds_chip_info.i2c_port = VIA_I2C_ADAP_31; + if (viafb_lvds_identify_vt1636(VIA_PORT_31)) { + viaparinfo->chip_info->lvds_chip_info.i2c_port = VIA_PORT_31; DEBUG_MSG(KERN_INFO "Found VIA VT1636 LVDS on port i2c 0x31\n"); } else { - if (viafb_lvds_identify_vt1636(VIA_I2C_ADAP_2C)) { + if (viafb_lvds_identify_vt1636(VIA_PORT_2C)) { viaparinfo->chip_info->lvds_chip_info.i2c_port = - VIA_I2C_ADAP_2C; + VIA_PORT_2C; DEBUG_MSG(KERN_INFO "Found VIA VT1636 LVDS on port gpio 0x2c\n"); } @@ -419,7 +419,7 @@ static int lvds_register_read(int index) { u8 data; - viafb_i2c_readbyte(VIA_I2C_ADAP_2C, + viafb_i2c_readbyte(VIA_PORT_2C, (u8) viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr, (u8) index, &data); return data; diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c new file mode 100644 index 000000000000..e7201470cf35 --- /dev/null +++ b/drivers/video/via/via-core.c @@ -0,0 +1,116 @@ +/* + * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + * Copyright 2009 Jonathan Corbet + */ + +/* + * Core code for the Via multifunction framebuffer device. + */ +#include +#include +#include "global.h" /* Includes everything under the sun */ + +/* + * The default port config. + */ +static struct via_port_cfg adap_configs[] = { + [VIA_PORT_26] = { VIA_PORT_I2C, VIA_MODE_OFF, VIASR, 0x26 }, + [VIA_PORT_31] = { VIA_PORT_I2C, VIA_MODE_I2C, VIASR, 0x31 }, + [VIA_PORT_25] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x25 }, + [VIA_PORT_2C] = { VIA_PORT_GPIO, VIA_MODE_I2C, VIASR, 0x2c }, + [VIA_PORT_3D] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x3d }, + { 0, 0, 0, 0 } +}; + + +static int __devinit via_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int ret; + + ret = pci_enable_device(pdev); + if (ret) + return ret; + /* + * Create the I2C busses. Bailing out on failure seems extreme, + * but that's what the code did before. + */ + ret = viafb_create_i2c_busses(adap_configs); + if (ret) + goto out_disable; + /* + * Set up the framebuffer. + */ + ret = via_fb_pci_probe(pdev, ent); + if (ret) + goto out_i2c; + return 0; + +out_i2c: + viafb_delete_i2c_busses(); +out_disable: + pci_disable_device(pdev); + return ret; +} + +static void __devexit via_pci_remove(struct pci_dev *pdev) +{ + viafb_delete_i2c_busses(); + via_fb_pci_remove(pdev); + pci_disable_device(pdev); +} + + +static struct pci_device_id via_pci_table[] __devinitdata = { + { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CLE266_DID), + .driver_data = UNICHROME_CLE266 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_PM800_DID), + .driver_data = UNICHROME_PM800 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K400_DID), + .driver_data = UNICHROME_K400 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K800_DID), + .driver_data = UNICHROME_K800 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M890_DID), + .driver_data = UNICHROME_CN700 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K8M890_DID), + .driver_data = UNICHROME_K8M890 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CX700_DID), + .driver_data = UNICHROME_CX700 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M900_DID), + .driver_data = UNICHROME_P4M900 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CN750_DID), + .driver_data = UNICHROME_CN750 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX800_DID), + .driver_data = UNICHROME_VX800 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX855_DID), + .driver_data = UNICHROME_VX855 }, + { } +}; +MODULE_DEVICE_TABLE(pci, via_pci_table); + +static struct pci_driver via_driver = { + .name = "viafb", + .id_table = via_pci_table, + .probe = via_pci_probe, + .remove = __devexit_p(via_pci_remove), +}; + +static int __init via_core_init(void) +{ + int ret; + + ret = viafb_init(); + if (ret) + return ret; + return pci_register_driver(&via_driver); +} + +static void __exit via_core_exit(void) +{ + pci_unregister_driver(&via_driver); + viafb_exit(); +} + +module_init(via_core_init); +module_exit(via_core_exit); diff --git a/drivers/video/via/via-core.h b/drivers/video/via/via-core.h new file mode 100644 index 000000000000..1c2fb06b77ae --- /dev/null +++ b/drivers/video/via/via-core.h @@ -0,0 +1,55 @@ +/* + * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + * Copyright 2009 Jonathan Corbet + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __VIA_CORE_H__ +#define __VIA_CORE_H__ +/* + * A description of each known serial I2C/GPIO port. + */ +enum via_port_type { + VIA_PORT_NONE = 0, + VIA_PORT_I2C, + VIA_PORT_GPIO, +}; + +enum via_port_mode { + VIA_MODE_OFF = 0, + VIA_MODE_I2C, /* Used as I2C port */ + VIA_MODE_GPIO, /* Two GPIO ports */ +}; + +enum viafb_i2c_adap { + VIA_PORT_26 = 0, + VIA_PORT_31, + VIA_PORT_25, + VIA_PORT_2C, + VIA_PORT_3D, +}; +#define VIAFB_NUM_PORTS 5 + +struct via_port_cfg { + enum via_port_type type; + enum via_port_mode mode; + u_int16_t io_port; + u_int8_t ioport_index; +}; +#endif /* __VIA_CORE_H__ */ diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c index b5253e3099f8..478829281562 100644 --- a/drivers/video/via/via_i2c.c +++ b/drivers/video/via/via_i2c.c @@ -21,13 +21,18 @@ #include "global.h" +/* + * There can only be one set of these, so there's no point in having + * them be dynamically allocated... + */ +#define VIAFB_NUM_I2C 5 +static struct via_i2c_stuff via_i2c_par[VIAFB_NUM_I2C]; + static void via_i2c_setscl(void *data, int state) { u8 val; - struct via_i2c_adap_cfg *adap_data = data; + struct via_port_cfg *adap_data = data; - DEBUG_MSG(KERN_DEBUG "reading index 0x%02x from IO 0x%x\n", - adap_data->ioport_index, adap_data->io_port); val = viafb_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0; if (state) @@ -35,10 +40,10 @@ static void via_i2c_setscl(void *data, int state) else val &= ~0x20; switch (adap_data->type) { - case VIA_I2C_I2C: + case VIA_PORT_I2C: val |= 0x01; break; - case VIA_I2C_GPIO: + case VIA_PORT_GPIO: val |= 0x80; break; default: @@ -50,7 +55,7 @@ static void via_i2c_setscl(void *data, int state) static int via_i2c_getscl(void *data) { - struct via_i2c_adap_cfg *adap_data = data; + struct via_port_cfg *adap_data = data; if (viafb_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x08) return 1; @@ -59,7 +64,7 @@ static int via_i2c_getscl(void *data) static int via_i2c_getsda(void *data) { - struct via_i2c_adap_cfg *adap_data = data; + struct via_port_cfg *adap_data = data; if (viafb_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x04) return 1; @@ -69,7 +74,7 @@ static int via_i2c_getsda(void *data) static void via_i2c_setsda(void *data, int state) { u8 val; - struct via_i2c_adap_cfg *adap_data = data; + struct via_port_cfg *adap_data = data; val = viafb_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0; @@ -78,10 +83,10 @@ static void via_i2c_setsda(void *data, int state) else val &= ~0x10; switch (adap_data->type) { - case VIA_I2C_I2C: + case VIA_PORT_I2C: val |= 0x01; break; - case VIA_I2C_GPIO: + case VIA_PORT_GPIO: val |= 0x40; break; default: @@ -103,8 +108,7 @@ int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata) mm1[0] = index; msgs[0].len = 1; msgs[1].len = 1; msgs[0].buf = mm1; msgs[1].buf = pdata; - return i2c_transfer(&viaparinfo->shared->i2c_stuff[adap].adapter, - msgs, 2); + return i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2); } int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data) @@ -116,8 +120,7 @@ int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data) msgs.addr = slave_addr / 2; msgs.len = 2; msgs.buf = msg; - return i2c_transfer(&viaparinfo->shared->i2c_stuff[adap].adapter, - &msgs, 1); + return i2c_transfer(&via_i2c_par[adap].adapter, &msgs, 1); } int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len) @@ -131,13 +134,12 @@ int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len mm1[0] = index; msgs[0].len = 1; msgs[1].len = buff_len; msgs[0].buf = mm1; msgs[1].buf = buff; - return i2c_transfer(&viaparinfo->shared->i2c_stuff[adap].adapter, - msgs, 2); + return i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2); } static int create_i2c_bus(struct i2c_adapter *adapter, struct i2c_algo_bit_data *algo, - struct via_i2c_adap_cfg *adap_cfg, + struct via_port_cfg *adap_cfg, struct pci_dev *pdev) { DEBUG_MSG(KERN_DEBUG "viafb: creating bus adap=0x%p, algo_bit_data=0x%p, adap_cfg=0x%p\n", adapter, algo, adap_cfg); @@ -170,31 +172,15 @@ static int create_i2c_bus(struct i2c_adapter *adapter, return i2c_bit_add_bus(adapter); } -/* - * By default, we only activate busses on ports 2c and 31 to avoid - * conflicts with other possible users; that default can be changed - * below. - */ -static struct via_i2c_adap_cfg adap_configs[] = { - [VIA_I2C_ADAP_26] = { VIA_I2C_I2C, VIASR, 0x26, 0 }, - [VIA_I2C_ADAP_31] = { VIA_I2C_I2C, VIASR, 0x31, 1 }, - [VIA_I2C_ADAP_25] = { VIA_I2C_GPIO, VIASR, 0x25, 0 }, - [VIA_I2C_ADAP_2C] = { VIA_I2C_GPIO, VIASR, 0x2c, 1 }, - [VIA_I2C_ADAP_3D] = { VIA_I2C_GPIO, VIASR, 0x3d, 0 }, - { 0, 0, 0, 0 } -}; - -int viafb_create_i2c_busses(struct viafb_par *viapar) +int viafb_create_i2c_busses(struct via_port_cfg *configs) { int i, ret; - for (i = 0; i < VIAFB_NUM_I2C; i++) { - struct via_i2c_adap_cfg *adap_cfg = &adap_configs[i]; - struct via_i2c_stuff *i2c_stuff = &viapar->shared->i2c_stuff[i]; + for (i = 0; i < VIAFB_NUM_PORTS; i++) { + struct via_port_cfg *adap_cfg = configs++; + struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i]; - if (adap_cfg->type == 0) - break; - if (!adap_cfg->is_active) + if (adap_cfg->type == 0 || adap_cfg->mode != VIA_MODE_I2C) continue; ret = create_i2c_bus(&i2c_stuff->adapter, @@ -211,14 +197,16 @@ int viafb_create_i2c_busses(struct viafb_par *viapar) return 0; } -void viafb_delete_i2c_busses(struct viafb_par *par) +void viafb_delete_i2c_busses(void) { int i; - for (i = 0; i < ARRAY_SIZE(par->shared->i2c_stuff); i++) { - struct via_i2c_stuff *i2c_stuff = &par->shared->i2c_stuff[i]; - /* only remove those entries in the array that we've - * actually used (and thus initialized algo_data) */ + for (i = 0; i < VIAFB_NUM_PORTS; i++) { + struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i]; + /* + * Only remove those entries in the array that we've + * actually used (and thus initialized algo_data) + */ if (i2c_stuff->adapter.algo_data == &i2c_stuff->algo) i2c_del_adapter(&i2c_stuff->adapter); } diff --git a/drivers/video/via/via_i2c.h b/drivers/video/via/via_i2c.h index 73d682fcf269..00932914b4ed 100644 --- a/drivers/video/via/via_i2c.h +++ b/drivers/video/via/via_i2c.h @@ -24,39 +24,19 @@ #include #include -enum via_i2c_type { - VIA_I2C_NONE, - VIA_I2C_I2C, - VIA_I2C_GPIO, -}; - -/* private data for each adapter */ -struct via_i2c_adap_cfg { - enum via_i2c_type type; - u_int16_t io_port; - u_int8_t ioport_index; - u8 is_active; -}; - struct via_i2c_stuff { u16 i2c_port; /* GPIO or I2C port */ struct i2c_adapter adapter; struct i2c_algo_bit_data algo; }; -enum viafb_i2c_adap { - VIA_I2C_ADAP_26, - VIA_I2C_ADAP_31, - VIA_I2C_ADAP_25, - VIA_I2C_ADAP_2C, - VIA_I2C_ADAP_3D, -}; int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata); int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data); int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len); struct viafb_par; -int viafb_create_i2c_busses(struct viafb_par *par); -void viafb_delete_i2c_busses(struct viafb_par *par); +int viafb_create_i2c_busses(struct via_port_cfg *cfg); +void viafb_delete_i2c_busses(void); +struct i2c_adapter *viafb_find_adapter(enum viafb_i2c_adap which); #endif /* __VIA_I2C_H__ */ diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index fa1004997c63..17a874f6ea1c 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -1731,8 +1731,9 @@ static int parse_mode(const char *str, u32 *xres, u32 *yres) return 0; } -static int __devinit via_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) + +int __devinit via_fb_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { u32 default_xres, default_yres; struct VideoModeTable *vmode_entry; @@ -1764,6 +1765,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, &viaparinfo->shared->lvds_setting_info2; viaparinfo->crt_setting_info = &viaparinfo->shared->crt_setting_info; viaparinfo->chip_info = &viaparinfo->shared->chip_info; + spin_lock_init(&viaparinfo->reg_lock); if (viafb_dual_fb) viafb_SAMM_ON = 1; @@ -1774,26 +1776,21 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, if (!viafb_SAMM_ON) viafb_dual_fb = 0; - /* Set up I2C bus stuff */ - rc = viafb_create_i2c_busses(viaparinfo); - if (rc) - goto out_fb_release; - viafb_init_chip_info(pdev, ent); viaparinfo->fbmem = pci_resource_start(pdev, 0); viaparinfo->memsize = viafb_get_fb_size_from_pci(); if (viaparinfo->memsize < 0) { rc = viaparinfo->memsize; - goto out_delete_i2c; + goto out_fb_release; } viaparinfo->fbmem_free = viaparinfo->memsize; viaparinfo->fbmem_used = 0; viafbinfo->screen_base = ioremap_nocache(viaparinfo->fbmem, viaparinfo->memsize); if (!viafbinfo->screen_base) { - printk(KERN_INFO "ioremap failed\n"); + printk(KERN_ERR "ioremap of fbmem failed\n"); rc = -ENOMEM; - goto out_delete_i2c; + goto out_fb_release; } viafbinfo->fix.mmio_start = pci_resource_start(pdev, 1); @@ -1963,14 +1960,12 @@ out_fb1_release: framebuffer_release(viafbinfo1); out_unmap_screen: iounmap(viafbinfo->screen_base); -out_delete_i2c: - viafb_delete_i2c_busses(viaparinfo); out_fb_release: framebuffer_release(viafbinfo); return rc; } -static void __devexit via_pci_remove(struct pci_dev *pdev) +void __devexit via_fb_pci_remove(struct pci_dev *pdev) { DEBUG_MSG(KERN_INFO "via_pci_remove!\n"); fb_dealloc_cmap(&viafbinfo->cmap); @@ -1980,8 +1975,6 @@ static void __devexit via_pci_remove(struct pci_dev *pdev) iounmap((void *)viafbinfo->screen_base); iounmap(viaparinfo->shared->engine_mmio); - viafb_delete_i2c_busses(viaparinfo); - framebuffer_release(viafbinfo); if (viafb_dual_fb) framebuffer_release(viafbinfo1); @@ -2062,41 +2055,10 @@ static int __init viafb_setup(char *options) } #endif -static struct pci_device_id viafb_pci_table[] __devinitdata = { - { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CLE266_DID), - .driver_data = UNICHROME_CLE266 }, - { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_PM800_DID), - .driver_data = UNICHROME_PM800 }, - { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K400_DID), - .driver_data = UNICHROME_K400 }, - { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K800_DID), - .driver_data = UNICHROME_K800 }, - { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M890_DID), - .driver_data = UNICHROME_CN700 }, - { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K8M890_DID), - .driver_data = UNICHROME_K8M890 }, - { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CX700_DID), - .driver_data = UNICHROME_CX700 }, - { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M900_DID), - .driver_data = UNICHROME_P4M900 }, - { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CN750_DID), - .driver_data = UNICHROME_CN750 }, - { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX800_DID), - .driver_data = UNICHROME_VX800 }, - { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX855_DID), - .driver_data = UNICHROME_VX855 }, - { } -}; -MODULE_DEVICE_TABLE(pci, viafb_pci_table); - -static struct pci_driver viafb_driver = { - .name = "viafb", - .id_table = viafb_pci_table, - .probe = via_pci_probe, - .remove = __devexit_p(via_pci_remove), -}; - -static int __init viafb_init(void) +/* + * These are called out of via-core for now. + */ +int __init viafb_init(void) { u32 dummy; #ifndef MODULE @@ -2115,13 +2077,12 @@ static int __init viafb_init(void) printk(KERN_INFO "VIA Graphics Intergration Chipset framebuffer %d.%d initializing\n", VERSION_MAJOR, VERSION_MINOR); - return pci_register_driver(&viafb_driver); + return 0; } -static void __exit viafb_exit(void) +void __exit viafb_exit(void) { DEBUG_MSG(KERN_INFO "viafb_exit!\n"); - pci_unregister_driver(&viafb_driver); } static struct fb_ops viafb_ops = { @@ -2141,8 +2102,6 @@ static struct fb_ops viafb_ops = { .fb_sync = viafb_sync, }; -module_init(viafb_init); -module_exit(viafb_exit); #ifdef MODULE module_param(viafb_mode, charp, S_IRUSR); diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h index 4bc00ec8fb1c..5604f27eb74e 100644 --- a/drivers/video/via/viafbdev.h +++ b/drivers/video/via/viafbdev.h @@ -24,6 +24,7 @@ #include #include +#include #include "ioctl.h" #include "share.h" @@ -42,9 +43,6 @@ struct viafb_shared { struct proc_dir_entry *proc_entry; /*viafb proc entry */ - /* I2C stuff */ - struct via_i2c_stuff i2c_stuff[VIAFB_NUM_I2C]; - /* All the information will be needed to set engine */ struct tmds_setting_information tmds_setting_info; struct crt_setting_information crt_setting_info; @@ -74,6 +72,14 @@ struct viafb_par { struct viafb_shared *shared; + /* + * (jc) I believe one should use locking to protect against + * concurrent access to the device ports and registers. Thus, + * this lock. Use of it is *far* from universal, though... + * someday... + */ + spinlock_t reg_lock; + /* All the information will be needed to set engine */ /* depreciated, use the ones in shared directly */ struct tmds_setting_information *tmds_setting_info; @@ -101,4 +107,9 @@ u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information void viafb_gpio_i2c_write_mask_lvds(struct lvds_setting_information *plvds_setting_info, struct lvds_chip_information *plvds_chip_info, struct IODATA io_data); +int via_fb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); +void via_fb_pci_remove(struct pci_dev *pdev); +/* Temporary */ +int viafb_init(void); +void viafb_exit(void); #endif /* __VIAFBDEV_H__ */ -- cgit v1.2.1 From 24b4d82e4715841848a499534ed5cb7db3d6bca3 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 22 Apr 2010 13:48:09 -0600 Subject: viafb: Separate global and fb-specific data This patch moves data of interest into a new viafb_dev structure which describes the device as a whole; the idea here is to create a separation between what all devices may need and what the framebuffer device in particular needs. I've also made some small steps toward thinning out the global.h mess. Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Cc: Harald Welte Acked-by: Florian Tobias Schandinat Signed-off-by: Jonathan Corbet --- drivers/video/via/accel.c | 14 ++-- drivers/video/via/dvi.c | 2 + drivers/video/via/global.h | 2 - drivers/video/via/hw.c | 131 ++---------------------------- drivers/video/via/hw.h | 4 +- drivers/video/via/lcd.c | 3 +- drivers/video/via/via-core.c | 185 ++++++++++++++++++++++++++++++++++++++++++- drivers/video/via/via-core.h | 38 ++++++++- drivers/video/via/via_i2c.c | 2 + drivers/video/via/viafbdev.c | 54 ++++++------- drivers/video/via/viafbdev.h | 13 +-- drivers/video/via/vt1636.c | 2 + 12 files changed, 265 insertions(+), 185 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c index 0d90c859cc1c..e77746857c8f 100644 --- a/drivers/video/via/accel.c +++ b/drivers/video/via/accel.c @@ -18,6 +18,7 @@ * Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "via-core.h" #include "global.h" /* @@ -321,8 +322,7 @@ int viafb_init_engine(struct fb_info *info) u32 vq_start_addr, vq_end_addr, vq_start_low, vq_end_low, vq_high, vq_len, chip_name = viapar->shared->chip_info.gfx_chip_name; - engine = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len); - viapar->shared->engine_mmio = engine; + engine = viapar->shared->vdev->engine_mmio; if (!engine) { printk(KERN_WARNING "viafb_init_accel: ioremap failed, " "hardware acceleration disabled\n"); @@ -465,7 +465,7 @@ void viafb_show_hw_cursor(struct fb_info *info, int Status) struct viafb_par *viapar = info->par; u32 temp, iga_path = viapar->iga_path; - temp = readl(viapar->shared->engine_mmio + VIA_REG_CURSOR_MODE); + temp = readl(viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE); switch (Status) { case HW_Cursor_ON: temp |= 0x1; @@ -482,7 +482,7 @@ void viafb_show_hw_cursor(struct fb_info *info, int Status) default: temp &= 0x7FFFFFFF; } - writel(temp, viapar->shared->engine_mmio + VIA_REG_CURSOR_MODE); + writel(temp, viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE); } void viafb_wait_engine_idle(struct fb_info *info) @@ -490,6 +490,7 @@ void viafb_wait_engine_idle(struct fb_info *info) struct viafb_par *viapar = info->par; int loop = 0; u32 mask; + void __iomem *engine = viapar->shared->vdev->engine_mmio; switch (viapar->shared->chip_info.twod_engine) { case VIA_2D_ENG_H5: @@ -498,7 +499,7 @@ void viafb_wait_engine_idle(struct fb_info *info) VIA_3D_ENG_BUSY_M1; break; default: - while (!(readl(viapar->shared->engine_mmio + VIA_REG_STATUS) & + while (!(readl(engine + VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) { loop++; cpu_relax(); @@ -507,8 +508,7 @@ void viafb_wait_engine_idle(struct fb_info *info) break; } - while ((readl(viapar->shared->engine_mmio + VIA_REG_STATUS) & mask) && - (loop < MAXLOOP)) { + while ((readl(engine + VIA_REG_STATUS) & mask) && (loop < MAXLOOP)) { loop++; cpu_relax(); } diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c index e357c4d1cd0f..6271b7696323 100644 --- a/drivers/video/via/dvi.c +++ b/drivers/video/via/dvi.c @@ -18,6 +18,8 @@ * Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "via-core.h" +#include "via_i2c.h" #include "global.h" static void tmds_register_write(int index, u8 data); diff --git a/drivers/video/via/global.h b/drivers/video/via/global.h index be48e73da045..28221a062dda 100644 --- a/drivers/video/via/global.h +++ b/drivers/video/via/global.h @@ -35,14 +35,12 @@ #include "debug.h" -#include "via-core.h" #include "viafbdev.h" #include "chip.h" #include "accel.h" #include "share.h" #include "dvi.h" #include "viamode.h" -#include "via_i2c.h" #include "hw.h" #include "lcd.h" diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index 2322612fbb95..f2425ae228ae 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -18,7 +18,7 @@ * Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - +#include "via-core.h" #include "global.h" static struct pll_map pll_value[] = { @@ -526,8 +526,7 @@ static void dvi_patch_skew_dvp_low(void); static void set_dvi_output_path(int set_iga, int output_interface); static void set_lcd_output_path(int set_iga, int output_interface); static void load_fix_bit_crtc_reg(void); -static void init_gfx_chip_info(struct pci_dev *pdev, - const struct pci_device_id *pdi); +static void init_gfx_chip_info(int chip_type); static void init_tmds_chip_info(void); static void init_lvds_chip_info(void); static void device_screen_off(void); @@ -1911,10 +1910,9 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, } -void viafb_init_chip_info(struct pci_dev *pdev, - const struct pci_device_id *pdi) +void viafb_init_chip_info(int chip_type) { - init_gfx_chip_info(pdev, pdi); + init_gfx_chip_info(chip_type); init_tmds_chip_info(); init_lvds_chip_info(); @@ -1981,12 +1979,11 @@ void viafb_update_device_setting(int hres, int vres, } } -static void init_gfx_chip_info(struct pci_dev *pdev, - const struct pci_device_id *pdi) +static void init_gfx_chip_info(int chip_type) { u8 tmp; - viaparinfo->chip_info->gfx_chip_name = pdi->driver_data; + viaparinfo->chip_info->gfx_chip_name = chip_type; /* Check revision of CLE266 Chip */ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) { @@ -2489,122 +2486,6 @@ static void disable_second_display_channel(void) viafb_write_reg_mask(CR6A, VIACR, BIT6, BIT6); } -static u_int16_t via_function3[] = { - CLE266_FUNCTION3, KM400_FUNCTION3, CN400_FUNCTION3, CN700_FUNCTION3, - CX700_FUNCTION3, KM800_FUNCTION3, KM890_FUNCTION3, P4M890_FUNCTION3, - P4M900_FUNCTION3, VX800_FUNCTION3, VX855_FUNCTION3, -}; - -/* Get the BIOS-configured framebuffer size from PCI configuration space - * of function 3 in the respective chipset */ -int viafb_get_fb_size_from_pci(void) -{ - int i; - u_int8_t offset = 0; - u_int32_t FBSize; - u_int32_t VideoMemSize; - - /* search for the "FUNCTION3" device in this chipset */ - for (i = 0; i < ARRAY_SIZE(via_function3); i++) { - struct pci_dev *pdev; - - pdev = pci_get_device(PCI_VENDOR_ID_VIA, via_function3[i], - NULL); - if (!pdev) - continue; - - DEBUG_MSG(KERN_INFO "Device ID = %x\n", pdev->device); - - switch (pdev->device) { - case CLE266_FUNCTION3: - case KM400_FUNCTION3: - offset = 0xE0; - break; - case CN400_FUNCTION3: - case CN700_FUNCTION3: - case CX700_FUNCTION3: - case KM800_FUNCTION3: - case KM890_FUNCTION3: - case P4M890_FUNCTION3: - case P4M900_FUNCTION3: - case VX800_FUNCTION3: - case VX855_FUNCTION3: - /*case CN750_FUNCTION3: */ - offset = 0xA0; - break; - } - - if (!offset) - break; - - pci_read_config_dword(pdev, offset, &FBSize); - pci_dev_put(pdev); - } - - if (!offset) { - printk(KERN_ERR "cannot determine framebuffer size\n"); - return -EIO; - } - - FBSize = FBSize & 0x00007000; - DEBUG_MSG(KERN_INFO "FB Size = %x\n", FBSize); - - if (viaparinfo->chip_info->gfx_chip_name < UNICHROME_CX700) { - switch (FBSize) { - case 0x00004000: - VideoMemSize = (16 << 20); /*16M */ - break; - - case 0x00005000: - VideoMemSize = (32 << 20); /*32M */ - break; - - case 0x00006000: - VideoMemSize = (64 << 20); /*64M */ - break; - - default: - VideoMemSize = (32 << 20); /*32M */ - break; - } - } else { - switch (FBSize) { - case 0x00001000: - VideoMemSize = (8 << 20); /*8M */ - break; - - case 0x00002000: - VideoMemSize = (16 << 20); /*16M */ - break; - - case 0x00003000: - VideoMemSize = (32 << 20); /*32M */ - break; - - case 0x00004000: - VideoMemSize = (64 << 20); /*64M */ - break; - - case 0x00005000: - VideoMemSize = (128 << 20); /*128M */ - break; - - case 0x00006000: - VideoMemSize = (256 << 20); /*256M */ - break; - - case 0x00007000: /* Only on VX855/875 */ - VideoMemSize = (512 << 20); /*512M */ - break; - - default: - VideoMemSize = (32 << 20); /*32M */ - break; - } - } - - return VideoMemSize; -} void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\ *p_gfx_dpa_setting) diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index d6b25acd4a99..d248f4dc12ec 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h @@ -900,15 +900,13 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, struct VideoModeTable *vmode_tbl1, int video_bpp1); void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh, struct VideoModeTable *vmode_tbl); -void viafb_init_chip_info(struct pci_dev *pdev, - const struct pci_device_id *pdi); +void viafb_init_chip_info(int chip_type); void viafb_init_dac(int set_iga); int viafb_get_pixclock(int hres, int vres, int vmode_refresh); int viafb_get_refresh(int hres, int vres, u32 float_refresh); void viafb_update_device_setting(int hres, int vres, int bpp, int vmode_refresh, int flag); -int viafb_get_fb_size_from_pci(void); void viafb_set_iga_path(void); void viafb_set_primary_address(u32 addr); void viafb_set_secondary_address(u32 addr); diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c index 8ef60c035fa2..04eec31aa9a2 100644 --- a/drivers/video/via/lcd.c +++ b/drivers/video/via/lcd.c @@ -18,7 +18,8 @@ * Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - +#include "via-core.h" +#include "via_i2c.h" #include "global.h" #include "lcdtbl.h" diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c index e7201470cf35..b77cd5c2fc96 100644 --- a/drivers/video/via/via-core.c +++ b/drivers/video/via/via-core.c @@ -7,9 +7,12 @@ /* * Core code for the Via multifunction framebuffer device. */ +#include "via-core.h" +#include "via_i2c.h" +#include "global.h" + #include #include -#include "global.h" /* Includes everything under the sun */ /* * The default port config. @@ -23,6 +26,169 @@ static struct via_port_cfg adap_configs[] = { { 0, 0, 0, 0 } }; +/* + * We currently only support one viafb device (will there ever be + * more than one?), so just declare it globally here. + */ +static struct viafb_dev global_dev; + + +/* + * Figure out how big our framebuffer memory is. Kind of ugly, + * but evidently we can't trust the information found in the + * fbdev configuration area. + */ +static u16 via_function3[] = { + CLE266_FUNCTION3, KM400_FUNCTION3, CN400_FUNCTION3, CN700_FUNCTION3, + CX700_FUNCTION3, KM800_FUNCTION3, KM890_FUNCTION3, P4M890_FUNCTION3, + P4M900_FUNCTION3, VX800_FUNCTION3, VX855_FUNCTION3, +}; + +/* Get the BIOS-configured framebuffer size from PCI configuration space + * of function 3 in the respective chipset */ +static int viafb_get_fb_size_from_pci(int chip_type) +{ + int i; + u8 offset = 0; + u32 FBSize; + u32 VideoMemSize; + + /* search for the "FUNCTION3" device in this chipset */ + for (i = 0; i < ARRAY_SIZE(via_function3); i++) { + struct pci_dev *pdev; + + pdev = pci_get_device(PCI_VENDOR_ID_VIA, via_function3[i], + NULL); + if (!pdev) + continue; + + DEBUG_MSG(KERN_INFO "Device ID = %x\n", pdev->device); + + switch (pdev->device) { + case CLE266_FUNCTION3: + case KM400_FUNCTION3: + offset = 0xE0; + break; + case CN400_FUNCTION3: + case CN700_FUNCTION3: + case CX700_FUNCTION3: + case KM800_FUNCTION3: + case KM890_FUNCTION3: + case P4M890_FUNCTION3: + case P4M900_FUNCTION3: + case VX800_FUNCTION3: + case VX855_FUNCTION3: + /*case CN750_FUNCTION3: */ + offset = 0xA0; + break; + } + + if (!offset) + break; + + pci_read_config_dword(pdev, offset, &FBSize); + pci_dev_put(pdev); + } + + if (!offset) { + printk(KERN_ERR "cannot determine framebuffer size\n"); + return -EIO; + } + + FBSize = FBSize & 0x00007000; + DEBUG_MSG(KERN_INFO "FB Size = %x\n", FBSize); + + if (chip_type < UNICHROME_CX700) { + switch (FBSize) { + case 0x00004000: + VideoMemSize = (16 << 20); /*16M */ + break; + + case 0x00005000: + VideoMemSize = (32 << 20); /*32M */ + break; + + case 0x00006000: + VideoMemSize = (64 << 20); /*64M */ + break; + + default: + VideoMemSize = (32 << 20); /*32M */ + break; + } + } else { + switch (FBSize) { + case 0x00001000: + VideoMemSize = (8 << 20); /*8M */ + break; + + case 0x00002000: + VideoMemSize = (16 << 20); /*16M */ + break; + + case 0x00003000: + VideoMemSize = (32 << 20); /*32M */ + break; + + case 0x00004000: + VideoMemSize = (64 << 20); /*64M */ + break; + + case 0x00005000: + VideoMemSize = (128 << 20); /*128M */ + break; + + case 0x00006000: + VideoMemSize = (256 << 20); /*256M */ + break; + + case 0x00007000: /* Only on VX855/875 */ + VideoMemSize = (512 << 20); /*512M */ + break; + + default: + VideoMemSize = (32 << 20); /*32M */ + break; + } + } + + return VideoMemSize; +} + + +/* + * Figure out and map our MMIO regions. + */ +static int __devinit via_pci_setup_mmio(struct viafb_dev *vdev) +{ + /* + * Hook up to the device registers. + */ + vdev->engine_start = pci_resource_start(vdev->pdev, 1); + vdev->engine_len = pci_resource_len(vdev->pdev, 1); + /* If this fails, others will notice later */ + vdev->engine_mmio = ioremap_nocache(vdev->engine_start, + vdev->engine_len); + + /* + * Likewise with I/O memory. + */ + vdev->fbmem_start = pci_resource_start(vdev->pdev, 0); + vdev->fbmem_len = viafb_get_fb_size_from_pci(vdev->chip_type); + if (vdev->fbmem_len < 0) + return vdev->fbmem_len; + vdev->fbmem = ioremap_nocache(vdev->fbmem_start, vdev->fbmem_len); + if (vdev->fbmem == NULL) + return -ENOMEM; + return 0; +} + +static void __devexit via_pci_teardown_mmio(struct viafb_dev *vdev) +{ + iounmap(vdev->fbmem); + iounmap(vdev->engine_mmio); +} + static int __devinit via_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -32,23 +198,35 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, ret = pci_enable_device(pdev); if (ret) return ret; + /* + * Global device initialization. + */ + memset(&global_dev, 0, sizeof(global_dev)); + global_dev.pdev = pdev; + global_dev.chip_type = ent->driver_data; + spin_lock_init(&global_dev.reg_lock); + ret = via_pci_setup_mmio(&global_dev); + if (ret) + goto out_disable; /* * Create the I2C busses. Bailing out on failure seems extreme, * but that's what the code did before. */ ret = viafb_create_i2c_busses(adap_configs); if (ret) - goto out_disable; + goto out_teardown; /* * Set up the framebuffer. */ - ret = via_fb_pci_probe(pdev, ent); + ret = via_fb_pci_probe(&global_dev); if (ret) goto out_i2c; return 0; out_i2c: viafb_delete_i2c_busses(); +out_teardown: + via_pci_teardown_mmio(&global_dev); out_disable: pci_disable_device(pdev); return ret; @@ -58,6 +236,7 @@ static void __devexit via_pci_remove(struct pci_dev *pdev) { viafb_delete_i2c_busses(); via_fb_pci_remove(pdev); + via_pci_teardown_mmio(&global_dev); pci_disable_device(pdev); } diff --git a/drivers/video/via/via-core.h b/drivers/video/via/via-core.h index 1c2fb06b77ae..d004290dc8f1 100644 --- a/drivers/video/via/via-core.h +++ b/drivers/video/via/via-core.h @@ -22,6 +22,9 @@ #ifndef __VIA_CORE_H__ #define __VIA_CORE_H__ +#include +#include + /* * A description of each known serial I2C/GPIO port. */ @@ -49,7 +52,38 @@ enum viafb_i2c_adap { struct via_port_cfg { enum via_port_type type; enum via_port_mode mode; - u_int16_t io_port; - u_int8_t ioport_index; + u16 io_port; + u8 ioport_index; }; + +/* + * This is the global viafb "device" containing stuff needed by + * all subdevs. + */ +struct viafb_dev { + struct pci_dev *pdev; + int chip_type; + /* + * Spinlock for access to device registers. Not yet + * globally used. + */ + spinlock_t reg_lock; + /* + * The framebuffer MMIO region. Little, if anything, touches + * this memory directly, and certainly nothing outside of the + * framebuffer device itself. We *do* have to be able to allocate + * chunks of this memory for other devices, though. + */ + unsigned long fbmem_start; + long fbmem_len; + void __iomem *fbmem; + /* + * The MMIO region for device registers. + */ + unsigned long engine_start; + unsigned long engine_len; + void __iomem *engine_mmio; + +}; + #endif /* __VIA_CORE_H__ */ diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c index 478829281562..bcf2fe61a6ec 100644 --- a/drivers/video/via/via_i2c.c +++ b/drivers/video/via/via_i2c.c @@ -19,6 +19,8 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "via-core.h" +#include "via_i2c.h" #include "global.h" /* diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 17a874f6ea1c..70ed71facd87 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -24,6 +24,7 @@ #include #define _MASTER_FILE +#include "via-core.h" #include "global.h" static char *viafb_name = "Via"; @@ -220,7 +221,7 @@ static int viafb_check_var(struct fb_var_screeninfo *var, /* Adjust var according to our driver's own table */ viafb_fill_var_timing_info(var, viafb_refresh, vmode_entry); if (info->var.accel_flags & FB_ACCELF_TEXT && - !ppar->shared->engine_mmio) + !ppar->shared->vdev->engine_mmio) info->var.accel_flags = 0; return 0; @@ -695,7 +696,7 @@ static void viafb_fillrect(struct fb_info *info, rop = 0xF0; DEBUG_MSG(KERN_DEBUG "viafb 2D engine: fillrect\n"); - if (shared->hw_bitblt(shared->engine_mmio, VIA_BITBLT_FILL, + if (shared->hw_bitblt(shared->vdev->engine_mmio, VIA_BITBLT_FILL, rect->width, rect->height, info->var.bits_per_pixel, viapar->vram_addr, info->fix.line_length, rect->dx, rect->dy, NULL, 0, 0, 0, 0, fg_color, 0, rop)) @@ -717,7 +718,7 @@ static void viafb_copyarea(struct fb_info *info, return; DEBUG_MSG(KERN_DEBUG "viafb 2D engine: copyarea\n"); - if (shared->hw_bitblt(shared->engine_mmio, VIA_BITBLT_COLOR, + if (shared->hw_bitblt(shared->vdev->engine_mmio, VIA_BITBLT_COLOR, area->width, area->height, info->var.bits_per_pixel, viapar->vram_addr, info->fix.line_length, area->dx, area->dy, NULL, viapar->vram_addr, info->fix.line_length, @@ -754,7 +755,7 @@ static void viafb_imageblit(struct fb_info *info, op = VIA_BITBLT_COLOR; DEBUG_MSG(KERN_DEBUG "viafb 2D engine: imageblit\n"); - if (shared->hw_bitblt(shared->engine_mmio, op, + if (shared->hw_bitblt(shared->vdev->engine_mmio, op, image->width, image->height, info->var.bits_per_pixel, viapar->vram_addr, info->fix.line_length, image->dx, image->dy, (u32 *)image->data, 0, 0, 0, 0, fg_color, bg_color, 0)) @@ -764,7 +765,7 @@ static void viafb_imageblit(struct fb_info *info, static int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor) { struct viafb_par *viapar = info->par; - void __iomem *engine = viapar->shared->engine_mmio; + void __iomem *engine = viapar->shared->vdev->engine_mmio; u32 temp, xx, yy, bg_color = 0, fg_color = 0, chip_name = viapar->shared->chip_info.gfx_chip_name; int i, j = 0, cur_size = 64; @@ -1732,8 +1733,7 @@ static int parse_mode(const char *str, u32 *xres, u32 *yres) } -int __devinit via_fb_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) +int __devinit via_fb_pci_probe(struct viafb_dev *vdev) { u32 default_xres, default_yres; struct VideoModeTable *vmode_entry; @@ -1750,7 +1750,7 @@ int __devinit via_fb_pci_probe(struct pci_dev *pdev, */ viafbinfo = framebuffer_alloc(viafb_par_length + ALIGN(sizeof(struct viafb_shared), BITS_PER_LONG/8), - &pdev->dev); + &vdev->pdev->dev); if (!viafbinfo) { printk(KERN_ERR"Could not allocate memory for viafb_info.\n"); return -ENOMEM; @@ -1758,6 +1758,7 @@ int __devinit via_fb_pci_probe(struct pci_dev *pdev, viaparinfo = (struct viafb_par *)viafbinfo->par; viaparinfo->shared = viafbinfo->par + viafb_par_length; + viaparinfo->shared->vdev = vdev; viaparinfo->vram_addr = 0; viaparinfo->tmds_setting_info = &viaparinfo->shared->tmds_setting_info; viaparinfo->lvds_setting_info = &viaparinfo->shared->lvds_setting_info; @@ -1765,7 +1766,6 @@ int __devinit via_fb_pci_probe(struct pci_dev *pdev, &viaparinfo->shared->lvds_setting_info2; viaparinfo->crt_setting_info = &viaparinfo->shared->crt_setting_info; viaparinfo->chip_info = &viaparinfo->shared->chip_info; - spin_lock_init(&viaparinfo->reg_lock); if (viafb_dual_fb) viafb_SAMM_ON = 1; @@ -1776,25 +1776,20 @@ int __devinit via_fb_pci_probe(struct pci_dev *pdev, if (!viafb_SAMM_ON) viafb_dual_fb = 0; - viafb_init_chip_info(pdev, ent); - viaparinfo->fbmem = pci_resource_start(pdev, 0); - viaparinfo->memsize = viafb_get_fb_size_from_pci(); - if (viaparinfo->memsize < 0) { - rc = viaparinfo->memsize; - goto out_fb_release; - } + viafb_init_chip_info(vdev->chip_type); + /* + * The framebuffer will have been successfully mapped by + * the core (or we'd not be here), but we still need to + * set up our own accounting. + */ + viaparinfo->fbmem = vdev->fbmem_start; + viaparinfo->memsize = vdev->fbmem_len; viaparinfo->fbmem_free = viaparinfo->memsize; viaparinfo->fbmem_used = 0; - viafbinfo->screen_base = ioremap_nocache(viaparinfo->fbmem, - viaparinfo->memsize); - if (!viafbinfo->screen_base) { - printk(KERN_ERR "ioremap of fbmem failed\n"); - rc = -ENOMEM; - goto out_fb_release; - } + viafbinfo->screen_base = vdev->fbmem; - viafbinfo->fix.mmio_start = pci_resource_start(pdev, 1); - viafbinfo->fix.mmio_len = pci_resource_len(pdev, 1); + viafbinfo->fix.mmio_start = vdev->engine_start; + viafbinfo->fix.mmio_len = vdev->engine_len; viafbinfo->node = 0; viafbinfo->fbops = &viafb_ops; viafbinfo->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; @@ -1862,12 +1857,13 @@ int __devinit via_fb_pci_probe(struct pci_dev *pdev, viafbinfo->var = default_var; if (viafb_dual_fb) { - viafbinfo1 = framebuffer_alloc(viafb_par_length, &pdev->dev); + viafbinfo1 = framebuffer_alloc(viafb_par_length, + &vdev->pdev->dev); if (!viafbinfo1) { printk(KERN_ERR "allocate the second framebuffer struct error\n"); rc = -ENOMEM; - goto out_unmap_screen; + goto out_fb_release; } viaparinfo1 = viafbinfo1->par; memcpy(viaparinfo1, viaparinfo, viafb_par_length); @@ -1958,8 +1954,6 @@ out_dealloc_cmap: out_fb1_release: if (viafbinfo1) framebuffer_release(viafbinfo1); -out_unmap_screen: - iounmap(viafbinfo->screen_base); out_fb_release: framebuffer_release(viafbinfo); return rc; @@ -1972,8 +1966,6 @@ void __devexit via_fb_pci_remove(struct pci_dev *pdev) unregister_framebuffer(viafbinfo); if (viafb_dual_fb) unregister_framebuffer(viafbinfo1); - iounmap((void *)viafbinfo->screen_base); - iounmap(viaparinfo->shared->engine_mmio); framebuffer_release(viafbinfo); if (viafb_dual_fb) diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h index 5604f27eb74e..52a35fabba91 100644 --- a/drivers/video/via/viafbdev.h +++ b/drivers/video/via/viafbdev.h @@ -30,7 +30,6 @@ #include "share.h" #include "chip.h" #include "hw.h" -#include "via_i2c.h" #define VERSION_MAJOR 2 #define VERSION_KERNEL 6 /* For kernel 2.6 */ @@ -42,6 +41,7 @@ struct viafb_shared { struct proc_dir_entry *proc_entry; /*viafb proc entry */ + struct viafb_dev *vdev; /* Global dev info */ /* All the information will be needed to set engine */ struct tmds_setting_information tmds_setting_info; @@ -51,7 +51,6 @@ struct viafb_shared { struct chip_information chip_info; /* hardware acceleration stuff */ - void __iomem *engine_mmio; u32 cursor_vram_addr; u32 vq_vram_addr; /* virtual queue address in video ram */ int (*hw_bitblt)(void __iomem *engine, u8 op, u32 width, u32 height, @@ -72,14 +71,6 @@ struct viafb_par { struct viafb_shared *shared; - /* - * (jc) I believe one should use locking to protect against - * concurrent access to the device ports and registers. Thus, - * this lock. Use of it is *far* from universal, though... - * someday... - */ - spinlock_t reg_lock; - /* All the information will be needed to set engine */ /* depreciated, use the ones in shared directly */ struct tmds_setting_information *tmds_setting_info; @@ -107,7 +98,7 @@ u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information void viafb_gpio_i2c_write_mask_lvds(struct lvds_setting_information *plvds_setting_info, struct lvds_chip_information *plvds_chip_info, struct IODATA io_data); -int via_fb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); +int via_fb_pci_probe(struct viafb_dev *vdev); void via_fb_pci_remove(struct pci_dev *pdev); /* Temporary */ int viafb_init(void); diff --git a/drivers/video/via/vt1636.c b/drivers/video/via/vt1636.c index 4589c6e73c5d..e9f3661d6b3f 100644 --- a/drivers/video/via/vt1636.c +++ b/drivers/video/via/vt1636.c @@ -19,6 +19,8 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "via-core.h" +#include "via_i2c.h" #include "global.h" u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information -- cgit v1.2.1 From 7e0de022680f7899d33141f3ab5724a704f5669a Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Tue, 1 Dec 2009 20:39:57 -0700 Subject: viafb: add a driver for GPIO lines This is a simple gpiolib driver giving access to the GPIO lines in the VIA framebuffer system. A simple mechanism exists for switching lines between GPIO and I2C, but it's only compile-time for now. Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Cc: Harald Welte Acked-by: Florian Tobias Schandinat Signed-off-by: Jonathan Corbet --- drivers/video/Kconfig | 2 + drivers/video/via/Makefile | 5 +- drivers/video/via/via-core.c | 7 ++ drivers/video/via/via-gpio.c | 268 +++++++++++++++++++++++++++++++++++++++++++ drivers/video/via/via-gpio.h | 15 +++ 5 files changed, 296 insertions(+), 1 deletion(-) create mode 100644 drivers/video/via/via-gpio.c create mode 100644 drivers/video/via/via-gpio.h (limited to 'drivers/video') diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 6e16244f3ed1..22c1662de964 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1511,6 +1511,7 @@ config FB_VIA select FB_CFB_IMAGEBLIT select I2C_ALGOBIT select I2C + select GPIOLIB help This is the frame buffer device driver for Graphics chips of VIA UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/ @@ -1520,6 +1521,7 @@ config FB_VIA To compile this driver as a module, choose M here: the module will be called viafb. + config FB_NEOMAGIC tristate "NeoMagic display support" depends on FB && PCI diff --git a/drivers/video/via/Makefile b/drivers/video/via/Makefile index aec3f8b24a96..8c42a42c3dbb 100644 --- a/drivers/video/via/Makefile +++ b/drivers/video/via/Makefile @@ -4,4 +4,7 @@ obj-$(CONFIG_FB_VIA) += viafb.o -viafb-y :=viafbdev.o hw.o via_i2c.o dvi.o lcd.o ioctl.o accel.o via_utility.o vt1636.o global.o tblDPASetting.o viamode.o tbl1636.o via-core.o +viafb-y :=viafbdev.o hw.o via_i2c.o dvi.o lcd.o ioctl.o accel.o \ + via_utility.o vt1636.o global.o tblDPASetting.o viamode.o tbl1636.o \ + via-core.o via-gpio.o + diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c index b77cd5c2fc96..806237e8b4a4 100644 --- a/drivers/video/via/via-core.c +++ b/drivers/video/via/via-core.c @@ -9,6 +9,7 @@ */ #include "via-core.h" #include "via_i2c.h" +#include "via-gpio.h" #include "global.h" #include @@ -221,6 +222,11 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, ret = via_fb_pci_probe(&global_dev); if (ret) goto out_i2c; + /* + * Create the GPIOs. We continue whether or not this succeeds; + * the framebuffer might be useful even without GPIO ports. + */ + ret = viafb_create_gpios(&global_dev, adap_configs); return 0; out_i2c: @@ -234,6 +240,7 @@ out_disable: static void __devexit via_pci_remove(struct pci_dev *pdev) { + viafb_destroy_gpios(); viafb_delete_i2c_busses(); via_fb_pci_remove(pdev); via_pci_teardown_mmio(&global_dev); diff --git a/drivers/video/via/via-gpio.c b/drivers/video/via/via-gpio.c new file mode 100644 index 000000000000..e119d2103730 --- /dev/null +++ b/drivers/video/via/via-gpio.c @@ -0,0 +1,268 @@ +/* + * Support for viafb GPIO ports. + * + * Copyright 2009 Jonathan Corbet + * Distributable under version 2 of the GNU General Public License. + */ + +#include +#include +#include "via-core.h" +#include "via-gpio.h" +#include "global.h" + +/* + * The ports we know about. Note that the port-25 gpios are not + * mentioned in the datasheet. + */ + +struct viafb_gpio { + char *vg_name; /* Data sheet name */ + u16 vg_io_port; + u8 vg_port_index; + int vg_mask_shift; +}; + +static struct viafb_gpio viafb_all_gpios[] = { + { + .vg_name = "VGPIO0", /* Guess - not in datasheet */ + .vg_io_port = VIASR, + .vg_port_index = 0x25, + .vg_mask_shift = 1 + }, + { + .vg_name = "VGPIO1", + .vg_io_port = VIASR, + .vg_port_index = 0x25, + .vg_mask_shift = 0 + }, + { + .vg_name = "VGPIO2", /* aka DISPCLKI0 */ + .vg_io_port = VIASR, + .vg_port_index = 0x2c, + .vg_mask_shift = 1 + }, + { + .vg_name = "VGPIO3", /* aka DISPCLKO0 */ + .vg_io_port = VIASR, + .vg_port_index = 0x2c, + .vg_mask_shift = 0 + }, + { + .vg_name = "VGPIO4", /* DISPCLKI1 */ + .vg_io_port = VIASR, + .vg_port_index = 0x3d, + .vg_mask_shift = 1 + }, + { + .vg_name = "VGPIO5", /* DISPCLKO1 */ + .vg_io_port = VIASR, + .vg_port_index = 0x3d, + .vg_mask_shift = 0 + }, +}; + +#define VIAFB_NUM_GPIOS ARRAY_SIZE(viafb_all_gpios) + +/* + * This structure controls the active GPIOs, which may be a subset + * of those which are known. + */ + +struct viafb_gpio_cfg { + struct gpio_chip gpio_chip; + struct viafb_dev *vdev; + struct viafb_gpio *active_gpios[VIAFB_NUM_GPIOS]; + char *gpio_names[VIAFB_NUM_GPIOS]; +}; + +/* + * GPIO access functions + */ +static void via_gpio_set(struct gpio_chip *chip, unsigned int nr, + int value) +{ + struct viafb_gpio_cfg *cfg = container_of(chip, + struct viafb_gpio_cfg, + gpio_chip); + u8 reg; + struct viafb_gpio *gpio; + unsigned long flags; + + spin_lock_irqsave(&cfg->vdev->reg_lock, flags); + gpio = cfg->active_gpios[nr]; + reg = viafb_read_reg(VIASR, gpio->vg_port_index); + reg |= 0x40 << gpio->vg_mask_shift; /* output enable */ + if (value) + reg |= 0x10 << gpio->vg_mask_shift; + else + reg &= ~(0x10 << gpio->vg_mask_shift); + viafb_write_reg(gpio->vg_port_index, VIASR, reg); + spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags); +} + +static int via_gpio_dir_out(struct gpio_chip *chip, unsigned int nr, + int value) +{ + via_gpio_set(chip, nr, value); + return 0; +} + +/* + * Set the input direction. I'm not sure this is right; we should + * be able to do input without disabling output. + */ +static int via_gpio_dir_input(struct gpio_chip *chip, unsigned int nr) +{ + struct viafb_gpio_cfg *cfg = container_of(chip, + struct viafb_gpio_cfg, + gpio_chip); + struct viafb_gpio *gpio; + unsigned long flags; + + spin_lock_irqsave(&cfg->vdev->reg_lock, flags); + gpio = cfg->active_gpios[nr]; + viafb_write_reg_mask(gpio->vg_port_index, VIASR, 0, + 0x40 << gpio->vg_mask_shift); + spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags); + return 0; +} + +static int via_gpio_get(struct gpio_chip *chip, unsigned int nr) +{ + struct viafb_gpio_cfg *cfg = container_of(chip, + struct viafb_gpio_cfg, + gpio_chip); + u8 reg; + struct viafb_gpio *gpio; + unsigned long flags; + + spin_lock_irqsave(&cfg->vdev->reg_lock, flags); + gpio = cfg->active_gpios[nr]; + reg = viafb_read_reg(VIASR, gpio->vg_port_index); + spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags); + return reg & (0x04 << gpio->vg_mask_shift); +} + + +static struct viafb_gpio_cfg gpio_config = { + .gpio_chip = { + .label = "VIAFB onboard GPIO", + .owner = THIS_MODULE, + .direction_output = via_gpio_dir_out, + .set = via_gpio_set, + .direction_input = via_gpio_dir_input, + .get = via_gpio_get, + .base = -1, + .ngpio = 0, + .can_sleep = 0 + } +}; + +/* + * Manage the software enable bit. + */ +static void viafb_gpio_enable(struct viafb_gpio *gpio) +{ + viafb_write_reg_mask(gpio->vg_port_index, VIASR, 0x02, 0x02); +} + +static void viafb_gpio_disable(struct viafb_gpio *gpio) +{ + viafb_write_reg_mask(gpio->vg_port_index, VIASR, 0, 0x02); +} + + + + +int viafb_create_gpios(struct viafb_dev *vdev, + const struct via_port_cfg *port_cfg) +{ + int i, ngpio = 0, ret; + struct viafb_gpio *gpio; + unsigned long flags; + + /* + * Set up entries for all GPIOs which have been configured to + * operate as such (as opposed to as i2c ports). + */ + for (i = 0; i < VIAFB_NUM_PORTS; i++) { + if (port_cfg[i].mode != VIA_MODE_GPIO) + continue; + for (gpio = viafb_all_gpios; + gpio < viafb_all_gpios + VIAFB_NUM_GPIOS; gpio++) + if (gpio->vg_port_index == port_cfg[i].ioport_index) { + gpio_config.active_gpios[ngpio] = gpio; + gpio_config.gpio_names[ngpio] = gpio->vg_name; + ngpio++; + } + } + gpio_config.gpio_chip.ngpio = ngpio; + gpio_config.gpio_chip.names = gpio_config.gpio_names; + gpio_config.vdev = vdev; + if (ngpio == 0) { + printk(KERN_INFO "viafb: no GPIOs configured\n"); + return 0; + } + /* + * Enable the ports. They come in pairs, with a single + * enable bit for both. + */ + spin_lock_irqsave(&gpio_config.vdev->reg_lock, flags); + for (i = 0; i < ngpio; i += 2) + viafb_gpio_enable(gpio_config.active_gpios[i]); + spin_unlock_irqrestore(&gpio_config.vdev->reg_lock, flags); + /* + * Get registered. + */ + gpio_config.gpio_chip.base = -1; /* Dynamic */ + ret = gpiochip_add(&gpio_config.gpio_chip); + if (ret) { + printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret); + gpio_config.gpio_chip.ngpio = 0; + } + return ret; +/* Port enable ? */ +} + + +int viafb_destroy_gpios(void) +{ + unsigned long flags; + int ret = 0, i; + + spin_lock_irqsave(&gpio_config.vdev->reg_lock, flags); + /* + * Get unregistered. + */ + if (gpio_config.gpio_chip.ngpio > 0) { + ret = gpiochip_remove(&gpio_config.gpio_chip); + if (ret) { /* Somebody still using it? */ + printk(KERN_ERR "Viafb: GPIO remove failed\n"); + goto out; + } + } + /* + * Disable the ports. + */ + for (i = 0; i < gpio_config.gpio_chip.ngpio; i += 2) + viafb_gpio_disable(gpio_config.active_gpios[i]); + gpio_config.gpio_chip.ngpio = 0; +out: + spin_unlock_irqrestore(&gpio_config.vdev->reg_lock, flags); + return ret; +} + +/* + * Look up a specific gpio and return the number it was assigned. + */ +int viafb_gpio_lookup(const char *name) +{ + int i; + + for (i = 0; i < gpio_config.gpio_chip.ngpio; i++) + if (!strcmp(name, gpio_config.active_gpios[i]->vg_name)) + return gpio_config.gpio_chip.base + i; + return -1; +} +EXPORT_SYMBOL_GPL(viafb_gpio_lookup); diff --git a/drivers/video/via/via-gpio.h b/drivers/video/via/via-gpio.h new file mode 100644 index 000000000000..7b53f966eb4b --- /dev/null +++ b/drivers/video/via/via-gpio.h @@ -0,0 +1,15 @@ +/* + * Support for viafb GPIO ports. + * + * Copyright 2009 Jonathan Corbet + * Distributable under version 2 of the GNU General Public License. + */ + +#ifndef __VIA_GPIO_H__ +#define __VIA_GPIO_H__ + +extern int viafb_create_gpios(struct viafb_dev *vdev, + const struct via_port_cfg *port_cfg); +extern int viafb_destroy_gpios(void); +extern int viafb_gpio_lookup(const char *name); +#endif -- cgit v1.2.1 From c389874805a6849e3e347fc0e13fa170d80840c1 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sat, 17 Apr 2010 19:44:51 +0000 Subject: viafb: package often used basic io functions This patch puts redesigned versions of the basic io functions that are used overall the driver in an extra header. It is prefixed with via_ as no framebuffer dependend stuff is in there. They were inlined as they are really simple which reduced the module size about 2.5%. The parameter order of read and write was fixed as it really doesn't make sense to change the order as they are parts of the same address and not source and destination. Wrapper which use the new functions were added to hw.h to replicate the old interface and avoid changing all old code. [jc: added one comment] Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/hw.c | 22 ------------------ drivers/video/via/hw.h | 8 ++++--- drivers/video/via/via_io.h | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 25 deletions(-) create mode 100644 drivers/video/via/via_io.h (limited to 'drivers/video') diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index f2425ae228ae..805151f48ea9 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -537,18 +537,6 @@ static void device_on(void); static void enable_second_display_channel(void); static void disable_second_display_channel(void); -void viafb_write_reg(u8 index, u16 io_port, u8 data) -{ - outb(index, io_port); - outb(data, io_port + 1); - /*DEBUG_MSG(KERN_INFO "\nIndex=%2d Value=%2d", index, data); */ -} -u8 viafb_read_reg(int io_port, u8 index) -{ - outb(index, io_port); - return inb(io_port + 1); -} - void viafb_lock_crt(void) { viafb_write_reg_mask(CR11, VIACR, BIT7, BIT7); @@ -560,16 +548,6 @@ void viafb_unlock_crt(void) viafb_write_reg_mask(CR47, VIACR, 0, BIT0); } -void viafb_write_reg_mask(u8 index, int io_port, u8 data, u8 mask) -{ - u8 tmp; - - outb(index, io_port); - tmp = inb(io_port + 1); - outb((data & mask) | (tmp & (~mask)), io_port + 1); - /*DEBUG_MSG(KERN_INFO "\nIndex=%2d Value=%2d", index, tmp); */ -} - void write_dac_reg(u8 index, u8 r, u8 g, u8 b) { outb(index, LUT_INDEX_WRITE); diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index d248f4dc12ec..23c319010913 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h @@ -24,6 +24,11 @@ #include "viamode.h" #include "global.h" +#include "via_io.h" + +#define viafb_read_reg(p, i) via_read_reg(p, i) +#define viafb_write_reg(i, p, d) via_write_reg(p, i, d) +#define viafb_write_reg_mask(i, p, d, m) via_write_reg_mask(p, i, d, m) /*************************************************** * Definition IGA1 Design Method of CRTC Registers * @@ -870,7 +875,6 @@ extern int viafb_LCD_ON; extern int viafb_DVI_ON; extern int viafb_hotplug; -void viafb_write_reg_mask(u8 index, int io_port, u8 data, u8 mask); void viafb_set_output_path(int device, int set_iga, int output_interface); @@ -885,8 +889,6 @@ void viafb_crt_disable(void); void viafb_crt_enable(void); void init_ad9389(void); /* Access I/O Function */ -void viafb_write_reg(u8 index, u16 io_port, u8 data); -u8 viafb_read_reg(int io_port, u8 index); void viafb_lock_crt(void); void viafb_unlock_crt(void); void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga); diff --git a/drivers/video/via/via_io.h b/drivers/video/via/via_io.h new file mode 100644 index 000000000000..e1c1093def00 --- /dev/null +++ b/drivers/video/via/via_io.h @@ -0,0 +1,58 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + * Copyright 2010 Florian Tobias Schandinat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +/* + * basic io functions + */ + +#ifndef __VIA_IO_H__ +#define __VIA_IO_H__ + +#include +#include + +/* + * Indexed port operations. Note that these are all multi-op + * functions; every invocation will be racy if you're not holding + * reg_lock. + */ +static inline u8 via_read_reg(u16 port, u8 index) +{ + outb(index, port); + return inb(port + 1); +} + +static inline void via_write_reg(u16 port, u8 index, u8 data) +{ + outb(index, port); + outb(data, port + 1); +} + +static inline void via_write_reg_mask(u16 port, u8 index, u8 data, u8 mask) +{ + u8 old; + + outb(index, port); + old = inb(port + 1); + outb((data & mask) | (old & ~mask), port + 1); +} + +#endif /* __VIA_IO_H__ */ -- cgit v1.2.1 From 75b035ace904761b8a340b524533a36e37313b29 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 22 Apr 2010 14:36:04 -0600 Subject: viafb: Convert GPIO and i2c to the new indexed port ops Also add low-level locking to the i2c driver. Signed-off-by: Jonathan Corbet --- drivers/video/via/via-core.c | 2 +- drivers/video/via/via-gpio.c | 14 +++++++------- drivers/video/via/via_i2c.c | 46 ++++++++++++++++++++++++++++---------------- drivers/video/via/via_i2c.h | 2 +- 4 files changed, 38 insertions(+), 26 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c index 806237e8b4a4..a1b5dae285a4 100644 --- a/drivers/video/via/via-core.c +++ b/drivers/video/via/via-core.c @@ -213,7 +213,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, * Create the I2C busses. Bailing out on failure seems extreme, * but that's what the code did before. */ - ret = viafb_create_i2c_busses(adap_configs); + ret = viafb_create_i2c_busses(&global_dev, adap_configs); if (ret) goto out_teardown; /* diff --git a/drivers/video/via/via-gpio.c b/drivers/video/via/via-gpio.c index e119d2103730..6b361177bf03 100644 --- a/drivers/video/via/via-gpio.c +++ b/drivers/video/via/via-gpio.c @@ -91,13 +91,13 @@ static void via_gpio_set(struct gpio_chip *chip, unsigned int nr, spin_lock_irqsave(&cfg->vdev->reg_lock, flags); gpio = cfg->active_gpios[nr]; - reg = viafb_read_reg(VIASR, gpio->vg_port_index); + reg = via_read_reg(VIASR, gpio->vg_port_index); reg |= 0x40 << gpio->vg_mask_shift; /* output enable */ if (value) reg |= 0x10 << gpio->vg_mask_shift; else reg &= ~(0x10 << gpio->vg_mask_shift); - viafb_write_reg(gpio->vg_port_index, VIASR, reg); + via_write_reg(VIASR, gpio->vg_port_index, reg); spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags); } @@ -122,8 +122,8 @@ static int via_gpio_dir_input(struct gpio_chip *chip, unsigned int nr) spin_lock_irqsave(&cfg->vdev->reg_lock, flags); gpio = cfg->active_gpios[nr]; - viafb_write_reg_mask(gpio->vg_port_index, VIASR, 0, - 0x40 << gpio->vg_mask_shift); + via_write_reg_mask(VIASR, gpio->vg_port_index, 0, + 0x40 << gpio->vg_mask_shift); spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags); return 0; } @@ -139,7 +139,7 @@ static int via_gpio_get(struct gpio_chip *chip, unsigned int nr) spin_lock_irqsave(&cfg->vdev->reg_lock, flags); gpio = cfg->active_gpios[nr]; - reg = viafb_read_reg(VIASR, gpio->vg_port_index); + reg = via_read_reg(VIASR, gpio->vg_port_index); spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags); return reg & (0x04 << gpio->vg_mask_shift); } @@ -164,12 +164,12 @@ static struct viafb_gpio_cfg gpio_config = { */ static void viafb_gpio_enable(struct viafb_gpio *gpio) { - viafb_write_reg_mask(gpio->vg_port_index, VIASR, 0x02, 0x02); + via_write_reg_mask(VIASR, gpio->vg_port_index, 0x02, 0x02); } static void viafb_gpio_disable(struct viafb_gpio *gpio) { - viafb_write_reg_mask(gpio->vg_port_index, VIASR, 0, 0x02); + via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02); } diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c index bcf2fe61a6ec..116fd3e62934 100644 --- a/drivers/video/via/via_i2c.c +++ b/drivers/video/via/via_i2c.c @@ -29,14 +29,16 @@ */ #define VIAFB_NUM_I2C 5 static struct via_i2c_stuff via_i2c_par[VIAFB_NUM_I2C]; +struct viafb_dev *i2c_vdev; /* Passed in from core */ static void via_i2c_setscl(void *data, int state) { u8 val; struct via_port_cfg *adap_data = data; + unsigned long flags; - val = viafb_read_reg(adap_data->io_port, - adap_data->ioport_index) & 0xF0; + spin_lock_irqsave(&i2c_vdev->reg_lock, flags); + val = via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0; if (state) val |= 0x20; else @@ -51,35 +53,44 @@ static void via_i2c_setscl(void *data, int state) default: DEBUG_MSG("viafb_i2c: specify wrong i2c type.\n"); } - viafb_write_reg(adap_data->ioport_index, - adap_data->io_port, val); + via_write_reg(adap_data->io_port, adap_data->ioport_index, val); + spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags); } static int via_i2c_getscl(void *data) { struct via_port_cfg *adap_data = data; - - if (viafb_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x08) - return 1; - return 0; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&i2c_vdev->reg_lock, flags); + if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x08) + ret = 1; + spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags); + return ret; } static int via_i2c_getsda(void *data) { struct via_port_cfg *adap_data = data; - - if (viafb_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x04) - return 1; - return 0; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&i2c_vdev->reg_lock, flags); + if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x04) + ret = 1; + spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags); + return ret; } static void via_i2c_setsda(void *data, int state) { u8 val; struct via_port_cfg *adap_data = data; + unsigned long flags; - val = viafb_read_reg(adap_data->io_port, - adap_data->ioport_index) & 0xF0; + spin_lock_irqsave(&i2c_vdev->reg_lock, flags); + val = via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0; if (state) val |= 0x10; else @@ -94,8 +105,8 @@ static void via_i2c_setsda(void *data, int state) default: DEBUG_MSG("viafb_i2c: specify wrong i2c type.\n"); } - viafb_write_reg(adap_data->ioport_index, - adap_data->io_port, val); + via_write_reg(adap_data->io_port, adap_data->ioport_index, val); + spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags); } int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata) @@ -174,10 +185,11 @@ static int create_i2c_bus(struct i2c_adapter *adapter, return i2c_bit_add_bus(adapter); } -int viafb_create_i2c_busses(struct via_port_cfg *configs) +int viafb_create_i2c_busses(struct viafb_dev *dev, struct via_port_cfg *configs) { int i, ret; + i2c_vdev = dev; for (i = 0; i < VIAFB_NUM_PORTS; i++) { struct via_port_cfg *adap_cfg = configs++; struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i]; diff --git a/drivers/video/via/via_i2c.h b/drivers/video/via/via_i2c.h index 00932914b4ed..0685de9a0c7a 100644 --- a/drivers/video/via/via_i2c.h +++ b/drivers/video/via/via_i2c.h @@ -36,7 +36,7 @@ int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data); int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len); struct viafb_par; -int viafb_create_i2c_busses(struct via_port_cfg *cfg); +int viafb_create_i2c_busses(struct viafb_dev *vdev, struct via_port_cfg *cfg); void viafb_delete_i2c_busses(void); struct i2c_adapter *viafb_find_adapter(enum viafb_i2c_adap which); #endif /* __VIA_I2C_H__ */ -- cgit v1.2.1 From 7582eb9be85f35271fd2569681a88a5b243e9380 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 22 Apr 2010 17:39:34 -0600 Subject: viafb: Turn GPIO and i2c into proper platform devices Another step toward making this thing a real multifunction device driver. Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Cc: Harald Welte Acked-by: Florian Tobias Schandinat Signed-off-by: Jonathan Corbet --- drivers/video/via/via-core.c | 91 ++++++++++++++++++++++++++++++++++++-------- drivers/video/via/via-core.h | 1 + drivers/video/via/via-gpio.c | 49 ++++++++++++++++-------- drivers/video/via/via-gpio.h | 5 +-- drivers/video/via/via_i2c.c | 29 ++++++++++++-- drivers/video/via/via_i2c.h | 6 +-- 6 files changed, 140 insertions(+), 41 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c index a1b5dae285a4..5a78ef9cb382 100644 --- a/drivers/video/via/via-core.c +++ b/drivers/video/via/via-core.c @@ -190,6 +190,70 @@ static void __devexit via_pci_teardown_mmio(struct viafb_dev *vdev) iounmap(vdev->engine_mmio); } +/* + * Create our subsidiary devices. + */ +static struct viafb_subdev_info { + char *name; + struct platform_device *platdev; +} viafb_subdevs[] = { + { + .name = "viafb-gpio", + }, + { + .name = "viafb-i2c", + } +}; +#define N_SUBDEVS ARRAY_SIZE(viafb_subdevs) + +static int __devinit via_create_subdev(struct viafb_dev *vdev, + struct viafb_subdev_info *info) +{ + int ret; + + info->platdev = platform_device_alloc(info->name, -1); + if (!info->platdev) { + dev_err(&vdev->pdev->dev, "Unable to allocate pdev %s\n", + info->name); + return -ENOMEM; + } + info->platdev->dev.parent = &vdev->pdev->dev; + info->platdev->dev.platform_data = vdev; + ret = platform_device_add(info->platdev); + if (ret) { + dev_err(&vdev->pdev->dev, "Unable to add pdev %s\n", + info->name); + platform_device_put(info->platdev); + info->platdev = NULL; + } + return ret; +} + +static int __devinit via_setup_subdevs(struct viafb_dev *vdev) +{ + int i; + + /* + * Ignore return values. Even if some of the devices + * fail to be created, we'll still be able to use some + * of the rest. + */ + for (i = 0; i < N_SUBDEVS; i++) + via_create_subdev(vdev, viafb_subdevs + i); + return 0; +} + +static void __devexit via_teardown_subdevs(void) +{ + int i; + + for (i = 0; i < N_SUBDEVS; i++) + if (viafb_subdevs[i].platdev) { + viafb_subdevs[i].platdev->dev.platform_data = NULL; + platform_device_unregister(viafb_subdevs[i].platdev); + } +} + static int __devinit via_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -205,33 +269,25 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, memset(&global_dev, 0, sizeof(global_dev)); global_dev.pdev = pdev; global_dev.chip_type = ent->driver_data; + global_dev.port_cfg = adap_configs; spin_lock_init(&global_dev.reg_lock); ret = via_pci_setup_mmio(&global_dev); if (ret) goto out_disable; /* - * Create the I2C busses. Bailing out on failure seems extreme, - * but that's what the code did before. + * Create our subdevices. Continue even if some things fail. */ - ret = viafb_create_i2c_busses(&global_dev, adap_configs); - if (ret) - goto out_teardown; + via_setup_subdevs(&global_dev); /* * Set up the framebuffer. */ ret = via_fb_pci_probe(&global_dev); if (ret) - goto out_i2c; - /* - * Create the GPIOs. We continue whether or not this succeeds; - * the framebuffer might be useful even without GPIO ports. - */ - ret = viafb_create_gpios(&global_dev, adap_configs); + goto out_subdevs; return 0; -out_i2c: - viafb_delete_i2c_busses(); -out_teardown: +out_subdevs: + via_teardown_subdevs(); via_pci_teardown_mmio(&global_dev); out_disable: pci_disable_device(pdev); @@ -240,8 +296,7 @@ out_disable: static void __devexit via_pci_remove(struct pci_dev *pdev) { - viafb_destroy_gpios(); - viafb_delete_i2c_busses(); + via_teardown_subdevs(); via_fb_pci_remove(pdev); via_pci_teardown_mmio(&global_dev); pci_disable_device(pdev); @@ -289,12 +344,16 @@ static int __init via_core_init(void) ret = viafb_init(); if (ret) return ret; + viafb_i2c_init(); + viafb_gpio_init(); return pci_register_driver(&via_driver); } static void __exit via_core_exit(void) { pci_unregister_driver(&via_driver); + viafb_gpio_exit(); + viafb_i2c_exit(); viafb_exit(); } diff --git a/drivers/video/via/via-core.h b/drivers/video/via/via-core.h index d004290dc8f1..ac89c2aa98b5 100644 --- a/drivers/video/via/via-core.h +++ b/drivers/video/via/via-core.h @@ -63,6 +63,7 @@ struct via_port_cfg { struct viafb_dev { struct pci_dev *pdev; int chip_type; + struct via_port_cfg *port_cfg; /* * Spinlock for access to device registers. Not yet * globally used. diff --git a/drivers/video/via/via-gpio.c b/drivers/video/via/via-gpio.c index 6b361177bf03..44537be1f070 100644 --- a/drivers/video/via/via-gpio.c +++ b/drivers/video/via/via-gpio.c @@ -7,6 +7,7 @@ #include #include +#include #include "via-core.h" #include "via-gpio.h" #include "global.h" @@ -172,12 +173,27 @@ static void viafb_gpio_disable(struct viafb_gpio *gpio) via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02); } +/* + * Look up a specific gpio and return the number it was assigned. + */ +int viafb_gpio_lookup(const char *name) +{ + int i; + for (i = 0; i < gpio_config.gpio_chip.ngpio; i++) + if (!strcmp(name, gpio_config.active_gpios[i]->vg_name)) + return gpio_config.gpio_chip.base + i; + return -1; +} +EXPORT_SYMBOL_GPL(viafb_gpio_lookup); - -int viafb_create_gpios(struct viafb_dev *vdev, - const struct via_port_cfg *port_cfg) +/* + * Platform device stuff. + */ +static __devinit int viafb_gpio_probe(struct platform_device *platdev) { + struct viafb_dev *vdev = platdev->dev.platform_data; + struct via_port_cfg *port_cfg = vdev->port_cfg; int i, ngpio = 0, ret; struct viafb_gpio *gpio; unsigned long flags; @@ -222,11 +238,10 @@ int viafb_create_gpios(struct viafb_dev *vdev, gpio_config.gpio_chip.ngpio = 0; } return ret; -/* Port enable ? */ } -int viafb_destroy_gpios(void) +static int viafb_gpio_remove(struct platform_device *platdev) { unsigned long flags; int ret = 0, i; @@ -253,16 +268,20 @@ out: return ret; } -/* - * Look up a specific gpio and return the number it was assigned. - */ -int viafb_gpio_lookup(const char *name) +static struct platform_driver via_gpio_driver = { + .driver = { + .name = "viafb-gpio", + }, + .probe = viafb_gpio_probe, + .remove = viafb_gpio_remove, +}; + +int viafb_gpio_init(void) { - int i; + return platform_driver_register(&via_gpio_driver); +} - for (i = 0; i < gpio_config.gpio_chip.ngpio; i++) - if (!strcmp(name, gpio_config.active_gpios[i]->vg_name)) - return gpio_config.gpio_chip.base + i; - return -1; +void viafb_gpio_exit(void) +{ + platform_driver_unregister(&via_gpio_driver); } -EXPORT_SYMBOL_GPL(viafb_gpio_lookup); diff --git a/drivers/video/via/via-gpio.h b/drivers/video/via/via-gpio.h index 7b53f966eb4b..8281aea3dd6d 100644 --- a/drivers/video/via/via-gpio.h +++ b/drivers/video/via/via-gpio.h @@ -8,8 +8,7 @@ #ifndef __VIA_GPIO_H__ #define __VIA_GPIO_H__ -extern int viafb_create_gpios(struct viafb_dev *vdev, - const struct via_port_cfg *port_cfg); -extern int viafb_destroy_gpios(void); extern int viafb_gpio_lookup(const char *name); +extern int viafb_gpio_init(void); +extern void viafb_gpio_exit(void); #endif diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c index 116fd3e62934..3ff60b280d88 100644 --- a/drivers/video/via/via_i2c.c +++ b/drivers/video/via/via_i2c.c @@ -19,6 +19,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include #include "via-core.h" #include "via_i2c.h" #include "global.h" @@ -185,11 +186,14 @@ static int create_i2c_bus(struct i2c_adapter *adapter, return i2c_bit_add_bus(adapter); } -int viafb_create_i2c_busses(struct viafb_dev *dev, struct via_port_cfg *configs) +static int viafb_i2c_probe(struct platform_device *platdev) { int i, ret; + struct via_port_cfg *configs; + + i2c_vdev = platdev->dev.platform_data; + configs = i2c_vdev->port_cfg; - i2c_vdev = dev; for (i = 0; i < VIAFB_NUM_PORTS; i++) { struct via_port_cfg *adap_cfg = configs++; struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i]; @@ -211,7 +215,7 @@ int viafb_create_i2c_busses(struct viafb_dev *dev, struct via_port_cfg *configs) return 0; } -void viafb_delete_i2c_busses(void) +static int viafb_i2c_remove(struct platform_device *platdev) { int i; @@ -224,4 +228,23 @@ void viafb_delete_i2c_busses(void) if (i2c_stuff->adapter.algo_data == &i2c_stuff->algo) i2c_del_adapter(&i2c_stuff->adapter); } + return 0; +} + +static struct platform_driver via_i2c_driver = { + .driver = { + .name = "viafb-i2c", + }, + .probe = viafb_i2c_probe, + .remove = viafb_i2c_remove, +}; + +int viafb_i2c_init(void) +{ + return platform_driver_register(&via_i2c_driver); +} + +void viafb_i2c_exit(void) +{ + platform_driver_unregister(&via_i2c_driver); } diff --git a/drivers/video/via/via_i2c.h b/drivers/video/via/via_i2c.h index 0685de9a0c7a..b2332cce9d18 100644 --- a/drivers/video/via/via_i2c.h +++ b/drivers/video/via/via_i2c.h @@ -35,8 +35,6 @@ int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata); int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data); int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len); -struct viafb_par; -int viafb_create_i2c_busses(struct viafb_dev *vdev, struct via_port_cfg *cfg); -void viafb_delete_i2c_busses(void); -struct i2c_adapter *viafb_find_adapter(enum viafb_i2c_adap which); +extern int viafb_i2c_init(void); +extern void viafb_i2c_exit(void); #endif /* __VIA_I2C_H__ */ -- cgit v1.2.1 From b052d7f81fdd352a5d89ef1ac37a2c77f219463b Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Mon, 28 Dec 2009 10:04:02 -0700 Subject: via: Do not attempt I/O on inactive I2C adapters If an adapter has been configured for GPIO (or off), we should not try to use it as an I2C port. Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Cc: Harald Welte Acked-by: Florian Tobias Schandinat Signed-off-by: Jonathan Corbet --- drivers/video/via/via_i2c.c | 14 ++++++++++---- drivers/video/via/via_i2c.h | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c index 3ff60b280d88..c88450ee62ba 100644 --- a/drivers/video/via/via_i2c.c +++ b/drivers/video/via/via_i2c.c @@ -115,6 +115,8 @@ int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata) u8 mm1[] = {0x00}; struct i2c_msg msgs[2]; + if (!via_i2c_par[adap].is_active) + return -ENODEV; *pdata = 0; msgs[0].flags = 0; msgs[1].flags = I2C_M_RD; @@ -130,6 +132,8 @@ int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data) u8 msg[2] = { index, data }; struct i2c_msg msgs; + if (!via_i2c_par[adap].is_active) + return -ENODEV; msgs.flags = 0; msgs.addr = slave_addr / 2; msgs.len = 2; @@ -142,6 +146,8 @@ int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len u8 mm1[] = {0x00}; struct i2c_msg msgs[2]; + if (!via_i2c_par[adap].is_active) + return -ENODEV; msgs[0].flags = 0; msgs[1].flags = I2C_M_RD; msgs[0].addr = msgs[1].addr = slave_addr / 2; @@ -198,18 +204,18 @@ static int viafb_i2c_probe(struct platform_device *platdev) struct via_port_cfg *adap_cfg = configs++; struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i]; + i2c_stuff->is_active = 0; if (adap_cfg->type == 0 || adap_cfg->mode != VIA_MODE_I2C) continue; - ret = create_i2c_bus(&i2c_stuff->adapter, &i2c_stuff->algo, adap_cfg, NULL); /* FIXME: PCIDEV */ if (ret < 0) { printk(KERN_ERR "viafb: cannot create i2c bus %u:%d\n", i, ret); - /* FIXME: properly release previous busses */ - return ret; + continue; /* Still try to make the rest */ } + i2c_stuff->is_active = 1; } return 0; @@ -225,7 +231,7 @@ static int viafb_i2c_remove(struct platform_device *platdev) * Only remove those entries in the array that we've * actually used (and thus initialized algo_data) */ - if (i2c_stuff->adapter.algo_data == &i2c_stuff->algo) + if (i2c_stuff->is_active) i2c_del_adapter(&i2c_stuff->adapter); } return 0; diff --git a/drivers/video/via/via_i2c.h b/drivers/video/via/via_i2c.h index b2332cce9d18..1d18e7d57b7f 100644 --- a/drivers/video/via/via_i2c.h +++ b/drivers/video/via/via_i2c.h @@ -26,6 +26,7 @@ struct via_i2c_stuff { u16 i2c_port; /* GPIO or I2C port */ + u16 is_active; /* Being used as I2C? */ struct i2c_adapter adapter; struct i2c_algo_bit_data algo; }; -- cgit v1.2.1 From b8f7e5d846387e3bcda35f3809856cf085740a24 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Fri, 23 Apr 2010 08:56:55 -0600 Subject: viafb: Introduce viafb_find_i2c_adapter() The camera driver will need this to look up a specific adapter. Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Cc: Harald Welte Acked-by: Florian Tobias Schandinat Signed-off-by: Jonathan Corbet --- drivers/video/via/via_i2c.c | 13 +++++++++++++ drivers/video/via/via_i2c.h | 1 + 2 files changed, 14 insertions(+) (limited to 'drivers/video') diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c index c88450ee62ba..febc1dda69c1 100644 --- a/drivers/video/via/via_i2c.c +++ b/drivers/video/via/via_i2c.c @@ -157,6 +157,19 @@ int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len return i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2); } +/* + * Allow other viafb subdevices to look up a specific adapter + * by port name. + */ +struct i2c_adapter *viafb_find_i2c_adapter(enum viafb_i2c_adap which) +{ + struct via_i2c_stuff *stuff = &via_i2c_par[which]; + + return &stuff->adapter; +} +EXPORT_SYMBOL_GPL(viafb_find_i2c_adapter); + + static int create_i2c_bus(struct i2c_adapter *adapter, struct i2c_algo_bit_data *algo, struct via_port_cfg *adap_cfg, diff --git a/drivers/video/via/via_i2c.h b/drivers/video/via/via_i2c.h index 1d18e7d57b7f..44532e468c05 100644 --- a/drivers/video/via/via_i2c.h +++ b/drivers/video/via/via_i2c.h @@ -35,6 +35,7 @@ struct via_i2c_stuff { int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata); int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data); int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len); +struct i2c_adapter *viafb_find_i2c_adapter(enum viafb_i2c_adap which); extern int viafb_i2c_init(void); extern void viafb_i2c_exit(void); -- cgit v1.2.1 From 6b841edf572ad757f11013326b796e126f05a719 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Mon, 28 Dec 2009 10:22:53 -0700 Subject: via: Rationalize vt1636 detection The code was ugly and didn't check whether i2c operations were succeeding; make it a little better. Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Cc: Harald Welte Acked-by: Florian Tobias Schandinat Signed-off-by: Jonathan Corbet --- drivers/video/via/vt1636.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/vt1636.c b/drivers/video/via/vt1636.c index e9f3661d6b3f..e5f802472883 100644 --- a/drivers/video/via/vt1636.c +++ b/drivers/video/via/vt1636.c @@ -167,26 +167,20 @@ bool viafb_lvds_identify_vt1636(u8 i2c_adapter) /* Sense VT1636 LVDS Transmiter */ viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr = - VT1636_LVDS_I2C_ADDR; + VT1636_LVDS_I2C_ADDR; /* Check vendor ID first: */ - viafb_i2c_readbyte(i2c_adapter, - (u8) viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr, - 0x00, &Buffer[0]); - viafb_i2c_readbyte(i2c_adapter, - (u8) viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr, - 0x01, &Buffer[1]); + if (viafb_i2c_readbyte(i2c_adapter, VT1636_LVDS_I2C_ADDR, + 0x00, &Buffer[0])) + return false; + viafb_i2c_readbyte(i2c_adapter, VT1636_LVDS_I2C_ADDR, 0x01, &Buffer[1]); if (!((Buffer[0] == 0x06) && (Buffer[1] == 0x11))) return false; /* Check Chip ID: */ - viafb_i2c_readbyte(i2c_adapter, - (u8) viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr, - 0x02, &Buffer[0]); - viafb_i2c_readbyte(i2c_adapter, - (u8) viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr, - 0x03, &Buffer[1]); + viafb_i2c_readbyte(i2c_adapter, VT1636_LVDS_I2C_ADDR, 0x02, &Buffer[0]); + viafb_i2c_readbyte(i2c_adapter, VT1636_LVDS_I2C_ADDR, 0x03, &Buffer[1]); if ((Buffer[0] == 0x45) && (Buffer[1] == 0x33)) { viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = VT1636_LVDS; -- cgit v1.2.1 From 94dd1a856b23bd51dfebf68e6dd63cfd4d4fd5ae Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Fri, 23 Apr 2010 09:46:59 -0600 Subject: viafb: Add a simple interrupt management infrastructure The viafb device shares a single interrupt control register among several distinct subunits. This adds a simple layer for management of that register. Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Cc: Harald Welte Acked-by: Florian Tobias Schandinat Signed-off-by: Jonathan Corbet --- drivers/video/via/via-core.c | 64 +++++++++++++++++++++++++++++++++++++++++++- drivers/video/via/via-core.h | 44 ++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 1 deletion(-) (limited to 'drivers/video') diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c index 5a78ef9cb382..701b95575747 100644 --- a/drivers/video/via/via-core.c +++ b/drivers/video/via/via-core.c @@ -34,6 +34,65 @@ static struct via_port_cfg adap_configs[] = { static struct viafb_dev global_dev; +/* + * Basic register access; spinlock required. + */ +static inline void viafb_mmio_write(int reg, u32 v) +{ + iowrite32(v, global_dev.engine_mmio + reg); +} + +static inline int viafb_mmio_read(int reg) +{ + return ioread32(global_dev.engine_mmio + reg); +} + +/* ---------------------------------------------------------------------- */ +/* + * Interrupt management. We have a single IRQ line for a lot of + * different functions, so we need to share it. The design here + * is that we don't want to reimplement the shared IRQ code here; + * we also want to avoid having contention for a single handler thread. + * So each subdev driver which needs interrupts just requests + * them directly from the kernel. We just have what's needed for + * overall access to the interrupt control register. + */ + +/* + * Which interrupts are enabled now? + */ +static u32 viafb_enabled_ints; + +static void viafb_int_init(void) +{ + viafb_enabled_ints = 0; + + viafb_mmio_write(VDE_INTERRUPT, 0); +} + +/* + * Allow subdevs to ask for specific interrupts to be enabled. These + * functions must be called with reg_lock held + */ +void viafb_irq_enable(u32 mask) +{ + viafb_enabled_ints |= mask; + viafb_mmio_write(VDE_INTERRUPT, viafb_enabled_ints | VDE_I_ENABLE); +} +EXPORT_SYMBOL_GPL(viafb_irq_enable); + +void viafb_irq_disable(u32 mask) +{ + viafb_enabled_ints &= ~mask; + if (viafb_enabled_ints == 0) + viafb_mmio_write(VDE_INTERRUPT, 0); /* Disable entirely */ + else + viafb_mmio_write(VDE_INTERRUPT, + viafb_enabled_ints | VDE_I_ENABLE); +} +EXPORT_SYMBOL_GPL(viafb_irq_disable); + + /* * Figure out how big our framebuffer memory is. Kind of ugly, * but evidently we can't trust the information found in the @@ -275,8 +334,10 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, if (ret) goto out_disable; /* - * Create our subdevices. Continue even if some things fail. + * Set up interrupts and create our subdevices. Continue even if + * some things fail. */ + viafb_int_init(); via_setup_subdevs(&global_dev); /* * Set up the framebuffer. @@ -284,6 +345,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, ret = via_fb_pci_probe(&global_dev); if (ret) goto out_subdevs; + return 0; out_subdevs: diff --git a/drivers/video/via/via-core.h b/drivers/video/via/via-core.h index ac89c2aa98b5..ba64b36d58e3 100644 --- a/drivers/video/via/via-core.h +++ b/drivers/video/via/via-core.h @@ -87,4 +87,48 @@ struct viafb_dev { }; +/* + * Interrupt management. + */ + +void viafb_irq_enable(u32 mask); +void viafb_irq_disable(u32 mask); + +/* + * The global interrupt control register and its bits. + */ +#define VDE_INTERRUPT 0x200 /* Video interrupt flags/masks */ +#define VDE_I_DVISENSE 0x00000001 /* DVI sense int status */ +#define VDE_I_VBLANK 0x00000002 /* Vertical blank status */ +#define VDE_I_MCCFI 0x00000004 /* MCE compl. frame int status */ +#define VDE_I_VSYNC 0x00000008 /* VGA VSYNC int status */ +#define VDE_I_DMA0DDONE 0x00000010 /* DMA 0 descr done */ +#define VDE_I_DMA0TDONE 0x00000020 /* DMA 0 transfer done */ +#define VDE_I_DMA1DDONE 0x00000040 /* DMA 1 descr done */ +#define VDE_I_DMA1TDONE 0x00000080 /* DMA 1 transfer done */ +#define VDE_I_C1AV 0x00000100 /* Cap Eng 1 act vid end */ +#define VDE_I_HQV0 0x00000200 /* First HQV engine */ +#define VDE_I_HQV1 0x00000400 /* Second HQV engine */ +#define VDE_I_HQV1EN 0x00000800 /* Second HQV engine enable */ +#define VDE_I_C0AV 0x00001000 /* Cap Eng 0 act vid end */ +#define VDE_I_C0VBI 0x00002000 /* Cap Eng 0 VBI end */ +#define VDE_I_C1VBI 0x00004000 /* Cap Eng 1 VBI end */ +#define VDE_I_VSYNC2 0x00008000 /* Sec. Disp. VSYNC */ +#define VDE_I_DVISNSEN 0x00010000 /* DVI sense enable */ +#define VDE_I_VSYNC2EN 0x00020000 /* Sec Disp VSYNC enable */ +#define VDE_I_MCCFIEN 0x00040000 /* MC comp frame int mask enable */ +#define VDE_I_VSYNCEN 0x00080000 /* VSYNC enable */ +#define VDE_I_DMA0DDEN 0x00100000 /* DMA 0 descr done enable */ +#define VDE_I_DMA0TDEN 0x00200000 /* DMA 0 trans done enable */ +#define VDE_I_DMA1DDEN 0x00400000 /* DMA 1 descr done enable */ +#define VDE_I_DMA1TDEN 0x00800000 /* DMA 1 trans done enable */ +#define VDE_I_C1AVEN 0x01000000 /* cap 1 act vid end enable */ +#define VDE_I_HQV0EN 0x02000000 /* First hqv engine enable */ +#define VDE_I_C1VBIEN 0x04000000 /* Cap 1 VBI end enable */ +#define VDE_I_LVDSSI 0x08000000 /* LVDS sense interrupt */ +#define VDE_I_C0AVEN 0x10000000 /* Cap 0 act vid end enable */ +#define VDE_I_C0VBIEN 0x20000000 /* Cap 0 VBI end enable */ +#define VDE_I_LVDSSIEN 0x40000000 /* LVDS Sense enable */ +#define VDE_I_ENABLE 0x80000000 /* Global interrupt enable */ + #endif /* __VIA_CORE_H__ */ -- cgit v1.2.1 From 3d28eb42c52a799c806082e6d856f634ed1db902 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Fri, 23 Apr 2010 10:04:12 -0600 Subject: viafb: Add a simple VX855 DMA engine driver This code provides a minimal amount of access to the DMA engine as needed by the camera driver. VX855 only; it's guaranteed not to work on other chipsets, so it won't try. Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Cc: Harald Welte Acked-by: Florian Tobias Schandinat Signed-off-by: Jonathan Corbet --- drivers/video/via/via-core.c | 232 +++++++++++++++++++++++++++++++++++++++++++ drivers/video/via/via-core.h | 29 ++++++ 2 files changed, 261 insertions(+) (limited to 'drivers/video') diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c index 701b95575747..9929bb1549b6 100644 --- a/drivers/video/via/via-core.c +++ b/drivers/video/via/via-core.c @@ -13,6 +13,7 @@ #include "global.h" #include +#include #include /* @@ -92,7 +93,238 @@ void viafb_irq_disable(u32 mask) } EXPORT_SYMBOL_GPL(viafb_irq_disable); +/* ---------------------------------------------------------------------- */ +/* + * Access to the DMA engine. This currently provides what the camera + * driver needs (i.e. outgoing only) but is easily expandable if need + * be. + */ + +/* + * There are four DMA channels in the vx855. For now, we only + * use one of them, though. Most of the time, the DMA channel + * will be idle, so we keep the IRQ handler unregistered except + * when some subsystem has indicated an interest. + */ +static int viafb_dma_users; +static DECLARE_COMPLETION(viafb_dma_completion); +/* + * This mutex protects viafb_dma_users and our global interrupt + * registration state; it also serializes access to the DMA + * engine. + */ +static DEFINE_MUTEX(viafb_dma_lock); + +/* + * The VX855 DMA descriptor (used for s/g transfers) looks + * like this. + */ +struct viafb_vx855_dma_descr { + u32 addr_low; /* Low part of phys addr */ + u32 addr_high; /* High 12 bits of addr */ + u32 fb_offset; /* Offset into FB memory */ + u32 seg_size; /* Size, 16-byte units */ + u32 tile_mode; /* "tile mode" setting */ + u32 next_desc_low; /* Next descriptor addr */ + u32 next_desc_high; + u32 pad; /* Fill out to 64 bytes */ +}; + +/* + * Flags added to the "next descriptor low" pointers + */ +#define VIAFB_DMA_MAGIC 0x01 /* ??? Just has to be there */ +#define VIAFB_DMA_FINAL_SEGMENT 0x02 /* Final segment */ + +/* + * The completion IRQ handler. + */ +static irqreturn_t viafb_dma_irq(int irq, void *data) +{ + int csr; + irqreturn_t ret = IRQ_NONE; + + spin_lock(&global_dev.reg_lock); + csr = viafb_mmio_read(VDMA_CSR0); + if (csr & VDMA_C_DONE) { + viafb_mmio_write(VDMA_CSR0, VDMA_C_DONE); + complete(&viafb_dma_completion); + ret = IRQ_HANDLED; + } + spin_unlock(&global_dev.reg_lock); + return ret; +} + +/* + * Indicate a need for DMA functionality. + */ +int viafb_request_dma(void) +{ + int ret = 0; + + /* + * Only VX855 is supported currently. + */ + if (global_dev.chip_type != UNICHROME_VX855) + return -ENODEV; + /* + * Note the new user and set up our interrupt handler + * if need be. + */ + mutex_lock(&viafb_dma_lock); + viafb_dma_users++; + if (viafb_dma_users == 1) { + ret = request_irq(global_dev.pdev->irq, viafb_dma_irq, + IRQF_SHARED, "via-dma", &viafb_dma_users); + if (ret) + viafb_dma_users--; + else + viafb_irq_enable(VDE_I_DMA0TDEN); + } + mutex_unlock(&viafb_dma_lock); + return ret; +} +EXPORT_SYMBOL_GPL(viafb_request_dma); + +void viafb_release_dma(void) +{ + mutex_lock(&viafb_dma_lock); + viafb_dma_users--; + if (viafb_dma_users == 0) { + viafb_irq_disable(VDE_I_DMA0TDEN); + free_irq(global_dev.pdev->irq, &viafb_dma_users); + } + mutex_unlock(&viafb_dma_lock); +} +EXPORT_SYMBOL_GPL(viafb_release_dma); + + +#if 0 +/* + * Copy a single buffer from FB memory, synchronously. This code works + * but is not currently used. + */ +void viafb_dma_copy_out(unsigned int offset, dma_addr_t paddr, int len) +{ + unsigned long flags; + int csr; + + mutex_lock(&viafb_dma_lock); + init_completion(&viafb_dma_completion); + /* + * Program the controller. + */ + spin_lock_irqsave(&global_dev.reg_lock, flags); + viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_DONE); + /* Enable ints; must happen after CSR0 write! */ + viafb_mmio_write(VDMA_MR0, VDMA_MR_TDIE); + viafb_mmio_write(VDMA_MARL0, (int) (paddr & 0xfffffff0)); + viafb_mmio_write(VDMA_MARH0, (int) ((paddr >> 28) & 0xfff)); + /* Data sheet suggests DAR0 should be <<4, but it lies */ + viafb_mmio_write(VDMA_DAR0, offset); + viafb_mmio_write(VDMA_DQWCR0, len >> 4); + viafb_mmio_write(VDMA_TMR0, 0); + viafb_mmio_write(VDMA_DPRL0, 0); + viafb_mmio_write(VDMA_DPRH0, 0); + viafb_mmio_write(VDMA_PMR0, 0); + csr = viafb_mmio_read(VDMA_CSR0); + viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_START); + spin_unlock_irqrestore(&global_dev.reg_lock, flags); + /* + * Now we just wait until the interrupt handler says + * we're done. + */ + wait_for_completion_interruptible(&viafb_dma_completion); + viafb_mmio_write(VDMA_MR0, 0); /* Reset int enable */ + mutex_unlock(&viafb_dma_lock); +} +EXPORT_SYMBOL_GPL(viafb_dma_copy_out); +#endif + +/* + * Do a scatter/gather DMA copy from FB memory. You must have done + * a successful call to viafb_request_dma() first. + */ +int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg) +{ + struct viafb_vx855_dma_descr *descr; + void *descrpages; + dma_addr_t descr_handle; + unsigned long flags; + int i; + struct scatterlist *sgentry; + dma_addr_t nextdesc; + /* + * Get a place to put the descriptors. + */ + descrpages = dma_alloc_coherent(&global_dev.pdev->dev, + nsg*sizeof(struct viafb_vx855_dma_descr), + &descr_handle, GFP_KERNEL); + if (descrpages == NULL) { + dev_err(&global_dev.pdev->dev, "Unable to get descr page.\n"); + return -ENOMEM; + } + mutex_lock(&viafb_dma_lock); + /* + * Fill them in. + */ + descr = descrpages; + nextdesc = descr_handle + sizeof(struct viafb_vx855_dma_descr); + for_each_sg(sg, sgentry, nsg, i) { + dma_addr_t paddr = sg_dma_address(sgentry); + descr->addr_low = paddr & 0xfffffff0; + descr->addr_high = ((u64) paddr >> 32) & 0x0fff; + descr->fb_offset = offset; + descr->seg_size = sg_dma_len(sgentry) >> 4; + descr->tile_mode = 0; + descr->next_desc_low = (nextdesc&0xfffffff0) | VIAFB_DMA_MAGIC; + descr->next_desc_high = ((u64) nextdesc >> 32) & 0x0fff; + descr->pad = 0xffffffff; /* VIA driver does this */ + offset += sg_dma_len(sgentry); + nextdesc += sizeof(struct viafb_vx855_dma_descr); + descr++; + } + descr[-1].next_desc_low = VIAFB_DMA_FINAL_SEGMENT|VIAFB_DMA_MAGIC; + /* + * Program the engine. + */ + spin_lock_irqsave(&global_dev.reg_lock, flags); + init_completion(&viafb_dma_completion); + viafb_mmio_write(VDMA_DQWCR0, 0); + viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_DONE); + viafb_mmio_write(VDMA_MR0, VDMA_MR_TDIE | VDMA_MR_CHAIN); + viafb_mmio_write(VDMA_DPRL0, descr_handle | VIAFB_DMA_MAGIC); + viafb_mmio_write(VDMA_DPRH0, + (((u64)descr_handle >> 32) & 0x0fff) | 0xf0000); + (void) viafb_mmio_read(VDMA_CSR0); + viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_START); + spin_unlock_irqrestore(&global_dev.reg_lock, flags); + /* + * Now we just wait until the interrupt handler says + * we're done. Except that, actually, we need to wait a little + * longer: the interrupts seem to jump the gun a little and we + * get corrupted frames sometimes. + */ + wait_for_completion_timeout(&viafb_dma_completion, 1); + msleep(1); + if ((viafb_mmio_read(VDMA_CSR0)&VDMA_C_DONE) == 0) + printk(KERN_ERR "VIA DMA timeout!\n"); + /* + * Clean up and we're done. + */ + viafb_mmio_write(VDMA_CSR0, VDMA_C_DONE); + viafb_mmio_write(VDMA_MR0, 0); /* Reset int enable */ + mutex_unlock(&viafb_dma_lock); + dma_free_coherent(&global_dev.pdev->dev, + nsg*sizeof(struct viafb_vx855_dma_descr), descrpages, + descr_handle); + return 0; +} +EXPORT_SYMBOL_GPL(viafb_dma_copy_out_sg); + + +/* ---------------------------------------------------------------------- */ /* * Figure out how big our framebuffer memory is. Kind of ugly, * but evidently we can't trust the information found in the diff --git a/drivers/video/via/via-core.h b/drivers/video/via/via-core.h index ba64b36d58e3..3d03141d6074 100644 --- a/drivers/video/via/via-core.h +++ b/drivers/video/via/via-core.h @@ -131,4 +131,33 @@ void viafb_irq_disable(u32 mask); #define VDE_I_LVDSSIEN 0x40000000 /* LVDS Sense enable */ #define VDE_I_ENABLE 0x80000000 /* Global interrupt enable */ +/* + * DMA management. + */ +int viafb_request_dma(void); +void viafb_release_dma(void); +/* void viafb_dma_copy_out(unsigned int offset, dma_addr_t paddr, int len); */ +int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg); + +/* + * DMA Controller registers. + */ +#define VDMA_MR0 0xe00 /* Mod reg 0 */ +#define VDMA_MR_CHAIN 0x01 /* Chaining mode */ +#define VDMA_MR_TDIE 0x02 /* Transfer done int enable */ +#define VDMA_CSR0 0xe04 /* Control/status */ +#define VDMA_C_ENABLE 0x01 /* DMA Enable */ +#define VDMA_C_START 0x02 /* Start a transfer */ +#define VDMA_C_ABORT 0x04 /* Abort a transfer */ +#define VDMA_C_DONE 0x08 /* Transfer is done */ +#define VDMA_MARL0 0xe20 /* Mem addr low */ +#define VDMA_MARH0 0xe24 /* Mem addr high */ +#define VDMA_DAR0 0xe28 /* Device address */ +#define VDMA_DQWCR0 0xe2c /* Count (16-byte) */ +#define VDMA_TMR0 0xe30 /* Tile mode reg */ +#define VDMA_DPRL0 0xe34 /* Not sure */ +#define VDMA_DPR_IN 0x08 /* Inbound transfer to FB */ +#define VDMA_DPRH0 0xe38 +#define VDMA_PMR0 (0xe00 + 0x134) /* Pitch mode */ + #endif /* __VIA_CORE_H__ */ -- cgit v1.2.1 From c2b12cd496bbe5eff6a48bc669fe6b0c56f2b3d9 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Fri, 23 Apr 2010 10:31:13 -0600 Subject: viafb: Reserve framebuffer memory for the upcoming camera driver The camera engine captures to framebuffer memory, so we need to set some aside for that purpose. There is no proper memory allocator for fbmem; instead, accel.c just trims some space off the top. Alas, without creating that proper memory allocator, the only way to make this work is to hack it into the same bit of code in accel.c. The allocation must happen *after* the others (some code, including user-space XV stuff, makes assumptions on where the cursor space is), and before the rest of the framebuffer is set up. Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Cc: Harald Welte Acked-by: Florian Tobias Schandinat Signed-off-by: Jonathan Corbet --- drivers/video/via/accel.c | 16 ++++++++++++++++ drivers/video/via/via-core.h | 10 ++++++++++ 2 files changed, 26 insertions(+) (limited to 'drivers/video') diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c index e77746857c8f..189aba41f9b9 100644 --- a/drivers/video/via/accel.c +++ b/drivers/video/via/accel.c @@ -370,6 +370,22 @@ int viafb_init_engine(struct fb_info *info) viapar->shared->vq_vram_addr = viapar->fbmem_free; viapar->fbmem_used += VQ_SIZE; +#if defined(CONFIG_FB_VIA_CAMERA) || defined(CONFIG_FB_VIA_CAMERA_MODULE) + /* + * Set aside a chunk of framebuffer memory for the camera + * driver. Someday this driver probably needs a proper allocator + * for fbmem; for now, we just have to do this before the + * framebuffer initializes itself. + * + * As for the size: the engine can handle three frames, + * 16 bits deep, up to VGA resolution. + */ + viapar->shared->vdev->camera_fbmem_size = 3*VGA_HEIGHT*VGA_WIDTH*2; + viapar->fbmem_free -= viapar->shared->vdev->camera_fbmem_size; + viapar->fbmem_used += viapar->shared->vdev->camera_fbmem_size; + viapar->shared->vdev->camera_fbmem_offset = viapar->fbmem_free; +#endif + /* Init AGP and VQ regs */ switch (chip_name) { case UNICHROME_K8M890: diff --git a/drivers/video/via/via-core.h b/drivers/video/via/via-core.h index 3d03141d6074..087c562abaec 100644 --- a/drivers/video/via/via-core.h +++ b/drivers/video/via/via-core.h @@ -78,6 +78,10 @@ struct viafb_dev { unsigned long fbmem_start; long fbmem_len; void __iomem *fbmem; +#if defined(CONFIG_FB_VIA_CAMERA) || defined(CONFIG_FB_VIA_CAMERA_MODULE) + long camera_fbmem_offset; + long camera_fbmem_size; +#endif /* * The MMIO region for device registers. */ @@ -160,4 +164,10 @@ int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg); #define VDMA_DPRH0 0xe38 #define VDMA_PMR0 (0xe00 + 0x134) /* Pitch mode */ +/* + * Useful stuff that probably belongs somewhere global. + */ +#define VGA_WIDTH 640 +#define VGA_HEIGHT 480 + #endif /* __VIA_CORE_H__ */ -- cgit v1.2.1 From 2749413db17723cf894036c0eaf339f289bcc841 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sat, 17 Apr 2010 19:44:52 +0000 Subject: viafb: unify modesetting functions viafb: unify modesetting functions This patch unifies some cleaned up modesetting functions to prepare for moving them to an extra file. This includes make them use via_io and changing there names to reflect that they do not depend on anything framebuffer specific. Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/hw.c | 66 ++++++++++++++++++++++---------------------- drivers/video/via/hw.h | 8 +++--- drivers/video/via/viafbdev.c | 17 ++++++------ 3 files changed, 46 insertions(+), 45 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index 805151f48ea9..1628a5f93dc2 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -624,50 +624,50 @@ void viafb_set_iga_path(void) } } -void viafb_set_primary_address(u32 addr) +void via_set_primary_address(u32 addr) { - DEBUG_MSG(KERN_DEBUG "viafb_set_primary_address(0x%08X)\n", addr); - viafb_write_reg(CR0D, VIACR, addr & 0xFF); - viafb_write_reg(CR0C, VIACR, (addr >> 8) & 0xFF); - viafb_write_reg(CR34, VIACR, (addr >> 16) & 0xFF); - viafb_write_reg_mask(CR48, VIACR, (addr >> 24) & 0x1F, 0x1F); + DEBUG_MSG(KERN_DEBUG "via_set_primary_address(0x%08X)\n", addr); + via_write_reg(VIACR, 0x0D, addr & 0xFF); + via_write_reg(VIACR, 0x0C, (addr >> 8) & 0xFF); + via_write_reg(VIACR, 0x34, (addr >> 16) & 0xFF); + via_write_reg_mask(VIACR, 0x48, (addr >> 24) & 0x1F, 0x1F); } -void viafb_set_secondary_address(u32 addr) +void via_set_secondary_address(u32 addr) { - DEBUG_MSG(KERN_DEBUG "viafb_set_secondary_address(0x%08X)\n", addr); + DEBUG_MSG(KERN_DEBUG "via_set_secondary_address(0x%08X)\n", addr); /* secondary display supports only quadword aligned memory */ - viafb_write_reg_mask(CR62, VIACR, (addr >> 2) & 0xFE, 0xFE); - viafb_write_reg(CR63, VIACR, (addr >> 10) & 0xFF); - viafb_write_reg(CR64, VIACR, (addr >> 18) & 0xFF); - viafb_write_reg_mask(CRA3, VIACR, (addr >> 26) & 0x07, 0x07); + via_write_reg_mask(VIACR, 0x62, (addr >> 2) & 0xFE, 0xFE); + via_write_reg(VIACR, 0x63, (addr >> 10) & 0xFF); + via_write_reg(VIACR, 0x64, (addr >> 18) & 0xFF); + via_write_reg_mask(VIACR, 0xA3, (addr >> 26) & 0x07, 0x07); } -void viafb_set_primary_pitch(u32 pitch) +void via_set_primary_pitch(u32 pitch) { - DEBUG_MSG(KERN_DEBUG "viafb_set_primary_pitch(0x%08X)\n", pitch); + DEBUG_MSG(KERN_DEBUG "via_set_primary_pitch(0x%08X)\n", pitch); /* spec does not say that first adapter skips 3 bits but old * code did it and seems to be reasonable in analogy to 2nd adapter */ pitch = pitch >> 3; - viafb_write_reg(0x13, VIACR, pitch & 0xFF); - viafb_write_reg_mask(0x35, VIACR, (pitch >> (8 - 5)) & 0xE0, 0xE0); + via_write_reg(VIACR, 0x13, pitch & 0xFF); + via_write_reg_mask(VIACR, 0x35, (pitch >> (8 - 5)) & 0xE0, 0xE0); } -void viafb_set_secondary_pitch(u32 pitch) +void via_set_secondary_pitch(u32 pitch) { - DEBUG_MSG(KERN_DEBUG "viafb_set_secondary_pitch(0x%08X)\n", pitch); + DEBUG_MSG(KERN_DEBUG "via_set_secondary_pitch(0x%08X)\n", pitch); pitch = pitch >> 3; - viafb_write_reg(0x66, VIACR, pitch & 0xFF); - viafb_write_reg_mask(0x67, VIACR, (pitch >> 8) & 0x03, 0x03); - viafb_write_reg_mask(0x71, VIACR, (pitch >> (10 - 7)) & 0x80, 0x80); + via_write_reg(VIACR, 0x66, pitch & 0xFF); + via_write_reg_mask(VIACR, 0x67, (pitch >> 8) & 0x03, 0x03); + via_write_reg_mask(VIACR, 0x71, (pitch >> (10 - 7)) & 0x80, 0x80); } -void viafb_set_primary_color_depth(u8 depth) +void via_set_primary_color_depth(u8 depth) { u8 value; - DEBUG_MSG(KERN_DEBUG "viafb_set_primary_color_depth(%d)\n", depth); + DEBUG_MSG(KERN_DEBUG "via_set_primary_color_depth(%d)\n", depth); switch (depth) { case 8: value = 0x00; @@ -685,19 +685,19 @@ void viafb_set_primary_color_depth(u8 depth) value = 0x08; break; default: - printk(KERN_WARNING "viafb_set_primary_color_depth: " + printk(KERN_WARNING "via_set_primary_color_depth: " "Unsupported depth: %d\n", depth); return; } - viafb_write_reg_mask(0x15, VIASR, value, 0x1C); + via_write_reg_mask(VIASR, 0x15, value, 0x1C); } -void viafb_set_secondary_color_depth(u8 depth) +void via_set_secondary_color_depth(u8 depth) { u8 value; - DEBUG_MSG(KERN_DEBUG "viafb_set_secondary_color_depth(%d)\n", depth); + DEBUG_MSG(KERN_DEBUG "via_set_secondary_color_depth(%d)\n", depth); switch (depth) { case 8: value = 0x00; @@ -712,12 +712,12 @@ void viafb_set_secondary_color_depth(u8 depth) value = 0x80; break; default: - printk(KERN_WARNING "viafb_set_secondary_color_depth: " + printk(KERN_WARNING "via_set_secondary_color_depth: " "Unsupported depth: %d\n", depth); return; } - viafb_write_reg_mask(0x67, VIACR, value, 0xC0); + via_write_reg_mask(VIACR, 0x67, value, 0xC0); } static void set_color_register(u8 index, u8 red, u8 green, u8 blue) @@ -2268,11 +2268,11 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, } } - viafb_set_primary_pitch(viafbinfo->fix.line_length); - viafb_set_secondary_pitch(viafb_dual_fb ? viafbinfo1->fix.line_length + via_set_primary_pitch(viafbinfo->fix.line_length); + via_set_secondary_pitch(viafb_dual_fb ? viafbinfo1->fix.line_length : viafbinfo->fix.line_length); - viafb_set_primary_color_depth(viaparinfo->depth); - viafb_set_secondary_color_depth(viafb_dual_fb ? viaparinfo1->depth + via_set_primary_color_depth(viaparinfo->depth); + via_set_secondary_color_depth(viafb_dual_fb ? viaparinfo1->depth : viaparinfo->depth); /* Update Refresh Rate Setting */ diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index 23c319010913..641a5fa4bd33 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h @@ -910,10 +910,10 @@ void viafb_update_device_setting(int hres, int vres, int bpp, int vmode_refresh, int flag); void viafb_set_iga_path(void); -void viafb_set_primary_address(u32 addr); -void viafb_set_secondary_address(u32 addr); -void viafb_set_primary_pitch(u32 pitch); -void viafb_set_secondary_pitch(u32 pitch); +void via_set_primary_address(u32 addr); +void via_set_secondary_address(u32 addr); +void via_set_primary_pitch(u32 pitch); +void via_set_secondary_pitch(u32 pitch); void viafb_set_primary_color_register(u8 index, u8 red, u8 green, u8 blue); void viafb_set_secondary_color_register(u8 index, u8 red, u8 green, u8 blue); void viafb_get_fb_info(unsigned int *fb_base, unsigned int *fb_len); diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 70ed71facd87..e94f913f87be 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -317,12 +317,12 @@ static int viafb_pan_display(struct fb_var_screeninfo *var, DEBUG_MSG(KERN_DEBUG "viafb_pan_display, address = %d\n", vram_addr); if (!viafb_dual_fb) { - viafb_set_primary_address(vram_addr); - viafb_set_secondary_address(vram_addr); + via_set_primary_address(vram_addr); + via_set_secondary_address(vram_addr); } else if (viapar->iga_path == IGA1) - viafb_set_primary_address(vram_addr); + via_set_primary_address(vram_addr); else - viafb_set_secondary_address(vram_addr); + via_set_secondary_address(vram_addr); return 0; } @@ -1018,8 +1018,8 @@ static void viafb_set_device(struct device_t active_dev) viafb_SAMM_ON = active_dev.samm; viafb_primary_dev = active_dev.primary_dev; - viafb_set_primary_address(0); - viafb_set_secondary_address(viafb_SAMM_ON ? viafb_second_offset : 0); + via_set_primary_address(0); + via_set_secondary_address(viafb_SAMM_ON ? viafb_second_offset : 0); viafb_set_iga_path(); } @@ -1165,8 +1165,9 @@ static int apply_device_setting(struct viafb_ioctl_setting setting_info, if (viafb_SAMM_ON) viafb_primary_dev = setting_info.primary_device; - viafb_set_primary_address(0); - viafb_set_secondary_address(viafb_SAMM_ON ? viafb_second_offset : 0); + via_set_primary_address(0); + via_set_secondary_address(viafb_SAMM_ON ? + viafb_second_offset : 0); viafb_set_iga_path(); } need_set_mode = 1; -- cgit v1.2.1 From 100e74a150d3a31d4c12658c926429ceb880d2f7 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sat, 17 Apr 2010 19:44:53 +0000 Subject: viafb: move some modesetting functions to a seperate file viafb: move some modesetting functions to a seperate file This patch moves the modesetting functions which are already cleaned up to a seperate file. Just the beginning to bring some structure in this mess. Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/Makefile | 3 +- drivers/video/via/hw.c | 96 --------------------------- drivers/video/via/hw.h | 5 +- drivers/video/via/via_modesetting.c | 126 ++++++++++++++++++++++++++++++++++++ drivers/video/via/via_modesetting.h | 38 +++++++++++ 5 files changed, 166 insertions(+), 102 deletions(-) create mode 100644 drivers/video/via/via_modesetting.c create mode 100644 drivers/video/via/via_modesetting.h (limited to 'drivers/video') diff --git a/drivers/video/via/Makefile b/drivers/video/via/Makefile index 8c42a42c3dbb..d496adb0f832 100644 --- a/drivers/video/via/Makefile +++ b/drivers/video/via/Makefile @@ -6,5 +6,4 @@ obj-$(CONFIG_FB_VIA) += viafb.o viafb-y :=viafbdev.o hw.o via_i2c.o dvi.o lcd.o ioctl.o accel.o \ via_utility.o vt1636.o global.o tblDPASetting.o viamode.o tbl1636.o \ - via-core.o via-gpio.o - + via-core.o via-gpio.o via_modesetting.o diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index 1628a5f93dc2..d474fbee3350 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -624,102 +624,6 @@ void viafb_set_iga_path(void) } } -void via_set_primary_address(u32 addr) -{ - DEBUG_MSG(KERN_DEBUG "via_set_primary_address(0x%08X)\n", addr); - via_write_reg(VIACR, 0x0D, addr & 0xFF); - via_write_reg(VIACR, 0x0C, (addr >> 8) & 0xFF); - via_write_reg(VIACR, 0x34, (addr >> 16) & 0xFF); - via_write_reg_mask(VIACR, 0x48, (addr >> 24) & 0x1F, 0x1F); -} - -void via_set_secondary_address(u32 addr) -{ - DEBUG_MSG(KERN_DEBUG "via_set_secondary_address(0x%08X)\n", addr); - /* secondary display supports only quadword aligned memory */ - via_write_reg_mask(VIACR, 0x62, (addr >> 2) & 0xFE, 0xFE); - via_write_reg(VIACR, 0x63, (addr >> 10) & 0xFF); - via_write_reg(VIACR, 0x64, (addr >> 18) & 0xFF); - via_write_reg_mask(VIACR, 0xA3, (addr >> 26) & 0x07, 0x07); -} - -void via_set_primary_pitch(u32 pitch) -{ - DEBUG_MSG(KERN_DEBUG "via_set_primary_pitch(0x%08X)\n", pitch); - /* spec does not say that first adapter skips 3 bits but old - * code did it and seems to be reasonable in analogy to 2nd adapter - */ - pitch = pitch >> 3; - via_write_reg(VIACR, 0x13, pitch & 0xFF); - via_write_reg_mask(VIACR, 0x35, (pitch >> (8 - 5)) & 0xE0, 0xE0); -} - -void via_set_secondary_pitch(u32 pitch) -{ - DEBUG_MSG(KERN_DEBUG "via_set_secondary_pitch(0x%08X)\n", pitch); - pitch = pitch >> 3; - via_write_reg(VIACR, 0x66, pitch & 0xFF); - via_write_reg_mask(VIACR, 0x67, (pitch >> 8) & 0x03, 0x03); - via_write_reg_mask(VIACR, 0x71, (pitch >> (10 - 7)) & 0x80, 0x80); -} - -void via_set_primary_color_depth(u8 depth) -{ - u8 value; - - DEBUG_MSG(KERN_DEBUG "via_set_primary_color_depth(%d)\n", depth); - switch (depth) { - case 8: - value = 0x00; - break; - case 15: - value = 0x04; - break; - case 16: - value = 0x14; - break; - case 24: - value = 0x0C; - break; - case 30: - value = 0x08; - break; - default: - printk(KERN_WARNING "via_set_primary_color_depth: " - "Unsupported depth: %d\n", depth); - return; - } - - via_write_reg_mask(VIASR, 0x15, value, 0x1C); -} - -void via_set_secondary_color_depth(u8 depth) -{ - u8 value; - - DEBUG_MSG(KERN_DEBUG "via_set_secondary_color_depth(%d)\n", depth); - switch (depth) { - case 8: - value = 0x00; - break; - case 16: - value = 0x40; - break; - case 24: - value = 0xC0; - break; - case 30: - value = 0x80; - break; - default: - printk(KERN_WARNING "via_set_secondary_color_depth: " - "Unsupported depth: %d\n", depth); - return; - } - - via_write_reg_mask(VIACR, 0x67, value, 0xC0); -} - static void set_color_register(u8 index, u8 red, u8 green, u8 blue) { outb(0xFF, 0x3C6); /* bit mask of palette */ diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index 641a5fa4bd33..a58701f3bf7f 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h @@ -25,6 +25,7 @@ #include "viamode.h" #include "global.h" #include "via_io.h" +#include "via_modesetting.h" #define viafb_read_reg(p, i) via_read_reg(p, i) #define viafb_write_reg(i, p, d) via_write_reg(p, i, d) @@ -910,10 +911,6 @@ void viafb_update_device_setting(int hres, int vres, int bpp, int vmode_refresh, int flag); void viafb_set_iga_path(void); -void via_set_primary_address(u32 addr); -void via_set_secondary_address(u32 addr); -void via_set_primary_pitch(u32 pitch); -void via_set_secondary_pitch(u32 pitch); void viafb_set_primary_color_register(u8 index, u8 red, u8 green, u8 blue); void viafb_set_secondary_color_register(u8 index, u8 red, u8 green, u8 blue); void viafb_get_fb_info(unsigned int *fb_base, unsigned int *fb_len); diff --git a/drivers/video/via/via_modesetting.c b/drivers/video/via/via_modesetting.c new file mode 100644 index 000000000000..69ff28575008 --- /dev/null +++ b/drivers/video/via/via_modesetting.c @@ -0,0 +1,126 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + * Copyright 2010 Florian Tobias Schandinat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +/* + * basic modesetting functions + */ + +#include +#include "via_modesetting.h" +#include "via_io.h" +#include "share.h" +#include "debug.h" + +void via_set_primary_address(u32 addr) +{ + DEBUG_MSG(KERN_DEBUG "via_set_primary_address(0x%08X)\n", addr); + via_write_reg(VIACR, 0x0D, addr & 0xFF); + via_write_reg(VIACR, 0x0C, (addr >> 8) & 0xFF); + via_write_reg(VIACR, 0x34, (addr >> 16) & 0xFF); + via_write_reg_mask(VIACR, 0x48, (addr >> 24) & 0x1F, 0x1F); +} + +void via_set_secondary_address(u32 addr) +{ + DEBUG_MSG(KERN_DEBUG "via_set_secondary_address(0x%08X)\n", addr); + /* secondary display supports only quadword aligned memory */ + via_write_reg_mask(VIACR, 0x62, (addr >> 2) & 0xFE, 0xFE); + via_write_reg(VIACR, 0x63, (addr >> 10) & 0xFF); + via_write_reg(VIACR, 0x64, (addr >> 18) & 0xFF); + via_write_reg_mask(VIACR, 0xA3, (addr >> 26) & 0x07, 0x07); +} + +void via_set_primary_pitch(u32 pitch) +{ + DEBUG_MSG(KERN_DEBUG "via_set_primary_pitch(0x%08X)\n", pitch); + /* spec does not say that first adapter skips 3 bits but old + * code did it and seems to be reasonable in analogy to 2nd adapter + */ + pitch = pitch >> 3; + via_write_reg(VIACR, 0x13, pitch & 0xFF); + via_write_reg_mask(VIACR, 0x35, (pitch >> (8 - 5)) & 0xE0, 0xE0); +} + +void via_set_secondary_pitch(u32 pitch) +{ + DEBUG_MSG(KERN_DEBUG "via_set_secondary_pitch(0x%08X)\n", pitch); + pitch = pitch >> 3; + via_write_reg(VIACR, 0x66, pitch & 0xFF); + via_write_reg_mask(VIACR, 0x67, (pitch >> 8) & 0x03, 0x03); + via_write_reg_mask(VIACR, 0x71, (pitch >> (10 - 7)) & 0x80, 0x80); +} + +void via_set_primary_color_depth(u8 depth) +{ + u8 value; + + DEBUG_MSG(KERN_DEBUG "via_set_primary_color_depth(%d)\n", depth); + switch (depth) { + case 8: + value = 0x00; + break; + case 15: + value = 0x04; + break; + case 16: + value = 0x14; + break; + case 24: + value = 0x0C; + break; + case 30: + value = 0x08; + break; + default: + printk(KERN_WARNING "via_set_primary_color_depth: " + "Unsupported depth: %d\n", depth); + return; + } + + via_write_reg_mask(VIASR, 0x15, value, 0x1C); +} + +void via_set_secondary_color_depth(u8 depth) +{ + u8 value; + + DEBUG_MSG(KERN_DEBUG "via_set_secondary_color_depth(%d)\n", depth); + switch (depth) { + case 8: + value = 0x00; + break; + case 16: + value = 0x40; + break; + case 24: + value = 0xC0; + break; + case 30: + value = 0x80; + break; + default: + printk(KERN_WARNING "via_set_secondary_color_depth: " + "Unsupported depth: %d\n", depth); + return; + } + + via_write_reg_mask(VIACR, 0x67, value, 0xC0); +} diff --git a/drivers/video/via/via_modesetting.h b/drivers/video/via/via_modesetting.h new file mode 100644 index 000000000000..ae35cfdeb37c --- /dev/null +++ b/drivers/video/via/via_modesetting.h @@ -0,0 +1,38 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + * Copyright 2010 Florian Tobias Schandinat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +/* + * basic modesetting functions + */ + +#ifndef __VIA_MODESETTING_H__ +#define __VIA_MODESETTING_H__ + +#include + +void via_set_primary_address(u32 addr); +void via_set_secondary_address(u32 addr); +void via_set_primary_pitch(u32 pitch); +void via_set_secondary_pitch(u32 pitch); +void via_set_primary_color_depth(u8 depth); +void via_set_secondary_color_depth(u8 depth); + +#endif /* __VIA_MODESETTING_H__ */ -- cgit v1.2.1 From 384c3041aeaf77d299b0d4a62481850fed86e53b Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sat, 17 Apr 2010 19:44:54 +0000 Subject: viafb: replace inb/outb viafb: replace inb/outb This patch replaces occurences of inb/outb with via_write_reg and via_write_reg_mask where this is possible to improve code readability. Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/hw.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index d474fbee3350..b2bb24e23f33 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -1008,16 +1008,12 @@ void viafb_load_reg(int timing_value, int viafb_load_reg_num, void viafb_write_regx(struct io_reg RegTable[], int ItemNum) { int i; - unsigned char RegTemp; /*DEBUG_MSG(KERN_INFO "Table Size : %x!!\n",ItemNum ); */ - for (i = 0; i < ItemNum; i++) { - outb(RegTable[i].index, RegTable[i].port); - RegTemp = inb(RegTable[i].port + 1); - RegTemp = (RegTemp & (~RegTable[i].mask)) | RegTable[i].value; - outb(RegTemp, RegTable[i].port + 1); - } + for (i = 0; i < ItemNum; i++) + via_write_reg_mask(RegTable[i].port, RegTable[i].index, + RegTable[i].value, RegTable[i].mask); } void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga) @@ -2130,10 +2126,8 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, outb(VPIT.Misc, VIAWMisc); /* Write Sequencer */ - for (i = 1; i <= StdSR; i++) { - outb(i, VIASR); - outb(VPIT.SR[i - 1], VIASR + 1); - } + for (i = 1; i <= StdSR; i++) + via_write_reg(VIASR, i, VPIT.SR[i - 1]); viafb_write_reg_mask(0x15, VIASR, 0xA2, 0xA2); viafb_set_iga_path(); @@ -2142,10 +2136,8 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, viafb_fill_crtc_timing(crt_timing, vmode_tbl, video_bpp / 8, IGA1); /* Write Graphic Controller */ - for (i = 0; i < StdGR; i++) { - outb(i, VIAGR); - outb(VPIT.GR[i], VIAGR + 1); - } + for (i = 0; i < StdGR; i++) + via_write_reg(VIAGR, i, VPIT.GR[i]); /* Write Attribute Controller */ for (i = 0; i < StdAR; i++) { -- cgit v1.2.1 From 162fc8c0c03d5b8536f14cbd2cdfb399c50c05ec Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sat, 17 Apr 2010 19:44:55 +0000 Subject: viafb: improve misc register handling viafb: improve misc register handling This patch improves the misc register handling by adding a modify function for this to via_io.h and moving expanded definitions of the relevant ports there. The code was changed to use those to improve readability. Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/hw.c | 27 ++++++++------------------- drivers/video/via/share.h | 2 -- drivers/video/via/via_io.h | 9 +++++++++ 3 files changed, 17 insertions(+), 21 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index b2bb24e23f33..e356fe8d8a90 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -1394,8 +1394,6 @@ u32 viafb_get_clk_value(int clk) /* Set VCLK*/ void viafb_set_vclock(u32 CLK, int set_iga) { - unsigned char RegTemp; - /* H.W. Reset : ON */ viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7); @@ -1468,8 +1466,7 @@ void viafb_set_vclock(u32 CLK, int set_iga) } /* Fire! */ - RegTemp = inb(VIARMisc); - outb(RegTemp | (BIT2 + BIT3), VIAWMisc); + via_write_misc_reg_mask(0x0C, 0x0C); /* select external clock */ } void viafb_load_crtc_timing(struct display_timing device_timing, @@ -1713,6 +1710,7 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, int index = 0; int h_addr, v_addr; u32 pll_D_N; + u8 polarity = 0; for (i = 0; i < video_mode->mode_array; i++) { index = i; @@ -1741,20 +1739,11 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, v_addr = crt_reg.ver_addr; /* update polarity for CRT timing */ - if (crt_table[index].h_sync_polarity == NEGATIVE) { - if (crt_table[index].v_sync_polarity == NEGATIVE) - outb((inb(VIARMisc) & (~(BIT6 + BIT7))) | - (BIT6 + BIT7), VIAWMisc); - else - outb((inb(VIARMisc) & (~(BIT6 + BIT7))) | (BIT6), - VIAWMisc); - } else { - if (crt_table[index].v_sync_polarity == NEGATIVE) - outb((inb(VIARMisc) & (~(BIT6 + BIT7))) | (BIT7), - VIAWMisc); - else - outb((inb(VIARMisc) & (~(BIT6 + BIT7))), VIAWMisc); - } + if (crt_table[index].h_sync_polarity == NEGATIVE) + polarity |= BIT6; + if (crt_table[index].v_sync_polarity == NEGATIVE) + polarity |= BIT7; + via_write_misc_reg_mask(polarity, BIT6 | BIT7); if (set_iga == IGA1) { viafb_unlock_crt(); @@ -2123,7 +2112,7 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, /* Fill VPIT Parameters */ /* Write Misc Register */ - outb(VPIT.Misc, VIAWMisc); + outb(VPIT.Misc, VIA_MISC_REG_WRITE); /* Write Sequencer */ for (i = 1; i <= StdSR; i++) diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h index f974c7333522..861b4142efad 100644 --- a/drivers/video/via/share.h +++ b/drivers/video/via/share.h @@ -45,8 +45,6 @@ /* standard VGA IO port */ -#define VIARMisc 0x3CC -#define VIAWMisc 0x3C2 #define VIAStatus 0x3DA #define VIACR 0x3D4 #define VIASR 0x3C4 diff --git a/drivers/video/via/via_io.h b/drivers/video/via/via_io.h index e1c1093def00..a3d2aca65540 100644 --- a/drivers/video/via/via_io.h +++ b/drivers/video/via/via_io.h @@ -29,6 +29,9 @@ #include #include +#define VIA_MISC_REG_READ 0x03CC +#define VIA_MISC_REG_WRITE 0x03C2 + /* * Indexed port operations. Note that these are all multi-op * functions; every invocation will be racy if you're not holding @@ -55,4 +58,10 @@ static inline void via_write_reg_mask(u16 port, u8 index, u8 data, u8 mask) outb((data & mask) | (old & ~mask), port + 1); } +static inline void via_write_misc_reg_mask(u8 data, u8 mask) +{ + u8 old = inb(VIA_MISC_REG_READ); + outb((data & mask) | (old & ~mask), VIA_MISC_REG_WRITE); +} + #endif /* __VIA_IO_H__ */ -- cgit v1.2.1 From 2fed547c0298e1465d62b34a75a7b76353fee7d3 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sat, 17 Apr 2010 19:44:56 +0000 Subject: viafb: fix proc entry removal viafb: fix proc entry removal Trying to remove unregistered proc entries became painful and is useless anyway. So remove the removal of an entry that was never registered and duplicate the logic for one which is added conditionally. Additionally move the removal above releasing fb_info as we still need the information. This prevents tainting the kernel by the procfs warn on and avoiding access to already freed memory is probably also a good idea. Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/viafbdev.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index e94f913f87be..51e9106138ce 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -1702,13 +1702,16 @@ static void viafb_init_proc(struct proc_dir_entry **viafb_entry) } static void viafb_remove_proc(struct proc_dir_entry *viafb_entry) { - /* no problem if it was not registered */ + struct chip_information *chip_info = &viaparinfo->shared->chip_info; + remove_proc_entry("dvp0", viafb_entry);/* parent dir */ remove_proc_entry("dvp1", viafb_entry); remove_proc_entry("dfph", viafb_entry); remove_proc_entry("dfpl", viafb_entry); - remove_proc_entry("vt1636", viafb_entry); - remove_proc_entry("vt1625", viafb_entry); + if (chip_info->lvds_chip_info.lvds_chip_name == VT1636_LVDS + || chip_info->lvds_chip_info2.lvds_chip_name == VT1636_LVDS) + remove_proc_entry("vt1636", viafb_entry); + remove_proc_entry("viafb", NULL); } @@ -1967,12 +1970,10 @@ void __devexit via_fb_pci_remove(struct pci_dev *pdev) unregister_framebuffer(viafbinfo); if (viafb_dual_fb) unregister_framebuffer(viafbinfo1); - + viafb_remove_proc(viaparinfo->shared->proc_entry); framebuffer_release(viafbinfo); if (viafb_dual_fb) framebuffer_release(viafbinfo1); - - viafb_remove_proc(viaparinfo->shared->proc_entry); } #ifndef MODULE -- cgit v1.2.1 From 2b78a963c800252a0016785813cc5140c006145c Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sat, 17 Apr 2010 19:44:57 +0000 Subject: viafb: make procfs entries optional viafb: make procfs entries optional This patch adds a config option to enable procfs entries for direct hardware access. This was the old behaviour but the option defaults to no as this is really ugly and should not be needed if the driver works correct (and if it doesn't, it needs to be fixed). That stuff is really something that should - not be needed at all (the driver should be capable of doing it) - not be there (debugfs would be better for such things) So add this option just for backwards compatiblity. Signed-off-by: Florian Tobias Schandinat --- drivers/video/Kconfig | 14 ++++++++++++++ drivers/video/via/viafbdev.c | 8 ++++++++ 2 files changed, 22 insertions(+) (limited to 'drivers/video') diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 22c1662de964..fd55c279915c 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1522,6 +1522,20 @@ config FB_VIA To compile this driver as a module, choose M here: the module will be called viafb. +if FB_VIA + +config FB_VIA_DIRECT_PROCFS + bool "direct hardware access via procfs (DEPRECATED)(DANGEROUS)" + depends on FB_VIA + default n + help + Allow direct hardware access to some output registers via procfs. + This is dangerous but may provide the only chance to get the + correct output device configuration. + Its use is strongly discouraged. + +endif + config FB_NEOMAGIC tristate "NeoMagic display support" depends on FB && PCI diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 51e9106138ce..3d033186a822 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -1326,6 +1326,8 @@ static void parse_dvi_port(void) output_interface); } +#ifdef CONFIG_FB_VIA_DIRECT_PROCFS + /* * The proc filesystem read/write function, a simple proc implement to * get/set the value of DPA DVP0, DVP0DataDriving, DVP0ClockDriving, DVP1, @@ -1715,6 +1717,8 @@ static void viafb_remove_proc(struct proc_dir_entry *viafb_entry) remove_proc_entry("viafb", NULL); } +#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */ + static int parse_mode(const char *str, u32 *xres, u32 *yres) { char *ptr; @@ -1943,7 +1947,9 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev) viafbinfo->node, viafbinfo->fix.id, default_var.xres, default_var.yres, default_var.bits_per_pixel); +#ifdef CONFIG_FB_VIA_DIRECT_PROCFS viafb_init_proc(&viaparinfo->shared->proc_entry); +#endif viafb_init_dac(IGA2); return 0; @@ -1970,7 +1976,9 @@ void __devexit via_fb_pci_remove(struct pci_dev *pdev) unregister_framebuffer(viafbinfo); if (viafb_dual_fb) unregister_framebuffer(viafbinfo1); +#ifdef CONFIG_FB_VIA_DIRECT_PROCFS viafb_remove_proc(viaparinfo->shared->proc_entry); +#endif framebuffer_release(viafbinfo); if (viafb_dual_fb) framebuffer_release(viafbinfo1); -- cgit v1.2.1 From 27fe971d08b43f649358745a55f3c48ac6f413f8 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Fri, 30 Apr 2010 09:45:51 -0600 Subject: viafb: Do not remove gpiochip under spinlock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gpiochip_remove() is not meant to be called with interrupts disabled, and there is no need for the lock here in any case. Reported-by: Bruno Prémont Signed-off-by: Jonathan Corbet --- drivers/video/via/via-gpio.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/via-gpio.c b/drivers/video/via/via-gpio.c index 44537be1f070..63cb7acc0faf 100644 --- a/drivers/video/via/via-gpio.c +++ b/drivers/video/via/via-gpio.c @@ -246,7 +246,6 @@ static int viafb_gpio_remove(struct platform_device *platdev) unsigned long flags; int ret = 0, i; - spin_lock_irqsave(&gpio_config.vdev->reg_lock, flags); /* * Get unregistered. */ @@ -254,16 +253,16 @@ static int viafb_gpio_remove(struct platform_device *platdev) ret = gpiochip_remove(&gpio_config.gpio_chip); if (ret) { /* Somebody still using it? */ printk(KERN_ERR "Viafb: GPIO remove failed\n"); - goto out; + return ret; } } /* * Disable the ports. */ + spin_lock_irqsave(&gpio_config.vdev->reg_lock, flags); for (i = 0; i < gpio_config.gpio_chip.ngpio; i += 2) viafb_gpio_disable(gpio_config.active_gpios[i]); gpio_config.gpio_chip.ngpio = 0; -out: spin_unlock_irqrestore(&gpio_config.vdev->reg_lock, flags); return ret; } -- cgit v1.2.1 From 8bbf50fe9c0fb8d83b993ae6d88a4ce27d81b999 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Fri, 30 Apr 2010 10:03:57 -0600 Subject: viafb: Fix initialization error paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Properly localize error cleanup, and make sure that the iomem regions are unmapped if framebuffer initialization fails. Reported-by: Bruno Prémont Signed-off-by: Jonathan Corbet --- drivers/video/via/via-core.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c index 9929bb1549b6..188c0022dcb4 100644 --- a/drivers/video/via/via-core.c +++ b/drivers/video/via/via-core.c @@ -453,26 +453,40 @@ static int viafb_get_fb_size_from_pci(int chip_type) */ static int __devinit via_pci_setup_mmio(struct viafb_dev *vdev) { + int ret; /* - * Hook up to the device registers. + * Hook up to the device registers. Note that we soldier + * on if it fails; the framebuffer can operate (without + * acceleration) without this region. */ vdev->engine_start = pci_resource_start(vdev->pdev, 1); vdev->engine_len = pci_resource_len(vdev->pdev, 1); - /* If this fails, others will notice later */ vdev->engine_mmio = ioremap_nocache(vdev->engine_start, vdev->engine_len); - + if (vdev->engine_mmio == NULL) + dev_err(&vdev->pdev->dev, + "Unable to map engine MMIO; operation will be " + "slow and crippled.\n"); /* - * Likewise with I/O memory. + * Map in framebuffer memory. For now, failure here is + * fatal. Unfortunately, in the absence of significant + * vmalloc space, failure here is also entirely plausible. + * Eventually we want to move away from mapping this + * entire region. */ vdev->fbmem_start = pci_resource_start(vdev->pdev, 0); - vdev->fbmem_len = viafb_get_fb_size_from_pci(vdev->chip_type); - if (vdev->fbmem_len < 0) - return vdev->fbmem_len; + ret = vdev->fbmem_len = viafb_get_fb_size_from_pci(vdev->chip_type); + if (ret < 0) + goto out_unmap; vdev->fbmem = ioremap_nocache(vdev->fbmem_start, vdev->fbmem_len); - if (vdev->fbmem == NULL) - return -ENOMEM; + if (vdev->fbmem == NULL) { + ret = -ENOMEM; + goto out_unmap; + } return 0; +out_unmap: + iounmap(vdev->engine_mmio); + return ret; } static void __devexit via_pci_teardown_mmio(struct viafb_dev *vdev) @@ -572,12 +586,11 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, viafb_int_init(); via_setup_subdevs(&global_dev); /* - * Set up the framebuffer. + * Set up the framebuffer device */ ret = via_fb_pci_probe(&global_dev); if (ret) goto out_subdevs; - return 0; out_subdevs: -- cgit v1.2.1 From 64a6bd6a570c53f1955eaedf3952dcbe9b62da1d Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Wed, 5 May 2010 13:42:49 -0600 Subject: viafb: fold via_io.h into via-core.h Preparatory move toward the ultimate goal of moving pan-subdevice stuff into include/linux. Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Cc: Harald Welte Acked-by: Florian Tobias Schandinat Signed-off-by: Jonathan Corbet --- drivers/video/via/hw.h | 1 - drivers/video/via/share.h | 11 ++---- drivers/video/via/via-core.h | 48 +++++++++++++++++++++++++- drivers/video/via/via_io.h | 67 ------------------------------------- drivers/video/via/via_modesetting.c | 2 +- drivers/video/via/via_utility.c | 1 + drivers/video/via/viamode.c | 1 + 7 files changed, 53 insertions(+), 78 deletions(-) delete mode 100644 drivers/video/via/via_io.h (limited to 'drivers/video') diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index a58701f3bf7f..a109de379816 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h @@ -24,7 +24,6 @@ #include "viamode.h" #include "global.h" -#include "via_io.h" #include "via_modesetting.h" #define viafb_read_reg(p, i) via_read_reg(p, i) diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h index 861b4142efad..7f0de7f006ad 100644 --- a/drivers/video/via/share.h +++ b/drivers/video/via/share.h @@ -43,14 +43,9 @@ /* Video Memory Size */ #define VIDEO_MEMORY_SIZE_16M 0x1000000 -/* standard VGA IO port -*/ -#define VIAStatus 0x3DA -#define VIACR 0x3D4 -#define VIASR 0x3C4 -#define VIAGR 0x3CE -#define VIAAR 0x3C0 - +/* + * Lengths of the VPIT structure arrays. + */ #define StdCR 0x19 #define StdSR 0x04 #define StdGR 0x09 diff --git a/drivers/video/via/via-core.h b/drivers/video/via/via-core.h index 087c562abaec..7ffb521e1a7a 100644 --- a/drivers/video/via/via-core.h +++ b/drivers/video/via/via-core.h @@ -1,7 +1,8 @@ /* * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved. * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. - * Copyright 2009 Jonathan Corbet + * Copyright 2009-2010 Jonathan Corbet + * Copyright 2010 Florian Tobias Schandinat * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public @@ -22,6 +23,8 @@ #ifndef __VIA_CORE_H__ #define __VIA_CORE_H__ +#include +#include #include #include @@ -170,4 +173,47 @@ int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg); #define VGA_WIDTH 640 #define VGA_HEIGHT 480 +/* + * Indexed port operations. Note that these are all multi-op + * functions; every invocation will be racy if you're not holding + * reg_lock. + */ + +#define VIAStatus 0x3DA /* Non-indexed port */ +#define VIACR 0x3D4 +#define VIASR 0x3C4 +#define VIAGR 0x3CE +#define VIAAR 0x3C0 + +static inline u8 via_read_reg(u16 port, u8 index) +{ + outb(index, port); + return inb(port + 1); +} + +static inline void via_write_reg(u16 port, u8 index, u8 data) +{ + outb(index, port); + outb(data, port + 1); +} + +static inline void via_write_reg_mask(u16 port, u8 index, u8 data, u8 mask) +{ + u8 old; + + outb(index, port); + old = inb(port + 1); + outb((data & mask) | (old & ~mask), port + 1); +} + +#define VIA_MISC_REG_READ 0x03CC +#define VIA_MISC_REG_WRITE 0x03C2 + +static inline void via_write_misc_reg_mask(u8 data, u8 mask) +{ + u8 old = inb(VIA_MISC_REG_READ); + outb((data & mask) | (old & ~mask), VIA_MISC_REG_WRITE); +} + + #endif /* __VIA_CORE_H__ */ diff --git a/drivers/video/via/via_io.h b/drivers/video/via/via_io.h deleted file mode 100644 index a3d2aca65540..000000000000 --- a/drivers/video/via/via_io.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. - * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. - * Copyright 2010 Florian Tobias Schandinat - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; - * either version 2, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE.See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -/* - * basic io functions - */ - -#ifndef __VIA_IO_H__ -#define __VIA_IO_H__ - -#include -#include - -#define VIA_MISC_REG_READ 0x03CC -#define VIA_MISC_REG_WRITE 0x03C2 - -/* - * Indexed port operations. Note that these are all multi-op - * functions; every invocation will be racy if you're not holding - * reg_lock. - */ -static inline u8 via_read_reg(u16 port, u8 index) -{ - outb(index, port); - return inb(port + 1); -} - -static inline void via_write_reg(u16 port, u8 index, u8 data) -{ - outb(index, port); - outb(data, port + 1); -} - -static inline void via_write_reg_mask(u16 port, u8 index, u8 data, u8 mask) -{ - u8 old; - - outb(index, port); - old = inb(port + 1); - outb((data & mask) | (old & ~mask), port + 1); -} - -static inline void via_write_misc_reg_mask(u8 data, u8 mask) -{ - u8 old = inb(VIA_MISC_REG_READ); - outb((data & mask) | (old & ~mask), VIA_MISC_REG_WRITE); -} - -#endif /* __VIA_IO_H__ */ diff --git a/drivers/video/via/via_modesetting.c b/drivers/video/via/via_modesetting.c index 69ff28575008..b4e735cc350e 100644 --- a/drivers/video/via/via_modesetting.c +++ b/drivers/video/via/via_modesetting.c @@ -25,7 +25,7 @@ #include #include "via_modesetting.h" -#include "via_io.h" +#include "via-core.h" #include "share.h" #include "debug.h" diff --git a/drivers/video/via/via_utility.c b/drivers/video/via/via_utility.c index aefdeeec89b1..575703141868 100644 --- a/drivers/video/via/via_utility.c +++ b/drivers/video/via/via_utility.c @@ -19,6 +19,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "via-core.h" #include "global.h" void viafb_get_device_support_state(u32 *support_state) diff --git a/drivers/video/via/viamode.c b/drivers/video/via/viamode.c index 6f3bcda8cb47..2fdb9e6724a4 100644 --- a/drivers/video/via/viamode.c +++ b/drivers/video/via/viamode.c @@ -19,6 +19,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "via-core.h" #include "global.h" struct res_map_refresh res_map_refresh_tbl[] = { /*hres, vres, vclock, vmode_refresh*/ -- cgit v1.2.1 From 4a28ea9cedaa673b8a1a7f84628d784d020f3b47 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Wed, 5 May 2010 14:28:53 -0600 Subject: viafb: get rid of i2c debug cruft It's ugly and adds a global.h dependency. Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Cc: Harald Welte Acked-by: Florian Tobias Schandinat Signed-off-by: Jonathan Corbet --- drivers/video/via/via_i2c.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c index febc1dda69c1..84ec2d6e98c4 100644 --- a/drivers/video/via/via_i2c.c +++ b/drivers/video/via/via_i2c.c @@ -52,7 +52,7 @@ static void via_i2c_setscl(void *data, int state) val |= 0x80; break; default: - DEBUG_MSG("viafb_i2c: specify wrong i2c type.\n"); + printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n"); } via_write_reg(adap_data->io_port, adap_data->ioport_index, val); spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags); @@ -104,7 +104,7 @@ static void via_i2c_setsda(void *data, int state) val |= 0x40; break; default: - DEBUG_MSG("viafb_i2c: specify wrong i2c type.\n"); + printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n"); } via_write_reg(adap_data->io_port, adap_data->ioport_index, val); spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags); @@ -175,8 +175,6 @@ static int create_i2c_bus(struct i2c_adapter *adapter, struct via_port_cfg *adap_cfg, struct pci_dev *pdev) { - DEBUG_MSG(KERN_DEBUG "viafb: creating bus adap=0x%p, algo_bit_data=0x%p, adap_cfg=0x%p\n", adapter, algo, adap_cfg); - algo->setsda = via_i2c_setsda; algo->setscl = via_i2c_setscl; algo->getsda = via_i2c_getsda; -- cgit v1.2.1 From 9221fc6556d6fa14b5c61050dd87e26fc4ad255c Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Wed, 5 May 2010 14:24:18 -0600 Subject: viafb: Eliminate some global.h references The various subdev drivers (other than the framebuffer itself) no longer need this file. Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Cc: Harald Welte Acked-by: Florian Tobias Schandinat Signed-off-by: Jonathan Corbet --- drivers/video/via/via-gpio.c | 1 - drivers/video/via/via_i2c.c | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/via/via-gpio.c b/drivers/video/via/via-gpio.c index 63cb7acc0faf..67d699cbfd2c 100644 --- a/drivers/video/via/via-gpio.c +++ b/drivers/video/via/via-gpio.c @@ -10,7 +10,6 @@ #include #include "via-core.h" #include "via-gpio.h" -#include "global.h" /* * The ports we know about. Note that the port-25 gpios are not diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c index 84ec2d6e98c4..2291765f2f8e 100644 --- a/drivers/video/via/via_i2c.c +++ b/drivers/video/via/via_i2c.c @@ -20,9 +20,11 @@ */ #include +#include +#include +#include #include "via-core.h" #include "via_i2c.h" -#include "global.h" /* * There can only be one set of these, so there's no point in having -- cgit v1.2.1 From ec66841e495b9ab4f92bdf91efe8cf56e1471fbd Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Wed, 5 May 2010 14:44:55 -0600 Subject: viafb: move some include files to include/linux These are the files which should be available to subdevices compiled outside of drivers/video/via. Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Cc: Harald Welte Acked-by: Florian Tobias Schandinat Signed-off-by: Jonathan Corbet --- drivers/video/via/accel.c | 2 +- drivers/video/via/dvi.c | 4 +- drivers/video/via/hw.c | 3 +- drivers/video/via/lcd.c | 4 +- drivers/video/via/via-core.c | 6 +- drivers/video/via/via-core.h | 219 ------------------------------------ drivers/video/via/via-gpio.c | 4 +- drivers/video/via/via-gpio.h | 14 --- drivers/video/via/via_i2c.c | 4 +- drivers/video/via/via_i2c.h | 42 ------- drivers/video/via/via_modesetting.c | 2 +- drivers/video/via/via_utility.c | 2 +- drivers/video/via/viafbdev.c | 4 +- drivers/video/via/viamode.c | 2 +- drivers/video/via/vt1636.c | 4 +- 15 files changed, 21 insertions(+), 295 deletions(-) delete mode 100644 drivers/video/via/via-core.h delete mode 100644 drivers/video/via/via-gpio.h delete mode 100644 drivers/video/via/via_i2c.h (limited to 'drivers/video') diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c index 189aba41f9b9..e44893ea590d 100644 --- a/drivers/video/via/accel.c +++ b/drivers/video/via/accel.c @@ -18,7 +18,7 @@ * Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "via-core.h" +#include #include "global.h" /* diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c index 6271b7696323..39b040bb3817 100644 --- a/drivers/video/via/dvi.c +++ b/drivers/video/via/dvi.c @@ -18,8 +18,8 @@ * Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "via-core.h" -#include "via_i2c.h" +#include +#include #include "global.h" static void tmds_register_write(int index, u8 data); diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index e356fe8d8a90..b996803ae2c1 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -18,7 +18,8 @@ * Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "via-core.h" + +#include #include "global.h" static struct pll_map pll_value[] = { diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c index 04eec31aa9a2..2ab0f156439a 100644 --- a/drivers/video/via/lcd.c +++ b/drivers/video/via/lcd.c @@ -18,8 +18,8 @@ * Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "via-core.h" -#include "via_i2c.h" +#include +#include #include "global.h" #include "lcdtbl.h" diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c index 188c0022dcb4..e8cfe8392110 100644 --- a/drivers/video/via/via-core.c +++ b/drivers/video/via/via-core.c @@ -7,9 +7,9 @@ /* * Core code for the Via multifunction framebuffer device. */ -#include "via-core.h" -#include "via_i2c.h" -#include "via-gpio.h" +#include +#include +#include #include "global.h" #include diff --git a/drivers/video/via/via-core.h b/drivers/video/via/via-core.h deleted file mode 100644 index 7ffb521e1a7a..000000000000 --- a/drivers/video/via/via-core.h +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved. - * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. - * Copyright 2009-2010 Jonathan Corbet - * Copyright 2010 Florian Tobias Schandinat - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; - * either version 2, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE.See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __VIA_CORE_H__ -#define __VIA_CORE_H__ -#include -#include -#include -#include - -/* - * A description of each known serial I2C/GPIO port. - */ -enum via_port_type { - VIA_PORT_NONE = 0, - VIA_PORT_I2C, - VIA_PORT_GPIO, -}; - -enum via_port_mode { - VIA_MODE_OFF = 0, - VIA_MODE_I2C, /* Used as I2C port */ - VIA_MODE_GPIO, /* Two GPIO ports */ -}; - -enum viafb_i2c_adap { - VIA_PORT_26 = 0, - VIA_PORT_31, - VIA_PORT_25, - VIA_PORT_2C, - VIA_PORT_3D, -}; -#define VIAFB_NUM_PORTS 5 - -struct via_port_cfg { - enum via_port_type type; - enum via_port_mode mode; - u16 io_port; - u8 ioport_index; -}; - -/* - * This is the global viafb "device" containing stuff needed by - * all subdevs. - */ -struct viafb_dev { - struct pci_dev *pdev; - int chip_type; - struct via_port_cfg *port_cfg; - /* - * Spinlock for access to device registers. Not yet - * globally used. - */ - spinlock_t reg_lock; - /* - * The framebuffer MMIO region. Little, if anything, touches - * this memory directly, and certainly nothing outside of the - * framebuffer device itself. We *do* have to be able to allocate - * chunks of this memory for other devices, though. - */ - unsigned long fbmem_start; - long fbmem_len; - void __iomem *fbmem; -#if defined(CONFIG_FB_VIA_CAMERA) || defined(CONFIG_FB_VIA_CAMERA_MODULE) - long camera_fbmem_offset; - long camera_fbmem_size; -#endif - /* - * The MMIO region for device registers. - */ - unsigned long engine_start; - unsigned long engine_len; - void __iomem *engine_mmio; - -}; - -/* - * Interrupt management. - */ - -void viafb_irq_enable(u32 mask); -void viafb_irq_disable(u32 mask); - -/* - * The global interrupt control register and its bits. - */ -#define VDE_INTERRUPT 0x200 /* Video interrupt flags/masks */ -#define VDE_I_DVISENSE 0x00000001 /* DVI sense int status */ -#define VDE_I_VBLANK 0x00000002 /* Vertical blank status */ -#define VDE_I_MCCFI 0x00000004 /* MCE compl. frame int status */ -#define VDE_I_VSYNC 0x00000008 /* VGA VSYNC int status */ -#define VDE_I_DMA0DDONE 0x00000010 /* DMA 0 descr done */ -#define VDE_I_DMA0TDONE 0x00000020 /* DMA 0 transfer done */ -#define VDE_I_DMA1DDONE 0x00000040 /* DMA 1 descr done */ -#define VDE_I_DMA1TDONE 0x00000080 /* DMA 1 transfer done */ -#define VDE_I_C1AV 0x00000100 /* Cap Eng 1 act vid end */ -#define VDE_I_HQV0 0x00000200 /* First HQV engine */ -#define VDE_I_HQV1 0x00000400 /* Second HQV engine */ -#define VDE_I_HQV1EN 0x00000800 /* Second HQV engine enable */ -#define VDE_I_C0AV 0x00001000 /* Cap Eng 0 act vid end */ -#define VDE_I_C0VBI 0x00002000 /* Cap Eng 0 VBI end */ -#define VDE_I_C1VBI 0x00004000 /* Cap Eng 1 VBI end */ -#define VDE_I_VSYNC2 0x00008000 /* Sec. Disp. VSYNC */ -#define VDE_I_DVISNSEN 0x00010000 /* DVI sense enable */ -#define VDE_I_VSYNC2EN 0x00020000 /* Sec Disp VSYNC enable */ -#define VDE_I_MCCFIEN 0x00040000 /* MC comp frame int mask enable */ -#define VDE_I_VSYNCEN 0x00080000 /* VSYNC enable */ -#define VDE_I_DMA0DDEN 0x00100000 /* DMA 0 descr done enable */ -#define VDE_I_DMA0TDEN 0x00200000 /* DMA 0 trans done enable */ -#define VDE_I_DMA1DDEN 0x00400000 /* DMA 1 descr done enable */ -#define VDE_I_DMA1TDEN 0x00800000 /* DMA 1 trans done enable */ -#define VDE_I_C1AVEN 0x01000000 /* cap 1 act vid end enable */ -#define VDE_I_HQV0EN 0x02000000 /* First hqv engine enable */ -#define VDE_I_C1VBIEN 0x04000000 /* Cap 1 VBI end enable */ -#define VDE_I_LVDSSI 0x08000000 /* LVDS sense interrupt */ -#define VDE_I_C0AVEN 0x10000000 /* Cap 0 act vid end enable */ -#define VDE_I_C0VBIEN 0x20000000 /* Cap 0 VBI end enable */ -#define VDE_I_LVDSSIEN 0x40000000 /* LVDS Sense enable */ -#define VDE_I_ENABLE 0x80000000 /* Global interrupt enable */ - -/* - * DMA management. - */ -int viafb_request_dma(void); -void viafb_release_dma(void); -/* void viafb_dma_copy_out(unsigned int offset, dma_addr_t paddr, int len); */ -int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg); - -/* - * DMA Controller registers. - */ -#define VDMA_MR0 0xe00 /* Mod reg 0 */ -#define VDMA_MR_CHAIN 0x01 /* Chaining mode */ -#define VDMA_MR_TDIE 0x02 /* Transfer done int enable */ -#define VDMA_CSR0 0xe04 /* Control/status */ -#define VDMA_C_ENABLE 0x01 /* DMA Enable */ -#define VDMA_C_START 0x02 /* Start a transfer */ -#define VDMA_C_ABORT 0x04 /* Abort a transfer */ -#define VDMA_C_DONE 0x08 /* Transfer is done */ -#define VDMA_MARL0 0xe20 /* Mem addr low */ -#define VDMA_MARH0 0xe24 /* Mem addr high */ -#define VDMA_DAR0 0xe28 /* Device address */ -#define VDMA_DQWCR0 0xe2c /* Count (16-byte) */ -#define VDMA_TMR0 0xe30 /* Tile mode reg */ -#define VDMA_DPRL0 0xe34 /* Not sure */ -#define VDMA_DPR_IN 0x08 /* Inbound transfer to FB */ -#define VDMA_DPRH0 0xe38 -#define VDMA_PMR0 (0xe00 + 0x134) /* Pitch mode */ - -/* - * Useful stuff that probably belongs somewhere global. - */ -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 - -/* - * Indexed port operations. Note that these are all multi-op - * functions; every invocation will be racy if you're not holding - * reg_lock. - */ - -#define VIAStatus 0x3DA /* Non-indexed port */ -#define VIACR 0x3D4 -#define VIASR 0x3C4 -#define VIAGR 0x3CE -#define VIAAR 0x3C0 - -static inline u8 via_read_reg(u16 port, u8 index) -{ - outb(index, port); - return inb(port + 1); -} - -static inline void via_write_reg(u16 port, u8 index, u8 data) -{ - outb(index, port); - outb(data, port + 1); -} - -static inline void via_write_reg_mask(u16 port, u8 index, u8 data, u8 mask) -{ - u8 old; - - outb(index, port); - old = inb(port + 1); - outb((data & mask) | (old & ~mask), port + 1); -} - -#define VIA_MISC_REG_READ 0x03CC -#define VIA_MISC_REG_WRITE 0x03C2 - -static inline void via_write_misc_reg_mask(u8 data, u8 mask) -{ - u8 old = inb(VIA_MISC_REG_READ); - outb((data & mask) | (old & ~mask), VIA_MISC_REG_WRITE); -} - - -#endif /* __VIA_CORE_H__ */ diff --git a/drivers/video/via/via-gpio.c b/drivers/video/via/via-gpio.c index 67d699cbfd2c..595516aea691 100644 --- a/drivers/video/via/via-gpio.c +++ b/drivers/video/via/via-gpio.c @@ -8,8 +8,8 @@ #include #include #include -#include "via-core.h" -#include "via-gpio.h" +#include +#include /* * The ports we know about. Note that the port-25 gpios are not diff --git a/drivers/video/via/via-gpio.h b/drivers/video/via/via-gpio.h deleted file mode 100644 index 8281aea3dd6d..000000000000 --- a/drivers/video/via/via-gpio.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Support for viafb GPIO ports. - * - * Copyright 2009 Jonathan Corbet - * Distributable under version 2 of the GNU General Public License. - */ - -#ifndef __VIA_GPIO_H__ -#define __VIA_GPIO_H__ - -extern int viafb_gpio_lookup(const char *name); -extern int viafb_gpio_init(void); -extern void viafb_gpio_exit(void); -#endif diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c index 2291765f2f8e..da9e4ca94b17 100644 --- a/drivers/video/via/via_i2c.c +++ b/drivers/video/via/via_i2c.c @@ -23,8 +23,8 @@ #include #include #include -#include "via-core.h" -#include "via_i2c.h" +#include +#include /* * There can only be one set of these, so there's no point in having diff --git a/drivers/video/via/via_i2c.h b/drivers/video/via/via_i2c.h deleted file mode 100644 index 44532e468c05..000000000000 --- a/drivers/video/via/via_i2c.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved. - * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. - - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; - * either version 2, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE.See the GNU General Public License - * for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#ifndef __VIA_I2C_H__ -#define __VIA_I2C_H__ - -#include -#include - -struct via_i2c_stuff { - u16 i2c_port; /* GPIO or I2C port */ - u16 is_active; /* Being used as I2C? */ - struct i2c_adapter adapter; - struct i2c_algo_bit_data algo; -}; - - -int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata); -int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data); -int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len); -struct i2c_adapter *viafb_find_i2c_adapter(enum viafb_i2c_adap which); - -extern int viafb_i2c_init(void); -extern void viafb_i2c_exit(void); -#endif /* __VIA_I2C_H__ */ diff --git a/drivers/video/via/via_modesetting.c b/drivers/video/via/via_modesetting.c index b4e735cc350e..3cddcff88ab9 100644 --- a/drivers/video/via/via_modesetting.c +++ b/drivers/video/via/via_modesetting.c @@ -24,8 +24,8 @@ */ #include +#include #include "via_modesetting.h" -#include "via-core.h" #include "share.h" #include "debug.h" diff --git a/drivers/video/via/via_utility.c b/drivers/video/via/via_utility.c index 575703141868..d05ccb62b55f 100644 --- a/drivers/video/via/via_utility.c +++ b/drivers/video/via/via_utility.c @@ -19,7 +19,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "via-core.h" +#include #include "global.h" void viafb_get_device_support_state(u32 *support_state) diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 3d033186a822..d3dd2eb95586 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -22,9 +22,9 @@ #include #include #include -#define _MASTER_FILE +#include -#include "via-core.h" +#define _MASTER_FILE #include "global.h" static char *viafb_name = "Via"; diff --git a/drivers/video/via/viamode.c b/drivers/video/via/viamode.c index 2fdb9e6724a4..2dbad3c0f679 100644 --- a/drivers/video/via/viamode.c +++ b/drivers/video/via/viamode.c @@ -19,7 +19,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "via-core.h" +#include #include "global.h" struct res_map_refresh res_map_refresh_tbl[] = { /*hres, vres, vclock, vmode_refresh*/ diff --git a/drivers/video/via/vt1636.c b/drivers/video/via/vt1636.c index e5f802472883..d65bf1aee87c 100644 --- a/drivers/video/via/vt1636.c +++ b/drivers/video/via/vt1636.c @@ -19,8 +19,8 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "via-core.h" -#include "via_i2c.h" +#include +#include #include "global.h" u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information -- cgit v1.2.1 From de145b44b95b9d3212a82d1c0f29b09778ef33c5 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 11 May 2010 14:07:00 -0700 Subject: fbdev: bfin-t350mcqb-fb: fix fbmem allocation with blanking lines The current allocation does not include the memory required for blanking lines. So avoid memory corruption when multiple devices are using the DMA memory near each other. Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/bfin-t350mcqb-fb.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c index 44e49c28b2a7..c2ec3dcd4e91 100644 --- a/drivers/video/bfin-t350mcqb-fb.c +++ b/drivers/video/bfin-t350mcqb-fb.c @@ -488,9 +488,9 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) fbinfo->fbops = &bfin_t350mcqb_fb_ops; fbinfo->flags = FBINFO_FLAG_DEFAULT; - info->fb_buffer = - dma_alloc_coherent(NULL, fbinfo->fix.smem_len, &info->dma_handle, - GFP_KERNEL); + info->fb_buffer = dma_alloc_coherent(NULL, fbinfo->fix.smem_len + + ACTIVE_VIDEO_MEM_OFFSET, + &info->dma_handle, GFP_KERNEL); if (NULL == info->fb_buffer) { printk(KERN_ERR DRIVER_NAME @@ -568,8 +568,8 @@ out7: out6: fb_dealloc_cmap(&fbinfo->cmap); out4: - dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, - info->dma_handle); + dma_free_coherent(NULL, fbinfo->fix.smem_len + ACTIVE_VIDEO_MEM_OFFSET, + info->fb_buffer, info->dma_handle); out3: framebuffer_release(fbinfo); out2: @@ -592,8 +592,9 @@ static int __devexit bfin_t350mcqb_remove(struct platform_device *pdev) free_irq(info->irq, info); if (info->fb_buffer != NULL) - dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, - info->dma_handle); + dma_free_coherent(NULL, fbinfo->fix.smem_len + + ACTIVE_VIDEO_MEM_OFFSET, info->fb_buffer, + info->dma_handle); fb_dealloc_cmap(&fbinfo->cmap); -- cgit v1.2.1 From bf54a2b3c0dbf76136f00ff785bf6d8f6291311d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 18 Nov 2008 21:13:53 +0100 Subject: m68k: amiga - Zorro bus modalias support Add Amiga Zorro bus modalias and uevent support Signed-off-by: Geert Uytterhoeven --- drivers/video/cirrusfb.c | 1 + drivers/video/fm2fb.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/video') diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index 8d8dfda2f868..6df7c54db0a3 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c @@ -299,6 +299,7 @@ static const struct zorro_device_id cirrusfb_zorro_table[] = { }, { 0 } }; +MODULE_DEVICE_TABLE(zorro, cirrusfb_zorro_table); static const struct { zorro_id id2; diff --git a/drivers/video/fm2fb.c b/drivers/video/fm2fb.c index 6c91c61cdb63..1b0feb8e7244 100644 --- a/drivers/video/fm2fb.c +++ b/drivers/video/fm2fb.c @@ -219,6 +219,7 @@ static struct zorro_device_id fm2fb_devices[] __devinitdata = { { ZORRO_PROD_HELFRICH_RAINBOW_II }, { 0 } }; +MODULE_DEVICE_TABLE(zorro, fm2fb_devices); static struct zorro_driver fm2fb_driver = { .name = "fm2fb", -- cgit v1.2.1 From fa6688e1c7e7341fb7d1ca5878a3641762e60dec Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 5 Apr 2009 12:45:56 +0200 Subject: m68k: amiga - Frame buffer platform device conversion Signed-off-by: Geert Uytterhoeven --- drivers/video/amifb.c | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index dca48df98444..e5d6b56d4447 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -50,8 +50,9 @@ #include #include #include - +#include #include + #include #include #include @@ -1135,7 +1136,7 @@ static int amifb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg * Interface to the low level console driver */ -static void amifb_deinit(void); +static void amifb_deinit(struct platform_device *pdev); /* * Internal routines @@ -2246,7 +2247,7 @@ static inline void chipfree(void) * Initialisation */ -static int __init amifb_init(void) +static int __init amifb_probe(struct platform_device *pdev) { int tag, i, err = 0; u_long chipptr; @@ -2261,16 +2262,6 @@ static int __init amifb_init(void) } amifb_setup(option); #endif - if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_VIDEO)) - return -ENODEV; - - /* - * We request all registers starting from bplpt[0] - */ - if (!request_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120, - "amifb [Denise/Lisa]")) - return -EBUSY; - custom.dmacon = DMAF_ALL | DMAF_MASTER; switch (amiga_chipset) { @@ -2377,6 +2368,7 @@ default_chipset: fb_info.fbops = &amifb_ops; fb_info.par = ¤tpar; fb_info.flags = FBINFO_DEFAULT; + fb_info.device = &pdev->dev; if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb, NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) { @@ -2451,18 +2443,18 @@ default_chipset: return 0; amifb_error: - amifb_deinit(); + amifb_deinit(pdev); return err; } -static void amifb_deinit(void) +static void amifb_deinit(struct platform_device *pdev) { if (fb_info.cmap.len) fb_dealloc_cmap(&fb_info.cmap); + fb_dealloc_cmap(&fb_info.cmap); chipfree(); if (videomemory) iounmap((void*)videomemory); - release_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120); custom.dmacon = DMAF_ALL | DMAF_MASTER; } @@ -3794,14 +3786,35 @@ static void ami_rebuild_copper(void) } } -static void __exit amifb_exit(void) +static int __exit amifb_remove(struct platform_device *pdev) { unregister_framebuffer(&fb_info); - amifb_deinit(); + amifb_deinit(pdev); amifb_video_off(); + return 0; +} + +static struct platform_driver amifb_driver = { + .remove = __exit_p(amifb_remove), + .driver = { + .name = "amiga-video", + .owner = THIS_MODULE, + }, +}; + +static int __init amifb_init(void) +{ + return platform_driver_probe(&amifb_driver, amifb_probe); } module_init(amifb_init); + +static void __exit amifb_exit(void) +{ + platform_driver_unregister(&amifb_driver); +} + module_exit(amifb_exit); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:amiga-video"); -- cgit v1.2.1 From 058276303dbc4ed089c1f7dad0871810b1f5ddf1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 17 May 2010 16:30:42 -0700 Subject: DMAENGINE: extend the control command to include an arg This adds an argument to the DMAengine control function, so that we can later provide control commands that need some external data passed in through an argument akin to the ioctl() operation prototype. [dan.j.williams@intel.com: fix up some missed conversions] Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/video/mx3fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/video') diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index 3aa50bc276eb..7cfc170bce19 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -388,7 +388,7 @@ static void sdc_disable_channel(struct mx3fb_info *mx3_fbi) spin_unlock_irqrestore(&mx3fb->lock, flags); mx3_fbi->txd->chan->device->device_control(mx3_fbi->txd->chan, - DMA_TERMINATE_ALL); + DMA_TERMINATE_ALL, 0); mx3_fbi->txd = NULL; mx3_fbi->cookie = -EINVAL; } -- cgit v1.2.1 From 1471ca9aa71cd37b6a7476bb6f06a3a8622ea1bd Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Sun, 16 May 2010 17:27:03 +0200 Subject: fbdev: allow passing more than one aperture for handoff It removes a hack from nouveau code which had to detect which region to pass to kick vesafb/efifb. Signed-off-by: Marcin Slusarz Cc: Eric Anholt Cc: Ben Skeggs Cc: Thomas Hellstrom Cc: Dave Airlie Cc: Peter Jones Cc: Benjamin Herrenschmidt Signed-off-by: Dave Airlie --- drivers/video/efifb.c | 11 ++++++++--- drivers/video/fbmem.c | 29 ++++++++++++++++++++++++++--- drivers/video/fbsysfs.c | 1 + drivers/video/offb.c | 28 +++++++++++++++++----------- drivers/video/vesafb.c | 11 ++++++++--- 5 files changed, 60 insertions(+), 20 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index 581d2dbf675a..3b986567111a 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c @@ -165,7 +165,7 @@ static void efifb_destroy(struct fb_info *info) { if (info->screen_base) iounmap(info->screen_base); - release_mem_region(info->aperture_base, info->aperture_size); + release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); framebuffer_release(info); } @@ -289,8 +289,13 @@ static int __devinit efifb_probe(struct platform_device *dev) info->pseudo_palette = info->par; info->par = NULL; - info->aperture_base = efifb_fix.smem_start; - info->aperture_size = size_remap; + info->apertures = alloc_apertures(1); + if (!info->apertures) { + err = -ENOMEM; + goto err_release_fb; + } + info->apertures->ranges[0].base = efifb_fix.smem_start; + info->apertures->ranges[0].size = size_remap; info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len); if (!info->screen_base) { diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index a15b44e9c003..03f2dc2470b5 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1468,16 +1468,39 @@ static int fb_check_foreignness(struct fb_info *fi) return 0; } -static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw) +static bool apertures_overlap(struct aperture *gen, struct aperture *hw) { /* is the generic aperture base the same as the HW one */ - if (gen->aperture_base == hw->aperture_base) + if (gen->base == hw->base) return true; /* is the generic aperture base inside the hw base->hw base+size */ - if (gen->aperture_base > hw->aperture_base && gen->aperture_base <= hw->aperture_base + hw->aperture_size) + if (gen->base > hw->base && gen->base <= hw->base + hw->size) return true; return false; } + +static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw) +{ + int i, j; + struct apertures_struct *hwa = hw->apertures; + struct apertures_struct *gena = gen->apertures; + if (!hwa || !gena) + return false; + + for (i = 0; i < hwa->count; ++i) { + struct aperture *h = &hwa->ranges[i]; + for (j = 0; j < gena->count; ++j) { + struct aperture *g = &gena->ranges[j]; + printk(KERN_DEBUG "checking generic (%llx %llx) vs hw (%llx %llx)\n", + g->base, g->size, h->base, h->size); + if (apertures_overlap(g, h)) + return true; + } + } + + return false; +} + /** * register_framebuffer - registers a frame buffer device * @fb_info: frame buffer info structure diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index 81aa3129c17d..0a08f1341227 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c @@ -80,6 +80,7 @@ EXPORT_SYMBOL(framebuffer_alloc); */ void framebuffer_release(struct fb_info *info) { + kfree(info->apertures); kfree(info); } EXPORT_SYMBOL(framebuffer_release); diff --git a/drivers/video/offb.c b/drivers/video/offb.c index 61f8b8f919b0..46dda7d8aaee 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -285,7 +285,7 @@ static void offb_destroy(struct fb_info *info) { if (info->screen_base) iounmap(info->screen_base); - release_mem_region(info->aperture_base, info->aperture_size); + release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); framebuffer_release(info); } @@ -491,8 +491,11 @@ static void __init offb_init_fb(const char *name, const char *full_name, var->vmode = FB_VMODE_NONINTERLACED; /* set offb aperture size for generic probing */ - info->aperture_base = address; - info->aperture_size = fix->smem_len; + info->apertures = alloc_apertures(1); + if (!info->apertures) + goto out_aper; + info->apertures->ranges[0].base = address; + info->apertures->ranges[0].size = fix->smem_len; info->fbops = &offb_ops; info->screen_base = ioremap(address, fix->smem_len); @@ -501,17 +504,20 @@ static void __init offb_init_fb(const char *name, const char *full_name, fb_alloc_cmap(&info->cmap, 256, 0); - if (register_framebuffer(info) < 0) { - iounmap(par->cmap_adr); - par->cmap_adr = NULL; - iounmap(info->screen_base); - framebuffer_release(info); - release_mem_region(res_start, res_size); - return; - } + if (register_framebuffer(info) < 0) + goto out_err; printk(KERN_INFO "fb%d: Open Firmware frame buffer device on %s\n", info->node, full_name); + return; + +out_err: + iounmap(info->screen_base); +out_aper: + iounmap(par->cmap_adr); + par->cmap_adr = NULL; + framebuffer_release(info); + release_mem_region(res_start, res_size); } diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index 0cadf7aee27e..090aa1a9be6e 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c @@ -177,7 +177,7 @@ static void vesafb_destroy(struct fb_info *info) { if (info->screen_base) iounmap(info->screen_base); - release_mem_region(info->aperture_base, info->aperture_size); + release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); framebuffer_release(info); } @@ -295,8 +295,13 @@ static int __init vesafb_probe(struct platform_device *dev) info->par = NULL; /* set vesafb aperture size for generic probing */ - info->aperture_base = screen_info.lfb_base; - info->aperture_size = size_total; + info->apertures = alloc_apertures(1); + if (!info->apertures) { + err = -ENOMEM; + goto err; + } + info->apertures->ranges[0].base = screen_info.lfb_base; + info->apertures->ranges[0].size = size_total; info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len); if (!info->screen_base) { -- cgit v1.2.1 From 06415c564fb98562a4d6b6215615deb2d1cc0dae Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Sun, 16 May 2010 17:29:56 +0200 Subject: fbmem, drm/nouveau: kick firmware framebuffers as soon as possible Currently vesafb/efifb/... is kicked when hardware driver is registering framebuffer. To do it hardware must be fully functional, so there's a short window between start of initialisation and framebuffer registration when two drivers touch the hardware. Unfortunately sometimes it breaks nouveau initialisation. Fix it by kicking firmware driver(s) before we start touching the hardware. Reported-by: Didier Spaier Tested-by: Didier Spaier Signed-off-by: Marcin Slusarz Cc: Ben Skeggs Cc: Peter Jones Cc: Andrew Morton Signed-off-by: Dave Airlie --- drivers/video/fbmem.c | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 03f2dc2470b5..7cfcd716fd5f 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1479,11 +1479,10 @@ static bool apertures_overlap(struct aperture *gen, struct aperture *hw) return false; } -static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw) +static bool fb_do_apertures_overlap(struct apertures_struct *gena, + struct apertures_struct *hwa) { int i, j; - struct apertures_struct *hwa = hw->apertures; - struct apertures_struct *gena = gen->apertures; if (!hwa || !gena) return false; @@ -1501,6 +1500,28 @@ static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw) return false; } +void remove_conflicting_framebuffers(struct apertures_struct *a, const char *name) +{ + int i; + + /* check all firmware fbs and kick off if the base addr overlaps */ + for (i = 0 ; i < FB_MAX; i++) { + if (!registered_fb[i]) + continue; + + if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE)) + continue; + + if (fb_do_apertures_overlap(registered_fb[i]->apertures, a)) { + printk(KERN_ERR "fb: conflicting fb hw usage " + "%s vs %s - removing generic driver\n", + name, registered_fb[i]->fix.id); + unregister_framebuffer(registered_fb[i]); + } + } +} +EXPORT_SYMBOL(remove_conflicting_framebuffers); + /** * register_framebuffer - registers a frame buffer device * @fb_info: frame buffer info structure @@ -1524,21 +1545,7 @@ register_framebuffer(struct fb_info *fb_info) if (fb_check_foreignness(fb_info)) return -ENOSYS; - /* check all firmware fbs and kick off if the base addr overlaps */ - for (i = 0 ; i < FB_MAX; i++) { - if (!registered_fb[i]) - continue; - - if (registered_fb[i]->flags & FBINFO_MISC_FIRMWARE) { - if (fb_do_apertures_overlap(registered_fb[i], fb_info)) { - printk(KERN_ERR "fb: conflicting fb hw usage " - "%s vs %s - removing generic driver\n", - fb_info->fix.id, - registered_fb[i]->fix.id); - unregister_framebuffer(registered_fb[i]); - } - } - } + remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id); num_registered_fb++; for (i = 0 ; i < FB_MAX; i++) -- cgit v1.2.1 From 3b9676e7ac6eff4f50f1b48b6c36664f55b79507 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Sun, 16 May 2010 17:33:09 +0200 Subject: vga16fb, drm: vga16fb->drm handoff let vga16fb claim 0xA0000+0x10000 region as its aperture; drm drivers don't use it, so we have to detect it and kick vga16fb manually - but only if drm is driving the primary card Signed-off-by: Marcin Slusarz Cc: James Simmons Cc: Dave Airlie Cc: Ben Skeggs Signed-off-by: Dave Airlie --- drivers/video/fbmem.c | 14 +++++++++++--- drivers/video/vga16fb.c | 26 +++++++++++++++++++------- 2 files changed, 30 insertions(+), 10 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 7cfcd716fd5f..e08b7b5cb326 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1500,19 +1500,26 @@ static bool fb_do_apertures_overlap(struct apertures_struct *gena, return false; } -void remove_conflicting_framebuffers(struct apertures_struct *a, const char *name) +#define VGA_FB_PHYS 0xA0000 +void remove_conflicting_framebuffers(struct apertures_struct *a, + const char *name, bool primary) { int i; /* check all firmware fbs and kick off if the base addr overlaps */ for (i = 0 ; i < FB_MAX; i++) { + struct apertures_struct *gen_aper; if (!registered_fb[i]) continue; if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE)) continue; - if (fb_do_apertures_overlap(registered_fb[i]->apertures, a)) { + gen_aper = registered_fb[i]->apertures; + if (fb_do_apertures_overlap(gen_aper, a) || + (primary && gen_aper && gen_aper->count && + gen_aper->ranges[0].base == VGA_FB_PHYS)) { + printk(KERN_ERR "fb: conflicting fb hw usage " "%s vs %s - removing generic driver\n", name, registered_fb[i]->fix.id); @@ -1545,7 +1552,8 @@ register_framebuffer(struct fb_info *fb_info) if (fb_check_foreignness(fb_info)) return -ENOSYS; - remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id); + remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id, + fb_is_primary_device(fb_info)); num_registered_fb++; for (i = 0 ; i < FB_MAX; i++) diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index bf638a47a5b3..149c47ac7e93 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c @@ -1263,10 +1263,19 @@ static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image vga_imageblit_color(info, image); } +static void vga16fb_destroy(struct fb_info *info) +{ + iounmap(info->screen_base); + fb_dealloc_cmap(&info->cmap); + /* XXX unshare VGA regions */ + framebuffer_release(info); +} + static struct fb_ops vga16fb_ops = { .owner = THIS_MODULE, .fb_open = vga16fb_open, .fb_release = vga16fb_release, + .fb_destroy = vga16fb_destroy, .fb_check_var = vga16fb_check_var, .fb_set_par = vga16fb_set_par, .fb_setcolreg = vga16fb_setcolreg, @@ -1306,6 +1315,11 @@ static int __devinit vga16fb_probe(struct platform_device *dev) ret = -ENOMEM; goto err_fb_alloc; } + info->apertures = alloc_apertures(1); + if (!info->apertures) { + ret = -ENOMEM; + goto err_ioremap; + } /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */ info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0); @@ -1335,7 +1349,7 @@ static int __devinit vga16fb_probe(struct platform_device *dev) info->fix = vga16fb_fix; /* supports rectangles with widths of multiples of 8 */ info->pixmap.blit_x = 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31; - info->flags = FBINFO_FLAG_DEFAULT | + info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE | FBINFO_HWACCEL_YPAN; i = (info->var.bits_per_pixel == 8) ? 256 : 16; @@ -1354,6 +1368,9 @@ static int __devinit vga16fb_probe(struct platform_device *dev) vga16fb_update_fix(info); + info->apertures->ranges[0].base = VGA_FB_PHYS; + info->apertures->ranges[0].size = VGA_FB_PHYS_LEN; + if (register_framebuffer(info) < 0) { printk(KERN_ERR "vga16fb: unable to register framebuffer\n"); ret = -EINVAL; @@ -1380,13 +1397,8 @@ static int vga16fb_remove(struct platform_device *dev) { struct fb_info *info = platform_get_drvdata(dev); - if (info) { + if (info) unregister_framebuffer(info); - iounmap(info->screen_base); - fb_dealloc_cmap(&info->cmap); - /* XXX unshare VGA regions */ - framebuffer_release(info); - } return 0; } -- cgit v1.2.1 From b4d78bf7a4663c8354ec9432eb9631b144a33ffa Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Wed, 17 Mar 2010 13:35:19 +0100 Subject: OMAP: DSS2: Add Kconfig option for DPI display type This allows us to disable DPI on systems that do not have it Signed-off-by: Roger Quadros Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/Kconfig | 6 ++++++ drivers/video/omap2/dss/Makefile | 3 ++- drivers/video/omap2/dss/core.c | 4 ++++ drivers/video/omap2/dss/display.c | 4 ++++ 4 files changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers/video') diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index 87afb81b2c44..43b64403eaa4 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig @@ -36,6 +36,12 @@ config OMAP2_DSS_COLLECT_IRQ_STATS /omapdss/dispc_irq for DISPC interrupts, and /omapdss/dsi_irq for DSI interrupts. +config OMAP2_DSS_DPI + bool "DPI support" + default y + help + DPI Interface. This is the Parallel Display Interface. + config OMAP2_DSS_RFBI bool "RFBI support" default n diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index 980c72c2db98..d71b5d9d71b1 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_OMAP2_DSS) += omapdss.o -omapdss-y := core.o dss.o dispc.o dpi.o display.o manager.o overlay.o +omapdss-y := core.o dss.o dispc.o display.o manager.o overlay.o +omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 7ebe50b335ed..6d54467e5e20 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -526,11 +526,13 @@ static int omap_dss_probe(struct platform_device *pdev) } #endif +#ifdef CONFIG_OMAP2_DSS_DPI r = dpi_init(pdev); if (r) { DSSERR("Failed to initialize dpi\n"); goto fail0; } +#endif r = dispc_init(); if (r) { @@ -601,7 +603,9 @@ static int omap_dss_remove(struct platform_device *pdev) venc_exit(); #endif dispc_exit(); +#ifdef CONFIG_OMAP2_DSS_DPI dpi_exit(); +#endif #ifdef CONFIG_OMAP2_DSS_RFBI rfbi_exit(); #endif diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 6a74ea116d29..71389630b108 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -392,7 +392,9 @@ void dss_init_device(struct platform_device *pdev, int r; switch (dssdev->type) { +#ifdef CONFIG_OMAP2_DSS_DPI case OMAP_DISPLAY_TYPE_DPI: +#endif #ifdef CONFIG_OMAP2_DSS_RFBI case OMAP_DISPLAY_TYPE_DBI: #endif @@ -413,9 +415,11 @@ void dss_init_device(struct platform_device *pdev, } switch (dssdev->type) { +#ifdef CONFIG_OMAP2_DSS_DPI case OMAP_DISPLAY_TYPE_DPI: r = dpi_init_display(dssdev); break; +#endif #ifdef CONFIG_OMAP2_DSS_RFBI case OMAP_DISPLAY_TYPE_DBI: r = rfbi_init_display(dssdev); -- cgit v1.2.1 From b1d145b6d3c07cb9ccb6afb224c78a9d61f8cd17 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Wed, 17 Mar 2010 13:35:20 +0100 Subject: OMAP: DSS2: Remove redundant enable/disable calls from SDI Panel enable/disable is now done via the panel driver, so we should not call the panel driver again Signed-off-by: Roger Quadros Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/sdi.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 12eb4042dd82..3de3c1e559aa 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -115,17 +115,9 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) dssdev->manager->enable(dssdev->manager); - if (dssdev->driver->enable) { - r = dssdev->driver->enable(dssdev); - if (r) - goto err3; - } - sdi.skip_init = 0; return 0; -err3: - dssdev->manager->disable(dssdev->manager); err2: dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); err1: @@ -137,9 +129,6 @@ EXPORT_SYMBOL(omapdss_sdi_display_enable); void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) { - if (dssdev->driver->disable) - dssdev->driver->disable(dssdev); - dssdev->manager->disable(dssdev->manager); dss_sdi_disable(); -- cgit v1.2.1 From 508886cf98c81cee73cd75943b3d0039801327ab Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Wed, 17 Mar 2010 13:35:21 +0100 Subject: OMAP: DSS2: Use vdds_sdi regulator supply in SDI This patch enables the use of vdds_sdi regulator in SDI subsystem. We can disable the vdds_sdi voltage when not in use to save power. Signed-off-by: Roger Quadros Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/sdi.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/video') diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 3de3c1e559aa..ee07a3cc22ef 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -23,13 +23,16 @@ #include #include #include +#include #include +#include #include "dss.h" static struct { bool skip_init; bool update_enabled; + struct regulator *vdds_sdi_reg; } sdi; static void sdi_basic_init(void) @@ -57,6 +60,10 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) goto err0; } + r = regulator_enable(sdi.vdds_sdi_reg); + if (r) + goto err1; + /* In case of skip_init sdi_init has already enabled the clocks */ if (!sdi.skip_init) dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); @@ -120,6 +127,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) return 0; err2: dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + regulator_disable(sdi.vdds_sdi_reg); err1: omap_dss_stop_device(dssdev); err0: @@ -135,6 +143,8 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + regulator_disable(sdi.vdds_sdi_reg); + omap_dss_stop_device(dssdev); } EXPORT_SYMBOL(omapdss_sdi_display_disable); @@ -151,6 +161,11 @@ int sdi_init(bool skip_init) /* we store this for first display enable, then clear it */ sdi.skip_init = skip_init; + sdi.vdds_sdi_reg = dss_get_vdds_sdi(); + if (IS_ERR(sdi.vdds_sdi_reg)) { + DSSERR("can't get VDDS_SDI regulator\n"); + return PTR_ERR(sdi.vdds_sdi_reg); + } /* * Enable clocks already here, otherwise there would be a toggle * of them until sdi_display_enable is called. -- cgit v1.2.1 From 238a41329ca208d1170962260babb428b6e222c2 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Mar 2010 10:32:05 +0100 Subject: OMAP: DSS2: fix lock_fb_info() and omapfb_lock() locking order Framebuffer ioctl processing forces lock_fb_info() -> omapfb_lock() locking order. Follow that order to avoid possible circular locking dependency, detected by lockdep. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb-ioctl.c | 4 ++-- drivers/video/omap2/omapfb/omapfb-sysfs.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 1ffa760b8545..2c0f01c44aab 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -183,13 +183,13 @@ int omapfb_update_window(struct fb_info *fbi, struct omapfb2_device *fbdev = ofbi->fbdev; int r; - omapfb_lock(fbdev); lock_fb_info(fbi); + omapfb_lock(fbdev); r = omapfb_update_window_nolock(fbi, x, y, w, h); - unlock_fb_info(fbi); omapfb_unlock(fbdev); + unlock_fb_info(fbi); return r; } diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c index 62bb88f5c192..e10445017985 100644 --- a/drivers/video/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c @@ -137,8 +137,8 @@ static ssize_t show_overlays(struct device *dev, ssize_t l = 0; int t; - omapfb_lock(fbdev); lock_fb_info(fbi); + omapfb_lock(fbdev); for (t = 0; t < ofbi->num_overlays; t++) { struct omap_overlay *ovl = ofbi->overlays[t]; @@ -154,8 +154,8 @@ static ssize_t show_overlays(struct device *dev, l += snprintf(buf + l, PAGE_SIZE - l, "\n"); - unlock_fb_info(fbi); omapfb_unlock(fbdev); + unlock_fb_info(fbi); return l; } @@ -195,8 +195,8 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr, if (buf[len - 1] == '\n') len = len - 1; - omapfb_lock(fbdev); lock_fb_info(fbi); + omapfb_lock(fbdev); if (len > 0) { char *p = (char *)buf; @@ -303,8 +303,8 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr, r = count; out: - unlock_fb_info(fbi); omapfb_unlock(fbdev); + unlock_fb_info(fbi); return r; } -- cgit v1.2.1 From 27b67c92a30967e3a9e9ea082d4ca4bc6882f879 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Mar 2010 10:32:06 +0100 Subject: OMAP: DSS2: check lock_fb_info() return value Give up if lock_fb_info() fails, following the same convention as other lock_fb_info() users. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb-ioctl.c | 3 ++- drivers/video/omap2/omapfb/omapfb-sysfs.c | 21 ++++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 2c0f01c44aab..9c7361871d78 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -183,7 +183,8 @@ int omapfb_update_window(struct fb_info *fbi, struct omapfb2_device *fbdev = ofbi->fbdev; int r; - lock_fb_info(fbi); + if (!lock_fb_info(fbi)) + return -ENODEV; omapfb_lock(fbdev); r = omapfb_update_window_nolock(fbi, x, y, w, h); diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c index e10445017985..5179219128bd 100644 --- a/drivers/video/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c @@ -57,7 +57,8 @@ static ssize_t store_rotate_type(struct device *dev, if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB) return -EINVAL; - lock_fb_info(fbi); + if (!lock_fb_info(fbi)) + return -ENODEV; r = 0; if (rot_type == ofbi->rotation_type) @@ -105,7 +106,8 @@ static ssize_t store_mirror(struct device *dev, if (mirror != 0 && mirror != 1) return -EINVAL; - lock_fb_info(fbi); + if (!lock_fb_info(fbi)) + return -ENODEV; ofbi->mirror = mirror; @@ -137,7 +139,8 @@ static ssize_t show_overlays(struct device *dev, ssize_t l = 0; int t; - lock_fb_info(fbi); + if (!lock_fb_info(fbi)) + return -ENODEV; omapfb_lock(fbdev); for (t = 0; t < ofbi->num_overlays; t++) { @@ -195,7 +198,8 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr, if (buf[len - 1] == '\n') len = len - 1; - lock_fb_info(fbi); + if (!lock_fb_info(fbi)) + return -ENODEV; omapfb_lock(fbdev); if (len > 0) { @@ -317,7 +321,8 @@ static ssize_t show_overlays_rotate(struct device *dev, ssize_t l = 0; int t; - lock_fb_info(fbi); + if (!lock_fb_info(fbi)) + return -ENODEV; for (t = 0; t < ofbi->num_overlays; t++) { l += snprintf(buf + l, PAGE_SIZE - l, "%s%d", @@ -345,7 +350,8 @@ static ssize_t store_overlays_rotate(struct device *dev, if (buf[len - 1] == '\n') len = len - 1; - lock_fb_info(fbi); + if (!lock_fb_info(fbi)) + return -ENODEV; if (len > 0) { char *p = (char *)buf; @@ -416,7 +422,8 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, size = PAGE_ALIGN(simple_strtoul(buf, NULL, 0)); - lock_fb_info(fbi); + if (!lock_fb_info(fbi)) + return -ENODEV; for (i = 0; i < ofbi->num_overlays; i++) { if (ofbi->overlays[i]->info.enabled) { -- cgit v1.2.1 From 35bc42c50432d3dde0119f7630f1e4574bd67519 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 24 Mar 2010 11:59:37 +0100 Subject: OMAP: DSS2: VENC: don't call platform_enable/disable() twice platform_enable/disable() is already called in venc_power_on/off(), so don't do it again in venc_panel_enable/disable(). Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/venc.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index f0ba5732d84a..eff35050e28a 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -479,12 +479,6 @@ static int venc_panel_enable(struct omap_dss_device *dssdev) goto err1; } - if (dssdev->platform_enable) { - r = dssdev->platform_enable(dssdev); - if (r) - goto err2; - } - venc_power_on(dssdev); venc.wss_data = 0; @@ -494,13 +488,9 @@ static int venc_panel_enable(struct omap_dss_device *dssdev) /* wait couple of vsyncs until enabling the LCD */ msleep(50); - mutex_unlock(&venc.venc_lock); - - return r; -err2: - venc_power_off(dssdev); err1: mutex_unlock(&venc.venc_lock); + return r; } @@ -524,9 +514,6 @@ static void venc_panel_disable(struct omap_dss_device *dssdev) /* wait at least 5 vsyncs after disabling the LCD */ msleep(100); - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; end: mutex_unlock(&venc.venc_lock); -- cgit v1.2.1 From 279fcd48c4a426050422b2d196fd99c2b5ae7d71 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 24 Mar 2010 11:59:38 +0100 Subject: OMAP: DSS2: Fix device disable when driver is not loaded Only call driver disable when device isn't already disabled, which also handles the driver not loaded case. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/display.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/video') diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 71389630b108..ef8c8529dda2 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -545,7 +545,10 @@ int dss_resume_all_devices(void) static int dss_disable_device(struct device *dev, void *data) { struct omap_dss_device *dssdev = to_dss_device(dev); - dssdev->driver->disable(dssdev); + + if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) + dssdev->driver->disable(dssdev); + return 0; } -- cgit v1.2.1 From f49a951f8a2dacbbb145b6199297fcc3e493b90f Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 26 Mar 2010 16:26:37 +0200 Subject: OMAP: DSS2: Make partial update width even MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are some strange problems with DSI and updates with odd widths. One particular problem is that HS TX timeout triggers easily with updates with odd widths. This patch makes the updates widths even, circumventing the problem. There should be no ill side effects with increasing the update area slightly to make the width even. Signed-off-by: Ville Syrjälä Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/manager.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers/video') diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 0820986d4a68..32ec2ff2e9cf 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -940,6 +940,22 @@ static int configure_dispc(void) return r; } +/* Make the coordinates even. There are some strange problems with OMAP and + * partial DSI update when the update widths are odd. */ +static void make_even(u16 *x, u16 *w) +{ + u16 x1, x2; + + x1 = *x; + x2 = *x + *w; + + x1 &= ~1; + x2 = ALIGN(x2, 2); + + *x = x1; + *w = x2 - x1; +} + /* Configure dispc for partial update. Return possibly modified update * area */ void dss_setup_partial_planes(struct omap_dss_device *dssdev, @@ -968,6 +984,8 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev, return; } + make_even(&x, &w); + spin_lock_irqsave(&dss_cache.lock, flags); /* We need to show the whole overlay if it is scaled. So look for @@ -1029,6 +1047,8 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev, w = x2 - x1; h = y2 - y1; + make_even(&x, &w); + DSSDBG("changing upd area due to ovl(%d) scaling %d,%d %dx%d\n", i, x, y, w, h); } -- cgit v1.2.1 From a3201a0eaed38dd7ece72393a778b4408ec79627 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 3 Mar 2010 14:31:45 +0200 Subject: OMAP: DSS2: Taal: add mutex to protect panel data Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 140 +++++++++++++++++++++++++----- 1 file changed, 119 insertions(+), 21 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 4f3988a41082..1799096a1388 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -67,6 +68,8 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable); struct taal_data { + struct mutex lock; + struct backlight_device *bldev; unsigned long hw_guard_end; /* next value of jiffies when we can @@ -510,6 +513,8 @@ static int taal_probe(struct omap_dss_device *dssdev) } td->dssdev = dssdev; + mutex_init(&td->lock); + td->esd_wq = create_singlethread_workqueue("taal_esd"); if (td->esd_wq == NULL) { dev_err(&dssdev->dev, "can't create ESD workqueue\n"); @@ -733,54 +738,96 @@ static void taal_power_off(struct omap_dss_device *dssdev) static int taal_enable(struct omap_dss_device *dssdev) { + struct taal_data *td = dev_get_drvdata(&dssdev->dev); int r; + dev_dbg(&dssdev->dev, "enable\n"); - if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) - return -EINVAL; + mutex_lock(&td->lock); + + if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { + r = -EINVAL; + goto err; + } r = taal_power_on(dssdev); if (r) - return r; + goto err; dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + mutex_unlock(&td->lock); + + return 0; +err: + dev_dbg(&dssdev->dev, "enable failed\n"); + mutex_unlock(&td->lock); return r; } static void taal_disable(struct omap_dss_device *dssdev) { + struct taal_data *td = dev_get_drvdata(&dssdev->dev); + dev_dbg(&dssdev->dev, "disable\n"); + mutex_lock(&td->lock); + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) taal_power_off(dssdev); dssdev->state = OMAP_DSS_DISPLAY_DISABLED; + + mutex_unlock(&td->lock); } static int taal_suspend(struct omap_dss_device *dssdev) { + struct taal_data *td = dev_get_drvdata(&dssdev->dev); + int r; + dev_dbg(&dssdev->dev, "suspend\n"); - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - return -EINVAL; + mutex_lock(&td->lock); + + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { + r = -EINVAL; + goto err; + } taal_power_off(dssdev); dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; + mutex_unlock(&td->lock); + return 0; +err: + mutex_unlock(&td->lock); + return r; } static int taal_resume(struct omap_dss_device *dssdev) { + struct taal_data *td = dev_get_drvdata(&dssdev->dev); int r; + dev_dbg(&dssdev->dev, "resume\n"); - if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) - return -EINVAL; + mutex_lock(&td->lock); + + if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) { + r = -EINVAL; + goto err; + } r = taal_power_on(dssdev); dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + mutex_unlock(&td->lock); + + return r; +err: + mutex_unlock(&td->lock); return r; } @@ -799,6 +846,7 @@ static int taal_update(struct omap_dss_device *dssdev, dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h); + mutex_lock(&td->lock); dsi_bus_lock(); if (!td->enabled) { @@ -820,18 +868,24 @@ static int taal_update(struct omap_dss_device *dssdev, goto err; /* note: no bus_unlock here. unlock is in framedone_cb */ + mutex_unlock(&td->lock); return 0; err: dsi_bus_unlock(); + mutex_unlock(&td->lock); return r; } static int taal_sync(struct omap_dss_device *dssdev) { + struct taal_data *td = dev_get_drvdata(&dssdev->dev); + dev_dbg(&dssdev->dev, "sync\n"); + mutex_lock(&td->lock); dsi_bus_lock(); dsi_bus_unlock(); + mutex_unlock(&td->lock); dev_dbg(&dssdev->dev, "sync done\n"); @@ -861,13 +915,16 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) static int taal_enable_te(struct omap_dss_device *dssdev, bool enable) { + struct taal_data *td = dev_get_drvdata(&dssdev->dev); int r; + mutex_lock(&td->lock); dsi_bus_lock(); r = _taal_enable_te(dssdev, enable); dsi_bus_unlock(); + mutex_unlock(&td->lock); return r; } @@ -875,7 +932,13 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable) static int taal_get_te(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - return td->te_enabled; + int r; + + mutex_lock(&td->lock); + r = td->te_enabled; + mutex_unlock(&td->lock); + + return r; } static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) @@ -885,6 +948,7 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) dev_dbg(&dssdev->dev, "rotate %d\n", rotate); + mutex_lock(&td->lock); dsi_bus_lock(); if (td->enabled) { @@ -896,16 +960,24 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) td->rotate = rotate; dsi_bus_unlock(); + mutex_unlock(&td->lock); return 0; err: dsi_bus_unlock(); + mutex_unlock(&td->lock); return r; } static u8 taal_get_rotate(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - return td->rotate; + int r; + + mutex_lock(&td->lock); + r = td->rotate; + mutex_unlock(&td->lock); + + return r; } static int taal_mirror(struct omap_dss_device *dssdev, bool enable) @@ -915,6 +987,7 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable) dev_dbg(&dssdev->dev, "mirror %d\n", enable); + mutex_lock(&td->lock); dsi_bus_lock(); if (td->enabled) { r = taal_set_addr_mode(td->rotate, enable); @@ -925,23 +998,33 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable) td->mirror = enable; dsi_bus_unlock(); + mutex_unlock(&td->lock); return 0; err: dsi_bus_unlock(); + mutex_unlock(&td->lock); return r; } static bool taal_get_mirror(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - return td->mirror; + int r; + + mutex_lock(&td->lock); + r = td->mirror; + mutex_unlock(&td->lock); + + return r; } static int taal_run_test(struct omap_dss_device *dssdev, int test_num) { + struct taal_data *td = dev_get_drvdata(&dssdev->dev); u8 id1, id2, id3; int r; + mutex_lock(&td->lock); dsi_bus_lock(); r = taal_dcs_read_1(DCS_GET_ID1, &id1); @@ -955,9 +1038,11 @@ static int taal_run_test(struct omap_dss_device *dssdev, int test_num) goto err; dsi_bus_unlock(); + mutex_unlock(&td->lock); return 0; err: dsi_bus_unlock(); + mutex_unlock(&td->lock); return r; } @@ -971,12 +1056,16 @@ static int taal_memory_read(struct omap_dss_device *dssdev, unsigned buf_used = 0; struct taal_data *td = dev_get_drvdata(&dssdev->dev); - if (!td->enabled) - return -ENODEV; - if (size < w * h * 3) return -ENOMEM; + mutex_lock(&td->lock); + + if (!td->enabled) { + r = -ENODEV; + goto err1; + } + size = min(w * h * 3, dssdev->panel.timings.x_res * dssdev->panel.timings.y_res * 3); @@ -995,7 +1084,7 @@ static int taal_memory_read(struct omap_dss_device *dssdev, r = dsi_vc_set_max_rx_packet_size(TCH, plen); if (r) - goto err0; + goto err2; while (buf_used < size) { u8 dcs_cmd = first ? 0x2e : 0x3e; @@ -1006,7 +1095,7 @@ static int taal_memory_read(struct omap_dss_device *dssdev, if (r < 0) { dev_err(&dssdev->dev, "read error\n"); - goto err; + goto err3; } buf_used += r; @@ -1020,16 +1109,18 @@ static int taal_memory_read(struct omap_dss_device *dssdev, dev_err(&dssdev->dev, "signal pending, " "aborting memory read\n"); r = -ERESTARTSYS; - goto err; + goto err3; } } r = buf_used; -err: +err3: dsi_vc_set_max_rx_packet_size(TCH, 1); -err0: +err2: dsi_bus_unlock(); +err1: + mutex_unlock(&td->lock); return r; } @@ -1041,8 +1132,12 @@ static void taal_esd_work(struct work_struct *work) u8 state1, state2; int r; - if (!td->enabled) + mutex_lock(&td->lock); + + if (!td->enabled) { + mutex_unlock(&td->lock); return; + } dsi_bus_lock(); @@ -1084,16 +1179,19 @@ static void taal_esd_work(struct work_struct *work) queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD); + mutex_unlock(&td->lock); return; err: dev_err(&dssdev->dev, "performing LCD reset\n"); - taal_disable(dssdev); - taal_enable(dssdev); + taal_power_off(dssdev); + taal_power_on(dssdev); dsi_bus_unlock(); queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD); + + mutex_unlock(&td->lock); } static int taal_set_update_mode(struct omap_dss_device *dssdev, -- cgit v1.2.1 From 6df37271f879f14119a0605549f1a2574e83b4fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 10 Mar 2010 18:24:54 +0100 Subject: OMAP: DSS2: Taal: Fix DSI bus locking problem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If omapdss_dsi_display_enable() failed the DSI bus was left locked. Also if the operation failed later omapdss_dsi_display_disable() would get called without holding the bus lock. Signed-off-by: Ville Syrjälä Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 1799096a1388..aaf5d308a046 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -702,10 +702,9 @@ static int taal_power_on(struct omap_dss_device *dssdev) return 0; err: - dsi_bus_unlock(); - omapdss_dsi_display_disable(dssdev); err0: + dsi_bus_unlock(); if (dssdev->platform_disable) dssdev->platform_disable(dssdev); -- cgit v1.2.1 From 2b88c5bc310dc7a2bf9341b86e9f01cf05e8769e Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Thu, 15 Apr 2010 16:00:00 +0200 Subject: OMAP: LCD LS037V7DW01: Add Backlight driver support Tested on OMAP3EVM for OMAP3530 and AM/DM 3730. Signed-off-by: Vaibhav Hiremath [tomi.valkeinen@nokia.com: added slab.h include] [tomi.valkeinen@nokia.com: added dependency to BACKLIGHT_CLASS_DEVICE] Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/Kconfig | 1 + .../video/omap2/displays/panel-sharp-ls037v7dw01.c | 78 ++++++++++++++++++++++ 2 files changed, 79 insertions(+) (limited to 'drivers/video') diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index dfb57ee50861..ea8ccd362c22 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig @@ -10,6 +10,7 @@ config PANEL_GENERIC config PANEL_SHARP_LS037V7DW01 tristate "Sharp LS037V7DW01 LCD Panel" depends on OMAP2_DSS + select BACKLIGHT_CLASS_DEVICE help LCD Panel used in TI's SDP3430 and EVM boards diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c index 8d51a5e6341c..7d9eb2b1f5af 100644 --- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c @@ -20,10 +20,17 @@ #include #include #include +#include +#include #include +#include #include +struct sharp_data { + struct backlight_device *bl; +}; + static struct omap_video_timings sharp_ls_timings = { .x_res = 480, .y_res = 640, @@ -39,18 +46,89 @@ static struct omap_video_timings sharp_ls_timings = { .vbp = 1, }; +static int sharp_ls_bl_update_status(struct backlight_device *bl) +{ + struct omap_dss_device *dssdev = dev_get_drvdata(&bl->dev); + int level; + + if (!dssdev->set_backlight) + return -EINVAL; + + if (bl->props.fb_blank == FB_BLANK_UNBLANK && + bl->props.power == FB_BLANK_UNBLANK) + level = bl->props.brightness; + else + level = 0; + + return dssdev->set_backlight(dssdev, level); +} + +static int sharp_ls_bl_get_brightness(struct backlight_device *bl) +{ + if (bl->props.fb_blank == FB_BLANK_UNBLANK && + bl->props.power == FB_BLANK_UNBLANK) + return bl->props.brightness; + + return 0; +} + +static const struct backlight_ops sharp_ls_bl_ops = { + .get_brightness = sharp_ls_bl_get_brightness, + .update_status = sharp_ls_bl_update_status, +}; + + + static int sharp_ls_panel_probe(struct omap_dss_device *dssdev) { + struct backlight_properties props; + struct backlight_device *bl; + struct sharp_data *sd; + int r; + dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS; dssdev->panel.acb = 0x28; dssdev->panel.timings = sharp_ls_timings; + sd = kzalloc(sizeof(*sd), GFP_KERNEL); + if (!sd) + return -ENOMEM; + + dev_set_drvdata(&dssdev->dev, sd); + + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = dssdev->max_backlight_level; + + bl = backlight_device_register("sharp-ls", &dssdev->dev, dssdev, + &sharp_ls_bl_ops, &props); + if (IS_ERR(bl)) { + r = PTR_ERR(bl); + kfree(sd); + return r; + } + sd->bl = bl; + + bl->props.fb_blank = FB_BLANK_UNBLANK; + bl->props.power = FB_BLANK_UNBLANK; + bl->props.brightness = dssdev->max_backlight_level; + r = sharp_ls_bl_update_status(bl); + if (r < 0) + dev_err(&dssdev->dev, "failed to set lcd brightness\n"); + return 0; } static void sharp_ls_panel_remove(struct omap_dss_device *dssdev) { + struct sharp_data *sd = dev_get_drvdata(&dssdev->dev); + struct backlight_device *bl = sd->bl; + + bl->props.power = FB_BLANK_POWERDOWN; + sharp_ls_bl_update_status(bl); + backlight_device_unregister(bl); + + kfree(sd); } static int sharp_ls_power_on(struct omap_dss_device *dssdev) -- cgit v1.2.1 From a40458eee7ee60a89f89602067921658b87ded73 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Thu, 15 Apr 2010 16:59:03 +0200 Subject: OMAP: DSS2: TPO-TD03MTEA1: fix Kconfig dependency This panel depends on SPI, not I2C. Signed-off-by: Grazvydas Ignotas Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/video') diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index ea8ccd362c22..4221957b0d2c 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig @@ -34,7 +34,7 @@ config PANEL_TOPPOLY_TDO35S config PANEL_TPO_TD043MTEA1 tristate "TPO TD043MTEA1 LCD Panel" - depends on OMAP2_DSS && I2C + depends on OMAP2_DSS && SPI help LCD Panel used in OMAP3 Pandora -- cgit v1.2.1 From 0188352b2774234575a41864fd0945be42975ee5 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Wed, 10 Mar 2010 17:32:44 +0200 Subject: OMAP: DSS2: Add ACX565AKM Panel Driver This is the panel used on Nokia N900 Signed-off-by: Roger Quadros Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/Kconfig | 6 + drivers/video/omap2/displays/Makefile | 1 + drivers/video/omap2/displays/panel-acx565akm.c | 819 +++++++++++++++++++++++++ 3 files changed, 826 insertions(+) create mode 100644 drivers/video/omap2/displays/panel-acx565akm.c (limited to 'drivers/video') diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index 4221957b0d2c..881c9f77c75a 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig @@ -38,4 +38,10 @@ config PANEL_TPO_TD043MTEA1 help LCD Panel used in OMAP3 Pandora +config PANEL_ACX565AKM + tristate "ACX565AKM Panel" + depends on OMAP2_DSS_SDI + select BACKLIGHT_CLASS_DEVICE + help + This is the LCD panel used on Nokia N900 endmenu diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile index e2bb32168dee..aa386095d7c4 100644 --- a/drivers/video/omap2/displays/Makefile +++ b/drivers/video/omap2/displays/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_PANEL_SHARP_LQ043T1DG01) += panel-sharp-lq043t1dg01.o obj-$(CONFIG_PANEL_TAAL) += panel-taal.o obj-$(CONFIG_PANEL_TOPPOLY_TDO35S) += panel-toppoly-tdo35s.o obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o +obj-$(CONFIG_PANEL_ACX565AKM) += panel-acx565akm.o diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c new file mode 100644 index 000000000000..1f8eb70e2937 --- /dev/null +++ b/drivers/video/omap2/displays/panel-acx565akm.c @@ -0,0 +1,819 @@ +/* + * Support for ACX565AKM LCD Panel used on Nokia N900 + * + * Copyright (C) 2010 Nokia Corporation + * + * Original Driver Author: Imre Deak + * Based on panel-generic.c by Tomi Valkeinen + * Adapted to new DSS2 framework: Roger Quadros + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MIPID_CMD_READ_DISP_ID 0x04 +#define MIPID_CMD_READ_RED 0x06 +#define MIPID_CMD_READ_GREEN 0x07 +#define MIPID_CMD_READ_BLUE 0x08 +#define MIPID_CMD_READ_DISP_STATUS 0x09 +#define MIPID_CMD_RDDSDR 0x0F +#define MIPID_CMD_SLEEP_IN 0x10 +#define MIPID_CMD_SLEEP_OUT 0x11 +#define MIPID_CMD_DISP_OFF 0x28 +#define MIPID_CMD_DISP_ON 0x29 +#define MIPID_CMD_WRITE_DISP_BRIGHTNESS 0x51 +#define MIPID_CMD_READ_DISP_BRIGHTNESS 0x52 +#define MIPID_CMD_WRITE_CTRL_DISP 0x53 + +#define CTRL_DISP_BRIGHTNESS_CTRL_ON (1 << 5) +#define CTRL_DISP_AMBIENT_LIGHT_CTRL_ON (1 << 4) +#define CTRL_DISP_BACKLIGHT_ON (1 << 2) +#define CTRL_DISP_AUTO_BRIGHTNESS_ON (1 << 1) + +#define MIPID_CMD_READ_CTRL_DISP 0x54 +#define MIPID_CMD_WRITE_CABC 0x55 +#define MIPID_CMD_READ_CABC 0x56 + +#define MIPID_VER_LPH8923 3 +#define MIPID_VER_LS041Y3 4 +#define MIPID_VER_L4F00311 8 +#define MIPID_VER_ACX565AKM 9 + +struct acx565akm_device { + char *name; + int enabled; + int model; + int revision; + u8 display_id[3]; + unsigned has_bc:1; + unsigned has_cabc:1; + unsigned cabc_mode; + unsigned long hw_guard_end; /* next value of jiffies + when we can issue the + next sleep in/out command */ + unsigned long hw_guard_wait; /* max guard time in jiffies */ + + struct spi_device *spi; + struct mutex mutex; + + struct omap_dss_device *dssdev; + struct backlight_device *bl_dev; +}; + +static struct acx565akm_device acx_dev; +static int acx565akm_bl_update_status(struct backlight_device *dev); + +/*--------------------MIPID interface-----------------------------*/ + +static void acx565akm_transfer(struct acx565akm_device *md, int cmd, + const u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + struct spi_message m; + struct spi_transfer *x, xfer[5]; + int r; + + BUG_ON(md->spi == NULL); + + spi_message_init(&m); + + memset(xfer, 0, sizeof(xfer)); + x = &xfer[0]; + + cmd &= 0xff; + x->tx_buf = &cmd; + x->bits_per_word = 9; + x->len = 2; + + if (rlen > 1 && wlen == 0) { + /* + * Between the command and the response data there is a + * dummy clock cycle. Add an extra bit after the command + * word to account for this. + */ + x->bits_per_word = 10; + cmd <<= 1; + } + spi_message_add_tail(x, &m); + + if (wlen) { + x++; + x->tx_buf = wbuf; + x->len = wlen; + x->bits_per_word = 9; + spi_message_add_tail(x, &m); + } + + if (rlen) { + x++; + x->rx_buf = rbuf; + x->len = rlen; + spi_message_add_tail(x, &m); + } + + r = spi_sync(md->spi, &m); + if (r < 0) + dev_dbg(&md->spi->dev, "spi_sync %d\n", r); +} + +static inline void acx565akm_cmd(struct acx565akm_device *md, int cmd) +{ + acx565akm_transfer(md, cmd, NULL, 0, NULL, 0); +} + +static inline void acx565akm_write(struct acx565akm_device *md, + int reg, const u8 *buf, int len) +{ + acx565akm_transfer(md, reg, buf, len, NULL, 0); +} + +static inline void acx565akm_read(struct acx565akm_device *md, + int reg, u8 *buf, int len) +{ + acx565akm_transfer(md, reg, NULL, 0, buf, len); +} + +static void hw_guard_start(struct acx565akm_device *md, int guard_msec) +{ + md->hw_guard_wait = msecs_to_jiffies(guard_msec); + md->hw_guard_end = jiffies + md->hw_guard_wait; +} + +static void hw_guard_wait(struct acx565akm_device *md) +{ + unsigned long wait = md->hw_guard_end - jiffies; + + if ((long)wait > 0 && wait <= md->hw_guard_wait) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(wait); + } +} + +/*----------------------MIPID wrappers----------------------------*/ + +static void set_sleep_mode(struct acx565akm_device *md, int on) +{ + int cmd; + + if (on) + cmd = MIPID_CMD_SLEEP_IN; + else + cmd = MIPID_CMD_SLEEP_OUT; + /* + * We have to keep 120msec between sleep in/out commands. + * (8.2.15, 8.2.16). + */ + hw_guard_wait(md); + acx565akm_cmd(md, cmd); + hw_guard_start(md, 120); +} + +static void set_display_state(struct acx565akm_device *md, int enabled) +{ + int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF; + + acx565akm_cmd(md, cmd); +} + +static int panel_enabled(struct acx565akm_device *md) +{ + u32 disp_status; + int enabled; + + acx565akm_read(md, MIPID_CMD_READ_DISP_STATUS, (u8 *)&disp_status, 4); + disp_status = __be32_to_cpu(disp_status); + enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10)); + dev_dbg(&md->spi->dev, + "LCD panel %senabled by bootloader (status 0x%04x)\n", + enabled ? "" : "not ", disp_status); + return enabled; +} + +static int panel_detect(struct acx565akm_device *md) +{ + acx565akm_read(md, MIPID_CMD_READ_DISP_ID, md->display_id, 3); + dev_dbg(&md->spi->dev, "MIPI display ID: %02x%02x%02x\n", + md->display_id[0], md->display_id[1], md->display_id[2]); + + switch (md->display_id[0]) { + case 0x10: + md->model = MIPID_VER_ACX565AKM; + md->name = "acx565akm"; + md->has_bc = 1; + md->has_cabc = 1; + break; + case 0x29: + md->model = MIPID_VER_L4F00311; + md->name = "l4f00311"; + break; + case 0x45: + md->model = MIPID_VER_LPH8923; + md->name = "lph8923"; + break; + case 0x83: + md->model = MIPID_VER_LS041Y3; + md->name = "ls041y3"; + break; + default: + md->name = "unknown"; + dev_err(&md->spi->dev, "invalid display ID\n"); + return -ENODEV; + } + + md->revision = md->display_id[1]; + + dev_info(&md->spi->dev, "omapfb: %s rev %02x LCD detected\n", + md->name, md->revision); + + return 0; +} + +/*----------------------Backlight Control-------------------------*/ + +static void enable_backlight_ctrl(struct acx565akm_device *md, int enable) +{ + u16 ctrl; + + acx565akm_read(md, MIPID_CMD_READ_CTRL_DISP, (u8 *)&ctrl, 1); + if (enable) { + ctrl |= CTRL_DISP_BRIGHTNESS_CTRL_ON | + CTRL_DISP_BACKLIGHT_ON; + } else { + ctrl &= ~(CTRL_DISP_BRIGHTNESS_CTRL_ON | + CTRL_DISP_BACKLIGHT_ON); + } + + ctrl |= 1 << 8; + acx565akm_write(md, MIPID_CMD_WRITE_CTRL_DISP, (u8 *)&ctrl, 2); +} + +static void set_cabc_mode(struct acx565akm_device *md, unsigned mode) +{ + u16 cabc_ctrl; + + md->cabc_mode = mode; + if (!md->enabled) + return; + cabc_ctrl = 0; + acx565akm_read(md, MIPID_CMD_READ_CABC, (u8 *)&cabc_ctrl, 1); + cabc_ctrl &= ~3; + cabc_ctrl |= (1 << 8) | (mode & 3); + acx565akm_write(md, MIPID_CMD_WRITE_CABC, (u8 *)&cabc_ctrl, 2); +} + +static unsigned get_cabc_mode(struct acx565akm_device *md) +{ + return md->cabc_mode; +} + +static unsigned get_hw_cabc_mode(struct acx565akm_device *md) +{ + u8 cabc_ctrl; + + acx565akm_read(md, MIPID_CMD_READ_CABC, &cabc_ctrl, 1); + return cabc_ctrl & 3; +} + +static void acx565akm_set_brightness(struct acx565akm_device *md, int level) +{ + int bv; + + bv = level | (1 << 8); + acx565akm_write(md, MIPID_CMD_WRITE_DISP_BRIGHTNESS, (u8 *)&bv, 2); + + if (level) + enable_backlight_ctrl(md, 1); + else + enable_backlight_ctrl(md, 0); +} + +static int acx565akm_get_actual_brightness(struct acx565akm_device *md) +{ + u8 bv; + + acx565akm_read(md, MIPID_CMD_READ_DISP_BRIGHTNESS, &bv, 1); + + return bv; +} + + +static int acx565akm_bl_update_status(struct backlight_device *dev) +{ + struct acx565akm_device *md = dev_get_drvdata(&dev->dev); + int r; + int level; + + dev_dbg(&md->spi->dev, "%s\n", __func__); + + mutex_lock(&md->mutex); + + if (dev->props.fb_blank == FB_BLANK_UNBLANK && + dev->props.power == FB_BLANK_UNBLANK) + level = dev->props.brightness; + else + level = 0; + + r = 0; + if (md->has_bc) + acx565akm_set_brightness(md, level); + else if (md->dssdev->set_backlight) + r = md->dssdev->set_backlight(md->dssdev, level); + else + r = -ENODEV; + + mutex_unlock(&md->mutex); + + return r; +} + +static int acx565akm_bl_get_intensity(struct backlight_device *dev) +{ + struct acx565akm_device *md = dev_get_drvdata(&dev->dev); + + dev_dbg(&dev->dev, "%s\n", __func__); + + if (!md->has_bc && md->dssdev->set_backlight == NULL) + return -ENODEV; + + if (dev->props.fb_blank == FB_BLANK_UNBLANK && + dev->props.power == FB_BLANK_UNBLANK) { + if (md->has_bc) + return acx565akm_get_actual_brightness(md); + else + return dev->props.brightness; + } + + return 0; +} + +static const struct backlight_ops acx565akm_bl_ops = { + .get_brightness = acx565akm_bl_get_intensity, + .update_status = acx565akm_bl_update_status, +}; + +/*--------------------Auto Brightness control via Sysfs---------------------*/ + +static const char *cabc_modes[] = { + "off", /* always used when CABC is not supported */ + "ui", + "still-image", + "moving-image", +}; + +static ssize_t show_cabc_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acx565akm_device *md = dev_get_drvdata(dev); + const char *mode_str; + int mode; + int len; + + if (!md->has_cabc) + mode = 0; + else + mode = get_cabc_mode(md); + mode_str = "unknown"; + if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes)) + mode_str = cabc_modes[mode]; + len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str); + + return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1; +} + +static ssize_t store_cabc_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct acx565akm_device *md = dev_get_drvdata(dev); + int i; + + for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) { + const char *mode_str = cabc_modes[i]; + int cmp_len = strlen(mode_str); + + if (count > 0 && buf[count - 1] == '\n') + count--; + if (count != cmp_len) + continue; + + if (strncmp(buf, mode_str, cmp_len) == 0) + break; + } + + if (i == ARRAY_SIZE(cabc_modes)) + return -EINVAL; + + if (!md->has_cabc && i != 0) + return -EINVAL; + + mutex_lock(&md->mutex); + set_cabc_mode(md, i); + mutex_unlock(&md->mutex); + + return count; +} + +static ssize_t show_cabc_available_modes(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acx565akm_device *md = dev_get_drvdata(dev); + int len; + int i; + + if (!md->has_cabc) + return snprintf(buf, PAGE_SIZE, "%s\n", cabc_modes[0]); + + for (i = 0, len = 0; + len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++) + len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s", + i ? " " : "", cabc_modes[i], + i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : ""); + + return len < PAGE_SIZE ? len : PAGE_SIZE - 1; +} + +static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR, + show_cabc_mode, store_cabc_mode); +static DEVICE_ATTR(cabc_available_modes, S_IRUGO, + show_cabc_available_modes, NULL); + +static struct attribute *bldev_attrs[] = { + &dev_attr_cabc_mode.attr, + &dev_attr_cabc_available_modes.attr, + NULL, +}; + +static struct attribute_group bldev_attr_group = { + .attrs = bldev_attrs, +}; + + +/*---------------------------ACX Panel----------------------------*/ + +static int acx_get_recommended_bpp(struct omap_dss_device *dssdev) +{ + return 16; +} + +static struct omap_video_timings acx_panel_timings = { + .x_res = 800, + .y_res = 480, + .pixel_clock = 24000, + .hfp = 28, + .hsw = 4, + .hbp = 24, + .vfp = 3, + .vsw = 3, + .vbp = 4, +}; + +static int acx_panel_probe(struct omap_dss_device *dssdev) +{ + int r; + struct acx565akm_device *md = &acx_dev; + struct backlight_device *bldev; + int max_brightness, brightness; + struct backlight_properties props; + + dev_dbg(&dssdev->dev, "%s\n", __func__); + dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS; + /* FIXME AC bias ? */ + dssdev->panel.timings = acx_panel_timings; + + if (dssdev->platform_enable) + dssdev->platform_enable(dssdev); + /* + * After reset we have to wait 5 msec before the first + * command can be sent. + */ + msleep(5); + + md->enabled = panel_enabled(md); + + r = panel_detect(md); + if (r) { + dev_err(&dssdev->dev, "%s panel detect error\n", __func__); + if (!md->enabled && dssdev->platform_disable) + dssdev->platform_disable(dssdev); + return r; + } + + mutex_lock(&acx_dev.mutex); + acx_dev.dssdev = dssdev; + mutex_unlock(&acx_dev.mutex); + + if (!md->enabled) { + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); + } + + /*------- Backlight control --------*/ + + props.fb_blank = FB_BLANK_UNBLANK; + props.power = FB_BLANK_UNBLANK; + + bldev = backlight_device_register("acx565akm", &md->spi->dev, + md, &acx565akm_bl_ops, &props); + md->bl_dev = bldev; + if (md->has_cabc) { + r = sysfs_create_group(&bldev->dev.kobj, &bldev_attr_group); + if (r) { + dev_err(&bldev->dev, + "%s failed to create sysfs files\n", __func__); + backlight_device_unregister(bldev); + return r; + } + md->cabc_mode = get_hw_cabc_mode(md); + } + + if (md->has_bc) + max_brightness = 255; + else + max_brightness = dssdev->max_backlight_level; + + if (md->has_bc) + brightness = acx565akm_get_actual_brightness(md); + else if (dssdev->get_backlight) + brightness = dssdev->get_backlight(dssdev); + else + brightness = 0; + + bldev->props.max_brightness = max_brightness; + bldev->props.brightness = brightness; + + acx565akm_bl_update_status(bldev); + return 0; +} + +static void acx_panel_remove(struct omap_dss_device *dssdev) +{ + struct acx565akm_device *md = &acx_dev; + + dev_dbg(&dssdev->dev, "%s\n", __func__); + sysfs_remove_group(&md->bl_dev->dev.kobj, &bldev_attr_group); + backlight_device_unregister(md->bl_dev); + mutex_lock(&acx_dev.mutex); + acx_dev.dssdev = NULL; + mutex_unlock(&acx_dev.mutex); +} + +static int acx_panel_power_on(struct omap_dss_device *dssdev) +{ + struct acx565akm_device *md = &acx_dev; + int r; + + dev_dbg(&dssdev->dev, "%s\n", __func__); + + mutex_lock(&md->mutex); + + r = omapdss_sdi_display_enable(dssdev); + if (r) { + pr_err("%s sdi enable failed\n", __func__); + return r; + } + + /*FIXME tweak me */ + msleep(50); + + if (dssdev->platform_enable) { + r = dssdev->platform_enable(dssdev); + if (r) + goto fail; + } + + if (md->enabled) { + dev_dbg(&md->spi->dev, "panel already enabled\n"); + mutex_unlock(&md->mutex); + return 0; + } + + /* + * We have to meet all the following delay requirements: + * 1. tRW: reset pulse width 10usec (7.12.1) + * 2. tRT: reset cancel time 5msec (7.12.1) + * 3. Providing PCLK,HS,VS signals for 2 frames = ~50msec worst + * case (7.6.2) + * 4. 120msec before the sleep out command (7.12.1) + */ + msleep(120); + + set_sleep_mode(md, 0); + md->enabled = 1; + + /* 5msec between sleep out and the next command. (8.2.16) */ + msleep(5); + set_display_state(md, 1); + set_cabc_mode(md, md->cabc_mode); + + mutex_unlock(&md->mutex); + + return acx565akm_bl_update_status(md->bl_dev); +fail: + omapdss_sdi_display_disable(dssdev); + return r; +} + +static void acx_panel_power_off(struct omap_dss_device *dssdev) +{ + struct acx565akm_device *md = &acx_dev; + + dev_dbg(&dssdev->dev, "%s\n", __func__); + + mutex_lock(&md->mutex); + + if (!md->enabled) { + mutex_unlock(&md->mutex); + return; + } + set_display_state(md, 0); + set_sleep_mode(md, 1); + md->enabled = 0; + /* + * We have to provide PCLK,HS,VS signals for 2 frames (worst case + * ~50msec) after sending the sleep in command and asserting the + * reset signal. We probably could assert the reset w/o the delay + * but we still delay to avoid possible artifacts. (7.6.1) + */ + msleep(50); + + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); + + /* FIXME need to tweak this delay */ + msleep(100); + + omapdss_sdi_display_disable(dssdev); + + mutex_unlock(&md->mutex); +} + +static int acx_panel_enable(struct omap_dss_device *dssdev) +{ + int r; + + dev_dbg(&dssdev->dev, "%s\n", __func__); + r = acx_panel_power_on(dssdev); + + if (r) + return r; + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + return 0; +} + +static void acx_panel_disable(struct omap_dss_device *dssdev) +{ + dev_dbg(&dssdev->dev, "%s\n", __func__); + acx_panel_power_off(dssdev); + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; +} + +static int acx_panel_suspend(struct omap_dss_device *dssdev) +{ + dev_dbg(&dssdev->dev, "%s\n", __func__); + acx_panel_power_off(dssdev); + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; + return 0; +} + +static int acx_panel_resume(struct omap_dss_device *dssdev) +{ + int r; + + dev_dbg(&dssdev->dev, "%s\n", __func__); + r = acx_panel_power_on(dssdev); + if (r) + return r; + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + return 0; +} + +static void acx_panel_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + int r; + + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) + omapdss_sdi_display_disable(dssdev); + + dssdev->panel.timings = *timings; + + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { + r = omapdss_sdi_display_enable(dssdev); + if (r) + dev_err(&dssdev->dev, "%s enable failed\n", __func__); + } +} + +static void acx_panel_get_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + *timings = dssdev->panel.timings; +} + +static int acx_panel_check_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + return 0; +} + + +static struct omap_dss_driver acx_panel_driver = { + .probe = acx_panel_probe, + .remove = acx_panel_remove, + + .enable = acx_panel_enable, + .disable = acx_panel_disable, + .suspend = acx_panel_suspend, + .resume = acx_panel_resume, + + .set_timings = acx_panel_set_timings, + .get_timings = acx_panel_get_timings, + .check_timings = acx_panel_check_timings, + + .get_recommended_bpp = acx_get_recommended_bpp, + + .driver = { + .name = "panel-acx565akm", + .owner = THIS_MODULE, + }, +}; + +/*--------------------SPI probe-------------------------*/ + +static int acx565akm_spi_probe(struct spi_device *spi) +{ + struct acx565akm_device *md = &acx_dev; + + dev_dbg(&spi->dev, "%s\n", __func__); + + spi->mode = SPI_MODE_3; + md->spi = spi; + mutex_init(&md->mutex); + dev_set_drvdata(&spi->dev, md); + + omap_dss_register_driver(&acx_panel_driver); + + return 0; +} + +static int acx565akm_spi_remove(struct spi_device *spi) +{ + struct acx565akm_device *md = dev_get_drvdata(&spi->dev); + + dev_dbg(&md->spi->dev, "%s\n", __func__); + omap_dss_unregister_driver(&acx_panel_driver); + + return 0; +} + +static struct spi_driver acx565akm_spi_driver = { + .driver = { + .name = "acx565akm", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = acx565akm_spi_probe, + .remove = __devexit_p(acx565akm_spi_remove), +}; + +static int __init acx565akm_init(void) +{ + return spi_register_driver(&acx565akm_spi_driver); +} + +static void __exit acx565akm_exit(void) +{ + spi_unregister_driver(&acx565akm_spi_driver); +} + +module_init(acx565akm_init); +module_exit(acx565akm_exit); + +MODULE_AUTHOR("Nokia Corporation"); +MODULE_DESCRIPTION("acx565akm LCD Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.1 From ac01bb7ea06a02c8dc9084b4ed59cb59efeceb39 Mon Sep 17 00:00:00 2001 From: Kishore Y Date: Sun, 25 Apr 2010 16:27:19 +0530 Subject: OMAP3630: DSS2: Updating MAX divider value In DPLL4 M3, M4, M5 and M6 field width has been increased by 1 bit in 3630. So the max divider value that can be achived will be 32 and not 16. In 3630 the functional clock is x1 of DPLL4 and not x2. Hence multiplier 2 is removed. Signed-off-by: Sudeep Basavaraj Signed-off-by: Mukund Mittal Signed-off-by: Kishore Y Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dss.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 54344184dd73..24b18258654f 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -223,7 +223,13 @@ void dss_dump_clocks(struct seq_file *s) seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); - seq_printf(s, "dss1_alwon_fclk = %lu / %lu * 2 = %lu\n", + if (cpu_is_omap3630()) + seq_printf(s, "dss1_alwon_fclk = %lu / %lu = %lu\n", + dpll4_ck_rate, + dpll4_ck_rate / dpll4_m4_ck_rate, + dss_clk_get_rate(DSS_CLK_FCK1)); + else + seq_printf(s, "dss1_alwon_fclk = %lu / %lu * 2 = %lu\n", dpll4_ck_rate, dpll4_ck_rate / dpll4_m4_ck_rate, dss_clk_get_rate(DSS_CLK_FCK1)); @@ -293,7 +299,8 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo) { unsigned long prate; - if (cinfo->fck_div > 16 || cinfo->fck_div == 0) + if (cinfo->fck_div > (cpu_is_omap3630() ? 32 : 16) || + cinfo->fck_div == 0) return -EINVAL; prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); @@ -329,7 +336,10 @@ int dss_get_clock_div(struct dss_clock_info *cinfo) if (cpu_is_omap34xx()) { unsigned long prate; prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); - cinfo->fck_div = prate / (cinfo->fck / 2); + if (cpu_is_omap3630()) + cinfo->fck_div = prate / (cinfo->fck); + else + cinfo->fck_div = prate / (cinfo->fck / 2); } else { cinfo->fck_div = 0; } @@ -402,10 +412,14 @@ retry: goto found; } else if (cpu_is_omap34xx()) { - for (fck_div = 16; fck_div > 0; --fck_div) { + for (fck_div = (cpu_is_omap3630() ? 32 : 16); + fck_div > 0; --fck_div) { struct dispc_clock_info cur_dispc; - fck = prate / fck_div * 2; + if (cpu_is_omap3630()) + fck = prate / fck_div; + else + fck = prate / fck_div * 2; if (fck > DISPC_MAX_FCK) continue; -- cgit v1.2.1 From a3bb67a75c0fe5c48def0fd39d2fe9ec043241d4 Mon Sep 17 00:00:00 2001 From: Carlos Lopez Date: Sun, 25 Apr 2010 12:53:35 +0200 Subject: OMAP2: DSS: Add missing line for update bg color The driver set the background color canvas but never writes it in DISPC_DEFAULT_COLOR_m register, which changes the background color on the LCD or TV. This patch adds a line to call to dispc_set_default_color() which is the function in charge to write the DISPC_DEFAULT_COLOR_m register. Signed-off-by: Carlos Lopez Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/manager.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/video') diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 32ec2ff2e9cf..9e1fbe531bf0 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -843,6 +843,7 @@ static void configure_manager(enum omap_channel channel) c = &dss_cache.manager_cache[channel]; + dispc_set_default_color(channel, c->default_color); dispc_set_trans_key(channel, c->trans_key_type, c->trans_key); dispc_enable_trans_key(channel, c->trans_enabled); dispc_enable_alpha_blending(channel, c->alpha_enabled); -- cgit v1.2.1 From 368a148ea3833b540945fa53a63227c8ce76aa8f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 7 May 2010 11:58:41 +0200 Subject: OMAP: DSS2: omap_dss_probe() conditional compilation cleanup Move a number of #ifdefs from code into dss.h and elsewhere, and conditionally define no-op static inline functions, cleaning up the code. This style is according to Documentation/SubmittingPatches. Signed-off-by: Jani Nikula Acked-by: Kevin Hilman Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/core.c | 35 ++++++++++------------------- drivers/video/omap2/dss/dss.h | 50 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 24 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 6d54467e5e20..92ee06742ece 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -482,6 +482,14 @@ static void dss_uninitialize_debugfs(void) if (dss_debugfs_dir) debugfs_remove_recursive(dss_debugfs_dir); } +#else /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */ +static inline int dss_initialize_debugfs(void) +{ + return 0; +} +static inline void dss_uninitialize_debugfs(void) +{ +} #endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */ /* PLATFORM DEVICE */ @@ -518,56 +526,47 @@ static int omap_dss_probe(struct platform_device *pdev) goto fail0; } -#ifdef CONFIG_OMAP2_DSS_RFBI r = rfbi_init(); if (r) { DSSERR("Failed to initialize rfbi\n"); goto fail0; } -#endif -#ifdef CONFIG_OMAP2_DSS_DPI r = dpi_init(pdev); if (r) { DSSERR("Failed to initialize dpi\n"); goto fail0; } -#endif r = dispc_init(); if (r) { DSSERR("Failed to initialize dispc\n"); goto fail0; } -#ifdef CONFIG_OMAP2_DSS_VENC + r = venc_init(pdev); if (r) { DSSERR("Failed to initialize venc\n"); goto fail0; } -#endif + if (cpu_is_omap34xx()) { -#ifdef CONFIG_OMAP2_DSS_SDI r = sdi_init(skip_init); if (r) { DSSERR("Failed to initialize SDI\n"); goto fail0; } -#endif -#ifdef CONFIG_OMAP2_DSS_DSI + r = dsi_init(pdev); if (r) { DSSERR("Failed to initialize DSI\n"); goto fail0; } -#endif } -#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) r = dss_initialize_debugfs(); if (r) goto fail0; -#endif for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; @@ -595,27 +594,15 @@ static int omap_dss_remove(struct platform_device *pdev) int i; int c; -#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) dss_uninitialize_debugfs(); -#endif -#ifdef CONFIG_OMAP2_DSS_VENC venc_exit(); -#endif dispc_exit(); -#ifdef CONFIG_OMAP2_DSS_DPI dpi_exit(); -#endif -#ifdef CONFIG_OMAP2_DSS_RFBI rfbi_exit(); -#endif if (cpu_is_omap34xx()) { -#ifdef CONFIG_OMAP2_DSS_DSI dsi_exit(); -#endif -#ifdef CONFIG_OMAP2_DSS_SDI sdi_exit(); -#endif } dss_exit(); diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 24326a5fd292..786f433fd571 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -242,11 +242,22 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck, struct dispc_clock_info *dispc_cinfo); /* SDI */ +#ifdef CONFIG_OMAP2_DSS_SDI int sdi_init(bool skip_init); void sdi_exit(void); int sdi_init_display(struct omap_dss_device *display); +#else +static inline int sdi_init(bool skip_init) +{ + return 0; +} +static inline void sdi_exit(void) +{ +} +#endif /* DSI */ +#ifdef CONFIG_OMAP2_DSS_DSI int dsi_init(struct platform_device *pdev); void dsi_exit(void); @@ -270,11 +281,30 @@ void dsi_pll_uninit(void); void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, u32 fifo_size, enum omap_burst_size *burst_size, u32 *fifo_low, u32 *fifo_high); +#else +static inline int dsi_init(struct platform_device *pdev) +{ + return 0; +} +static inline void dsi_exit(void) +{ +} +#endif /* DPI */ +#ifdef CONFIG_OMAP2_DSS_DPI int dpi_init(struct platform_device *pdev); void dpi_exit(void); int dpi_init_display(struct omap_dss_device *dssdev); +#else +static inline int dpi_init(struct platform_device *pdev) +{ + return 0; +} +static inline void dpi_exit(void) +{ +} +#endif /* DISPC */ int dispc_init(void); @@ -362,12 +392,23 @@ int dispc_get_clock_div(struct dispc_clock_info *cinfo); /* VENC */ +#ifdef CONFIG_OMAP2_DSS_VENC int venc_init(struct platform_device *pdev); void venc_exit(void); void venc_dump_regs(struct seq_file *s); int venc_init_display(struct omap_dss_device *display); +#else +static inline int venc_init(struct platform_device *pdev) +{ + return 0; +} +static inline void venc_exit(void) +{ +} +#endif /* RFBI */ +#ifdef CONFIG_OMAP2_DSS_RFBI int rfbi_init(void); void rfbi_exit(void); void rfbi_dump_regs(struct seq_file *s); @@ -379,6 +420,15 @@ void rfbi_transfer_area(u16 width, u16 height, void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t); unsigned long rfbi_get_max_tx_rate(void); int rfbi_init_display(struct omap_dss_device *display); +#else +static inline int rfbi_init(void) +{ + return 0; +} +static inline void rfbi_exit(void) +{ +} +#endif #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS -- cgit v1.2.1 From fce064cbda85dda330150e8d4d9f6db1a3300023 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 7 May 2010 11:58:42 +0200 Subject: OMAP: DSS2: Fix omap_dss_probe() error path Perform graceful cleanup on errors instead of just bailing out. Signed-off-by: Jani Nikula Tested-by: Kevin Hilman Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/core.c | 54 ++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 13 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 92ee06742ece..b3a498f22d36 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -507,7 +507,7 @@ static int omap_dss_probe(struct platform_device *pdev) r = dss_get_clocks(); if (r) - goto fail0; + goto err_clocks; dss_clk_enable_all_no_ctx(); @@ -523,57 +523,64 @@ static int omap_dss_probe(struct platform_device *pdev) r = dss_init(skip_init); if (r) { DSSERR("Failed to initialize DSS\n"); - goto fail0; + goto err_dss; } r = rfbi_init(); if (r) { DSSERR("Failed to initialize rfbi\n"); - goto fail0; + goto err_rfbi; } r = dpi_init(pdev); if (r) { DSSERR("Failed to initialize dpi\n"); - goto fail0; + goto err_dpi; } r = dispc_init(); if (r) { DSSERR("Failed to initialize dispc\n"); - goto fail0; + goto err_dispc; } r = venc_init(pdev); if (r) { DSSERR("Failed to initialize venc\n"); - goto fail0; + goto err_venc; } if (cpu_is_omap34xx()) { r = sdi_init(skip_init); if (r) { DSSERR("Failed to initialize SDI\n"); - goto fail0; + goto err_sdi; } r = dsi_init(pdev); if (r) { DSSERR("Failed to initialize DSI\n"); - goto fail0; + goto err_dsi; } } r = dss_initialize_debugfs(); if (r) - goto fail0; + goto err_debugfs; for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; r = omap_dss_register_device(dssdev); - if (r) - DSSERR("device reg failed %d\n", i); + if (r) { + DSSERR("device %d %s register failed %d\n", i, + dssdev->name ?: "unnamed", r); + + while (--i >= 0) + omap_dss_unregister_device(pdata->devices[i]); + + goto err_register; + } if (def_disp_name && strcmp(def_disp_name, dssdev->name) == 0) pdata->default_device = dssdev; @@ -583,8 +590,29 @@ static int omap_dss_probe(struct platform_device *pdev) return 0; - /* XXX fail correctly */ -fail0: +err_register: + dss_uninitialize_debugfs(); +err_debugfs: + if (cpu_is_omap34xx()) + dsi_exit(); +err_dsi: + if (cpu_is_omap34xx()) + sdi_exit(); +err_sdi: + venc_exit(); +err_venc: + dispc_exit(); +err_dispc: + dpi_exit(); +err_dpi: + rfbi_exit(); +err_rfbi: + dss_exit(); +err_dss: + dss_clk_disable_all_no_ctx(); + dss_put_clocks(); +err_clocks: + return r; } -- cgit v1.2.1 From 2c3c8bea608866d8bd9dcf92657d57fdcac011c5 Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Wed, 12 May 2010 18:28:57 -0700 Subject: sysfs: add struct file* to bin_attr callbacks This allows bin_attr->read,write,mmap callbacks to check file specific data (such as inode owner) as part of any privilege validation. Signed-off-by: Chris Wright Signed-off-by: Greg Kroah-Hartman --- drivers/video/aty/radeon_base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 6c37e8ee5efe..3c1e13ed1cba 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -2099,7 +2099,7 @@ static ssize_t radeon_show_one_edid(char *buf, loff_t off, size_t count, const u } -static ssize_t radeon_show_edid1(struct kobject *kobj, +static ssize_t radeon_show_edid1(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { @@ -2112,7 +2112,7 @@ static ssize_t radeon_show_edid1(struct kobject *kobj, } -static ssize_t radeon_show_edid2(struct kobject *kobj, +static ssize_t radeon_show_edid2(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { -- cgit v1.2.1 From f4b87dee923342505e1ddba8d34ce9de33e75050 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 21 May 2010 12:44:47 -0700 Subject: fbmem: avoid printk format warning with 32-bit resources Fix printk formats: drivers/video/fbmem.c: In function 'fb_do_apertures_overlap': drivers/video/fbmem.c:1494: warning: format '%llx' expects type 'long long unsigned int', but argument 2 has type 'resource_size_t' drivers/video/fbmem.c:1494: warning: format '%llx' expects type 'long long unsigned int', but argument 3 has type 'resource_size_t' drivers/video/fbmem.c:1494: warning: format '%llx' expects type 'long long unsigned int', but argument 4 has type 'resource_size_t' drivers/video/fbmem.c:1494: warning: format '%llx' expects type 'long long unsigned int', but argument 5 has type 'resource_size_t' Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- drivers/video/fbmem.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/video') diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index e08b7b5cb326..731fce64df9d 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1491,7 +1491,10 @@ static bool fb_do_apertures_overlap(struct apertures_struct *gena, for (j = 0; j < gena->count; ++j) { struct aperture *g = &gena->ranges[j]; printk(KERN_DEBUG "checking generic (%llx %llx) vs hw (%llx %llx)\n", - g->base, g->size, h->base, h->size); + (unsigned long long)g->base, + (unsigned long long)g->size, + (unsigned long long)h->base, + (unsigned long long)h->size); if (apertures_overlap(g, h)) return true; } -- cgit v1.2.1